about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/bootstrap/defaults/bootstrap.dist.toml2
-rw-r--r--src/bootstrap/src/core/build_steps/check.rs53
-rw-r--r--src/bootstrap/src/core/build_steps/clippy.rs2
-rw-r--r--src/bootstrap/src/core/build_steps/compile.rs20
-rw-r--r--src/bootstrap/src/core/build_steps/dist.rs2
-rw-r--r--src/bootstrap/src/core/build_steps/doc.rs21
-rw-r--r--src/bootstrap/src/core/build_steps/gcc.rs2
-rw-r--r--src/bootstrap/src/core/build_steps/test.rs35
-rw-r--r--src/bootstrap/src/core/build_steps/tool.rs18
-rw-r--r--src/bootstrap/src/core/builder/cargo.rs14
-rw-r--r--src/bootstrap/src/core/builder/mod.rs8
-rw-r--r--src/bootstrap/src/core/builder/tests.rs206
-rw-r--r--src/bootstrap/src/core/config/config.rs99
-rw-r--r--src/bootstrap/src/core/config/mod.rs12
-rw-r--r--src/bootstrap/src/core/config/tests.rs584
-rw-r--r--src/bootstrap/src/core/config/toml/build.rs2
-rw-r--r--src/bootstrap/src/core/config/toml/mod.rs4
-rw-r--r--src/bootstrap/src/core/config/toml/rust.rs49
-rw-r--r--src/bootstrap/src/core/download.rs20
-rw-r--r--src/bootstrap/src/core/sanity.rs4
-rw-r--r--src/bootstrap/src/lib.rs44
-rw-r--r--src/bootstrap/src/utils/build_stamp.rs2
-rw-r--r--src/bootstrap/src/utils/cc_detect.rs10
-rw-r--r--src/bootstrap/src/utils/change_tracker.rs10
-rw-r--r--src/bootstrap/src/utils/exec.rs6
-rw-r--r--src/bootstrap/src/utils/helpers.rs28
-rw-r--r--src/bootstrap/src/utils/helpers/tests.rs11
-rw-r--r--src/bootstrap/src/utils/render_tests.rs2
-rw-r--r--src/bootstrap/src/utils/tarball.rs2
-rw-r--r--src/bootstrap/src/utils/tests/mod.rs53
-rw-r--r--src/build_helper/src/stage0_parser.rs14
-rw-r--r--src/ci/citool/tests/test-jobs.yml2
-rw-r--r--src/ci/docker/host-aarch64/dist-aarch64-linux/Dockerfile2
-rw-r--r--src/ci/docker/host-x86_64/dist-x86_64-linux/Dockerfile2
-rw-r--r--src/ci/docker/host-x86_64/pr-check-1/Dockerfile1
-rw-r--r--src/ci/docker/host-x86_64/x86_64-gnu-tools/Dockerfile1
-rw-r--r--src/ci/github-actions/jobs.yml26
-rw-r--r--src/doc/rustc/src/SUMMARY.md10
-rw-r--r--src/doc/rustc/src/lints/levels.md2
-rw-r--r--src/doc/rustc/src/platform-support.md6
-rw-r--r--src/doc/rustc/src/platform-support/apple-ios-macabi.md2
-rw-r--r--src/doc/rustc/src/platform-support/apple-ios.md2
-rw-r--r--src/doc/rustc/src/platform-support/arm-linux.md217
-rw-r--r--src/doc/rustc/src/platform-support/armeb-unknown-linux-gnueabi.md3
-rw-r--r--src/doc/rustc/src/platform-support/armebv7r-none-eabi.md2
-rw-r--r--src/doc/rustc/src/platform-support/armv5te-unknown-linux-gnueabi.md3
-rw-r--r--src/doc/rustc/src/platform-support/armv7-unknown-linux-uclibceabi.md3
-rw-r--r--src/doc/rustc/src/platform-support/armv7-unknown-linux-uclibceabihf.md3
-rw-r--r--src/doc/rustc/src/symbol-mangling/v0.md28
-rw-r--r--src/doc/rustdoc/src/advanced-features.md20
-rw-r--r--src/doc/rustdoc/src/unstable-features.md350
-rw-r--r--src/doc/rustdoc/src/write-documentation/linking-to-items-by-name.md2
-rw-r--r--src/doc/unstable-book/src/compiler-flags/split-dwarf-out-dir.md7
-rw-r--r--src/etc/lldb_providers.py5
-rwxr-xr-xsrc/etc/pre-push.sh5
-rw-r--r--src/librustdoc/Cargo.toml4
-rw-r--r--src/librustdoc/clean/cfg.rs30
-rw-r--r--src/librustdoc/clean/inline.rs19
-rw-r--r--src/librustdoc/clean/mod.rs10
-rw-r--r--src/librustdoc/clean/types.rs427
-rw-r--r--src/librustdoc/doctest.rs10
-rw-r--r--src/librustdoc/doctest/rust.rs5
-rw-r--r--src/librustdoc/formats/cache.rs2
-rw-r--r--src/librustdoc/html/format.rs4
-rw-r--r--src/librustdoc/html/highlight.rs253
-rw-r--r--src/librustdoc/html/highlight/tests.rs14
-rw-r--r--src/librustdoc/html/markdown.rs45
-rw-r--r--src/librustdoc/html/render/context.rs3
-rw-r--r--src/librustdoc/html/render/mod.rs390
-rw-r--r--src/librustdoc/html/render/print_item.rs8
-rw-r--r--src/librustdoc/html/render/search_index.rs40
-rw-r--r--src/librustdoc/html/render/span_map.rs186
-rw-r--r--src/librustdoc/html/render/write_shared.rs9
-rw-r--r--src/librustdoc/html/sources.rs7
-rw-r--r--src/librustdoc/html/static/js/stringdex.js78
-rw-r--r--src/librustdoc/lib.rs2
-rw-r--r--src/librustdoc/passes/collect_intra_doc_links.rs2
-rw-r--r--src/librustdoc/passes/mod.rs4
-rw-r--r--src/librustdoc/passes/propagate_doc_cfg.rs142
-rw-r--r--src/librustdoc/visit_ast.rs29
-rw-r--r--src/stage01022
-rw-r--r--src/tools/bump-stage0/Cargo.toml2
-rw-r--r--src/tools/bump-stage0/src/main.rs97
-rw-r--r--src/tools/clippy/clippy_lints/src/casts/cast_ptr_alignment.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/casts/manual_dangling_ptr.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/lib.rs1
-rw-r--r--src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs4
-rw-r--r--src/tools/clippy/tests/missing-test-files.rs1
-rw-r--r--src/tools/clippy/tests/ui/author/macro_in_closure.stdout32
-rw-r--r--src/tools/clippy/tests/ui/author/macro_in_loop.stdout28
-rw-r--r--src/tools/clippy/tests/ui/useless_attribute.fixed2
-rw-r--r--src/tools/clippy/tests/ui/useless_attribute.rs2
-rw-r--r--src/tools/compiletest/src/common.rs9
-rw-r--r--src/tools/compiletest/src/directives.rs217
-rw-r--r--src/tools/compiletest/src/directives/auxiliary.rs35
-rw-r--r--src/tools/compiletest/src/directives/cfg.rs14
-rw-r--r--src/tools/compiletest/src/directives/needs.rs6
-rw-r--r--src/tools/compiletest/src/executor.rs35
-rw-r--r--src/tools/compiletest/src/lib.rs32
-rw-r--r--src/tools/compiletest/src/panic_hook.rs15
-rw-r--r--src/tools/compiletest/src/runtest/debugger.rs27
-rw-r--r--src/tools/compiletest/src/runtest/debuginfo.rs6
-rw-r--r--src/tools/miri/src/lib.rs1
-rw-r--r--src/tools/miri/src/machine.rs2
-rw-r--r--src/tools/miri/tests/panic/mir-validation.rs5
-rw-r--r--src/tools/miri/tests/pass/both_borrows/smallvec.rs2
-rw-r--r--src/tools/miri/tests/pass/vec.rs10
-rw-r--r--src/tools/run-make-support/src/external_deps/rustc.rs7
-rw-r--r--src/tools/rust-analyzer/.github/workflows/ci.yaml10
-rw-r--r--src/tools/rust-analyzer/Cargo.lock22
-rw-r--r--src/tools/rust-analyzer/Cargo.toml1
-rw-r--r--src/tools/rust-analyzer/crates/hir-expand/src/builtin/derive_macro.rs2
-rw-r--r--src/tools/rust-analyzer/crates/hir-expand/src/builtin/fn_macro.rs2
-rw-r--r--src/tools/rust-analyzer/crates/hir-expand/src/builtin/quote.rs2
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/Cargo.toml1
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/autoderef.rs10
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/builder.rs33
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/chalk_ext.rs14
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/consteval.rs6
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/consteval/tests.rs48
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/consteval_nextsolver.rs2
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/db.rs231
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/expr.rs8
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/match_check/pat_analysis.rs4
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/unsafe_check.rs16
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/display.rs21
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/drop.rs19
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/dyn_compatibility.rs4
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/infer.rs167
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/infer/closure.rs6
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/infer/coerce.rs56
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/infer/expr.rs47
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/infer/fallback.rs439
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/infer/path.rs23
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/infer/unify.rs458
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/inhabitedness.rs6
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/layout.rs6
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/layout/adt.rs4
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/layout/tests.rs27
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/lib.rs57
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/lower.rs443
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/lower/path.rs36
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/lower_nextsolver.rs189
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/lower_nextsolver/path.rs58
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/method_resolution.rs196
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/mir/eval.rs25
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/mir/eval/shim.rs10
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/mir/lower.rs16
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/mir/monomorphization.rs20
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/next_solver.rs2
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/next_solver/interner.rs22
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/next_solver/mapping.rs47
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/next_solver/region.rs10
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/next_solver/solver.rs6
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/next_solver/ty.rs9
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/tests/incremental.rs6
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/tests/method_resolution.rs4
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/tests/never_type.rs10
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/tests/regression.rs4
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/tests/regression/new_solver.rs56
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/tests/traits.rs14
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/traits.rs24
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/variance.rs19
-rw-r--r--src/tools/rust-analyzer/crates/hir/src/display.rs8
-rw-r--r--src/tools/rust-analyzer/crates/hir/src/lib.rs186
-rw-r--r--src/tools/rust-analyzer/crates/hir/src/source_analyzer.rs12
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/handlers/add_braces.rs33
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/handlers/add_missing_match_arms.rs2
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/handlers/apply_demorgan.rs35
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/handlers/bind_unused_param.rs33
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_to_guarded_return.rs297
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/handlers/destructure_struct_binding.rs155
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/handlers/expand_rest_pattern.rs292
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_variable.rs29
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_default_from_enum_variant.rs46
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/handlers/invert_if.rs12
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/handlers/pull_assignment_up.rs35
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/handlers/remove_dbg.rs17
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_arith_op.rs40
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_if_let_with_match.rs24
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_is_method_with_if_let_method.rs18
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/tests/generated.rs36
-rw-r--r--src/tools/rust-analyzer/crates/ide-completion/src/completions.rs4
-rw-r--r--src/tools/rust-analyzer/crates/ide-completion/src/completions/attribute.rs2
-rw-r--r--src/tools/rust-analyzer/crates/ide-completion/src/completions/attribute/cfg.rs30
-rw-r--r--src/tools/rust-analyzer/crates/ide-completion/src/completions/expr.rs3
-rw-r--r--src/tools/rust-analyzer/crates/ide-completion/src/completions/record.rs12
-rw-r--r--src/tools/rust-analyzer/crates/ide-completion/src/context.rs1
-rw-r--r--src/tools/rust-analyzer/crates/ide-completion/src/context/analysis.rs30
-rw-r--r--src/tools/rust-analyzer/crates/ide-completion/src/context/tests.rs69
-rw-r--r--src/tools/rust-analyzer/crates/ide-completion/src/render/pattern.rs1
-rw-r--r--src/tools/rust-analyzer/crates/ide-completion/src/tests.rs8
-rw-r--r--src/tools/rust-analyzer/crates/ide-completion/src/tests/attribute.rs84
-rw-r--r--src/tools/rust-analyzer/crates/ide-completion/src/tests/expression.rs132
-rw-r--r--src/tools/rust-analyzer/crates/ide-completion/src/tests/pattern.rs19
-rw-r--r--src/tools/rust-analyzer/crates/ide-completion/src/tests/special.rs25
-rw-r--r--src/tools/rust-analyzer/crates/ide-completion/src/tests/type_pos.rs18
-rw-r--r--src/tools/rust-analyzer/crates/ide-db/src/syntax_helpers/node_ext.rs5
-rw-r--r--src/tools/rust-analyzer/crates/ide-db/src/syntax_helpers/suggest_name.rs2
-rw-r--r--src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/missing_lifetime.rs12
-rw-r--r--src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/missing_unsafe.rs43
-rw-r--r--src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unused_variables.rs82
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/goto_type_definition.rs2
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/hover.rs4
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/hover/render.rs8
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/hover/tests.rs42
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/inlay_hints/bind_pat.rs2
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/inlay_hints/closing_brace.rs2
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/signature_help.rs2
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/static_index.rs2
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_unsafe.html2
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/view_memory_layout.rs10
-rw-r--r--src/tools/rust-analyzer/crates/intern/src/symbol/symbols.rs1
-rw-r--r--src/tools/rust-analyzer/crates/mbe/src/expander/transcriber.rs14
-rw-r--r--src/tools/rust-analyzer/crates/project-model/src/build_dependencies.rs11
-rw-r--r--src/tools/rust-analyzer/crates/project-model/src/cargo_workspace.rs57
-rw-r--r--src/tools/rust-analyzer/crates/rust-analyzer/src/config.rs2
-rw-r--r--src/tools/rust-analyzer/crates/rust-analyzer/src/diagnostics.rs23
-rw-r--r--src/tools/rust-analyzer/crates/rust-analyzer/src/flycheck.rs110
-rw-r--r--src/tools/rust-analyzer/crates/rust-analyzer/src/global_state.rs23
-rw-r--r--src/tools/rust-analyzer/crates/rust-analyzer/src/handlers/notification.rs10
-rw-r--r--src/tools/rust-analyzer/crates/rust-analyzer/src/main_loop.rs19
-rw-r--r--src/tools/rust-analyzer/crates/rust-analyzer/src/target_spec.rs3
-rw-r--r--src/tools/rust-analyzer/crates/stdx/src/lib.rs44
-rw-r--r--src/tools/rust-analyzer/crates/syntax/src/syntax_error.rs2
-rw-r--r--src/tools/rust-analyzer/docs/book/src/configuration_generated.md2
-rw-r--r--src/tools/rust-analyzer/editors/code/package-lock.json6
-rw-r--r--src/tools/rust-analyzer/editors/code/package.json2
-rw-r--r--src/tools/rust-analyzer/rust-version2
-rw-r--r--src/tools/rustfmt/src/config/mod.rs1
-rw-r--r--src/tools/tidy/src/lib.rs11
231 files changed, 6838 insertions, 3837 deletions
diff --git a/src/bootstrap/defaults/bootstrap.dist.toml b/src/bootstrap/defaults/bootstrap.dist.toml
index b111a20f8d8..bb0592ce947 100644
--- a/src/bootstrap/defaults/bootstrap.dist.toml
+++ b/src/bootstrap/defaults/bootstrap.dist.toml
@@ -7,8 +7,6 @@ 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]
diff --git a/src/bootstrap/src/core/build_steps/check.rs b/src/bootstrap/src/core/build_steps/check.rs
index 043457f64e5..20c54a28dda 100644
--- a/src/bootstrap/src/core/build_steps/check.rs
+++ b/src/bootstrap/src/core/build_steps/check.rs
@@ -8,8 +8,8 @@ use crate::core::build_steps::compile::{
 };
 use crate::core::build_steps::tool;
 use crate::core::build_steps::tool::{
-    COMPILETEST_ALLOW_FEATURES, SourceType, TEST_FLOAT_PARSE_ALLOW_FEATURES, ToolTargetBuildMode,
-    get_tool_target_compiler, prepare_tool_cargo,
+    SourceType, TEST_FLOAT_PARSE_ALLOW_FEATURES, ToolTargetBuildMode, get_tool_target_compiler,
+    prepare_tool_cargo,
 };
 use crate::core::builder::{
     self, Alias, Builder, Cargo, Kind, RunConfig, ShouldRun, Step, StepMetadata, crate_description,
@@ -654,7 +654,7 @@ macro_rules! tool_check_step {
             // The part of this path after the final '/' is also used as a display name.
             path: $path:literal
             $(, alt_path: $alt_path:literal )*
-            // Closure that returns `Mode` based on the passed `&Builder<'_>`
+            // `Mode` to use when checking this tool
             , mode: $mode:expr
             // Subset of nightly features that are allowed to be used when checking
             $(, allow_features: $allow_features:expr )?
@@ -682,8 +682,7 @@ macro_rules! tool_check_step {
 
             fn make_run(run: RunConfig<'_>) {
                 let target = run.target;
-                let builder = run.builder;
-                let mode = $mode(builder);
+                let mode: Mode = $mode;
 
                 let compiler = prepare_compiler_for_check(run.builder, target, mode);
 
@@ -704,7 +703,7 @@ macro_rules! tool_check_step {
                     _value
                 };
                 let extra_features: &[&str] = &[$($($enable_features),*)?];
-                let mode = $mode(builder);
+                let mode: Mode = $mode;
                 run_tool_check_step(builder, compiler, target, $path, mode, allow_features, extra_features);
             }
 
@@ -767,57 +766,50 @@ fn run_tool_check_step(
 tool_check_step!(Rustdoc {
     path: "src/tools/rustdoc",
     alt_path: "src/librustdoc",
-    mode: |_builder| Mode::ToolRustcPrivate
+    mode: Mode::ToolRustcPrivate
 });
 // Clippy, miri and Rustfmt are hybrids. They are external tools, but use a git subtree instead
 // of a submodule. Since the SourceType only drives the deny-warnings
 // behavior, treat it as in-tree so that any new warnings in clippy will be
 // rejected.
-tool_check_step!(Clippy { path: "src/tools/clippy", mode: |_builder| Mode::ToolRustcPrivate });
-tool_check_step!(Miri { path: "src/tools/miri", mode: |_builder| Mode::ToolRustcPrivate });
-tool_check_step!(CargoMiri {
-    path: "src/tools/miri/cargo-miri",
-    mode: |_builder| Mode::ToolRustcPrivate
-});
-tool_check_step!(Rustfmt { path: "src/tools/rustfmt", mode: |_builder| Mode::ToolRustcPrivate });
+tool_check_step!(Clippy { path: "src/tools/clippy", mode: Mode::ToolRustcPrivate });
+tool_check_step!(Miri { path: "src/tools/miri", mode: Mode::ToolRustcPrivate });
+tool_check_step!(CargoMiri { path: "src/tools/miri/cargo-miri", mode: Mode::ToolRustcPrivate });
+tool_check_step!(Rustfmt { path: "src/tools/rustfmt", mode: Mode::ToolRustcPrivate });
 tool_check_step!(RustAnalyzer {
     path: "src/tools/rust-analyzer",
-    mode: |_builder| Mode::ToolRustcPrivate,
+    mode: Mode::ToolRustcPrivate,
     allow_features: tool::RustAnalyzer::ALLOW_FEATURES,
     enable_features: ["in-rust-tree"],
 });
 tool_check_step!(MiroptTestTools {
     path: "src/tools/miropt-test-tools",
-    mode: |_builder| Mode::ToolBootstrap
+    mode: Mode::ToolBootstrap
 });
 // We want to test the local std
 tool_check_step!(TestFloatParse {
     path: "src/tools/test-float-parse",
-    mode: |_builder| Mode::ToolStd,
+    mode: Mode::ToolStd,
     allow_features: TEST_FLOAT_PARSE_ALLOW_FEATURES
 });
 tool_check_step!(FeaturesStatusDump {
     path: "src/tools/features-status-dump",
-    mode: |_builder| Mode::ToolBootstrap
+    mode: Mode::ToolBootstrap
 });
 
-tool_check_step!(Bootstrap {
-    path: "src/bootstrap",
-    mode: |_builder| Mode::ToolBootstrap,
-    default: false
-});
+tool_check_step!(Bootstrap { path: "src/bootstrap", mode: Mode::ToolBootstrap, 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",
-    mode: |_builder| Mode::ToolBootstrap,
+    mode: Mode::ToolBootstrap,
     default: false
 });
 
 tool_check_step!(CoverageDump {
     path: "src/tools/coverage-dump",
-    mode: |_builder| Mode::ToolBootstrap,
+    mode: Mode::ToolBootstrap,
     default: false
 });
 
@@ -825,23 +817,18 @@ tool_check_step!(CoverageDump {
 // so this is mainly for people working on compiletest to run locally.
 tool_check_step!(Compiletest {
     path: "src/tools/compiletest",
-    mode: |builder: &Builder<'_>| if builder.config.compiletest_use_stage0_libtest {
-        Mode::ToolBootstrap
-    } else {
-        Mode::ToolStd
-    },
-    allow_features: COMPILETEST_ALLOW_FEATURES,
+    mode: Mode::ToolBootstrap,
     default: false,
 });
 
 tool_check_step!(Linkchecker {
     path: "src/tools/linkchecker",
-    mode: |_builder| Mode::ToolBootstrap,
+    mode: Mode::ToolBootstrap,
     default: false
 });
 
 tool_check_step!(BumpStage0 {
     path: "src/tools/bump-stage0",
-    mode: |_builder| Mode::ToolBootstrap,
+    mode: Mode::ToolBootstrap,
     default: false
 });
diff --git a/src/bootstrap/src/core/build_steps/clippy.rs b/src/bootstrap/src/core/build_steps/clippy.rs
index 2083c675e1f..d5b15d79086 100644
--- a/src/bootstrap/src/core/build_steps/clippy.rs
+++ b/src/bootstrap/src/core/build_steps/clippy.rs
@@ -564,6 +564,7 @@ impl Step for CI {
                 "clippy::same_item_push".into(),
                 "clippy::single_char_add_str".into(),
                 "clippy::to_string_in_format_args".into(),
+                "clippy::unconditional_recursion".into(),
             ],
             forbid: vec![],
         };
@@ -591,6 +592,7 @@ impl Step for CI {
                 "clippy::same_item_push".into(),
                 "clippy::single_char_add_str".into(),
                 "clippy::to_string_in_format_args".into(),
+                "clippy::unconditional_recursion".into(),
             ],
             forbid: vec![],
         };
diff --git a/src/bootstrap/src/core/build_steps/compile.rs b/src/bootstrap/src/core/build_steps/compile.rs
index 14104d7d1d7..96b4e15433f 100644
--- a/src/bootstrap/src/core/build_steps/compile.rs
+++ b/src/bootstrap/src/core/build_steps/compile.rs
@@ -895,6 +895,8 @@ impl Step for StartupObjects {
     fn run(self, builder: &Builder<'_>) -> Vec<(PathBuf, DependencyType)> {
         let for_compiler = self.compiler;
         let target = self.target;
+        // Even though no longer necessary on x86_64, they are kept for now to
+        // avoid potential issues in downstream crates.
         if !target.is_windows_gnu() {
             return vec![];
         }
@@ -1219,7 +1221,7 @@ pub fn rustc_cargo(
     // us a faster startup time. However GNU ld < 2.40 will error if we try to link a shared object
     // with direct references to protected symbols, so for now we only use protected symbols if
     // linking with LLD is enabled.
-    if builder.build.config.lld_mode.is_used() {
+    if builder.build.config.bootstrap_override_lld.is_used() {
         cargo.rustflag("-Zdefault-visibility=protected");
     }
 
@@ -1256,7 +1258,7 @@ pub fn rustc_cargo(
     // is already on by default in MSVC optimized builds, which is interpreted as --icf=all:
     // https://github.com/llvm/llvm-project/blob/3329cec2f79185bafd678f310fafadba2a8c76d2/lld/COFF/Driver.cpp#L1746
     // https://github.com/rust-lang/rust/blob/f22819bcce4abaff7d1246a56eec493418f9f4ee/compiler/rustc_codegen_ssa/src/back/linker.rs#L827
-    if builder.config.lld_mode.is_used() && !build_compiler.host.is_msvc() {
+    if builder.config.bootstrap_override_lld.is_used() && !build_compiler.host.is_msvc() {
         cargo.rustflag("-Clink-args=-Wl,--icf=all");
     }
 
@@ -1832,8 +1834,9 @@ impl Step for Sysroot {
         let sysroot = sysroot_dir(compiler.stage);
         trace!(stage = ?compiler.stage, ?sysroot);
 
-        builder
-            .verbose(|| println!("Removing sysroot {} to avoid caching bugs", sysroot.display()));
+        builder.do_if_verbose(|| {
+            println!("Removing sysroot {} to avoid caching bugs", sysroot.display())
+        });
         let _ = fs::remove_dir_all(&sysroot);
         t!(fs::create_dir_all(&sysroot));
 
@@ -1902,12 +1905,7 @@ impl Step for Sysroot {
                 if !path.parent().is_none_or(|p| p.ends_with(&suffix)) {
                     return true;
                 }
-                if !filtered_files.iter().all(|f| f != path.file_name().unwrap()) {
-                    builder.verbose_than(1, || println!("ignoring {}", path.display()));
-                    false
-                } else {
-                    true
-                }
+                filtered_files.iter().all(|f| f != path.file_name().unwrap())
             });
         }
 
@@ -2596,7 +2594,7 @@ pub fn stream_cargo(
         cmd.arg(arg);
     }
 
-    builder.verbose(|| println!("running: {cmd:?}"));
+    builder.do_if_verbose(|| println!("running: {cmd:?}"));
 
     let streaming_command = cmd.stream_capture_stdout(&builder.config.exec_ctx);
 
diff --git a/src/bootstrap/src/core/build_steps/dist.rs b/src/bootstrap/src/core/build_steps/dist.rs
index 99a1062109a..b79d2cb413d 100644
--- a/src/bootstrap/src/core/build_steps/dist.rs
+++ b/src/bootstrap/src/core/build_steps/dist.rs
@@ -2304,7 +2304,7 @@ fn maybe_install_llvm(
         let mut cmd = command(host_llvm_config);
         cmd.cached();
         cmd.arg("--libfiles");
-        builder.verbose(|| println!("running {cmd:?}"));
+        builder.do_if_verbose(|| println!("running {cmd:?}"));
         let files = cmd.run_capture_stdout(builder).stdout();
         let build_llvm_out = &builder.llvm_out(builder.config.host_target);
         let target_llvm_out = &builder.llvm_out(target);
diff --git a/src/bootstrap/src/core/build_steps/doc.rs b/src/bootstrap/src/core/build_steps/doc.rs
index 7865b685659..37462c63f1b 100644
--- a/src/bootstrap/src/core/build_steps/doc.rs
+++ b/src/bootstrap/src/core/build_steps/doc.rs
@@ -1024,12 +1024,9 @@ macro_rules! tool_doc {
                         run.builder.ensure(Rustc::from_build_compiler(run.builder, compilers.build_compiler(), target));
                         compilers.build_compiler()
                     }
-                    Mode::ToolBootstrap => {
-                        // bootstrap/host tools should be documented with the stage 0 compiler
-                        prepare_doc_compiler(run.builder, run.builder.host_target, 1)
-                    }
                     Mode::ToolTarget => {
-                        // target tools should be documented with the in-tree compiler
+                        // when shipping multiple docs together in one folder,
+                        // they all need to use the same rustdoc version
                         prepare_doc_compiler(run.builder, run.builder.host_target, run.builder.top_stage)
                     }
                     _ => {
@@ -1132,7 +1129,11 @@ macro_rules! tool_doc {
 tool_doc!(
     BuildHelper,
     "src/build_helper",
-    mode = Mode::ToolBootstrap,
+    // ideally, this would use ToolBootstrap,
+    // but we distribute these docs together in the same folder
+    // as a bunch of stage1 tools, and you can't mix rustdoc versions
+    // because that breaks cross-crate data (particularly search)
+    mode = Mode::ToolTarget,
     is_library = true,
     crates = ["build_helper"]
 );
@@ -1175,25 +1176,25 @@ tool_doc!(
     // "specialization" feature in its build script when it detects a nightly toolchain.
     allow_features: "specialization"
 );
-tool_doc!(Tidy, "src/tools/tidy", mode = Mode::ToolBootstrap, crates = ["tidy"]);
+tool_doc!(Tidy, "src/tools/tidy", mode = Mode::ToolTarget, crates = ["tidy"]);
 tool_doc!(
     Bootstrap,
     "src/bootstrap",
-    mode = Mode::ToolBootstrap,
+    mode = Mode::ToolTarget,
     is_library = true,
     crates = ["bootstrap"]
 );
 tool_doc!(
     RunMakeSupport,
     "src/tools/run-make-support",
-    mode = Mode::ToolBootstrap,
+    mode = Mode::ToolTarget,
     is_library = true,
     crates = ["run_make_support"]
 );
 tool_doc!(
     Compiletest,
     "src/tools/compiletest",
-    mode = Mode::ToolBootstrap,
+    mode = Mode::ToolTarget,
     is_library = true,
     crates = ["compiletest"]
 );
diff --git a/src/bootstrap/src/core/build_steps/gcc.rs b/src/bootstrap/src/core/build_steps/gcc.rs
index 717dea37e9e..17ab8c4e2f4 100644
--- a/src/bootstrap/src/core/build_steps/gcc.rs
+++ b/src/bootstrap/src/core/build_steps/gcc.rs
@@ -128,7 +128,7 @@ fn try_download_gcc(builder: &Builder<'_>, target: TargetSelection) -> Option<Pa
         &builder.config,
         builder.config.rust_info.is_managed_git_subrepository(),
     );
-    builder.verbose(|| {
+    builder.do_if_verbose(|| {
         eprintln!("GCC freshness: {source:?}");
     });
     match source {
diff --git a/src/bootstrap/src/core/build_steps/test.rs b/src/bootstrap/src/core/build_steps/test.rs
index e7f5879b5f5..00aea8feab7 100644
--- a/src/bootstrap/src/core/build_steps/test.rs
+++ b/src/bootstrap/src/core/build_steps/test.rs
@@ -18,8 +18,8 @@ use crate::core::build_steps::llvm::get_llvm_version;
 use crate::core::build_steps::run::get_completion_paths;
 use crate::core::build_steps::synthetic_targets::MirOptPanicAbortSyntheticTarget;
 use crate::core::build_steps::tool::{
-    self, COMPILETEST_ALLOW_FEATURES, RustcPrivateCompilers, SourceType,
-    TEST_FLOAT_PARSE_ALLOW_FEATURES, Tool, ToolTargetBuildMode, get_tool_target_compiler,
+    self, RustcPrivateCompilers, SourceType, TEST_FLOAT_PARSE_ALLOW_FEATURES, Tool,
+    ToolTargetBuildMode, get_tool_target_compiler,
 };
 use crate::core::build_steps::toolstate::ToolState;
 use crate::core::build_steps::{compile, dist, llvm};
@@ -36,7 +36,7 @@ use crate::utils::helpers::{
     linker_args, linker_flags, t, target_supports_cranelift_backend, up_to_date,
 };
 use crate::utils::render_tests::{add_flags_and_try_run_tests, try_run_tests};
-use crate::{CLang, CodegenBackendKind, DocTests, GitRepo, Mode, PathSet, debug, envify};
+use crate::{CLang, CodegenBackendKind, DocTests, GitRepo, Mode, PathSet, envify};
 
 const ADB_TEST_DIR: &str = "/data/local/tmp/work";
 
@@ -582,11 +582,11 @@ impl Miri {
         // We re-use the `cargo` from above.
         cargo.arg("--print-sysroot");
 
-        builder.verbose(|| println!("running: {cargo:?}"));
+        builder.do_if_verbose(|| println!("running: {cargo:?}"));
         let stdout = cargo.run_capture_stdout(builder).stdout();
         // Output is "<sysroot>\n".
         let sysroot = stdout.trim_end();
-        builder.verbose(|| println!("`cargo miri setup --print-sysroot` said: {sysroot:?}"));
+        builder.do_if_verbose(|| println!("`cargo miri setup --print-sysroot` said: {sysroot:?}"));
         PathBuf::from(sysroot)
     }
 }
@@ -786,26 +786,26 @@ impl Step for CompiletestTest {
     fn run(self, builder: &Builder<'_>) {
         let host = self.host;
 
+        // Now that compiletest uses only stable Rust, building it always uses
+        // the stage 0 compiler. However, some of its unit tests need to be able
+        // to query information from an in-tree compiler, so we treat `--stage`
+        // as selecting the stage of that secondary compiler.
+
         if builder.top_stage == 0 && !builder.config.compiletest_allow_stage0 {
             eprintln!("\
-ERROR: `--stage 0` runs compiletest self-tests against the stage0 (precompiled) compiler, not the in-tree compiler, and will almost always cause tests to fail
+ERROR: `--stage 0` causes compiletest to query information from the stage0 (precompiled) compiler, instead of the in-tree compiler, which can cause some tests to fail inappropriately
 NOTE: if you're sure you want to do this, please open an issue as to why. In the meantime, you can override this with `--set build.compiletest-allow-stage0=true`."
             );
             crate::exit!(1);
         }
 
-        let compiler = builder.compiler(builder.top_stage, host);
-        debug!(?compiler);
+        let bootstrap_compiler = builder.compiler(0, host);
+        let staged_compiler = builder.compiler(builder.top_stage, host);
 
-        // We need `ToolStd` for the locally-built sysroot because
-        // compiletest uses unstable features of the `test` crate.
-        builder.std(compiler, host);
         let mut cargo = tool::prepare_tool_cargo(
             builder,
-            compiler,
-            // compiletest uses libtest internals; make it use the in-tree std to make sure it never
-            // breaks when std sources change.
-            Mode::ToolStd,
+            bootstrap_compiler,
+            Mode::ToolBootstrap,
             host,
             Kind::Test,
             "src/tools/compiletest",
@@ -816,9 +816,8 @@ NOTE: if you're sure you want to do this, please open an issue as to why. In the
         // Used for `compiletest` self-tests to have the path to the *staged* compiler. Getting this
         // right is important, as `compiletest` is intended to only support one target spec JSON
         // format, namely that of the staged compiler.
-        cargo.env("TEST_RUSTC", builder.rustc(compiler));
+        cargo.env("TEST_RUSTC", builder.rustc(staged_compiler));
 
-        cargo.allow_features(COMPILETEST_ALLOW_FEATURES);
         run_cargo_test(cargo, &[], &[], "compiletest self test", host, builder);
     }
 }
@@ -2675,7 +2674,7 @@ fn markdown_test(builder: &Builder<'_>, compiler: Compiler, markdown: &Path) ->
         return true;
     }
 
-    builder.verbose(|| println!("doc tests for: {}", markdown.display()));
+    builder.do_if_verbose(|| println!("doc tests for: {}", markdown.display()));
     let mut cmd = builder.rustdoc_cmd(compiler);
     builder.add_rust_test_threads(&mut cmd);
     // allow for unstable options such as new editions
diff --git a/src/bootstrap/src/core/build_steps/tool.rs b/src/bootstrap/src/core/build_steps/tool.rs
index 4f096d50ea5..819e903020c 100644
--- a/src/bootstrap/src/core/build_steps/tool.rs
+++ b/src/bootstrap/src/core/build_steps/tool.rs
@@ -380,7 +380,6 @@ macro_rules! bootstrap_tool {
     ($(
         $name:ident, $path:expr, $tool_name:expr
         $(,is_external_tool = $external:expr)*
-        $(,is_unstable_tool = $unstable:expr)*
         $(,allow_features = $allow_features:expr)?
         $(,submodules = $submodules:expr)?
         $(,artifact_kind = $artifact_kind:expr)?
@@ -438,19 +437,11 @@ 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 {
                     build_compiler: self.compiler,
                     target: self.target,
                     tool: $tool_name,
-                    mode: if is_unstable && !compiletest_wants_stage0 {
-                        // use in-tree libraries for unstable features
-                        Mode::ToolStd
-                    } else {
-                        Mode::ToolBootstrap
-                    },
+                    mode: Mode::ToolBootstrap,
                     path: $path,
                     source_type: if false $(|| $external)* {
                         SourceType::Submodule
@@ -483,8 +474,6 @@ macro_rules! bootstrap_tool {
     }
 }
 
-pub(crate) const COMPILETEST_ALLOW_FEATURES: &str = "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
@@ -495,7 +484,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 = COMPILETEST_ALLOW_FEATURES;
+    Compiletest, "src/tools/compiletest", "compiletest";
     BuildManifest, "src/tools/build-manifest", "build-manifest";
     RemoteTestClient, "src/tools/remote-test-client", "remote-test-client";
     RustInstaller, "src/tools/rust-installer", "rust-installer";
@@ -509,8 +498,7 @@ bootstrap_tool!(
     CollectLicenseMetadata, "src/tools/collect-license-metadata", "collect-license-metadata";
     GenerateCopyright, "src/tools/generate-copyright", "generate-copyright";
     GenerateWindowsSys, "src/tools/generate-windows-sys", "generate-windows-sys";
-    // 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;
+    RustdocGUITest, "src/tools/rustdoc-gui-test", "rustdoc-gui-test";
     CoverageDump, "src/tools/coverage-dump", "coverage-dump";
     UnicodeTableGenerator, "src/tools/unicode-table-generator", "unicode-table-generator";
     FeaturesStatusDump, "src/tools/features-status-dump", "features-status-dump";
diff --git a/src/bootstrap/src/core/builder/cargo.rs b/src/bootstrap/src/core/builder/cargo.rs
index ee2bb710674..a404aec5120 100644
--- a/src/bootstrap/src/core/builder/cargo.rs
+++ b/src/bootstrap/src/core/builder/cargo.rs
@@ -10,7 +10,7 @@ use crate::core::config::flags::Color;
 use crate::utils::build_stamp;
 use crate::utils::helpers::{self, LldThreads, check_cfg_arg, linker_args, linker_flags};
 use crate::{
-    BootstrapCommand, CLang, Compiler, Config, DocTests, DryRun, EXTRA_CHECK_CFGS, GitRepo, Mode,
+    BootstrapCommand, CLang, Compiler, Config, DryRun, EXTRA_CHECK_CFGS, GitRepo, Mode,
     RemapScheme, TargetSelection, command, prepare_behaviour_dump_dir, t,
 };
 
@@ -851,8 +851,6 @@ impl Builder<'_> {
 
         rustflags.arg("-Zmacro-backtrace");
 
-        let want_rustdoc = self.doc_tests != DocTests::No;
-
         // Clear the output directory if the real rustc we're using has changed;
         // Cargo cannot detect this as it thinks rustc is bootstrap/debug/rustc.
         //
@@ -881,7 +879,8 @@ impl Builder<'_> {
             .env("RUSTC_REAL", self.rustc(compiler))
             .env("RUSTC_STAGE", build_compiler_stage.to_string())
             .env("RUSTC_SYSROOT", sysroot)
-            .env("RUSTC_LIBDIR", libdir)
+            .env("RUSTC_LIBDIR", &libdir)
+            .env("RUSTDOC_LIBDIR", libdir)
             .env("RUSTDOC", self.bootstrap_out.join("rustdoc"))
             .env("RUSTDOC_REAL", rustdoc_path)
             .env("RUSTC_ERROR_METADATA_DST", self.extended_error_dir());
@@ -919,11 +918,6 @@ impl Builder<'_> {
             rustflags.arg(&format!("-Zstack-protector={stack_protector}"));
         }
 
-        if !matches!(cmd_kind, Kind::Build | Kind::Check | Kind::Clippy | Kind::Fix) && want_rustdoc
-        {
-            cargo.env("RUSTDOC_LIBDIR", self.rustc_libdir(compiler));
-        }
-
         let debuginfo_level = match mode {
             Mode::Rustc | Mode::Codegen => self.config.rust_debuginfo_level_rustc,
             Mode::Std => self.config.rust_debuginfo_level_std,
@@ -1139,7 +1133,7 @@ impl Builder<'_> {
             cargo.env("RUSTC_BACKTRACE_ON_ICE", "1");
         }
 
-        if self.is_verbose_than(1) {
+        if self.verbosity >= 2 {
             // This provides very useful logs especially when debugging build cache-related stuff.
             cargo.env("CARGO_LOG", "cargo::core::compiler::fingerprint=info");
         }
diff --git a/src/bootstrap/src/core/builder/mod.rs b/src/bootstrap/src/core/builder/mod.rs
index 8226b4325b6..fc06db8f80b 100644
--- a/src/bootstrap/src/core/builder/mod.rs
+++ b/src/bootstrap/src/core/builder/mod.rs
@@ -545,7 +545,7 @@ impl StepDescription {
         if !builder.config.skip.is_empty()
             && !matches!(builder.config.get_dry_run(), DryRun::SelfCheck)
         {
-            builder.verbose(|| {
+            builder.do_if_verbose(|| {
                 println!(
                     "{:?} not skipped for {:?} -- not in {:?}",
                     pathset, self.name, builder.config.skip
@@ -947,7 +947,7 @@ impl Step for Libdir {
             // Sysroot`).
             if !builder.download_rustc() {
                 let sysroot_target_libdir = sysroot.join(self.target).join("lib");
-                builder.verbose(|| {
+                builder.do_if_verbose(|| {
                     eprintln!(
                         "Removing sysroot {} to avoid caching bugs",
                         sysroot_target_libdir.display()
@@ -1145,7 +1145,7 @@ impl<'a> Builder<'a> {
                 test::RunMakeCargo,
             ),
             Kind::Miri => describe!(test::Crate),
-            Kind::Bench => describe!(test::Crate, test::CrateLibrustc),
+            Kind::Bench => describe!(test::Crate, test::CrateLibrustc, test::CrateRustdoc),
             Kind::Doc => describe!(
                 doc::UnstableBook,
                 doc::UnstableBookGen,
@@ -1221,6 +1221,8 @@ impl<'a> Builder<'a> {
                 install::Miri,
                 install::LlvmTools,
                 install::Src,
+                install::RustcCodegenCranelift,
+                install::LlvmBitcodeLinker
             ),
             Kind::Run => describe!(
                 run::BuildManifest,
diff --git a/src/bootstrap/src/core/builder/tests.rs b/src/bootstrap/src/core/builder/tests.rs
index 229adf71459..3306435758b 100644
--- a/src/bootstrap/src/core/builder/tests.rs
+++ b/src/bootstrap/src/core/builder/tests.rs
@@ -22,13 +22,7 @@ fn configure(cmd: &str, host: &[&str], target: &[&str]) -> Config {
 }
 
 fn configure_with_args(cmd: &[&str], host: &[&str], target: &[&str]) -> Config {
-    TestCtx::new()
-        .config(cmd[0])
-        .args(&cmd[1..])
-        .hosts(host)
-        .targets(target)
-        .args(&["--build", TEST_TRIPLE_1])
-        .create_config()
+    TestCtx::new().config(cmd[0]).args(&cmd[1..]).hosts(host).targets(target).create_config()
 }
 
 fn first<A, B>(v: Vec<(A, B)>) -> Vec<A> {
@@ -218,18 +212,17 @@ fn prepare_rustc_checkout(ctx: &mut GitCtx) {
 
 /// Parses a Config directory from `path`, with the given value of `download_rustc`.
 fn parse_config_download_rustc_at(path: &Path, download_rustc: &str, ci: bool) -> Config {
-    Config::parse_inner(
-        Flags::parse(&[
-            "build".to_owned(),
-            "--dry-run".to_owned(),
-            "--ci".to_owned(),
-            if ci { "true" } else { "false" }.to_owned(),
-            format!("--set=rust.download-rustc='{download_rustc}'"),
-            "--src".to_owned(),
-            path.to_str().unwrap().to_owned(),
-        ]),
-        |&_| Ok(Default::default()),
-    )
+    TestCtx::new()
+        .config("build")
+        .args(&[
+            "--ci",
+            if ci { "true" } else { "false" },
+            format!("--set=rust.download-rustc='{download_rustc}'").as_str(),
+            "--src",
+            path.to_str().unwrap(),
+        ])
+        .no_override_download_ci_llvm()
+        .create_config()
 }
 
 mod dist {
@@ -237,6 +230,7 @@ mod dist {
 
     use super::{Config, TEST_TRIPLE_1, TEST_TRIPLE_2, TEST_TRIPLE_3, first, run_build};
     use crate::Flags;
+    use crate::core::builder::tests::host_target;
     use crate::core::builder::*;
 
     fn configure(host: &[&str], target: &[&str]) -> Config {
@@ -245,11 +239,11 @@ mod dist {
 
     #[test]
     fn llvm_out_behaviour() {
-        let mut config = configure(&[TEST_TRIPLE_1], &[TEST_TRIPLE_2]);
+        let mut config = configure(&[], &[TEST_TRIPLE_2]);
         config.llvm_from_ci = true;
         let build = Build::new(config.clone());
 
-        let target = TargetSelection::from_user(TEST_TRIPLE_1);
+        let target = TargetSelection::from_user(&host_target());
         assert!(build.llvm_out(target).ends_with("ci-llvm"));
         let target = TargetSelection::from_user(TEST_TRIPLE_2);
         assert!(build.llvm_out(target).ends_with("llvm"));
@@ -314,7 +308,7 @@ mod sysroot_target_dirs {
 /// cg_gcc tests instead.
 #[test]
 fn test_test_compiler() {
-    let config = configure_with_args(&["test", "compiler"], &[TEST_TRIPLE_1], &[TEST_TRIPLE_1]);
+    let config = configure_with_args(&["test", "compiler"], &[&host_target()], &[TEST_TRIPLE_1]);
     let cache = run_build(&config.paths.clone(), config);
 
     let compiler = cache.contains::<test::CrateLibrustc>();
@@ -347,7 +341,7 @@ fn test_test_coverage() {
         // Print each test case so that if one fails, the most recently printed
         // case is the one that failed.
         println!("Testing case: {cmd:?}");
-        let config = configure_with_args(cmd, &[TEST_TRIPLE_1], &[TEST_TRIPLE_1]);
+        let config = configure_with_args(cmd, &[], &[TEST_TRIPLE_1]);
         let mut cache = run_build(&config.paths.clone(), config);
 
         let modes =
@@ -359,14 +353,7 @@ fn test_test_coverage() {
 #[test]
 fn test_prebuilt_llvm_config_path_resolution() {
     fn configure(config: &str) -> Config {
-        Config::parse_inner(
-            Flags::parse(&[
-                "build".to_string(),
-                "--dry-run".to_string(),
-                "--config=/does/not/exist".to_string(),
-            ]),
-            |&_| toml::from_str(&config),
-        )
+        TestCtx::new().config("build").with_default_toml_config(config).create_config()
     }
 
     // Removes Windows disk prefix if present
@@ -1171,13 +1158,12 @@ mod snapshot {
         [doc] embedded-book (book) <host>
         [doc] edition-guide (book) <host>
         [doc] style-guide (book) <host>
-        [build] rustdoc 0 <host>
-        [doc] rustc 0 <host> -> Tidy 1 <host>
-        [doc] rustc 0 <host> -> Bootstrap 1 <host>
+        [doc] rustc 1 <host> -> Tidy 2 <host>
+        [doc] rustc 1 <host> -> Bootstrap 2 <host>
         [doc] rustc 1 <host> -> releases 2 <host>
-        [doc] rustc 0 <host> -> RunMakeSupport 1 <host>
-        [doc] rustc 0 <host> -> BuildHelper 1 <host>
-        [doc] rustc 0 <host> -> Compiletest 1 <host>
+        [doc] rustc 1 <host> -> RunMakeSupport 2 <host>
+        [doc] rustc 1 <host> -> BuildHelper 2 <host>
+        [doc] rustc 1 <host> -> Compiletest 2 <host>
         [build] rustc 0 <host> -> RustInstaller 1 <host>
         "
         );
@@ -2018,21 +2004,6 @@ mod snapshot {
     }
 
     #[test]
-    fn check_compiletest_stage1_libtest() {
-        let ctx = TestCtx::new();
-        insta::assert_snapshot!(
-            ctx.config("check")
-                .path("compiletest")
-                .args(&["--set", "build.compiletest-use-stage0-libtest=false"])
-                .render_steps(), @r"
-        [build] llvm <host>
-        [build] rustc 0 <host> -> rustc 1 <host>
-        [build] rustc 1 <host> -> std 1 <host>
-        [check] rustc 1 <host> -> Compiletest 2 <host>
-        ");
-    }
-
-    #[test]
     fn check_codegen() {
         let ctx = TestCtx::new();
         insta::assert_snapshot!(
@@ -2159,6 +2130,17 @@ mod snapshot {
     }
 
     #[test]
+    fn test_compiletest_self_test() {
+        let ctx = TestCtx::new();
+        let steps = ctx.config("test").arg("compiletest").render_steps();
+        insta::assert_snapshot!(steps, @r"
+        [build] llvm <host>
+        [build] rustc 0 <host> -> rustc 1 <host>
+        [build] rustdoc 0 <host>
+        ");
+    }
+
+    #[test]
     fn test_compiletest_suites_stage1() {
         let ctx = TestCtx::new();
         insta::assert_snapshot!(
@@ -2703,8 +2685,11 @@ mod snapshot {
                 .path("src/tools/compiletest")
                 .stage(2)
                 .render_steps(), @r"
-        [build] rustdoc 0 <host>
-        [doc] rustc 0 <host> -> Compiletest 1 <host>
+        [build] llvm <host>
+        [build] rustc 0 <host> -> rustc 1 <host>
+        [build] rustc 1 <host> -> std 1 <host>
+        [build] rustdoc 1 <host>
+        [doc] rustc 1 <host> -> Compiletest 2 <host>
         ");
     }
 
@@ -2857,60 +2842,69 @@ mod snapshot {
                     // Using backslashes fails with `--set`
                     "--set", &format!("install.prefix={}", ctx.dir().display()).replace("\\", "/"),
                     "--set", &format!("install.sysconfdir={}", ctx.dir().display()).replace("\\", "/"),
-                    "--set", "build.extended=true"
+                    "--set", "build.extended=true",
+                    // For Cranelift to be disted
+                    "--build", "x86_64-unknown-linux-gnu",
+                    "--host", "x86_64-unknown-linux-gnu"
                 ])
-                .render_steps(), @r"
-        [build] llvm <host>
-        [build] rustc 0 <host> -> rustc 1 <host>
-        [build] rustc 0 <host> -> WasmComponentLd 1 <host>
-        [build] rustc 0 <host> -> UnstableBookGen 1 <host>
-        [build] rustc 0 <host> -> Rustbook 1 <host>
-        [doc] unstable-book (book) <host>
-        [build] rustc 1 <host> -> std 1 <host>
-        [doc] book (book) <host>
-        [doc] book/first-edition (book) <host>
-        [doc] book/second-edition (book) <host>
-        [doc] book/2018-edition (book) <host>
-        [build] rustdoc 1 <host>
-        [doc] rustc 1 <host> -> standalone 2 <host>
-        [doc] rustc 1 <host> -> std 1 <host> crates=[alloc,compiler_builtins,core,panic_abort,panic_unwind,proc_macro,rustc-std-workspace-core,std,std_detect,sysroot,test,unwind]
-        [build] rustc 1 <host> -> rustc 2 <host>
-        [build] rustc 1 <host> -> WasmComponentLd 2 <host>
-        [build] rustc 1 <host> -> error-index 2 <host>
-        [doc] rustc 1 <host> -> error-index 2 <host>
-        [doc] nomicon (book) <host>
-        [doc] rustc 1 <host> -> reference (book) 2 <host>
-        [doc] rustdoc (book) <host>
-        [doc] rust-by-example (book) <host>
-        [build] rustc 0 <host> -> LintDocs 1 <host>
-        [doc] rustc (book) <host>
-        [doc] cargo (book) <host>
-        [doc] clippy (book) <host>
-        [doc] embedded-book (book) <host>
-        [doc] edition-guide (book) <host>
-        [doc] style-guide (book) <host>
-        [doc] rustc 1 <host> -> releases 2 <host>
-        [build] rustc 0 <host> -> RustInstaller 1 <host>
-        [dist] docs <host>
-        [dist] rustc 1 <host> -> std 1 <host>
-        [build] rustdoc 2 <host>
-        [build] rustc 1 <host> -> rust-analyzer-proc-macro-srv 2 <host>
-        [build] rustc 0 <host> -> GenerateCopyright 1 <host>
-        [dist] rustc <host>
-        [build] rustc 1 <host> -> cargo 2 <host>
-        [dist] rustc 1 <host> -> cargo 2 <host>
-        [build] rustc 1 <host> -> rust-analyzer 2 <host>
-        [dist] rustc 1 <host> -> rust-analyzer 2 <host>
-        [build] rustc 1 <host> -> rustfmt 2 <host>
-        [build] rustc 1 <host> -> cargo-fmt 2 <host>
-        [dist] rustc 1 <host> -> rustfmt 2 <host>
-        [build] rustc 1 <host> -> clippy-driver 2 <host>
-        [build] rustc 1 <host> -> cargo-clippy 2 <host>
-        [dist] rustc 1 <host> -> clippy 2 <host>
-        [build] rustc 1 <host> -> miri 2 <host>
-        [build] rustc 1 <host> -> cargo-miri 2 <host>
-        [dist] rustc 1 <host> -> miri 2 <host>
+                .get_steps()
+                .render_with(RenderConfig {
+                    normalize_host: false
+                }), @r"
+        [build] llvm <x86_64-unknown-linux-gnu>
+        [build] rustc 0 <x86_64-unknown-linux-gnu> -> rustc 1 <x86_64-unknown-linux-gnu>
+        [build] rustc 0 <x86_64-unknown-linux-gnu> -> WasmComponentLd 1 <x86_64-unknown-linux-gnu>
+        [build] rustc 0 <x86_64-unknown-linux-gnu> -> UnstableBookGen 1 <x86_64-unknown-linux-gnu>
+        [build] rustc 0 <x86_64-unknown-linux-gnu> -> Rustbook 1 <x86_64-unknown-linux-gnu>
+        [doc] unstable-book (book) <x86_64-unknown-linux-gnu>
+        [build] rustc 1 <x86_64-unknown-linux-gnu> -> std 1 <x86_64-unknown-linux-gnu>
+        [doc] book (book) <x86_64-unknown-linux-gnu>
+        [doc] book/first-edition (book) <x86_64-unknown-linux-gnu>
+        [doc] book/second-edition (book) <x86_64-unknown-linux-gnu>
+        [doc] book/2018-edition (book) <x86_64-unknown-linux-gnu>
+        [build] rustdoc 1 <x86_64-unknown-linux-gnu>
+        [doc] rustc 1 <x86_64-unknown-linux-gnu> -> standalone 2 <x86_64-unknown-linux-gnu>
+        [doc] rustc 1 <x86_64-unknown-linux-gnu> -> std 1 <x86_64-unknown-linux-gnu> crates=[alloc,compiler_builtins,core,panic_abort,panic_unwind,proc_macro,rustc-std-workspace-core,std,std_detect,sysroot,test,unwind]
+        [build] rustc 1 <x86_64-unknown-linux-gnu> -> rustc 2 <x86_64-unknown-linux-gnu>
+        [build] rustc 1 <x86_64-unknown-linux-gnu> -> WasmComponentLd 2 <x86_64-unknown-linux-gnu>
+        [build] rustc 1 <x86_64-unknown-linux-gnu> -> error-index 2 <x86_64-unknown-linux-gnu>
+        [doc] rustc 1 <x86_64-unknown-linux-gnu> -> error-index 2 <x86_64-unknown-linux-gnu>
+        [doc] nomicon (book) <x86_64-unknown-linux-gnu>
+        [doc] rustc 1 <x86_64-unknown-linux-gnu> -> reference (book) 2 <x86_64-unknown-linux-gnu>
+        [doc] rustdoc (book) <x86_64-unknown-linux-gnu>
+        [doc] rust-by-example (book) <x86_64-unknown-linux-gnu>
+        [build] rustc 0 <x86_64-unknown-linux-gnu> -> LintDocs 1 <x86_64-unknown-linux-gnu>
+        [doc] rustc (book) <x86_64-unknown-linux-gnu>
+        [doc] cargo (book) <x86_64-unknown-linux-gnu>
+        [doc] clippy (book) <x86_64-unknown-linux-gnu>
+        [doc] embedded-book (book) <x86_64-unknown-linux-gnu>
+        [doc] edition-guide (book) <x86_64-unknown-linux-gnu>
+        [doc] style-guide (book) <x86_64-unknown-linux-gnu>
+        [doc] rustc 1 <x86_64-unknown-linux-gnu> -> releases 2 <x86_64-unknown-linux-gnu>
+        [build] rustc 0 <x86_64-unknown-linux-gnu> -> RustInstaller 1 <x86_64-unknown-linux-gnu>
+        [dist] docs <x86_64-unknown-linux-gnu>
+        [dist] rustc 1 <x86_64-unknown-linux-gnu> -> std 1 <x86_64-unknown-linux-gnu>
+        [build] rustdoc 2 <x86_64-unknown-linux-gnu>
+        [build] rustc 1 <x86_64-unknown-linux-gnu> -> rust-analyzer-proc-macro-srv 2 <x86_64-unknown-linux-gnu>
+        [build] rustc 0 <x86_64-unknown-linux-gnu> -> GenerateCopyright 1 <x86_64-unknown-linux-gnu>
+        [dist] rustc <x86_64-unknown-linux-gnu>
+        [build] rustc 1 <x86_64-unknown-linux-gnu> -> cargo 2 <x86_64-unknown-linux-gnu>
+        [dist] rustc 1 <x86_64-unknown-linux-gnu> -> cargo 2 <x86_64-unknown-linux-gnu>
+        [build] rustc 1 <x86_64-unknown-linux-gnu> -> rust-analyzer 2 <x86_64-unknown-linux-gnu>
+        [dist] rustc 1 <x86_64-unknown-linux-gnu> -> rust-analyzer 2 <x86_64-unknown-linux-gnu>
+        [build] rustc 1 <x86_64-unknown-linux-gnu> -> rustfmt 2 <x86_64-unknown-linux-gnu>
+        [build] rustc 1 <x86_64-unknown-linux-gnu> -> cargo-fmt 2 <x86_64-unknown-linux-gnu>
+        [dist] rustc 1 <x86_64-unknown-linux-gnu> -> rustfmt 2 <x86_64-unknown-linux-gnu>
+        [build] rustc 1 <x86_64-unknown-linux-gnu> -> clippy-driver 2 <x86_64-unknown-linux-gnu>
+        [build] rustc 1 <x86_64-unknown-linux-gnu> -> cargo-clippy 2 <x86_64-unknown-linux-gnu>
+        [dist] rustc 1 <x86_64-unknown-linux-gnu> -> clippy 2 <x86_64-unknown-linux-gnu>
+        [build] rustc 1 <x86_64-unknown-linux-gnu> -> miri 2 <x86_64-unknown-linux-gnu>
+        [build] rustc 1 <x86_64-unknown-linux-gnu> -> cargo-miri 2 <x86_64-unknown-linux-gnu>
+        [dist] rustc 1 <x86_64-unknown-linux-gnu> -> miri 2 <x86_64-unknown-linux-gnu>
         [dist] src <>
+        [build] rustc 1 <x86_64-unknown-linux-gnu> -> rustc_codegen_cranelift 2 <x86_64-unknown-linux-gnu>
+        [dist] rustc 1 <x86_64-unknown-linux-gnu> -> rustc_codegen_cranelift 2 <x86_64-unknown-linux-gnu>
+        [build] rustc 1 <x86_64-unknown-linux-gnu> -> LlvmBitcodeLinker 2 <x86_64-unknown-linux-gnu>
         ");
     }
 
diff --git a/src/bootstrap/src/core/config/config.rs b/src/bootstrap/src/core/config/config.rs
index dd2d5a1fd53..1fcc1174e85 100644
--- a/src/bootstrap/src/core/config/config.rs
+++ b/src/bootstrap/src/core/config/config.rs
@@ -41,7 +41,7 @@ use crate::core::config::toml::gcc::Gcc;
 use crate::core::config::toml::install::Install;
 use crate::core::config::toml::llvm::Llvm;
 use crate::core::config::toml::rust::{
-    LldMode, Rust, RustOptimize, check_incompatible_options_for_ci_rustc,
+    BootstrapOverrideLld, Rust, RustOptimize, check_incompatible_options_for_ci_rustc,
     default_lld_opt_in_targets, parse_codegen_backends,
 };
 use crate::core::config::toml::target::Target;
@@ -174,7 +174,7 @@ pub struct Config {
     pub llvm_from_ci: bool,
     pub llvm_build_config: HashMap<String, String>,
 
-    pub lld_mode: LldMode,
+    pub bootstrap_override_lld: BootstrapOverrideLld,
     pub lld_enabled: bool,
     pub llvm_tools_enabled: bool,
     pub llvm_bitcode_linker_enabled: bool,
@@ -310,9 +310,6 @@ pub struct Config {
     /// sources.
     pub compiletest_allow_stage0: bool,
 
-    /// Whether to use the precompiled stage0 libtest with compiletest.
-    pub compiletest_use_stage0_libtest: bool,
-
     /// Default value for `--extra-checks`
     pub tidy_extra_checks: Option<String>,
     pub is_running_on_ci: bool,
@@ -414,14 +411,28 @@ impl Config {
         // Set config values based on flags.
         let mut exec_ctx = ExecutionContext::new(flags_verbose, flags_cmd.fail_fast());
         exec_ctx.set_dry_run(if flags_dry_run { DryRun::UserSelected } else { DryRun::Disabled });
-        let mut src = {
+
+        let default_src_dir = {
             let manifest_dir = PathBuf::from(env!("CARGO_MANIFEST_DIR"));
             // Undo `src/bootstrap`
             manifest_dir.parent().unwrap().parent().unwrap().to_owned()
         };
+        let src = if let Some(s) = compute_src_directory(flags_src, &exec_ctx) {
+            s
+        } else {
+            default_src_dir.clone()
+        };
 
-        if let Some(src_) = compute_src_directory(flags_src, &exec_ctx) {
-            src = src_;
+        #[cfg(test)]
+        {
+            if let Some(config_path) = flags_config.as_ref() {
+                assert!(
+                    !config_path.starts_with(&src),
+                    "Path {config_path:?} should not be inside or equal to src dir {src:?}"
+                );
+            } else {
+                panic!("During test the config should be explicitly added");
+            }
         }
 
         // Now load the TOML config, as soon as possible
@@ -483,7 +494,8 @@ impl Config {
             optimized_compiler_builtins: build_optimized_compiler_builtins,
             jobs: build_jobs,
             compiletest_diff_tool: build_compiletest_diff_tool,
-            compiletest_use_stage0_libtest: build_compiletest_use_stage0_libtest,
+            // No longer has any effect; kept (for now) to avoid breaking people's configs.
+            compiletest_use_stage0_libtest: _,
             tidy_extra_checks: build_tidy_extra_checks,
             ccache: build_ccache,
             exclude: build_exclude,
@@ -553,7 +565,8 @@ impl Config {
             frame_pointers: rust_frame_pointers,
             stack_protector: rust_stack_protector,
             strip: rust_strip,
-            lld_mode: rust_lld_mode,
+            bootstrap_override_lld: rust_bootstrap_override_lld,
+            bootstrap_override_lld_legacy: rust_bootstrap_override_lld_legacy,
             std_features: rust_std_features,
             break_on_ice: rust_break_on_ice,
         } = toml.rust.unwrap_or_default();
@@ -601,6 +614,15 @@ impl Config {
 
         let Gcc { download_ci_gcc: gcc_download_ci_gcc } = toml.gcc.unwrap_or_default();
 
+        if rust_bootstrap_override_lld.is_some() && rust_bootstrap_override_lld_legacy.is_some() {
+            panic!(
+                "Cannot use both `rust.use-lld` and `rust.bootstrap-override-lld`. Please use only `rust.bootstrap-override-lld`"
+            );
+        }
+
+        let bootstrap_override_lld =
+            rust_bootstrap_override_lld.or(rust_bootstrap_override_lld_legacy).unwrap_or_default();
+
         if rust_optimize.as_ref().is_some_and(|v| matches!(v, RustOptimize::Bool(false))) {
             eprintln!(
                 "WARNING: setting `optimize` to `false` is known to cause errors and \
@@ -630,19 +652,13 @@ impl Config {
         let llvm_assertions = llvm_assertions.unwrap_or(false);
         let mut target_config = HashMap::new();
         let mut channel = "dev".to_string();
-        let out = flags_build_dir.or(build_build_dir.map(PathBuf::from)).unwrap_or_else(|| {
-            if cfg!(test) {
-                // Use the build directory of the original x.py invocation, so that we can set `initial_rustc` properly.
-                Path::new(
-                    &env::var_os("CARGO_TARGET_DIR").expect("cargo test directly is not supported"),
-                )
-                .parent()
-                .unwrap()
-                .to_path_buf()
-            } else {
-                PathBuf::from("build")
-            }
-        });
+
+        let out = flags_build_dir.or_else(|| build_build_dir.map(PathBuf::from));
+        let out = if cfg!(test) {
+            out.expect("--build-dir has to be specified in tests")
+        } else {
+            out.unwrap_or_else(|| PathBuf::from("build"))
+        };
 
         // NOTE: Bootstrap spawns various commands with different working directories.
         // To avoid writing to random places on the file system, `config.out` needs to be an absolute path.
@@ -653,6 +669,10 @@ impl Config {
             out
         };
 
+        let default_stage0_rustc_path = |dir: &Path| {
+            dir.join(host_target).join("stage0").join("bin").join(exe("rustc", host_target))
+        };
+
         if cfg!(test) {
             // When configuring bootstrap for tests, make sure to set the rustc and Cargo to the
             // same ones used to call the tests (if custom ones are not defined in the toml). If we
@@ -661,6 +681,22 @@ impl Config {
             // Cargo in their bootstrap.toml.
             build_rustc = build_rustc.take().or(std::env::var_os("RUSTC").map(|p| p.into()));
             build_cargo = build_cargo.take().or(std::env::var_os("CARGO").map(|p| p.into()));
+
+            // If we are running only `cargo test` (and not `x test bootstrap`), which is useful
+            // e.g. for debugging bootstrap itself, then we won't have RUSTC and CARGO set to the
+            // proper paths.
+            // We thus "guess" that the build directory is located at <src>/build, and try to load
+            // rustc and cargo from there
+            let is_test_outside_x = std::env::var("CARGO_TARGET_DIR").is_err();
+            if is_test_outside_x && build_rustc.is_none() {
+                let stage0_rustc = default_stage0_rustc_path(&default_src_dir.join("build"));
+                assert!(
+                    stage0_rustc.exists(),
+                    "Trying to run cargo test without having a stage0 rustc available in {}",
+                    stage0_rustc.display()
+                );
+                build_rustc = Some(stage0_rustc);
+            }
         }
 
         if !flags_skip_stage0_validation {
@@ -694,7 +730,7 @@ impl Config {
 
         let initial_rustc = build_rustc.unwrap_or_else(|| {
             download_beta_toolchain(&dwn_ctx, &out);
-            out.join(host_target).join("stage0").join("bin").join(exe("rustc", host_target))
+            default_stage0_rustc_path(&out)
         });
 
         let initial_sysroot = t!(PathBuf::from_str(
@@ -932,7 +968,7 @@ impl Config {
 
         let initial_rustfmt = build_rustfmt.or_else(|| maybe_download_rustfmt(&dwn_ctx, &out));
 
-        if matches!(rust_lld_mode.unwrap_or_default(), LldMode::SelfContained)
+        if matches!(bootstrap_override_lld, BootstrapOverrideLld::SelfContained)
             && !lld_enabled
             && flags_stage.unwrap_or(0) > 0
         {
@@ -1144,6 +1180,7 @@ impl Config {
             backtrace_on_ice: rust_backtrace_on_ice.unwrap_or(false),
             bindir: install_bindir.map(PathBuf::from).unwrap_or("bin".into()),
             bootstrap_cache_path: build_bootstrap_cache_path,
+            bootstrap_override_lld,
             bypass_bootstrap_lock: flags_bypass_bootstrap_lock,
             cargo_info,
             cargo_native_static: build_cargo_native_static.unwrap_or(false),
@@ -1158,7 +1195,6 @@ impl Config {
             compiler_docs: build_compiler_docs.unwrap_or(false),
             compiletest_allow_stage0: build_compiletest_allow_stage0.unwrap_or(false),
             compiletest_diff_tool: build_compiletest_diff_tool,
-            compiletest_use_stage0_libtest: build_compiletest_use_stage0_libtest.unwrap_or(true),
             config: toml_path,
             configure_args: build_configure_args.unwrap_or_default(),
             control_flow_guard: rust_control_flow_guard.unwrap_or(false),
@@ -1210,7 +1246,6 @@ impl Config {
             libdir: install_libdir.map(PathBuf::from),
             library_docs_private_items: build_library_docs_private_items.unwrap_or(false),
             lld_enabled,
-            lld_mode: rust_lld_mode.unwrap_or_default(),
             lldb: build_lldb.map(PathBuf::from),
             llvm_allow_old_toolchain: llvm_allow_old_toolchain.unwrap_or(false),
             llvm_assertions,
@@ -1534,11 +1569,11 @@ impl Config {
                                 println!("WARNING: CI rustc has some fields that are no longer supported in bootstrap; download-rustc will be disabled.");
                                 println!("HELP: Consider rebasing to a newer commit if available.");
                                 return None;
-                            },
+                            }
                             Err(e) => {
                                 eprintln!("ERROR: Failed to parse CI rustc bootstrap.toml: {e}");
                                 exit!(2);
-                            },
+                            }
                         };
 
                         let current_config_toml = Self::get_toml(config_path).unwrap();
@@ -1571,8 +1606,8 @@ impl Config {
     }
 
     /// Runs a function if verbosity is greater than 0
-    pub fn verbose(&self, f: impl Fn()) {
-        self.exec_ctx.verbose(f);
+    pub fn do_if_verbose(&self, f: impl Fn()) {
+        self.exec_ctx.do_if_verbose(f);
     }
 
     pub fn any_sanitizers_to_build(&self) -> bool {
@@ -2061,7 +2096,7 @@ pub fn download_ci_rustc_commit<'a>(
         // Look for a version to compare to based on the current commit.
         // Only commits merged by bors will have CI artifacts.
         let freshness = check_path_modifications_(dwn_ctx, RUSTC_IF_UNCHANGED_ALLOWED_PATHS);
-        dwn_ctx.exec_ctx.verbose(|| {
+        dwn_ctx.exec_ctx.do_if_verbose(|| {
             eprintln!("rustc freshness: {freshness:?}");
         });
         match freshness {
diff --git a/src/bootstrap/src/core/config/mod.rs b/src/bootstrap/src/core/config/mod.rs
index 05a5dfc0bc5..007ed4aaba1 100644
--- a/src/bootstrap/src/core/config/mod.rs
+++ b/src/bootstrap/src/core/config/mod.rs
@@ -37,7 +37,7 @@ use serde_derive::Deserialize;
 pub use target_selection::TargetSelection;
 pub use toml::BUILDER_CONFIG_FILENAME;
 pub use toml::change_id::ChangeId;
-pub use toml::rust::LldMode;
+pub use toml::rust::BootstrapOverrideLld;
 pub use toml::target::Target;
 
 use crate::Display;
@@ -47,11 +47,17 @@ use crate::str::FromStr;
 #[macro_export]
 macro_rules! define_config {
     ($(#[$attr:meta])* struct $name:ident {
-        $($field:ident: Option<$field_ty:ty> = $field_key:literal,)*
+        $(
+            $(#[$field_attr:meta])*
+            $field:ident: Option<$field_ty:ty> = $field_key:literal,
+        )*
     }) => {
         $(#[$attr])*
         pub struct $name {
-            $(pub $field: Option<$field_ty>,)*
+            $(
+                $(#[$field_attr])*
+                pub $field: Option<$field_ty>,
+            )*
         }
 
         impl Merge for $name {
diff --git a/src/bootstrap/src/core/config/tests.rs b/src/bootstrap/src/core/config/tests.rs
index e93525fbd09..e19604d4ab1 100644
--- a/src/bootstrap/src/core/config/tests.rs
+++ b/src/bootstrap/src/core/config/tests.rs
@@ -14,17 +14,17 @@ use super::toml::change_id::ChangeIdWrapper;
 use super::{Config, RUSTC_IF_UNCHANGED_ALLOWED_PATHS};
 use crate::ChangeId;
 use crate::core::build_steps::clippy::{LintConfig, get_clippy_rules_in_order};
-use crate::core::build_steps::llvm;
 use crate::core::build_steps::llvm::LLVM_INVALIDATION_PATHS;
+use crate::core::build_steps::{llvm, test};
 use crate::core::config::toml::TomlConfig;
-use crate::core::config::{CompilerBuiltins, LldMode, StringOrBool, Target, TargetSelection};
+use crate::core::config::{
+    BootstrapOverrideLld, CompilerBuiltins, StringOrBool, Target, TargetSelection,
+};
+use crate::utils::tests::TestCtx;
 use crate::utils::tests::git::git_test;
 
 pub(crate) fn parse(config: &str) -> Config {
-    Config::parse_inner(
-        Flags::parse(&["check".to_string(), "--config=/does/not/exist".to_string()]),
-        |&_| toml::from_str(&config),
-    )
+    TestCtx::new().config("check").with_default_toml_config(config).create_config()
 }
 
 fn get_toml(file: &Path) -> Result<TomlConfig, toml::de::Error> {
@@ -32,28 +32,16 @@ fn get_toml(file: &Path) -> Result<TomlConfig, toml::de::Error> {
     toml::from_str(&contents).and_then(|table: toml::Value| TomlConfig::deserialize(table))
 }
 
-/// Helps with debugging by using consistent test-specific directories instead of
-/// random temporary directories.
-fn prepare_test_specific_dir() -> PathBuf {
-    let current = std::thread::current();
-    // Replace "::" with "_" to make it safe for directory names on Windows systems
-    let test_path = current.name().unwrap().replace("::", "_");
-
-    let testdir = parse("").tempdir().join(test_path);
-
-    // clean up any old test files
-    let _ = fs::remove_dir_all(&testdir);
-    let _ = fs::create_dir_all(&testdir);
-
-    testdir
-}
-
 #[test]
 fn download_ci_llvm() {
-    let config = parse("llvm.download-ci-llvm = false");
+    let config = TestCtx::new().config("check").create_config();
     assert!(!config.llvm_from_ci);
 
-    let if_unchanged_config = parse("llvm.download-ci-llvm = \"if-unchanged\"");
+    // this doesn't make sense, as we are overriding it later.
+    let if_unchanged_config = TestCtx::new()
+        .config("check")
+        .with_default_toml_config("llvm.download-ci-llvm = \"if-unchanged\"")
+        .create_config();
     if if_unchanged_config.llvm_from_ci && if_unchanged_config.is_running_on_ci {
         let has_changes = if_unchanged_config.has_changes_from_upstream(LLVM_INVALIDATION_PATHS);
 
@@ -64,62 +52,6 @@ fn download_ci_llvm() {
     }
 }
 
-// FIXME(onur-ozkan): extend scope of the test
-// refs:
-//   - https://github.com/rust-lang/rust/issues/109120
-//   - https://github.com/rust-lang/rust/pull/109162#issuecomment-1496782487
-#[test]
-fn detect_src_and_out() {
-    fn test(cfg: Config, build_dir: Option<&str>) {
-        // This will bring absolute form of `src/bootstrap` path
-        let current_dir = std::env::current_dir().unwrap();
-
-        // get `src` by moving into project root path
-        let expected_src = current_dir.ancestors().nth(2).unwrap();
-        assert_eq!(&cfg.src, expected_src);
-
-        // Sanity check for `src`
-        let manifest_dir = Path::new(env!("CARGO_MANIFEST_DIR"));
-        let expected_src = manifest_dir.ancestors().nth(2).unwrap();
-        assert_eq!(&cfg.src, expected_src);
-
-        // test if build-dir was manually given in bootstrap.toml
-        if let Some(custom_build_dir) = build_dir {
-            assert_eq!(&cfg.out, Path::new(custom_build_dir));
-        }
-        // test the native bootstrap way
-        else {
-            // This should bring output path of bootstrap in absolute form
-            let cargo_target_dir = env::var_os("CARGO_TARGET_DIR").expect(
-                "CARGO_TARGET_DIR must been provided for the test environment from bootstrap",
-            );
-
-            // Move to `build` from `build/bootstrap`
-            let expected_out = Path::new(&cargo_target_dir).parent().unwrap();
-            assert_eq!(&cfg.out, expected_out);
-
-            let args: Vec<String> = env::args().collect();
-
-            // Another test for `out` as a sanity check
-            //
-            // This will bring something similar to:
-            //     `{build-dir}/bootstrap/debug/deps/bootstrap-c7ee91d5661e2804`
-            // `{build-dir}` can be anywhere, not just in the rust project directory.
-            let dep = Path::new(args.first().unwrap());
-            let expected_out = dep.ancestors().nth(5).unwrap();
-
-            assert_eq!(&cfg.out, expected_out);
-        }
-    }
-
-    test(parse(""), None);
-
-    {
-        let build_dir = if cfg!(windows) { "C:\\tmp" } else { "/tmp" };
-        test(parse(&format!("build.build-dir = '{build_dir}'")), Some(build_dir));
-    }
-}
-
 #[test]
 fn clap_verify() {
     Flags::command().debug_assert();
@@ -127,54 +59,54 @@ fn clap_verify() {
 
 #[test]
 fn override_toml() {
-    let config = Config::parse_inner(
-        Flags::parse(&[
-            "check".to_owned(),
-            "--config=/does/not/exist".to_owned(),
-            "--set=change-id=1".to_owned(),
-            "--set=rust.lto=fat".to_owned(),
-            "--set=rust.deny-warnings=false".to_owned(),
-            "--set=build.optimized-compiler-builtins=true".to_owned(),
-            "--set=build.gdb=\"bar\"".to_owned(),
-            "--set=build.tools=[\"cargo\"]".to_owned(),
-            "--set=llvm.build-config={\"foo\" = \"bar\"}".to_owned(),
-            "--set=target.x86_64-unknown-linux-gnu.runner=bar".to_owned(),
-            "--set=target.x86_64-unknown-linux-gnu.rpath=false".to_owned(),
-            "--set=target.aarch64-unknown-linux-gnu.sanitizers=false".to_owned(),
-            "--set=target.aarch64-apple-darwin.runner=apple".to_owned(),
-            "--set=target.aarch64-apple-darwin.optimized-compiler-builtins=false".to_owned(),
-        ]),
-        |&_| {
-            toml::from_str(
-                r#"
-change-id = 0
-[rust]
-lto = "off"
-deny-warnings = true
-download-rustc=false
-
-[build]
-gdb = "foo"
-tools = []
-
-[llvm]
-download-ci-llvm = false
-build-config = {}
-
-[target.aarch64-unknown-linux-gnu]
-sanitizers = true
-rpath = true
-runner = "aarch64-runner"
-
-[target.x86_64-unknown-linux-gnu]
-sanitizers = true
-rpath = true
-runner = "x86_64-runner"
-
-                "#,
-            )
-        },
-    );
+    let config_toml: &str = r#"
+    change-id = 0
+
+    [rust]
+    lto = "off"
+    deny-warnings = true
+    download-rustc = false
+
+    [build]
+    gdb = "foo"
+    tools = []
+
+    [llvm]
+    download-ci-llvm = false
+    build-config = {}
+
+    [target.aarch64-unknown-linux-gnu]
+    sanitizers = true
+    rpath = true
+    runner = "aarch64-runner"
+
+    [target.x86_64-unknown-linux-gnu]
+    sanitizers = true
+    rpath = true
+    runner = "x86_64-runner"
+    "#;
+
+    let args = [
+        "--set=change-id=1",
+        "--set=rust.lto=fat",
+        "--set=rust.deny-warnings=false",
+        "--set=build.optimized-compiler-builtins=true",
+        "--set=build.gdb=\"bar\"",
+        "--set=build.tools=[\"cargo\"]",
+        "--set=llvm.build-config={\"foo\" = \"bar\"}",
+        "--set=target.x86_64-unknown-linux-gnu.runner=bar",
+        "--set=target.x86_64-unknown-linux-gnu.rpath=false",
+        "--set=target.aarch64-unknown-linux-gnu.sanitizers=false",
+        "--set=target.aarch64-apple-darwin.runner=apple",
+        "--set=target.aarch64-apple-darwin.optimized-compiler-builtins=false",
+    ];
+
+    let config = TestCtx::new()
+        .config("check")
+        .with_default_toml_config(config_toml)
+        .args(&args)
+        .create_config();
+
     assert_eq!(config.change_id, Some(ChangeId::Id(1)), "setting top-level value");
     assert_eq!(
         config.rust_lto,
@@ -233,33 +165,26 @@ runner = "x86_64-runner"
 #[test]
 #[should_panic]
 fn override_toml_duplicate() {
-    Config::parse_inner(
-        Flags::parse(&[
-            "check".to_owned(),
-            "--config=/does/not/exist".to_string(),
-            "--set=change-id=1".to_owned(),
-            "--set=change-id=2".to_owned(),
-        ]),
-        |&_| toml::from_str("change-id = 0"),
-    );
+    TestCtx::new()
+        .config("check")
+        .with_default_toml_config("change-id = 0")
+        .arg("--set")
+        .arg("change-id=1")
+        .arg("--set")
+        .arg("change-id=2")
+        .create_config();
 }
 
 #[test]
 fn profile_user_dist() {
-    fn get_toml(file: &Path) -> Result<TomlConfig, toml::de::Error> {
-        let contents = if file.ends_with("bootstrap.toml")
-            || file.ends_with("config.toml")
-            || env::var_os("RUST_BOOTSTRAP_CONFIG").is_some()
-        {
-            "profile = \"user\"".to_owned()
-        } else {
-            assert!(file.ends_with("config.dist.toml") || file.ends_with("bootstrap.dist.toml"));
-            std::fs::read_to_string(file).unwrap()
-        };
-
-        toml::from_str(&contents).and_then(|table: toml::Value| TomlConfig::deserialize(table))
-    }
-    Config::parse_inner(Flags::parse(&["check".to_owned()]), get_toml);
+    TestCtx::new()
+        .config("check")
+        .with_default_toml_config(
+            r#"
+        profile = "user"
+    "#,
+        )
+        .create_config();
 }
 
 #[test]
@@ -277,12 +202,15 @@ fn rust_optimize() {
 #[test]
 #[should_panic]
 fn invalid_rust_optimize() {
-    parse("rust.optimize = \"a\"");
+    TestCtx::new()
+        .config("check")
+        .with_default_toml_config("rust.optimize = \"a\"")
+        .create_config();
 }
 
 #[test]
 fn verify_file_integrity() {
-    let config = parse("");
+    let config = TestCtx::new().config("check").no_dry_run().create_config();
 
     let tempfile = config.tempdir().join(".tmp-test-file");
     File::create(&tempfile).unwrap().write_all(b"dummy value").unwrap();
@@ -292,17 +220,37 @@ fn verify_file_integrity() {
         config
             .verify(&tempfile, "7e255dd9542648a8779268a0f268b891a198e9828e860ed23f826440e786eae5")
     );
-
-    remove_file(tempfile).unwrap();
 }
 
 #[test]
 fn rust_lld() {
-    assert!(matches!(parse("").lld_mode, LldMode::Unused));
-    assert!(matches!(parse("rust.use-lld = \"self-contained\"").lld_mode, LldMode::SelfContained));
-    assert!(matches!(parse("rust.use-lld = \"external\"").lld_mode, LldMode::External));
-    assert!(matches!(parse("rust.use-lld = true").lld_mode, LldMode::External));
-    assert!(matches!(parse("rust.use-lld = false").lld_mode, LldMode::Unused));
+    assert!(matches!(parse("").bootstrap_override_lld, BootstrapOverrideLld::None));
+    assert!(matches!(
+        parse("rust.bootstrap-override-lld = \"self-contained\"").bootstrap_override_lld,
+        BootstrapOverrideLld::SelfContained
+    ));
+    assert!(matches!(
+        parse("rust.bootstrap-override-lld = \"external\"").bootstrap_override_lld,
+        BootstrapOverrideLld::External
+    ));
+    assert!(matches!(
+        parse("rust.bootstrap-override-lld = true").bootstrap_override_lld,
+        BootstrapOverrideLld::External
+    ));
+    assert!(matches!(
+        parse("rust.bootstrap-override-lld = false").bootstrap_override_lld,
+        BootstrapOverrideLld::None
+    ));
+
+    // Also check the legacy options
+    assert!(matches!(
+        parse("rust.use-lld = true").bootstrap_override_lld,
+        BootstrapOverrideLld::External
+    ));
+    assert!(matches!(
+        parse("rust.use-lld = false").bootstrap_override_lld,
+        BootstrapOverrideLld::None
+    ));
 }
 
 #[test]
@@ -324,22 +272,23 @@ fn parse_change_id_with_unknown_field() {
 
 #[test]
 fn order_of_clippy_rules() {
-    let args = vec![
-        "clippy".to_string(),
-        "--fix".to_string(),
-        "--allow-dirty".to_string(),
-        "--allow-staged".to_string(),
-        "-Aclippy:all".to_string(),
-        "-Wclippy::style".to_string(),
-        "-Aclippy::foo1".to_string(),
-        "-Aclippy::foo2".to_string(),
+    let args = [
+        "clippy",
+        "--fix",
+        "--allow-dirty",
+        "--allow-staged",
+        "-Aclippy:all",
+        "-Wclippy::style",
+        "-Aclippy::foo1",
+        "-Aclippy::foo2",
     ];
-    let config = Config::parse(Flags::parse(&args));
+    let config = TestCtx::new().config(&args[0]).args(&args[1..]).create_config();
 
     let actual = match config.cmd.clone() {
         crate::Subcommand::Clippy { allow, deny, warn, forbid, .. } => {
             let cfg = LintConfig { allow, deny, warn, forbid };
-            get_clippy_rules_in_order(&args, &cfg)
+            let args_vec: Vec<String> = args.iter().map(|s| s.to_string()).collect();
+            get_clippy_rules_in_order(&args_vec, &cfg)
         }
         _ => panic!("invalid subcommand"),
     };
@@ -356,14 +305,14 @@ fn order_of_clippy_rules() {
 
 #[test]
 fn clippy_rule_separate_prefix() {
-    let args =
-        vec!["clippy".to_string(), "-A clippy:all".to_string(), "-W clippy::style".to_string()];
-    let config = Config::parse(Flags::parse(&args));
+    let args = ["clippy", "-A clippy:all", "-W clippy::style"];
+    let config = TestCtx::new().config(&args[0]).args(&args[1..]).create_config();
 
     let actual = match config.cmd.clone() {
         crate::Subcommand::Clippy { allow, deny, warn, forbid, .. } => {
             let cfg = LintConfig { allow, deny, warn, forbid };
-            get_clippy_rules_in_order(&args, &cfg)
+            let args_vec: Vec<String> = args.iter().map(|s| s.to_string()).collect();
+            get_clippy_rules_in_order(&args_vec, &cfg)
         }
         _ => panic!("invalid subcommand"),
     };
@@ -374,16 +323,20 @@ fn clippy_rule_separate_prefix() {
 
 #[test]
 fn verbose_tests_default_value() {
-    let config = Config::parse(Flags::parse(&["build".into(), "compiler".into()]));
+    let config = TestCtx::new().config("build").args(&["compiler".into()]).create_config();
     assert_eq!(config.verbose_tests, false);
 
-    let config = Config::parse(Flags::parse(&["build".into(), "compiler".into(), "-v".into()]));
+    let config =
+        TestCtx::new().config("build").args(&["compiler".into(), "-v".into()]).create_config();
     assert_eq!(config.verbose_tests, true);
 }
 
 #[test]
 fn parse_rust_std_features() {
-    let config = parse("rust.std-features = [\"panic-unwind\", \"backtrace\"]");
+    let config = TestCtx::new()
+        .config("check")
+        .with_default_toml_config("rust.std-features = [\"panic-unwind\", \"backtrace\"]")
+        .create_config();
     let expected_features: BTreeSet<String> =
         ["panic-unwind", "backtrace"].into_iter().map(|s| s.to_string()).collect();
     assert_eq!(config.rust_std_features, expected_features);
@@ -391,7 +344,10 @@ fn parse_rust_std_features() {
 
 #[test]
 fn parse_rust_std_features_empty() {
-    let config = parse("rust.std-features = []");
+    let config = TestCtx::new()
+        .config("check")
+        .with_default_toml_config("rust.std-features = []")
+        .create_config();
     let expected_features: BTreeSet<String> = BTreeSet::new();
     assert_eq!(config.rust_std_features, expected_features);
 }
@@ -399,70 +355,65 @@ fn parse_rust_std_features_empty() {
 #[test]
 #[should_panic]
 fn parse_rust_std_features_invalid() {
-    parse("rust.std-features = \"backtrace\"");
+    TestCtx::new()
+        .config("check")
+        .with_default_toml_config("rust.std-features = \"backtrace\"")
+        .create_config();
 }
 
 #[test]
 fn parse_jobs() {
-    assert_eq!(parse("build.jobs = 1").jobs, Some(1));
+    assert_eq!(
+        TestCtx::new()
+            .config("check")
+            .with_default_toml_config("build.jobs = 1")
+            .create_config()
+            .jobs,
+        Some(1)
+    );
 }
 
 #[test]
 fn jobs_precedence() {
     // `--jobs` should take precedence over using `--set build.jobs`.
 
-    let config = Config::parse_inner(
-        Flags::parse(&[
-            "check".to_owned(),
-            "--config=/does/not/exist".to_owned(),
-            "--jobs=67890".to_owned(),
-            "--set=build.jobs=12345".to_owned(),
-        ]),
-        |&_| toml::from_str(""),
-    );
+    let config = TestCtx::new()
+        .config("check")
+        .args(&["--jobs=67890", "--set=build.jobs=12345"])
+        .create_config();
     assert_eq!(config.jobs, Some(67890));
 
     // `--set build.jobs` should take precedence over `bootstrap.toml`.
-    let config = Config::parse_inner(
-        Flags::parse(&[
-            "check".to_owned(),
-            "--config=/does/not/exist".to_owned(),
-            "--set=build.jobs=12345".to_owned(),
-        ]),
-        |&_| {
-            toml::from_str(
-                r#"
-            [build]
-            jobs = 67890
-        "#,
-            )
-        },
-    );
+    let config = TestCtx::new()
+        .config("check")
+        .args(&["--set=build.jobs=12345"])
+        .with_default_toml_config(
+            r#"
+        [build]
+        jobs = 67890
+    "#,
+        )
+        .create_config();
+
     assert_eq!(config.jobs, Some(12345));
 
     // `--jobs` > `--set build.jobs` > `bootstrap.toml`
-    let config = Config::parse_inner(
-        Flags::parse(&[
-            "check".to_owned(),
-            "--jobs=123".to_owned(),
-            "--config=/does/not/exist".to_owned(),
-            "--set=build.jobs=456".to_owned(),
-        ]),
-        |&_| {
-            toml::from_str(
-                r#"
-            [build]
-            jobs = 789
-        "#,
-            )
-        },
-    );
+    let config = TestCtx::new()
+        .config("check")
+        .args(&["--jobs=123", "--set=build.jobs=456"])
+        .with_default_toml_config(
+            r#"
+        [build]
+        jobs = 789
+    "#,
+        )
+        .create_config();
     assert_eq!(config.jobs, Some(123));
 }
 
 #[test]
 fn check_rustc_if_unchanged_paths() {
-    let config = parse("");
+    let config = TestCtx::new().config("check").create_config();
     let normalised_allowed_paths: Vec<_> = RUSTC_IF_UNCHANGED_ALLOWED_PATHS
         .iter()
         .map(|t| {
@@ -477,59 +428,42 @@ fn check_rustc_if_unchanged_paths() {
 
 #[test]
 fn test_explicit_stage() {
-    let config = Config::parse_inner(
-        Flags::parse(&["check".to_owned(), "--config=/does/not/exist".to_owned()]),
-        |&_| {
-            toml::from_str(
-                r#"
+    let config = TestCtx::new()
+        .config("check")
+        .with_default_toml_config(
+            r#"
             [build]
             test-stage = 1
         "#,
-            )
-        },
-    );
+        )
+        .create_config();
 
     assert!(!config.explicit_stage_from_cli);
     assert!(config.explicit_stage_from_config);
     assert!(config.is_explicit_stage());
 
-    let config = Config::parse_inner(
-        Flags::parse(&[
-            "check".to_owned(),
-            "--stage=2".to_owned(),
-            "--config=/does/not/exist".to_owned(),
-        ]),
-        |&_| toml::from_str(""),
-    );
+    let config = TestCtx::new().config("check").stage(2).create_config();
 
     assert!(config.explicit_stage_from_cli);
     assert!(!config.explicit_stage_from_config);
     assert!(config.is_explicit_stage());
 
-    let config = Config::parse_inner(
-        Flags::parse(&[
-            "check".to_owned(),
-            "--stage=2".to_owned(),
-            "--config=/does/not/exist".to_owned(),
-        ]),
-        |&_| {
-            toml::from_str(
-                r#"
+    let config = TestCtx::new()
+        .config("check")
+        .stage(2)
+        .with_default_toml_config(
+            r#"
             [build]
             test-stage = 1
         "#,
-            )
-        },
-    );
+        )
+        .create_config();
 
     assert!(config.explicit_stage_from_cli);
     assert!(config.explicit_stage_from_config);
     assert!(config.is_explicit_stage());
 
-    let config = Config::parse_inner(
-        Flags::parse(&["check".to_owned(), "--config=/does/not/exist".to_owned()]),
-        |&_| toml::from_str(""),
-    );
+    let config = TestCtx::new().config("check").create_config();
 
     assert!(!config.explicit_stage_from_cli);
     assert!(!config.explicit_stage_from_config);
@@ -539,7 +473,10 @@ fn test_explicit_stage() {
 #[test]
 fn test_exclude() {
     let exclude_path = "compiler";
-    let config = parse(&format!("build.exclude=[\"{}\"]", exclude_path));
+    let config = TestCtx::new()
+        .config("check")
+        .with_default_toml_config(&format!("build.exclude=[\"{}\"]", exclude_path))
+        .create_config();
 
     let first_excluded = config
         .skip
@@ -553,32 +490,20 @@ fn test_exclude() {
 
 #[test]
 fn test_ci_flag() {
-    let config = Config::parse_inner(Flags::parse(&["check".into(), "--ci=false".into()]), |&_| {
-        toml::from_str("")
-    });
+    let config = TestCtx::new().config("check").arg("--ci").arg("false").create_config();
     assert!(!config.is_running_on_ci);
 
-    let config = Config::parse_inner(Flags::parse(&["check".into(), "--ci=true".into()]), |&_| {
-        toml::from_str("")
-    });
+    let config = TestCtx::new().config("check").arg("--ci").arg("true").create_config();
     assert!(config.is_running_on_ci);
 
-    let config = Config::parse_inner(Flags::parse(&["check".into()]), |&_| toml::from_str(""));
+    let config = TestCtx::new().config("check").create_config();
     assert_eq!(config.is_running_on_ci, CiEnv::is_ci());
 }
 
 #[test]
 fn test_precedence_of_includes() {
-    let testdir = prepare_test_specific_dir();
-
-    let root_config = testdir.join("config.toml");
-    let root_config_content = br#"
-        include = ["./extension.toml"]
-
-        [llvm]
-        link-jobs = 2
-    "#;
-    File::create(&root_config).unwrap().write_all(root_config_content).unwrap();
+    let test_ctx = TestCtx::new();
+    let testdir = test_ctx.dir();
 
     let extension = testdir.join("extension.toml");
     let extension_content = br#"
@@ -599,10 +524,17 @@ fn test_precedence_of_includes() {
     "#;
     File::create(extension).unwrap().write_all(extension_content).unwrap();
 
-    let config = Config::parse_inner(
-        Flags::parse(&["check".to_owned(), format!("--config={}", root_config.to_str().unwrap())]),
-        get_toml,
-    );
+    let config = test_ctx
+        .config("check")
+        .with_default_toml_config(
+            r#"
+        include = ["./extension.toml"]
+
+        [llvm]
+        link-jobs = 2
+    "#,
+        )
+        .create_config();
 
     assert_eq!(config.change_id.unwrap(), ChangeId::Id(543));
     assert_eq!(config.llvm_link_jobs.unwrap(), 2);
@@ -612,36 +544,29 @@ fn test_precedence_of_includes() {
 #[test]
 #[should_panic(expected = "Cyclic inclusion detected")]
 fn test_cyclic_include_direct() {
-    let testdir = prepare_test_specific_dir();
-
-    let root_config = testdir.join("config.toml");
-    let root_config_content = br#"
-        include = ["./extension.toml"]
-    "#;
-    File::create(&root_config).unwrap().write_all(root_config_content).unwrap();
-
+    let test_ctx = TestCtx::new();
+    let testdir = test_ctx.dir();
     let extension = testdir.join("extension.toml");
     let extension_content = br#"
-        include = ["./config.toml"]
+        include = ["./bootstrap.toml"]
     "#;
     File::create(extension).unwrap().write_all(extension_content).unwrap();
 
-    let config = Config::parse_inner(
-        Flags::parse(&["check".to_owned(), format!("--config={}", root_config.to_str().unwrap())]),
-        get_toml,
-    );
+    test_ctx
+        .config("check")
+        .with_default_toml_config(
+            r#"
+        include = ["./extension.toml"]
+    "#,
+        )
+        .create_config();
 }
 
 #[test]
 #[should_panic(expected = "Cyclic inclusion detected")]
 fn test_cyclic_include_indirect() {
-    let testdir = prepare_test_specific_dir();
-
-    let root_config = testdir.join("config.toml");
-    let root_config_content = br#"
-        include = ["./extension.toml"]
-    "#;
-    File::create(&root_config).unwrap().write_all(root_config_content).unwrap();
+    let test_ctx = TestCtx::new();
+    let testdir = test_ctx.dir();
 
     let extension = testdir.join("extension.toml");
     let extension_content = br#"
@@ -661,43 +586,37 @@ fn test_cyclic_include_indirect() {
     "#;
     File::create(extension).unwrap().write_all(extension_content).unwrap();
 
-    let config = Config::parse_inner(
-        Flags::parse(&["check".to_owned(), format!("--config={}", root_config.to_str().unwrap())]),
-        get_toml,
-    );
+    test_ctx
+        .config("check")
+        .with_default_toml_config(
+            r#"
+        include = ["./extension.toml"]
+    "#,
+        )
+        .create_config();
 }
 
 #[test]
 fn test_include_absolute_paths() {
-    let testdir = prepare_test_specific_dir();
+    let test_ctx = TestCtx::new();
+    let testdir = test_ctx.dir();
 
     let extension = testdir.join("extension.toml");
     File::create(&extension).unwrap().write_all(&[]).unwrap();
 
-    let root_config = testdir.join("config.toml");
     let extension_absolute_path =
         extension.canonicalize().unwrap().to_str().unwrap().replace('\\', r"\\");
     let root_config_content = format!(r#"include = ["{}"]"#, extension_absolute_path);
-    File::create(&root_config).unwrap().write_all(root_config_content.as_bytes()).unwrap();
-
-    let config = Config::parse_inner(
-        Flags::parse(&["check".to_owned(), format!("--config={}", root_config.to_str().unwrap())]),
-        get_toml,
-    );
+    test_ctx.config("check").with_default_toml_config(&root_config_content).create_config();
 }
 
 #[test]
 fn test_include_relative_paths() {
-    let testdir = prepare_test_specific_dir();
+    let test_ctx = TestCtx::new();
+    let testdir = test_ctx.dir();
 
     let _ = fs::create_dir_all(&testdir.join("subdir/another_subdir"));
 
-    let root_config = testdir.join("config.toml");
-    let root_config_content = br#"
-        include = ["./subdir/extension.toml"]
-    "#;
-    File::create(&root_config).unwrap().write_all(root_config_content).unwrap();
-
     let extension = testdir.join("subdir/extension.toml");
     let extension_content = br#"
         include = ["../extension2.toml"]
@@ -719,22 +638,20 @@ fn test_include_relative_paths() {
     let extension = testdir.join("extension4.toml");
     File::create(extension).unwrap().write_all(&[]).unwrap();
 
-    let config = Config::parse_inner(
-        Flags::parse(&["check".to_owned(), format!("--config={}", root_config.to_str().unwrap())]),
-        get_toml,
-    );
+    test_ctx
+        .config("check")
+        .with_default_toml_config(
+            r#"
+        include = ["./subdir/extension.toml"]
+    "#,
+        )
+        .create_config();
 }
 
 #[test]
 fn test_include_precedence_over_profile() {
-    let testdir = prepare_test_specific_dir();
-
-    let root_config = testdir.join("config.toml");
-    let root_config_content = br#"
-        profile = "dist"
-        include = ["./extension.toml"]
-    "#;
-    File::create(&root_config).unwrap().write_all(root_config_content).unwrap();
+    let test_ctx = TestCtx::new();
+    let testdir = test_ctx.dir();
 
     let extension = testdir.join("extension.toml");
     let extension_content = br#"
@@ -743,10 +660,15 @@ fn test_include_precedence_over_profile() {
     "#;
     File::create(extension).unwrap().write_all(extension_content).unwrap();
 
-    let config = Config::parse_inner(
-        Flags::parse(&["check".to_owned(), format!("--config={}", root_config.to_str().unwrap())]),
-        get_toml,
-    );
+    let config = test_ctx
+        .config("check")
+        .with_default_toml_config(
+            r#"
+        profile = "dist"
+        include = ["./extension.toml"]
+    "#,
+        )
+        .create_config();
 
     // "dist" profile would normally set the channel to "auto-detect", but includes should
     // override profile settings, so we expect this to be "dev" here.
diff --git a/src/bootstrap/src/core/config/toml/build.rs b/src/bootstrap/src/core/config/toml/build.rs
index a9d4d3961c9..c63673dd980 100644
--- a/src/bootstrap/src/core/config/toml/build.rs
+++ b/src/bootstrap/src/core/config/toml/build.rs
@@ -70,6 +70,8 @@ define_config! {
         jobs: Option<u32> = "jobs",
         compiletest_diff_tool: Option<String> = "compiletest-diff-tool",
         compiletest_allow_stage0: Option<bool> = "compiletest-allow-stage0",
+        /// No longer has any effect; kept (for now) to avoid breaking people's configs.
+        /// FIXME(#146929): Remove this in 2026.
         compiletest_use_stage0_libtest: Option<bool> = "compiletest-use-stage0-libtest",
         tidy_extra_checks: Option<String> = "tidy-extra-checks",
         ccache: Option<StringOrBool> = "ccache",
diff --git a/src/bootstrap/src/core/config/toml/mod.rs b/src/bootstrap/src/core/config/toml/mod.rs
index 7af22432ef8..f6dc5b67e10 100644
--- a/src/bootstrap/src/core/config/toml/mod.rs
+++ b/src/bootstrap/src/core/config/toml/mod.rs
@@ -152,10 +152,6 @@ impl Config {
     }
 
     pub(crate) fn get_toml(file: &Path) -> Result<TomlConfig, toml::de::Error> {
-        #[cfg(test)]
-        return Ok(TomlConfig::default());
-
-        #[cfg(not(test))]
         Self::get_toml_inner(file)
     }
 
diff --git a/src/bootstrap/src/core/config/toml/rust.rs b/src/bootstrap/src/core/config/toml/rust.rs
index e5987d7040a..ca9e0d0bc98 100644
--- a/src/bootstrap/src/core/config/toml/rust.rs
+++ b/src/bootstrap/src/core/config/toml/rust.rs
@@ -45,7 +45,9 @@ define_config! {
         codegen_backends: Option<Vec<String>> = "codegen-backends",
         llvm_bitcode_linker: Option<bool> = "llvm-bitcode-linker",
         lld: Option<bool> = "lld",
-        lld_mode: Option<LldMode> = "use-lld",
+        bootstrap_override_lld: Option<BootstrapOverrideLld> = "bootstrap-override-lld",
+        // FIXME: Remove this option in Spring 2026
+        bootstrap_override_lld_legacy: Option<BootstrapOverrideLld> = "use-lld",
         llvm_tools: Option<bool> = "llvm-tools",
         deny_warnings: Option<bool> = "deny-warnings",
         backtrace_on_ice: Option<bool> = "backtrace-on-ice",
@@ -70,22 +72,33 @@ define_config! {
     }
 }
 
-/// LLD in bootstrap works like this:
-/// - Self-contained lld: use `rust-lld` from the compiler's sysroot
+/// Determines if we should override the linker used for linking Rust code built
+/// during the bootstrapping process to be LLD.
+///
+/// The primary use-case for this is to make local (re)builds of Rust code faster
+/// when using bootstrap.
+///
+/// This does not affect the *behavior* of the built/distributed compiler when invoked
+/// outside of bootstrap.
+/// It might affect its performance/binary size though, as that can depend on the
+/// linker that links rustc.
+///
+/// There are two ways of overriding the linker to be LLD:
+/// - Self-contained LLD: use `rust-lld` from the compiler's sysroot
 /// - External: use an external `lld` binary
 ///
 /// It is configured depending on the target:
 /// 1) Everything except MSVC
-/// - Self-contained: `-Clinker-flavor=gnu-lld-cc -Clink-self-contained=+linker`
-/// - External: `-Clinker-flavor=gnu-lld-cc`
+/// - Self-contained: `-Clinker-features=+lld -Clink-self-contained=+linker`
+/// - External: `-Clinker-features=+lld`
 /// 2) MSVC
 /// - Self-contained: `-Clinker=<path to rust-lld>`
 /// - External: `-Clinker=lld`
 #[derive(Copy, Clone, Default, Debug, PartialEq)]
-pub enum LldMode {
-    /// Do not use LLD
+pub enum BootstrapOverrideLld {
+    /// Do not override the linker LLD
     #[default]
-    Unused,
+    None,
     /// Use `rust-lld` from the compiler's sysroot
     SelfContained,
     /// Use an externally provided `lld` binary.
@@ -94,16 +107,16 @@ pub enum LldMode {
     External,
 }
 
-impl LldMode {
+impl BootstrapOverrideLld {
     pub fn is_used(&self) -> bool {
         match self {
-            LldMode::SelfContained | LldMode::External => true,
-            LldMode::Unused => false,
+            BootstrapOverrideLld::SelfContained | BootstrapOverrideLld::External => true,
+            BootstrapOverrideLld::None => false,
         }
     }
 }
 
-impl<'de> Deserialize<'de> for LldMode {
+impl<'de> Deserialize<'de> for BootstrapOverrideLld {
     fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
     where
         D: Deserializer<'de>,
@@ -111,7 +124,7 @@ impl<'de> Deserialize<'de> for LldMode {
         struct LldModeVisitor;
 
         impl serde::de::Visitor<'_> for LldModeVisitor {
-            type Value = LldMode;
+            type Value = BootstrapOverrideLld;
 
             fn expecting(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
                 formatter.write_str("one of true, 'self-contained' or 'external'")
@@ -121,7 +134,7 @@ impl<'de> Deserialize<'de> for LldMode {
             where
                 E: serde::de::Error,
             {
-                Ok(if v { LldMode::External } else { LldMode::Unused })
+                Ok(if v { BootstrapOverrideLld::External } else { BootstrapOverrideLld::None })
             }
 
             fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
@@ -129,8 +142,8 @@ impl<'de> Deserialize<'de> for LldMode {
                 E: serde::de::Error,
             {
                 match v {
-                    "external" => Ok(LldMode::External),
-                    "self-contained" => Ok(LldMode::SelfContained),
+                    "external" => Ok(BootstrapOverrideLld::External),
+                    "self-contained" => Ok(BootstrapOverrideLld::SelfContained),
                     _ => Err(E::custom(format!("unknown mode {v}"))),
                 }
             }
@@ -311,7 +324,6 @@ pub fn check_incompatible_options_for_ci_rustc(
         lto,
         stack_protector,
         strip,
-        lld_mode,
         jemalloc,
         rpath,
         channel,
@@ -359,6 +371,8 @@ pub fn check_incompatible_options_for_ci_rustc(
         frame_pointers: _,
         break_on_ice: _,
         parallel_frontend_threads: _,
+        bootstrap_override_lld: _,
+        bootstrap_override_lld_legacy: _,
     } = ci_rust_config;
 
     // There are two kinds of checks for CI rustc incompatible options:
@@ -374,7 +388,6 @@ pub fn check_incompatible_options_for_ci_rustc(
     err!(current_rust_config.debuginfo_level_rustc, debuginfo_level_rustc, "rust");
     err!(current_rust_config.rpath, rpath, "rust");
     err!(current_rust_config.strip, strip, "rust");
-    err!(current_rust_config.lld_mode, lld_mode, "rust");
     err!(current_rust_config.llvm_tools, llvm_tools, "rust");
     err!(current_rust_config.llvm_bitcode_linker, llvm_bitcode_linker, "rust");
     err!(current_rust_config.jemalloc, jemalloc, "rust");
diff --git a/src/bootstrap/src/core/download.rs b/src/bootstrap/src/core/download.rs
index 2f3c80559c0..a096d116e73 100644
--- a/src/bootstrap/src/core/download.rs
+++ b/src/bootstrap/src/core/download.rs
@@ -106,7 +106,7 @@ enum DownloadSource {
 /// 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"));
+        self.do_if_verbose(|| println!("downloading stage0 clippy artifacts"));
 
         let date = &self.stage0_metadata.compiler.date;
         let version = &self.stage0_metadata.compiler.version;
@@ -151,7 +151,9 @@ impl Config {
     }
 
     pub(crate) fn download_ci_rustc(&self, commit: &str) {
-        self.verbose(|| println!("using downloaded stage2 artifacts from CI (commit {commit})"));
+        self.do_if_verbose(|| {
+            println!("using downloaded stage2 artifacts from CI (commit {commit})")
+        });
 
         let version = self.artifact_version_part(commit);
         // download-rustc doesn't need its own cargo, it can just use beta's. But it does need the
@@ -258,7 +260,7 @@ impl Config {
         let llvm_root = self.ci_llvm_root();
         let llvm_freshness =
             detect_llvm_freshness(self, self.rust_info.is_managed_git_subrepository());
-        self.verbose(|| {
+        self.do_if_verbose(|| {
             eprintln!("LLVM freshness: {llvm_freshness:?}");
         });
         let llvm_sha = match llvm_freshness {
@@ -504,7 +506,7 @@ pub(crate) fn maybe_download_rustfmt<'a>(
         return Some(PathBuf::new());
     }
 
-    let VersionMetadata { date, version } = dwn_ctx.stage0_metadata.rustfmt.as_ref()?;
+    let VersionMetadata { date, version, .. } = dwn_ctx.stage0_metadata.rustfmt.as_ref()?;
     let channel = format!("{version}-{date}");
 
     let host = dwn_ctx.host_target;
@@ -557,7 +559,7 @@ pub(crate) fn download_beta_toolchain<'a>(dwn_ctx: impl AsRef<DownloadContext<'a
 #[cfg(not(test))]
 pub(crate) fn download_beta_toolchain<'a>(dwn_ctx: impl AsRef<DownloadContext<'a>>, out: &Path) {
     let dwn_ctx = dwn_ctx.as_ref();
-    dwn_ctx.exec_ctx.verbose(|| {
+    dwn_ctx.exec_ctx.do_if_verbose(|| {
         println!("downloading stage0 beta artifacts");
     });
 
@@ -812,7 +814,7 @@ fn download_component<'a>(
                 unpack(dwn_ctx.exec_ctx, &tarball, &bin_root, prefix);
                 return;
             } else {
-                dwn_ctx.exec_ctx.verbose(|| {
+                dwn_ctx.exec_ctx.do_if_verbose(|| {
                     println!(
                         "ignoring cached file {} due to failed verification",
                         tarball.display()
@@ -853,7 +855,7 @@ download-rustc = false
 pub(crate) fn verify(exec_ctx: &ExecutionContext, path: &Path, expected: &str) -> bool {
     use sha2::Digest;
 
-    exec_ctx.verbose(|| {
+    exec_ctx.do_if_verbose(|| {
         println!("verifying {}", path.display());
     });
 
@@ -934,7 +936,7 @@ fn unpack(exec_ctx: &ExecutionContext, tarball: &Path, dst: &Path, pattern: &str
         short_path = short_path.strip_prefix(pattern).unwrap_or(short_path);
         let dst_path = dst.join(short_path);
 
-        exec_ctx.verbose(|| {
+        exec_ctx.do_if_verbose(|| {
             println!("extracting {} to {}", original_path.display(), dst.display());
         });
 
@@ -965,7 +967,7 @@ fn download_file<'a>(
 ) {
     let dwn_ctx = dwn_ctx.as_ref();
 
-    dwn_ctx.exec_ctx.verbose(|| {
+    dwn_ctx.exec_ctx.do_if_verbose(|| {
         println!("download {url}");
     });
     // Use a temporary file in case we crash while downloading, to avoid a corrupt download in cache/.
diff --git a/src/bootstrap/src/core/sanity.rs b/src/bootstrap/src/core/sanity.rs
index 91d80c96e42..eaa9e3a6a3e 100644
--- a/src/bootstrap/src/core/sanity.rs
+++ b/src/bootstrap/src/core/sanity.rs
@@ -33,11 +33,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] = &[
-    "armv7a-vex-v5",
-    "riscv64a23-unknown-linux-gnu",
     // just a dummy comment so the list doesn't get onelined
-    "aarch64_be-unknown-hermit",
-    "aarch64_be-unknown-none-softfloat",
     "x86_64-unknown-motor",
 ];
 
diff --git a/src/bootstrap/src/lib.rs b/src/bootstrap/src/lib.rs
index e953fe2945e..dd30f05b728 100644
--- a/src/bootstrap/src/lib.rs
+++ b/src/bootstrap/src/lib.rs
@@ -35,7 +35,7 @@ use utils::exec::ExecutionContext;
 
 use crate::core::builder;
 use crate::core::builder::Kind;
-use crate::core::config::{DryRun, LldMode, LlvmLibunwind, TargetSelection, flags};
+use crate::core::config::{BootstrapOverrideLld, DryRun, LlvmLibunwind, TargetSelection, flags};
 use crate::utils::exec::{BootstrapCommand, command};
 use crate::utils::helpers::{self, dir_is_empty, exe, libdir, set_file_times, split_debuginfo};
 
@@ -327,8 +327,8 @@ pub enum Mode {
     ToolTarget,
 
     /// Build a tool which uses the locally built std, placing output in the
-    /// "stageN-tools" directory. Its usage is quite rare, mainly used by
-    /// compiletest which needs libtest.
+    /// "stageN-tools" directory. Its usage is quite rare; historically it was
+    /// needed by compiletest, but now it is mainly used by `test-float-parse`.
     ToolStd,
 
     /// Build a tool which uses the `rustc_private` mechanism, and thus
@@ -415,7 +415,7 @@ macro_rules! forward {
 }
 
 forward! {
-    verbose(f: impl Fn()),
+    do_if_verbose(f: impl Fn()),
     is_verbose() -> bool,
     create(path: &Path, s: &str),
     remove(f: &Path),
@@ -601,11 +601,11 @@ impl Build {
             .unwrap()
             .trim();
         if local_release.split('.').take(2).eq(version.split('.').take(2)) {
-            build.verbose(|| println!("auto-detected local-rebuild {local_release}"));
+            build.do_if_verbose(|| println!("auto-detected local-rebuild {local_release}"));
             build.local_rebuild = true;
         }
 
-        build.verbose(|| println!("finding compilers"));
+        build.do_if_verbose(|| println!("finding compilers"));
         utils::cc_detect::fill_compilers(&mut build);
         // When running `setup`, the profile is about to change, so any requirements we have now may
         // be different on the next invocation. Don't check for them until the next time x.py is
@@ -613,7 +613,7 @@ impl Build {
         //
         // Similarly, for `setup` we don't actually need submodules or cargo metadata.
         if !matches!(build.config.cmd, Subcommand::Setup { .. }) {
-            build.verbose(|| println!("running sanity check"));
+            build.do_if_verbose(|| println!("running sanity check"));
             crate::core::sanity::check(&mut build);
 
             // Make sure we update these before gathering metadata so we don't get an error about missing
@@ -631,7 +631,7 @@ impl Build {
             // Now, update all existing submodules.
             build.update_existing_submodules();
 
-            build.verbose(|| println!("learning about cargo"));
+            build.do_if_verbose(|| println!("learning about cargo"));
             crate::core::metadata::build(&mut build);
         }
 
@@ -1087,18 +1087,6 @@ impl Build {
         })
     }
 
-    /// Check if verbosity is greater than the `level`
-    pub fn is_verbose_than(&self, level: usize) -> bool {
-        self.verbosity > level
-    }
-
-    /// Runs a function if verbosity is greater than `level`.
-    fn verbose_than(&self, level: usize, f: impl Fn()) {
-        if self.is_verbose_than(level) {
-            f()
-        }
-    }
-
     fn info(&self, msg: &str) {
         match self.config.get_dry_run() {
             DryRun::SelfCheck => (),
@@ -1370,14 +1358,14 @@ impl Build {
             && !target.is_msvc()
         {
             Some(self.cc(target))
-        } else if self.config.lld_mode.is_used()
+        } else if self.config.bootstrap_override_lld.is_used()
             && self.is_lld_direct_linker(target)
             && self.host_target == target
         {
-            match self.config.lld_mode {
-                LldMode::SelfContained => Some(self.initial_lld.clone()),
-                LldMode::External => Some("lld".into()),
-                LldMode::Unused => None,
+            match self.config.bootstrap_override_lld {
+                BootstrapOverrideLld::SelfContained => Some(self.initial_lld.clone()),
+                BootstrapOverrideLld::External => Some("lld".into()),
+                BootstrapOverrideLld::None => None,
             }
         } else {
             None
@@ -1816,7 +1804,6 @@ impl Build {
         if self.config.dry_run() {
             return;
         }
-        self.verbose_than(1, || println!("Copy/Link {src:?} to {dst:?}"));
         if src == dst {
             return;
         }
@@ -1933,7 +1920,10 @@ impl Build {
             return;
         }
         let dst = dstdir.join(src.file_name().unwrap());
-        self.verbose_than(1, || println!("Install {src:?} to {dst:?}"));
+
+        #[cfg(feature = "tracing")]
+        let _span = trace_io!("install", ?src, ?dst);
+
         t!(fs::create_dir_all(dstdir));
         if !src.exists() {
             panic!("ERROR: File \"{}\" not found!", src.display());
diff --git a/src/bootstrap/src/utils/build_stamp.rs b/src/bootstrap/src/utils/build_stamp.rs
index 4c35388a181..5cd68f6d4fe 100644
--- a/src/bootstrap/src/utils/build_stamp.rs
+++ b/src/bootstrap/src/utils/build_stamp.rs
@@ -112,7 +112,7 @@ pub fn clear_if_dirty(builder: &Builder<'_>, dir: &Path, input: &Path) -> bool {
     let stamp = BuildStamp::new(dir);
     let mut cleared = false;
     if mtime(stamp.path()) < mtime(input) {
-        builder.verbose(|| println!("Dirty - {}", dir.display()));
+        builder.do_if_verbose(|| println!("Dirty - {}", dir.display()));
         let _ = fs::remove_dir_all(dir);
         cleared = true;
     } else if stamp.path().exists() {
diff --git a/src/bootstrap/src/utils/cc_detect.rs b/src/bootstrap/src/utils/cc_detect.rs
index d3926df9650..0662ae304ac 100644
--- a/src/bootstrap/src/utils/cc_detect.rs
+++ b/src/bootstrap/src/utils/cc_detect.rs
@@ -137,16 +137,16 @@ pub fn fill_target_compiler(build: &mut Build, target: TargetSelection) {
         build.cxx.insert(target, compiler);
     }
 
-    build.verbose(|| println!("CC_{} = {:?}", target.triple, build.cc(target)));
-    build.verbose(|| println!("CFLAGS_{} = {cflags:?}", target.triple));
+    build.do_if_verbose(|| println!("CC_{} = {:?}", target.triple, build.cc(target)));
+    build.do_if_verbose(|| println!("CFLAGS_{} = {cflags:?}", target.triple));
     if let Ok(cxx) = build.cxx(target) {
         let mut cxxflags = build.cc_handled_clags(target, CLang::Cxx);
         cxxflags.extend(build.cc_unhandled_cflags(target, GitRepo::Rustc, CLang::Cxx));
-        build.verbose(|| println!("CXX_{} = {cxx:?}", target.triple));
-        build.verbose(|| println!("CXXFLAGS_{} = {cxxflags:?}", target.triple));
+        build.do_if_verbose(|| println!("CXX_{} = {cxx:?}", target.triple));
+        build.do_if_verbose(|| println!("CXXFLAGS_{} = {cxxflags:?}", target.triple));
     }
     if let Some(ar) = ar {
-        build.verbose(|| println!("AR_{} = {ar:?}", target.triple));
+        build.do_if_verbose(|| println!("AR_{} = {ar:?}", target.triple));
         build.ar.insert(target, ar);
     }
 
diff --git a/src/bootstrap/src/utils/change_tracker.rs b/src/bootstrap/src/utils/change_tracker.rs
index 6b187578c31..853fc4e6623 100644
--- a/src/bootstrap/src/utils/change_tracker.rs
+++ b/src/bootstrap/src/utils/change_tracker.rs
@@ -556,4 +556,14 @@ pub const CONFIG_CHANGE_HISTORY: &[ChangeInfo] = &[
         severity: ChangeSeverity::Info,
         summary: "New option `build.windows-rc` that will override which resource compiler on Windows will be used to compile Rust.",
     },
+    ChangeInfo {
+        change_id: 147046,
+        severity: ChangeSeverity::Warning,
+        summary: "The `rust.use-lld` option has been renamed to `rust.bootstrap-override-lld`. Note that it only serves for overriding the linker used when building Rust code in bootstrap to be LLD.",
+    },
+    ChangeInfo {
+        change_id: 146929,
+        severity: ChangeSeverity::Info,
+        summary: "`compiletest` is now always built with the stage 0 compiler, so `build.compiletest-use-stage0-libtest` has no effect.",
+    },
 ];
diff --git a/src/bootstrap/src/utils/exec.rs b/src/bootstrap/src/utils/exec.rs
index e09f3086b77..f875e6e1af7 100644
--- a/src/bootstrap/src/utils/exec.rs
+++ b/src/bootstrap/src/utils/exec.rs
@@ -630,7 +630,7 @@ impl ExecutionContext {
         &self.dry_run
     }
 
-    pub fn verbose(&self, f: impl Fn()) {
+    pub fn do_if_verbose(&self, f: impl Fn()) {
         if self.is_verbose() {
             f()
         }
@@ -686,7 +686,7 @@ impl ExecutionContext {
 
         if let Some(cached_output) = self.command_cache.get(&fingerprint) {
             command.mark_as_executed();
-            self.verbose(|| println!("Cache hit: {command:?}"));
+            self.do_if_verbose(|| println!("Cache hit: {command:?}"));
             self.profiler.record_cache_hit(fingerprint);
             return DeferredCommand { state: CommandState::Cached(cached_output) };
         }
@@ -713,7 +713,7 @@ impl ExecutionContext {
             };
         }
 
-        self.verbose(|| {
+        self.do_if_verbose(|| {
             println!("running: {command:?} (created at {created_at}, executed at {executed_at})")
         });
 
diff --git a/src/bootstrap/src/utils/helpers.rs b/src/bootstrap/src/utils/helpers.rs
index e802c0214dd..faada9a111d 100644
--- a/src/bootstrap/src/utils/helpers.rs
+++ b/src/bootstrap/src/utils/helpers.rs
@@ -12,7 +12,7 @@ use std::{env, fs, io, panic, str};
 
 use object::read::archive::ArchiveFile;
 
-use crate::LldMode;
+use crate::BootstrapOverrideLld;
 use crate::core::builder::Builder;
 use crate::core::config::{Config, TargetSelection};
 use crate::utils::exec::{BootstrapCommand, command};
@@ -357,15 +357,19 @@ pub fn get_clang_cl_resource_dir(builder: &Builder<'_>, clang_cl_path: &str) ->
 /// Returns a flag that configures LLD to use only a single thread.
 /// If we use an external LLD, we need to find out which version is it to know which flag should we
 /// pass to it (LLD older than version 10 had a different flag).
-fn lld_flag_no_threads(builder: &Builder<'_>, lld_mode: LldMode, is_windows: bool) -> &'static str {
+fn lld_flag_no_threads(
+    builder: &Builder<'_>,
+    bootstrap_override_lld: BootstrapOverrideLld,
+    is_windows: bool,
+) -> &'static str {
     static LLD_NO_THREADS: OnceLock<(&'static str, &'static str)> = OnceLock::new();
 
     let new_flags = ("/threads:1", "--threads=1");
     let old_flags = ("/no-threads", "--no-threads");
 
     let (windows_flag, other_flag) = LLD_NO_THREADS.get_or_init(|| {
-        let newer_version = match lld_mode {
-            LldMode::External => {
+        let newer_version = match bootstrap_override_lld {
+            BootstrapOverrideLld::External => {
                 let mut cmd = command("lld");
                 cmd.arg("-flavor").arg("ld").arg("--version");
                 let out = cmd.run_capture_stdout(builder).stdout();
@@ -422,24 +426,28 @@ pub fn linker_flags(
     lld_threads: LldThreads,
 ) -> 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 => {
+    if !builder.is_lld_direct_linker(target) && builder.config.bootstrap_override_lld.is_used() {
+        match builder.config.bootstrap_override_lld {
+            BootstrapOverrideLld::External => {
                 args.push("-Clinker-features=+lld".to_string());
                 args.push("-Zunstable-options".to_string());
             }
-            LldMode::SelfContained => {
+            BootstrapOverrideLld::SelfContained => {
                 args.push("-Clinker-features=+lld".to_string());
                 args.push("-Clink-self-contained=+linker".to_string());
                 args.push("-Zunstable-options".to_string());
             }
-            LldMode::Unused => unreachable!(),
+            BootstrapOverrideLld::None => unreachable!(),
         };
 
         if matches!(lld_threads, LldThreads::No) {
             args.push(format!(
                 "-Clink-arg=-Wl,{}",
-                lld_flag_no_threads(builder, builder.config.lld_mode, target.is_windows())
+                lld_flag_no_threads(
+                    builder,
+                    builder.config.bootstrap_override_lld,
+                    target.is_windows()
+                )
             ));
         }
     }
diff --git a/src/bootstrap/src/utils/helpers/tests.rs b/src/bootstrap/src/utils/helpers/tests.rs
index 9030ca2820a..676fe6cbd5f 100644
--- a/src/bootstrap/src/utils/helpers/tests.rs
+++ b/src/bootstrap/src/utils/helpers/tests.rs
@@ -6,6 +6,7 @@ use crate::utils::helpers::{
     check_cfg_arg, extract_beta_rev, hex_encode, make, set_file_times, submodule_path_of,
     symlink_dir,
 };
+use crate::utils::tests::TestCtx;
 use crate::{Config, Flags};
 
 #[test]
@@ -59,8 +60,7 @@ fn test_check_cfg_arg() {
 
 #[test]
 fn test_symlink_dir() {
-    let config =
-        Config::parse(Flags::parse(&["check".to_owned(), "--config=/does/not/exist".to_owned()]));
+    let config = TestCtx::new().config("check").no_dry_run().create_config();
     let tempdir = config.tempdir().join(".tmp-dir");
     let link_path = config.tempdir().join(".tmp-link");
 
@@ -80,8 +80,7 @@ fn test_symlink_dir() {
 
 #[test]
 fn test_set_file_times_sanity_check() {
-    let config =
-        Config::parse(Flags::parse(&["check".to_owned(), "--config=/does/not/exist".to_owned()]));
+    let config = TestCtx::new().config("check").create_config();
     let tempfile = config.tempdir().join(".tmp-file");
 
     {
@@ -102,9 +101,7 @@ fn test_set_file_times_sanity_check() {
 
 #[test]
 fn test_submodule_path_of() {
-    let config = Config::parse_inner(Flags::parse(&["build".into(), "--dry-run".into()]), |&_| {
-        Ok(Default::default())
-    });
+    let config = TestCtx::new().config("build").create_config();
 
     let build = crate::Build::new(config.clone());
     let builder = crate::core::builder::Builder::new(&build);
diff --git a/src/bootstrap/src/utils/render_tests.rs b/src/bootstrap/src/utils/render_tests.rs
index 90fd57d976d..e90a7ef4232 100644
--- a/src/bootstrap/src/utils/render_tests.rs
+++ b/src/bootstrap/src/utils/render_tests.rs
@@ -48,7 +48,7 @@ pub(crate) fn try_run_tests(
 }
 
 fn run_tests(builder: &Builder<'_>, cmd: &mut BootstrapCommand, stream: bool) -> bool {
-    builder.verbose(|| println!("running: {cmd:?}"));
+    builder.do_if_verbose(|| println!("running: {cmd:?}"));
 
     let Some(mut streaming_command) = cmd.stream_capture_stdout(&builder.config.exec_ctx) else {
         return true;
diff --git a/src/bootstrap/src/utils/tarball.rs b/src/bootstrap/src/utils/tarball.rs
index 7b77b212934..079afb7a005 100644
--- a/src/bootstrap/src/utils/tarball.rs
+++ b/src/bootstrap/src/utils/tarball.rs
@@ -356,7 +356,7 @@ impl<'a> Tarball<'a> {
 
         // For `x install` tarball files aren't needed, so we can speed up the process by not producing them.
         let compression_profile = if self.builder.kind == Kind::Install {
-            self.builder.verbose(|| {
+            self.builder.do_if_verbose(|| {
                 println!("Forcing dist.compression-profile = 'no-op' for `x install`.")
             });
             // "no-op" indicates that the rust-installer won't produce compressed tarball sources.
diff --git a/src/bootstrap/src/utils/tests/mod.rs b/src/bootstrap/src/utils/tests/mod.rs
index 3332187e2a8..764b89086cf 100644
--- a/src/bootstrap/src/utils/tests/mod.rs
+++ b/src/bootstrap/src/utils/tests/mod.rs
@@ -48,11 +48,20 @@ impl TestCtx {
 pub struct ConfigBuilder {
     args: Vec<String>,
     directory: PathBuf,
+    override_download_ci_llvm: bool,
+    dry_run: bool,
+    explicit_config: bool,
 }
 
 impl ConfigBuilder {
     fn from_args(args: &[&str], directory: PathBuf) -> Self {
-        Self { args: args.iter().copied().map(String::from).collect(), directory }
+        Self {
+            args: args.iter().copied().map(String::from).collect(),
+            directory,
+            override_download_ci_llvm: true,
+            dry_run: true,
+            explicit_config: true,
+        }
     }
 
     pub fn path(mut self, path: &str) -> Self {
@@ -98,18 +107,46 @@ impl ConfigBuilder {
         self
     }
 
-    pub fn create_config(mut self) -> Config {
-        // Run in dry-check, otherwise the test would be too slow
-        self.args.push("--dry-run".to_string());
+    pub fn with_default_toml_config(mut self, config_toml: &str) -> Self {
+        let toml_path = self.directory.join("bootstrap.toml");
+        std::fs::write(&toml_path, config_toml).unwrap();
+        self.explicit_config = false;
+        self.args.push("--config".to_string());
+        self.args.push(toml_path.display().to_string());
+        self
+    }
+
+    pub fn no_override_download_ci_llvm(mut self) -> Self {
+        self.override_download_ci_llvm = false;
+        self
+    }
+
+    pub fn no_dry_run(mut self) -> Self {
+        self.dry_run = false;
+        self
+    }
 
+    pub fn create_config(mut self) -> Config {
+        if self.dry_run {
+            // Run in dry-check, otherwise the test would be too slow
+            self.args.push("--dry-run".to_string());
+        }
         // Ignore submodules
         self.args.push("--set".to_string());
         self.args.push("build.submodules=false".to_string());
 
-        // Override any external LLVM set and inhibit CI LLVM; pretend that we're always building
-        // in-tree LLVM from sources.
-        self.args.push("--set".to_string());
-        self.args.push("llvm.download-ci-llvm=false".to_string());
+        if self.override_download_ci_llvm {
+            // Override any external LLVM set and inhibit CI LLVM; pretend that we're always building
+            // in-tree LLVM from sources.
+            self.args.push("--set".to_string());
+            self.args.push("llvm.download-ci-llvm=false".to_string());
+        }
+
+        // always use the bootstrap toml created in the
+        // temporary directory and not from the <src>
+        if self.explicit_config {
+            self = self.with_default_toml_config("");
+        }
 
         // Do not mess with the local rustc checkout build directory
         self.args.push("--build-dir".to_string());
diff --git a/src/build_helper/src/stage0_parser.rs b/src/build_helper/src/stage0_parser.rs
index 2723f4aa7b9..3f3297dcd2b 100644
--- a/src/build_helper/src/stage0_parser.rs
+++ b/src/build_helper/src/stage0_parser.rs
@@ -10,6 +10,8 @@ pub struct Stage0 {
 
 #[derive(Default, Clone)]
 pub struct VersionMetadata {
+    pub channel_manifest_hash: String,
+    pub git_commit_hash: String,
     pub date: String,
     pub version: String,
 }
@@ -50,9 +52,21 @@ pub fn parse_stage0_file() -> Stage0 {
             "git_merge_commit_email" => stage0.config.git_merge_commit_email = value.to_owned(),
             "nightly_branch" => stage0.config.nightly_branch = value.to_owned(),
 
+            "compiler_channel_manifest_hash" => {
+                stage0.compiler.channel_manifest_hash = value.to_owned()
+            }
+            "compiler_git_commit_hash" => stage0.compiler.git_commit_hash = value.to_owned(),
             "compiler_date" => stage0.compiler.date = value.to_owned(),
             "compiler_version" => stage0.compiler.version = value.to_owned(),
 
+            "rustfmt_channel_manifest_hash" => {
+                stage0.rustfmt.get_or_insert(VersionMetadata::default()).channel_manifest_hash =
+                    value.to_owned();
+            }
+            "rustfmt_git_commit_hash" => {
+                stage0.rustfmt.get_or_insert(VersionMetadata::default()).git_commit_hash =
+                    value.to_owned();
+            }
             "rustfmt_date" => {
                 stage0.rustfmt.get_or_insert(VersionMetadata::default()).date = value.to_owned();
             }
diff --git a/src/ci/citool/tests/test-jobs.yml b/src/ci/citool/tests/test-jobs.yml
index d82b3e7648e..512c8062857 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 check compiletest --set build.compiletest-use-stage0-libtest=true && ./x.py --stage 2 test --skip tests/ui --skip tests/rustdoc -- --exact
+    SCRIPT: ./x.py check compiletest && ./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/host-aarch64/dist-aarch64-linux/Dockerfile b/src/ci/docker/host-aarch64/dist-aarch64-linux/Dockerfile
index e726329753f..3abca36fe70 100644
--- a/src/ci/docker/host-aarch64/dist-aarch64-linux/Dockerfile
+++ b/src/ci/docker/host-aarch64/dist-aarch64-linux/Dockerfile
@@ -91,7 +91,7 @@ ENV RUST_CONFIGURE_ARGS \
       --set llvm.ninja=false \
       --set rust.debug-assertions=false \
       --set rust.jemalloc \
-      --set rust.use-lld=true \
+      --set rust.bootstrap-override-lld=true \
       --set rust.lto=thin \
       --set rust.codegen-units=1
 
diff --git a/src/ci/docker/host-x86_64/dist-x86_64-linux/Dockerfile b/src/ci/docker/host-x86_64/dist-x86_64-linux/Dockerfile
index 01f19eac1d2..cb574787619 100644
--- a/src/ci/docker/host-x86_64/dist-x86_64-linux/Dockerfile
+++ b/src/ci/docker/host-x86_64/dist-x86_64-linux/Dockerfile
@@ -92,7 +92,7 @@ ENV RUST_CONFIGURE_ARGS \
       --set llvm.ninja=false \
       --set llvm.libzstd=true \
       --set rust.jemalloc \
-      --set rust.use-lld=true \
+      --set rust.bootstrap-override-lld=true \
       --set rust.lto=thin \
       --set rust.codegen-units=1
 
diff --git a/src/ci/docker/host-x86_64/pr-check-1/Dockerfile b/src/ci/docker/host-x86_64/pr-check-1/Dockerfile
index 04ac0f33daf..776bbb12e44 100644
--- a/src/ci/docker/host-x86_64/pr-check-1/Dockerfile
+++ b/src/ci/docker/host-x86_64/pr-check-1/Dockerfile
@@ -43,7 +43,6 @@ ENV SCRIPT \
   python3 ../x.py check bootstrap && \
   /scripts/check-default-config-profiles.sh && \
   python3 ../x.py build src/tools/build-manifest && \
-  python3 ../x.py check compiletest --set build.compiletest-use-stage0-libtest=true && \
   python3 ../x.py check --target=i686-pc-windows-gnu --host=i686-pc-windows-gnu && \
   python3 ../x.py check --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/validate-toolstate.sh && \
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 95357d22937..278e40eb71f 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
@@ -90,5 +90,4 @@ ENV HOST_TARGET x86_64-unknown-linux-gnu
 COPY scripts/shared.sh /scripts/
 
 ENV SCRIPT /tmp/checktools.sh ../x.py && \
-  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/github-actions/jobs.yml b/src/ci/github-actions/jobs.yml
index b3e3fe7d96a..4384ec76769 100644
--- a/src/ci/github-actions/jobs.yml
+++ b/src/ci/github-actions/jobs.yml
@@ -430,10 +430,8 @@ auto:
       # Ensure that host tooling is built to support our minimum support macOS version.
       MACOSX_DEPLOYMENT_TARGET: 10.12
       MACOSX_STD_DEPLOYMENT_TARGET: 10.12
-      SELECT_XCODE: /Applications/Xcode_15.2.app
-      NO_LLVM_ASSERTIONS: 1
-      NO_DEBUG_ASSERTIONS: 1
-      NO_OVERFLOW_CHECKS: 1
+      SELECT_XCODE: /Applications/Xcode_15.4.app
+      USE_XCODE_CLANG: 1
       DIST_REQUIRE_ALL_TOOLS: 1
       CODEGEN_BACKENDS: llvm,cranelift
     <<: *job-macos
@@ -449,31 +447,28 @@ auto:
       MACOSX_DEPLOYMENT_TARGET: 10.12
       MACOSX_STD_DEPLOYMENT_TARGET: 10.12
       SELECT_XCODE: /Applications/Xcode_15.2.app
-      NO_LLVM_ASSERTIONS: 1
-      NO_DEBUG_ASSERTIONS: 1
-      NO_OVERFLOW_CHECKS: 1
     <<: *job-macos
 
   - name: dist-aarch64-apple
     env:
-      SCRIPT: ./x.py dist bootstrap --include-default-paths --host=aarch64-apple-darwin --target=aarch64-apple-darwin
+      SCRIPT: >-
+        ./x.py dist bootstrap
+        --include-default-paths
+        --host=aarch64-apple-darwin
+        --target=aarch64-apple-darwin
       RUST_CONFIGURE_ARGS: >-
         --enable-full-tools
         --enable-sanitizers
         --enable-profiler
         --set rust.jemalloc
-        --set llvm.ninja=false
         --set rust.lto=thin
         --set rust.codegen-units=1
-      SELECT_XCODE: /Applications/Xcode_15.4.app
-      USE_XCODE_CLANG: 1
       # Aarch64 tooling only needs to support macOS 11.0 and up as nothing else
       # supports the hardware.
       MACOSX_DEPLOYMENT_TARGET: 11.0
       MACOSX_STD_DEPLOYMENT_TARGET: 11.0
-      NO_LLVM_ASSERTIONS: 1
-      NO_DEBUG_ASSERTIONS: 1
-      NO_OVERFLOW_CHECKS: 1
+      SELECT_XCODE: /Applications/Xcode_15.4.app
+      USE_XCODE_CLANG: 1
       DIST_REQUIRE_ALL_TOOLS: 1
       CODEGEN_BACKENDS: llvm,cranelift
     <<: *job-macos
@@ -493,9 +488,6 @@ auto:
       # supports the hardware, so only need to test it there.
       MACOSX_DEPLOYMENT_TARGET: 11.0
       MACOSX_STD_DEPLOYMENT_TARGET: 11.0
-      NO_LLVM_ASSERTIONS: 1
-      NO_DEBUG_ASSERTIONS: 1
-      NO_OVERFLOW_CHECKS: 1
     <<: *job-macos
 
   ######################
diff --git a/src/doc/rustc/src/SUMMARY.md b/src/doc/rustc/src/SUMMARY.md
index e4bf33dd8a0..67882bb3813 100644
--- a/src/doc/rustc/src/SUMMARY.md
+++ b/src/doc/rustc/src/SUMMARY.md
@@ -52,7 +52,6 @@
     - [aarch64_be-unknown-none-softfloat](platform-support/aarch64_be-unknown-none-softfloat.md)
     - [aarch64_be-unknown-linux-musl](platform-support/aarch64_be-unknown-linux-musl.md)
     - [amdgcn-amd-amdhsa](platform-support/amdgcn-amd-amdhsa.md)
-    - [armeb-unknown-linux-gnueabi](platform-support/armeb-unknown-linux-gnueabi.md)
     - [arm-none-eabi](platform-support/arm-none-eabi.md)
       - [armv4t-none-eabi](platform-support/armv4t-none-eabi.md)
       - [armv5te-none-eabi](platform-support/armv5te-none-eabi.md)
@@ -65,12 +64,14 @@
       - [thumbv7m-none-eabi](./platform-support/thumbv7m-none-eabi.md)
       - [thumbv8m.base-none-eabi](./platform-support/thumbv8m.base-none-eabi.md)
       - [thumbv8m.main-none-eabi\*](./platform-support/thumbv8m.main-none-eabi.md)
-    - [armv5te-unknown-linux-gnueabi](platform-support/armv5te-unknown-linux-gnueabi.md)
+    - [arm\*-unknown-linux-\*](./platform-support/arm-linux.md)
+        - [armeb-unknown-linux-gnueabi](platform-support/armeb-unknown-linux-gnueabi.md)
+        - [armv5te-unknown-linux-gnueabi](platform-support/armv5te-unknown-linux-gnueabi.md)
+        - [armv7-unknown-linux-uclibceabi](platform-support/armv7-unknown-linux-uclibceabi.md)
+        - [armv7-unknown-linux-uclibceabihf](platform-support/armv7-unknown-linux-uclibceabihf.md)
     - [armv6k-nintendo-3ds](platform-support/armv6k-nintendo-3ds.md)
     - [armv7-rtems-eabihf](platform-support/armv7-rtems-eabihf.md)
     - [armv7-sony-vita-newlibeabihf](platform-support/armv7-sony-vita-newlibeabihf.md)
-    - [armv7-unknown-linux-uclibceabi](platform-support/armv7-unknown-linux-uclibceabi.md)
-    - [armv7-unknown-linux-uclibceabihf](platform-support/armv7-unknown-linux-uclibceabihf.md)
     - [armv7a-vex-v5](platform-support/armv7a-vex-v5.md)
     - [\*-android and \*-androideabi](platform-support/android.md)
     - [\*-linux-ohos](platform-support/openharmony.md)
@@ -120,6 +121,7 @@
     - [\*-unknown-hermit](platform-support/hermit.md)
     - [\*-unknown-freebsd](platform-support/freebsd.md)
     - [\*-unknown-managarm-mlibc](platform-support/managarm.md)
+    - [\*-unknown-motor](platform-support/motor.md)
     - [\*-unknown-netbsd\*](platform-support/netbsd.md)
     - [\*-unknown-openbsd](platform-support/openbsd.md)
     - [\*-unknown-redox](platform-support/redox.md)
diff --git a/src/doc/rustc/src/lints/levels.md b/src/doc/rustc/src/lints/levels.md
index 5b002b435a5..09b55da741d 100644
--- a/src/doc/rustc/src/lints/levels.md
+++ b/src/doc/rustc/src/lints/levels.md
@@ -38,7 +38,7 @@ talk about later in this section.
 
 Sometimes, it can be helpful to suppress lints, but at the same time ensure that
 the code in question still emits them. The 'expect' level does exactly this. If
-the lint in question is not emitted, the `unfulfilled_lint_expectation` lint
+the lint in question is not emitted, the `unfulfilled_lint_expectations` lint
 triggers on the `expect` attribute, notifying you that the expectation is no
 longer fulfilled.
 
diff --git a/src/doc/rustc/src/platform-support.md b/src/doc/rustc/src/platform-support.md
index 99c8e365f5c..d0b6ed51bc1 100644
--- a/src/doc/rustc/src/platform-support.md
+++ b/src/doc/rustc/src/platform-support.md
@@ -156,8 +156,6 @@ target | std | notes
 `arm-unknown-linux-musleabi` | ✓ | Armv6 Linux with musl 1.2.3
 `arm-unknown-linux-musleabihf` | ✓ | Armv6 Linux with musl 1.2.3, hardfloat
 [`arm64ec-pc-windows-msvc`](platform-support/arm64ec-pc-windows-msvc.md) | ✓ | Arm64EC Windows MSVC
-[`armebv7r-none-eabi`](platform-support/armebv7r-none-eabi.md) | * | Bare Armv7-R, Big Endian
-[`armebv7r-none-eabihf`](platform-support/armebv7r-none-eabi.md) | * | Bare Armv7-R, Big Endian, hardfloat
 [`armv5te-unknown-linux-gnueabi`](platform-support/armv5te-unknown-linux-gnueabi.md) | ✓ | Armv5TE Linux (kernel 4.4+, glibc 2.23)
 `armv5te-unknown-linux-musleabi` | ✓ | Armv5TE Linux with musl 1.2.3
 [`armv7-linux-androideabi`](platform-support/android.md) | ✓ | Armv7-A Android
@@ -283,6 +281,8 @@ target | std | host | notes
 [`arm64e-apple-ios`](platform-support/arm64e-apple-ios.md) | ✓ | | ARM64e Apple iOS
 [`arm64e-apple-tvos`](platform-support/arm64e-apple-tvos.md)  | ✓ | | ARM64e Apple tvOS
 [`armeb-unknown-linux-gnueabi`](platform-support/armeb-unknown-linux-gnueabi.md) | ✓ | ? | Arm BE8 the default Arm big-endian architecture since [Armv6](https://developer.arm.com/documentation/101754/0616/armlink-Reference/armlink-Command-line-Options/--be8?lang=en).
+[`armebv7r-none-eabi`](platform-support/armebv7r-none-eabi.md) | * | Bare Armv7-R, Big Endian
+[`armebv7r-none-eabihf`](platform-support/armebv7r-none-eabi.md) | * | Bare Armv7-R, Big Endian, hardfloat
 [`armv4t-none-eabi`](platform-support/armv4t-none-eabi.md) | * |  | Bare Armv4T
 `armv4t-unknown-linux-gnueabi` | ? |  | Armv4T Linux
 [`armv5te-none-eabi`](platform-support/armv5te-none-eabi.md) | * |  | Bare Armv5TE
@@ -431,7 +431,7 @@ target | std | host | notes
 `x86_64-unknown-l4re-uclibc` | ? |  |
 [`x86_64-unknown-linux-none`](platform-support/x86_64-unknown-linux-none.md) | * |  | 64-bit Linux with no libc
 [`x86_64-unknown-managarm-mlibc`](platform-support/managarm.md) | ? |   | x86_64 Managarm
-[`x86_64-unknown-motor`[(platform-support/motor.md) | ? |  | x86_64 Motor OS
+[`x86_64-unknown-motor`](platform-support/motor.md) | ? |  | x86_64 Motor OS
 [`x86_64-unknown-openbsd`](platform-support/openbsd.md) | ✓ | ✓ | 64-bit OpenBSD
 [`x86_64-unknown-trusty`](platform-support/trusty.md) | ✓ |  |
 `x86_64-uwp-windows-gnu` | ✓ |  |
diff --git a/src/doc/rustc/src/platform-support/apple-ios-macabi.md b/src/doc/rustc/src/platform-support/apple-ios-macabi.md
index c6f68f7a1e8..0d0acaa3bef 100644
--- a/src/doc/rustc/src/platform-support/apple-ios-macabi.md
+++ b/src/doc/rustc/src/platform-support/apple-ios-macabi.md
@@ -57,7 +57,7 @@ $ rustc --target aarch64-apple-ios-macabi your-code.rs
 ```
 
 The target can be differentiated from the iOS targets with the
-`target_env = "macabi"` cfg (or `target_abi = "macabi"` before Rust CURRENT_RUSTC_VERSION).
+`target_env = "macabi"` cfg (or `target_abi = "macabi"` before Rust 1.91.0).
 
 ```rust
 if cfg!(target_env = "macabi") {
diff --git a/src/doc/rustc/src/platform-support/apple-ios.md b/src/doc/rustc/src/platform-support/apple-ios.md
index 3ac14704754..5de87dc349e 100644
--- a/src/doc/rustc/src/platform-support/apple-ios.md
+++ b/src/doc/rustc/src/platform-support/apple-ios.md
@@ -73,7 +73,7 @@ $ cargo +nightly build -Zbuild-std --target armv7s-apple-ios
 
 The simulator variants can be differentiated from the variants running
 on-device with the `target_env = "sim"` cfg (or `target_abi = "sim"` before
-Rust CURRENT_RUSTC_VERSION).
+Rust 1.91.0).
 
 ```rust
 if cfg!(all(target_vendor = "apple", target_env = "sim")) {
diff --git a/src/doc/rustc/src/platform-support/arm-linux.md b/src/doc/rustc/src/platform-support/arm-linux.md
new file mode 100644
index 00000000000..5f40743f3d0
--- /dev/null
+++ b/src/doc/rustc/src/platform-support/arm-linux.md
@@ -0,0 +1,217 @@
+# Arm Linux support in Rust
+
+The Arm Architecture has been around since the mid-1980s, going through nine
+major revisions, many minor revisions, and spanning both 32-bith and 64-bit
+architectures. This page covers 32-bit Arm platforms that run some form of
+Linux (but not Android). Those targets are:
+
+* `arm-unknown-linux-gnueabi`
+* `arm-unknown-linux-gnueabihf`
+* `arm-unknown-linux-musleabi`
+* `arm-unknown-linux-musleabihf`
+* [`armeb-unknown-linux-gnueabi`](armeb-unknown-linux-gnueabi.md)
+* `armv4t-unknown-linux-gnueabi`
+* [`armv5te-unknown-linux-gnueabi`](armv5te-unknown-linux-gnueabi.md)
+* `armv5te-unknown-linux-musleabi`
+* `armv5te-unknown-linux-uclibceabi`
+* `armv7-unknown-linux-gnueabi`
+* `armv7-unknown-linux-gnueabihf`
+* `armv7-unknown-linux-musleabi`
+* `armv7-unknown-linux-musleabihf`
+* `armv7-unknown-linux-ohos`
+* [`armv7-unknown-linux-uclibceabi`](armv7-unknown-linux-uclibceabi.md)
+* [`armv7-unknown-linux-uclibceabihf`](armv7-unknown-linux-uclibceabihf.md)
+* `thumbv7neon-unknown-linux-gnueabihf`
+* `thumbv7neon-unknown-linux-musleabihf`
+
+Some of these targets have dedicated pages and some do not. This is largely
+due to historical accident, or the enthusiasm of the maintainers. This
+document attempts to cover all the targets, but only in broad terms.
+
+To make sense of this list, the architecture and ABI component of the
+`<architecture>-unknown-linux-<abi>` tuple will be discussed separately.
+
+The second part of the tuple is `unknown` because these systems don't come
+from any one specific vendor (like `powerpc-ibm-aix` or
+`aarch64-apple-darwin`). The third part is `linux`, because this page only
+discusses Linux targets.
+
+## Architecture Component
+
+* `arm`
+* `armeb`
+* `armv4t`
+* `armv5te`
+* `armv7`
+* `thumbv7neon`
+
+The architecture component simply called `arm` corresponds to the Armv6
+architecture - that is, version 6 of the Arm Architecture as defined in
+version 6 of the Arm Architecture Reference Manual (the Arm ARM). This was the
+last 'legacy' release of the Arm architecture, before they split into
+Application, Real-Time and Microcontroller profiles (leading to Armv7-A,
+Armv7-R and Armv7-M). Processors that implement the Armv6 architecture include
+the ARM1176JZF-S, as found in BCM2835 SoC that powers the Raspberry Pi Zero.
+Arm processors are generally fairly backwards compatible, especially for
+user-mode code, so code compiled for the `arm` architecture should also work
+on newer ARMv7-A systems, or even 64/32-bit Armv8-A systems.
+
+The `armeb` architecture component specifies an Armv6 processor running in Big
+Endian mode (`eb` is for big-endian - the letters are backwards because
+engineers used to little-endian systems perceive big-endian numbers to be
+written into memory backwards, and they thought it was funnier like that).
+Most Arm processors can operate in either little-endian or big-endian mode and
+little-endian mode is by far the most common. However, if for whatever reason
+you wish to store your Most Significant Bytes first, these targets are
+available. They just aren't terribly well tested, or compatible with most
+existing pre-compiled Arm libraries.
+
+Targets that start with `armv4t` are for processors implementing the Armv4T
+architecture from 1994. These include the ARM7TDMI, as found in the Nokia 6110
+brick-phone and the Game Boy Advance. The 'T' stands for *Thumb* and indicate
+that the processors can execute smaller 16-bit versions of some of the 32-bit
+Arm instructions. Because a Thumb is like a small version of an Arm.
+
+Targets that start with `armv5te` are for processors implementing the Armv5TE
+architecture. These are mostly from the ARM9 family, like the ARM946E-S found
+in the Nintendo DS. If you are programming an Arm machine from the early
+2000s, this might be what you need.
+
+The `armv7` is arguably a misnomer, and it should be `armv7a`. This is because
+it corresponds to the Application profile of Armv7 (i.e. Armv7-A), as opposed
+to the Real-Time or Microcontroller profile. Processors implementing this
+architecture include the Cortex-A7 and Cortex-A8.
+
+The `thumbv7neon` component indicates support for a processor that implements
+ARMv7-A (the same as `armv7`), it generates Thumb instructions (technically
+Thumb-2, also known as the T32 ISA) as opposed to Arm instructions (also known
+as the A32 ISA). These instructions are smaller, giving more code per KB of
+RAM, but may have a performance penalty if they take two instructions to do
+something Arm instructions could do in one. It's a complex trade-off and you
+should be doing benchmarks to work out which is better for you, if you
+strongly care about code size and/or performance. This component also enables
+support for Arm's SIMD extensions, known as Neon. These extensions will
+improve performance for certain kinds of repetitive operations.
+
+## ABI Component
+
+* `gnueabi`
+* `gnueabihf`
+* `musleabi`
+* `musleabihf`
+* `ohos`
+* `uclibceabi`
+* `uclibceabihf`
+
+You will need to select the appropriate ABI to match the system you want to be
+running this code on. For example, running `eabihf` code on an `eabi` system
+will not work correctly.
+
+The `gnueabi` ABI component indicates support for using the GNU C Library
+(glibc), and the Arm Embedded ABI (EABI). The EABI is a replacement for the
+original ABI (now called the Old ABI or OABI), and it is the standard ABI for
+32-bit Arm systems. With this ABI, function parameters that are `f32` or `f64`
+are passed as if they were integers, instead of being passed via in FPU
+registers. Generally these targets also disable the use of the FPU entirely,
+although that isn't always true.
+
+The `gnueabihf` ABI component is like `gnueabi`, except that it support the
+'hard-float' of the EABI. That is, function parameters that are `f32` or `f64`
+are passed in FPU registers. Naturally, this makes the FPU mandatory.
+
+Most 'desktop' Linux distributions (Debian, Ubuntu, Fedora, etc) use the GNU C
+Library and so you should probably select either `gnueabi` or `gnueabihf`,
+depending on whether your distribution is using 'soft-float' (EABI) or
+'hard-float' (EABIHF). Debian happens to offer
+[both](https://wiki.debian.org/ArmEabiPort)
+[kinds](https://wiki.debian.org/ArmHardFloatPort).
+
+The `musleabi` and `musleabihf` ABI components offer support for the [musl C
+library](https://musl.libc.org/). This C library can be used to create 'static
+binaries' that have no run-time library requirements (a feature that glibc
+does not support). There are soft-float (`eabi`) and hard-float (`eabihf`)
+variants, as per the `gnu*` targets above.
+
+The `uclibceabi` and `uclibceabihf` ABI components are for the [uClibc-ng C
+library](https://uclibc-ng.org/). This is sometimes used in light-weight
+embedded Linux distributions, like those created with
+[buildroot](https://www.buildroot.org/).
+
+## Cross Compilation
+
+Unfortunately, 32-bit Arm machines are generally not the fastest around, and
+they don't have much RAM. This means you are likely to be cross-compiling.
+
+To do this, you need to give Rust a suitable linker to use - one that knows
+the Arm architecture, and more importantly, knows where to find a suitable C
+Library to link against.
+
+To do that, you can add the `linker` property to your `.cargo/config.toml`.
+Typically you would refer to a suitable copy of GCC that has built as a
+cross-compiler, alongside a C library.
+
+```toml
+[target.arm-unknown-linux-gnueabi]
+linker = "arm-linux-gnueabi-gcc"
+```
+
+On Debian Linux, you could install such a cross-compilation toolchain with
+`apt install gcc-arm-linux-gnueabi`. For more exotic combinations, you might
+need to build a bespoke version of GCC using [crosstool-ng].
+
+[crosstool-ng]: https://github.com/crosstool-ng/crosstool-ng
+
+Note that for GCC, all 32-bit Arm architectures are handled in the same build
+- there are no separate Armv4T or Armv6 builds of GCC. The architecture is
+selected with flags, like `-march=armv6`, but they aren't required for the
+linker.
+
+Let's assume we are on some Debian machine, and we want to build a basic Arm
+Linux binary for a distribution using the GNU C Library, targeting Armv6 with
+a hard-float ABI. Such a binary should work on a Raspberry Pi, for example.
+The commands are:
+
+```bash
+sudo apt install -y gcc-arm-linux-gnueabihf
+rustup target add arm-unknown-linux-gnueabihf
+cargo new --bin armdemo
+cd armdemo
+mkdir .cargo
+cat > .cargo/config.toml << EOF
+[target.arm-unknown-linux-gnueabihf]
+linker = "arm-linux-gnueabihf-gcc"
+EOF
+cargo build --target=arm-unknown-linux-gnueabihf
+```
+
+This will give us our ARM Linux binary for the GNU C Library with a soft-float ABI:
+
+```console
+$ file ./target/arm-unknown-linux-gnueabi/debug/armdemo
+./target/arm-unknown-linux-gnueabi/debug/armdemo: ELF 32-bit LSB pie
+  executable, ARM, EABI5 version 1 (SYSV), dynamically linked, interpreter
+  /lib/ld-linux.so.3, BuildID[sha1]=dd0b9aa5ae876330fd4e2fcf393850f083ec7fcd,
+  for GNU/Linux 3.2.0, with debug_info, not stripped
+```
+
+If you are building C code as part of your Rust project, you may want to
+direct `cc-rs` to use an appropriate cross-compiler with the `CROSS_COMPILE`
+environment variable. You may also want to set the CFLAGS environment variable
+for the target. For example:
+
+```bash
+export CROSS_COMPILE=arm-linux-gnueabi
+export CFLAGS_arm_unknown_linux_gnueabi="-march=armv6"
+```
+
+(Note that the dashes (`-`) turn to underscores (`_`) to form the name of the
+CFLAGS environment variable)
+
+If you are building for a Tier 3 target using `-Zbuild-std` (on Nightly Rust),
+you need to set these variables as well:
+
+```bash
+export CXX_arm_unknown_linux_gnueabi=arm-linux-gnueabi-g++
+export CC_arm_unknown_linux_gnueabi=arm-linux-gnueabi-gcc
+cargo +nightly build -Zbuild-std --target=arm-unknown-linux-gnueabi
+```
diff --git a/src/doc/rustc/src/platform-support/armeb-unknown-linux-gnueabi.md b/src/doc/rustc/src/platform-support/armeb-unknown-linux-gnueabi.md
index 7c1c5db7076..cd0623f73a1 100644
--- a/src/doc/rustc/src/platform-support/armeb-unknown-linux-gnueabi.md
+++ b/src/doc/rustc/src/platform-support/armeb-unknown-linux-gnueabi.md
@@ -3,6 +3,9 @@
 
 Target for cross-compiling Linux user-mode applications targeting the Arm BE8 architecture.
 
+See [`arm-linux`](arm-linux.md) for information applicable to all Arm Linux
+targets.
+
 ## Overview
 BE8 architecture retains the same little-endian ordered code-stream used by conventional little endian Arm systems, however the data accesses are in big-endian. BE8 is used primarily in high-performance networking applications where the ability to read packets in their native "Network Byte Order" is important (many network protocols transmit data in big-endian byte order for their wire formats).
 
diff --git a/src/doc/rustc/src/platform-support/armebv7r-none-eabi.md b/src/doc/rustc/src/platform-support/armebv7r-none-eabi.md
index 3e90319c373..d5c676ea9a4 100644
--- a/src/doc/rustc/src/platform-support/armebv7r-none-eabi.md
+++ b/src/doc/rustc/src/platform-support/armebv7r-none-eabi.md
@@ -1,6 +1,6 @@
 # `armebv7r-none-eabi` and `armebv7r-none-eabihf`
 
-* **Tier: 2**
+* **Tier: 3**
 * **Library Support:** core and alloc (bare-metal, `#![no_std]`)
 
 Bare-metal target for CPUs in the Armv7-R architecture family running in Big
diff --git a/src/doc/rustc/src/platform-support/armv5te-unknown-linux-gnueabi.md b/src/doc/rustc/src/platform-support/armv5te-unknown-linux-gnueabi.md
index 0aebbc34d40..a924f476411 100644
--- a/src/doc/rustc/src/platform-support/armv5te-unknown-linux-gnueabi.md
+++ b/src/doc/rustc/src/platform-support/armv5te-unknown-linux-gnueabi.md
@@ -5,6 +5,9 @@
 This target supports Linux programs with glibc on ARMv5TE CPUs without
 floating-point units.
 
+See [`arm-linux`](arm-linux.md) for information applicable to all Arm Linux
+targets.
+
 ## Target maintainers
 
 There are currently no formally documented target maintainers.
diff --git a/src/doc/rustc/src/platform-support/armv7-unknown-linux-uclibceabi.md b/src/doc/rustc/src/platform-support/armv7-unknown-linux-uclibceabi.md
index e553c49589d..4ab0a07090a 100644
--- a/src/doc/rustc/src/platform-support/armv7-unknown-linux-uclibceabi.md
+++ b/src/doc/rustc/src/platform-support/armv7-unknown-linux-uclibceabi.md
@@ -4,6 +4,9 @@
 
 This target supports Armv7-A softfloat CPUs and uses the uclibc-ng standard library. This is a common configuration on many consumer routers (e.g., Netgear R7000, Asus RT-AC68U).
 
+See [`arm-linux`](arm-linux.md) for information applicable to all Arm Linux
+targets.
+
 ## Target maintainers
 
 [@lancethepants](https://github.com/lancethepants)
diff --git a/src/doc/rustc/src/platform-support/armv7-unknown-linux-uclibceabihf.md b/src/doc/rustc/src/platform-support/armv7-unknown-linux-uclibceabihf.md
index 91f3ea886cc..9fb24906b4f 100644
--- a/src/doc/rustc/src/platform-support/armv7-unknown-linux-uclibceabihf.md
+++ b/src/doc/rustc/src/platform-support/armv7-unknown-linux-uclibceabihf.md
@@ -4,6 +4,9 @@
 
 This tier supports the Armv7-A processor running a Linux kernel and uClibc-ng standard library.  It provides full support for rust and the rust standard library.
 
+See [`arm-linux`](arm-linux.md) for information applicable to all Arm Linux
+targets.
+
 ## Target Maintainers
 
 [@skrap](https://github.com/skrap)
diff --git a/src/doc/rustc/src/symbol-mangling/v0.md b/src/doc/rustc/src/symbol-mangling/v0.md
index 109942518fc..2bcc453a532 100644
--- a/src/doc/rustc/src/symbol-mangling/v0.md
+++ b/src/doc/rustc/src/symbol-mangling/v0.md
@@ -710,6 +710,7 @@ A *placeholder* may occur in circumstances where a type or const value is not re
 [mut-ptr-type]: #mut-ptr-type
 [fn-type]: #fn-type
 [dyn-trait-type]: #dyn-trait-type
+[pattern-type]: #pattern-type
 
 > type → \
 > &nbsp;&nbsp;&nbsp;&nbsp;&nbsp; *[basic-type]* \
@@ -722,6 +723,7 @@ A *placeholder* may occur in circumstances where a type or const value is not re
 > &nbsp;&nbsp; | *[mut-ptr-type]* \
 > &nbsp;&nbsp; | *[fn-type]* \
 > &nbsp;&nbsp; | *[dyn-trait-type]* \
+> &nbsp;&nbsp; | *[pattern-type]* \
 > &nbsp;&nbsp; | *[path]* \
 > &nbsp;&nbsp; | *[backref]*
 
@@ -830,6 +832,23 @@ Remaining primitives are encoded as a crate production, e.g. `C4f128`.
 [fn-sig]: #fn-sig
 [abi]: #abi
 
+* `W` — A [pattern-type][pattern-tpye] `u32 is 0..100`.
+  > <span id="pattern-type">pattern-type</span> → `W` *[pattern-kind]*
+  >
+  > <span id="pattern-kind">pattern-kind</span> → \
+  > &nbsp;&nbsp;&nbsp;&nbsp;&nbsp; *[range-pattern-kind]* \
+  > &nbsp;&nbsp; *[or-pattern-kind]*
+  >
+  > <span id="range-pattern-kind">range-pattern-kind</span> → `R` *[const]* *[const]*
+  >
+  > <span id="or-pattern-kind">or-pattern-kind</span> → `O` *[pattern-kind]* `E`
+
+  While or patterns can be nested in theory, in practice this does not happen and they are instead flattened.
+
+  Range patterns have a start and end constant that are both included in the range.
+  The end must be larger than the start (there can be no wraparound). To emulate wraparound,
+  you need to use an or pattern of the two ranges to the upper limit and from the lower limit.
+
 * `D` — A [trait object][reference-trait-object] `dyn Trait<Assoc=X> + Send + 'a`.
 
   > <span id="dyn-trait-type">dyn-trait-type</span> → `D` *[dyn-bounds]* *[lifetime]*
@@ -1139,6 +1158,7 @@ The following is a summary of all of the productions of the symbol grammar.
 > &nbsp;&nbsp; | *[mut-ptr-type]* \
 > &nbsp;&nbsp; | *[fn-type]* \
 > &nbsp;&nbsp; | *[dyn-trait-type]* \
+> &nbsp;&nbsp; | *[pattern-type]* \
 > &nbsp;&nbsp; | *[path]* \
 > &nbsp;&nbsp; | *[backref]*
 >
@@ -1152,6 +1172,14 @@ The following is a summary of all of the productions of the symbol grammar.
 > [mut-ptr-type] → `O` *[type]* \
 > [fn-type] → `F` *[fn-sig]* \
 > [dyn-trait-type] → `D` *[dyn-bounds]* *[lifetime]*
+> [pattern-type] → `W` *[pattern-kind]*
+>
+> [pattern-kind] → \
+> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp; *[range-pattern-kind]* \
+> &nbsp;&nbsp; *[or-pattern-kind]*
+>
+> [range-pattern-kind] -> `R` *[const]* *[const]* \
+> [or-pattern-kind] -> `O` *[pattern-kind]* `E` \
 >
 > [namespace] → *[lower]* | *[upper]*
 >
diff --git a/src/doc/rustdoc/src/advanced-features.md b/src/doc/rustdoc/src/advanced-features.md
index c02c9aebe7e..f49edb2ac78 100644
--- a/src/doc/rustdoc/src/advanced-features.md
+++ b/src/doc/rustdoc/src/advanced-features.md
@@ -89,20 +89,30 @@ https://doc.rust-lang.org/stable/std/?search=%s&go_to_first=true
 This URL adds the `go_to_first=true` query parameter which can be appended to any `rustdoc` search URL
 to automatically go to the first result.
 
-## `#[repr(transparent)]`: Documenting the transparent representation
+## `#[repr(...)]`: Documenting the representation of a type
+
+Generally, rustdoc only displays the representation of a given type if none of its variants are
+`#[doc(hidden)]` and if all of its fields are public and not `#[doc(hidden)]` since it's likely
+not meant to be considered part of the public ABI otherwise.
+
+Note that there's no way to overwrite that heuristic and force rustdoc to show the representation
+regardless.
+
+### `#[repr(transparent)]`
 
 You can read more about `#[repr(transparent)]` itself in the [Rust Reference][repr-trans-ref] and
 in the [Rustonomicon][repr-trans-nomicon].
 
 Since this representation is only considered part of the public ABI if the single field with non-trivial
-size or alignment is public and if the documentation does not state otherwise, Rustdoc helpfully displays
-the attribute if and only if the non-1-ZST field is public or at least one field is public in case all
-fields are 1-ZST fields. The term *1-ZST* refers to types that are one-aligned and zero-sized.
+size or alignment is public and if the documentation does not state otherwise, rustdoc helpfully displays
+the attribute if and only if the non-1-ZST field is public and not `#[doc(hidden)]` or
+– in case all fields are 1-ZST fields — at least one field is public and not `#[doc(hidden)]`.
+The term *1-ZST* refers to types that are one-aligned and zero-sized.
 
 It would seem that one can manually hide the attribute with `#[cfg_attr(not(doc), repr(transparent))]`
 if one wishes to declare the representation as private even if the non-1-ZST field is public.
 However, due to [current limitations][cross-crate-cfg-doc], this method is not always guaranteed to work.
-Therefore, if you would like to do so, you should always write it down in prose independently of whether
+Therefore, if you would like to do so, you should always write that down in prose independently of whether
 you use `cfg_attr` or not.
 
 [repr-trans-ref]: https://doc.rust-lang.org/reference/type-layout.html#the-transparent-representation
diff --git a/src/doc/rustdoc/src/unstable-features.md b/src/doc/rustdoc/src/unstable-features.md
index 4327a80cd08..04d3c0cd630 100644
--- a/src/doc/rustdoc/src/unstable-features.md
+++ b/src/doc/rustdoc/src/unstable-features.md
@@ -56,88 +56,6 @@ It is also not emitted for foreign items, aliases, extern crates and imports.
 These features operate by extending the `#[doc]` attribute, and thus can be caught by the compiler
 and enabled with a `#![feature(...)]` attribute in your crate.
 
-### `#[doc(cfg)]`: Recording what platforms or features are required for code to be present
-
- * Tracking issue: [#43781](https://github.com/rust-lang/rust/issues/43781)
-
-You can use `#[doc(cfg(...))]` to tell Rustdoc exactly which platform items appear on.
-This has two effects:
-
-1. doctests will only run on the appropriate platforms, and
-2. When Rustdoc renders documentation for that item, it will be accompanied by a banner explaining
-   that the item is only available on certain platforms.
-
-`#[doc(cfg)]` is intended to be used alongside [`#[cfg(doc)]`][cfg-doc].
-For example, `#[cfg(any(windows, doc))]` will preserve the item either on Windows or during the
-documentation process. Then, adding a new attribute `#[doc(cfg(windows))]` will tell Rustdoc that
-the item is supposed to be used on Windows. For example:
-
-```rust
-#![feature(doc_cfg)]
-
-/// Token struct that can only be used on Windows.
-#[cfg(any(windows, doc))]
-#[doc(cfg(windows))]
-pub struct WindowsToken;
-
-/// Token struct that can only be used on Unix.
-#[cfg(any(unix, doc))]
-#[doc(cfg(unix))]
-pub struct UnixToken;
-
-/// Token struct that is only available with the `serde` feature
-#[cfg(feature = "serde")]
-#[doc(cfg(feature = "serde"))]
-#[derive(serde::Deserialize)]
-pub struct SerdeToken;
-```
-
-In this sample, the tokens will only appear on their respective platforms, but they will both appear
-in documentation.
-
-`#[doc(cfg(...))]` was introduced to be used by the standard library and currently requires the
-`#![feature(doc_cfg)]` feature gate. For more information, see [its chapter in the Unstable
-Book][unstable-doc-cfg] and [its tracking issue][issue-doc-cfg].
-
-### `doc_auto_cfg`: Automatically generate `#[doc(cfg)]`
-
- * Tracking issue: [#43781](https://github.com/rust-lang/rust/issues/43781)
-
-`doc_auto_cfg` is an extension to the `#[doc(cfg)]` feature. With it, you don't need to add
-`#[doc(cfg(...)]` anymore unless you want to override the default behaviour. So if we take the
-previous source code:
-
-```rust
-#![feature(doc_auto_cfg)]
-
-/// Token struct that can only be used on Windows.
-#[cfg(any(windows, doc))]
-pub struct WindowsToken;
-
-/// Token struct that can only be used on Unix.
-#[cfg(any(unix, doc))]
-pub struct UnixToken;
-
-/// Token struct that is only available with the `serde` feature
-#[cfg(feature = "serde")]
-#[derive(serde::Deserialize)]
-pub struct SerdeToken;
-```
-
-It'll render almost the same, the difference being that `doc` will also be displayed. To fix this,
-you can use `doc_cfg_hide`:
-
-```rust
-#![feature(doc_cfg_hide)]
-#![doc(cfg_hide(doc))]
-```
-
-And `doc` won't show up anymore!
-
-[cfg-doc]: ./advanced-features.md
-[unstable-doc-cfg]: ../unstable-book/language-features/doc-cfg.html
-[issue-doc-cfg]: https://github.com/rust-lang/rust/issues/43781
-
 ### Adding your trait to the "Notable traits" dialog
 
  * Tracking issue: [#45040](https://github.com/rust-lang/rust/issues/45040)
@@ -801,3 +719,271 @@ pass `--doctest-build-arg ARG` for each argument `ARG`.
 ## `--generate-macro-expansion`: Generate macros expansion toggles in source code
 
 This flag enables the generation of toggles to expand macros in the HTML source code pages.
+
+## `#[doc(cfg)]` and `#[doc(auto_cfg)]`
+
+This feature aims at providing rustdoc users the possibility to add visual markers to the rendered documentation to know under which conditions an item is available (currently possible through the following unstable feature: `doc_cfg`).
+
+It does not aim to allow having a same item with different `cfg`s to appear more than once in the generated documentation.
+
+It does not aim to document items which are *inactive* under the current configuration (i.e., “`cfg`ed out”).
+
+This features adds the following attributes:
+
+ * `#[doc(auto_cfg)]`/`#[doc(auto_cfg = true)]`/`#[doc(auto_cfg = false)]`
+ * `#[doc(cfg(...))]`
+ * `#![doc(auto_cfg(hide(...)))]` / `#[doc(auto_cfg(show(...)))]`
+
+All of these attributes can be added to a module or to the crate root, and they will be inherited by the child items unless another attribute overrides it. This is why "opposite" attributes like `auto_cfg(hide(...))` and `auto_cfg(show(...))` are provided: they allow a child item to override its parent.
+
+### `#[doc(cfg(...))]`
+
+This attribute provides a standardized format to override `#[cfg()]` attributes to document conditionally available items. Example:
+
+```rust,ignore (nightly)
+// the "real" cfg condition
+#[cfg(feature = "futures-io")]
+// the `doc(cfg())` so it's displayed to the readers
+#[doc(cfg(feature = "futures-io"))]
+pub mod futures {}
+```
+
+It will display in the documentation for this module:
+
+```text
+This is supported on feature="futures-io" only.
+```
+
+You can use it to display information in generated documentation, whether or not there is a `#[cfg()]` attribute:
+
+```rust,ignore (nightly)
+#[doc(cfg(feature = "futures-io"))]
+pub mod futures {}
+```
+
+It will be displayed exactly the same as the previous code.
+
+This attribute has the same syntax as conditional compilation, but it only causes documentation to be added. This means `#[doc(cfg(not(windows)))]` will not cause your docs to be hidden on non-windows targets, even though `#[cfg(not(windows))]` does do that.
+
+If `doc(auto_cfg)` is enabled on the item, `doc(cfg)` will override it anyway so in the two previous examples, even if the `doc(auto_cfg)` feature was enabled, it would still display the same thing.
+
+This attribute works on modules and on items.
+
+### `#[doc(auto_cfg(hide(...)))]`
+
+This attribute is used to prevent some `cfg` to be generated in the visual markers. It only applies to `#[doc(auto_cfg = true)]`, not to `#[doc(cfg(...))]`. So in the previous example:
+
+```rust,ignore (nightly)
+#[cfg(any(unix, feature = "futures-io"))]
+pub mod futures {}
+```
+
+It currently displays both `unix` and `feature = "futures-io"` into the documentation, which is not great. To prevent the `unix` cfg to ever be displayed, you can use this attribute at the crate root level:
+
+```rust,ignore (nightly)
+#![doc(auto_cfg(hide(unix)))]
+```
+
+Or directly on a given item/module as it covers any of the item's descendants:
+
+```rust,ignore (nightly)
+#[doc(auto_cfg(hide(unix)))]
+#[cfg(any(unix, feature = "futures-io"))]
+pub mod futures {
+    // `futures` and all its descendants won't display "unix" in their cfgs.
+}
+```
+
+Then, the `unix` cfg will never be displayed into the documentation.
+
+Rustdoc currently hides `doc` and `doctest` attributes by default and reserves the right to change the list of "hidden by default" attributes.
+
+The attribute accepts only a list of identifiers or key/value items. So you can write:
+
+```rust,ignore (nightly)
+#[doc(auto_cfg(hide(unix, doctest, feature = "something")))]
+#[doc(auto_cfg(hide()))]
+```
+
+But you cannot write:
+
+```rust,ignore (nightly)
+#[doc(auto_cfg(hide(not(unix))))]
+```
+
+So if we use `doc(auto_cfg(hide(unix)))`, it means it will hide all mentions of `unix`:
+
+```rust,ignore (nightly)
+#[cfg(unix)] // nothing displayed
+#[cfg(any(unix))] // nothing displayed
+#[cfg(any(unix, windows))] // only `windows` displayed
+```
+
+However, it only impacts the `unix` cfg, not the feature:
+
+```rust,ignore (nightly)
+#[cfg(feature = "unix")] // `feature = "unix"` is displayed
+```
+
+If `cfg_auto(show(...))` and `cfg_auto(hide(...))` are used to show/hide a same `cfg` on a same item, it'll emit an error. Example:
+
+```rust,ignore (nightly)
+#[doc(auto_cfg(hide(unix)))]
+#[doc(auto_cfg(show(unix)))] // Error!
+pub fn foo() {}
+```
+
+Using this attribute will re-enable `auto_cfg` if it was disabled at this location:
+
+```rust,ignore (nightly)
+#[doc(auto_cfg = false)] // Disabling `auto_cfg`
+pub fn foo() {}
+```
+
+And using `doc(auto_cfg)` will re-enable it:
+
+```rust,ignore (nightly)
+#[doc(auto_cfg = false)] // Disabling `auto_cfg`
+pub mod module {
+    #[doc(auto_cfg(hide(unix)))] // `auto_cfg` is re-enabled.
+    pub fn foo() {}
+}
+```
+
+However, using `doc(auto_cfg = ...)` and `doc(auto_cfg(...))` on the same item will emit an error:
+
+```rust,ignore (nightly)
+#[doc(auto_cfg = false)]
+#[doc(auto_cfg(hide(unix)))] // error
+pub fn foo() {}
+```
+
+The reason behind this is that `doc(auto_cfg = ...)` enables or disables the feature, whereas `doc(auto_cfg(...))` enables it unconditionally, making the first attribute to appear useless as it will be overidden by the next `doc(auto_cfg)` attribute.
+
+### `#[doc(auto_cfg(show(...)))]`
+
+This attribute does the opposite of `#[doc(auto_cfg(hide(...)))]`: if you used `#[doc(auto_cfg(hide(...)))]` and want to revert its effect on an item and its descendants, you can use `#[doc(auto_cfg(show(...)))]`.
+It only applies to `#[doc(auto_cfg = true)]`, not to `#[doc(cfg(...))]`.
+
+For example:
+
+```rust,ignore (nightly)
+#[doc(auto_cfg(hide(unix)))]
+#[cfg(any(unix, feature = "futures-io"))]
+pub mod futures {
+    // `futures` and all its descendants won't display "unix" in their cfgs.
+    #[doc(auto_cfg(show(unix)))]
+    pub mod child {
+        // `child` and all its descendants will display "unix" in their cfgs.
+    }
+}
+```
+
+The attribute accepts only a list of identifiers or key/value items. So you can write:
+
+```rust,ignore (nightly)
+#[doc(auto_cfg(show(unix, doctest, feature = "something")))]
+#[doc(auto_cfg(show()))]
+```
+
+But you cannot write:
+
+```rust,ignore (nightly)
+#[doc(auto_cfg(show(not(unix))))]
+```
+
+If `auto_cfg(show(...))` and `auto_cfg(hide(...))` are used to show/hide a same `cfg` on a same item, it'll emit an error. Example:
+
+```rust,ignore (nightly)
+#[doc(auto_cfg(show(unix)))]
+#[doc(auto_cfg(hide(unix)))] // Error!
+pub fn foo() {}
+```
+
+Using this attribute will re-enable `auto_cfg` if it was disabled at this location:
+
+```rust,ignore (nightly)
+#[doc(auto_cfg = false)] // Disabling `auto_cfg`
+#[doc(auto_cfg(show(unix)))] // `auto_cfg` is re-enabled.
+pub fn foo() {}
+```
+
+### `#[doc(auto_cfg)`/`#[doc(auto_cfg = true)]`/`#[doc(auto_cfg = false)]`
+
+By default, `#[doc(auto_cfg)]` is enabled at the crate-level. When it's enabled, Rustdoc will automatically display `cfg(...)` compatibility information as-if the same `#[doc(cfg(...))]` had been specified.
+
+This attribute impacts the item on which it is used and its descendants.
+
+So if we take back the previous example:
+
+```rust
+#[cfg(feature = "futures-io")]
+pub mod futures {}
+```
+
+There's no need to "duplicate" the `cfg` into a `doc(cfg())` to make Rustdoc display it.
+
+In some situations, the detailed conditional compilation rules used to implement the feature might not serve as good documentation (for example, the list of supported platforms might be very long, and it might be better to document them in one place). To turn it off, add the `#[doc(auto_cfg = false)]` attribute on the item.
+
+If no argument is specified (ie `#[doc(auto_cfg)]`), it's the same as writing `#[doc(auto_cfg = true)]`.
+
+## Inheritance
+
+Rustdoc merges `cfg` attributes from parent modules to its children. For example, in this case, the module `non_unix` will describe the entire compatibility matrix for the module, and not just its directly attached information:
+
+```rust,ignore (nightly)
+#[doc(cfg(any(windows, unix)))]
+pub mod desktop {
+    #[doc(cfg(not(unix)))]
+    pub mod non_unix {
+        // ...
+    }
+}
+```
+
+This code will display:
+
+```text
+Available on (Windows or Unix) and non-Unix only.
+```
+
+### Re-exports and inlining
+
+`cfg` attributes of a re-export are never merged with the re-exported item(s) attributes except if the re-export has the `#[doc(inline)]` attribute. In this case, the `cfg` of the re-exported item will be merged with the re-export's.
+
+When talking about "attributes merge", we mean that if the re-export has `#[cfg(unix)]` and the re-exported item has `#[cfg(feature = "foo")]`, you will only see `cfg(unix)` on the re-export and only `cfg(feature = "foo")` on the re-exported item, unless the re-export has `#[doc(inline)]`, then you will only see the re-exported item with both `cfg(unix)` and `cfg(feature = "foo")`.
+
+Example:
+
+```rust,ignore (nightly)
+#[doc(cfg(any(windows, unix)))]
+pub mod desktop {
+    #[doc(cfg(not(unix)))]
+    pub mod non_unix {
+        // code
+    }
+}
+
+#[doc(cfg(target_os = "freebsd"))]
+pub use desktop::non_unix as non_unix_desktop;
+#[doc(cfg(target_os = "macos"))]
+#[doc(inline)]
+pub use desktop::non_unix as inlined_non_unix_desktop;
+```
+
+In this example, `non_unix_desktop` will only display `cfg(target_os = "freeebsd")` and not display any `cfg` from `desktop::non_unix`.
+
+On the contrary, `inlined_non_unix_desktop` will have cfgs from both the re-export and the re-exported item.
+
+So that also means that if a crate re-exports a foreign item, unless it has `#[doc(inline)]`, the `cfg` and `doc(cfg)` attributes will not be visible:
+
+```rust,ignore (nightly)
+// dep:
+#[cfg(feature = "a")]
+pub struct S;
+
+// crate using dep:
+
+// There will be no mention of `feature = "a"` in the documentation.
+pub use dep::S as Y;
+```
diff --git a/src/doc/rustdoc/src/write-documentation/linking-to-items-by-name.md b/src/doc/rustdoc/src/write-documentation/linking-to-items-by-name.md
index 5e785483402..b1495b2575e 100644
--- a/src/doc/rustdoc/src/write-documentation/linking-to-items-by-name.md
+++ b/src/doc/rustdoc/src/write-documentation/linking-to-items-by-name.md
@@ -90,7 +90,7 @@ fn Foo() {}
 These prefixes will be stripped when displayed in the documentation, so `[struct@Foo]` will be
 rendered as `Foo`. The following prefixes are available: `struct`, `enum`, `trait`, `union`,
 `mod`, `module`, `const`, `constant`, `fn`, `function`, `field`, `variant`, `method`, `derive`,
-`type`, `value`, `macro`, `prim` or `primitive`.
+`type`, `value`, `macro`, `tyalias`, `typealias`, `prim` or `primitive`.
 
 You can also disambiguate for functions by adding `()` after the function name,
 or for macros by adding `!` after the macro name. The macro `!` can be followed by `()`, `{}`,
diff --git a/src/doc/unstable-book/src/compiler-flags/split-dwarf-out-dir.md b/src/doc/unstable-book/src/compiler-flags/split-dwarf-out-dir.md
new file mode 100644
index 00000000000..a2070730b42
--- /dev/null
+++ b/src/doc/unstable-book/src/compiler-flags/split-dwarf-out-dir.md
@@ -0,0 +1,7 @@
+# `split-dwarf-out-dir`
+
+On systems which use DWARF debug info this flag causes `.dwo` files produced
+by `-C split-debuginfo` to be written to the specified directory rather than
+placed next to the object files. This is mostly useful if you have a build
+system which needs to control where to find compile outputs without running the
+compiler and have to put your `.dwo` files in a separate directory.
diff --git a/src/etc/lldb_providers.py b/src/etc/lldb_providers.py
index 65f18baa937..3eb964d2fba 100644
--- a/src/etc/lldb_providers.py
+++ b/src/etc/lldb_providers.py
@@ -761,7 +761,8 @@ class MSVCTupleSyntheticProvider:
 
     def get_child_at_index(self, index: int) -> SBValue:
         child: SBValue = self.valobj.GetChildAtIndex(index)
-        return child.CreateChildAtOffset(str(index), 0, child.GetType())
+        offset = self.valobj.GetType().GetFieldAtIndex(index).byte_offset
+        return self.valobj.CreateChildAtOffset(str(index), offset, child.GetType())
 
     def update(self):
         pass
@@ -772,7 +773,7 @@ class MSVCTupleSyntheticProvider:
     def get_type_name(self) -> str:
         name = self.valobj.GetTypeName()
         # remove "tuple$<" and ">", str.removeprefix and str.removesuffix require python 3.9+
-        name = name[7:-1]
+        name = name[7:-1].strip()
         return "(" + name + ")"
 
 
diff --git a/src/etc/pre-push.sh b/src/etc/pre-push.sh
index 7bacc943f25..33ed2f0e406 100755
--- a/src/etc/pre-push.sh
+++ b/src/etc/pre-push.sh
@@ -26,7 +26,10 @@ ROOT_DIR="$(git rev-parse --show-toplevel)"
 echo "Running pre-push script $ROOT_DIR/x test tidy"
 
 cd "$ROOT_DIR"
-./x test tidy --set build.locked-deps=true
+# The env var is necessary for printing diffs in py (fmt/lint) and cpp.
+TIDY_PRINT_DIFF=1 ./x test tidy \
+    --set build.locked-deps=true \
+    --extra-checks auto:py,auto:cpp,auto:js
 if [ $? -ne 0 ]; then
     echo "You may use \`git push --no-verify\` to skip this check."
     exit 1
diff --git a/src/librustdoc/Cargo.toml b/src/librustdoc/Cargo.toml
index f37a8d85361..f9c2465fb3c 100644
--- a/src/librustdoc/Cargo.toml
+++ b/src/librustdoc/Cargo.toml
@@ -12,7 +12,7 @@ path = "lib.rs"
 arrayvec = { version = "0.7", default-features = false }
 askama = { version = "0.14", default-features = false, features = ["alloc", "config", "derive"] }
 base64 = "0.21.7"
-indexmap = "2"
+indexmap = { version = "2", features = ["serde"] }
 itertools = "0.12"
 minifier = { version = "0.3.5", default-features = false }
 pulldown-cmark-escape = { version = "0.11.0", features = ["simd"] }
@@ -21,7 +21,7 @@ rustdoc-json-types = { path = "../rustdoc-json-types" }
 serde = { version = "1.0", features = ["derive"] }
 serde_json = "1.0"
 smallvec = "1.8.1"
-stringdex = { version = "0.0.1-alpha9" }
+stringdex = { version = "0.0.1-alpha10" }
 tempfile = "3"
 threadpool = "1.8.1"
 tracing = "0.1"
diff --git a/src/librustdoc/clean/cfg.rs b/src/librustdoc/clean/cfg.rs
index 8feca1367fc..aa614b73dea 100644
--- a/src/librustdoc/clean/cfg.rs
+++ b/src/librustdoc/clean/cfg.rs
@@ -256,6 +256,36 @@ impl Cfg {
     fn omit_preposition(&self) -> bool {
         matches!(self, Cfg::True | Cfg::False)
     }
+
+    pub(crate) fn strip_hidden(&self, hidden: &FxHashSet<Cfg>) -> Option<Self> {
+        match self {
+            Self::True | Self::False => Some(self.clone()),
+            Self::Cfg(..) => {
+                if !hidden.contains(self) {
+                    Some(self.clone())
+                } else {
+                    None
+                }
+            }
+            Self::Not(cfg) => {
+                if let Some(cfg) = cfg.strip_hidden(hidden) {
+                    Some(Self::Not(Box::new(cfg)))
+                } else {
+                    None
+                }
+            }
+            Self::Any(cfgs) => {
+                let cfgs =
+                    cfgs.iter().filter_map(|cfg| cfg.strip_hidden(hidden)).collect::<Vec<_>>();
+                if cfgs.is_empty() { None } else { Some(Self::Any(cfgs)) }
+            }
+            Self::All(cfgs) => {
+                let cfgs =
+                    cfgs.iter().filter_map(|cfg| cfg.strip_hidden(hidden)).collect::<Vec<_>>();
+                if cfgs.is_empty() { None } else { Some(Self::All(cfgs)) }
+            }
+        }
+    }
 }
 
 impl ops::Not for Cfg {
diff --git a/src/librustdoc/clean/inline.rs b/src/librustdoc/clean/inline.rs
index 8461e15c6c3..8beea0580de 100644
--- a/src/librustdoc/clean/inline.rs
+++ b/src/librustdoc/clean/inline.rs
@@ -19,10 +19,10 @@ use tracing::{debug, trace};
 
 use super::{Item, extract_cfg_from_attrs};
 use crate::clean::{
-    self, Attributes, ImplKind, ItemId, Type, clean_bound_vars, clean_generics, clean_impl_item,
-    clean_middle_assoc_item, clean_middle_field, clean_middle_ty, clean_poly_fn_sig,
-    clean_trait_ref_with_constraints, clean_ty, clean_ty_alias_inner_type, clean_ty_generics,
-    clean_variant_def, utils,
+    self, Attributes, CfgInfo, ImplKind, ItemId, Type, clean_bound_vars, clean_generics,
+    clean_impl_item, clean_middle_assoc_item, clean_middle_field, clean_middle_ty,
+    clean_poly_fn_sig, clean_trait_ref_with_constraints, clean_ty, clean_ty_alias_inner_type,
+    clean_ty_generics, clean_variant_def, utils,
 };
 use crate::core::DocContext;
 use crate::formats::item_type::ItemType;
@@ -409,6 +409,7 @@ pub(crate) fn merge_attrs(
     cx: &mut DocContext<'_>,
     old_attrs: &[hir::Attribute],
     new_attrs: Option<(&[hir::Attribute], Option<LocalDefId>)>,
+    cfg_info: &mut CfgInfo,
 ) -> (clean::Attributes, Option<Arc<clean::cfg::Cfg>>) {
     // NOTE: If we have additional attributes (from a re-export),
     // always insert them first. This ensure that re-export
@@ -423,12 +424,12 @@ pub(crate) fn merge_attrs(
             } else {
                 Attributes::from_hir(&both)
             },
-            extract_cfg_from_attrs(both.iter(), cx.tcx, &cx.cache.hidden_cfg),
+            extract_cfg_from_attrs(both.iter(), cx.tcx, cfg_info),
         )
     } else {
         (
             Attributes::from_hir(old_attrs),
-            extract_cfg_from_attrs(old_attrs.iter(), cx.tcx, &cx.cache.hidden_cfg),
+            extract_cfg_from_attrs(old_attrs.iter(), cx.tcx, cfg_info),
         )
     }
 }
@@ -604,7 +605,11 @@ pub(crate) fn build_impl(
         });
     }
 
-    let (merged_attrs, cfg) = merge_attrs(cx, load_attrs(cx, did), attrs);
+    // In here, we pass an empty `CfgInfo` because the computation of `cfg` happens later, so it
+    // doesn't matter at this point.
+    //
+    // We need to pass this empty `CfgInfo` because `merge_attrs` is used when computing the `cfg`.
+    let (merged_attrs, cfg) = merge_attrs(cx, load_attrs(cx, did), attrs, &mut CfgInfo::default());
     trace!("merged_attrs={merged_attrs:?}");
 
     trace!(
diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs
index 0afb969d5c8..c6339dd4755 100644
--- a/src/librustdoc/clean/mod.rs
+++ b/src/librustdoc/clean/mod.rs
@@ -212,18 +212,10 @@ fn generate_item_with_correct_attrs(
         // We only keep the item's attributes.
         target_attrs.iter().map(|attr| (Cow::Borrowed(attr), None)).collect()
     };
-    let cfg = extract_cfg_from_attrs(
-        attrs.iter().map(move |(attr, _)| match attr {
-            Cow::Borrowed(attr) => *attr,
-            Cow::Owned(attr) => attr,
-        }),
-        cx.tcx,
-        &cx.cache.hidden_cfg,
-    );
     let attrs = Attributes::from_hir_iter(attrs.iter().map(|(attr, did)| (&**attr, *did)), false);
 
     let name = renamed.or(Some(name));
-    let mut item = Item::from_def_id_and_attrs_and_parts(def_id, name, kind, attrs, cfg);
+    let mut item = Item::from_def_id_and_attrs_and_parts(def_id, name, kind, attrs, None);
     // FIXME (GuillaumeGomez): Should we also make `inline_stmt_id` a `Vec` instead of an `Option`?
     item.inner.inline_stmt_id = import_ids.first().copied();
     item
diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs
index bd3f4e9a6f2..6e3dfa0ac22 100644
--- a/src/librustdoc/clean/types.rs
+++ b/src/librustdoc/clean/types.rs
@@ -6,7 +6,8 @@ use std::{fmt, iter};
 use arrayvec::ArrayVec;
 use itertools::Either;
 use rustc_abi::{ExternAbi, VariantIdx};
-use rustc_data_structures::fx::{FxHashSet, FxIndexMap, FxIndexSet};
+use rustc_ast::ast::{LitKind, MetaItemInner, MetaItemKind};
+use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexMap, FxIndexSet};
 use rustc_hir::attrs::{AttributeKind, DeprecatedSince, Deprecation};
 use rustc_hir::def::{CtorKind, DefKind, Res};
 use rustc_hir::def_id::{CrateNum, DefId, LOCAL_CRATE, LocalDefId};
@@ -467,7 +468,7 @@ impl Item {
             name,
             kind,
             Attributes::from_hir(hir_attrs),
-            extract_cfg_from_attrs(hir_attrs.iter(), cx.tcx, &cx.cache.hidden_cfg),
+            None,
         )
     }
 
@@ -794,50 +795,6 @@ impl Item {
         Some(tcx.visibility(def_id))
     }
 
-    /// Get a list of attributes excluding `#[repr]` to display.
-    ///
-    /// Only used by the HTML output-format.
-    fn attributes_without_repr(&self) -> Vec<String> {
-        self.attrs
-            .other_attrs
-            .iter()
-            .filter_map(|attr| match attr {
-                hir::Attribute::Parsed(AttributeKind::LinkSection { name, .. }) => {
-                    Some(format!("#[unsafe(link_section = \"{name}\")]"))
-                }
-                hir::Attribute::Parsed(AttributeKind::NoMangle(..)) => {
-                    Some("#[unsafe(no_mangle)]".to_string())
-                }
-                hir::Attribute::Parsed(AttributeKind::ExportName { name, .. }) => {
-                    Some(format!("#[unsafe(export_name = \"{name}\")]"))
-                }
-                hir::Attribute::Parsed(AttributeKind::NonExhaustive(..)) => {
-                    Some("#[non_exhaustive]".to_string())
-                }
-                _ => None,
-            })
-            .collect()
-    }
-
-    /// Get a list of attributes to display on this item.
-    ///
-    /// Only used by the HTML output-format.
-    pub(crate) fn attributes(&self, tcx: TyCtxt<'_>, cache: &Cache) -> Vec<String> {
-        let mut attrs = self.attributes_without_repr();
-
-        if let Some(repr_attr) = self.repr(tcx, cache) {
-            attrs.push(repr_attr);
-        }
-        attrs
-    }
-
-    /// Returns a stringified `#[repr(...)]` attribute.
-    ///
-    /// Only used by the HTML output-format.
-    pub(crate) fn repr(&self, tcx: TyCtxt<'_>, cache: &Cache) -> Option<String> {
-        repr_attributes(tcx, cache, self.def_id()?, self.type_())
-    }
-
     pub fn is_doc_hidden(&self) -> bool {
         self.attrs.is_doc_hidden()
     }
@@ -847,74 +804,6 @@ impl Item {
     }
 }
 
-/// Return a string representing the `#[repr]` attribute if present.
-///
-/// Only used by the HTML output-format.
-pub(crate) fn repr_attributes(
-    tcx: TyCtxt<'_>,
-    cache: &Cache,
-    def_id: DefId,
-    item_type: ItemType,
-) -> Option<String> {
-    use rustc_abi::IntegerType;
-
-    if !matches!(item_type, ItemType::Struct | ItemType::Enum | ItemType::Union) {
-        return None;
-    }
-    let adt = tcx.adt_def(def_id);
-    let repr = adt.repr();
-    let mut out = Vec::new();
-    if repr.c() {
-        out.push("C");
-    }
-    if repr.transparent() {
-        // Render `repr(transparent)` iff the non-1-ZST field is public or at least one
-        // field is public in case all fields are 1-ZST fields.
-        let render_transparent = cache.document_private
-            || adt
-                .all_fields()
-                .find(|field| {
-                    let ty = field.ty(tcx, ty::GenericArgs::identity_for_item(tcx, field.did));
-                    tcx.layout_of(ty::TypingEnv::post_analysis(tcx, field.did).as_query_input(ty))
-                        .is_ok_and(|layout| !layout.is_1zst())
-                })
-                .map_or_else(
-                    || adt.all_fields().any(|field| field.vis.is_public()),
-                    |field| field.vis.is_public(),
-                );
-
-        if render_transparent {
-            out.push("transparent");
-        }
-    }
-    if repr.simd() {
-        out.push("simd");
-    }
-    let pack_s;
-    if let Some(pack) = repr.pack {
-        pack_s = format!("packed({})", pack.bytes());
-        out.push(&pack_s);
-    }
-    let align_s;
-    if let Some(align) = repr.align {
-        align_s = format!("align({})", align.bytes());
-        out.push(&align_s);
-    }
-    let int_s;
-    if let Some(int) = repr.int {
-        int_s = match int {
-            IntegerType::Pointer(is_signed) => {
-                format!("{}size", if is_signed { 'i' } else { 'u' })
-            }
-            IntegerType::Fixed(size, is_signed) => {
-                format!("{}{}", if is_signed { 'i' } else { 'u' }, size.size().bytes() * 8)
-            }
-        };
-        out.push(&int_s);
-    }
-    if !out.is_empty() { Some(format!("#[repr({})]", out.join(", "))) } else { None }
-}
-
 #[derive(Clone, Debug)]
 pub(crate) enum ItemKind {
     ExternCrateItem {
@@ -1014,30 +903,6 @@ impl ItemKind {
             | AttributeItem => [].iter(),
         }
     }
-
-    /// Returns `true` if this item does not appear inside an impl block.
-    pub(crate) fn is_non_assoc(&self) -> bool {
-        matches!(
-            self,
-            StructItem(_)
-                | UnionItem(_)
-                | EnumItem(_)
-                | TraitItem(_)
-                | ModuleItem(_)
-                | ExternCrateItem { .. }
-                | FunctionItem(_)
-                | TypeAliasItem(_)
-                | StaticItem(_)
-                | ConstantItem(_)
-                | TraitAliasItem(_)
-                | ForeignFunctionItem(_, _)
-                | ForeignStaticItem(_, _)
-                | ForeignTypeItem
-                | MacroItem(_)
-                | ProcMacroItem(_)
-                | PrimitiveItem(_)
-        )
-    }
 }
 
 #[derive(Clone, Debug)]
@@ -1057,14 +922,99 @@ pub(crate) fn hir_attr_lists<'a, I: IntoIterator<Item = &'a hir::Attribute>>(
         .flatten()
 }
 
+/// This type keeps track of (doc) cfg information as we go down the item tree.
+#[derive(Clone, Debug)]
+pub(crate) struct CfgInfo {
+    /// List of currently active `doc(auto_cfg(hide(...)))` cfgs, minus currently active
+    /// `doc(auto_cfg(show(...)))` cfgs.
+    hidden_cfg: FxHashSet<Cfg>,
+    /// Current computed `cfg`. Each time we enter a new item, this field is updated as well while
+    /// taking into account the `hidden_cfg` information.
+    current_cfg: Cfg,
+    /// Whether the `doc(auto_cfg())` feature is enabled or not at this point.
+    auto_cfg_active: bool,
+    /// If the parent item used `doc(cfg(...))`, then we don't want to overwrite `current_cfg`,
+    /// instead we will concatenate with it. However, if it's not the case, we need to overwrite
+    /// `current_cfg`.
+    parent_is_doc_cfg: bool,
+}
+
+impl Default for CfgInfo {
+    fn default() -> Self {
+        Self {
+            hidden_cfg: FxHashSet::from_iter([
+                Cfg::Cfg(sym::test, None),
+                Cfg::Cfg(sym::doc, None),
+                Cfg::Cfg(sym::doctest, None),
+            ]),
+            current_cfg: Cfg::True,
+            auto_cfg_active: true,
+            parent_is_doc_cfg: false,
+        }
+    }
+}
+
+fn show_hide_show_conflict_error(
+    tcx: TyCtxt<'_>,
+    item_span: rustc_span::Span,
+    previous: rustc_span::Span,
+) {
+    let mut diag = tcx.sess.dcx().struct_span_err(
+        item_span,
+        format!(
+            "same `cfg` was in `auto_cfg(hide(...))` and `auto_cfg(show(...))` on the same item"
+        ),
+    );
+    diag.span_note(previous, "first change was here");
+    diag.emit();
+}
+
+/// This functions updates the `hidden_cfg` field of the provided `cfg_info` argument.
+///
+/// It also checks if a same `cfg` is present in both `auto_cfg(hide(...))` and
+/// `auto_cfg(show(...))` on the same item and emits an error if it's the case.
+///
+/// Because we go through a list of `cfg`s, we keep track of the `cfg`s we saw in `new_show_attrs`
+/// and in `new_hide_attrs` arguments.
+fn handle_auto_cfg_hide_show(
+    tcx: TyCtxt<'_>,
+    cfg_info: &mut CfgInfo,
+    sub_attr: &MetaItemInner,
+    is_show: bool,
+    new_show_attrs: &mut FxHashMap<(Symbol, Option<Symbol>), rustc_span::Span>,
+    new_hide_attrs: &mut FxHashMap<(Symbol, Option<Symbol>), rustc_span::Span>,
+) {
+    if let MetaItemInner::MetaItem(item) = sub_attr
+        && let MetaItemKind::List(items) = &item.kind
+    {
+        for item in items {
+            // FIXME: Report in case `Cfg::parse` reports an error?
+            if let Ok(Cfg::Cfg(key, value)) = Cfg::parse(item) {
+                if is_show {
+                    if let Some(span) = new_hide_attrs.get(&(key, value)) {
+                        show_hide_show_conflict_error(tcx, item.span(), *span);
+                    } else {
+                        new_show_attrs.insert((key, value), item.span());
+                    }
+                    cfg_info.hidden_cfg.remove(&Cfg::Cfg(key, value));
+                } else {
+                    if let Some(span) = new_show_attrs.get(&(key, value)) {
+                        show_hide_show_conflict_error(tcx, item.span(), *span);
+                    } else {
+                        new_hide_attrs.insert((key, value), item.span());
+                    }
+                    cfg_info.hidden_cfg.insert(Cfg::Cfg(key, value));
+                }
+            }
+        }
+    }
+}
+
 pub(crate) fn extract_cfg_from_attrs<'a, I: Iterator<Item = &'a hir::Attribute> + Clone>(
     attrs: I,
     tcx: TyCtxt<'_>,
-    hidden_cfg: &FxHashSet<Cfg>,
+    cfg_info: &mut CfgInfo,
 ) -> Option<Arc<Cfg>> {
-    let doc_cfg_active = tcx.features().doc_cfg();
-    let doc_auto_cfg_active = tcx.features().doc_auto_cfg();
-
     fn single<T: IntoIterator>(it: T) -> Option<T::Item> {
         let mut iter = it.into_iter();
         let item = iter.next()?;
@@ -1074,56 +1024,163 @@ pub(crate) fn extract_cfg_from_attrs<'a, I: Iterator<Item = &'a hir::Attribute>
         Some(item)
     }
 
-    let mut cfg = if doc_cfg_active || doc_auto_cfg_active {
-        let mut doc_cfg = attrs
-            .clone()
-            .filter(|attr| attr.has_name(sym::doc))
-            .flat_map(|attr| attr.meta_item_list().unwrap_or_default())
-            .filter(|attr| attr.has_name(sym::cfg))
-            .peekable();
-        if doc_cfg.peek().is_some() && doc_cfg_active {
-            let sess = tcx.sess;
-
-            doc_cfg.fold(Cfg::True, |mut cfg, item| {
-                if let Some(cfg_mi) =
-                    item.meta_item().and_then(|item| rustc_expand::config::parse_cfg(item, sess))
-                {
-                    match Cfg::parse(cfg_mi) {
-                        Ok(new_cfg) => cfg &= new_cfg,
-                        Err(e) => {
-                            sess.dcx().span_err(e.span, e.msg);
-                        }
+    fn check_changed_auto_active_status(
+        changed_auto_active_status: &mut Option<rustc_span::Span>,
+        attr: &ast::MetaItem,
+        cfg_info: &mut CfgInfo,
+        tcx: TyCtxt<'_>,
+        new_value: bool,
+    ) -> bool {
+        if let Some(first_change) = changed_auto_active_status {
+            if cfg_info.auto_cfg_active != new_value {
+                tcx.sess
+                    .dcx()
+                    .struct_span_err(
+                        vec![*first_change, attr.span],
+                        "`auto_cfg` was disabled and enabled more than once on the same item",
+                    )
+                    .emit();
+                return true;
+            }
+        } else {
+            *changed_auto_active_status = Some(attr.span);
+        }
+        cfg_info.auto_cfg_active = new_value;
+        false
+    }
+
+    let mut new_show_attrs = FxHashMap::default();
+    let mut new_hide_attrs = FxHashMap::default();
+
+    let mut doc_cfg = attrs
+        .clone()
+        .filter(|attr| attr.has_name(sym::doc))
+        .flat_map(|attr| attr.meta_item_list().unwrap_or_default())
+        .filter(|attr| attr.has_name(sym::cfg))
+        .peekable();
+    // If the item uses `doc(cfg(...))`, then we ignore the other `cfg(...)` attributes.
+    if doc_cfg.peek().is_some() {
+        let sess = tcx.sess;
+        // We overwrite existing `cfg`.
+        if !cfg_info.parent_is_doc_cfg {
+            cfg_info.current_cfg = Cfg::True;
+            cfg_info.parent_is_doc_cfg = true;
+        }
+        for attr in doc_cfg {
+            if let Some(cfg_mi) =
+                attr.meta_item().and_then(|attr| rustc_expand::config::parse_cfg(attr, sess))
+            {
+                match Cfg::parse(cfg_mi) {
+                    Ok(new_cfg) => cfg_info.current_cfg &= new_cfg,
+                    Err(e) => {
+                        sess.dcx().span_err(e.span, e.msg);
                     }
                 }
-                cfg
-            })
-        } else if doc_auto_cfg_active {
-            // If there is no `doc(cfg())`, then we retrieve the `cfg()` attributes (because
-            // `doc(cfg())` overrides `cfg()`).
-            attrs
-                .clone()
-                .filter(|attr| attr.has_name(sym::cfg_trace))
-                .filter_map(|attr| single(attr.meta_item_list()?))
-                .filter_map(|attr| Cfg::parse_without(attr.meta_item()?, hidden_cfg).ok().flatten())
-                .fold(Cfg::True, |cfg, new_cfg| cfg & new_cfg)
-        } else {
-            Cfg::True
+            }
         }
     } else {
-        Cfg::True
-    };
+        cfg_info.parent_is_doc_cfg = false;
+    }
 
-    // treat #[target_feature(enable = "feat")] attributes as if they were
-    // #[doc(cfg(target_feature = "feat"))] attributes as well
-    if let Some(features) =
-        find_attr!(attrs, AttributeKind::TargetFeature { features, .. } => features)
-    {
-        for (feature, _) in features {
-            cfg &= Cfg::Cfg(sym::target_feature, Some(*feature));
+    let mut changed_auto_active_status = None;
+
+    // We get all `doc(auto_cfg)`, `cfg` and `target_feature` attributes.
+    for attr in attrs {
+        if let Some(ident) = attr.ident()
+            && ident.name == sym::doc
+            && let Some(attrs) = attr.meta_item_list()
+        {
+            for attr in attrs.iter().filter(|attr| attr.has_name(sym::auto_cfg)) {
+                let MetaItemInner::MetaItem(attr) = attr else {
+                    continue;
+                };
+                match &attr.kind {
+                    MetaItemKind::Word => {
+                        if check_changed_auto_active_status(
+                            &mut changed_auto_active_status,
+                            attr,
+                            cfg_info,
+                            tcx,
+                            true,
+                        ) {
+                            return None;
+                        }
+                    }
+                    MetaItemKind::NameValue(lit) => {
+                        if let LitKind::Bool(value) = lit.kind {
+                            if check_changed_auto_active_status(
+                                &mut changed_auto_active_status,
+                                attr,
+                                cfg_info,
+                                tcx,
+                                value,
+                            ) {
+                                return None;
+                            }
+                        }
+                    }
+                    MetaItemKind::List(sub_attrs) => {
+                        if check_changed_auto_active_status(
+                            &mut changed_auto_active_status,
+                            attr,
+                            cfg_info,
+                            tcx,
+                            true,
+                        ) {
+                            return None;
+                        }
+                        for sub_attr in sub_attrs.iter() {
+                            if let Some(ident) = sub_attr.ident()
+                                && (ident.name == sym::show || ident.name == sym::hide)
+                            {
+                                handle_auto_cfg_hide_show(
+                                    tcx,
+                                    cfg_info,
+                                    &sub_attr,
+                                    ident.name == sym::show,
+                                    &mut new_show_attrs,
+                                    &mut new_hide_attrs,
+                                );
+                            }
+                        }
+                    }
+                }
+            }
+        } else if let hir::Attribute::Parsed(AttributeKind::TargetFeature { features, .. }) = attr {
+            // Treat `#[target_feature(enable = "feat")]` attributes as if they were
+            // `#[doc(cfg(target_feature = "feat"))]` attributes as well.
+            for (feature, _) in features {
+                cfg_info.current_cfg &= Cfg::Cfg(sym::target_feature, Some(*feature));
+            }
+            continue;
+        } else if !cfg_info.parent_is_doc_cfg
+            && let Some(ident) = attr.ident()
+            && matches!(ident.name, sym::cfg | sym::cfg_trace)
+            && let Some(attr) = single(attr.meta_item_list()?)
+            && let Ok(new_cfg) = Cfg::parse(&attr)
+        {
+            cfg_info.current_cfg &= new_cfg;
         }
     }
 
-    if cfg == Cfg::True { None } else { Some(Arc::new(cfg)) }
+    // If `doc(auto_cfg)` feature is disabled and `doc(cfg())` wasn't used, there is nothing
+    // to be done here.
+    if !cfg_info.auto_cfg_active && !cfg_info.parent_is_doc_cfg {
+        None
+    } else if cfg_info.parent_is_doc_cfg {
+        if cfg_info.current_cfg == Cfg::True {
+            None
+        } else {
+            Some(Arc::new(cfg_info.current_cfg.clone()))
+        }
+    } else {
+        // If `doc(auto_cfg)` feature is enabled, we want to collect all `cfg` items, we remove the
+        // hidden ones afterward.
+        match cfg_info.current_cfg.strip_hidden(&cfg_info.hidden_cfg) {
+            None | Some(Cfg::True) => None,
+            Some(cfg) => Some(Arc::new(cfg)),
+        }
+    }
 }
 
 pub(crate) trait NestedAttributesExt {
@@ -1622,7 +1679,7 @@ impl Type {
         match (self_cleared, other_cleared) {
             // Recursive cases.
             (Type::Tuple(a), Type::Tuple(b)) => {
-                a.len() == b.len() && a.iter().zip(b).all(|(a, b)| a.is_doc_subtype_of(b, cache))
+                a.iter().eq_by(b, |a, b| a.is_doc_subtype_of(b, cache))
             }
             (Type::Slice(a), Type::Slice(b)) => a.is_doc_subtype_of(b, cache),
             (Type::Array(a, al), Type::Array(b, bl)) => al == bl && a.is_doc_subtype_of(b, cache),
diff --git a/src/librustdoc/doctest.rs b/src/librustdoc/doctest.rs
index 95bd31729de..9499258f983 100644
--- a/src/librustdoc/doctest.rs
+++ b/src/librustdoc/doctest.rs
@@ -404,11 +404,15 @@ pub(crate) fn run_tests(
             std::mem::drop(temp_dir.take());
             times.display_times();
         });
+    } else {
+        // If the first condition branch exited successfully, `test_main_with_exit_callback` will
+        // not exit the process. So to prevent displaying the times twice, we put it behind an
+        // `else` condition.
+        times.display_times();
     }
+    // We ensure temp dir destructor is called.
+    std::mem::drop(temp_dir);
     if nb_errors != 0 {
-        // We ensure temp dir destructor is called.
-        std::mem::drop(temp_dir);
-        times.display_times();
         std::process::exit(test::ERROR_EXIT_CODE);
     }
 }
diff --git a/src/librustdoc/doctest/rust.rs b/src/librustdoc/doctest/rust.rs
index f5ec828187a..4d3f976c2a6 100644
--- a/src/librustdoc/doctest/rust.rs
+++ b/src/librustdoc/doctest/rust.rs
@@ -5,7 +5,6 @@ use std::env;
 use std::sync::Arc;
 
 use rustc_ast_pretty::pprust;
-use rustc_data_structures::fx::FxHashSet;
 use rustc_hir::def_id::{CRATE_DEF_ID, LocalDefId};
 use rustc_hir::{self as hir, CRATE_HIR_ID, intravisit};
 use rustc_middle::hir::nested_filter;
@@ -15,7 +14,7 @@ use rustc_span::source_map::SourceMap;
 use rustc_span::{BytePos, DUMMY_SP, FileName, Pos, Span, sym};
 
 use super::{DocTestVisitor, ScrapedDocTest};
-use crate::clean::{Attributes, extract_cfg_from_attrs};
+use crate::clean::{Attributes, CfgInfo, extract_cfg_from_attrs};
 use crate::html::markdown::{self, ErrorCodes, LangString, MdRelLine};
 
 struct RustCollector {
@@ -121,7 +120,7 @@ impl HirCollector<'_> {
     ) {
         let ast_attrs = self.tcx.hir_attrs(self.tcx.local_def_id_to_hir_id(def_id));
         if let Some(ref cfg) =
-            extract_cfg_from_attrs(ast_attrs.iter(), self.tcx, &FxHashSet::default())
+            extract_cfg_from_attrs(ast_attrs.iter(), self.tcx, &mut CfgInfo::default())
             && !cfg.matches(&self.tcx.sess.psess)
         {
             return;
diff --git a/src/librustdoc/formats/cache.rs b/src/librustdoc/formats/cache.rs
index 29b4c4caaf8..a19d254ea95 100644
--- a/src/librustdoc/formats/cache.rs
+++ b/src/librustdoc/formats/cache.rs
@@ -125,8 +125,6 @@ pub(crate) struct Cache {
     ///
     /// Links are indexed by the DefId of the item they document.
     pub(crate) intra_doc_links: FxHashMap<ItemId, FxIndexSet<clean::ItemLink>>,
-    /// Cfg that have been hidden via #![doc(cfg_hide(...))]
-    pub(crate) hidden_cfg: FxHashSet<clean::cfg::Cfg>,
 
     /// Contains the list of `DefId`s which have been inlined. It is used when generating files
     /// to check if a stripped item should get its file generated or not: if it's inside a
diff --git a/src/librustdoc/html/format.rs b/src/librustdoc/html/format.rs
index ecaff4cdf43..856e637a458 100644
--- a/src/librustdoc/html/format.rs
+++ b/src/librustdoc/html/format.rs
@@ -37,10 +37,6 @@ use crate::html::escape::{Escape, EscapeBodyText};
 use crate::html::render::Context;
 use crate::passes::collect_intra_doc_links::UrlFragment;
 
-pub(crate) fn write_str(s: &mut String, f: fmt::Arguments<'_>) {
-    s.write_fmt(f).unwrap();
-}
-
 pub(crate) fn print_generic_bounds(
     bounds: &[clean::GenericBound],
     cx: &Context<'_>,
diff --git a/src/librustdoc/html/highlight.rs b/src/librustdoc/html/highlight.rs
index 0e06361024b..1dcb4dcc3ff 100644
--- a/src/librustdoc/html/highlight.rs
+++ b/src/librustdoc/html/highlight.rs
@@ -8,17 +8,20 @@
 use std::borrow::Cow;
 use std::collections::VecDeque;
 use std::fmt::{self, Display, Write};
+use std::iter;
 
 use rustc_data_structures::fx::FxIndexMap;
 use rustc_lexer::{Cursor, FrontmatterAllowed, LiteralKind, TokenKind};
+use rustc_span::BytePos;
 use rustc_span::edition::Edition;
 use rustc_span::symbol::Symbol;
-use rustc_span::{BytePos, DUMMY_SP, Span};
 
-use super::format::{self, write_str};
+use super::format;
 use crate::clean::PrimitiveType;
+use crate::display::Joined as _;
 use crate::html::escape::EscapeBodyText;
 use crate::html::macro_expansion::ExpandedCode;
+use crate::html::render::span_map::{DUMMY_SP, Span};
 use crate::html::render::{Context, LinkFromSrc};
 
 /// This type is needed in case we want to render links on items to allow to go to their definition.
@@ -45,92 +48,72 @@ pub(crate) enum Tooltip {
     CompileFail,
     ShouldPanic,
     Edition(Edition),
-    None,
 }
 
 /// Highlights `src` as an inline example, returning the HTML output.
 pub(crate) fn render_example_with_highlighting(
     src: &str,
-    out: &mut String,
-    tooltip: Tooltip,
+    tooltip: Option<&Tooltip>,
     playground_button: Option<&str>,
     extra_classes: &[String],
-) {
-    write_header(out, "rust-example-rendered", None, tooltip, extra_classes);
-    write_code(out, src, None, None, None);
-    write_footer(out, playground_button);
+) -> impl Display {
+    fmt::from_fn(move |f| {
+        write_header("rust-example-rendered", tooltip, extra_classes).fmt(f)?;
+        write_code(f, src, None, None, None);
+        write_footer(playground_button).fmt(f)
+    })
 }
 
-fn write_header(
-    out: &mut String,
-    class: &str,
-    extra_content: Option<&str>,
-    tooltip: Tooltip,
-    extra_classes: &[String],
-) {
-    write_str(
-        out,
-        format_args!(
+fn write_header(class: &str, tooltip: Option<&Tooltip>, extra_classes: &[String]) -> impl Display {
+    fmt::from_fn(move |f| {
+        write!(
+            f,
             "<div class=\"example-wrap{}\">",
-            match tooltip {
-                Tooltip::IgnoreAll | Tooltip::IgnoreSome(_) => " ignore",
-                Tooltip::CompileFail => " compile_fail",
-                Tooltip::ShouldPanic => " should_panic",
-                Tooltip::Edition(_) => " edition",
-                Tooltip::None => "",
-            }
-        ),
-    );
-
-    if tooltip != Tooltip::None {
-        let tooltip = fmt::from_fn(|f| match &tooltip {
-            Tooltip::IgnoreAll => f.write_str("This example is not tested"),
-            Tooltip::IgnoreSome(platforms) => {
-                f.write_str("This example is not tested on ")?;
-                match &platforms[..] {
-                    [] => unreachable!(),
-                    [platform] => f.write_str(platform)?,
-                    [first, second] => write!(f, "{first} or {second}")?,
-                    [platforms @ .., last] => {
-                        for platform in platforms {
-                            write!(f, "{platform}, ")?;
+            tooltip
+                .map(|tooltip| match tooltip {
+                    Tooltip::IgnoreAll | Tooltip::IgnoreSome(_) => " ignore",
+                    Tooltip::CompileFail => " compile_fail",
+                    Tooltip::ShouldPanic => " should_panic",
+                    Tooltip::Edition(_) => " edition",
+                })
+                .unwrap_or_default()
+        )?;
+
+        if let Some(tooltip) = tooltip {
+            let tooltip = fmt::from_fn(|f| match tooltip {
+                Tooltip::IgnoreAll => f.write_str("This example is not tested"),
+                Tooltip::IgnoreSome(platforms) => {
+                    f.write_str("This example is not tested on ")?;
+                    match &platforms[..] {
+                        [] => unreachable!(),
+                        [platform] => f.write_str(platform)?,
+                        [first, second] => write!(f, "{first} or {second}")?,
+                        [platforms @ .., last] => {
+                            for platform in platforms {
+                                write!(f, "{platform}, ")?;
+                            }
+                            write!(f, "or {last}")?;
                         }
-                        write!(f, "or {last}")?;
                     }
+                    Ok(())
                 }
-                Ok(())
-            }
-            Tooltip::CompileFail => f.write_str("This example deliberately fails to compile"),
-            Tooltip::ShouldPanic => f.write_str("This example panics"),
-            Tooltip::Edition(edition) => write!(f, "This example runs with edition {edition}"),
-            Tooltip::None => unreachable!(),
+                Tooltip::CompileFail => f.write_str("This example deliberately fails to compile"),
+                Tooltip::ShouldPanic => f.write_str("This example panics"),
+                Tooltip::Edition(edition) => write!(f, "This example runs with edition {edition}"),
+            });
+
+            write!(f, "<a href=\"#\" class=\"tooltip\" title=\"{tooltip}\">ⓘ</a>")?;
+        }
+
+        let classes = fmt::from_fn(|f| {
+            iter::once("rust")
+                .chain(Some(class).filter(|class| !class.is_empty()))
+                .chain(extra_classes.iter().map(String::as_str))
+                .joined(" ", f)
         });
-        write_str(out, format_args!("<a href=\"#\" class=\"tooltip\" title=\"{tooltip}\">ⓘ</a>"));
-    }
 
-    if let Some(extra) = extra_content {
-        out.push_str(extra);
-    }
-    if class.is_empty() {
-        write_str(
-            out,
-            format_args!(
-                "<pre class=\"rust{}{}\">",
-                if extra_classes.is_empty() { "" } else { " " },
-                extra_classes.join(" ")
-            ),
-        );
-    } else {
-        write_str(
-            out,
-            format_args!(
-                "<pre class=\"rust {class}{}{}\">",
-                if extra_classes.is_empty() { "" } else { " " },
-                extra_classes.join(" ")
-            ),
-        );
-    }
-    write_str(out, format_args!("<code>"));
+        write!(f, "<pre class=\"{classes}\"><code>")
+    })
 }
 
 /// Check if two `Class` can be merged together. In the following rules, "unclassified" means `None`
@@ -577,8 +560,8 @@ pub(super) fn write_code(
     });
 }
 
-fn write_footer(out: &mut String, playground_button: Option<&str>) {
-    write_str(out, format_args!("</code></pre>{}</div>", playground_button.unwrap_or_default()));
+fn write_footer(playground_button: Option<&str>) -> impl Display {
+    fmt::from_fn(move |f| write!(f, "</code></pre>{}</div>", playground_button.unwrap_or_default()))
 }
 
 /// How a span of text is classified. Mostly corresponds to token kinds.
@@ -1262,6 +1245,64 @@ fn string<W: Write>(
     }
 }
 
+fn generate_link_to_def(
+    out: &mut impl Write,
+    text_s: &str,
+    klass: Class,
+    href_context: &Option<HrefContext<'_, '_>>,
+    def_span: Span,
+    open_tag: bool,
+) -> bool {
+    if let Some(href_context) = href_context
+        && let Some(href) =
+            href_context.context.shared.span_correspondence_map.get(&def_span).and_then(|href| {
+                let context = href_context.context;
+                // FIXME: later on, it'd be nice to provide two links (if possible) for all items:
+                // one to the documentation page and one to the source definition.
+                // FIXME: currently, external items only generate a link to their documentation,
+                // a link to their definition can be generated using this:
+                // https://github.com/rust-lang/rust/blob/60f1a2fc4b535ead9c85ce085fdce49b1b097531/src/librustdoc/html/render/context.rs#L315-L338
+                match href {
+                    LinkFromSrc::Local(span) => {
+                        context.href_from_span_relative(*span, &href_context.current_href)
+                    }
+                    LinkFromSrc::External(def_id) => {
+                        format::href_with_root_path(*def_id, context, Some(href_context.root_path))
+                            .ok()
+                            .map(|(url, _, _)| url)
+                    }
+                    LinkFromSrc::Primitive(prim) => format::href_with_root_path(
+                        PrimitiveType::primitive_locations(context.tcx())[prim],
+                        context,
+                        Some(href_context.root_path),
+                    )
+                    .ok()
+                    .map(|(url, _, _)| url),
+                    LinkFromSrc::Doc(def_id) => {
+                        format::href_with_root_path(*def_id, context, Some(href_context.root_path))
+                            .ok()
+                            .map(|(doc_link, _, _)| doc_link)
+                    }
+                }
+            })
+    {
+        if !open_tag {
+            // We're already inside an element which has the same klass, no need to give it
+            // again.
+            write!(out, "<a href=\"{href}\">{text_s}").unwrap();
+        } else {
+            let klass_s = klass.as_html();
+            if klass_s.is_empty() {
+                write!(out, "<a href=\"{href}\">{text_s}").unwrap();
+            } else {
+                write!(out, "<a class=\"{klass_s}\" href=\"{href}\">{text_s}").unwrap();
+            }
+        }
+        return true;
+    }
+    false
+}
+
 /// This function writes `text` into `out` with some modifications depending on `klass`:
 ///
 /// * If `klass` is `None`, `text` is written into `out` with no modification.
@@ -1291,10 +1332,14 @@ fn string_without_closing_tag<T: Display>(
         return Some("</span>");
     };
 
+    let mut added_links = false;
     let mut text_s = text.to_string();
     if text_s.contains("::") {
+        let mut span = def_span.with_hi(def_span.lo());
         text_s = text_s.split("::").intersperse("::").fold(String::new(), |mut path, t| {
+            span = span.with_hi(span.hi() + BytePos(t.len() as _));
             match t {
+                "::" => write!(&mut path, "::"),
                 "self" | "Self" => write!(
                     &mut path,
                     "<span class=\"{klass}\">{t}</span>",
@@ -1307,58 +1352,24 @@ fn string_without_closing_tag<T: Display>(
                         klass = Class::KeyWord.as_html(),
                     )
                 }
-                t => write!(&mut path, "{t}"),
+                t => {
+                    if !t.is_empty()
+                        && generate_link_to_def(&mut path, t, klass, href_context, span, open_tag)
+                    {
+                        added_links = true;
+                        write!(&mut path, "</a>")
+                    } else {
+                        write!(&mut path, "{t}")
+                    }
+                }
             }
             .expect("Failed to build source HTML path");
+            span = span.with_lo(span.lo() + BytePos(t.len() as _));
             path
         });
     }
 
-    if let Some(href_context) = href_context
-        && let Some(href) = href_context.context.shared.span_correspondence_map.get(&def_span)
-        && let Some(href) = {
-            let context = href_context.context;
-            // FIXME: later on, it'd be nice to provide two links (if possible) for all items:
-            // one to the documentation page and one to the source definition.
-            // FIXME: currently, external items only generate a link to their documentation,
-            // a link to their definition can be generated using this:
-            // https://github.com/rust-lang/rust/blob/60f1a2fc4b535ead9c85ce085fdce49b1b097531/src/librustdoc/html/render/context.rs#L315-L338
-            match href {
-                LinkFromSrc::Local(span) => {
-                    context.href_from_span_relative(*span, &href_context.current_href)
-                }
-                LinkFromSrc::External(def_id) => {
-                    format::href_with_root_path(*def_id, context, Some(href_context.root_path))
-                        .ok()
-                        .map(|(url, _, _)| url)
-                }
-                LinkFromSrc::Primitive(prim) => format::href_with_root_path(
-                    PrimitiveType::primitive_locations(context.tcx())[prim],
-                    context,
-                    Some(href_context.root_path),
-                )
-                .ok()
-                .map(|(url, _, _)| url),
-                LinkFromSrc::Doc(def_id) => {
-                    format::href_with_root_path(*def_id, context, Some(href_context.root_path))
-                        .ok()
-                        .map(|(doc_link, _, _)| doc_link)
-                }
-            }
-        }
-    {
-        if !open_tag {
-            // We're already inside an element which has the same klass, no need to give it
-            // again.
-            write!(out, "<a href=\"{href}\">{text_s}").unwrap();
-        } else {
-            let klass_s = klass.as_html();
-            if klass_s.is_empty() {
-                write!(out, "<a href=\"{href}\">{text_s}").unwrap();
-            } else {
-                write!(out, "<a class=\"{klass_s}\" href=\"{href}\">{text_s}").unwrap();
-            }
-        }
+    if !added_links && generate_link_to_def(out, &text_s, klass, href_context, def_span, open_tag) {
         return Some("</a>");
     }
     if !open_tag {
diff --git a/src/librustdoc/html/highlight/tests.rs b/src/librustdoc/html/highlight/tests.rs
index 2603e887bea..4d1bee9b3a1 100644
--- a/src/librustdoc/html/highlight/tests.rs
+++ b/src/librustdoc/html/highlight/tests.rs
@@ -1,6 +1,7 @@
 use expect_test::expect_file;
 use rustc_data_structures::fx::FxIndexMap;
 use rustc_span::create_default_session_globals_then;
+use test::Bencher;
 
 use super::{DecorationInfo, write_code};
 
@@ -81,3 +82,16 @@ let a = 4;";
         expect_file!["fixtures/decorations.html"].assert_eq(&html);
     });
 }
+
+#[bench]
+fn bench_html_highlighting(b: &mut Bencher) {
+    let src = include_str!("../../../../compiler/rustc_ast/src/visit.rs");
+
+    create_default_session_globals_then(|| {
+        b.iter(|| {
+            let mut out = String::new();
+            write_code(&mut out, src, None, None, None);
+            out
+        });
+    });
+}
diff --git a/src/librustdoc/html/markdown.rs b/src/librustdoc/html/markdown.rs
index 4addf2c3c96..7065de14c8e 100644
--- a/src/librustdoc/html/markdown.rs
+++ b/src/librustdoc/html/markdown.rs
@@ -321,31 +321,34 @@ impl<'a, I: Iterator<Item = Event<'a>>> Iterator for CodeBlocks<'_, 'a, I> {
             ))
         });
 
-        let tooltip = if ignore == Ignore::All {
-            highlight::Tooltip::IgnoreAll
-        } else if let Ignore::Some(platforms) = ignore {
-            highlight::Tooltip::IgnoreSome(platforms)
-        } else if compile_fail {
-            highlight::Tooltip::CompileFail
-        } else if should_panic {
-            highlight::Tooltip::ShouldPanic
-        } else if explicit_edition {
-            highlight::Tooltip::Edition(edition)
-        } else {
-            highlight::Tooltip::None
+        let tooltip = {
+            use highlight::Tooltip::*;
+
+            if ignore == Ignore::All {
+                Some(IgnoreAll)
+            } else if let Ignore::Some(platforms) = ignore {
+                Some(IgnoreSome(platforms))
+            } else if compile_fail {
+                Some(CompileFail)
+            } else if should_panic {
+                Some(ShouldPanic)
+            } else if explicit_edition {
+                Some(Edition(edition))
+            } else {
+                None
+            }
         };
 
         // insert newline to clearly separate it from the
         // previous block so we can shorten the html output
-        let mut s = String::new();
-        s.push('\n');
-
-        highlight::render_example_with_highlighting(
-            &text,
-            &mut s,
-            tooltip,
-            playground_button.as_deref(),
-            &added_classes,
+        let s = format!(
+            "\n{}",
+            highlight::render_example_with_highlighting(
+                &text,
+                tooltip.as_ref(),
+                playground_button.as_deref(),
+                &added_classes,
+            )
         );
         Some(Event::Html(s.into()))
     }
diff --git a/src/librustdoc/html/render/context.rs b/src/librustdoc/html/render/context.rs
index 5f92ab2fada..4c06d0da470 100644
--- a/src/librustdoc/html/render/context.rs
+++ b/src/librustdoc/html/render/context.rs
@@ -30,6 +30,7 @@ use crate::formats::item_type::ItemType;
 use crate::html::escape::Escape;
 use crate::html::macro_expansion::ExpandedCode;
 use crate::html::markdown::{self, ErrorCodes, IdMap, plain_text_summary};
+use crate::html::render::span_map::Span;
 use crate::html::render::write_shared::write_shared;
 use crate::html::url_parts_builder::UrlPartsBuilder;
 use crate::html::{layout, sources, static_files};
@@ -139,7 +140,7 @@ pub(crate) struct SharedContext<'tcx> {
 
     /// Correspondence map used to link types used in the source code pages to allow to click on
     /// links to jump to the type's definition.
-    pub(crate) span_correspondence_map: FxHashMap<rustc_span::Span, LinkFromSrc>,
+    pub(crate) span_correspondence_map: FxHashMap<Span, LinkFromSrc>,
     pub(crate) expanded_codes: FxHashMap<BytePos, Vec<ExpandedCode>>,
     /// The [`Cache`] used during rendering.
     pub(crate) cache: Cache,
diff --git a/src/librustdoc/html/render/mod.rs b/src/librustdoc/html/render/mod.rs
index 6d684449b6d..d6371e4dbab 100644
--- a/src/librustdoc/html/render/mod.rs
+++ b/src/librustdoc/html/render/mod.rs
@@ -36,7 +36,7 @@ mod ordered_json;
 mod print_item;
 pub(crate) mod sidebar;
 mod sorted_template;
-mod span_map;
+pub(crate) mod span_map;
 mod type_layout;
 mod write_shared;
 
@@ -48,18 +48,19 @@ use std::path::PathBuf;
 use std::{fs, str};
 
 use askama::Template;
+use indexmap::IndexMap;
 use itertools::Either;
 use rustc_ast::join_path_syms;
 use rustc_data_structures::fx::{FxHashSet, FxIndexMap, FxIndexSet};
-use rustc_hir::attrs::{DeprecatedSince, Deprecation};
+use rustc_hir as hir;
+use rustc_hir::attrs::{AttributeKind, DeprecatedSince, Deprecation};
+use rustc_hir::def::DefKind;
 use rustc_hir::def_id::{DefId, DefIdSet};
 use rustc_hir::{ConstStability, Mutability, RustcVersion, StabilityLevel, StableSince};
 use rustc_middle::ty::print::PrintTraitRefExt;
 use rustc_middle::ty::{self, TyCtxt};
 use rustc_span::symbol::{Symbol, sym};
 use rustc_span::{BytePos, DUMMY_SP, FileName, RealFileName};
-use serde::ser::SerializeMap;
-use serde::{Serialize, Serializer};
 use tracing::{debug, info};
 
 pub(crate) use self::context::*;
@@ -75,7 +76,6 @@ use crate::html::escape::Escape;
 use crate::html::format::{
     Ending, HrefError, PrintWithSpace, href, print_abi_with_space, print_constness_with_space,
     print_default_space, print_generic_bounds, print_where_clause, visibility_print_with_space,
-    write_str,
 };
 use crate::html::markdown::{
     HeadingOffset, IdMap, Markdown, MarkdownItemInfo, MarkdownSummaryLine,
@@ -601,7 +601,12 @@ impl AllTypes {
         }
 
         fmt::from_fn(|f| {
-            f.write_str("<h1>List of all items</h1>")?;
+            f.write_str(
+                "<div class=\"main-heading\">\
+                    <h1>List of all items</h1>\
+                    <rustdoc-toolbar></rustdoc-toolbar>\
+                </div>",
+            )?;
             // 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)?;
@@ -1310,43 +1315,6 @@ fn render_assoc_item(
     })
 }
 
-struct CodeAttribute(String);
-
-fn render_code_attribute(prefix: &str, code_attr: CodeAttribute, w: &mut impl fmt::Write) {
-    write!(
-        w,
-        "<div class=\"code-attribute\">{prefix}{attr}</div>",
-        prefix = prefix,
-        attr = code_attr.0
-    )
-    .unwrap();
-}
-
-// When an attribute is rendered inside a <code> tag, it is formatted using
-// a div to produce a newline after it.
-fn render_attributes_in_code(
-    w: &mut impl fmt::Write,
-    it: &clean::Item,
-    prefix: &str,
-    cx: &Context<'_>,
-) {
-    for attr in it.attributes(cx.tcx(), cx.cache()) {
-        render_code_attribute(prefix, CodeAttribute(attr), w);
-    }
-}
-
-/// used for type aliases to only render their `repr` attribute.
-fn render_repr_attributes_in_code(
-    w: &mut impl fmt::Write,
-    cx: &Context<'_>,
-    def_id: DefId,
-    item_type: ItemType,
-) {
-    if let Some(repr) = clean::repr_attributes(cx.tcx(), cx.cache(), def_id, item_type) {
-        render_code_attribute("", CodeAttribute(repr), w);
-    }
-}
-
 #[derive(Copy, Clone)]
 enum AssocItemLink<'a> {
     Anchor(Option<&'a str>),
@@ -1507,12 +1475,10 @@ fn render_assoc_items_inner(
                 )
             }
         };
-        let mut impls_buf = String::new();
-        for i in &non_trait {
-            write_str(
-                &mut impls_buf,
-                format_args!(
-                    "{}",
+        let impls_buf = fmt::from_fn(|f| {
+            non_trait
+                .iter()
+                .map(|i| {
                     render_impl(
                         cx,
                         i,
@@ -1528,9 +1494,11 @@ fn render_assoc_items_inner(
                             toggle_open_by_default: true,
                         },
                     )
-                ),
-            );
-        }
+                })
+                .joined("", f)
+        })
+        .to_string();
+
         if !impls_buf.is_empty() {
             write!(
                 w,
@@ -1682,91 +1650,85 @@ fn notable_traits_button(ty: &clean::Type, cx: &Context<'_>) -> Option<impl fmt:
 }
 
 fn notable_traits_decl(ty: &clean::Type, cx: &Context<'_>) -> (String, String) {
-    let mut out = String::new();
-
     let did = ty.def_id(cx.cache()).expect("notable_traits_button already checked this");
 
     let impls = cx.cache().impls.get(&did).expect("notable_traits_button already checked this");
 
-    for i in impls {
-        let impl_ = i.inner_impl();
-        if impl_.polarity != ty::ImplPolarity::Positive {
-            continue;
-        }
-
-        if !ty.is_doc_subtype_of(&impl_.for_, cx.cache()) {
-            // Two different types might have the same did,
-            // without actually being the same.
-            continue;
-        }
-        if let Some(trait_) = &impl_.trait_ {
-            let trait_did = trait_.def_id();
-
-            if cx.cache().traits.get(&trait_did).is_some_and(|t| t.is_notable_trait(cx.tcx())) {
-                if out.is_empty() {
-                    write_str(
-                        &mut out,
-                        format_args!(
-                            "<h3>Notable traits for <code>{}</code></h3>\
-                            <pre><code>",
-                            impl_.for_.print(cx)
-                        ),
-                    );
+    let out = fmt::from_fn(|f| {
+        let mut notable_impls = impls
+            .iter()
+            .map(|impl_| impl_.inner_impl())
+            .filter(|impl_| impl_.polarity == ty::ImplPolarity::Positive)
+            .filter(|impl_| {
+                // Two different types might have the same did, without actually being the same.
+                ty.is_doc_subtype_of(&impl_.for_, cx.cache())
+            })
+            .filter_map(|impl_| {
+                if let Some(trait_) = &impl_.trait_
+                    && let trait_did = trait_.def_id()
+                    && let Some(trait_) = cx.cache().traits.get(&trait_did)
+                    && trait_.is_notable_trait(cx.tcx())
+                {
+                    Some((impl_, trait_did))
+                } else {
+                    None
                 }
+            })
+            .peekable();
 
-                write_str(
-                    &mut out,
-                    format_args!("<div class=\"where\">{}</div>", impl_.print(false, cx)),
-                );
-                for it in &impl_.items {
-                    if let clean::AssocTypeItem(ref tydef, ref _bounds) = it.kind {
-                        let empty_set = FxIndexSet::default();
-                        let src_link = AssocItemLink::GotoSource(trait_did.into(), &empty_set);
-                        write_str(
-                            &mut out,
-                            format_args!(
-                                "<div class=\"where\">    {};</div>",
-                                assoc_type(
-                                    it,
-                                    &tydef.generics,
-                                    &[], // intentionally leaving out bounds
-                                    Some(&tydef.type_),
-                                    src_link,
-                                    0,
-                                    cx,
-                                )
-                            ),
-                        );
-                    }
-                }
+        let has_notable_impl = if let Some((impl_, _)) = notable_impls.peek() {
+            write!(
+                f,
+                "<h3>Notable traits for <code>{}</code></h3>\
+                <pre><code>",
+                impl_.for_.print(cx)
+            )?;
+            true
+        } else {
+            false
+        };
+
+        for (impl_, trait_did) in notable_impls {
+            write!(f, "<div class=\"where\">{}</div>", impl_.print(false, cx))?;
+            for it in &impl_.items {
+                let clean::AssocTypeItem(tydef, ..) = &it.kind else {
+                    continue;
+                };
+
+                let empty_set = FxIndexSet::default();
+                let src_link = AssocItemLink::GotoSource(trait_did.into(), &empty_set);
+
+                write!(
+                    f,
+                    "<div class=\"where\">    {};</div>",
+                    assoc_type(
+                        it,
+                        &tydef.generics,
+                        &[], // intentionally leaving out bounds
+                        Some(&tydef.type_),
+                        src_link,
+                        0,
+                        cx,
+                    )
+                )?;
             }
         }
-    }
-    if out.is_empty() {
-        out.push_str("</code></pre>");
-    }
+
+        if !has_notable_impl {
+            f.write_str("</code></pre>")?;
+        }
+
+        Ok(())
+    })
+    .to_string();
 
     (format!("{:#}", ty.print(cx)), out)
 }
 
 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)>);
-    impl Serialize for NotableTraitsMap {
-        fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
-        where
-            S: Serializer,
-        {
-            let mut map = serializer.serialize_map(Some(self.0.len()))?;
-            for item in &self.0 {
-                map.serialize_entry(&item.0, &item.1)?;
-            }
-            map.end()
-        }
-    }
-    serde_json::to_string(&NotableTraitsMap(mp))
-        .expect("serialize (string, string) -> json object cannot fail")
+    let mut mp = tys.map(|ty| notable_traits_decl(ty, cx)).collect::<IndexMap<_, _>>();
+    mp.sort_unstable_keys();
+    serde_json::to_string(&mp).expect("serialize (string, string) -> json object cannot fail")
 }
 
 #[derive(Clone, Copy, Debug)]
@@ -1840,27 +1802,19 @@ fn render_impl(
                                 document_item_info(cx, it, Some(parent))
                                     .render_into(&mut info_buffer)
                                     .unwrap();
-                                write_str(
-                                    &mut doc_buffer,
-                                    format_args!("{}", document_full(item, cx, HeadingOffset::H5)),
-                                );
+                                doc_buffer = document_full(item, cx, HeadingOffset::H5).to_string();
                                 short_documented = false;
                             } else {
                                 // In case the item isn't documented,
                                 // provide short documentation from the trait.
-                                write_str(
-                                    &mut doc_buffer,
-                                    format_args!(
-                                        "{}",
-                                        document_short(
-                                            it,
-                                            cx,
-                                            link,
-                                            parent,
-                                            rendering_params.show_def_docs,
-                                        )
-                                    ),
-                                );
+                                doc_buffer = document_short(
+                                    it,
+                                    cx,
+                                    link,
+                                    parent,
+                                    rendering_params.show_def_docs,
+                                )
+                                .to_string();
                             }
                         }
                     } else {
@@ -1868,21 +1822,14 @@ fn render_impl(
                             .render_into(&mut info_buffer)
                             .unwrap();
                         if rendering_params.show_def_docs {
-                            write_str(
-                                &mut doc_buffer,
-                                format_args!("{}", document_full(item, cx, HeadingOffset::H5)),
-                            );
+                            doc_buffer = document_full(item, cx, HeadingOffset::H5).to_string();
                             short_documented = false;
                         }
                     }
                 } else {
-                    write_str(
-                        &mut doc_buffer,
-                        format_args!(
-                            "{}",
-                            document_short(item, cx, link, parent, rendering_params.show_def_docs)
-                        ),
-                    );
+                    doc_buffer =
+                        document_short(item, cx, link, parent, rendering_params.show_def_docs)
+                            .to_string();
                 }
             }
             let mut w = if short_documented && trait_.is_some() {
@@ -2959,3 +2906,142 @@ fn render_call_locations<W: fmt::Write>(
 
     w.write_str("</div>")
 }
+
+fn render_attributes_in_code(
+    w: &mut impl fmt::Write,
+    item: &clean::Item,
+    prefix: &str,
+    cx: &Context<'_>,
+) {
+    for attr in &item.attrs.other_attrs {
+        let hir::Attribute::Parsed(kind) = attr else { continue };
+        let attr = match kind {
+            AttributeKind::LinkSection { name, .. } => {
+                Cow::Owned(format!("#[unsafe(link_section = {})]", Escape(&format!("{name:?}"))))
+            }
+            AttributeKind::NoMangle(..) => Cow::Borrowed("#[unsafe(no_mangle)]"),
+            AttributeKind::ExportName { name, .. } => {
+                Cow::Owned(format!("#[unsafe(export_name = {})]", Escape(&format!("{name:?}"))))
+            }
+            AttributeKind::NonExhaustive(..) => Cow::Borrowed("#[non_exhaustive]"),
+            _ => continue,
+        };
+        render_code_attribute(prefix, attr.as_ref(), w);
+    }
+
+    if let Some(def_id) = item.def_id()
+        && let Some(repr) = repr_attribute(cx.tcx(), cx.cache(), def_id)
+    {
+        render_code_attribute(prefix, &repr, w);
+    }
+}
+
+fn render_repr_attribute_in_code(w: &mut impl fmt::Write, cx: &Context<'_>, def_id: DefId) {
+    if let Some(repr) = repr_attribute(cx.tcx(), cx.cache(), def_id) {
+        render_code_attribute("", &repr, w);
+    }
+}
+
+fn render_code_attribute(prefix: &str, attr: &str, w: &mut impl fmt::Write) {
+    write!(w, "<div class=\"code-attribute\">{prefix}{attr}</div>").unwrap();
+}
+
+/// Compute the *public* `#[repr]` of the item given by `DefId`.
+///
+/// Read more about it here:
+/// <https://doc.rust-lang.org/nightly/rustdoc/advanced-features.html#repr-documenting-the-representation-of-a-type>.
+fn repr_attribute<'tcx>(
+    tcx: TyCtxt<'tcx>,
+    cache: &Cache,
+    def_id: DefId,
+) -> Option<Cow<'static, str>> {
+    let adt = match tcx.def_kind(def_id) {
+        DefKind::Struct | DefKind::Enum | DefKind::Union => tcx.adt_def(def_id),
+        _ => return None,
+    };
+    let repr = adt.repr();
+
+    let is_visible = |def_id| cache.document_hidden || !tcx.is_doc_hidden(def_id);
+    let is_public_field = |field: &ty::FieldDef| {
+        (cache.document_private || field.vis.is_public()) && is_visible(field.did)
+    };
+
+    if repr.transparent() {
+        // The transparent repr is public iff the non-1-ZST field is public and visible or
+        // – in case all fields are 1-ZST fields — at least one field is public and visible.
+        let is_public = 'is_public: {
+            // `#[repr(transparent)]` can only be applied to structs and single-variant enums.
+            let var = adt.variant(rustc_abi::FIRST_VARIANT); // the first and only variant
+
+            if !is_visible(var.def_id) {
+                break 'is_public false;
+            }
+
+            // Side note: There can only ever be one or zero non-1-ZST fields.
+            let non_1zst_field = var.fields.iter().find(|field| {
+                let ty = ty::TypingEnv::post_analysis(tcx, field.did)
+                    .as_query_input(tcx.type_of(field.did).instantiate_identity());
+                tcx.layout_of(ty).is_ok_and(|layout| !layout.is_1zst())
+            });
+
+            match non_1zst_field {
+                Some(field) => is_public_field(field),
+                None => var.fields.is_empty() || var.fields.iter().any(is_public_field),
+            }
+        };
+
+        // Since the transparent repr can't have any other reprs or
+        // repr modifiers beside it, we can safely return early here.
+        return is_public.then(|| "#[repr(transparent)]".into());
+    }
+
+    // Fast path which avoids looking through the variants and fields in
+    // the common case of no `#[repr]` or in the case of `#[repr(Rust)]`.
+    // FIXME: This check is not very robust / forward compatible!
+    if !repr.c()
+        && !repr.simd()
+        && repr.int.is_none()
+        && repr.pack.is_none()
+        && repr.align.is_none()
+    {
+        return None;
+    }
+
+    // The repr is public iff all components are public and visible.
+    let is_public = adt
+        .variants()
+        .iter()
+        .all(|variant| is_visible(variant.def_id) && variant.fields.iter().all(is_public_field));
+    if !is_public {
+        return None;
+    }
+
+    let mut result = Vec::<Cow<'_, _>>::new();
+
+    if repr.c() {
+        result.push("C".into());
+    }
+    if repr.simd() {
+        result.push("simd".into());
+    }
+    if let Some(int) = repr.int {
+        let prefix = if int.is_signed() { 'i' } else { 'u' };
+        let int = match int {
+            rustc_abi::IntegerType::Pointer(_) => format!("{prefix}size"),
+            rustc_abi::IntegerType::Fixed(int, _) => {
+                format!("{prefix}{}", int.size().bytes() * 8)
+            }
+        };
+        result.push(int.into());
+    }
+
+    // Render modifiers last.
+    if let Some(pack) = repr.pack {
+        result.push(format!("packed({})", pack.bytes()).into());
+    }
+    if let Some(align) = repr.align {
+        result.push(format!("align({})", align.bytes()).into());
+    }
+
+    (!result.is_empty()).then(|| format!("#[repr({})]", result.join(", ")).into())
+}
diff --git a/src/librustdoc/html/render/print_item.rs b/src/librustdoc/html/render/print_item.rs
index afa438f2596..adfc7481c73 100644
--- a/src/librustdoc/html/render/print_item.rs
+++ b/src/librustdoc/html/render/print_item.rs
@@ -21,7 +21,7 @@ use super::{
     collect_paths_for_type, document, ensure_trailing_slash, get_filtered_impls_for_reference,
     item_ty_to_section, notable_traits_button, notable_traits_json, render_all_impls,
     render_assoc_item, render_assoc_items, render_attributes_in_code, render_impl,
-    render_repr_attributes_in_code, render_rightside, render_stability_since_raw,
+    render_repr_attribute_in_code, render_rightside, render_stability_since_raw,
     render_stability_since_raw_with_extra, write_section_heading,
 };
 use crate::clean;
@@ -1555,7 +1555,7 @@ impl<'clean> DisplayEnum<'clean> {
         wrap_item(w, |w| {
             if is_type_alias {
                 // For now the only attributes we render for type aliases are `repr` attributes.
-                render_repr_attributes_in_code(w, cx, self.def_id, ItemType::Enum);
+                render_repr_attribute_in_code(w, cx, self.def_id);
             } else {
                 render_attributes_in_code(w, it, "", cx);
             }
@@ -2017,7 +2017,7 @@ impl<'a> DisplayStruct<'a> {
         wrap_item(w, |w| {
             if is_type_alias {
                 // For now the only attributes we render for type aliases are `repr` attributes.
-                render_repr_attributes_in_code(w, cx, self.def_id, ItemType::Struct);
+                render_repr_attribute_in_code(w, cx, self.def_id);
             } else {
                 render_attributes_in_code(w, it, "", cx);
             }
@@ -2371,7 +2371,7 @@ fn render_union(
     fmt::from_fn(move |mut f| {
         if is_type_alias {
             // For now the only attributes we render for type aliases are `repr` attributes.
-            render_repr_attributes_in_code(f, cx, def_id, ItemType::Union);
+            render_repr_attribute_in_code(f, cx, def_id);
         } else {
             render_attributes_in_code(f, it, "", cx);
         }
diff --git a/src/librustdoc/html/render/search_index.rs b/src/librustdoc/html/render/search_index.rs
index 3ffce61f7c6..7b21c68d2e9 100644
--- a/src/librustdoc/html/render/search_index.rs
+++ b/src/librustdoc/html/render/search_index.rs
@@ -241,6 +241,34 @@ impl SerializedSearchIndex {
         self.alias_pointers.push(alias_pointer);
         index
     }
+    /// Add potential search result to the database and return the row ID.
+    ///
+    /// The returned ID can be used to attach more data to the search result.
+    fn add_entry(&mut self, name: Symbol, entry_data: EntryData, desc: String) -> usize {
+        let fqp = if let Some(module_path_index) = entry_data.module_path {
+            let mut fqp = self.path_data[module_path_index].as_ref().unwrap().module_path.clone();
+            fqp.push(Symbol::intern(&self.names[module_path_index]));
+            fqp.push(name);
+            fqp
+        } else {
+            vec![name]
+        };
+        // If a path with the same name already exists, but no entry does,
+        // we can fill in the entry without having to allocate a new row ID.
+        //
+        // Because paths and entries both share the same index, using the same
+        // ID saves space by making the tree smaller.
+        if let Some(&other_path) = self.crate_paths_index.get(&(entry_data.ty, fqp))
+            && self.entry_data[other_path].is_none()
+            && self.descs[other_path].is_empty()
+        {
+            self.entry_data[other_path] = Some(entry_data);
+            self.descs[other_path] = desc;
+            other_path
+        } else {
+            self.push(name.as_str().to_string(), None, Some(entry_data), desc, None, None, None)
+        }
+    }
     fn push_path(&mut self, name: String, path_data: PathData) -> usize {
         self.push(name, Some(path_data), None, String::new(), None, None, None)
     }
@@ -1516,10 +1544,9 @@ pub(crate) fn build_index(
             .as_ref()
             .map(|path| serialized_index.get_id_by_module_path(path));
 
-        let new_entry_id = serialized_index.push(
-            item.name.as_str().to_string(),
-            None,
-            Some(EntryData {
+        let new_entry_id = serialized_index.add_entry(
+            item.name,
+            EntryData {
                 ty: item.ty,
                 parent: item.parent_idx,
                 module_path,
@@ -1538,11 +1565,8 @@ pub(crate) fn build_index(
                     None
                 },
                 krate: crate_idx,
-            }),
+            },
             item.desc.to_string(),
-            None, // filled in after all the types have been indexed
-            None,
-            None,
         );
 
         // Aliases
diff --git a/src/librustdoc/html/render/span_map.rs b/src/librustdoc/html/render/span_map.rs
index 8bc2e0bd957..bc9417b1bb1 100644
--- a/src/librustdoc/html/render/span_map.rs
+++ b/src/librustdoc/html/render/span_map.rs
@@ -2,19 +2,54 @@ use std::path::{Path, PathBuf};
 
 use rustc_data_structures::fx::{FxHashMap, FxIndexMap};
 use rustc_hir::def::{DefKind, Res};
-use rustc_hir::def_id::{DefId, LOCAL_CRATE};
-use rustc_hir::intravisit::{self, Visitor};
-use rustc_hir::{
-    ExprKind, HirId, Item, ItemKind, Mod, Node, Pat, PatExpr, PatExprKind, PatKind, QPath,
-};
+use rustc_hir::def_id::{DefId, LOCAL_CRATE, LocalDefId};
+use rustc_hir::intravisit::{self, Visitor, VisitorExt};
+use rustc_hir::{ExprKind, HirId, Item, ItemKind, Mod, Node, QPath};
 use rustc_middle::hir::nested_filter;
 use rustc_middle::ty::TyCtxt;
 use rustc_span::hygiene::MacroKind;
-use rustc_span::{BytePos, ExpnKind, Span};
+use rustc_span::{BytePos, ExpnKind};
 
 use crate::clean::{self, PrimitiveType, rustc_span};
 use crate::html::sources;
 
+/// This is a stripped down version of [`rustc_span::Span`] that only contains the start and end byte positions of the span.
+///
+/// Profiling showed that the `Span` interner was taking up a lot of the run-time when highlighting, and since we
+/// never actually use the context and parent that are stored in a normal `Span`, we can replace its usages with this
+/// one, which is much cheaper to construct.
+#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
+pub(crate) struct Span {
+    lo: BytePos,
+    hi: BytePos,
+}
+
+impl From<rustc_span::Span> for Span {
+    fn from(value: rustc_span::Span) -> Self {
+        Self { lo: value.lo(), hi: value.hi() }
+    }
+}
+
+impl Span {
+    pub(crate) fn lo(self) -> BytePos {
+        self.lo
+    }
+
+    pub(crate) fn hi(self) -> BytePos {
+        self.hi
+    }
+
+    pub(crate) fn with_lo(self, lo: BytePos) -> Self {
+        Self { lo, hi: self.hi() }
+    }
+
+    pub(crate) fn with_hi(self, hi: BytePos) -> Self {
+        Self { lo: self.lo(), hi }
+    }
+}
+
+pub(crate) const DUMMY_SP: Span = Span { lo: BytePos(0), hi: BytePos(0) };
+
 /// This enum allows us to store two different kinds of information:
 ///
 /// In case the `span` definition comes from the same crate, we can simply get the `span` and use
@@ -67,7 +102,7 @@ struct SpanMapVisitor<'tcx> {
 
 impl SpanMapVisitor<'_> {
     /// This function is where we handle `hir::Path` elements and add them into the "span map".
-    fn handle_path(&mut self, path: &rustc_hir::Path<'_>) {
+    fn handle_path(&mut self, path: &rustc_hir::Path<'_>, only_use_last_segment: bool) {
         match path.res {
             // FIXME: For now, we handle `DefKind` if it's not a `DefKind::TyParam`.
             // Would be nice to support them too alongside the other `DefKind`
@@ -79,28 +114,41 @@ impl SpanMapVisitor<'_> {
                     LinkFromSrc::External(def_id)
                 };
                 // In case the path ends with generics, we remove them from the span.
-                let span = path
-                    .segments
-                    .last()
-                    .map(|last| {
-                        // In `use` statements, the included item is not in the path segments.
-                        // However, it doesn't matter because you can't have generics on `use`
-                        // statements.
-                        if path.span.contains(last.ident.span) {
-                            path.span.with_hi(last.ident.span.hi())
-                        } else {
-                            path.span
-                        }
-                    })
-                    .unwrap_or(path.span);
-                self.matches.insert(span, link);
+                let span = if only_use_last_segment
+                    && let Some(path_span) = path.segments.last().map(|segment| segment.ident.span)
+                {
+                    path_span
+                } else {
+                    path.segments
+                        .last()
+                        .map(|last| {
+                            // In `use` statements, the included item is not in the path segments.
+                            // However, it doesn't matter because you can't have generics on `use`
+                            // statements.
+                            if path.span.contains(last.ident.span) {
+                                path.span.with_hi(last.ident.span.hi())
+                            } else {
+                                path.span
+                            }
+                        })
+                        .unwrap_or(path.span)
+                };
+                self.matches.insert(span.into(), link);
             }
             Res::Local(_) if let Some(span) = self.tcx.hir_res_span(path.res) => {
-                self.matches.insert(path.span, LinkFromSrc::Local(clean::Span::new(span)));
+                let path_span = if only_use_last_segment
+                    && let Some(path_span) = path.segments.last().map(|segment| segment.ident.span)
+                {
+                    path_span
+                } else {
+                    path.span
+                };
+                self.matches.insert(path_span.into(), LinkFromSrc::Local(clean::Span::new(span)));
             }
             Res::PrimTy(p) => {
                 // FIXME: Doesn't handle "path-like" primitives like arrays or tuples.
-                self.matches.insert(path.span, LinkFromSrc::Primitive(PrimitiveType::from(p)));
+                self.matches
+                    .insert(path.span.into(), LinkFromSrc::Primitive(PrimitiveType::from(p)));
             }
             Res::Err => {}
             _ => {}
@@ -117,7 +165,7 @@ impl SpanMapVisitor<'_> {
             if cspan.inner().is_dummy() || cspan.cnum(self.tcx.sess) != LOCAL_CRATE {
                 return;
             }
-            self.matches.insert(span, LinkFromSrc::Doc(item.owner_id.to_def_id()));
+            self.matches.insert(span.into(), LinkFromSrc::Doc(item.owner_id.to_def_id()));
         }
     }
 
@@ -128,7 +176,7 @@ impl SpanMapVisitor<'_> {
     /// so, we loop until we find the macro definition by using `outer_expn_data` in a loop.
     /// Finally, we get the information about the macro itself (`span` if "local", `DefId`
     /// otherwise) and store it inside the span map.
-    fn handle_macro(&mut self, span: Span) -> bool {
+    fn handle_macro(&mut self, span: rustc_span::Span) -> bool {
         if !span.from_expansion() {
             return false;
         }
@@ -166,7 +214,7 @@ impl SpanMapVisitor<'_> {
         // The "call_site" includes the whole macro with its "arguments". We only want
         // the macro name.
         let new_span = new_span.with_hi(new_span.lo() + BytePos(macro_name.len() as u32));
-        self.matches.insert(new_span, link_from_src);
+        self.matches.insert(new_span.into(), link_from_src);
         true
     }
 
@@ -189,31 +237,23 @@ impl SpanMapVisitor<'_> {
             self.matches.insert(span, link);
         }
     }
+}
 
-    fn handle_pat(&mut self, p: &Pat<'_>) {
-        let mut check_qpath = |qpath, hir_id| match qpath {
-            QPath::TypeRelative(_, path) if matches!(path.res, Res::Err) => {
-                self.infer_id(path.hir_id, Some(hir_id), qpath.span());
-            }
-            QPath::Resolved(_, path) => self.handle_path(path),
-            _ => {}
-        };
-        match p.kind {
-            PatKind::Binding(_, _, _, Some(p)) => self.handle_pat(p),
-            PatKind::Struct(qpath, _, _) | PatKind::TupleStruct(qpath, _, _) => {
-                check_qpath(qpath, p.hir_id)
-            }
-            PatKind::Expr(PatExpr { kind: PatExprKind::Path(qpath), hir_id, .. }) => {
-                check_qpath(*qpath, *hir_id)
-            }
-            PatKind::Or(pats) => {
-                for pat in pats {
-                    self.handle_pat(pat);
-                }
-            }
-            _ => {}
+// This is a reimplementation of `hir_enclosing_body_owner` which allows to fail without
+// panicking.
+fn hir_enclosing_body_owner(tcx: TyCtxt<'_>, hir_id: HirId) -> Option<LocalDefId> {
+    for (_, node) in tcx.hir_parent_iter(hir_id) {
+        // FIXME: associated type impl items don't have an associated body, so we don't handle
+        // them currently.
+        if let Node::ImplItem(impl_item) = node
+            && matches!(impl_item.kind, rustc_hir::ImplItemKind::Type(_))
+        {
+            return None;
+        } else if let Some((def_id, _)) = node.associated_body() {
+            return Some(def_id);
         }
     }
+    None
 }
 
 impl<'tcx> Visitor<'tcx> for SpanMapVisitor<'tcx> {
@@ -227,15 +267,45 @@ impl<'tcx> Visitor<'tcx> for SpanMapVisitor<'tcx> {
         if self.handle_macro(path.span) {
             return;
         }
-        self.handle_path(path);
+        self.handle_path(path, false);
         intravisit::walk_path(self, path);
     }
 
-    fn visit_pat(&mut self, p: &Pat<'tcx>) {
-        self.handle_pat(p);
+    fn visit_qpath(&mut self, qpath: &QPath<'tcx>, id: HirId, _span: rustc_span::Span) {
+        match *qpath {
+            QPath::TypeRelative(qself, path) => {
+                if matches!(path.res, Res::Err) {
+                    let tcx = self.tcx;
+                    if let Some(body_id) = hir_enclosing_body_owner(tcx, id) {
+                        let typeck_results = tcx.typeck_body(tcx.hir_body_owned_by(body_id).id());
+                        let path = rustc_hir::Path {
+                            // We change the span to not include parens.
+                            span: path.ident.span,
+                            res: typeck_results.qpath_res(qpath, id),
+                            segments: &[],
+                        };
+                        self.handle_path(&path, false);
+                    }
+                } else {
+                    self.infer_id(path.hir_id, Some(id), path.ident.span.into());
+                }
+
+                rustc_ast::visit::try_visit!(self.visit_ty_unambig(qself));
+                self.visit_path_segment(path);
+            }
+            QPath::Resolved(maybe_qself, path) => {
+                self.handle_path(path, true);
+
+                rustc_ast::visit::visit_opt!(self, visit_ty_unambig, maybe_qself);
+                if !self.handle_macro(path.span) {
+                    intravisit::walk_path(self, path);
+                }
+            }
+            _ => {}
+        }
     }
 
-    fn visit_mod(&mut self, m: &'tcx Mod<'tcx>, span: Span, id: HirId) {
+    fn visit_mod(&mut self, m: &'tcx Mod<'tcx>, span: rustc_span::Span, id: HirId) {
         // To make the difference between "mod foo {}" and "mod foo;". In case we "import" another
         // file, we want to link to it. Otherwise no need to create a link.
         if !span.overlaps(m.spans.inner_span) {
@@ -243,8 +313,10 @@ impl<'tcx> Visitor<'tcx> for SpanMapVisitor<'tcx> {
             // name only and not all the "mod foo;".
             if let Node::Item(item) = self.tcx.hir_node(id) {
                 let (ident, _) = item.expect_mod();
-                self.matches
-                    .insert(ident.span, LinkFromSrc::Local(clean::Span::new(m.spans.inner_span)));
+                self.matches.insert(
+                    ident.span.into(),
+                    LinkFromSrc::Local(clean::Span::new(m.spans.inner_span)),
+                );
             }
         } else {
             // If it's a "mod foo {}", we want to look to its documentation page.
@@ -256,9 +328,9 @@ impl<'tcx> Visitor<'tcx> for SpanMapVisitor<'tcx> {
     fn visit_expr(&mut self, expr: &'tcx rustc_hir::Expr<'tcx>) {
         match expr.kind {
             ExprKind::MethodCall(segment, ..) => {
-                self.infer_id(segment.hir_id, Some(expr.hir_id), segment.ident.span)
+                self.infer_id(segment.hir_id, Some(expr.hir_id), segment.ident.span.into())
             }
-            ExprKind::Call(call, ..) => self.infer_id(call.hir_id, None, call.span),
+            ExprKind::Call(call, ..) => self.infer_id(call.hir_id, None, call.span.into()),
             _ => {
                 if self.handle_macro(expr.span) {
                     // We don't want to go deeper into the macro.
diff --git a/src/librustdoc/html/render/write_shared.rs b/src/librustdoc/html/render/write_shared.rs
index e37a5246a76..3a1db805d01 100644
--- a/src/librustdoc/html/render/write_shared.rs
+++ b/src/librustdoc/html/render/write_shared.rs
@@ -386,8 +386,13 @@ impl CratesIndexPart {
         let layout = &cx.shared.layout;
         let style_files = &cx.shared.style_files;
         const DELIMITER: &str = "\u{FFFC}"; // users are being naughty if they have this
-        let content =
-            format!("<h1>List of all crates</h1><ul class=\"all-items\">{DELIMITER}</ul>");
+        let content = format!(
+            "<div class=\"main-heading\">\
+                <h1>List of all crates</h1>\
+                <rustdoc-toolbar></rustdoc-toolbar>\
+            </div>\
+            <ul class=\"all-items\">{DELIMITER}</ul>"
+        );
         let template = layout::render(layout, &page, "", content, style_files);
         SortedTemplate::from_template(&template, DELIMITER)
             .expect("Object Replacement Character (U+FFFC) should not appear in the --index-page")
diff --git a/src/librustdoc/html/sources.rs b/src/librustdoc/html/sources.rs
index 9c5518a780e..c79f63fbc20 100644
--- a/src/librustdoc/html/sources.rs
+++ b/src/librustdoc/html/sources.rs
@@ -348,7 +348,12 @@ pub(crate) fn print_src(
         highlight::write_code(
             fmt,
             s,
-            Some(highlight::HrefContext { context, file_span, root_path, current_href }),
+            Some(highlight::HrefContext {
+                context,
+                file_span: file_span.into(),
+                root_path,
+                current_href,
+            }),
             Some(decoration_info),
             Some(line_info),
         );
diff --git a/src/librustdoc/html/static/js/stringdex.js b/src/librustdoc/html/static/js/stringdex.js
index 5bdc81e330e..6299576d564 100644
--- a/src/librustdoc/html/static/js/stringdex.js
+++ b/src/librustdoc/html/static/js/stringdex.js
@@ -1108,22 +1108,39 @@ function loadDatabase(hooks) {
                     const id2 = id1 + ((nodeid[4] << 8) | nodeid[5]);
                     leaves = RoaringBitmap.makeSingleton(id1)
                         .union(RoaringBitmap.makeSingleton(id2));
+                } else if (!isWhole && (nodeid[0] & 0xf0) === 0x80) {
+                    const id1 = ((nodeid[0] & 0x0f) << 16) | (nodeid[1] << 8) | nodeid[2];
+                    const id2 = id1 + ((nodeid[3] << 4) | ((nodeid[4] >> 4) & 0x0f));
+                    const id3 = id2 + (((nodeid[4] & 0x0f) << 8) | nodeid[5]);
+                    leaves = RoaringBitmap.makeSingleton(id1)
+                        .union(RoaringBitmap.makeSingleton(id2))
+                        .union(RoaringBitmap.makeSingleton(id3));
                 } else {
                     leaves = RoaringBitmap.makeSingleton(
                         (nodeid[2] << 24) | (nodeid[3] << 16) |
                         (nodeid[4] << 8) | nodeid[5],
                     );
                 }
-                const data = (nodeid[0] & 0x20) !== 0 ?
-                    Uint8Array.of(((nodeid[0] & 0x0f) << 4) | (nodeid[1] >> 4)) :
-                    EMPTY_UINT8;
-                newPromise = Promise.resolve(new PrefixSearchTree(
-                    EMPTY_SEARCH_TREE_BRANCHES,
-                    EMPTY_SEARCH_TREE_BRANCHES,
-                    data,
-                    isWhole ? leaves : EMPTY_BITMAP,
-                    isWhole ? EMPTY_BITMAP : leaves,
-                ));
+                if (isWhole) {
+                    const data = (nodeid[0] & 0x20) !== 0 ?
+                        Uint8Array.of(((nodeid[0] & 0x0f) << 4) | (nodeid[1] >> 4)) :
+                        EMPTY_UINT8;
+                    newPromise = Promise.resolve(new PrefixSearchTree(
+                        EMPTY_SEARCH_TREE_BRANCHES,
+                        EMPTY_SEARCH_TREE_BRANCHES,
+                        data,
+                        leaves,
+                        EMPTY_BITMAP,
+                    ));
+                } else {
+                    const data = (nodeid[0] & 0xf0) === 0x80 ? 0 : (
+                        ((nodeid[0] & 0x0f) << 4) | (nodeid[1] >> 4));
+                    newPromise = Promise.resolve(new SuffixSearchTree(
+                        EMPTY_SEARCH_TREE_BRANCHES,
+                        data,
+                        leaves,
+                    ));
+                }
             } else {
                 const hashHex = makeHexFromUint8Array(nodeid);
                 newPromise = new Promise((resolve, reject) => {
@@ -2748,6 +2765,7 @@ function loadDatabase(hooks) {
             // because that's the canonical, hashed version of the data
             let compression_tag = input[i];
             const is_pure_suffixes_only_node = (compression_tag & 0x01) !== 0;
+            let no_leaves_flag;
             if (compression_tag > 1) {
                 // compressed node
                 const is_long_compressed = (compression_tag & 0x04) !== 0;
@@ -2759,7 +2777,8 @@ function loadDatabase(hooks) {
                     compression_tag |= input[i] << 16;
                     i += 1;
                 }
-                let dlen = input[i];
+                let dlen = input[i] & 0x7F;
+                no_leaves_flag = input[i] & 0x80;
                 i += 1;
                 if (is_data_compressed) {
                     data = data_history[data_history.length - dlen - 1];
@@ -2786,10 +2805,15 @@ function loadDatabase(hooks) {
                 let whole;
                 let suffix;
                 if (is_pure_suffixes_only_node) {
-                    suffix = input[i] === 0 ?
-                        EMPTY_BITMAP1 :
-                        new RoaringBitmap(input, i);
-                    i += suffix.consumed_len_bytes;
+                    if (no_leaves_flag) {
+                        whole = EMPTY_BITMAP;
+                        suffix = EMPTY_BITMAP;
+                    } else {
+                        suffix = input[i] === 0 ?
+                            EMPTY_BITMAP1 :
+                            new RoaringBitmap(input, i);
+                        i += suffix.consumed_len_bytes;
+                    }
                     tree = new SuffixSearchTree(
                         branches,
                         dlen,
@@ -2807,7 +2831,7 @@ function loadDatabase(hooks) {
                     let ci = 0;
                     canonical[ci] = 1;
                     ci += 1;
-                    canonical[ci] = dlen;
+                    canonical[ci] = dlen | no_leaves_flag;
                     ci += 1;
                     canonical[ci] = input[coffset]; // suffix child count
                     ci += 1;
@@ -2821,10 +2845,9 @@ function loadDatabase(hooks) {
                     }
                     siphashOfBytes(canonical.subarray(0, clen), 0, 0, 0, 0, hash);
                 } else {
-                    if (input[i] === 0xff) {
+                    if (no_leaves_flag) {
                         whole = EMPTY_BITMAP;
-                        suffix = EMPTY_BITMAP1;
-                        i += 1;
+                        suffix = EMPTY_BITMAP;
                     } else {
                         whole = input[i] === 0 ?
                             EMPTY_BITMAP1 :
@@ -2856,7 +2879,7 @@ function loadDatabase(hooks) {
                     let ci = 0;
                     canonical[ci] = 0;
                     ci += 1;
-                    canonical[ci] = dlen;
+                    canonical[ci] = dlen | no_leaves_flag;
                     ci += 1;
                     canonical.set(data, ci);
                     ci += data.length;
@@ -2880,9 +2903,11 @@ function loadDatabase(hooks) {
                 }
                 hash[2] &= 0x7f;
             } else {
+                i += 1;
                 // uncompressed node
-                const dlen = input [i + 1];
-                i += 2;
+                const dlen = input[i] & 0x7F;
+                no_leaves_flag = input[i] & 0x80;
+                i += 1;
                 if (dlen === 0 || is_pure_suffixes_only_node) {
                     data = EMPTY_UINT8;
                 } else {
@@ -2897,16 +2922,15 @@ function loadDatabase(hooks) {
                 i += branches_consumed_len_bytes;
                 let whole;
                 let suffix;
-                if (is_pure_suffixes_only_node) {
+                if (no_leaves_flag) {
+                    whole = EMPTY_BITMAP;
+                    suffix = EMPTY_BITMAP;
+                } else if (is_pure_suffixes_only_node) {
                     whole = EMPTY_BITMAP;
                     suffix = input[i] === 0 ?
                         EMPTY_BITMAP1 :
                         new RoaringBitmap(input, i);
                     i += suffix.consumed_len_bytes;
-                } else if (input[i] === 0xff) {
-                    whole = EMPTY_BITMAP;
-                    suffix = EMPTY_BITMAP;
-                    i += 1;
                 } else {
                     whole = input[i] === 0 ?
                         EMPTY_BITMAP1 :
diff --git a/src/librustdoc/lib.rs b/src/librustdoc/lib.rs
index 5d8f8f4bed1..d7ffb25f8bd 100644
--- a/src/librustdoc/lib.rs
+++ b/src/librustdoc/lib.rs
@@ -1,5 +1,4 @@
 // tidy-alphabetical-start
-#![cfg_attr(bootstrap, feature(round_char_boundary))]
 #![doc(
     html_root_url = "https://doc.rust-lang.org/nightly/",
     html_playground_url = "https://play.rust-lang.org/"
@@ -14,6 +13,7 @@
 #![feature(if_let_guard)]
 #![feature(iter_advance_by)]
 #![feature(iter_intersperse)]
+#![feature(iter_order_by)]
 #![feature(rustc_private)]
 #![feature(test)]
 #![warn(rustc::internal)]
diff --git a/src/librustdoc/passes/collect_intra_doc_links.rs b/src/librustdoc/passes/collect_intra_doc_links.rs
index 0da42f38251..79d74c3c4eb 100644
--- a/src/librustdoc/passes/collect_intra_doc_links.rs
+++ b/src/librustdoc/passes/collect_intra_doc_links.rs
@@ -130,6 +130,7 @@ impl Res {
             DefKind::Static { .. } => "static",
             DefKind::Field => "field",
             DefKind::Variant | DefKind::Ctor(..) => "variant",
+            DefKind::TyAlias => "tyalias",
             // Now handle things that don't have a specific disambiguator
             _ => match kind
                 .ns()
@@ -1708,6 +1709,7 @@ impl Disambiguator {
                 "value" => NS(Namespace::ValueNS),
                 "macro" => NS(Namespace::MacroNS),
                 "prim" | "primitive" => Primitive,
+                "tyalias" | "typealias" => Kind(DefKind::TyAlias),
                 _ => return Err((format!("unknown disambiguator `{prefix}`"), 0..idx)),
             };
 
diff --git a/src/librustdoc/passes/mod.rs b/src/librustdoc/passes/mod.rs
index 475d05b7d0e..f45df8d2d0d 100644
--- a/src/librustdoc/passes/mod.rs
+++ b/src/librustdoc/passes/mod.rs
@@ -77,11 +77,11 @@ pub(crate) enum Condition {
 pub(crate) const PASSES: &[Pass] = &[
     CHECK_DOC_CFG,
     CHECK_DOC_TEST_VISIBILITY,
+    PROPAGATE_DOC_CFG,
     STRIP_ALIASED_NON_LOCAL,
     STRIP_HIDDEN,
     STRIP_PRIVATE,
     STRIP_PRIV_IMPORTS,
-    PROPAGATE_DOC_CFG,
     PROPAGATE_STABILITY,
     COLLECT_INTRA_DOC_LINKS,
     COLLECT_TRAIT_IMPLS,
@@ -94,11 +94,11 @@ pub(crate) const DEFAULT_PASSES: &[ConditionalPass] = &[
     ConditionalPass::always(COLLECT_TRAIT_IMPLS),
     ConditionalPass::always(CHECK_DOC_TEST_VISIBILITY),
     ConditionalPass::always(CHECK_DOC_CFG),
+    ConditionalPass::always(COLLECT_INTRA_DOC_LINKS),
     ConditionalPass::always(STRIP_ALIASED_NON_LOCAL),
     ConditionalPass::new(STRIP_HIDDEN, WhenNotDocumentHidden),
     ConditionalPass::new(STRIP_PRIVATE, WhenNotDocumentPrivate),
     ConditionalPass::new(STRIP_PRIV_IMPORTS, WhenDocumentPrivate),
-    ConditionalPass::always(COLLECT_INTRA_DOC_LINKS),
     ConditionalPass::always(PROPAGATE_DOC_CFG),
     ConditionalPass::always(PROPAGATE_STABILITY),
     ConditionalPass::always(RUN_LINTS),
diff --git a/src/librustdoc/passes/propagate_doc_cfg.rs b/src/librustdoc/passes/propagate_doc_cfg.rs
index eddafa9ba8e..d5b20f2b941 100644
--- a/src/librustdoc/passes/propagate_doc_cfg.rs
+++ b/src/librustdoc/passes/propagate_doc_cfg.rs
@@ -1,12 +1,12 @@
 //! Propagates [`#[doc(cfg(...))]`](https://github.com/rust-lang/rust/issues/43781) to child items.
 
-use std::sync::Arc;
+use rustc_ast::token::{Token, TokenKind};
+use rustc_ast::tokenstream::{TokenStream, TokenTree};
+use rustc_hir::{AttrArgs, Attribute};
+use rustc_span::symbol::sym;
 
-use rustc_hir::def_id::LocalDefId;
-
-use crate::clean::cfg::Cfg;
 use crate::clean::inline::{load_attrs, merge_attrs};
-use crate::clean::{Crate, Item, ItemKind};
+use crate::clean::{CfgInfo, Crate, Item, ItemKind};
 use crate::core::DocContext;
 use crate::fold::DocFolder;
 use crate::passes::Pass;
@@ -18,80 +18,112 @@ pub(crate) const PROPAGATE_DOC_CFG: Pass = Pass {
 };
 
 pub(crate) fn propagate_doc_cfg(cr: Crate, cx: &mut DocContext<'_>) -> Crate {
-    CfgPropagator { parent_cfg: None, parent: None, cx }.fold_crate(cr)
+    if cx.tcx.features().doc_cfg() {
+        CfgPropagator { cx, cfg_info: CfgInfo::default() }.fold_crate(cr)
+    } else {
+        cr
+    }
 }
 
 struct CfgPropagator<'a, 'tcx> {
-    parent_cfg: Option<Arc<Cfg>>,
-    parent: Option<LocalDefId>,
     cx: &'a mut DocContext<'tcx>,
+    cfg_info: CfgInfo,
 }
 
-impl CfgPropagator<'_, '_> {
-    // Some items need to merge their attributes with their parents' otherwise a few of them
-    // (mostly `cfg` ones) will be missing.
-    fn merge_with_parent_attributes(&mut self, item: &mut Item) {
-        let check_parent = match &item.kind {
-            // impl blocks can be in different modules with different cfg and we need to get them
-            // as well.
-            ItemKind::ImplItem(_) => false,
-            kind if kind.is_non_assoc() => true,
-            _ => return,
-        };
+/// Returns true if the provided `token` is a `cfg` ident.
+fn is_cfg_token(token: &TokenTree) -> bool {
+    // We only keep `doc(cfg)` items.
+    matches!(token, TokenTree::Token(Token { kind: TokenKind::Ident(sym::cfg, _,), .. }, _,),)
+}
 
-        let Some(def_id) = item.item_id.as_def_id().and_then(|def_id| def_id.as_local()) else {
-            return;
-        };
+/// We only want to keep `#[cfg()]` and `#[doc(cfg())]` attributes so we rebuild a vec of
+/// `TokenTree` with only the tokens we're interested into.
+fn filter_non_cfg_tokens_from_list(args_tokens: &TokenStream) -> Vec<TokenTree> {
+    let mut tokens = Vec::with_capacity(args_tokens.len());
+    let mut skip_next_delimited = false;
+    for token in args_tokens.iter() {
+        match token {
+            TokenTree::Delimited(..) => {
+                if !skip_next_delimited {
+                    tokens.push(token.clone());
+                }
+                skip_next_delimited = false;
+            }
+            token if is_cfg_token(token) => {
+                skip_next_delimited = false;
+                tokens.push(token.clone());
+            }
+            _ => {
+                skip_next_delimited = true;
+            }
+        }
+    }
+    tokens
+}
 
-        if check_parent {
-            let expected_parent = self.cx.tcx.opt_local_parent(def_id);
-            // If parents are different, it means that `item` is a reexport and we need
-            // to compute the actual `cfg` by iterating through its "real" parents.
-            if self.parent.is_some() && self.parent == expected_parent {
-                return;
+/// This function goes through the attributes list (`new_attrs`) and extract the `cfg` tokens from
+/// it and put them into `attrs`.
+fn add_only_cfg_attributes(attrs: &mut Vec<Attribute>, new_attrs: &[Attribute]) {
+    for attr in new_attrs {
+        if attr.is_doc_comment() {
+            continue;
+        }
+        let mut attr = attr.clone();
+        if let Attribute::Unparsed(ref mut normal) = attr
+            && let [ident] = &*normal.path.segments
+        {
+            let ident = ident.name;
+            if ident == sym::doc
+                && let AttrArgs::Delimited(args) = &mut normal.args
+            {
+                let tokens = filter_non_cfg_tokens_from_list(&args.tokens);
+                args.tokens = TokenStream::new(tokens);
+                attrs.push(attr);
+            } else if ident == sym::cfg_trace {
+                // If it's a `cfg()` attribute, we keep it.
+                attrs.push(attr);
             }
         }
+    }
+}
 
+impl CfgPropagator<'_, '_> {
+    // Some items need to merge their attributes with their parents' otherwise a few of them
+    // (mostly `cfg` ones) will be missing.
+    fn merge_with_parent_attributes(&mut self, item: &mut Item) {
         let mut attrs = Vec::new();
-        let mut next_def_id = def_id;
-        while let Some(parent_def_id) = self.cx.tcx.opt_local_parent(next_def_id) {
-            attrs.extend_from_slice(load_attrs(self.cx, parent_def_id.to_def_id()));
-            next_def_id = parent_def_id;
+        // We only need to merge an item attributes with its parent's in case it's an impl as an
+        // impl might not be defined in the same module as the item it implements.
+        //
+        // Otherwise, `cfg_info` already tracks everything we need so nothing else to do!
+        if matches!(item.kind, ItemKind::ImplItem(_))
+            && let Some(mut next_def_id) = item.item_id.as_local_def_id()
+        {
+            while let Some(parent_def_id) = self.cx.tcx.opt_local_parent(next_def_id) {
+                let x = load_attrs(self.cx, parent_def_id.to_def_id());
+                add_only_cfg_attributes(&mut attrs, x);
+                next_def_id = parent_def_id;
+            }
         }
 
-        let (_, cfg) =
-            merge_attrs(self.cx, item.attrs.other_attrs.as_slice(), Some((&attrs, None)));
+        let (_, cfg) = merge_attrs(
+            self.cx,
+            item.attrs.other_attrs.as_slice(),
+            Some((&attrs, None)),
+            &mut self.cfg_info,
+        );
         item.inner.cfg = cfg;
     }
 }
 
 impl DocFolder for CfgPropagator<'_, '_> {
     fn fold_item(&mut self, mut item: Item) -> Option<Item> {
-        let old_parent_cfg = self.parent_cfg.clone();
+        let old_cfg_info = self.cfg_info.clone();
 
         self.merge_with_parent_attributes(&mut item);
 
-        let new_cfg = match (self.parent_cfg.take(), item.inner.cfg.take()) {
-            (None, None) => None,
-            (Some(rc), None) | (None, Some(rc)) => Some(rc),
-            (Some(mut a), Some(b)) => {
-                let b = Arc::try_unwrap(b).unwrap_or_else(|rc| Cfg::clone(&rc));
-                *Arc::make_mut(&mut a) &= b;
-                Some(a)
-            }
-        };
-        self.parent_cfg = new_cfg.clone();
-        item.inner.cfg = new_cfg;
-
-        let old_parent =
-            if let Some(def_id) = item.item_id.as_def_id().and_then(|def_id| def_id.as_local()) {
-                self.parent.replace(def_id)
-            } else {
-                self.parent.take()
-            };
         let result = self.fold_item_recur(item);
-        self.parent_cfg = old_parent_cfg;
-        self.parent = old_parent;
+        self.cfg_info = old_cfg_info;
 
         Some(result)
     }
diff --git a/src/librustdoc/visit_ast.rs b/src/librustdoc/visit_ast.rs
index cd28322f590..dc9889cec21 100644
--- a/src/librustdoc/visit_ast.rs
+++ b/src/librustdoc/visit_ast.rs
@@ -9,7 +9,7 @@ use rustc_hir::attrs::AttributeKind;
 use rustc_hir::def::{DefKind, MacroKinds, Res};
 use rustc_hir::def_id::{DefId, DefIdMap, LocalDefId, LocalDefIdSet};
 use rustc_hir::intravisit::{Visitor, walk_body, walk_item};
-use rustc_hir::{CRATE_HIR_ID, Node, find_attr};
+use rustc_hir::{Node, find_attr};
 use rustc_middle::hir::nested_filter;
 use rustc_middle::ty::TyCtxt;
 use rustc_span::Span;
@@ -17,7 +17,6 @@ use rustc_span::def_id::{CRATE_DEF_ID, LOCAL_CRATE};
 use rustc_span::symbol::{Symbol, kw, sym};
 use tracing::debug;
 
-use crate::clean::cfg::Cfg;
 use crate::clean::utils::{inherits_doc_hidden, should_ignore_res};
 use crate::clean::{NestedAttributesExt, hir_attr_lists, reexport_chain};
 use crate::core;
@@ -178,32 +177,6 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> {
             }
         }
 
-        self.cx.cache.hidden_cfg = self
-            .cx
-            .tcx
-            .hir_attrs(CRATE_HIR_ID)
-            .iter()
-            .filter(|attr| attr.has_name(sym::doc))
-            .flat_map(|attr| attr.meta_item_list().into_iter().flatten())
-            .filter(|attr| attr.has_name(sym::cfg_hide))
-            .flat_map(|attr| {
-                attr.meta_item_list()
-                    .unwrap_or(&[])
-                    .iter()
-                    .filter_map(|attr| {
-                        Cfg::parse(attr)
-                            .map_err(|e| self.cx.sess().dcx().span_err(e.span, e.msg))
-                            .ok()
-                    })
-                    .collect::<Vec<_>>()
-            })
-            .chain([
-                Cfg::Cfg(sym::test, None),
-                Cfg::Cfg(sym::doc, None),
-                Cfg::Cfg(sym::doctest, None),
-            ])
-            .collect();
-
         self.cx.cache.exact_paths = self.exact_paths;
         top_level_module
     }
diff --git a/src/stage0 b/src/stage0
index a705cd1c760..556ced41d3d 100644
--- a/src/stage0
+++ b/src/stage0
@@ -13,506 +13,528 @@ nightly_branch=master
 # All changes below this comment will be overridden the next time the
 # tool is executed.
 
-compiler_date=2025-08-05
+compiler_channel_manifest_hash=55f3014ea3a3b17cfa5060d9188fd13d13b065456661a3d670dd061719713f32
+compiler_git_commit_hash=bb624dcb4c8ab987e10c0808d92d76f3b84dd117
+compiler_date=2025-09-21
 compiler_version=beta
-rustfmt_date=2025-09-05
+rustfmt_channel_manifest_hash=2f19b9b74a17d0283264a227ed552d7df6729929fcb73b2d5bb321feed8a5c85
+rustfmt_git_commit_hash=54a8a1db604e4caff93e26e167ad4a6fde9f0681
+rustfmt_date=2025-09-27
 rustfmt_version=nightly
 
-dist/2025-08-05/rustc-beta-aarch64-apple-darwin.tar.gz=b9d8f74da46aeadb6c650a4ccfc3c2de08e229e4211a198fa2914103f09f579d
-dist/2025-08-05/rustc-beta-aarch64-apple-darwin.tar.xz=493ed87c65bac5593c104373a3277ddc2330072796704e4b6800c531326da860
-dist/2025-08-05/rustc-beta-aarch64-pc-windows-gnullvm.tar.gz=6c20a3b2e4d3ef9a54b1fe4f50c71895d4d8557d6960f887ef4958c0f2a19eab
-dist/2025-08-05/rustc-beta-aarch64-pc-windows-gnullvm.tar.xz=d6bffc013745c0d69f4cf7ab4f747f8ad885e3b1b77fa56c2e7de8808e278294
-dist/2025-08-05/rustc-beta-aarch64-pc-windows-msvc.tar.gz=3b6bf7e2aff93854346c1d0970cf207c049c17c5ea6ee299dcdb1fd92e996fc0
-dist/2025-08-05/rustc-beta-aarch64-pc-windows-msvc.tar.xz=8241fdc7c673499091700cfcfafe10f3b70bf91918a3b7204a73d2b28445cfa5
-dist/2025-08-05/rustc-beta-aarch64-unknown-linux-gnu.tar.gz=36a093e6c99f227e293ebcaebc89e58166e3da7447d2499069c616610fb4e691
-dist/2025-08-05/rustc-beta-aarch64-unknown-linux-gnu.tar.xz=7cad77f36dcabbe77d603b8b3b4bfa83488a3af2e9b815f698f544de148c77a8
-dist/2025-08-05/rustc-beta-aarch64-unknown-linux-musl.tar.gz=421980aa1ef5467f59c1a8ad43415d69057c9277fdc91d1d5c2b53c246e8bbe9
-dist/2025-08-05/rustc-beta-aarch64-unknown-linux-musl.tar.xz=0ba5b4cd4f5975a58cf86331de5a3c80fb2fd620d50797360a5af4ebf2bba575
-dist/2025-08-05/rustc-beta-arm-unknown-linux-gnueabi.tar.gz=13b3e61ca606bfdf90d46a8873ca4f14fa07ad8bd77364f1a85f557f31ba7299
-dist/2025-08-05/rustc-beta-arm-unknown-linux-gnueabi.tar.xz=f6a1991e55af549d6cd59ddbebb6d2289d90d1e37b2a9449d7831b4c117a54bf
-dist/2025-08-05/rustc-beta-arm-unknown-linux-gnueabihf.tar.gz=a5533df1ae642bcea571aa6c2b5eda16a56c6cd597906081840bb7531f7b02a3
-dist/2025-08-05/rustc-beta-arm-unknown-linux-gnueabihf.tar.xz=2a7187ad6d0215f07d0472880e117556508780e37df6e2a1a7fdbb67fd8dc87e
-dist/2025-08-05/rustc-beta-armv7-unknown-linux-gnueabihf.tar.gz=3ae6e7d83ae3e1c5c8030ba93b9103addaf11f0f8807f1fbf813305d8e6a9188
-dist/2025-08-05/rustc-beta-armv7-unknown-linux-gnueabihf.tar.xz=324d6de1a8e4d9c1dd13cc86665fd06cb167d4a3ea55607cd5353300733f480e
-dist/2025-08-05/rustc-beta-i686-pc-windows-gnu.tar.gz=0bc4b50638818008e054af245d4e987ce5e55fdc56e19d31c18e8c0165f860ab
-dist/2025-08-05/rustc-beta-i686-pc-windows-gnu.tar.xz=b0e5343207a9684d5efe81e536d23135df07bebd869dcad69c632811e1e37137
-dist/2025-08-05/rustc-beta-i686-pc-windows-msvc.tar.gz=c3231335a50402989d4e08857fd7194a3fe5384d2aa34153a25a3f2955a942ef
-dist/2025-08-05/rustc-beta-i686-pc-windows-msvc.tar.xz=be578fcbfe32e40fd9688e618927ddcce88e7e08a279778d4c3399eb46e8ae29
-dist/2025-08-05/rustc-beta-i686-unknown-linux-gnu.tar.gz=96b2cdda499b63aadb76b37a4895623a4806c5c8db8f6edeaeb1b812d337192f
-dist/2025-08-05/rustc-beta-i686-unknown-linux-gnu.tar.xz=f6496eabe0efcc09c7a4994cc4825e9c3e494c8ca7679cfcbd38a699438e1b74
-dist/2025-08-05/rustc-beta-loongarch64-unknown-linux-gnu.tar.gz=3403d7be2f49387149ce075b427f8eaa306066db9fd4ec69de61dc01f6834037
-dist/2025-08-05/rustc-beta-loongarch64-unknown-linux-gnu.tar.xz=8cb3a329ef3632afc1f709b9f9b99a2ab7f5c18590590ddacf64f1b3e5a3ff69
-dist/2025-08-05/rustc-beta-loongarch64-unknown-linux-musl.tar.gz=9485ce37e99a6a53b5521683bec65d015a730a41c4c3f3baa19226edd211fc39
-dist/2025-08-05/rustc-beta-loongarch64-unknown-linux-musl.tar.xz=450d91ad61a23f69560e53c7001aec047bd17fb4831bafb97e7226162bb3c0f4
-dist/2025-08-05/rustc-beta-powerpc-unknown-linux-gnu.tar.gz=dc9ff117a7dd3e685c634e8668d78022f66f6e58dc449fbe5f398688ed2dae0a
-dist/2025-08-05/rustc-beta-powerpc-unknown-linux-gnu.tar.xz=7dbc936f94d531040601d6fc02d9db87335a1b7927637494c9e208a43f012010
-dist/2025-08-05/rustc-beta-powerpc64-unknown-linux-gnu.tar.gz=4a68557cf53063817ee651f5838ad2c3de93a647b9002fe3c82f0372cbd71708
-dist/2025-08-05/rustc-beta-powerpc64-unknown-linux-gnu.tar.xz=f5ae9c4ba17d2941e8fa947d9712a8db8dbbdecbcfa4330988d02b9299fbc814
-dist/2025-08-05/rustc-beta-powerpc64le-unknown-linux-gnu.tar.gz=ad33c48172c3b9abbd95b9dd3c1d38d5f6bc25fe84b95e492b6cdad27ef1bf19
-dist/2025-08-05/rustc-beta-powerpc64le-unknown-linux-gnu.tar.xz=89d40fb02cded4e8d9b3e177f07e1b984481d493015a2532dfdb5b8aaf5ffa94
-dist/2025-08-05/rustc-beta-powerpc64le-unknown-linux-musl.tar.gz=a5ab7a321363502609a4ec5464be96629c693395503c8ce285990db3c556a775
-dist/2025-08-05/rustc-beta-powerpc64le-unknown-linux-musl.tar.xz=7e3b5afc7858857d5840bd6e788fd88449555e2fbe4c9a206ee3552e61dd79b0
-dist/2025-08-05/rustc-beta-riscv64gc-unknown-linux-gnu.tar.gz=fde633217cf77d6fc6f901d84619f681a1fd1e42be75960809bab4806528a451
-dist/2025-08-05/rustc-beta-riscv64gc-unknown-linux-gnu.tar.xz=69541c68f31a401229d770ef2ea6d032104fe928db845eae23f04c40db021a8d
-dist/2025-08-05/rustc-beta-s390x-unknown-linux-gnu.tar.gz=dc257bbab4790dbc3f9df70853eadce198dd5f6f47c8e830254ee2b21c6c79a3
-dist/2025-08-05/rustc-beta-s390x-unknown-linux-gnu.tar.xz=d5a9d5c555241b231eacc0584db0b540ee2982e8bd66cf8568064aab4beb0c94
-dist/2025-08-05/rustc-beta-sparcv9-sun-solaris.tar.gz=96b25f8ce6db2f9d9b7e8da75839d1bd4c97011bebd2544633ab2061e4460bb3
-dist/2025-08-05/rustc-beta-sparcv9-sun-solaris.tar.xz=88438d143441da62bf5415857aab3490697f7f413b7de41cd113bac1480ea7de
-dist/2025-08-05/rustc-beta-x86_64-apple-darwin.tar.gz=f59175ef402489c1dd2f6a8984ecb66314240a8e4f7c55e5d92017fc025fa4ee
-dist/2025-08-05/rustc-beta-x86_64-apple-darwin.tar.xz=21de96e49395252e6eb5b175ee794acad78ccd4ac081303a8da7ec84bf2b6ab1
-dist/2025-08-05/rustc-beta-x86_64-pc-solaris.tar.gz=164a9b76347131d78fb81519627ab50f13a313d8da13d09f7fa479a41c519458
-dist/2025-08-05/rustc-beta-x86_64-pc-solaris.tar.xz=0f91f1f4b8880944341d82894b830a70f8a60837687829e0ab9626f3281ddd1b
-dist/2025-08-05/rustc-beta-x86_64-pc-windows-gnu.tar.gz=634711ae22708a5ae57bb2022fd22257664a8510b59975f4b4ad4b9a8acf475b
-dist/2025-08-05/rustc-beta-x86_64-pc-windows-gnu.tar.xz=b72c0d3f5800e92b91d1361e52b28ff622aeb1f1cbdff2efd22c2f2a3315dd68
-dist/2025-08-05/rustc-beta-x86_64-pc-windows-gnullvm.tar.gz=668f3a8b48092721bb6e1a01440776d6b906850a11e1bcc37a50bb13ef8d7b04
-dist/2025-08-05/rustc-beta-x86_64-pc-windows-gnullvm.tar.xz=e06a183829e09448e76daaf8c317b52d11fac7d16ad191ef61b8f7a806eb9414
-dist/2025-08-05/rustc-beta-x86_64-pc-windows-msvc.tar.gz=564849501d1e41fe776f5443b87c9500621adef97eff05d2c03d539ea3c886da
-dist/2025-08-05/rustc-beta-x86_64-pc-windows-msvc.tar.xz=6a1c1cc47c0e8b6aaad215d4d4e8b770b96336e9f2a0317fcf0511b662966bfd
-dist/2025-08-05/rustc-beta-x86_64-unknown-freebsd.tar.gz=560bcc4d150f4e22f5598d61fce86c9baeda1b57bda837270f7cac78cfc12b19
-dist/2025-08-05/rustc-beta-x86_64-unknown-freebsd.tar.xz=cdfe207645068b4659b0f979cae177723c5f211084f45ae9180b2d93ee83fce6
-dist/2025-08-05/rustc-beta-x86_64-unknown-illumos.tar.gz=5a362ca0c686b0e0666824df3f304ec49d7d419abb08473fece69d41e96ee625
-dist/2025-08-05/rustc-beta-x86_64-unknown-illumos.tar.xz=fb4e7b12b5223545f6fd57754744f03dd6807b6801e97f9f0fe07bc371efed62
-dist/2025-08-05/rustc-beta-x86_64-unknown-linux-gnu.tar.gz=74225a1889120c0174a056e7ca7656f38e8788137ee3d29df857567ae0605692
-dist/2025-08-05/rustc-beta-x86_64-unknown-linux-gnu.tar.xz=2d37542e88f84a0501841e12865262142fec0efef9ca729d26a3c333f16e465d
-dist/2025-08-05/rustc-beta-x86_64-unknown-linux-musl.tar.gz=156eabc89e1ee9558b9de6f60b1bc47c81ab33ae20fa946c4ad4e32b7f30c221
-dist/2025-08-05/rustc-beta-x86_64-unknown-linux-musl.tar.xz=0cf9e649b9020fcfd25282ae1edb1ac59560b7d6d0f79ff7ff3b62871ff25d86
-dist/2025-08-05/rustc-beta-x86_64-unknown-netbsd.tar.gz=8db86a95b22efc2ff2f344e301171813375ccfd2aacad61d3aa84a63f573647a
-dist/2025-08-05/rustc-beta-x86_64-unknown-netbsd.tar.xz=68c10c6431b4433d4de5d24a9bb6ebabe99769b077cdd80ab5e0ee67a273035e
-dist/2025-08-05/rust-std-beta-aarch64-apple-darwin.tar.gz=872e61e6d6915c02de0b9437b910f6f37f5e11c83347bbe2284a59c31aa27ac3
-dist/2025-08-05/rust-std-beta-aarch64-apple-darwin.tar.xz=748516af852836f06efa927cc96bdd2ad6b012d0262e87bdec97a112212cc24a
-dist/2025-08-05/rust-std-beta-aarch64-apple-ios.tar.gz=2c1cf24819ec790d124c7ace59c12a903250eefdad6362b40c779a97b732459e
-dist/2025-08-05/rust-std-beta-aarch64-apple-ios.tar.xz=b2fd6df9653b6c0bc13d4331355b3b9a4756886ba46d6c744687bf7bbd8e4630
-dist/2025-08-05/rust-std-beta-aarch64-apple-ios-macabi.tar.gz=c266b75c66ea17b174ce8a746bbad78bca58bd72c3cdda603f20a868f9b3b00c
-dist/2025-08-05/rust-std-beta-aarch64-apple-ios-macabi.tar.xz=da5558b25c82a5fc1b66786b035212c5d0df2d4124da3e581e15636f29547dd0
-dist/2025-08-05/rust-std-beta-aarch64-apple-ios-sim.tar.gz=8441032f41e142faebe78e84501344180447121602a2000d1310d7a716cf3695
-dist/2025-08-05/rust-std-beta-aarch64-apple-ios-sim.tar.xz=48713adfa5605addd97e13312f6bc4cf103c06623f67705732684b51d0bed8b1
-dist/2025-08-05/rust-std-beta-aarch64-linux-android.tar.gz=1eb2bbc5fac670aa5867546f1caf1378591d5c0d3a3800ca1dd052645fea0cd6
-dist/2025-08-05/rust-std-beta-aarch64-linux-android.tar.xz=ae5e8aedcc5c8bf719e8ed788d52cc69daf64dfcf878e8497b45454c1c582c56
-dist/2025-08-05/rust-std-beta-aarch64-pc-windows-gnullvm.tar.gz=bedf5d7663acb4e1afed9dea4b5b8e9b7f0e0dd68e311d3597819ddd028576f7
-dist/2025-08-05/rust-std-beta-aarch64-pc-windows-gnullvm.tar.xz=e19fd9dc6d9e774e30a9e4a16ac5d6d1fd3300eb880c09f6b61cc63d52370629
-dist/2025-08-05/rust-std-beta-aarch64-pc-windows-msvc.tar.gz=8ad111b1e8e19fdc5bd33d82a1f6d88b9c1809e27531af9d9fed2e37f75edeb4
-dist/2025-08-05/rust-std-beta-aarch64-pc-windows-msvc.tar.xz=332976524e42b4d7b2763a28cae3ebbc3eec03465c098df26e81242294277de4
-dist/2025-08-05/rust-std-beta-aarch64-unknown-fuchsia.tar.gz=92f4737a1775c1fed9311b8949950c6606ca34d272f787d222923555fb69f98b
-dist/2025-08-05/rust-std-beta-aarch64-unknown-fuchsia.tar.xz=2f1ebaa974dc3c6b39c43e38cf6d9f5c6fba0d46229a0423be676d817905850c
-dist/2025-08-05/rust-std-beta-aarch64-unknown-linux-gnu.tar.gz=798dafd6f581f367dfed9763b62b35e77466f87ae8252a52f503f1c1bf58f1a5
-dist/2025-08-05/rust-std-beta-aarch64-unknown-linux-gnu.tar.xz=c4434727604a2773f73e8919a6e967c7c487d75684514cacbe59fb2d6a5f0d29
-dist/2025-08-05/rust-std-beta-aarch64-unknown-linux-musl.tar.gz=c48d4e44b0e94f341e7ab2f9d47b08280930152a53dff20d6c9140739fbd2898
-dist/2025-08-05/rust-std-beta-aarch64-unknown-linux-musl.tar.xz=8cac54d6a39c13dd0f38fde523a852c5db7f61a7f05b3e3ad0f78c7f59513d02
-dist/2025-08-05/rust-std-beta-aarch64-unknown-linux-ohos.tar.gz=5c3d7ea7ac6ab60311fb49c5a2f04a92266bc8a675d7f333219177a91b400f9b
-dist/2025-08-05/rust-std-beta-aarch64-unknown-linux-ohos.tar.xz=f1f9f8a71fc5903bf720d39bedaadab16363b37f9e99817d7cf27b7122ad1ad0
-dist/2025-08-05/rust-std-beta-aarch64-unknown-none.tar.gz=ceffb671e87556b304e63cf01572e1cad8c8cfa0b33ccd1a373b033c60696376
-dist/2025-08-05/rust-std-beta-aarch64-unknown-none.tar.xz=a9a9b17f2b4fdf45f46359726e0c28f6a1289a7abf81fdbe1ae180b2f550aa60
-dist/2025-08-05/rust-std-beta-aarch64-unknown-none-softfloat.tar.gz=9f6f6a121e3b19b7b3b2c85dcd13544c12af18cc5544403e29ea8bbd5b13fecc
-dist/2025-08-05/rust-std-beta-aarch64-unknown-none-softfloat.tar.xz=5b0f0059dd5d837fad74aaf2971fb135229b030a832268106be512557cc7a611
-dist/2025-08-05/rust-std-beta-aarch64-unknown-uefi.tar.gz=67166c7d6d7210ca97c3610abfa126234653d0e26658bbea64d574852fad04fe
-dist/2025-08-05/rust-std-beta-aarch64-unknown-uefi.tar.xz=05f72e7c0ebbf7b41bf3e773bbbc073ca9c71417a80dec8f3916dafbe0cdcf7b
-dist/2025-08-05/rust-std-beta-arm-linux-androideabi.tar.gz=bdf103a29035659972f35bb9060ba8df5ca9b7b068e3c094d758331a5e667144
-dist/2025-08-05/rust-std-beta-arm-linux-androideabi.tar.xz=8fa8b6994b4e04fec77a6657db0fde4e4cb9336466ce0c4f3e2b154709969c93
-dist/2025-08-05/rust-std-beta-arm-unknown-linux-gnueabi.tar.gz=4298510905c958e45291c2fbc4c54bfed9fdafbd48636896fe00a73e94f700ba
-dist/2025-08-05/rust-std-beta-arm-unknown-linux-gnueabi.tar.xz=79e0e393f5286429755faee738ed110fb1cc51b83aec3c94194e903f0b938d73
-dist/2025-08-05/rust-std-beta-arm-unknown-linux-gnueabihf.tar.gz=37278a621e2449b9030045c174c71f3ddf74e70b49b5f247c36fea1b1654979f
-dist/2025-08-05/rust-std-beta-arm-unknown-linux-gnueabihf.tar.xz=3ac094e855f7593a22a56ec40923384a0e25265645d05b2a46dde2612d9c6cf9
-dist/2025-08-05/rust-std-beta-arm-unknown-linux-musleabi.tar.gz=b5bc7d83a3c59764cdc169ae349e01cd052b8ab054eb13b4f2a1cd02ddd7fd6c
-dist/2025-08-05/rust-std-beta-arm-unknown-linux-musleabi.tar.xz=2f8558fee897543da620531e500f3a73c5aac4ea815b7bd418945103dedde530
-dist/2025-08-05/rust-std-beta-arm-unknown-linux-musleabihf.tar.gz=2e812427b5169e7de22b720776208ae92f9075c5509f6b9ad8666b9866232735
-dist/2025-08-05/rust-std-beta-arm-unknown-linux-musleabihf.tar.xz=e544363209177357386f220d6c4101b1d86d84c03e51254ff459ca42ef187107
-dist/2025-08-05/rust-std-beta-arm64ec-pc-windows-msvc.tar.gz=778c947235bb0023ca26dc0592e4d3cb9ad9665c3316d57822c173ba2b5e231e
-dist/2025-08-05/rust-std-beta-arm64ec-pc-windows-msvc.tar.xz=3a5bf7620e1b24e1f72968f5cc28cc58acc9b5739f2c08f5c4b9e449d8c551a1
-dist/2025-08-05/rust-std-beta-armebv7r-none-eabi.tar.gz=fcace82dc77156a6e7c658fc5abe4992075cfe822fb18a1edfca1967102a6adc
-dist/2025-08-05/rust-std-beta-armebv7r-none-eabi.tar.xz=9616372693902e89b55de55b62009a59baccb11ccb63710a475856deca70655c
-dist/2025-08-05/rust-std-beta-armebv7r-none-eabihf.tar.gz=2c596de7d22a4762908676d4e048f5075cbf2d66c5f7a03afb96e709f2d080ca
-dist/2025-08-05/rust-std-beta-armebv7r-none-eabihf.tar.xz=b1ff9e3fe11acc22fa5ad46530dff62bfceac9df6fcbd3da7999535a00dd2e3e
-dist/2025-08-05/rust-std-beta-armv5te-unknown-linux-gnueabi.tar.gz=e033e4bfc11a5bcb7f0645426fac899f7d071236a228300ca2022935997b17fd
-dist/2025-08-05/rust-std-beta-armv5te-unknown-linux-gnueabi.tar.xz=919587b40e2bc6c6e8f496244c357c04d5e53b8adb9b3f274432943fd789a1a4
-dist/2025-08-05/rust-std-beta-armv5te-unknown-linux-musleabi.tar.gz=392a1f0528e4b783e5fd0be74efbec58eb3b0ebd69c3855675301ebf96b76c4a
-dist/2025-08-05/rust-std-beta-armv5te-unknown-linux-musleabi.tar.xz=183144eb89cc1a035c04d50c4060e159ca5099fec71f4f25801a924fa013d04a
-dist/2025-08-05/rust-std-beta-armv7-linux-androideabi.tar.gz=f968b761773b76f151b39dce0f3757f59eee2d8b70373d1419e0986429885d7d
-dist/2025-08-05/rust-std-beta-armv7-linux-androideabi.tar.xz=fecda678541a151b76f3874e710e875a662a9165eaf1cf12b081ea55ea18a38b
-dist/2025-08-05/rust-std-beta-armv7-unknown-linux-gnueabi.tar.gz=300d7e8adaad86ddeff643109d0c83a87e41a056171f9d48b0b6108719003325
-dist/2025-08-05/rust-std-beta-armv7-unknown-linux-gnueabi.tar.xz=acb8f61c97efae6e95aaabe1cab1300bc3cc3a1dc2066c7e2376ad6a9994971c
-dist/2025-08-05/rust-std-beta-armv7-unknown-linux-gnueabihf.tar.gz=5e90333cb68f3161f8cb30e69d4ebe46f6653998651c72a87a795ab02c11dade
-dist/2025-08-05/rust-std-beta-armv7-unknown-linux-gnueabihf.tar.xz=355bc516a7a6454eaacc66eadaa4d640cb3ffc7b5400a01bb4bdccf4470ae650
-dist/2025-08-05/rust-std-beta-armv7-unknown-linux-musleabi.tar.gz=8daa2c4c4dd9e8a1b9ee8a60f2cab0dab81aaf1e7a9d732093979ccdeac8bf60
-dist/2025-08-05/rust-std-beta-armv7-unknown-linux-musleabi.tar.xz=52b78d85f8e9e19da83504bb523aecf7b641d15c1de2f9b988bedf52912636d4
-dist/2025-08-05/rust-std-beta-armv7-unknown-linux-musleabihf.tar.gz=c63000f15b52881c20f40cf1468afd4f3a2a6a84e944357fe6532c7d0e281b3a
-dist/2025-08-05/rust-std-beta-armv7-unknown-linux-musleabihf.tar.xz=53fc3486e4d805386c1ac4d6a1007a9b5461ae606c9c820951b720b45dc8f35c
-dist/2025-08-05/rust-std-beta-armv7-unknown-linux-ohos.tar.gz=315fc371ac2cddeb65c87bd50369e28247c16ca55fdab527e88899e01adc9efe
-dist/2025-08-05/rust-std-beta-armv7-unknown-linux-ohos.tar.xz=d7999aff0a39c63709977f5c18d79b575f8bfb467fbacf4f1b41cd26b52a6701
-dist/2025-08-05/rust-std-beta-armv7a-none-eabi.tar.gz=0707721586e8929811c2904e4136d31f5c415e3f00bfa88dbb920360aa9deea9
-dist/2025-08-05/rust-std-beta-armv7a-none-eabi.tar.xz=bedfd1a808f758f5088ea0fcb746d3ccf11730945e2b07220e93829c0d5c472a
-dist/2025-08-05/rust-std-beta-armv7r-none-eabi.tar.gz=315fadb161b3be540b7a276ebe15b1f8d4bdf73b46c1633e39f698014aca8eb1
-dist/2025-08-05/rust-std-beta-armv7r-none-eabi.tar.xz=4bc2fcd9dee2ee44914da0e6af3763c7ddcbe3ebd9fb20c1d552a0226cd877d7
-dist/2025-08-05/rust-std-beta-armv7r-none-eabihf.tar.gz=9c8be30130709ff94a9718091559a752530f0eeb21be80fc3cca0665e85ae0dc
-dist/2025-08-05/rust-std-beta-armv7r-none-eabihf.tar.xz=f0dd0bd30ed70c3a022016d8bbed54a6e942571f2e4c773bd8b4198d7dccdb5c
-dist/2025-08-05/rust-std-beta-i586-unknown-linux-gnu.tar.gz=ca6c3b8af1c44deaf7dce9e8d4c8786a5801226b30beaa646067d393eeaa0ee8
-dist/2025-08-05/rust-std-beta-i586-unknown-linux-gnu.tar.xz=4e96f0e5f2e3eda60ca2b6d9ce234ae74c5eb2412a7e2c0c571eaf792dca6e28
-dist/2025-08-05/rust-std-beta-i586-unknown-linux-musl.tar.gz=60c736e3ac2aa5b9ceedcd73e39efa12bc9b889ef85f548170f80fbf2b05dfa0
-dist/2025-08-05/rust-std-beta-i586-unknown-linux-musl.tar.xz=fe636d893e38c32a163a88ece160d5b5ea61a3fa63463d4e4f425d229c2927f1
-dist/2025-08-05/rust-std-beta-i686-linux-android.tar.gz=9e62d61041187a91b74c81fe77cd6802a7e38c5a535412c71850426f6a48f37c
-dist/2025-08-05/rust-std-beta-i686-linux-android.tar.xz=862d3d5442fb011b917f565aaadb201c22e7b2ecd6a68c0c410b3335741c1c22
-dist/2025-08-05/rust-std-beta-i686-pc-windows-gnu.tar.gz=05a8da51c477e2c2ce4ea12d41c8afaaf0d226a6b933b6c55fd3584b39103366
-dist/2025-08-05/rust-std-beta-i686-pc-windows-gnu.tar.xz=cf15b3d2011ceb57064d0b2285defee7df8628c3bf2b95f7f2ac92a449546d4f
-dist/2025-08-05/rust-std-beta-i686-pc-windows-gnullvm.tar.gz=fe11b777eae25d823f40352e47272222c2de8edc2d271eb4f6e7ff508efa198d
-dist/2025-08-05/rust-std-beta-i686-pc-windows-gnullvm.tar.xz=a7bb6f223e3542e613eaa7f2b9d9974be71cd2debf8426faa50cfb63fde681fd
-dist/2025-08-05/rust-std-beta-i686-pc-windows-msvc.tar.gz=5fbd709698d80b3227a8bc6cbecfc597e99dede3824c751e1d166cac2c5862dc
-dist/2025-08-05/rust-std-beta-i686-pc-windows-msvc.tar.xz=92fd2a6a5dbe53f68e9ba3ce40cd3beea95ba9d6a2f1293f7f3d917f34739a66
-dist/2025-08-05/rust-std-beta-i686-unknown-freebsd.tar.gz=182acad6cea45855f66646d437ee44ddb1f85c2c998cc5c7a4bbb025ca0d9da9
-dist/2025-08-05/rust-std-beta-i686-unknown-freebsd.tar.xz=53f8bfaabff1dbc47929a99a92025a31c1e272bf6a8091c4f95d33557dfe9ea1
-dist/2025-08-05/rust-std-beta-i686-unknown-linux-gnu.tar.gz=b80dd4e77c56256f7a7f837bf84129d19e1a4aa08a0ca7e2881402371a7e4395
-dist/2025-08-05/rust-std-beta-i686-unknown-linux-gnu.tar.xz=52efb657f28303b0747cf281c972653abfbeb4bf6d0b841f8bbab7f08c5d7310
-dist/2025-08-05/rust-std-beta-i686-unknown-linux-musl.tar.gz=323abc9766231dca10c225b3ec567c694c0ff6f6eddcc30d728a0f08aa6d2186
-dist/2025-08-05/rust-std-beta-i686-unknown-linux-musl.tar.xz=8998ce49f1be28bcd837831f1d7b79b0b339bc74ced42adb6d997ed016e90e88
-dist/2025-08-05/rust-std-beta-i686-unknown-uefi.tar.gz=07261ce98c95839b8714f40e07cbffa32c10fc7c59394dc87b07e144564c5fef
-dist/2025-08-05/rust-std-beta-i686-unknown-uefi.tar.xz=fb6eb023b9722a44e63bcd48fd88c61cf41453842a211107c84039c6883409e5
-dist/2025-08-05/rust-std-beta-loongarch64-unknown-linux-gnu.tar.gz=d0a52888f5ef3107ecdbf28b918eb516a9176ae8695079a81a22d1b7ca0e29bd
-dist/2025-08-05/rust-std-beta-loongarch64-unknown-linux-gnu.tar.xz=c14a477558a6c924e05e1b58bd9df60f5e4966c7f0da294dd38e3bd89c1dc5f6
-dist/2025-08-05/rust-std-beta-loongarch64-unknown-linux-musl.tar.gz=bbb93219393948d055df44edcdfff4b03ca251205c545d6f1bd53ade5f314d52
-dist/2025-08-05/rust-std-beta-loongarch64-unknown-linux-musl.tar.xz=48b437a8afe240828c0377a6baa276500f125661f1bc888ebd1ea546f0497f4a
-dist/2025-08-05/rust-std-beta-loongarch64-unknown-none.tar.gz=fcec6b60a1a22dcd04b8409d38103496d76bb4297ded9f1f092743bd05f0bd54
-dist/2025-08-05/rust-std-beta-loongarch64-unknown-none.tar.xz=2f4aacb734b5a1dd522b4836035ab213db675508b9ff9a1bdc0c2df3ea9d39d1
-dist/2025-08-05/rust-std-beta-loongarch64-unknown-none-softfloat.tar.gz=aad8445e9a5deb4a466ebed84cab101bbe8ef49530315c0349d93e2062ae65a8
-dist/2025-08-05/rust-std-beta-loongarch64-unknown-none-softfloat.tar.xz=906e1cbd1e3b22eb5c378417646baf18b00acb274ee4198ea59ea356f4f1a0da
-dist/2025-08-05/rust-std-beta-nvptx64-nvidia-cuda.tar.gz=b0d7e8daae2eff0c660b6e01bc76258550b9bfbdbf95c104019db7c797339ef5
-dist/2025-08-05/rust-std-beta-nvptx64-nvidia-cuda.tar.xz=c0bffdbb4de90486cad1a26df997006c142f1acc7ed39419975c10b0d09c6217
-dist/2025-08-05/rust-std-beta-powerpc-unknown-linux-gnu.tar.gz=3c845cade37fe2b1cfe3087c69f9ecb3e0eec32d2558701c677d4c21ea9e08db
-dist/2025-08-05/rust-std-beta-powerpc-unknown-linux-gnu.tar.xz=15830d827258f6c3386fa09da66e06ff0460098b46432e28b4e96bd36d61e787
-dist/2025-08-05/rust-std-beta-powerpc64-unknown-linux-gnu.tar.gz=4b63d9260253f1d3a0168ed367792284584b87aa936fc76262e9fe0ad83c7fa1
-dist/2025-08-05/rust-std-beta-powerpc64-unknown-linux-gnu.tar.xz=dfba70ad94524437fc8ec5e4684239eceb76678112776915f02502b80cb0afac
-dist/2025-08-05/rust-std-beta-powerpc64le-unknown-linux-gnu.tar.gz=3d96bebe611a0167a43060312cbfa2fe4000b9949772ee44ffd27226acd006c8
-dist/2025-08-05/rust-std-beta-powerpc64le-unknown-linux-gnu.tar.xz=44e95c2756f52129b8bd21d7d4ad7ec8e05e43192f3bc894cba4a371b579a6d8
-dist/2025-08-05/rust-std-beta-powerpc64le-unknown-linux-musl.tar.gz=ca5b7c47b63fa8e005078cb73d111462c438b764909ca106933837ac93d5780f
-dist/2025-08-05/rust-std-beta-powerpc64le-unknown-linux-musl.tar.xz=b102756451c18003ad1b132d25d333ed1a0e4959b87d2904a6e407fc02a7e422
-dist/2025-08-05/rust-std-beta-riscv32i-unknown-none-elf.tar.gz=a592e995b40d3b1eb69cb1f7cd3c100713ea092742ab6ec5769e8df8551ffa16
-dist/2025-08-05/rust-std-beta-riscv32i-unknown-none-elf.tar.xz=af9cd91be3d667cf31b535862882537a406f49932f58308f283228b20fc7bd76
-dist/2025-08-05/rust-std-beta-riscv32im-unknown-none-elf.tar.gz=bf9e9d0f8c4ce8041c6e628e1b637ac0cb316f865f97a43cf2bf522e255c5ec1
-dist/2025-08-05/rust-std-beta-riscv32im-unknown-none-elf.tar.xz=c3e56d71c1586559212f701508ee94f0bfa7801e7d2fdc62c062dcce8a0d040d
-dist/2025-08-05/rust-std-beta-riscv32imac-unknown-none-elf.tar.gz=068023ed1f1dea01f2523f3b2b9ef41b22a301ceafa0526ebaa757481d14408a
-dist/2025-08-05/rust-std-beta-riscv32imac-unknown-none-elf.tar.xz=1e3db6625ebb12a8c735cf4e8658a33bac7bca461de1e516860843d50027ee7d
-dist/2025-08-05/rust-std-beta-riscv32imafc-unknown-none-elf.tar.gz=aeb986eef375fa1ebb179668c6778c587d1af8b9e1ff50e5b56f9a3b48f1d8df
-dist/2025-08-05/rust-std-beta-riscv32imafc-unknown-none-elf.tar.xz=45d314189b9327645f6490628157fce32b7b59eccdf57676be0c31e1247f5385
-dist/2025-08-05/rust-std-beta-riscv32imc-unknown-none-elf.tar.gz=82d6e6549c80e62d392654693a28528f2ea540652f3ec0810b6646968cae6509
-dist/2025-08-05/rust-std-beta-riscv32imc-unknown-none-elf.tar.xz=805ffe0a6dfbc886f0ba93ac9ce796c110ea6d0a64b2d6209cdadd56cd2a570f
-dist/2025-08-05/rust-std-beta-riscv64gc-unknown-linux-gnu.tar.gz=941c683ef7d013166c7f3439ee1229f80a367405f55bab9072dd12725364db6b
-dist/2025-08-05/rust-std-beta-riscv64gc-unknown-linux-gnu.tar.xz=8b666222443b3954a7550b14ef919b7ab038e6a4a2355386e42c9acbe28f2024
-dist/2025-08-05/rust-std-beta-riscv64gc-unknown-linux-musl.tar.gz=80f740bd004b98d5c090fe280ef5e372e4bff7a34dc2ba4940204cf02f50bb93
-dist/2025-08-05/rust-std-beta-riscv64gc-unknown-linux-musl.tar.xz=b69ad00f5d60c63fa6d7b32c4d7006d195540d902f8390754c7db92a9221973d
-dist/2025-08-05/rust-std-beta-riscv64gc-unknown-none-elf.tar.gz=ed52f0f9bac7b9d7ec49226eea471e44fecf0416608a5b169d35b12d009e9c1b
-dist/2025-08-05/rust-std-beta-riscv64gc-unknown-none-elf.tar.xz=d4dc1b096b26814f14e1e23717cef10f3f63cdc6902e345916e015a99851cb69
-dist/2025-08-05/rust-std-beta-riscv64imac-unknown-none-elf.tar.gz=aa1de02a79f16bb4affb50c3ba0e719352c9925fc57f22f989eed3f7df1a8e5c
-dist/2025-08-05/rust-std-beta-riscv64imac-unknown-none-elf.tar.xz=a36e2749e118f995417f0de9c9835db4b36f8ed6d76d8805510853984f648c5b
-dist/2025-08-05/rust-std-beta-s390x-unknown-linux-gnu.tar.gz=32e6e3672d3c379a1defb6c661eca6f2ce342784feaceafec004bdaa89a0b226
-dist/2025-08-05/rust-std-beta-s390x-unknown-linux-gnu.tar.xz=a449f0392193ab8a48a30b0a8c0c57b0a02747ae8302d08b3be89d475f1b8291
-dist/2025-08-05/rust-std-beta-sparc64-unknown-linux-gnu.tar.gz=a4e0901c13d3c534e176fdf824a97e5a6ca66a198b73a132b957d41b1f198261
-dist/2025-08-05/rust-std-beta-sparc64-unknown-linux-gnu.tar.xz=64720eab59f7c958aadd360b8e2dc5696760d62e9f5f44daba890fc55a4fb6a1
-dist/2025-08-05/rust-std-beta-sparcv9-sun-solaris.tar.gz=8d5d3be06cfe5431b9a8e965fe06837efe531c365e8d46ee8cdc8e9da19099f0
-dist/2025-08-05/rust-std-beta-sparcv9-sun-solaris.tar.xz=913d7fc4aa75ac2175aa52891f9086d48065d96007885e0caf5feb628953a86d
-dist/2025-08-05/rust-std-beta-thumbv6m-none-eabi.tar.gz=ca59366093c472f19381fdc71aacf6b3d659750a8a3bd8894191a42c8c3b82f9
-dist/2025-08-05/rust-std-beta-thumbv6m-none-eabi.tar.xz=e16dc610520f4748ffca99b235e58a544e7f97ca4cf99cbebbeb106ed4acffd1
-dist/2025-08-05/rust-std-beta-thumbv7em-none-eabi.tar.gz=08a281c1bd56149ebd05531fe405a621383ad440fcf273fec04e0792f325d669
-dist/2025-08-05/rust-std-beta-thumbv7em-none-eabi.tar.xz=a9f7eadfa375061835f139bbb870a5692b727de8a85fb8177d8fabd0588e28cd
-dist/2025-08-05/rust-std-beta-thumbv7em-none-eabihf.tar.gz=f996d8b1aae894af11407ac90c277e161acd58378307548ffaa2fa0a4314f3d7
-dist/2025-08-05/rust-std-beta-thumbv7em-none-eabihf.tar.xz=48b9e7d257ad1fac0b23b3a7d6b3ae8afb5dd19db7b5dd2a59ddfe51364db72f
-dist/2025-08-05/rust-std-beta-thumbv7m-none-eabi.tar.gz=1061c6b8794aa4e1f66ff17d91934bb9711c6064362cca7bca1d7cdd4f9189cb
-dist/2025-08-05/rust-std-beta-thumbv7m-none-eabi.tar.xz=974b1078724ac06757d7899fde62f623e61c86ac0853cdbf02a252b13383e55a
-dist/2025-08-05/rust-std-beta-thumbv7neon-linux-androideabi.tar.gz=a4fd4047a744bea871a54af311f27a08b5f7c8f04e5e62f7abf292689378ab4f
-dist/2025-08-05/rust-std-beta-thumbv7neon-linux-androideabi.tar.xz=19c31d2a0982689228eb58522ac7610d33cfcc1b5f72ee2e41e218695a49d09d
-dist/2025-08-05/rust-std-beta-thumbv7neon-unknown-linux-gnueabihf.tar.gz=8b5e150d6950866734b025e58b3714c4acfe631785fc464e6fe3cbedd98709d0
-dist/2025-08-05/rust-std-beta-thumbv7neon-unknown-linux-gnueabihf.tar.xz=23ca585e084fb548488e17adaea92e16ac98340fe146073046d1bfbe6faa325f
-dist/2025-08-05/rust-std-beta-thumbv8m.base-none-eabi.tar.gz=d31bcb162cd2ee40a69acb2c201c07c233b8c2710bc07ad322263121f0d422db
-dist/2025-08-05/rust-std-beta-thumbv8m.base-none-eabi.tar.xz=67354653ab11222806f4a688c11be6dc80468785e14a8b58f2285a695c53c5a2
-dist/2025-08-05/rust-std-beta-thumbv8m.main-none-eabi.tar.gz=ad61d8510d82ca1094a893879d7148446e2880dd1d172b9e8a420772b0b4611b
-dist/2025-08-05/rust-std-beta-thumbv8m.main-none-eabi.tar.xz=5c1ddf66949a40265effbc76ac3da59efb1bb3349dbe2a8037b8215375647fdb
-dist/2025-08-05/rust-std-beta-thumbv8m.main-none-eabihf.tar.gz=4895c9a6659e831cdacd314ff2ca4c968fd368c6bf9308f334468cb07892ae56
-dist/2025-08-05/rust-std-beta-thumbv8m.main-none-eabihf.tar.xz=f64a05715457288b36dd16fcbbdd91816829b889047c277841f3f4972bcc6076
-dist/2025-08-05/rust-std-beta-wasm32-unknown-emscripten.tar.gz=3b144570ddc44868a6609f921028b23f994de337c54a96fccaf976abe4e2ceff
-dist/2025-08-05/rust-std-beta-wasm32-unknown-emscripten.tar.xz=355a1bc09dd4163a416cb78e55ec998e95b8acbb9b072dbd3a8e34f5e95d3378
-dist/2025-08-05/rust-std-beta-wasm32-unknown-unknown.tar.gz=52213b11d29f02d4531495c9d35ee7022ef6b8400a8386b8728156b33d2a9eed
-dist/2025-08-05/rust-std-beta-wasm32-unknown-unknown.tar.xz=1f282c355a1499fc2a212705700fbb8de7e568dbdc5d43d3c895af86fe9f735b
-dist/2025-08-05/rust-std-beta-wasm32-wasip1.tar.gz=f40da6445acb1e854625a02b1078f670874e75d763168430d0ca17ef3b9bae26
-dist/2025-08-05/rust-std-beta-wasm32-wasip1.tar.xz=a0e59495bacc1bceaeec940273fcc6d1505c283de9e2a60ee7d492f2a7efec3d
-dist/2025-08-05/rust-std-beta-wasm32-wasip1-threads.tar.gz=4b4eb08ab33ff2a300828c65a9636f32428dfec784bf115aa53856b5336d61d5
-dist/2025-08-05/rust-std-beta-wasm32-wasip1-threads.tar.xz=54ae55557d66f922112a42aa2c296841f5919907ccd81354f0dbe1b0517867f8
-dist/2025-08-05/rust-std-beta-wasm32-wasip2.tar.gz=b625337e6180ec57abbed063de5bf384949254c46a5fbbb12804a3dbd0d1c3a6
-dist/2025-08-05/rust-std-beta-wasm32-wasip2.tar.xz=5a098a042f5586e7e1b7444bf64edf3dcc535d75226fa44be420c0d42b90c25c
-dist/2025-08-05/rust-std-beta-wasm32v1-none.tar.gz=b11ed27b745437b39ea9699f7fd5413bdb25019720569b9940f1cbac4849344c
-dist/2025-08-05/rust-std-beta-wasm32v1-none.tar.xz=3dd3f07214429f36a088a89c3de7404659d1b584895ff5b7938845fd4a669f27
-dist/2025-08-05/rust-std-beta-x86_64-apple-darwin.tar.gz=14522f13786b81727646acfcb18c81b3f78b24bf522ebaf65adba416971d9939
-dist/2025-08-05/rust-std-beta-x86_64-apple-darwin.tar.xz=b78a1df21a97c25d9977a69bf778190fbf34947c6837f895aeeb53c870083438
-dist/2025-08-05/rust-std-beta-x86_64-apple-ios.tar.gz=a5d57bef3b09c4a4e6789d756cbec9e9459261ab70c94a406d4519eb2da992ec
-dist/2025-08-05/rust-std-beta-x86_64-apple-ios.tar.xz=1b461aaf03e808d26bcae49417f04b71ad1432f266f0b25b3d6b26a67b7f8953
-dist/2025-08-05/rust-std-beta-x86_64-apple-ios-macabi.tar.gz=6c7a3326abd3fb7c878af095699164237f97ce5827bd428d8aad5c9818b2098c
-dist/2025-08-05/rust-std-beta-x86_64-apple-ios-macabi.tar.xz=427684c9613ce04737837a594987bb1eb81d1d3f5ea2a1b19c2b76b3be32ab62
-dist/2025-08-05/rust-std-beta-x86_64-fortanix-unknown-sgx.tar.gz=2e10607e6eb7fb3168fe593f1d260b52ac578d590cc6788555346cf9bac9f586
-dist/2025-08-05/rust-std-beta-x86_64-fortanix-unknown-sgx.tar.xz=256331077a036bfed1650177cd1a886aeb4ce9aa9ce2a35f5450767f5e06aee6
-dist/2025-08-05/rust-std-beta-x86_64-linux-android.tar.gz=b5943cc4d10bf039d9b52e56713a99e8edb21d9de3655450d16c557c9013f47e
-dist/2025-08-05/rust-std-beta-x86_64-linux-android.tar.xz=ceeb89fa082b98c8d50c043cfd2e4bb8ac1d98943859a75d74a555ffda8d0a5d
-dist/2025-08-05/rust-std-beta-x86_64-pc-solaris.tar.gz=98d9d51da4b74a2a1899be7f0dd8d3c0f980fb4ce96fddd1c2dedb76e174984b
-dist/2025-08-05/rust-std-beta-x86_64-pc-solaris.tar.xz=0fed1f0452475bf10d3ec0bfef12e9fe05bb117910d871f4099bdd4ca947d74b
-dist/2025-08-05/rust-std-beta-x86_64-pc-windows-gnu.tar.gz=f458eab66adc91aba026a434cab47bbbd98a9d5e7d0f5a1a1979e0e6a89c8e7e
-dist/2025-08-05/rust-std-beta-x86_64-pc-windows-gnu.tar.xz=bfdc3bb5b66a525281236b01513f49d96d644e4cd62ce89eb59a8179fe4707b0
-dist/2025-08-05/rust-std-beta-x86_64-pc-windows-gnullvm.tar.gz=b543f21106bc3a72d31a5c49118553187cbb0d2e630ea943aa97d3ae5bb4c40f
-dist/2025-08-05/rust-std-beta-x86_64-pc-windows-gnullvm.tar.xz=9056c113ee03defb6cd33acbed9829712b57ef3606623169d28416be4110a31a
-dist/2025-08-05/rust-std-beta-x86_64-pc-windows-msvc.tar.gz=c66ff2e88c79f3fe574f9ef7822d5d2e6f73efe3ebe67c6bd35096622b668d1c
-dist/2025-08-05/rust-std-beta-x86_64-pc-windows-msvc.tar.xz=45765252e930a96badbf06eb04ec092bb989c0ce2067aaab52b7ddc72ea511b8
-dist/2025-08-05/rust-std-beta-x86_64-unknown-freebsd.tar.gz=9b3d68e86e0ce6a484bf615313f98bd289db73899a55cecfa5b7955b4b0878f4
-dist/2025-08-05/rust-std-beta-x86_64-unknown-freebsd.tar.xz=bd48292b8582167a5e89ebe521c9754495403968c184b925df8b2ec1da344fc3
-dist/2025-08-05/rust-std-beta-x86_64-unknown-fuchsia.tar.gz=b4c6c046299391beb2f50eff198f4c9b6571b6c1748dd621bdd154694fffce3a
-dist/2025-08-05/rust-std-beta-x86_64-unknown-fuchsia.tar.xz=a30857c8f066191b64d7b52378fae8790814a251ca452c80710bd9a49c5c0c85
-dist/2025-08-05/rust-std-beta-x86_64-unknown-illumos.tar.gz=1ee4b264021b510342c2ed96da0dacf5cf1704874de3bf9380642433defb3e0a
-dist/2025-08-05/rust-std-beta-x86_64-unknown-illumos.tar.xz=ca431d4426cfba2efd408b8822f9aeb0961d81373c6154a0b7eeb957abebc33b
-dist/2025-08-05/rust-std-beta-x86_64-unknown-linux-gnu.tar.gz=ebba9fa476d5b0a42054a6b6ca51526efd7c2cf5ac34eb8af119bfa69f3f0a5c
-dist/2025-08-05/rust-std-beta-x86_64-unknown-linux-gnu.tar.xz=d4498920cce484a8b3a5cdf8ee856d80cf1379f9782169340dfff2597b530598
-dist/2025-08-05/rust-std-beta-x86_64-unknown-linux-gnux32.tar.gz=20c37745f3ee13c2c81dfc77a80919cc0448180f6be0be56d7fb5239e5651294
-dist/2025-08-05/rust-std-beta-x86_64-unknown-linux-gnux32.tar.xz=dd319a6c381b372ba230d86bd07a089cd2431656c7c765f029e8e10d60bbd778
-dist/2025-08-05/rust-std-beta-x86_64-unknown-linux-musl.tar.gz=d0c20b13113eb62c9a78a796418386d0352f4221095de272018af6d5ec6bd9f1
-dist/2025-08-05/rust-std-beta-x86_64-unknown-linux-musl.tar.xz=d0e1001e8e5af571f0fd53115ec873091a33e4943dd27a16ccd74dcd8c71abce
-dist/2025-08-05/rust-std-beta-x86_64-unknown-linux-ohos.tar.gz=4be537d5fb6c0d867a131539ef4b0872f9f6d175ba0517fed50b1d463c615157
-dist/2025-08-05/rust-std-beta-x86_64-unknown-linux-ohos.tar.xz=ca034c852a4c9099a062f55c5e479bd700f2ffd89a3b2c2c7354df54e41057a8
-dist/2025-08-05/rust-std-beta-x86_64-unknown-netbsd.tar.gz=11b5a73da1f560c218cecf9a71d6b2173df1fbe276e63e20e1e85f2dc48579bf
-dist/2025-08-05/rust-std-beta-x86_64-unknown-netbsd.tar.xz=2de6a8850076e9c1edd8aa3e13902ebbc599da9637f88da347858007f8e5c212
-dist/2025-08-05/rust-std-beta-x86_64-unknown-none.tar.gz=dacb8aa48387ad15380a094104bbcfabdcdd5f88e189d9203fd3e3f466b92fa3
-dist/2025-08-05/rust-std-beta-x86_64-unknown-none.tar.xz=ce2eb95efe252de2ecbe619b3805b01ec84863a9b30330dc4ad5683d67d7c9d8
-dist/2025-08-05/rust-std-beta-x86_64-unknown-redox.tar.gz=bf28f90b1b24eabd80da75262bd260ee811ef30a1ba94bdeb7a005f132ceeead
-dist/2025-08-05/rust-std-beta-x86_64-unknown-redox.tar.xz=99aa3603b7fdc84893a02e66a774e147439a1cfd77ba63818c58b11ae692058d
-dist/2025-08-05/rust-std-beta-x86_64-unknown-uefi.tar.gz=75c57e4a9367a6fbee02f8857da2dd4bce8bd20c8946a3c2460a77cb95af0972
-dist/2025-08-05/rust-std-beta-x86_64-unknown-uefi.tar.xz=552c14c20d1f786c8350882a32618951de0a06e0636fa3b8d69f2ffab7e7561d
-dist/2025-08-05/cargo-beta-aarch64-apple-darwin.tar.gz=4723292f91e645d3f86474ed55e52eae4f35af7458602d3da9d38b0a513cfeef
-dist/2025-08-05/cargo-beta-aarch64-apple-darwin.tar.xz=d0150ce874376c41950966b0385f011ebbbd5ef4955deec7829d8ccb669e9e86
-dist/2025-08-05/cargo-beta-aarch64-pc-windows-gnullvm.tar.gz=fb0a8a8dff4d42f9491ed9a0223a9541bbaf8691c831b5536220494c479b21e3
-dist/2025-08-05/cargo-beta-aarch64-pc-windows-gnullvm.tar.xz=6bd35ea43ab877d84bff4b32b965371b942b10c6f6feabb3a5b481a4c84513fc
-dist/2025-08-05/cargo-beta-aarch64-pc-windows-msvc.tar.gz=3437221155f338e81f55dea9d715b3958fe7d3a260d77d14725e62d0780bfc76
-dist/2025-08-05/cargo-beta-aarch64-pc-windows-msvc.tar.xz=94886636f7bf805809a8a1ac99b514036c5db1755ccfed61cb6cd01d57d244a3
-dist/2025-08-05/cargo-beta-aarch64-unknown-linux-gnu.tar.gz=7f167793fc72f5fdb6bbed97e96684cfa089f9932d3a64239bc755fe7603e7a3
-dist/2025-08-05/cargo-beta-aarch64-unknown-linux-gnu.tar.xz=1018ea99c4142db9fbf386547dee8396dc27d3d3608085a1b0b0e97e2d0172c7
-dist/2025-08-05/cargo-beta-aarch64-unknown-linux-musl.tar.gz=8e03af7a838e81c12c395ed76151aa6ead12b3e60effa3b0d775508118149058
-dist/2025-08-05/cargo-beta-aarch64-unknown-linux-musl.tar.xz=507de5fbe92e144dd37dc34123ee58b9e46805c85eccd4a759a117020578d742
-dist/2025-08-05/cargo-beta-arm-unknown-linux-gnueabi.tar.gz=263ad4a9ed084dd76b6ea62d377fa470043f78e0343f7fb80d5c9b50659d8977
-dist/2025-08-05/cargo-beta-arm-unknown-linux-gnueabi.tar.xz=ed850f484ee870172b721ab6824f0a15b41dd80ffc623557aa58a5b839d992c5
-dist/2025-08-05/cargo-beta-arm-unknown-linux-gnueabihf.tar.gz=afb4cdac4a3c28fe08fbba8b98962eec6c625f6a10a52ee8cc988881852b79dd
-dist/2025-08-05/cargo-beta-arm-unknown-linux-gnueabihf.tar.xz=7f332d11e74d76efe236a7858021a626d31fb856d9ad0745369b99d9fdfe3b44
-dist/2025-08-05/cargo-beta-armv7-unknown-linux-gnueabihf.tar.gz=5c0c79bbf734c0ce18001cf27605f6728d83d24bc97ea5c78b423fb9faf46d96
-dist/2025-08-05/cargo-beta-armv7-unknown-linux-gnueabihf.tar.xz=3aff39ef7b9e8adc2e6bca19c2940287c4e091ad7ce4503c46334e6969ce0c95
-dist/2025-08-05/cargo-beta-i686-pc-windows-gnu.tar.gz=af99a5778ab4c9cea122897bcd3ea1626893156fb71346d66a584553d6531469
-dist/2025-08-05/cargo-beta-i686-pc-windows-gnu.tar.xz=8425eda844728c0353b4c7edc4636141dad265e461addf009cfa1a224df0e7cd
-dist/2025-08-05/cargo-beta-i686-pc-windows-msvc.tar.gz=46d1b318b6cf826d8e7e694e54ce5b9c651dc2f8facf32ddebe21fc32e1e8dc4
-dist/2025-08-05/cargo-beta-i686-pc-windows-msvc.tar.xz=bef58a9f31aa3434152f79b2e271958fb07e925c938a569d1c9431f7764d19f1
-dist/2025-08-05/cargo-beta-i686-unknown-linux-gnu.tar.gz=c432ae4d909a21336a6645b85a90ec541818424bb76da16b19979a61a11845b2
-dist/2025-08-05/cargo-beta-i686-unknown-linux-gnu.tar.xz=053c02b341219d583caba881e525eae2cbb125ecc188e1b43d641fd7f3f027f2
-dist/2025-08-05/cargo-beta-loongarch64-unknown-linux-gnu.tar.gz=40542d76adaebdbc3fb16047a8324d439abba0485d227253614beddcc3cee2dd
-dist/2025-08-05/cargo-beta-loongarch64-unknown-linux-gnu.tar.xz=d25210467dabf91917eefad9a5a415a3912a31b37ce1fd3d755b6c72b3a6ce8a
-dist/2025-08-05/cargo-beta-loongarch64-unknown-linux-musl.tar.gz=09755de73380c39daf64208df9708613ed6f8790e2f5cf79e80cb7826fd74f28
-dist/2025-08-05/cargo-beta-loongarch64-unknown-linux-musl.tar.xz=e8eab1aa5b41c04b518d43a86849307cbfec76df13c834a460c546ab6b170089
-dist/2025-08-05/cargo-beta-powerpc-unknown-linux-gnu.tar.gz=93398391d308bd0c08fa2a7bab7bb6a38b78400280cbe765604a3da9d6caeb47
-dist/2025-08-05/cargo-beta-powerpc-unknown-linux-gnu.tar.xz=ed37a7c5a8c62db06e709779b81d1e013975feeb82c185c76bb3d218aa142cc4
-dist/2025-08-05/cargo-beta-powerpc64-unknown-linux-gnu.tar.gz=a398b3ff0967b1ec2fdc2716a6b2c3a04defc14ebed577d93e45040aa5552dc8
-dist/2025-08-05/cargo-beta-powerpc64-unknown-linux-gnu.tar.xz=51d6a1a3e71713157a4e6291023b8393e21334a952a947f82f9636a725989281
-dist/2025-08-05/cargo-beta-powerpc64le-unknown-linux-gnu.tar.gz=cef935747fe5205c3c5944f4dcf80e3111d2859616e7d727b8a5c77abe2d9fef
-dist/2025-08-05/cargo-beta-powerpc64le-unknown-linux-gnu.tar.xz=fcb8aee743adcc3796b564570e0ad6d9950031160ba9a6cafbd92af2f0a0c213
-dist/2025-08-05/cargo-beta-powerpc64le-unknown-linux-musl.tar.gz=73b2c9676122e842a73a8a9890f1e1aac426f75449a99b4fc0ae3f5dd5ce238e
-dist/2025-08-05/cargo-beta-powerpc64le-unknown-linux-musl.tar.xz=ba293bb860349ee4732c5363d38b5e386544a25f65ef8ee33850061bc84bfe64
-dist/2025-08-05/cargo-beta-riscv64gc-unknown-linux-gnu.tar.gz=bff3ac251a42b1664a544706185826a4d9137cde990620dc73951252d2d7fb41
-dist/2025-08-05/cargo-beta-riscv64gc-unknown-linux-gnu.tar.xz=61056d4405af01b4b1c3134af8e83ed86473d0846beb41d3ab72df92edf316a6
-dist/2025-08-05/cargo-beta-s390x-unknown-linux-gnu.tar.gz=f89a30322a3621c4737f932788f4ca78c83b9f2845e324c4944522f35d44baf1
-dist/2025-08-05/cargo-beta-s390x-unknown-linux-gnu.tar.xz=394d522c9553182cf5f496e2b5324499c1845c0a0621fa527aaa925946b58d21
-dist/2025-08-05/cargo-beta-sparcv9-sun-solaris.tar.gz=0b18adbb22b34448576e6a3ba637c7565d369e1c994474337bed48b3cd0b0231
-dist/2025-08-05/cargo-beta-sparcv9-sun-solaris.tar.xz=c57709b87524d29661f77df3e3585bae4776fb3fb6de3874edb942f724543a89
-dist/2025-08-05/cargo-beta-x86_64-apple-darwin.tar.gz=c8faf66575d43fcbc03376225ac22d571def08ed1fc239d468c15929d9ecd393
-dist/2025-08-05/cargo-beta-x86_64-apple-darwin.tar.xz=538d81c3fe2b5a9edfc1e99655120d37fa159dcf761e1ddbe5233115e39b38b1
-dist/2025-08-05/cargo-beta-x86_64-pc-solaris.tar.gz=a2fb63b0a2cc3d3ea9523c8ffe61ba9ccb367dff136e6fc39aeea6400034363c
-dist/2025-08-05/cargo-beta-x86_64-pc-solaris.tar.xz=02e8990865ef8f14a31e4d0f17be4cc0cbecda7e82e062b4b9cfdb99dd45156d
-dist/2025-08-05/cargo-beta-x86_64-pc-windows-gnu.tar.gz=ba86f300cd40cb3cb23ac41970246ce54c03ee153f86127a379fecda930c020b
-dist/2025-08-05/cargo-beta-x86_64-pc-windows-gnu.tar.xz=3bc0bf2da392ac52bcf2aa1dc19bea1a86bd7a4fe246feaae862a792c82ec476
-dist/2025-08-05/cargo-beta-x86_64-pc-windows-gnullvm.tar.gz=68a2a34e656395fabd42d20b7008d96b2a86e9a47caa52e6e2613ccb3b1b2d8f
-dist/2025-08-05/cargo-beta-x86_64-pc-windows-gnullvm.tar.xz=1e2e31fe2306e26bfe58c49a99cc89664e8a7857c2c18ad74c20cdb35bd3c586
-dist/2025-08-05/cargo-beta-x86_64-pc-windows-msvc.tar.gz=5fa21f665aa40fab1896bd4a49dc5608b4b453d26f4b975771908634c699ab8e
-dist/2025-08-05/cargo-beta-x86_64-pc-windows-msvc.tar.xz=adc5900506d399246960445c1e2d59f0c4b2a5cfeff9972f1617de030ce82bfa
-dist/2025-08-05/cargo-beta-x86_64-unknown-freebsd.tar.gz=a2bbb1d5fa283e77ddbbc0c8d69e36b9c2bbb01912f302f522af48c2187327b3
-dist/2025-08-05/cargo-beta-x86_64-unknown-freebsd.tar.xz=11e1a51740a728f5825364a8679b28454a68e7efc96320730f9b58a8fc2e6fae
-dist/2025-08-05/cargo-beta-x86_64-unknown-illumos.tar.gz=9993f4130b5ce50898e530e7411efe6923a36b5d56459ab672b1395717fe69bb
-dist/2025-08-05/cargo-beta-x86_64-unknown-illumos.tar.xz=0a41315ced9f4fdce9c1877a4c27e5cca6e494f5dc8c2560334a5b75d42f495e
-dist/2025-08-05/cargo-beta-x86_64-unknown-linux-gnu.tar.gz=6b8f74b1c850093acb7227306caaed4581d70d015ebb0bb5f924af1c8bee7bd1
-dist/2025-08-05/cargo-beta-x86_64-unknown-linux-gnu.tar.xz=f6f7bb4e4f1156329946d83bad5893e508645dd76b9ce522a53ea673791da006
-dist/2025-08-05/cargo-beta-x86_64-unknown-linux-musl.tar.gz=68c829663d6166661563704e25a6e85a973705e12efc9265a23264b9ffbff4d7
-dist/2025-08-05/cargo-beta-x86_64-unknown-linux-musl.tar.xz=2c40e68c9978e58250f0e017b5cdb2fc390f26ef96324129c489f55898784488
-dist/2025-08-05/cargo-beta-x86_64-unknown-netbsd.tar.gz=65166585138bc6f09f54f88ee889aea6d4e63019d64a684798341d6b332ce99d
-dist/2025-08-05/cargo-beta-x86_64-unknown-netbsd.tar.xz=97491edef98b3a13b0571907555bf5867be13ec8fd4af69142db92a8deaf8586
-dist/2025-08-05/clippy-beta-aarch64-apple-darwin.tar.gz=b933611d47ccbcf5aad43f1134cc72ac708fdf59bace0dab75cfe139e2357373
-dist/2025-08-05/clippy-beta-aarch64-apple-darwin.tar.xz=c3d473e366db3b271cbe438b3a5531e9c5a72e28248d94de0f81ee93a8a2e7cd
-dist/2025-08-05/clippy-beta-aarch64-pc-windows-gnullvm.tar.gz=e5b4fc054121eb13b21171b2e851dc1c824e11aad1257dc92b4ca9e332898b40
-dist/2025-08-05/clippy-beta-aarch64-pc-windows-gnullvm.tar.xz=40bddcdd9186cfb9f8763e8e289087c15c2c8b8ab78f41ba7380cdb08fedb0da
-dist/2025-08-05/clippy-beta-aarch64-pc-windows-msvc.tar.gz=7e7c47305708ae073ed8d86e621a3c0be0e135b2480508814665f24121588a56
-dist/2025-08-05/clippy-beta-aarch64-pc-windows-msvc.tar.xz=c4a5bfe2d48a2301adb4f7524cccd64f4a3ccecf985f131972a13bd221346454
-dist/2025-08-05/clippy-beta-aarch64-unknown-linux-gnu.tar.gz=dd26d49359f6010e94e04198067f83c83e81618546d1cf51606d157a02b4938f
-dist/2025-08-05/clippy-beta-aarch64-unknown-linux-gnu.tar.xz=e7c9834067311a87f547450108718582991498a102dfcba0e1a99671205e9bc2
-dist/2025-08-05/clippy-beta-aarch64-unknown-linux-musl.tar.gz=b584c26e267b0f7e105f65c436c12cfd6d9b8f2b92f9662a4797fa5e95455e11
-dist/2025-08-05/clippy-beta-aarch64-unknown-linux-musl.tar.xz=6b0eaadfea879cfc8c758fce002ffe77e34484e167c496ac0659dcc789dfc080
-dist/2025-08-05/clippy-beta-arm-unknown-linux-gnueabi.tar.gz=eebd0632971888cb3bcc3b07a06f25a47af594ce5606e8e1e069fe85ec702e5c
-dist/2025-08-05/clippy-beta-arm-unknown-linux-gnueabi.tar.xz=946d6791e4e15ffca6195bd7c9bd2d160b9c65468fddc800948f41adc8fec597
-dist/2025-08-05/clippy-beta-arm-unknown-linux-gnueabihf.tar.gz=3862815aa14e8122b70b39c1137088e0c2a724900d2d13ac2b37a1a430b23a1f
-dist/2025-08-05/clippy-beta-arm-unknown-linux-gnueabihf.tar.xz=8278e11b7ea2bc035e6de21f826a775d66273a9031195d8b887752137424f2e0
-dist/2025-08-05/clippy-beta-armv7-unknown-linux-gnueabihf.tar.gz=83a847698eeafcbd3288d59013157d3d2a11b90b521ebadf1b26dac90877d11f
-dist/2025-08-05/clippy-beta-armv7-unknown-linux-gnueabihf.tar.xz=308de9cedc422c2051661df74024ab26c59b86368fbf50ce4dd7b2b2907ccc8f
-dist/2025-08-05/clippy-beta-i686-pc-windows-gnu.tar.gz=95fe71a1f8e68f0f3a5306dfa04e269c636ad036908e201c1b4ed7a3f99b1dc7
-dist/2025-08-05/clippy-beta-i686-pc-windows-gnu.tar.xz=5b8c928be909433fb005498a92d2fb3ff535f31c68a5e134523f9731cacb029a
-dist/2025-08-05/clippy-beta-i686-pc-windows-msvc.tar.gz=d736ec4f447f6b204f250b044b406b4e4b96f014887b6f7755b037e211aad3af
-dist/2025-08-05/clippy-beta-i686-pc-windows-msvc.tar.xz=8a4ac568284aabb994964323465c7287715d3dd4ab881271a4746d2ae5390ffc
-dist/2025-08-05/clippy-beta-i686-unknown-linux-gnu.tar.gz=d8b87338abdb4123eb25dd778d038c516c5bd472e1426b5a5f74f25126957039
-dist/2025-08-05/clippy-beta-i686-unknown-linux-gnu.tar.xz=ebb6dcc1b038deff6a966062ca3a966d3426f8932e5aeba398636a2d2e9be0c0
-dist/2025-08-05/clippy-beta-loongarch64-unknown-linux-gnu.tar.gz=51bf4e84be5b677ad9afba442d9567b96f59209219cddad5eb3f49b788bd8fe2
-dist/2025-08-05/clippy-beta-loongarch64-unknown-linux-gnu.tar.xz=e63e3346089c7f300bdc73521def20cd2a012f8de98b8b05a653e85f3516371c
-dist/2025-08-05/clippy-beta-loongarch64-unknown-linux-musl.tar.gz=aeb3782ca34a0ac47420109c241041ebbc029050a690a5c828c865108f56ca18
-dist/2025-08-05/clippy-beta-loongarch64-unknown-linux-musl.tar.xz=80dabbd511bd5bdfc944d7613a02c9bdac702abf2de916222a37e59a92c2e577
-dist/2025-08-05/clippy-beta-powerpc-unknown-linux-gnu.tar.gz=9307396973615663330474ec145efebd4246c6bae5d979a80b6d93f832af0137
-dist/2025-08-05/clippy-beta-powerpc-unknown-linux-gnu.tar.xz=fb2a34f9472d2c1beb1381e9ff8bca23d9058c978fdb2e52a3c7f0cba8305c59
-dist/2025-08-05/clippy-beta-powerpc64-unknown-linux-gnu.tar.gz=e985eebd182d78604861ce60aba5078e98a9a078b76752da8fabcfc5fa471fc3
-dist/2025-08-05/clippy-beta-powerpc64-unknown-linux-gnu.tar.xz=1092ddf60ba04418f91c1e51f9c9da1e0d6b61dbdb104fc8028043dc1a33caec
-dist/2025-08-05/clippy-beta-powerpc64le-unknown-linux-gnu.tar.gz=bf0238a4909fa15034f067d5a51e38e43c91e69f29f51c39246d5c0b23925042
-dist/2025-08-05/clippy-beta-powerpc64le-unknown-linux-gnu.tar.xz=39caa6aedcd746ed1c4745e207cf8cd65de7b774f15e8892987ce2c3fdde543e
-dist/2025-08-05/clippy-beta-powerpc64le-unknown-linux-musl.tar.gz=b19ef1a8cdc21925887ced0c594ff5ab658bf66a0d137c01b6375fcdd0de8e35
-dist/2025-08-05/clippy-beta-powerpc64le-unknown-linux-musl.tar.xz=0ec300c1e791f946503db692e602680acf11857715b9ecc87cb446ac10d2527c
-dist/2025-08-05/clippy-beta-riscv64gc-unknown-linux-gnu.tar.gz=e7c8fe214ffd70599648cfacb50b3457597b479d320bf8383869dda8b0559d42
-dist/2025-08-05/clippy-beta-riscv64gc-unknown-linux-gnu.tar.xz=d8ba0c42074c2a94dff3b05f2388f17225044485abd0459e155928f4762c8988
-dist/2025-08-05/clippy-beta-s390x-unknown-linux-gnu.tar.gz=510b9c9ca885a8e91c3d25f14cbfb34a7a927d374fa1a9149678d7ed9c4e4c2c
-dist/2025-08-05/clippy-beta-s390x-unknown-linux-gnu.tar.xz=b53697799d99beb46fc17b3cca8ccfdc4ecbf7f3e1fd47f031852f07fb749ea0
-dist/2025-08-05/clippy-beta-sparcv9-sun-solaris.tar.gz=f3109a1dd87c23256057fcc94d3fade0b49d20a51040b4fbdda366f5b7c9b58e
-dist/2025-08-05/clippy-beta-sparcv9-sun-solaris.tar.xz=ba265d781254d0b032d836a440c94c31ca33bc136e027ad05332cfc0cf40bf54
-dist/2025-08-05/clippy-beta-x86_64-apple-darwin.tar.gz=74c49a7cd4b6605b9a43961415fcaed1197b8f5aca798efd4b62a15d837b956b
-dist/2025-08-05/clippy-beta-x86_64-apple-darwin.tar.xz=69128daabb11fd29720752bb13d83ef4bb3faa1d4aea8d525da2cb04f42b6010
-dist/2025-08-05/clippy-beta-x86_64-pc-solaris.tar.gz=e1975507778e448ac9b3040f330340f3a7d54e6dd40357494e3d891008375364
-dist/2025-08-05/clippy-beta-x86_64-pc-solaris.tar.xz=43c142c870116f4c2408f4b3208680b81390a4b37805f5a32696ad17bb313b48
-dist/2025-08-05/clippy-beta-x86_64-pc-windows-gnu.tar.gz=ccd8806b6614edb270a2816cf0dc3b6376046fe58d258d296ffb222929d42d91
-dist/2025-08-05/clippy-beta-x86_64-pc-windows-gnu.tar.xz=21148cd754493da3cdf72adc8da19ebfca1da8d642e1bef51782772241b48084
-dist/2025-08-05/clippy-beta-x86_64-pc-windows-gnullvm.tar.gz=5a7cecb6c054a71ec5b1fb284f6bf2c069925fffcc1757ac631e8a2d08b116b0
-dist/2025-08-05/clippy-beta-x86_64-pc-windows-gnullvm.tar.xz=b451057a4a75341924072fe26334eefce8b6eaa3edd79d3226eb02c1c99fcdb3
-dist/2025-08-05/clippy-beta-x86_64-pc-windows-msvc.tar.gz=74e9cea693203c6217934549694a240460dda2818b144bac5777f41c44a06d53
-dist/2025-08-05/clippy-beta-x86_64-pc-windows-msvc.tar.xz=bd90fc3fc80f28ce415dc1cfd105d17ec5ecfc63fae017baeec734bf94f5d71b
-dist/2025-08-05/clippy-beta-x86_64-unknown-freebsd.tar.gz=fb61d60d6c66a4632911944b5c7858b8c055ab8ae5a194d78e7d7ba18b65e940
-dist/2025-08-05/clippy-beta-x86_64-unknown-freebsd.tar.xz=bbc7b2aa6f05ecf391a757ffc5b6fa6e0989d00f7e8fa48b83faca8996f99dd1
-dist/2025-08-05/clippy-beta-x86_64-unknown-illumos.tar.gz=10e8be6eb15269cb2d0573e19e3a5004dbbd2b14e2f016d6b9c60713e22f716b
-dist/2025-08-05/clippy-beta-x86_64-unknown-illumos.tar.xz=c3748db93829d3f5d9c5498592d247468125ca301ef238c41e42d37b7b90c6a4
-dist/2025-08-05/clippy-beta-x86_64-unknown-linux-gnu.tar.gz=5a0365eda14ac1a366f3c480a2358eccbfcbfce86323711d7fcfdcfd85652b42
-dist/2025-08-05/clippy-beta-x86_64-unknown-linux-gnu.tar.xz=908576635e79fe589583f18bd6ace4c488cd11ed0c59501082bb0b397df24f39
-dist/2025-08-05/clippy-beta-x86_64-unknown-linux-musl.tar.gz=79fd42cffac98024308c511144b716d18693b902dbdc1c4b88645bc7d4ae7109
-dist/2025-08-05/clippy-beta-x86_64-unknown-linux-musl.tar.xz=a3a616554ed25630df9f8cef37a5d36573e6f722b1f6b4220ff4885e2d3a60de
-dist/2025-08-05/clippy-beta-x86_64-unknown-netbsd.tar.gz=ad1849cb72ccfd52ba17a34d90f65226726e5044f7ffbe975c74f23643d87d98
-dist/2025-08-05/clippy-beta-x86_64-unknown-netbsd.tar.xz=608001728598164e234f176d0c6cfe7317dde27fb4cbb8ad1c2452289e83bf30
-dist/2025-09-05/rustfmt-nightly-aarch64-apple-darwin.tar.gz=6fd7eece7221e76c2596e0472e7311fdced87e9fab26d2a4673a3242fe779bd3
-dist/2025-09-05/rustfmt-nightly-aarch64-apple-darwin.tar.xz=1a662a55931f58be9ac05841360305f277f8b1e36f99bd0a2ee4d2cc92b7ad14
-dist/2025-09-05/rustfmt-nightly-aarch64-pc-windows-gnullvm.tar.gz=d1c3c52cf61522697d726b32ed28d7b8b4cfadf30ec57f242e8c7f9f8e09f692
-dist/2025-09-05/rustfmt-nightly-aarch64-pc-windows-gnullvm.tar.xz=2cc7cbbfa06803a2fe422ed3266f6eb519360b403c83f92259cc1b83f5ddca45
-dist/2025-09-05/rustfmt-nightly-aarch64-pc-windows-msvc.tar.gz=61f525d050d1ff4a29cc7240912d84c9c091f25195b58411af9ef176175a3200
-dist/2025-09-05/rustfmt-nightly-aarch64-pc-windows-msvc.tar.xz=504b8ace2ab7ac13be143d95ed74d94940e8706ef9f53b7778da215840337e20
-dist/2025-09-05/rustfmt-nightly-aarch64-unknown-linux-gnu.tar.gz=ff48bd98d109310638822f5813042583900e2b70edd45fccd871c7c03dd1c2e6
-dist/2025-09-05/rustfmt-nightly-aarch64-unknown-linux-gnu.tar.xz=b3de2bba7858e76cdafd326f3072e4c5b534ca9b679ea62caeffb07722e9a3c9
-dist/2025-09-05/rustfmt-nightly-aarch64-unknown-linux-musl.tar.gz=8ca4caedc50f09995dad7bc6e001cc863c524e28c45c186022ded589f3728709
-dist/2025-09-05/rustfmt-nightly-aarch64-unknown-linux-musl.tar.xz=8f2cfb052f9697052d89bb729d17d74583af3fa0be98f18a3c44ea518a8f4855
-dist/2025-09-05/rustfmt-nightly-arm-unknown-linux-gnueabi.tar.gz=b12ac2a38b379bf0de4a92f29ca40e1955c45273e798edd1a72bd40253de70f1
-dist/2025-09-05/rustfmt-nightly-arm-unknown-linux-gnueabi.tar.xz=87fb7185aa46f3810e09479dc8fafb66d13b41f4f40e9c4e866ea77fa47b1bb6
-dist/2025-09-05/rustfmt-nightly-arm-unknown-linux-gnueabihf.tar.gz=be1e8377f3d10f4f8a07ae06ab9f649f9d2fc9cfc395abaa5f0ad10a95c4fe7a
-dist/2025-09-05/rustfmt-nightly-arm-unknown-linux-gnueabihf.tar.xz=60646799fdacdafec9e0ed81357b5db70f85bb1241fe775e71b8ad3feb686116
-dist/2025-09-05/rustfmt-nightly-armv7-unknown-linux-gnueabihf.tar.gz=ed8cade9b846efb5ac121aa70ac188fbd2e61fa9402fe68c80b2cbd3ee32ccbd
-dist/2025-09-05/rustfmt-nightly-armv7-unknown-linux-gnueabihf.tar.xz=0d0bfbd9cd4123e0404fe476a6f16eec6e435ce28d328dc0dd0aad257b295d64
-dist/2025-09-05/rustfmt-nightly-i686-pc-windows-gnu.tar.gz=bd411db34707c36d5b60f14bba776b0b89b69d4266007a3b591c467a17ef053c
-dist/2025-09-05/rustfmt-nightly-i686-pc-windows-gnu.tar.xz=f0f2a6a81177ae6d06ff9b8f4a5bdf3bc8b26710aaf0f09258b32f7f710722c0
-dist/2025-09-05/rustfmt-nightly-i686-pc-windows-msvc.tar.gz=b49130da444e01fe4ef997b649aada8978b8dcca60dd38cf9e7400a7c7569e1b
-dist/2025-09-05/rustfmt-nightly-i686-pc-windows-msvc.tar.xz=0195cdddc74cba2bf17eaa1d53edb1a2bc0e34cdf13c7b25a34ad9729a2635b8
-dist/2025-09-05/rustfmt-nightly-i686-unknown-linux-gnu.tar.gz=1141897495ddca10fd6d9476a624b6a340fc2bfc619148e183bcf355a0078b18
-dist/2025-09-05/rustfmt-nightly-i686-unknown-linux-gnu.tar.xz=81b31bc8b3d431120005c3c8eeff3ed194dd18e56220c175c3250855cbdcddbe
-dist/2025-09-05/rustfmt-nightly-loongarch64-unknown-linux-gnu.tar.gz=10a27070239e7dfcf701669c8d93ecb2d310b9fde768639a2bf5be62cd13528d
-dist/2025-09-05/rustfmt-nightly-loongarch64-unknown-linux-gnu.tar.xz=0ac4a529f4f62a94d5ae4cc8a4a52f0e7d57296ac0884258dcc5478e6b0b1785
-dist/2025-09-05/rustfmt-nightly-loongarch64-unknown-linux-musl.tar.gz=9d0ed6778fc4f0601be1e317438cf95c414fcab6d3207c635babb4f3a6faf2b0
-dist/2025-09-05/rustfmt-nightly-loongarch64-unknown-linux-musl.tar.xz=e40b607faf2f37c9d654cc0b60c47ea155893a3b62236cd66728f68665becb18
-dist/2025-09-05/rustfmt-nightly-powerpc-unknown-linux-gnu.tar.gz=46c029ebbfa35972b0b9e366d17c41ff8e278e01ce12634d5e3146cbf6d1a32e
-dist/2025-09-05/rustfmt-nightly-powerpc-unknown-linux-gnu.tar.xz=8d1462fd09b04a94bfb1c1841c522430b644961995bf0e19e7c8fa150628e7c7
-dist/2025-09-05/rustfmt-nightly-powerpc64-unknown-linux-gnu.tar.gz=5827684ccb4d38956e77858ddeadeaff2d92905c67093207bed0f38202268151
-dist/2025-09-05/rustfmt-nightly-powerpc64-unknown-linux-gnu.tar.xz=975c7d7beb5b66caed7d507aaec092fdf33de2308f4dc7de46fe74e5e15b5352
-dist/2025-09-05/rustfmt-nightly-powerpc64le-unknown-linux-gnu.tar.gz=8829677ab0f898c98badf22dad61094cf53c6d599b2cc76142d3d792a44f3770
-dist/2025-09-05/rustfmt-nightly-powerpc64le-unknown-linux-gnu.tar.xz=3d961bead4010f8a488a065ac8a4153e3c747dfcd7d5f7eeba1cad00767a7ac5
-dist/2025-09-05/rustfmt-nightly-powerpc64le-unknown-linux-musl.tar.gz=0138c30ebe74e8ee838d9eef31c7882812bb52d2304f2de7c23c47dedd6a5032
-dist/2025-09-05/rustfmt-nightly-powerpc64le-unknown-linux-musl.tar.xz=bdb4b7b3c89a30c79f51b5fa33a2a29fc8313f8193bc43ee611e8ce7d80382d2
-dist/2025-09-05/rustfmt-nightly-riscv64gc-unknown-linux-gnu.tar.gz=8e440dd400bf3eb4a144318459e111069a64bb309a5a51eeb0f0383dc48ee55f
-dist/2025-09-05/rustfmt-nightly-riscv64gc-unknown-linux-gnu.tar.xz=f623e1d7d38d94965d7653fdf4a272630b2b6dec81662fbbe5d2573f2f3f3b8f
-dist/2025-09-05/rustfmt-nightly-s390x-unknown-linux-gnu.tar.gz=f46a8278352d5a981c6746b876fe19df3093090a866d20d24cd5cb081136b1c0
-dist/2025-09-05/rustfmt-nightly-s390x-unknown-linux-gnu.tar.xz=fdf8b44c6f110a33ad7f969e651ad396c880a85545aadfee8a24ca3cbed35974
-dist/2025-09-05/rustfmt-nightly-sparcv9-sun-solaris.tar.gz=59d778dea354867d64c809b40443ca0762c685dd0e5361971daab04aa7c5a5ad
-dist/2025-09-05/rustfmt-nightly-sparcv9-sun-solaris.tar.xz=18628b2888d77281fc9b2ac5636ce4ec444ab0e47bbe0e8a08238f90040c20a3
-dist/2025-09-05/rustfmt-nightly-x86_64-apple-darwin.tar.gz=169d9f2ee4a0c726040f4940370d1162502aa6568a0a442c92cad3fbc7bd95c2
-dist/2025-09-05/rustfmt-nightly-x86_64-apple-darwin.tar.xz=7f955cfa1ab07819f31cd904b0a79c67cae70090aabc7dafffdc1f3f67463248
-dist/2025-09-05/rustfmt-nightly-x86_64-pc-solaris.tar.gz=d2cc32d6be1d0f1a8654400f0418d16e789b62db3fbc0cca0d0d492615bcf6e2
-dist/2025-09-05/rustfmt-nightly-x86_64-pc-solaris.tar.xz=3dbc29c923a6a2809a8ef561d2ad375211b09dcb107bceabbf510ab0d7b471f0
-dist/2025-09-05/rustfmt-nightly-x86_64-pc-windows-gnu.tar.gz=d9b4ca2abf1062e888b31f31f517ccc6b451bd2bfdae915ec3984bc88a8be91a
-dist/2025-09-05/rustfmt-nightly-x86_64-pc-windows-gnu.tar.xz=00c6d92b6e82ae58e682e72c974f2dcc865820567ba44ed008e4759dfdbdca87
-dist/2025-09-05/rustfmt-nightly-x86_64-pc-windows-gnullvm.tar.gz=e75424d0aece8d548b2c9d896291288615d08ff2a37f1c4844a70839c612e633
-dist/2025-09-05/rustfmt-nightly-x86_64-pc-windows-gnullvm.tar.xz=cce9578d9b35bd8192a26e2dc7d7f7e7d5b9f08c7d73b3f4dde08208b448b063
-dist/2025-09-05/rustfmt-nightly-x86_64-pc-windows-msvc.tar.gz=ac4282e06b0972033f974c63d2c6cbf194d4e66a1c811f443d3fa0b886868825
-dist/2025-09-05/rustfmt-nightly-x86_64-pc-windows-msvc.tar.xz=a2465b31855861d0e0eea072bb366480acf2bafdd7fdfdab79c809d8bbf8d8e4
-dist/2025-09-05/rustfmt-nightly-x86_64-unknown-freebsd.tar.gz=30c22a97066a5711f207c1919a1d74a328540da0d9d6f85a0cc044174049c927
-dist/2025-09-05/rustfmt-nightly-x86_64-unknown-freebsd.tar.xz=40987da0b665940f9c406cfbb4889dc101d73846730b0bdfa1382d051297ad08
-dist/2025-09-05/rustfmt-nightly-x86_64-unknown-illumos.tar.gz=443ba10092122fbba9854abb4aa9d2e71d8e5e65b99fae6dd572909bf50f28c5
-dist/2025-09-05/rustfmt-nightly-x86_64-unknown-illumos.tar.xz=10285942b9140efc9897965cb3a4204145e774bd1b0c2690d45d8b04498fb917
-dist/2025-09-05/rustfmt-nightly-x86_64-unknown-linux-gnu.tar.gz=b09af4fe367df416bce622654d9e3dfb610c564f5e6d14b200d949340595673c
-dist/2025-09-05/rustfmt-nightly-x86_64-unknown-linux-gnu.tar.xz=1f9a585a017cee5a05190377cab105603f039fbefd9b4934278dc555dfca91b0
-dist/2025-09-05/rustfmt-nightly-x86_64-unknown-linux-musl.tar.gz=24f911745fcc9f120e44acccb98f54dc6406e492915410aae17efdd00e2752c3
-dist/2025-09-05/rustfmt-nightly-x86_64-unknown-linux-musl.tar.xz=48eb58ba1d58701dbff341e19fb6d446ed937cc410207b35297babafa29dd889
-dist/2025-09-05/rustfmt-nightly-x86_64-unknown-netbsd.tar.gz=c2d1cfdcd8a08bde3f9a635eaf2d6d2fbd82e4cabbbd459e3c47e64bf1581f11
-dist/2025-09-05/rustfmt-nightly-x86_64-unknown-netbsd.tar.xz=ed1775b4fd3d7d1203f8749f70328ea4ade802fa0a76c4d7ab3e2d63ca1535af
-dist/2025-09-05/rustc-nightly-aarch64-apple-darwin.tar.gz=4b64c4148e5cdd6585a4200125cc394c6a998da3686ef758f37742ec2d33d573
-dist/2025-09-05/rustc-nightly-aarch64-apple-darwin.tar.xz=fd45182f9db059bdc17f2c465dbaae22589eb8e8d2d88776437a34ddca3b7153
-dist/2025-09-05/rustc-nightly-aarch64-pc-windows-gnullvm.tar.gz=c14f2d7f391492d150f2f2f91af413266649cbdbdb042fc8b660b3cb141b80c7
-dist/2025-09-05/rustc-nightly-aarch64-pc-windows-gnullvm.tar.xz=d72ea1c571fe2376ef05cfd15fb3207ee2d27c3c851f3391dfbb082c06a5bdd0
-dist/2025-09-05/rustc-nightly-aarch64-pc-windows-msvc.tar.gz=3a485d8fd8d58fdfbc1216e51414aa4d90f0c7285a99abea0fa5935d2337251b
-dist/2025-09-05/rustc-nightly-aarch64-pc-windows-msvc.tar.xz=7317060a29eecd2e28d47f0ff8780150059756b07e2bc9137c3877be8af593b7
-dist/2025-09-05/rustc-nightly-aarch64-unknown-linux-gnu.tar.gz=58a53ae147de1beb0a53629898bf7c51097351271be3713a2e2344b86a4080a4
-dist/2025-09-05/rustc-nightly-aarch64-unknown-linux-gnu.tar.xz=f79d2730843dbea9e9588fd1c1b0d854441969d8f93f76021f06af2efe22b845
-dist/2025-09-05/rustc-nightly-aarch64-unknown-linux-musl.tar.gz=eddf23e28b8067021e80883faf2eb1d6d3005a6e8419a1232b84236bea286f78
-dist/2025-09-05/rustc-nightly-aarch64-unknown-linux-musl.tar.xz=4f0af1a66050f5e2d9d48b696349b9ccd420bdcfdb88b251a6655cc22a11949b
-dist/2025-09-05/rustc-nightly-arm-unknown-linux-gnueabi.tar.gz=fd2f0446e3c993d746e8a5f72ccebd8b0a49172316ac1d1c58bad10596becbf3
-dist/2025-09-05/rustc-nightly-arm-unknown-linux-gnueabi.tar.xz=0b06e7ba47621819b4e59e048e5d336b3d6978e906c7363f06bbc804e49f1046
-dist/2025-09-05/rustc-nightly-arm-unknown-linux-gnueabihf.tar.gz=97d7c34b53628f28e6636fae738a18d0f1f4c60a9febddfb7145e6b91fcf3fdc
-dist/2025-09-05/rustc-nightly-arm-unknown-linux-gnueabihf.tar.xz=323025215bf851024a7eb6566ad7dc5719832d81e8d46e70adaece98adc5644b
-dist/2025-09-05/rustc-nightly-armv7-unknown-linux-gnueabihf.tar.gz=3017e03222d030448ffe2805624143540197bd6d3b3e93f9f73469ace25ae4be
-dist/2025-09-05/rustc-nightly-armv7-unknown-linux-gnueabihf.tar.xz=4f6e86b185fb54f7a0b7d09a0faae7daac722351354f6abebd388efb3037dfa0
-dist/2025-09-05/rustc-nightly-i686-pc-windows-gnu.tar.gz=292c3770b96cde97072d70c58234488f955ed5582b7c3044c6de66891e73d639
-dist/2025-09-05/rustc-nightly-i686-pc-windows-gnu.tar.xz=6855d3fd9040fb4da554fd732eaf8a1c723921c35bb8a8efb31c78af69b2e4ec
-dist/2025-09-05/rustc-nightly-i686-pc-windows-msvc.tar.gz=64a86a2971ed9934bbb6aaa0afc2a7f747da463afb55b51a7c5fdbdaa294e437
-dist/2025-09-05/rustc-nightly-i686-pc-windows-msvc.tar.xz=c98f1fc3e077b8c8eb3e526c416a6551c08c62e58be57b4a4c7d59670bc435f9
-dist/2025-09-05/rustc-nightly-i686-unknown-linux-gnu.tar.gz=5481c97d788899f896473380dde0877808489bc4a0ed6d98265558631fa67a57
-dist/2025-09-05/rustc-nightly-i686-unknown-linux-gnu.tar.xz=afadaae945c0b9a8b50dbdee28791e0c03c880cb22d3c20996eeb7fab94df0bf
-dist/2025-09-05/rustc-nightly-loongarch64-unknown-linux-gnu.tar.gz=18b276a2464b6c5a817d72384f25442c7619cac05b2d8d0af212c0dad96ccfc6
-dist/2025-09-05/rustc-nightly-loongarch64-unknown-linux-gnu.tar.xz=b74323cd2dbee966eebe8e63e24fae026ecd900a025e9167cca0341e50333cc3
-dist/2025-09-05/rustc-nightly-loongarch64-unknown-linux-musl.tar.gz=916dc5144107d9173479b320b55b0a95d2d42156c69fbdb0f21377d825fe0892
-dist/2025-09-05/rustc-nightly-loongarch64-unknown-linux-musl.tar.xz=3a83da72aa4a6553ecd957af35a05274528dc79f87d24d8470c20b8b4478b05b
-dist/2025-09-05/rustc-nightly-powerpc-unknown-linux-gnu.tar.gz=59e031b6b79a1f11406c0640e1a357f2941967ea8c034a94148d60928038e58e
-dist/2025-09-05/rustc-nightly-powerpc-unknown-linux-gnu.tar.xz=53f0e33cf2651d5dc8931ec5af8f04994188d8f9a10a5c61bd72cc822df34501
-dist/2025-09-05/rustc-nightly-powerpc64-unknown-linux-gnu.tar.gz=0eec56e3b725d918cb21e494a803b2e38eb6d744f64f1a82481a4c704eb7c1f0
-dist/2025-09-05/rustc-nightly-powerpc64-unknown-linux-gnu.tar.xz=5efc97abb235f349c6cc952b4a1e4dae7d56d70b0f8b8da2a1060b85f9b734fd
-dist/2025-09-05/rustc-nightly-powerpc64le-unknown-linux-gnu.tar.gz=cb45bbcdf8841b1ac184a0aacc909f153c830e8051260e09ca4e32c1f048e2fb
-dist/2025-09-05/rustc-nightly-powerpc64le-unknown-linux-gnu.tar.xz=1c9ddddb90d45612e4fd190fb71e527b523df13146343dde200580fb2b638794
-dist/2025-09-05/rustc-nightly-powerpc64le-unknown-linux-musl.tar.gz=3a9bdd4d14e8f121d3051944ee83a901b5ca4c0921f2d01e34596fb7450b49e3
-dist/2025-09-05/rustc-nightly-powerpc64le-unknown-linux-musl.tar.xz=732b9abb8a80191884fe1ff1d4d923cc1b74c21b81e6327bc5979ae526337400
-dist/2025-09-05/rustc-nightly-riscv64gc-unknown-linux-gnu.tar.gz=1826e74200fe286478e1659ab88ea86b43efa7b023074d00dbc814d80bebc883
-dist/2025-09-05/rustc-nightly-riscv64gc-unknown-linux-gnu.tar.xz=c30b52d0f474fd6193bb1b3e147fb79fa8cc31e5db38444f023d84d1c2d93d12
-dist/2025-09-05/rustc-nightly-s390x-unknown-linux-gnu.tar.gz=c330067621ed25d8383f27e494346eca4d7d4866e48f331f2ec897ff1c386e56
-dist/2025-09-05/rustc-nightly-s390x-unknown-linux-gnu.tar.xz=cb4097ea582a83a94cab80ff2f36b6f7141c140d75c30b1d261a1ddd4ea45bd4
-dist/2025-09-05/rustc-nightly-sparcv9-sun-solaris.tar.gz=0af19e764f10333017a3ab66020b82c7185ad648d1230b68f10977e0affb937f
-dist/2025-09-05/rustc-nightly-sparcv9-sun-solaris.tar.xz=a22cfb55cdd122dd99bf3566eabd781bb2ecded90c71a41fd33b1e0588bcc39c
-dist/2025-09-05/rustc-nightly-x86_64-apple-darwin.tar.gz=163a07b91e36e85c6c41368598793667414cdc6cadc980866811234539f3aec3
-dist/2025-09-05/rustc-nightly-x86_64-apple-darwin.tar.xz=76711800685b39b3b75945395682062c40efe3195f9979784bf318837e21768a
-dist/2025-09-05/rustc-nightly-x86_64-pc-solaris.tar.gz=69142a6c04703c3c8309c6fdf66b25831bf9efa3ee70cc93da4b5b75f901b29a
-dist/2025-09-05/rustc-nightly-x86_64-pc-solaris.tar.xz=7e535f4aa136284e4bdfd4d56891caac6844dab91e1b711fa3914a5974dfcb60
-dist/2025-09-05/rustc-nightly-x86_64-pc-windows-gnu.tar.gz=ff0ea563126ff28df297258001d9fac4dbd85788b5d27a0f5d6be75306f21139
-dist/2025-09-05/rustc-nightly-x86_64-pc-windows-gnu.tar.xz=6b66adcaa9a5332979591464242423897f59276e9e2cbeb9ab038a72e72c3a5c
-dist/2025-09-05/rustc-nightly-x86_64-pc-windows-gnullvm.tar.gz=64cac5e377bc115a8f8176719575903e695337941db43cfb35546d65c0723130
-dist/2025-09-05/rustc-nightly-x86_64-pc-windows-gnullvm.tar.xz=11e2765e4b3e2296ea05ecf735cf7b5f7beb08d76d12449cfae67f88bab02819
-dist/2025-09-05/rustc-nightly-x86_64-pc-windows-msvc.tar.gz=c7d15ae7cd5af774ae70e63fec3ba8723b85fa4c4640917b3960907eedb30b39
-dist/2025-09-05/rustc-nightly-x86_64-pc-windows-msvc.tar.xz=55036567af270cdac046fb4306e515787ca6ef5073617311fac79fb87ffe9366
-dist/2025-09-05/rustc-nightly-x86_64-unknown-freebsd.tar.gz=2d24470d2bb4c4d2605c15f1b2654cc45805384babb73b1960e8aea0b8cc227d
-dist/2025-09-05/rustc-nightly-x86_64-unknown-freebsd.tar.xz=fa41782cb2e22aba30d1619db1f478c0305944ceb4de1d1001f221c5c68c104e
-dist/2025-09-05/rustc-nightly-x86_64-unknown-illumos.tar.gz=d0f9785f76c59f3a67a499cfff4a5639f3ae05cbc76750b867faaa60b7d67f78
-dist/2025-09-05/rustc-nightly-x86_64-unknown-illumos.tar.xz=925e473c6e31d8811879a805358cfd2e5ab8f4de836c270d02dc8403771bed3a
-dist/2025-09-05/rustc-nightly-x86_64-unknown-linux-gnu.tar.gz=ebac845114b89dfe7d0efc0cfe8820902faad617ed21eb2a701d73cf7b544a85
-dist/2025-09-05/rustc-nightly-x86_64-unknown-linux-gnu.tar.xz=2512a5462e3f46c95ed4aba4228282a357b3e0694e9db117a857196448fe7bcc
-dist/2025-09-05/rustc-nightly-x86_64-unknown-linux-musl.tar.gz=b4a5d364b84464e9a92140fff50349d4942b8d970b64150a4bc6d720cc6c4a4e
-dist/2025-09-05/rustc-nightly-x86_64-unknown-linux-musl.tar.xz=6c57c2edc305737530f8551d789ee79ff952f42a0d52d6f8d7d7f1ea2027cfca
-dist/2025-09-05/rustc-nightly-x86_64-unknown-netbsd.tar.gz=f3192ded327875d5a27fb50c690e3fce36669e8f71c47de304dc21edad573ff9
-dist/2025-09-05/rustc-nightly-x86_64-unknown-netbsd.tar.xz=11359e4731866f6a788e5699867e45befdf1ad49ef35c0aba22af76d3f327cc3
+dist/2025-09-21/rustc-beta-aarch64-apple-darwin.tar.gz=08f8aee2085d8da9041fa9f4c7c6d79b5b1c06c544a3e2309f353844e1250bd0
+dist/2025-09-21/rustc-beta-aarch64-apple-darwin.tar.xz=a36bed31d0f600ca8e8efc19322fe05a88e31bc218078e79c8ca0e7c3d582b20
+dist/2025-09-21/rustc-beta-aarch64-pc-windows-gnullvm.tar.gz=2b6b8f275d1b03ed7bc05e631378c0b462d274b7f1f038f2feec752b29993b10
+dist/2025-09-21/rustc-beta-aarch64-pc-windows-gnullvm.tar.xz=13adf0b39c176761adcf754671911d5309cf04348ef9f93fcf8c09afa6b70da0
+dist/2025-09-21/rustc-beta-aarch64-pc-windows-msvc.tar.gz=568566c82dd296babbd5588d0c69f23c5b5bfd32b3b25e493e6d45f15d645db7
+dist/2025-09-21/rustc-beta-aarch64-pc-windows-msvc.tar.xz=8357fb4ec176279416cabc0edbb2f7c3d4c812975867c8dd490fd2ee30ed1d1f
+dist/2025-09-21/rustc-beta-aarch64-unknown-linux-gnu.tar.gz=a885d01f6f5043bacb3bf4820777e29ab45aac4dbdfed75ee71a3de01b056e05
+dist/2025-09-21/rustc-beta-aarch64-unknown-linux-gnu.tar.xz=3a2bed859214bbea2cdd13675eaf480e62c01646efed26067ba7078e6dd8591f
+dist/2025-09-21/rustc-beta-aarch64-unknown-linux-musl.tar.gz=4b66e79a48d172eb674ba7e6b4eea91ebda2351d6d253deef90010ffc48d4801
+dist/2025-09-21/rustc-beta-aarch64-unknown-linux-musl.tar.xz=131f270aee35b36ae02959abe032c77e1de0c75f23f7c61bbca1e2c18a23f4f9
+dist/2025-09-21/rustc-beta-arm-unknown-linux-gnueabi.tar.gz=d8c38594dfd1ef17c9ceb2ea614be730f4647fa5e75e80b5bc12d235216ecbf4
+dist/2025-09-21/rustc-beta-arm-unknown-linux-gnueabi.tar.xz=1643434757b590b1586e9074e82be3cc9e50e5551212d5f2040fdd8feba8f1e2
+dist/2025-09-21/rustc-beta-arm-unknown-linux-gnueabihf.tar.gz=1619461791fa6c2b8750043a41acd285bdf1f32d376af675343be3449bb7e5b8
+dist/2025-09-21/rustc-beta-arm-unknown-linux-gnueabihf.tar.xz=cd2ed3ae30cf77b5530a2ebee13daeb1419ceec2ab18f754d07b081dd6a607c1
+dist/2025-09-21/rustc-beta-armv7-unknown-linux-gnueabihf.tar.gz=b0703e79530bd836df864facbfb5065c3e5e8b3a457e4ef55b4f7a4d362b9ba8
+dist/2025-09-21/rustc-beta-armv7-unknown-linux-gnueabihf.tar.xz=a647780abbe8d36049edd90857b3baab556ac9b61caaef1d98307fe92fc20453
+dist/2025-09-21/rustc-beta-i686-pc-windows-gnu.tar.gz=c7ec1f853b96edbf1a914b8345b025c87641225e0c49507bbffd88f2da05b8f4
+dist/2025-09-21/rustc-beta-i686-pc-windows-gnu.tar.xz=53803baae3061eb164f34900f5867cfdf3bf50733ca0a6bda674b491bc0250b8
+dist/2025-09-21/rustc-beta-i686-pc-windows-msvc.tar.gz=a0f9192059b9989db0c4dba57b5eae9cace1b8e6f8bb2362b028c7f36e34d44c
+dist/2025-09-21/rustc-beta-i686-pc-windows-msvc.tar.xz=f8c237af5f0e2fe293671ddfe7fcf90f6e2b161a52314b2eb622f2a1b23ba3fc
+dist/2025-09-21/rustc-beta-i686-unknown-linux-gnu.tar.gz=da2a42e5a76e95460a348ba70cdf1c5c6ade82eb6ad3796935158bbf5859b602
+dist/2025-09-21/rustc-beta-i686-unknown-linux-gnu.tar.xz=c98df2f0156c3065179f50d55dafda8c5db1f2eae99ecb3f568a8861299be289
+dist/2025-09-21/rustc-beta-loongarch64-unknown-linux-gnu.tar.gz=1149494d96b4ce949308620a360a365c4304b8ee8f8c9512a35f08048aa13c78
+dist/2025-09-21/rustc-beta-loongarch64-unknown-linux-gnu.tar.xz=c906f519bc65a3a7514a62f8920d334bc10623a76dd2d3464af88065b79cb334
+dist/2025-09-21/rustc-beta-loongarch64-unknown-linux-musl.tar.gz=e3a9dd7ae0179ebb7659024532b9f3cca9ac4cdf62c0ae411b00d8f8768aaa34
+dist/2025-09-21/rustc-beta-loongarch64-unknown-linux-musl.tar.xz=d9f3428d80a7b72b15c62bd3306628820f73b64f48de37ea079699b733bda048
+dist/2025-09-21/rustc-beta-powerpc-unknown-linux-gnu.tar.gz=4b52241a8b65a9a42db2a75e057176a99e3b434907f498c4b6b9da104e138c72
+dist/2025-09-21/rustc-beta-powerpc-unknown-linux-gnu.tar.xz=40f3a5fc7478b40153ab20e3f14a6d838c80dda529481735e898de989a31f963
+dist/2025-09-21/rustc-beta-powerpc64-unknown-linux-gnu.tar.gz=f5aa411dfe614ed288351fa4b17d1e2935501c804c0ad51f22e3db71617b17ea
+dist/2025-09-21/rustc-beta-powerpc64-unknown-linux-gnu.tar.xz=b9efeb2e185e43775d309d083d8c4f45e30e18b7af71b9c45e397af6bc723fcf
+dist/2025-09-21/rustc-beta-powerpc64le-unknown-linux-gnu.tar.gz=38b6a69885e4dac48f7c3128ff1e88d0bf2d0ce1fbd6a5baa9dda62bca0b2b08
+dist/2025-09-21/rustc-beta-powerpc64le-unknown-linux-gnu.tar.xz=8576ae6d787b0f8b127bb2dbeee213cc6093ba92dc7d5ff08f463d56e2e6ce90
+dist/2025-09-21/rustc-beta-powerpc64le-unknown-linux-musl.tar.gz=5e91ce627e900da2606782ae60598843a6ba17593a7eb0dcc8f5f9a1cc20676d
+dist/2025-09-21/rustc-beta-powerpc64le-unknown-linux-musl.tar.xz=fe24fad781f829838592e6670655dcff52002ae720f987868fd4b17eb9ed631e
+dist/2025-09-21/rustc-beta-riscv64gc-unknown-linux-gnu.tar.gz=170ccaaa94eb7c813bcedf2afb37cb0c696c5f48ca9d93238ee8cf26efc5bafa
+dist/2025-09-21/rustc-beta-riscv64gc-unknown-linux-gnu.tar.xz=db5a862a260fe8688e3b1da1161948eed5361723a296bb27dcc62758eaa2b873
+dist/2025-09-21/rustc-beta-s390x-unknown-linux-gnu.tar.gz=c764aa7b70dacf7ac3ef5d2184d021304b633309b771f24d62375fa64791614f
+dist/2025-09-21/rustc-beta-s390x-unknown-linux-gnu.tar.xz=69eedf71d20924d9729684e27a3a8cebc60efa7c0e7a3f8b6fe664f469a36788
+dist/2025-09-21/rustc-beta-sparcv9-sun-solaris.tar.gz=efb9d78cc395774e05353615c029ed674c1ba55204ae9be3d022abda9f5c6d9c
+dist/2025-09-21/rustc-beta-sparcv9-sun-solaris.tar.xz=e8de37de871888886bb58d915f3a27bfd8c30a912ea3f3af4abf52f66708268f
+dist/2025-09-21/rustc-beta-x86_64-apple-darwin.tar.gz=b945ef94a4efdc0fdd4a66c3708cb95a97592c922652af06d8d1b6bbaaf71660
+dist/2025-09-21/rustc-beta-x86_64-apple-darwin.tar.xz=876a6080177df194c14d0984f112692295a21186b05bd03a77d0a304dec5ad51
+dist/2025-09-21/rustc-beta-x86_64-pc-solaris.tar.gz=d7c0b4fb19c785ed3a0c16d903cef266438031c3a43b1721d19864a1923d3cb4
+dist/2025-09-21/rustc-beta-x86_64-pc-solaris.tar.xz=b4a5494890bd92b85f66054523b26e9aae5e74b3177c9eae64740ed7fa1d4da4
+dist/2025-09-21/rustc-beta-x86_64-pc-windows-gnu.tar.gz=ea55aab0bd57f0cd6568a6e78c9d0a3727fb7cfaf8ada9379084091244b3221b
+dist/2025-09-21/rustc-beta-x86_64-pc-windows-gnu.tar.xz=426009c68fa78001b34f8b329cac7634dd8921c569061f45972058b770206f9f
+dist/2025-09-21/rustc-beta-x86_64-pc-windows-gnullvm.tar.gz=c79a925f6f2b406db97732e22e1b245ef2c7d1291a574b0d55a861d3c7e5d766
+dist/2025-09-21/rustc-beta-x86_64-pc-windows-gnullvm.tar.xz=0f46e118b67656fe16c484589ee0213654cd6edfbe5a29d641aa810bddcc8c62
+dist/2025-09-21/rustc-beta-x86_64-pc-windows-msvc.tar.gz=d7b5fb269841039af498a6d0be2cbd70cb7b65f6a9918a2b6c022cadfdb30fcd
+dist/2025-09-21/rustc-beta-x86_64-pc-windows-msvc.tar.xz=dfef15ca4fcf06622953296ebec960e446402ce542e2f264c12c0c03b9a476ce
+dist/2025-09-21/rustc-beta-x86_64-unknown-freebsd.tar.gz=09994a33e03f50212cabee85294dfb684fafcef95e1de5b082540d01d92df1ce
+dist/2025-09-21/rustc-beta-x86_64-unknown-freebsd.tar.xz=a0e3409ec6f6b02517c8f9d0e00a0627434f6b06a5360da286c46ceab9d12ab1
+dist/2025-09-21/rustc-beta-x86_64-unknown-illumos.tar.gz=01daeea1f1f10d84444b56e8e74e3a451c54e65832234b2caa2ce0a63c0a9ea1
+dist/2025-09-21/rustc-beta-x86_64-unknown-illumos.tar.xz=6299fa81533b9362d1cdbf7984506fcbc26f7d9e857a942f081f5325c87cc4c4
+dist/2025-09-21/rustc-beta-x86_64-unknown-linux-gnu.tar.gz=cafaecb5158fcf39b676baf2d0060fb8b31558be0e442389755ae33a3e7bb42f
+dist/2025-09-21/rustc-beta-x86_64-unknown-linux-gnu.tar.xz=5d3c1fceba5285bc54f5a327841ecb8893e719ba874e483c904b903f4dc293ed
+dist/2025-09-21/rustc-beta-x86_64-unknown-linux-musl.tar.gz=290a07f32c769f74d21c57a856b3aa39da89e2f086e53c42f3333d1f9ffb5673
+dist/2025-09-21/rustc-beta-x86_64-unknown-linux-musl.tar.xz=8bb354230d3da85bb0fc280c3e95ceadd9f7522d231fe787be8c82aa072ad506
+dist/2025-09-21/rustc-beta-x86_64-unknown-netbsd.tar.gz=af3c98fb99b419cfe50433f5f4a046065066183b248708ec8800253867c678df
+dist/2025-09-21/rustc-beta-x86_64-unknown-netbsd.tar.xz=0ea09297621d3b735b2931f6472f95e1587d38f6fb0df7fdf5e427fa3baec4a1
+dist/2025-09-21/rust-std-beta-aarch64-apple-darwin.tar.gz=8c08542fe69e9fd5b2256d17d84427ac206c9e79e265fddbcdf12d1af4e5d913
+dist/2025-09-21/rust-std-beta-aarch64-apple-darwin.tar.xz=7ddd43d1e32a829ffa9a7a798e1339d0569e773d841d8b7ad33701664373b8ae
+dist/2025-09-21/rust-std-beta-aarch64-apple-ios.tar.gz=bf3df6d2eb7e5515ae86bb970b5c145140f8e9d503e636fcfc435d47797b650a
+dist/2025-09-21/rust-std-beta-aarch64-apple-ios.tar.xz=fbb88375a8c0c5e41d35e4838ecbd31e4ad1b96e22eb689ae37dd50322545d39
+dist/2025-09-21/rust-std-beta-aarch64-apple-ios-macabi.tar.gz=26e9fb3607dfeab90500bac3e9eaa23170f7f22a4738ae6b58e2e89e0c87f72a
+dist/2025-09-21/rust-std-beta-aarch64-apple-ios-macabi.tar.xz=6c9622771203bf342d59673bb1f53fe715b4255f0860feb6b19be57de2ef9f92
+dist/2025-09-21/rust-std-beta-aarch64-apple-ios-sim.tar.gz=a9c15e05b58adede5d08d7628de75d47d5c38ca60fad87dca8b8c9801050ee1a
+dist/2025-09-21/rust-std-beta-aarch64-apple-ios-sim.tar.xz=bd847e7952c02312e36900766a71a5284c221b177ddef0b9cb071c5f6186a70b
+dist/2025-09-21/rust-std-beta-aarch64-linux-android.tar.gz=2dbfa47893553b2868c375bedda6c4e08c33bbfa9cc96ff6e89ccf0525f8b14b
+dist/2025-09-21/rust-std-beta-aarch64-linux-android.tar.xz=6b83da57cd768bad91a820d698bd18ae60586b0920950ea14105d6f23b4b1db8
+dist/2025-09-21/rust-std-beta-aarch64-pc-windows-gnullvm.tar.gz=a71a57f26812c2e1529c10e2e02b8d9b466564065a8a10ceb69f22cb76e83814
+dist/2025-09-21/rust-std-beta-aarch64-pc-windows-gnullvm.tar.xz=29f8789707c545e45680acd30a329fa28613dd247ce7c91d65b13a10c0c21202
+dist/2025-09-21/rust-std-beta-aarch64-pc-windows-msvc.tar.gz=07067546648ac6e784f9d5f6455534b62b9eb5cd86805c327b98505a0caeb2d8
+dist/2025-09-21/rust-std-beta-aarch64-pc-windows-msvc.tar.xz=f224f6b979ceef56ef8a10eaf063a6ea072d405a52ef123b720d44925b530d36
+dist/2025-09-21/rust-std-beta-aarch64-unknown-fuchsia.tar.gz=756534ef3e62c80481e4886348bc80632ca68ec9c49045d71838dc7ef0751373
+dist/2025-09-21/rust-std-beta-aarch64-unknown-fuchsia.tar.xz=c6eee692a79106d7733c1cbc525b241b6d88a53ee08242e494d286eb0ad3024a
+dist/2025-09-21/rust-std-beta-aarch64-unknown-linux-gnu.tar.gz=4843b5a6d3e8b89a54ab91e44768bb023178c8cc7cd745639d9a616f2331d9a2
+dist/2025-09-21/rust-std-beta-aarch64-unknown-linux-gnu.tar.xz=89a808aade0a91043bef23f3e3f38d193b4f02b6556f01cbaf103c43ce428478
+dist/2025-09-21/rust-std-beta-aarch64-unknown-linux-musl.tar.gz=6c09b424925e89957fb1921887b7034c3d3adf012571415b9930e1d0119bed41
+dist/2025-09-21/rust-std-beta-aarch64-unknown-linux-musl.tar.xz=3c34d71b74adb145302772db2a5c565235576a14c42eca0a270b0e9e67ac9032
+dist/2025-09-21/rust-std-beta-aarch64-unknown-linux-ohos.tar.gz=70225984fa7ad361126efd9cbd40fe9dcf4756866b23079e4dbde5ec51f3a10d
+dist/2025-09-21/rust-std-beta-aarch64-unknown-linux-ohos.tar.xz=e696cf9ac5b4b0e16e3947377424515c761697541351d0924b61a37557394828
+dist/2025-09-21/rust-std-beta-aarch64-unknown-none.tar.gz=7b754105300a911c24f7483b7eb482d076f5f98e16f685215d06df3dab1fdcba
+dist/2025-09-21/rust-std-beta-aarch64-unknown-none.tar.xz=8168916ec457eaeb32ad1d274ce67666d6ff8fdf662f32bc6e17656ef4ff7c81
+dist/2025-09-21/rust-std-beta-aarch64-unknown-none-softfloat.tar.gz=1ff511547185b42b801ce51f84985767d580c08f183b15033e8ae05274b7f90c
+dist/2025-09-21/rust-std-beta-aarch64-unknown-none-softfloat.tar.xz=263e10d4226c5328cb41299466b82e154fa1c94c67fc3a185a0bb9a6639bebad
+dist/2025-09-21/rust-std-beta-aarch64-unknown-uefi.tar.gz=eb3710b6ccbde9a265217a4e64f2c62bb22bcc79dd58a48381cc81c5e95073d4
+dist/2025-09-21/rust-std-beta-aarch64-unknown-uefi.tar.xz=b1c231790f55fd9a3dfcb9e6c946f34afb3bf96c57bb9d8615894d81aed44f95
+dist/2025-09-21/rust-std-beta-arm-linux-androideabi.tar.gz=0d12ed3a2980fce0d71d728d6c2840eac36a3e3ae93f2dfc3cb391d56c20cbf1
+dist/2025-09-21/rust-std-beta-arm-linux-androideabi.tar.xz=2219966a5e884a94c324b74872a2a4a12378d595cae10b53958190acc05ccd45
+dist/2025-09-21/rust-std-beta-arm-unknown-linux-gnueabi.tar.gz=286c12975e333cdf9c7ad0b21217e3b83682047c37c1dba766cff4a201bab40b
+dist/2025-09-21/rust-std-beta-arm-unknown-linux-gnueabi.tar.xz=9e56db5ac01ae18077551117348fe56050426f521e41f217ac3d71c23eff4d88
+dist/2025-09-21/rust-std-beta-arm-unknown-linux-gnueabihf.tar.gz=f52e699638e352d9f816a21965a5696acc5fd77325ff074f93c27587292bca19
+dist/2025-09-21/rust-std-beta-arm-unknown-linux-gnueabihf.tar.xz=d0a4abaa489bfc6f2f7d2305e8edbd502b12f247357ba4cda541786377648108
+dist/2025-09-21/rust-std-beta-arm-unknown-linux-musleabi.tar.gz=7ee043969e94b14ea74e083fd3edb9e0639d68c2bdd7ebdb188e98b36c854fcb
+dist/2025-09-21/rust-std-beta-arm-unknown-linux-musleabi.tar.xz=8ce6bafaae0e8217bdb138d104955ce7f0a747ef915aebb181cf3047beb4456f
+dist/2025-09-21/rust-std-beta-arm-unknown-linux-musleabihf.tar.gz=8e5c901df3f932bac7dad635bc1197ffbee4884c0a101632d51a32f23c875cdb
+dist/2025-09-21/rust-std-beta-arm-unknown-linux-musleabihf.tar.xz=166a1d949b6847e9bf102a89f9a417a30d8ac25a35fe3f732d6a513a7674af85
+dist/2025-09-21/rust-std-beta-arm64ec-pc-windows-msvc.tar.gz=8660de6d0d97fdffe3bbcfd5ffc7e11bbfe9c43f80067ba17845414958778845
+dist/2025-09-21/rust-std-beta-arm64ec-pc-windows-msvc.tar.xz=8b563eb032535c58c487d4ad992a12a106208861e45ea78c342e940b9356ebf1
+dist/2025-09-21/rust-std-beta-armebv7r-none-eabi.tar.gz=cd761b3f761198cc6ac64809eaa28ac299b67ba48d964298db3f5b4ea52f3623
+dist/2025-09-21/rust-std-beta-armebv7r-none-eabi.tar.xz=071864464c52c37bd102fad26b5d28f31aa9e06d34ee868a33ead297c3e20a4d
+dist/2025-09-21/rust-std-beta-armebv7r-none-eabihf.tar.gz=402c044cdaad16d2b60365b6894250aa43424902c0b3f0526e849d7d0d452315
+dist/2025-09-21/rust-std-beta-armebv7r-none-eabihf.tar.xz=0028e17d0164bbb8166ddaad815874123fcc326dffef4740389ff2cb069a3e2b
+dist/2025-09-21/rust-std-beta-armv5te-unknown-linux-gnueabi.tar.gz=0b9be6bfa168756361aa5feb7802133c4cbebd3fd20d75d32a4385b716417a9f
+dist/2025-09-21/rust-std-beta-armv5te-unknown-linux-gnueabi.tar.xz=1893fcd9b16f0c334257cbc78dc416cc048d7c1603ba632ed7300bbf6c0bffb0
+dist/2025-09-21/rust-std-beta-armv5te-unknown-linux-musleabi.tar.gz=5aa03609f57d6c959673963b633adf194ea240b3604ba6635a6ef5fbe5c519d3
+dist/2025-09-21/rust-std-beta-armv5te-unknown-linux-musleabi.tar.xz=8f075eb3b1ed0bdfde8af08ee69778af2d2e896d1cdf17035657d1a84c85e856
+dist/2025-09-21/rust-std-beta-armv7-linux-androideabi.tar.gz=1499f0b4c3a4838dbd7b0df7303fbe7e157dfaec396b5ee1a6ae6a727ea3122a
+dist/2025-09-21/rust-std-beta-armv7-linux-androideabi.tar.xz=f0ad36dd56abf6c03395bfc246209bce90aba1887dee81a2841f7e1013f93850
+dist/2025-09-21/rust-std-beta-armv7-unknown-linux-gnueabi.tar.gz=4a430fa04ef3d23dcf1d5e1f69c37127a5fb58e883ac52c8885125e0f578cde9
+dist/2025-09-21/rust-std-beta-armv7-unknown-linux-gnueabi.tar.xz=6fab12ecab36252aa1a4f6aa523ae1546f534548394e2585e96a869b87656806
+dist/2025-09-21/rust-std-beta-armv7-unknown-linux-gnueabihf.tar.gz=4081b51910cb95fbacafc9518ee5891e1131af79a8348635c13765706c18c3ea
+dist/2025-09-21/rust-std-beta-armv7-unknown-linux-gnueabihf.tar.xz=ed9a56e0e8b4e0f639afd9c6c75c4adfeddc7ce0aaa9132591f774754f412b6e
+dist/2025-09-21/rust-std-beta-armv7-unknown-linux-musleabi.tar.gz=571a08bf8eaa522017b0aa67fb78b344590fde57ab3425575c01ceb3b258c557
+dist/2025-09-21/rust-std-beta-armv7-unknown-linux-musleabi.tar.xz=e50728c440ae8fc9d154a3893914126d4486ca7dd197891b78531f7d5d081211
+dist/2025-09-21/rust-std-beta-armv7-unknown-linux-musleabihf.tar.gz=1f8570de307fbc59e962ef6b419009d57fb05b2e1d5fc9ade9d425e3c9977cfe
+dist/2025-09-21/rust-std-beta-armv7-unknown-linux-musleabihf.tar.xz=35db980cea1ba70003374a738f20af63d54796e9181b8cf0e9d0626e0935a9a2
+dist/2025-09-21/rust-std-beta-armv7-unknown-linux-ohos.tar.gz=ba5a8487dbb60851fc927dc24ee58186aa6e74d42dbf5202df7981a456b5f8f7
+dist/2025-09-21/rust-std-beta-armv7-unknown-linux-ohos.tar.xz=f763ae3e33f4785ff505eb068ed6515aff8ffcdb9895595d23c2cea519e26355
+dist/2025-09-21/rust-std-beta-armv7a-none-eabi.tar.gz=3cd90f1a7c14a732a951026458a976fd5e833f212c6f6433f8de348b7b742b9c
+dist/2025-09-21/rust-std-beta-armv7a-none-eabi.tar.xz=237f44f2b9984743f71ef0cab8d693092748fd2da25cabd3468e3e45ca20e2bc
+dist/2025-09-21/rust-std-beta-armv7r-none-eabi.tar.gz=ec38043fd7877d45331414d059d0198d055ab724e84c077ca75a2902afbb2d6b
+dist/2025-09-21/rust-std-beta-armv7r-none-eabi.tar.xz=f511909286f3e1cb52f0e698722bec1a3cfb750e19bb2fa781bfff225620ca8c
+dist/2025-09-21/rust-std-beta-armv7r-none-eabihf.tar.gz=556365cb3ed473222e1b135be77086214f3f94f863817de4a87ee7d75456b824
+dist/2025-09-21/rust-std-beta-armv7r-none-eabihf.tar.xz=8483d2550782e253cdace51fe24249fbd6bd0b10a850c75e62dc60f803be17b0
+dist/2025-09-21/rust-std-beta-i586-unknown-linux-gnu.tar.gz=0ed5faa9e8e73f4e7b9e75741d000954558bafeaf776a6e61a4e44ac120b91e9
+dist/2025-09-21/rust-std-beta-i586-unknown-linux-gnu.tar.xz=665d5a0debd829f3682572e4c3578d41bec58b01df10cc8c71ca66d326a3579f
+dist/2025-09-21/rust-std-beta-i586-unknown-linux-musl.tar.gz=c59dcbce2435a5826161d4319dcf84e128f9fa4c0bf075fab2a26c2bfb5d9887
+dist/2025-09-21/rust-std-beta-i586-unknown-linux-musl.tar.xz=13a2292936e289941be4a02903051eadb076bb44368494d530cf66832978f46f
+dist/2025-09-21/rust-std-beta-i686-linux-android.tar.gz=5d23e660218e04a7dc4aaf940959619ec9aa14bf5574a554c0d8f377910ed017
+dist/2025-09-21/rust-std-beta-i686-linux-android.tar.xz=cffd08cc85df3cc661d8a572e940316da06754b61893efcd9ad3b7db09a0e6ee
+dist/2025-09-21/rust-std-beta-i686-pc-windows-gnu.tar.gz=91743434207475f4404707cf7a203b46f032a041184a729ddcaeca280b2fac05
+dist/2025-09-21/rust-std-beta-i686-pc-windows-gnu.tar.xz=1f0240a71bf5a3bd74e1ae960c1aae440c3b3e32e6c62835287f78cc777f0d7f
+dist/2025-09-21/rust-std-beta-i686-pc-windows-gnullvm.tar.gz=ec5907cfb6faafcc20f3d7cdb22fd7836c9c2d7cb4871c48e64732bb7f5dcba5
+dist/2025-09-21/rust-std-beta-i686-pc-windows-gnullvm.tar.xz=e7e8453b9dafc3c8c222455f5327fc8cde127f8dc877991688afd3c2f23675f5
+dist/2025-09-21/rust-std-beta-i686-pc-windows-msvc.tar.gz=50dd40b16e8ea85fd7ca67583d5cae80910d36531a7babe13a94cb638015a1d3
+dist/2025-09-21/rust-std-beta-i686-pc-windows-msvc.tar.xz=dafeb013333acc8a3a4181358584851b47c5f21138d8164ccfd6863b171309ba
+dist/2025-09-21/rust-std-beta-i686-unknown-freebsd.tar.gz=91d741bfd158f22f4dea8bf768c5fb60ca05f5dc64cd5a848428b8dfe8beccbf
+dist/2025-09-21/rust-std-beta-i686-unknown-freebsd.tar.xz=12ddbbb201a973148979a99ccbac3c65690010dd2f6984fa390fe5e63a28dbda
+dist/2025-09-21/rust-std-beta-i686-unknown-linux-gnu.tar.gz=975e30f37f03afb47777a38edcd535df6729311cc0acb587d417ebff694df796
+dist/2025-09-21/rust-std-beta-i686-unknown-linux-gnu.tar.xz=bc95dd6129e90c9275e0340962993de7a0842040bdfcde9aa419f227d79dbf31
+dist/2025-09-21/rust-std-beta-i686-unknown-linux-musl.tar.gz=1c937cce8b40567851578790512fe079c0aa828374a3bb76423d685357388576
+dist/2025-09-21/rust-std-beta-i686-unknown-linux-musl.tar.xz=b42d227d63f0b3352d4d66f1198294c2f4df574c48fff794ac3483cef869c2bf
+dist/2025-09-21/rust-std-beta-i686-unknown-uefi.tar.gz=0e8c239ce3b8701c4a26b46aca9a700083667ffc3228d796ba0ba6d0728c6826
+dist/2025-09-21/rust-std-beta-i686-unknown-uefi.tar.xz=54cba2405dfa2a23164bb8e7de5e0d6a6a6523f36b0763f077d2bfec1f303576
+dist/2025-09-21/rust-std-beta-loongarch64-unknown-linux-gnu.tar.gz=72db70ab9289bce8ace5da246432d2a00552b4cd9ebef7930b563e04d1cdebf1
+dist/2025-09-21/rust-std-beta-loongarch64-unknown-linux-gnu.tar.xz=5b578548a62dfd3902920719acd17550f45d0e9106049cbdc1f36c8907a8291f
+dist/2025-09-21/rust-std-beta-loongarch64-unknown-linux-musl.tar.gz=993fdc6d1894f823b3782fe180ac40a3ad7baba110f2eff68d9e38e8f79a95a4
+dist/2025-09-21/rust-std-beta-loongarch64-unknown-linux-musl.tar.xz=b5161bd0064bfb312cf156ec4689a3f5922c7df24468660e1046798c8984938c
+dist/2025-09-21/rust-std-beta-loongarch64-unknown-none.tar.gz=670ef40754ac30a2edb65384de65f028a4f8e96dca49fd0bb5eb2d9d6020e906
+dist/2025-09-21/rust-std-beta-loongarch64-unknown-none.tar.xz=b9aa6311d6a3e428f151fc6720147ea8759092545b05cad3f16b6e563d523813
+dist/2025-09-21/rust-std-beta-loongarch64-unknown-none-softfloat.tar.gz=5c4c2e6bdc6d3c79578a3fd581064ba6aeb21fd9311a39a62bf58b36e7ea00cc
+dist/2025-09-21/rust-std-beta-loongarch64-unknown-none-softfloat.tar.xz=8e272682e98ff8b139da621d7273cf71efa407538ea176d873a1ea7e22246ebd
+dist/2025-09-21/rust-std-beta-nvptx64-nvidia-cuda.tar.gz=0781275b356176417c21c1bd1a4068fe2a42dc6de9b34695c937d5ba94b98ad6
+dist/2025-09-21/rust-std-beta-nvptx64-nvidia-cuda.tar.xz=8747e3e686fbf41389a8ad958596577670f0626a610d380b0a775e704bc6c6be
+dist/2025-09-21/rust-std-beta-powerpc-unknown-linux-gnu.tar.gz=95e8443355571edf645d75d31a33277f0d6f7161f8592ec213a407bc4839819c
+dist/2025-09-21/rust-std-beta-powerpc-unknown-linux-gnu.tar.xz=4abcda8b23d17f6e6681329b54215f37cca5fc1f3383e58dd60c38220f5528de
+dist/2025-09-21/rust-std-beta-powerpc64-unknown-linux-gnu.tar.gz=a24d3b7db647c114c95f7da40ca2001085d935ebffcc17e269af5be636ec1f2a
+dist/2025-09-21/rust-std-beta-powerpc64-unknown-linux-gnu.tar.xz=7579f587df01fb55211e6a0a61ed96f14955b7f56990e679715157b06b49fe79
+dist/2025-09-21/rust-std-beta-powerpc64le-unknown-linux-gnu.tar.gz=ea071da90747334a786f1e4784e39c11058d7f7719e498a8b6ae29672a999abb
+dist/2025-09-21/rust-std-beta-powerpc64le-unknown-linux-gnu.tar.xz=d612ed01011c1e7f24b08318029523f6b7ffb12ec38b1f41ebcedf463f924430
+dist/2025-09-21/rust-std-beta-powerpc64le-unknown-linux-musl.tar.gz=722b93d6c5e1f9a326461bb920fafef62cc8257ff67732c3f65ecc540782a504
+dist/2025-09-21/rust-std-beta-powerpc64le-unknown-linux-musl.tar.xz=5b5010f550b317facbd599fa363d633e0540836145717f35ffa0bff14ec80558
+dist/2025-09-21/rust-std-beta-riscv32i-unknown-none-elf.tar.gz=7dea77dc10830754d5aa9a6e5ae3272e4955cab8df1e20f0784901ca6a60c49d
+dist/2025-09-21/rust-std-beta-riscv32i-unknown-none-elf.tar.xz=f212b4afaaa954809af920d3fb3de76a611d387910e6162b902fad8f38f36c49
+dist/2025-09-21/rust-std-beta-riscv32im-unknown-none-elf.tar.gz=3f81a7134f44a87b7724a510e4cd4209ab52fb03fee3dc051c26bc0612e4b1af
+dist/2025-09-21/rust-std-beta-riscv32im-unknown-none-elf.tar.xz=cd9db852c6f7e454e94161379c032e3ccabfcdaeddd74e8f612870ef39eb230f
+dist/2025-09-21/rust-std-beta-riscv32imac-unknown-none-elf.tar.gz=6da7d7c9cdc05fc3b86930d98fe9828ecef02b5b3cead51252fe9f131ab5f9e2
+dist/2025-09-21/rust-std-beta-riscv32imac-unknown-none-elf.tar.xz=97ad71f7f63f2c3b01ba822164df457d88331880bd21837a18354fffd1b38918
+dist/2025-09-21/rust-std-beta-riscv32imafc-unknown-none-elf.tar.gz=9a5d94e1a77159a4bbf4fe7490019fff763daeb24dc2b8c732442275619f9ffd
+dist/2025-09-21/rust-std-beta-riscv32imafc-unknown-none-elf.tar.xz=dc5826fef922a6987650b491957b17693c49d1ab26b618efacbb1bb0b5a9b1bc
+dist/2025-09-21/rust-std-beta-riscv32imc-unknown-none-elf.tar.gz=1b9c1cc0648fc86fdaaf23e6793fa826f3639bab9d42e1bbe2c70f19cecc11a8
+dist/2025-09-21/rust-std-beta-riscv32imc-unknown-none-elf.tar.xz=90cb9c376894a122f3872a77a653e3decf95f1eef54ba7980846165e6f34377f
+dist/2025-09-21/rust-std-beta-riscv64gc-unknown-linux-gnu.tar.gz=22069b14b3eab5f3bd24a0f10185a5484022ac60fb7b2b5cb0019281bee79a4d
+dist/2025-09-21/rust-std-beta-riscv64gc-unknown-linux-gnu.tar.xz=395f2975bc86a63736ba7661985db038efa5f5982459add18201c97e4b1a9200
+dist/2025-09-21/rust-std-beta-riscv64gc-unknown-linux-musl.tar.gz=7932c8dbc9727a85dbf2ad28066cef1da46cf0ced358aea0e78a254fc1e423f9
+dist/2025-09-21/rust-std-beta-riscv64gc-unknown-linux-musl.tar.xz=69b8ce57a0c459ca57353cd8302deba6791a19dcf54e16b8d07f76b44e3c65fa
+dist/2025-09-21/rust-std-beta-riscv64gc-unknown-none-elf.tar.gz=27717f0b8b51f90c7e1579a2e3fa781f2a19064872133a951e60200c05db1df8
+dist/2025-09-21/rust-std-beta-riscv64gc-unknown-none-elf.tar.xz=d6cccdb4ca0856ce1d314c03779c082ee0dff153aa6bf9ea050ca3d0a395dc1c
+dist/2025-09-21/rust-std-beta-riscv64imac-unknown-none-elf.tar.gz=9fd58b7c529d530e8b894a24e7f3a33d291d7305357c7cf52bbe708cde28c381
+dist/2025-09-21/rust-std-beta-riscv64imac-unknown-none-elf.tar.xz=f62de7e74f558a27bc2ef04897ad2f4fdfc162a17f21fde8efb2ba15435d80f2
+dist/2025-09-21/rust-std-beta-s390x-unknown-linux-gnu.tar.gz=3e97b06bc72aa51aafd2d2f65b4c4d9ab08599c2616729b79dbd9c51886ab6f4
+dist/2025-09-21/rust-std-beta-s390x-unknown-linux-gnu.tar.xz=8f149e17d654de210a71ace9db03f23bd1a80d0e2c17f8336da2b1ec2315c8a0
+dist/2025-09-21/rust-std-beta-sparc64-unknown-linux-gnu.tar.gz=ae6f3a738f1793fb9659e7613811b2ac151e91e3d8e470166b6ae615e5a285b2
+dist/2025-09-21/rust-std-beta-sparc64-unknown-linux-gnu.tar.xz=92af1bc3beaf80a763aac682a15957d82771fc619d446fb4327f4e8be229438d
+dist/2025-09-21/rust-std-beta-sparcv9-sun-solaris.tar.gz=b1f5ef77e28e9ed25050b130299a1c431a851df8b11bd457393fd464a7a9c35a
+dist/2025-09-21/rust-std-beta-sparcv9-sun-solaris.tar.xz=e5d744447649c57f8238c7d020f405559185d644b9739cae53c6963cdb380ea1
+dist/2025-09-21/rust-std-beta-thumbv6m-none-eabi.tar.gz=964c824519d8f352ea049766c428e6409549f7a4921c50f91dc548f2ec7f65f0
+dist/2025-09-21/rust-std-beta-thumbv6m-none-eabi.tar.xz=2f3b6d4781b21902e5f6986b75f3a0617198bad4741d4a9b957ab5ae2beab05d
+dist/2025-09-21/rust-std-beta-thumbv7em-none-eabi.tar.gz=7a95faa851ac8dff7f57cfa42169018b29683fbe06dbcf29e2cb311a0c880e84
+dist/2025-09-21/rust-std-beta-thumbv7em-none-eabi.tar.xz=deb1eafb4cdad0391bad8dd0657577d4c0960fb7fad7b7552ef1e662c4c1f12a
+dist/2025-09-21/rust-std-beta-thumbv7em-none-eabihf.tar.gz=1b35c7e25986065e63dfe8e8a1824bf13b62daa5777f32b140f03d0f4fe5cd1e
+dist/2025-09-21/rust-std-beta-thumbv7em-none-eabihf.tar.xz=335b28756025f8454ae7c6ef6760a512f0b59385cdeacc7dca0ea1bfe5e9a703
+dist/2025-09-21/rust-std-beta-thumbv7m-none-eabi.tar.gz=2291b4c7f27fa0408f394c48390cfd6c7144db5cc4e51c8891c3bb24300b8421
+dist/2025-09-21/rust-std-beta-thumbv7m-none-eabi.tar.xz=16b6104ae79bc0f3fa6d862c72cb3f35a9f67bbea7f9aee7b2a3b0c810225c6b
+dist/2025-09-21/rust-std-beta-thumbv7neon-linux-androideabi.tar.gz=6a7f167dd4c457d6185ee47dc206d19d6ca93e3e0418b21c0745d84c53995e64
+dist/2025-09-21/rust-std-beta-thumbv7neon-linux-androideabi.tar.xz=4fb366719cdadec26e88d64154b2b1b459affe5b894b426a0509681d173cf823
+dist/2025-09-21/rust-std-beta-thumbv7neon-unknown-linux-gnueabihf.tar.gz=3ff578be0c8b1171c5c2d0aaa3f4fc20f3a252f5adf050bd5856b201cc22841f
+dist/2025-09-21/rust-std-beta-thumbv7neon-unknown-linux-gnueabihf.tar.xz=16c518c3daf87722a5e2556e92e97d429a06b2ed2c79380989db04ffa4791279
+dist/2025-09-21/rust-std-beta-thumbv8m.base-none-eabi.tar.gz=b1d67e62ac198fcff25c29e731f2dca9eba3fbb09adb29db68d823b0ad63e85b
+dist/2025-09-21/rust-std-beta-thumbv8m.base-none-eabi.tar.xz=ac586b0a3cd91eb2928861ded895b96a85880851df2f3e63c2391cb38d98d140
+dist/2025-09-21/rust-std-beta-thumbv8m.main-none-eabi.tar.gz=93cfb0ceb07879366ecb4e00caf5b4459574852943363b0d6fd3293c4a0c27eb
+dist/2025-09-21/rust-std-beta-thumbv8m.main-none-eabi.tar.xz=879724fc40ca55193760b3739387dc237587e91c30e334709d5453e07840d4d0
+dist/2025-09-21/rust-std-beta-thumbv8m.main-none-eabihf.tar.gz=7eb1217837173f0974f7a0fc69b0e9fea484f2d457f3b193ca3b2c04ed83bcd9
+dist/2025-09-21/rust-std-beta-thumbv8m.main-none-eabihf.tar.xz=c38af1e6560589be7a0733508b800e68bb5b57f2ec3c5452fb14000cf9ef2fa0
+dist/2025-09-21/rust-std-beta-wasm32-unknown-emscripten.tar.gz=9475cb292c64491c545a02df4deae77d4174d77db18a84c8db635ae6de691b8e
+dist/2025-09-21/rust-std-beta-wasm32-unknown-emscripten.tar.xz=6e477e9ea0e5bac0b567deacfba3c236ceda28fab4d63c011d6bc54ac22c8570
+dist/2025-09-21/rust-std-beta-wasm32-unknown-unknown.tar.gz=eb7bf16e819eabe3f685bb8dd09bfff31d35d87cf03535195c411ec1738b6647
+dist/2025-09-21/rust-std-beta-wasm32-unknown-unknown.tar.xz=05a2bc1539b02ef314b268fc2860836c111705b872d5d56ba6ea511cb47e7169
+dist/2025-09-21/rust-std-beta-wasm32-wasip1.tar.gz=aa34f89676c72a3ce5df82cd819466631ed91896dd7a1b64fb4ca9a97595e254
+dist/2025-09-21/rust-std-beta-wasm32-wasip1.tar.xz=ad5756f4ce3e0309d04746609abdee2152fae66383b2b13d338c900b8f787060
+dist/2025-09-21/rust-std-beta-wasm32-wasip1-threads.tar.gz=36c42b952305d381718c36f34c4d5c1705aec71f946eee56c685eae56f9c40d1
+dist/2025-09-21/rust-std-beta-wasm32-wasip1-threads.tar.xz=c0285e26be272e3e832a74f22960899ac0f350dc6764701df748541ddbf69377
+dist/2025-09-21/rust-std-beta-wasm32-wasip2.tar.gz=198d4cb5195fa1e992cec8bf84716eed1ade0e9a8cc3981f3fb3cb9971e2796d
+dist/2025-09-21/rust-std-beta-wasm32-wasip2.tar.xz=0fd2cd8923741931aa17d1571a5f8c20c9b0e96d74dc75ab47cd9245586bfa03
+dist/2025-09-21/rust-std-beta-wasm32v1-none.tar.gz=cef69dbdfbd0352bf781c1e59129c29c17a6c1367aa00184be309c56f8f29dfe
+dist/2025-09-21/rust-std-beta-wasm32v1-none.tar.xz=a412840ff9550e447a2608a9c26ec02e969b2579bfe5c635a3af0cccd011922f
+dist/2025-09-21/rust-std-beta-x86_64-apple-darwin.tar.gz=290fefcf45ff24a79459c44523bfbbeeaf9eb9bf3e7e64fcab64368fe21ed2d7
+dist/2025-09-21/rust-std-beta-x86_64-apple-darwin.tar.xz=176634d6797df21873c317b93cecfc32f415b3248139a32bfdbee83607e734c1
+dist/2025-09-21/rust-std-beta-x86_64-apple-ios.tar.gz=639916204bcc229bd5d5fd1ccb455d9a962a11d05388252c1e5e310d424f1ef6
+dist/2025-09-21/rust-std-beta-x86_64-apple-ios.tar.xz=c0c597f428fdc8f2f89e26c0e5d9debef45ec449b869ea0a738102a8727e8da4
+dist/2025-09-21/rust-std-beta-x86_64-apple-ios-macabi.tar.gz=debfb6dfe448e345cc934e5a0d09715ca899ed9593c26eab07c58c41683113f4
+dist/2025-09-21/rust-std-beta-x86_64-apple-ios-macabi.tar.xz=a9b6b2de9e26182f5a37a8ff56487916379809b2afe9e14d34ee55f98d526267
+dist/2025-09-21/rust-std-beta-x86_64-fortanix-unknown-sgx.tar.gz=2517ded939281e8722e5ca6d2cdff6a78a4fa39b5828a3048d9f25a3ec40bbea
+dist/2025-09-21/rust-std-beta-x86_64-fortanix-unknown-sgx.tar.xz=7e8efa9cb373f580c46fa348b1f76acb46456c71fb6afea2b22d5a16b90ce28a
+dist/2025-09-21/rust-std-beta-x86_64-linux-android.tar.gz=2bb9470fe62c5c1e1d31f63544b2bedb833c07c5305448e46283b48d8a575d65
+dist/2025-09-21/rust-std-beta-x86_64-linux-android.tar.xz=66a024fd9bda49ff4db5d70a2dc094708ef73c027ad0aa7dcbd7cea8449b151f
+dist/2025-09-21/rust-std-beta-x86_64-pc-solaris.tar.gz=104b17a08a01593195921a56153a2b54782640f9dbf9e59c7da9f29afe3fe4aa
+dist/2025-09-21/rust-std-beta-x86_64-pc-solaris.tar.xz=c3950a3a8bdd1326ab7d0ac08dc2a4f5c354e9ef6447324145cbe9fdef54f026
+dist/2025-09-21/rust-std-beta-x86_64-pc-windows-gnu.tar.gz=d1d998991c9c8107f919c851d327d730beb6d4f4937a9f8dd2de2fbade1c1dd6
+dist/2025-09-21/rust-std-beta-x86_64-pc-windows-gnu.tar.xz=654322ad813f9414e7ba2c5c5cb141db234d73b9ad237595d844dad564917a98
+dist/2025-09-21/rust-std-beta-x86_64-pc-windows-gnullvm.tar.gz=6b9323f0bc1055dbf3e5fb4ec5fa09f28b7a0cd04ee8bb40e727d85d1a5225b5
+dist/2025-09-21/rust-std-beta-x86_64-pc-windows-gnullvm.tar.xz=3ea958ef88fc3334e98556fd3bcc00264d9dd75cccf6f19f6f5514ec447d0557
+dist/2025-09-21/rust-std-beta-x86_64-pc-windows-msvc.tar.gz=ddfbb760544eb8a7562cc8fab7cf313d45f490dacde3575329f627546971db0b
+dist/2025-09-21/rust-std-beta-x86_64-pc-windows-msvc.tar.xz=25f8e1279fc8647e117c6f3dbf3f4059e7ddc058cf6e02b43f499a72bee6ebbe
+dist/2025-09-21/rust-std-beta-x86_64-unknown-freebsd.tar.gz=2941d17a2370ecab1e839236ba092c065cfa1b94e448a77a5851dab9ec2f1a59
+dist/2025-09-21/rust-std-beta-x86_64-unknown-freebsd.tar.xz=ff2aae7c2e37e48f500df5876c3a26d3dd10affd04e888ce54a4635a5345efa6
+dist/2025-09-21/rust-std-beta-x86_64-unknown-fuchsia.tar.gz=1cdbbbdf1aa9c6e764493576adbd962e004ff029b064089be35910768f409579
+dist/2025-09-21/rust-std-beta-x86_64-unknown-fuchsia.tar.xz=8196d32e28630a3ccc1dc96d9abb3efb5f2090b7bdce9963b2579995f575435c
+dist/2025-09-21/rust-std-beta-x86_64-unknown-illumos.tar.gz=bbe4419e2d9f5bee75f6c1f7b0cf272100e3a37aebc28bc626820c886fabec47
+dist/2025-09-21/rust-std-beta-x86_64-unknown-illumos.tar.xz=2fc8f8ccd022152a87a447079169340218d7541b3513eed36cf7af20d5f565ce
+dist/2025-09-21/rust-std-beta-x86_64-unknown-linux-gnu.tar.gz=222198fa6b782010beac1710693ee1aeac1ad7eb9ac183625128de788a1a4bfd
+dist/2025-09-21/rust-std-beta-x86_64-unknown-linux-gnu.tar.xz=b60da22feb82c21128a151013c690cdef1c291de33e1b6ada5dcc95d3bff3899
+dist/2025-09-21/rust-std-beta-x86_64-unknown-linux-gnux32.tar.gz=31ab3940e428fe58ac584c33072be16d31edb0c16df379d9847cb904947126cc
+dist/2025-09-21/rust-std-beta-x86_64-unknown-linux-gnux32.tar.xz=8304e2e4440e0a91b05bfe58bd44e7087c28c2682a1a5f5b659e2aba708463fb
+dist/2025-09-21/rust-std-beta-x86_64-unknown-linux-musl.tar.gz=c15ecaa46a814cfd5fa27b29aed9e0e578a652b8f6392b916341d30172da7ede
+dist/2025-09-21/rust-std-beta-x86_64-unknown-linux-musl.tar.xz=08a84716ed6bc70a58841c5d61216a781b8a947bbb5fb5ebde757e537a2e5dd3
+dist/2025-09-21/rust-std-beta-x86_64-unknown-linux-ohos.tar.gz=5f1a8ed2093099b18cc83eddb304234f201f8ab137ae950c73329156570ba975
+dist/2025-09-21/rust-std-beta-x86_64-unknown-linux-ohos.tar.xz=ebcd581394fd243eac3d683e334d73ef3d3bbaf7de28bd4082329683e2c770c1
+dist/2025-09-21/rust-std-beta-x86_64-unknown-netbsd.tar.gz=430f4b7f7eceb5e633bccafa9acf08095c1aa4b3dfaa94734fcd331b3d69ca44
+dist/2025-09-21/rust-std-beta-x86_64-unknown-netbsd.tar.xz=2e403587de5c02ba9c5f9f2515d4c9fdffde59cec28c8dcafdfe40d03e4f3152
+dist/2025-09-21/rust-std-beta-x86_64-unknown-none.tar.gz=84d695e6f19706fdd7c01dbfc4607f310e8495f57c29bad2476e00c7bb269646
+dist/2025-09-21/rust-std-beta-x86_64-unknown-none.tar.xz=6e12698afd8a6743a9a6a011ad67ab16d5a40b6dbf1d09104b8294ea95fc2636
+dist/2025-09-21/rust-std-beta-x86_64-unknown-redox.tar.gz=cadafa58684734fc43417742d9151aea36b62f82aa3cd7b858140ce31e9a6ce6
+dist/2025-09-21/rust-std-beta-x86_64-unknown-redox.tar.xz=f1089cab004cb67134bbac6d8acb09b4dd5e02010e069790e13970b004ca4ab5
+dist/2025-09-21/rust-std-beta-x86_64-unknown-uefi.tar.gz=2dbc6eec98b7d730fe2ba982d78f7331346e9018146597200340256d28c0aaf2
+dist/2025-09-21/rust-std-beta-x86_64-unknown-uefi.tar.xz=8a5896f3301a6238984114cf52f7f234bdcb712cb6d914093159ecc82904ba7e
+dist/2025-09-21/cargo-beta-aarch64-apple-darwin.tar.gz=4c6172e8523576deaa6c83274dbd993338d545a794e42aca3c074450d7e7cea0
+dist/2025-09-21/cargo-beta-aarch64-apple-darwin.tar.xz=5e8978daaaed1304e94c071ab5414ce90eb9c7bd1c4f1c8c5f4ff515f6558851
+dist/2025-09-21/cargo-beta-aarch64-pc-windows-gnullvm.tar.gz=49cba73291916ddf2e4912d4ea02add165f2786ad7f7b8885628d92579cbebd8
+dist/2025-09-21/cargo-beta-aarch64-pc-windows-gnullvm.tar.xz=d60a0a176b7d15606f6ee31b67d4a5ac6735e5a0b012022e9212fe723bddec48
+dist/2025-09-21/cargo-beta-aarch64-pc-windows-msvc.tar.gz=dfd4aa83d38a6236789676ef02c81382f0741671ed9a973cd74d37c65b3f111a
+dist/2025-09-21/cargo-beta-aarch64-pc-windows-msvc.tar.xz=8ab6cd565993b58c6e2169bfb468c441dd385c5336081c45f6a60608522ce549
+dist/2025-09-21/cargo-beta-aarch64-unknown-linux-gnu.tar.gz=eb361e2d12c90c9380112ef48b81db1b41f04b4ae08cd061fe1caa46cca9ce6b
+dist/2025-09-21/cargo-beta-aarch64-unknown-linux-gnu.tar.xz=e9f4c66995b8e955e86a67c44fd8d7f6e7349645393bfa605c6c1bb0afc7b930
+dist/2025-09-21/cargo-beta-aarch64-unknown-linux-musl.tar.gz=dc88806e5ac4004a9a3cb24f0c850fde2c22b0e38e6ad84bd570069043485bfc
+dist/2025-09-21/cargo-beta-aarch64-unknown-linux-musl.tar.xz=e103f1d074ab105d03a88066363d2b103508ec95c18cbf8b1f92d0f473ddbf40
+dist/2025-09-21/cargo-beta-arm-unknown-linux-gnueabi.tar.gz=e35bcf36bd7578cdbccb60d554feb19f8376fd41850e4e8046e0b2f931040c01
+dist/2025-09-21/cargo-beta-arm-unknown-linux-gnueabi.tar.xz=ff1b46781284948aaf8c8f582203877ffda5a78d86c266bf724fbb08503a6e80
+dist/2025-09-21/cargo-beta-arm-unknown-linux-gnueabihf.tar.gz=dd657b5eb50264c90fafbd967b20768d9e4df14ef179902420b3f9a3e2145271
+dist/2025-09-21/cargo-beta-arm-unknown-linux-gnueabihf.tar.xz=3f821c437963aec534cdbd686f719eb86bfe41cf254ed5395730f7827d45a68a
+dist/2025-09-21/cargo-beta-armv7-unknown-linux-gnueabihf.tar.gz=7874b945f3d77e2a8ca308e5400a2411ab4f615f45a036bd9fab8a74434c309d
+dist/2025-09-21/cargo-beta-armv7-unknown-linux-gnueabihf.tar.xz=39523f09c76473d10b91ee946523976e01dc337d2af067f08168f1d9cb44226a
+dist/2025-09-21/cargo-beta-i686-pc-windows-gnu.tar.gz=43b095acb25cf5c0dbfffc6fbc864c2b2415251931b149b282d5e70844fc2c50
+dist/2025-09-21/cargo-beta-i686-pc-windows-gnu.tar.xz=6cac1a1a6d74765f4233908920d295761570ddcd8cf3638bbc8f8eb427084b92
+dist/2025-09-21/cargo-beta-i686-pc-windows-msvc.tar.gz=7f4314596e6ea01a35b9e2e250227a74b5d4bd772ac8d33d12bd44f8c11b37e5
+dist/2025-09-21/cargo-beta-i686-pc-windows-msvc.tar.xz=eeaca23bf3cafbd01cdcef890d02ecd622d3ccfd6d9830f1e599d29acfa371bb
+dist/2025-09-21/cargo-beta-i686-unknown-linux-gnu.tar.gz=e79e3a25bb790c5f6ed9e81a0559a55750a1a3e35250f0fc5fd92c195625aa28
+dist/2025-09-21/cargo-beta-i686-unknown-linux-gnu.tar.xz=1fe31a0e463736a9ae90ef11c1e3c7b7972eb82779ecdf5b6bff1f643684a014
+dist/2025-09-21/cargo-beta-loongarch64-unknown-linux-gnu.tar.gz=917db09ef343b6702c1410c2c68070c4bcfd90f6951591490a6a237290a4aed3
+dist/2025-09-21/cargo-beta-loongarch64-unknown-linux-gnu.tar.xz=222010f8428a3d165801d95a820b639ac930747af3cb4a42a25548330585f73e
+dist/2025-09-21/cargo-beta-loongarch64-unknown-linux-musl.tar.gz=7e949bc169a58e450e58088fd716aac9a05f5fca0790d94dd211ce823c2c5d36
+dist/2025-09-21/cargo-beta-loongarch64-unknown-linux-musl.tar.xz=dfeb99ac76e18160aee7ff1c878b44b9fdb725f7be28609e637bd372aab448a3
+dist/2025-09-21/cargo-beta-powerpc-unknown-linux-gnu.tar.gz=523103d950944aed52578002dd372207b3bb38e4130b4b11097b03f7d55345c9
+dist/2025-09-21/cargo-beta-powerpc-unknown-linux-gnu.tar.xz=db5c4ce1a1a4d87cca4fb64a6c533cc5ab1c94e25e69b26e13808b0fa5e853e9
+dist/2025-09-21/cargo-beta-powerpc64-unknown-linux-gnu.tar.gz=68479082544f7f68a2fe073ed3d35e1895643f8ab9abe9d0e968efa9f342de36
+dist/2025-09-21/cargo-beta-powerpc64-unknown-linux-gnu.tar.xz=8878cf473faf120efb80bac0564b193f3baa14a9027fb4c060574e6fc921edcc
+dist/2025-09-21/cargo-beta-powerpc64le-unknown-linux-gnu.tar.gz=eb37177cdbc9e2b7f9b74856b351bb764e5c2603366fd92a5c863cbad26e6940
+dist/2025-09-21/cargo-beta-powerpc64le-unknown-linux-gnu.tar.xz=92734c444e0156e16c8d8998a8432b24d9d01b82da15123508d0002eb008b9bb
+dist/2025-09-21/cargo-beta-powerpc64le-unknown-linux-musl.tar.gz=502d5d2ec61d9fcd5b92caa0b4f0aaa11f27fccb7ec4736e05beca313f306585
+dist/2025-09-21/cargo-beta-powerpc64le-unknown-linux-musl.tar.xz=e00bc0ef1784b2f7b1fdbb757cd50342cacc49f7f5d2d3f7b36f9f4eca23882c
+dist/2025-09-21/cargo-beta-riscv64gc-unknown-linux-gnu.tar.gz=3e00c4c0d64977ddd2fcece9407a01f92ec9b44ea37d72ebbdb77cf0c532163c
+dist/2025-09-21/cargo-beta-riscv64gc-unknown-linux-gnu.tar.xz=3be5932af030c758a84bc09cbb1c2bc5abecc4e7d8a82de58c2a069ad36e737e
+dist/2025-09-21/cargo-beta-s390x-unknown-linux-gnu.tar.gz=aefcadb257bbcf93dda58526390962316b4e579707c043c45e52bfd4d7a097dc
+dist/2025-09-21/cargo-beta-s390x-unknown-linux-gnu.tar.xz=3d163f9fdc2b8b0f5cbbf846caf1dccaee07984d8783250e8988ef447e53663d
+dist/2025-09-21/cargo-beta-sparcv9-sun-solaris.tar.gz=bc1692d8d75654012a823adb40b87d3b5721b19beb49a30b404a6c78f431c944
+dist/2025-09-21/cargo-beta-sparcv9-sun-solaris.tar.xz=ff7f36d7832b094b9ca2132df4851cf0ca50c9fc2de3d55bb6c75b46dd028f10
+dist/2025-09-21/cargo-beta-x86_64-apple-darwin.tar.gz=1a67e618eeadf362e868bf2cb35c1a312db83d1a59cee38f61794e45cba3ba4e
+dist/2025-09-21/cargo-beta-x86_64-apple-darwin.tar.xz=28c0ae4f78f37abe27a3db5e5fb8c78c51a98b71cd0c4c69f9256b5d4064e78d
+dist/2025-09-21/cargo-beta-x86_64-pc-solaris.tar.gz=c2da94328a164d889ebbbcd5f403068126e8f28ebc0c4ff7bf5cde1e8cc380b4
+dist/2025-09-21/cargo-beta-x86_64-pc-solaris.tar.xz=4fb30f600f8a10f43bfbf4361fbc7e906217007d46d65731b1bae0007eaca783
+dist/2025-09-21/cargo-beta-x86_64-pc-windows-gnu.tar.gz=86e23a551906f961a8a05b50185185de683f824a69bc739c3786e4f2004d83f8
+dist/2025-09-21/cargo-beta-x86_64-pc-windows-gnu.tar.xz=860562d5c50c60233d088886dd22b23c0c40504107b04cdfb51506c631d948ba
+dist/2025-09-21/cargo-beta-x86_64-pc-windows-gnullvm.tar.gz=b568148f13e609e6cbb7e2b424c13a8b85126c8ef84f3b884043aab204352615
+dist/2025-09-21/cargo-beta-x86_64-pc-windows-gnullvm.tar.xz=7983768e6c77334eedd563cea4cd51cbf85d5234d1952801783016f07f1d6ce7
+dist/2025-09-21/cargo-beta-x86_64-pc-windows-msvc.tar.gz=839f7866c75750a5fdc0e7b9fdf37e0b60e71be916b496a9be3ecedc87473c2c
+dist/2025-09-21/cargo-beta-x86_64-pc-windows-msvc.tar.xz=5d0e3c8e9082a00be80cc3924e12b7d9d067f9ecfbe14dd1e1bfadff55d2bccd
+dist/2025-09-21/cargo-beta-x86_64-unknown-freebsd.tar.gz=8c22ee4fb01955f20d04dba271b44e69718266d70610fbd979565d95df316e6b
+dist/2025-09-21/cargo-beta-x86_64-unknown-freebsd.tar.xz=6356f4d133c3820736f82c4eb2857548b5255af4ead57f1f8e66ebc6aaa628ed
+dist/2025-09-21/cargo-beta-x86_64-unknown-illumos.tar.gz=43523fa8da79aca1e5a618c10ea031404250cdf1a41b0da369ed6efd05c4190e
+dist/2025-09-21/cargo-beta-x86_64-unknown-illumos.tar.xz=c9a1b43c762b3658b0fac5145c6314a1c9e416d025ac22958fc0809fbb24d1e0
+dist/2025-09-21/cargo-beta-x86_64-unknown-linux-gnu.tar.gz=ba780983f067e7dbcce49dd4d39a0d3c0002dbe7dba73eb2a98d7eae17f70931
+dist/2025-09-21/cargo-beta-x86_64-unknown-linux-gnu.tar.xz=07aa13a5411a49238b31191a0797d63b74120a1fa9b5658a67f6c1065271c30c
+dist/2025-09-21/cargo-beta-x86_64-unknown-linux-musl.tar.gz=96e6367138d6ff9ae2ca4343f3d5277b5fce39fe6909cfccdd57f1867eb9b021
+dist/2025-09-21/cargo-beta-x86_64-unknown-linux-musl.tar.xz=83e6fb5196805c9bdfca4e80e76e185a885da0820108e98e1fc7ef4aeea7f1e5
+dist/2025-09-21/cargo-beta-x86_64-unknown-netbsd.tar.gz=422fdb2cc97767f235d6abb29dbb0e802b320e11c743f794f8ad13160e4c7c7c
+dist/2025-09-21/cargo-beta-x86_64-unknown-netbsd.tar.xz=75c4aee9a720fa55ac5e80c58a890efbf88c57fbd2c57043b9f29bdbd6ae0e3b
+dist/2025-09-21/clippy-beta-aarch64-apple-darwin.tar.gz=de39b5014bffa7e20ae1f981616664703828428b6b1a74a6fee80fbab446e74e
+dist/2025-09-21/clippy-beta-aarch64-apple-darwin.tar.xz=d5ad3181f6978604f725db8607daf39ee20cbbb6ade35bb50ae7b032b0b62e9f
+dist/2025-09-21/clippy-beta-aarch64-pc-windows-gnullvm.tar.gz=a4f5538776b2f1f31bef81f37615d9bc3495080174fe83be0c549508923c9e9b
+dist/2025-09-21/clippy-beta-aarch64-pc-windows-gnullvm.tar.xz=a78a56cf381483703f120c596d6921b04aface91847310e20da53aa887a2e603
+dist/2025-09-21/clippy-beta-aarch64-pc-windows-msvc.tar.gz=06a6ee3aa204812322d0b9946ea31dbc5045e59253891fea7e079d4c7e1de894
+dist/2025-09-21/clippy-beta-aarch64-pc-windows-msvc.tar.xz=a4f0add69dad90f0dd7c47966b12f6cb7a4c6e34cc1b44e4a816d359659ae012
+dist/2025-09-21/clippy-beta-aarch64-unknown-linux-gnu.tar.gz=9d88fade821957052581f65765ae84286eee07e0985504d5a7324f615649a506
+dist/2025-09-21/clippy-beta-aarch64-unknown-linux-gnu.tar.xz=0c278a9aaa1ae41bd9bd96f52fed50b1a11a65822024fd01a9eacfa3aa8f1de9
+dist/2025-09-21/clippy-beta-aarch64-unknown-linux-musl.tar.gz=7d04aeb77402ca2ad964b6430ad75d0ec08a68efb505573f5e134664a5aae044
+dist/2025-09-21/clippy-beta-aarch64-unknown-linux-musl.tar.xz=d28207a804219edccb110160ffdf1c1525248ac225df89f4d11e3538a5dd0dcb
+dist/2025-09-21/clippy-beta-arm-unknown-linux-gnueabi.tar.gz=2433be238da05b6dbf44a74537e48a1dcd96fc03a8059ab78e553833546f1b97
+dist/2025-09-21/clippy-beta-arm-unknown-linux-gnueabi.tar.xz=74d5920785504fbc0c1e0237a4ee4e8355ffeba2c4bd9471c38d44e3ae52ef4d
+dist/2025-09-21/clippy-beta-arm-unknown-linux-gnueabihf.tar.gz=f83867145c740302ad81912f8e39433aac19fa5312f14d35aee2b59638660299
+dist/2025-09-21/clippy-beta-arm-unknown-linux-gnueabihf.tar.xz=420c7b7b6cf54eb27fc3446223ab03a3f90628b47d6b4ae66e432380b57661ad
+dist/2025-09-21/clippy-beta-armv7-unknown-linux-gnueabihf.tar.gz=14eefaa624591a49d6d2a3af9663ea4f3aca804d3563f668c734d9e18cc0b39b
+dist/2025-09-21/clippy-beta-armv7-unknown-linux-gnueabihf.tar.xz=14e8371566643fdf146117d06b9fa77aa886360d3696d9e43482f288338822b6
+dist/2025-09-21/clippy-beta-i686-pc-windows-gnu.tar.gz=b7ceb33faebadc67294e1df3f08d8d9760a6a17ca1ad30f26da3c586487a14c6
+dist/2025-09-21/clippy-beta-i686-pc-windows-gnu.tar.xz=f0a3f41a65d90119a4c66c6a2007d1f1a75a24e86d9a572837c4410b02af426b
+dist/2025-09-21/clippy-beta-i686-pc-windows-msvc.tar.gz=dbdf0cae38daed8bee11eb63d7c3f1c5d019777c238495149baa5ccb10af0f37
+dist/2025-09-21/clippy-beta-i686-pc-windows-msvc.tar.xz=adc49c09b72ff46d3d03f31c8c641675af389ba99c4c517149a10ae471c37c25
+dist/2025-09-21/clippy-beta-i686-unknown-linux-gnu.tar.gz=793ace0c8927a48caf443b794de097895f9e503299da07da13238a56ea8ac07e
+dist/2025-09-21/clippy-beta-i686-unknown-linux-gnu.tar.xz=22b9b2b27d0b6b1fd88d67b18d34a4a91207e6b64ba8d47dbfd0c58763d429b3
+dist/2025-09-21/clippy-beta-loongarch64-unknown-linux-gnu.tar.gz=101437e0f1bdc8ca07455d92c87bc32914a5047f6c9d7b7ab9e34799c5d4a5a3
+dist/2025-09-21/clippy-beta-loongarch64-unknown-linux-gnu.tar.xz=afd8c55fa82482a852b564511c4fdddf12abbffc0bbee1b0b4155fd1d6c04105
+dist/2025-09-21/clippy-beta-loongarch64-unknown-linux-musl.tar.gz=df33c329856ed057d069a479181b4fa97fd4a11d109abfa32d6b46c36215e6f3
+dist/2025-09-21/clippy-beta-loongarch64-unknown-linux-musl.tar.xz=ca8451dfcb5b919c1a6510616c8e93dfb15914e689cb30f7debf4c1a4aef58fe
+dist/2025-09-21/clippy-beta-powerpc-unknown-linux-gnu.tar.gz=1b738f58256186f0b530375ea2da804aa1834a908412e56767c9a44b134cfd68
+dist/2025-09-21/clippy-beta-powerpc-unknown-linux-gnu.tar.xz=93333f47a041d4ddea4fd9ad3fb3ab43c40fcee4fabe6405190fa26d6bfe3e2a
+dist/2025-09-21/clippy-beta-powerpc64-unknown-linux-gnu.tar.gz=2f0da38cf8efcda85634249df5398bb99f3b34982fb4509a0a3171437d809ab0
+dist/2025-09-21/clippy-beta-powerpc64-unknown-linux-gnu.tar.xz=fb3d68e09e40cbf7d6c330c3866c37c759ed728c1d8cbeb6e8e834f6a1fce1c9
+dist/2025-09-21/clippy-beta-powerpc64le-unknown-linux-gnu.tar.gz=7cb5fdfebbc0565e2d883da09815dfb626104afe39c01b169a919a82f62df607
+dist/2025-09-21/clippy-beta-powerpc64le-unknown-linux-gnu.tar.xz=d6705b1e6722e3faf5b863fb319cd811fcb27f4a564e633f164f02f8699c9255
+dist/2025-09-21/clippy-beta-powerpc64le-unknown-linux-musl.tar.gz=ea33f22a67f7c8354e7421129bfcbfb4bce7d909fcfa6a64a3107d82be69d213
+dist/2025-09-21/clippy-beta-powerpc64le-unknown-linux-musl.tar.xz=081e303cf123ddc162633d4d1e3adef4e6fd39598f60ac9dd75c76230df39ddb
+dist/2025-09-21/clippy-beta-riscv64gc-unknown-linux-gnu.tar.gz=76ac5dc8b8284437e5fe81cb4978460a6aa5c4a857c4f14246dfabf1831998f4
+dist/2025-09-21/clippy-beta-riscv64gc-unknown-linux-gnu.tar.xz=2ed67a738a07e9d07c1db7789cc5ebe7af033334670fcb1ce84441b9e474ec0c
+dist/2025-09-21/clippy-beta-s390x-unknown-linux-gnu.tar.gz=d5a7e6cfdd099ed18e54d88dc1d740b90d1f7d2f22d1fe6ca7960b7319b0783a
+dist/2025-09-21/clippy-beta-s390x-unknown-linux-gnu.tar.xz=78231b81d8e612a4c41828428ba2e9af926f2119308b291c8ce81a5233c3c6a6
+dist/2025-09-21/clippy-beta-sparcv9-sun-solaris.tar.gz=a1b0086259586a26f6ca65b02adea83b953989a508385d58fa56c7eafb770227
+dist/2025-09-21/clippy-beta-sparcv9-sun-solaris.tar.xz=b58151b098d58b19bc900f72813138799e2e568a5ad3038528045e5ac562606e
+dist/2025-09-21/clippy-beta-x86_64-apple-darwin.tar.gz=62ecc253fa747ec67ae11c7a1672661cbac7d78c1001654e17ca5c0e3bd72d91
+dist/2025-09-21/clippy-beta-x86_64-apple-darwin.tar.xz=b7e9785d3ab00163a0070b7772a4354e9503cdb8456d1a2b0708920658aac614
+dist/2025-09-21/clippy-beta-x86_64-pc-solaris.tar.gz=783d47012b943cd4497c2e0e854cd7727b0957518178165cc1cbc4dc5e6509ff
+dist/2025-09-21/clippy-beta-x86_64-pc-solaris.tar.xz=94efccbbe73b2f15f5f86c90324b3adbd1b58bbdb81ea9c32d7efaf067bc6795
+dist/2025-09-21/clippy-beta-x86_64-pc-windows-gnu.tar.gz=8b12cc5e7b9b7e0b234a29886c81455878e806067c025cf3d26eef4a52e08bc5
+dist/2025-09-21/clippy-beta-x86_64-pc-windows-gnu.tar.xz=35fc298fd25949b491c54bfa2f40c963d7ca530b65ac8e52031edf17624b3d05
+dist/2025-09-21/clippy-beta-x86_64-pc-windows-gnullvm.tar.gz=824e1590e12bcad69b43912068e27585466fcc5cf7a2f92f41f727aa39cbcaad
+dist/2025-09-21/clippy-beta-x86_64-pc-windows-gnullvm.tar.xz=6fad67e180d0eb0d551b2101dc27bf6846ae2840c63d1ef05588691d055e3806
+dist/2025-09-21/clippy-beta-x86_64-pc-windows-msvc.tar.gz=1353d8c3310d53576d94aa744fe0844b5527d8b54fe43a692042be78b0fca6f5
+dist/2025-09-21/clippy-beta-x86_64-pc-windows-msvc.tar.xz=a7ca6fecd77dc44f3102abad7fbe1fa3846d9ff6ea98a25d4c3bd703800894d2
+dist/2025-09-21/clippy-beta-x86_64-unknown-freebsd.tar.gz=33b5f8dd6a0ef045ad19df4327259a468ece00b250d9fbfe1be7c0f293f874ce
+dist/2025-09-21/clippy-beta-x86_64-unknown-freebsd.tar.xz=1bd56197e30fc325c7482aa7a42006a7ad9a0ffad9f3d74d209e98582d2897e4
+dist/2025-09-21/clippy-beta-x86_64-unknown-illumos.tar.gz=0ba3c497472c34de44bda2485d3b964cdab83e3700b44ffd8b41037ccf59a932
+dist/2025-09-21/clippy-beta-x86_64-unknown-illumos.tar.xz=040302a04decb3cfcd599b329db3f17e5f96b7aa4b8174d6f2b17ba19c991853
+dist/2025-09-21/clippy-beta-x86_64-unknown-linux-gnu.tar.gz=21fde20675c5f786b5da4f1be39785d1106f748d88a6609fd4976bfe372e6817
+dist/2025-09-21/clippy-beta-x86_64-unknown-linux-gnu.tar.xz=217255d6ea157f7b06aa66d033dca6239bbc296bc14ff3f0017d5c68bb4d1022
+dist/2025-09-21/clippy-beta-x86_64-unknown-linux-musl.tar.gz=7be4202a658df30aeba451e6dd4f740068dbcc769fe0eaa9a7eb8cb2c2e264ff
+dist/2025-09-21/clippy-beta-x86_64-unknown-linux-musl.tar.xz=d2cf3cfa0c5c67d57867586709c274e320c1a76418ffe7dcf65b271448d4de06
+dist/2025-09-21/clippy-beta-x86_64-unknown-netbsd.tar.gz=91f510466f2a8606efc746a5be209a1f0ffe1e20b803f9c54ee91786053cabbc
+dist/2025-09-21/clippy-beta-x86_64-unknown-netbsd.tar.xz=2c17d3a00885495f81cb8606ceb78674f63396b3c2a0b3415bb2e62ab39f9d87
+dist/2025-09-21/rust-beta-aarch64-pc-windows-msvc.msi=d5e39b0a1deaaeaf956e57da755e16255b265e80722428625783e7be0835cbb8
+dist/2025-09-21/rust-beta-i686-pc-windows-gnu.msi=edcb39b92d1e84c7d6b0d2559e37be673795a14e807e77e40b32dcaac8b9d415
+dist/2025-09-21/rust-beta-i686-pc-windows-msvc.msi=dac7d64336aa8fcc77761910392efc845aa2137fff8be8df980b02d48809bbd4
+dist/2025-09-21/rust-beta-x86_64-pc-windows-gnu.msi=44e1e8298714b11bc7cc44184f2b20aa39fbadc23f8b2b86005e74879b8430f8
+dist/2025-09-21/rust-beta-x86_64-pc-windows-msvc.msi=4c673f514c7f0f9bf780c2448fa4a4bbe4e4db618d6a9931bd092a6116d432fa
+dist/2025-09-21/rust-beta-aarch64-apple-darwin.pkg=4a23353da7a58deac032341011c7bdb78f069ff4bda97d837c67e54454e6e1af
+dist/2025-09-21/rust-beta-x86_64-apple-darwin.pkg=5e02da3f6ab8791426060ca40ac7c719451f6f5acba06ec27c273e6f2590cad6
+dist/2025-09-21/rustc-beta-src.tar.gz=22b0288ca9f949cac41260370afd4e6e487c1e3430f6aef23340b50ec4e4ea9b
+dist/2025-09-21/rustc-beta-src.tar.xz=31f4b8b4b3471e7063da5038fe5072e44293705ec65b2c272f8d4cdd37875ff1
+dist/2025-09-27/rustfmt-nightly-aarch64-apple-darwin.tar.gz=78627de068d788f65482cdb2763b27fb7570a197b97056ad16f9f6117fccff8a
+dist/2025-09-27/rustfmt-nightly-aarch64-apple-darwin.tar.xz=d6c4252e895d303337ce1c8edf2fcfd02078b81007e785ff7a15f773a1789e3e
+dist/2025-09-27/rustfmt-nightly-aarch64-pc-windows-gnullvm.tar.gz=d65ef7c1348a74dc1b042c30281ec57c2619a25bdfd8151223415f9d6e067fc5
+dist/2025-09-27/rustfmt-nightly-aarch64-pc-windows-gnullvm.tar.xz=dcd986e9560c45eae6f1d0ee0bce9ad2365d101f4c9b792062557cb26a26152e
+dist/2025-09-27/rustfmt-nightly-aarch64-pc-windows-msvc.tar.gz=8b5a164ee78ee9bf76c1ac9d95f63743cc0b05cff9823d42b88d596ee34c9b52
+dist/2025-09-27/rustfmt-nightly-aarch64-pc-windows-msvc.tar.xz=da675f08931285b2d59be0b8cda46f7489855ec9cc07a608d17e4c0f1e6de486
+dist/2025-09-27/rustfmt-nightly-aarch64-unknown-linux-gnu.tar.gz=7a1b11c66f3832e0ccd390441a921cd50a25ae87e641bb856966fd81cd3d5d59
+dist/2025-09-27/rustfmt-nightly-aarch64-unknown-linux-gnu.tar.xz=5f6aa12529624b66f1de643afe6805cf5484c57e3a7c791f85023d28b590dac2
+dist/2025-09-27/rustfmt-nightly-aarch64-unknown-linux-musl.tar.gz=0cc213fabdad76e6ff699f2f0462c8b3dfe5bdc6b14131fc2c87d915a8fdabbb
+dist/2025-09-27/rustfmt-nightly-aarch64-unknown-linux-musl.tar.xz=ca84ce0de6d11b69ddc691f4edca1474e66b513f695fab738374942d57ab8b83
+dist/2025-09-27/rustfmt-nightly-arm-unknown-linux-gnueabi.tar.gz=dc0f391a0ac09a8ae2271443584dc8f1338bc0b89b50ee82d47599912fb74c52
+dist/2025-09-27/rustfmt-nightly-arm-unknown-linux-gnueabi.tar.xz=d4bebefbc157ecde2fbf7f7ef6a6d8c703d264f56e2ca8a80b7c241b8e14f862
+dist/2025-09-27/rustfmt-nightly-arm-unknown-linux-gnueabihf.tar.gz=672fd91b880195a0fb2eb294129c0ec465aa3be217451fd4b835b2c3294d4c1b
+dist/2025-09-27/rustfmt-nightly-arm-unknown-linux-gnueabihf.tar.xz=4aa45c993b82f9d9f6b8bf79db2d04acb83cd70147c9ecb1804a3c8258a6c022
+dist/2025-09-27/rustfmt-nightly-armv7-unknown-linux-gnueabihf.tar.gz=3a8fef72bf471ea1c575c3a6d3a0ffb957fd862f55afb0d40b39c85ff7fc1f13
+dist/2025-09-27/rustfmt-nightly-armv7-unknown-linux-gnueabihf.tar.xz=08854b212790685caa928e37aa7fe50009590050873c390d2999d6b814bcd2bc
+dist/2025-09-27/rustfmt-nightly-i686-pc-windows-gnu.tar.gz=e99f0d4b314c59b7564e85be580477e751e46acf30752b970c36aa9719e10995
+dist/2025-09-27/rustfmt-nightly-i686-pc-windows-gnu.tar.xz=ba3b9a0e0c44c6edc1396915034efe9e7f59e0724271fd6c1fd4805382e95677
+dist/2025-09-27/rustfmt-nightly-i686-pc-windows-msvc.tar.gz=40f42081d1d2eec00bf49f62c12d75e5e5c345e2a4d8da4fa0741239aea72218
+dist/2025-09-27/rustfmt-nightly-i686-pc-windows-msvc.tar.xz=1b9ef88c7ea98880835d8c298625e2bdd219af46eabb18b8c18c92882d81d054
+dist/2025-09-27/rustfmt-nightly-i686-unknown-linux-gnu.tar.gz=2ff88b8231c70044e9b35c3855515d143aac1b3d7a82bfc84833f76f45539c97
+dist/2025-09-27/rustfmt-nightly-i686-unknown-linux-gnu.tar.xz=e07bab9116c10576b7ab01e26af72bdc97bd34a56aa2468e188e58864b030c33
+dist/2025-09-27/rustfmt-nightly-loongarch64-unknown-linux-gnu.tar.gz=766a69e69be097f710a7c175dbfa39b20970135a6fe420457191e095de5fab1e
+dist/2025-09-27/rustfmt-nightly-loongarch64-unknown-linux-gnu.tar.xz=ad4a38853cb9e6bb6029dbb2ffedf4b49dfc7cb696edbcb561b204bfa89fd8d8
+dist/2025-09-27/rustfmt-nightly-loongarch64-unknown-linux-musl.tar.gz=f08d5f5ac31fda285b81069709a74eb382450543c4d22289980a9ef94a473fac
+dist/2025-09-27/rustfmt-nightly-loongarch64-unknown-linux-musl.tar.xz=40bb1e41db10d4c6b22e46c0f8b5fa1a6ad06cd5f3102c189705380383444323
+dist/2025-09-27/rustfmt-nightly-powerpc-unknown-linux-gnu.tar.gz=d3bf8c8c186c94a0190ae73386839e53dd6ea76cd81e9132438fb7f245d955c5
+dist/2025-09-27/rustfmt-nightly-powerpc-unknown-linux-gnu.tar.xz=665dce6b1a464e1969e3901d7bd293d35a85d5a50ad976600566dcc2a9c46b58
+dist/2025-09-27/rustfmt-nightly-powerpc64-unknown-linux-gnu.tar.gz=a28c82ea8a7e2bbd61043e89994cf2be71ead745b3fa782d0653a99fd81bfa64
+dist/2025-09-27/rustfmt-nightly-powerpc64-unknown-linux-gnu.tar.xz=3c5cc78a7e311f73c39030f42b8f1d3dd0e54e09f4d636be6a581a829f15483d
+dist/2025-09-27/rustfmt-nightly-powerpc64le-unknown-linux-gnu.tar.gz=372c476dc902ffb7ebb8ab8934a89d1bbddf9df9c810bc6d90d3afab984b8205
+dist/2025-09-27/rustfmt-nightly-powerpc64le-unknown-linux-gnu.tar.xz=cf2e738c44ea95d71090bc3526d8c7c70e4554667449f4705614c93444e817a9
+dist/2025-09-27/rustfmt-nightly-powerpc64le-unknown-linux-musl.tar.gz=47f215d0c639f0a4bb67423c65c5b87a06cbecd47ea53484b57c9b7d87c6791b
+dist/2025-09-27/rustfmt-nightly-powerpc64le-unknown-linux-musl.tar.xz=9085b66b2e8e3460f0993896ca3d684395001ab4ed37a16947ce1d15d5aa224b
+dist/2025-09-27/rustfmt-nightly-riscv64gc-unknown-linux-gnu.tar.gz=0f07ac40b25eeef46a4f4a0d34cf50c9336407f2d7f23c05c47fe35f3a7a1d49
+dist/2025-09-27/rustfmt-nightly-riscv64gc-unknown-linux-gnu.tar.xz=ce08e9b33e75eb504f28ba23e1cc3003c0aa503fbdceb04271bd533613713160
+dist/2025-09-27/rustfmt-nightly-s390x-unknown-linux-gnu.tar.gz=4e64fc0ec680a294308f897131f8ab185872dc68cd1312fbe1a306ed6e53ba26
+dist/2025-09-27/rustfmt-nightly-s390x-unknown-linux-gnu.tar.xz=b46d423db54a90944276cee172b8cf0ea70562c01537c37c65f3ea17c13a47fe
+dist/2025-09-27/rustfmt-nightly-sparcv9-sun-solaris.tar.gz=3a84501e05cc7430f91903dbb0de0946621d05c095459c47dde3cf7e662e771f
+dist/2025-09-27/rustfmt-nightly-sparcv9-sun-solaris.tar.xz=0107d3c129e1a18a814d5c213b6445aa7ecb7dd95507641d2cb3d0c39293818c
+dist/2025-09-27/rustfmt-nightly-x86_64-apple-darwin.tar.gz=c58e0a2db9b3933539a20614b143e6575f6aa1459ee35af4d67210dd572e6af0
+dist/2025-09-27/rustfmt-nightly-x86_64-apple-darwin.tar.xz=0cd4d7a8cfedc2787bacebbb2fa481d5efe3d56ba476ef8799c34325c40283e1
+dist/2025-09-27/rustfmt-nightly-x86_64-pc-solaris.tar.gz=ad3fdf81b7b00ee670b05ed2bdc05f79a9c066104d797dc7eaa4d767dfe2eeae
+dist/2025-09-27/rustfmt-nightly-x86_64-pc-solaris.tar.xz=df79594ece4b8753d8215672004e9071a8c10c8ece8c86d1d3608c8d7c3f0486
+dist/2025-09-27/rustfmt-nightly-x86_64-pc-windows-gnu.tar.gz=cb800c92a8f899d148adc96283818aa81c115b73555c047e07a67d738e9cd2c9
+dist/2025-09-27/rustfmt-nightly-x86_64-pc-windows-gnu.tar.xz=09f6d95c49725c36bace10c8e119d6850dabee1dcdebac264074e296f9e8ab48
+dist/2025-09-27/rustfmt-nightly-x86_64-pc-windows-gnullvm.tar.gz=e061a3925b95a99dffb17d34c85803bbcac4604f95da2674872f0725d82cdda4
+dist/2025-09-27/rustfmt-nightly-x86_64-pc-windows-gnullvm.tar.xz=1090793fe09cd2ec4c54063600c1999f5e53a9ddc5c5d74e4f5e85dc6f2ef98f
+dist/2025-09-27/rustfmt-nightly-x86_64-pc-windows-msvc.tar.gz=f3978135d4a9bf2537625e38866fca74ca1f0655fc9fae736bf87d257d6cd0d5
+dist/2025-09-27/rustfmt-nightly-x86_64-pc-windows-msvc.tar.xz=03814722fe9798b503ab7d8284c67e84cf18a9a2f179fe227e3313d0ae3e2cff
+dist/2025-09-27/rustfmt-nightly-x86_64-unknown-freebsd.tar.gz=d5a477ce3f220016f097f8949fc2eb1c700c612e97105804156e82264e7ba787
+dist/2025-09-27/rustfmt-nightly-x86_64-unknown-freebsd.tar.xz=0fe90bad20ee599e4e57c46d4bf700c5775c484f0a8bfb2ce4957d2aa2df90cb
+dist/2025-09-27/rustfmt-nightly-x86_64-unknown-illumos.tar.gz=6d48ed9c944fb01655d4025c4aa3b719813cfef040fecff1f59b8b51a0b9510d
+dist/2025-09-27/rustfmt-nightly-x86_64-unknown-illumos.tar.xz=34d5a066b9f5bcef81b38badcc96f295150c2b2a96c35621235bdcc54ce92158
+dist/2025-09-27/rustfmt-nightly-x86_64-unknown-linux-gnu.tar.gz=61a6a8feaf0490e3db169e86e85989538bff994fb76481a81a1ae02222c7ba59
+dist/2025-09-27/rustfmt-nightly-x86_64-unknown-linux-gnu.tar.xz=cd94e20b4985964442b080454c2b628bcb435898e50bc2de55799cc51cd75f16
+dist/2025-09-27/rustfmt-nightly-x86_64-unknown-linux-musl.tar.gz=c2912263d24904ee5b1014a98d5b349754a6fa1bd66498f607cc62ebcf903cc3
+dist/2025-09-27/rustfmt-nightly-x86_64-unknown-linux-musl.tar.xz=8ad5b1284c91798a01fd25b3b690f88b55026e109471e759d4cecdefd1f83a39
+dist/2025-09-27/rustfmt-nightly-x86_64-unknown-netbsd.tar.gz=e0f52a6511c36c2ece175bc993861cffe0cc72a2e1b56b1def246e09f70d3a75
+dist/2025-09-27/rustfmt-nightly-x86_64-unknown-netbsd.tar.xz=229b92a2c0ef8ab1ac588858bb371ea0ed3449dec82a11ca7386df6efb2f65b7
+dist/2025-09-27/rustc-nightly-aarch64-apple-darwin.tar.gz=de7af74b8c91fb87b20df2d65b536fe6f49cc632b1f0c52a1e65a215fd5e4a06
+dist/2025-09-27/rustc-nightly-aarch64-apple-darwin.tar.xz=7a3e8c68f0bf4d393393628bd85d22242eee59605e3d56e0e94d06163ee2d4e9
+dist/2025-09-27/rustc-nightly-aarch64-pc-windows-gnullvm.tar.gz=2826132a82eb5adaabe2fdadc76ddc21460834365085ff2a113d934c11870a41
+dist/2025-09-27/rustc-nightly-aarch64-pc-windows-gnullvm.tar.xz=47980ea13cb887d85f8e501ca2b5d6e4b77ba8f229b2cfb9a1f28426c60d87a9
+dist/2025-09-27/rustc-nightly-aarch64-pc-windows-msvc.tar.gz=10dc98065c0b19d737ea93506df1ac399c33190edb3f6bbc51d6c1697e910f8a
+dist/2025-09-27/rustc-nightly-aarch64-pc-windows-msvc.tar.xz=d791bf9c54ccdb02da34e408aa93e0680f19a3bfbed1e5dbd61b57f1e1f38fdd
+dist/2025-09-27/rustc-nightly-aarch64-unknown-linux-gnu.tar.gz=ba6e33f6efa2f5a97790e29bb72c89bd460d758244dc9dfa4684e01bc75b6656
+dist/2025-09-27/rustc-nightly-aarch64-unknown-linux-gnu.tar.xz=4e38e862770ed0215720445e56fb027570e4f3c09d63a7f68cdacbff482b4cec
+dist/2025-09-27/rustc-nightly-aarch64-unknown-linux-musl.tar.gz=b126fbef234c0b67df42fb0568580b3d95ce98b7346095c3762214fcdece14a5
+dist/2025-09-27/rustc-nightly-aarch64-unknown-linux-musl.tar.xz=07af694d0ab0b55b18bd437ec9edb965f451f1bbb8334e1667f87d1d8e8354b2
+dist/2025-09-27/rustc-nightly-arm-unknown-linux-gnueabi.tar.gz=6901b57b0fe7182a45b1934e1d7a006ba353daf114ea7601563caade4de1b2c2
+dist/2025-09-27/rustc-nightly-arm-unknown-linux-gnueabi.tar.xz=c1af7bcb75c1ce5975e606aacb2d3decaf7a8470cd347d4caf75f11f84d3122f
+dist/2025-09-27/rustc-nightly-arm-unknown-linux-gnueabihf.tar.gz=8f29e493bd15175ed2a72d50857cbcc07992194c0b38d2b0a4660217b04b8276
+dist/2025-09-27/rustc-nightly-arm-unknown-linux-gnueabihf.tar.xz=fe478ade162b6b5d33808f4872de54e0b9dedd84e9e420480a370a2555d28cbc
+dist/2025-09-27/rustc-nightly-armv7-unknown-linux-gnueabihf.tar.gz=f03a3368f41969d061a9ec2e87af512c346f9e82b6286eea65dbce33de90391e
+dist/2025-09-27/rustc-nightly-armv7-unknown-linux-gnueabihf.tar.xz=c771ab34e5bab9344be3dab9315225296e41b3fa70cfe59fd3e0b287c4985fc2
+dist/2025-09-27/rustc-nightly-i686-pc-windows-gnu.tar.gz=9f5555633f1f1462285c0eb39aa42d0beb45cdb3b45c524483e4e4c6b76b6551
+dist/2025-09-27/rustc-nightly-i686-pc-windows-gnu.tar.xz=ae8c171fa20a49d7323bb5e6a36b262947caae260adb942204206aada00bcfaf
+dist/2025-09-27/rustc-nightly-i686-pc-windows-msvc.tar.gz=2b50b6d9027d5b480dcd2693a551bf80db7d3dae802bfd9a825b68a50ab022a6
+dist/2025-09-27/rustc-nightly-i686-pc-windows-msvc.tar.xz=d4b396eb0256cd62718751f3a52498dba992ba063ed77e5d675da8dc06a6751e
+dist/2025-09-27/rustc-nightly-i686-unknown-linux-gnu.tar.gz=f74acd9ecd35d10040e388d5224a9c88e66348dca09930d89068e87a0371a7d8
+dist/2025-09-27/rustc-nightly-i686-unknown-linux-gnu.tar.xz=92bb07e968cbbbfcf1bc7d0ecdd1a088b8c2975691bbf6ed846bc69708e34f13
+dist/2025-09-27/rustc-nightly-loongarch64-unknown-linux-gnu.tar.gz=7b756904c495de2d37993d71fe1e70e182c232aa408296c6ba05f71a94423406
+dist/2025-09-27/rustc-nightly-loongarch64-unknown-linux-gnu.tar.xz=522114675fb36949b953491d9a5fa0db39d22118f015f8ce92a120eab39244b0
+dist/2025-09-27/rustc-nightly-loongarch64-unknown-linux-musl.tar.gz=2309e49988ec8c35ef17f7293d6b2a787589eb38bba217a8f9429446713cc2a4
+dist/2025-09-27/rustc-nightly-loongarch64-unknown-linux-musl.tar.xz=820950e1cbfe6d973e1835532f9e201fe215d149bc415ac7ea011b16bf6b7bc8
+dist/2025-09-27/rustc-nightly-powerpc-unknown-linux-gnu.tar.gz=6fe053425d6b840c72352a88021c3b2b6deb389986575cb5e7b8c5991e86d039
+dist/2025-09-27/rustc-nightly-powerpc-unknown-linux-gnu.tar.xz=d62cad3e6a7dbab7cbefa493e78a0b7d7e8f724dcd766ae03b6715c325594fe5
+dist/2025-09-27/rustc-nightly-powerpc64-unknown-linux-gnu.tar.gz=8bc6b3d521f5117bd3f9321d9d086e928fecf548be58edc71b257269e68ad21c
+dist/2025-09-27/rustc-nightly-powerpc64-unknown-linux-gnu.tar.xz=d08a0ed4adb7fdf451d39c1dd56171d6ce345b10cf905515c07ac5eb66f7d030
+dist/2025-09-27/rustc-nightly-powerpc64le-unknown-linux-gnu.tar.gz=02ac6a9c23c1dfaf12e26b466bb33057787c28f2bfe8503b998a5d5aa55a4370
+dist/2025-09-27/rustc-nightly-powerpc64le-unknown-linux-gnu.tar.xz=77709b47a9d99657e03c77f32183b2127e75488df59cd000ed20cad5868afd5d
+dist/2025-09-27/rustc-nightly-powerpc64le-unknown-linux-musl.tar.gz=b811bfae5380ffe89e2f48f6c0e6f293e8db33461a1fda94a85759d3464100c4
+dist/2025-09-27/rustc-nightly-powerpc64le-unknown-linux-musl.tar.xz=bc41de8c0c65d912b5d6be06f3b12b3e4be1c20c1dc6ce1b7f5226e7d3ab3ae2
+dist/2025-09-27/rustc-nightly-riscv64gc-unknown-linux-gnu.tar.gz=110b42065218c2607b01edb83d41425176d7f065fac52c5836bed0d2215fc5b3
+dist/2025-09-27/rustc-nightly-riscv64gc-unknown-linux-gnu.tar.xz=97e3a41b0718ea14be4b7320aa4efc7f19b3feeabc7aa9079ce4ea487cad8064
+dist/2025-09-27/rustc-nightly-s390x-unknown-linux-gnu.tar.gz=4e1fd4ed9df5ae921380e3396159053c87623a9ee1c7bcc1f897674c9165714d
+dist/2025-09-27/rustc-nightly-s390x-unknown-linux-gnu.tar.xz=1e2833f165f7b255731fb1d26bd6026f5b6152ed91ac70d8dceb4f692ea9a66f
+dist/2025-09-27/rustc-nightly-sparcv9-sun-solaris.tar.gz=8113fa75d9ad92c411c71b6769f2af4450ed3ae285be1ebf10afe022abe52661
+dist/2025-09-27/rustc-nightly-sparcv9-sun-solaris.tar.xz=150128e8dde149bfbb2071cc933844ff87931cb856939db922eab98230ab7bb1
+dist/2025-09-27/rustc-nightly-x86_64-apple-darwin.tar.gz=727f7ae1f1e5fe51a3722105211cef3eb92f792cd054857ffef7bf858d0963cd
+dist/2025-09-27/rustc-nightly-x86_64-apple-darwin.tar.xz=295672b0d6afb6e80f25dfd6d1643414f976eab6da00a5babf377ecede580e56
+dist/2025-09-27/rustc-nightly-x86_64-pc-solaris.tar.gz=3505cebc0659388e110d1e55a5eca94ac945d75b3320f16ed9ded08629a91638
+dist/2025-09-27/rustc-nightly-x86_64-pc-solaris.tar.xz=515d5a5046dd2c4b3ac2b21a6dd4bc834eba20d08b902ed396e0b62101978210
+dist/2025-09-27/rustc-nightly-x86_64-pc-windows-gnu.tar.gz=838ce3f625b6dfb87f0271770515988d3b3f1535d75353b8f0f4a69074c1ceac
+dist/2025-09-27/rustc-nightly-x86_64-pc-windows-gnu.tar.xz=186eae6c01ecfc67facc96ac75d8518c31de1bf8897d82bc587941c3f686f4c3
+dist/2025-09-27/rustc-nightly-x86_64-pc-windows-gnullvm.tar.gz=76e5d092c78b663c2d75ee9d95f6c60d1ecb509b440312f4a8ad333d58de54b8
+dist/2025-09-27/rustc-nightly-x86_64-pc-windows-gnullvm.tar.xz=69ffcda8f985b3c5b78b18f0eea037890f2efc205f0b7cc4b788f1b35a3b7eb1
+dist/2025-09-27/rustc-nightly-x86_64-pc-windows-msvc.tar.gz=2b08c563daa21d817bdac9c8dd81021a80967e7e671a312c2990575e3622b928
+dist/2025-09-27/rustc-nightly-x86_64-pc-windows-msvc.tar.xz=2e54f6a6b6e096be1f717361d2e474b2ca94957ee006d5fa62910ff3d85cf05b
+dist/2025-09-27/rustc-nightly-x86_64-unknown-freebsd.tar.gz=6e00949c5d3a2f0ba86f1d89f54278f09e58f043cfd00d1f5df984835228d28d
+dist/2025-09-27/rustc-nightly-x86_64-unknown-freebsd.tar.xz=46d9945d5361b758448454c4778a42ce01b4cff7370b9988d5e7b2c7d889d24f
+dist/2025-09-27/rustc-nightly-x86_64-unknown-illumos.tar.gz=83f3d4d069729a72da4b96067400b812367e0a81284bfe3cd73b1939fb81db9c
+dist/2025-09-27/rustc-nightly-x86_64-unknown-illumos.tar.xz=110ca4f2630368f1c94084332d825964f3852bc9e70db8ec738de2cd4f450f2a
+dist/2025-09-27/rustc-nightly-x86_64-unknown-linux-gnu.tar.gz=e1ad313cbe777997222bbdd4b26a5b4c21da50b6378e434501c58219137dad77
+dist/2025-09-27/rustc-nightly-x86_64-unknown-linux-gnu.tar.xz=2ab176057835fabd55e6e2372b036c245be44c0705198557ef2a16d187ea9457
+dist/2025-09-27/rustc-nightly-x86_64-unknown-linux-musl.tar.gz=3e643ce549e9db3768c478b37f088afbf9b2f63dc0275bfdf7c2cbb48ac4fef8
+dist/2025-09-27/rustc-nightly-x86_64-unknown-linux-musl.tar.xz=597c47ff84de68f317b0672d5564a3121edd88cbf5dd3d27192d133ca4ac05a8
+dist/2025-09-27/rustc-nightly-x86_64-unknown-netbsd.tar.gz=5f948f48d64420119f1bd1a90952a04cec074ca45bda8d46f020163cb2809016
+dist/2025-09-27/rustc-nightly-x86_64-unknown-netbsd.tar.xz=977612fd1ed20d57b95e577dd9b3632209fb1f376f46c66467e2a2ccdd7d29f0
+dist/2025-09-27/rust-nightly-aarch64-pc-windows-msvc.msi=b39edbdc83f4329be0e194be1b7e002e764153628bb107bdc77e6f8c2331abe1
+dist/2025-09-27/rust-nightly-i686-pc-windows-gnu.msi=d023b88f94d2d25b4a29c03d4e1243484fd7a20d67753fd3e9a10e6f39069df8
+dist/2025-09-27/rust-nightly-i686-pc-windows-msvc.msi=8441a5f6e8650613b5b9c0c2778bc88bcf259fd4f3acd226a6ec52f1b4a960cb
+dist/2025-09-27/rust-nightly-x86_64-pc-windows-gnu.msi=15a83b7056623d30dc1d47560151ec79e2cb7db1d229069085e73b782347e8e7
+dist/2025-09-27/rust-nightly-x86_64-pc-windows-msvc.msi=607a9219272d8b41fd6bedf884515d3584471c75be19f9353c1c67826c115aea
+dist/2025-09-27/rust-nightly-aarch64-apple-darwin.pkg=55cc7129e581244dcbc567eb905183ff3e45edc8847fc58cb350394e6df55e96
+dist/2025-09-27/rust-nightly-x86_64-apple-darwin.pkg=a6add14a01bfd77634e67425db47cf63144dbc0b618beeaa4f37be2d7103146c
+dist/2025-09-27/rustc-nightly-src.tar.gz=419d5aea9252c3a9377fcfefe0a0e91b7be1354b9c33e36e346c547c4a9ec3eb
+dist/2025-09-27/rustc-nightly-src.tar.xz=fd454f13408f045e3ba1d4618699a3c6e42fcc66902c37972aa3729bb681d951
diff --git a/src/tools/bump-stage0/Cargo.toml b/src/tools/bump-stage0/Cargo.toml
index 79097f2c189..943b8453ef8 100644
--- a/src/tools/bump-stage0/Cargo.toml
+++ b/src/tools/bump-stage0/Cargo.toml
@@ -9,6 +9,8 @@ edition = "2021"
 anyhow = "1.0.34"
 build_helper = { path = "../../build_helper" }
 curl = "0.4.38"
+hex = "0.4.3"
 indexmap = { version = "2.0.0", features = ["serde"] }
 serde = { version = "1.0.125", features = ["derive"] }
 toml = "0.8.23"
+sha2 = "0.10.1"
diff --git a/src/tools/bump-stage0/src/main.rs b/src/tools/bump-stage0/src/main.rs
index faed748785f..079e7b1ce71 100644
--- a/src/tools/bump-stage0/src/main.rs
+++ b/src/tools/bump-stage0/src/main.rs
@@ -4,6 +4,7 @@ use anyhow::{Context, Error};
 use build_helper::stage0_parser::{Stage0Config, VersionMetadata, parse_stage0_file};
 use curl::easy::Easy;
 use indexmap::IndexMap;
+use sha2::{Digest, Sha256};
 
 const PATH: &str = "src/stage0";
 const COMPILER_COMPONENTS: &[&str] = &["rustc", "rust-std", "cargo", "clippy-preview"];
@@ -13,13 +14,14 @@ struct Tool {
     config: Stage0Config,
 
     channel: Channel,
-    date: Option<String>,
+    compiler_date: Option<String>,
+    rustfmt_date: Option<String>,
     version: [u16; 3],
     checksums: IndexMap<String, String>,
 }
 
 impl Tool {
-    fn new(date: Option<String>) -> Result<Self, Error> {
+    fn new(compiler_date: Option<String>, rustfmt_date: Option<String>) -> Result<Self, Error> {
         let channel = match std::fs::read_to_string("src/ci/channel")?.trim() {
             "stable" => Channel::Stable,
             "beta" => Channel::Beta,
@@ -38,7 +40,14 @@ impl Tool {
 
         let existing = parse_stage0_file();
 
-        Ok(Self { channel, version, date, config: existing.config, checksums: IndexMap::new() })
+        Ok(Self {
+            channel,
+            version,
+            compiler_date,
+            rustfmt_date,
+            config: existing.config,
+            checksums: IndexMap::new(),
+        })
     }
 
     fn update_stage0_file(mut self) -> Result<(), Error> {
@@ -78,10 +87,21 @@ impl Tool {
         file_content.push_str("\n");
 
         let compiler = self.detect_compiler()?;
+        file_content.push_str(&format!(
+            "compiler_channel_manifest_hash={}\n",
+            compiler.channel_manifest_hash
+        ));
+        file_content.push_str(&format!("compiler_git_commit_hash={}\n", compiler.git_commit_hash));
         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!(
+                "rustfmt_channel_manifest_hash={}\n",
+                rustfmt.channel_manifest_hash
+            ));
+            file_content
+                .push_str(&format!("rustfmt_git_commit_hash={}\n", rustfmt.git_commit_hash));
             file_content.push_str(&format!("rustfmt_date={}\n", rustfmt.date));
             file_content.push_str(&format!("rustfmt_version={}\n", rustfmt.version));
         }
@@ -112,9 +132,16 @@ impl Tool {
             Channel::Nightly => "beta".to_string(),
         };
 
-        let manifest = fetch_manifest(&self.config, &channel, self.date.as_deref())?;
+        let (manifest, manifest_hash) =
+            fetch_manifest(&self.config, &channel, self.compiler_date.as_deref())?;
         self.collect_checksums(&manifest, COMPILER_COMPONENTS)?;
         Ok(VersionMetadata {
+            channel_manifest_hash: manifest_hash,
+            git_commit_hash: manifest.pkg["rust"]
+                .git_commit_hash
+                .as_ref()
+                .expect("invalid git_commit_hash")
+                .into(),
             date: manifest.date,
             version: if self.channel == Channel::Nightly {
                 "beta".to_string()
@@ -138,9 +165,19 @@ impl Tool {
             return Ok(None);
         }
 
-        let manifest = fetch_manifest(&self.config, "nightly", self.date.as_deref())?;
+        let (manifest, manifest_hash) =
+            fetch_manifest(&self.config, "nightly", self.rustfmt_date.as_deref())?;
         self.collect_checksums(&manifest, RUSTFMT_COMPONENTS)?;
-        Ok(Some(VersionMetadata { date: manifest.date, version: "nightly".into() }))
+        Ok(Some(VersionMetadata {
+            channel_manifest_hash: manifest_hash,
+            git_commit_hash: manifest.pkg["rust"]
+                .git_commit_hash
+                .as_ref()
+                .expect("invalid git_commit_hash")
+                .into(),
+            date: manifest.date,
+            version: "nightly".into(),
+        }))
     }
 
     fn collect_checksums(&mut self, manifest: &Manifest, components: &[&str]) -> Result<(), Error> {
@@ -164,12 +201,29 @@ impl Tool {
                 }
             }
         }
+        for artifact in manifest.artifacts.values() {
+            for targets in artifact.target.values() {
+                for target in targets {
+                    let url = target
+                        .url
+                        .strip_prefix(&prefix)
+                        .ok_or_else(|| {
+                            anyhow::anyhow!(
+                                "url doesn't start with dist server base: {}",
+                                target.url
+                            )
+                        })?
+                        .to_string();
+                    self.checksums.insert(url, target.hash_sha256.clone());
+                }
+            }
+        }
         Ok(())
     }
 }
 
 fn main() -> Result<(), Error> {
-    let tool = Tool::new(std::env::args().nth(1))?;
+    let tool = Tool::new(std::env::args().nth(1), std::env::args().nth(2))?;
     tool.update_stage0_file()?;
     Ok(())
 }
@@ -178,18 +232,24 @@ fn fetch_manifest(
     config: &Stage0Config,
     channel: &str,
     date: Option<&str>,
-) -> Result<Manifest, Error> {
+) -> Result<(Manifest, String), Error> {
     let url = if let Some(date) = date {
         format!("{}/dist/{}/channel-rust-{}.toml", config.dist_server, date, channel)
     } else {
         format!("{}/dist/channel-rust-{}.toml", config.dist_server, channel)
     };
 
+    let manifest_bytes = http_get(&url)?;
+
+    let mut sha256 = Sha256::new();
+    sha256.update(&manifest_bytes);
+    let manifest_hash = hex::encode(sha256.finalize());
+
     // FIXME: on newer `toml` (>= `0.9.*`), use `toml::from_slice`. For now, we use the most recent
     // `toml` available in-tree which is `0.8.*`, so we have to do an additional dance here.
-    let response = http_get(&url)?;
-    let response = String::from_utf8(response)?;
-    Ok(toml::from_str(&response)?)
+    let manifest_str = String::from_utf8(manifest_bytes)?;
+    let manifest = toml::from_str(&manifest_str)?;
+    Ok((manifest, manifest_hash))
 }
 
 fn http_get(url: &str) -> Result<Vec<u8>, Error> {
@@ -219,11 +279,14 @@ enum Channel {
 struct Manifest {
     date: String,
     pkg: IndexMap<String, ManifestPackage>,
+    artifacts: IndexMap<String, ManifestArtifact>,
 }
 
 #[derive(Debug, serde::Serialize, serde::Deserialize)]
 struct ManifestPackage {
     version: String,
+    #[serde(default)]
+    git_commit_hash: Option<String>,
     target: IndexMap<String, ManifestTargetPackage>,
 }
 
@@ -234,3 +297,15 @@ struct ManifestTargetPackage {
     xz_url: Option<String>,
     xz_hash: Option<String>,
 }
+
+#[derive(Debug, serde::Serialize, serde::Deserialize)]
+struct ManifestArtifact {
+    target: IndexMap<String, Vec<ManifestTargetArtifact>>,
+}
+
+#[derive(Debug, serde::Serialize, serde::Deserialize)]
+#[serde(rename_all = "kebab-case")]
+struct ManifestTargetArtifact {
+    url: String,
+    hash_sha256: String,
+}
diff --git a/src/tools/clippy/clippy_lints/src/casts/cast_ptr_alignment.rs b/src/tools/clippy/clippy_lints/src/casts/cast_ptr_alignment.rs
index d78da9396fa..7d14ba7fcf1 100644
--- a/src/tools/clippy/clippy_lints/src/casts/cast_ptr_alignment.rs
+++ b/src/tools/clippy/clippy_lints/src/casts/cast_ptr_alignment.rs
@@ -43,8 +43,8 @@ fn lint_cast_ptr_alignment<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'_>, cast_f
             expr.span,
             format!(
                 "casting from `{cast_from}` to a more-strictly-aligned pointer (`{cast_to}`) ({} < {} bytes)",
-                from_layout.align.abi.bytes(),
-                to_layout.align.abi.bytes(),
+                from_layout.align.bytes(),
+                to_layout.align.bytes(),
             ),
         );
     }
diff --git a/src/tools/clippy/clippy_lints/src/casts/manual_dangling_ptr.rs b/src/tools/clippy/clippy_lints/src/casts/manual_dangling_ptr.rs
index 92910cf8adf..ff5320719aa 100644
--- a/src/tools/clippy/clippy_lints/src/casts/manual_dangling_ptr.rs
+++ b/src/tools/clippy/clippy_lints/src/casts/manual_dangling_ptr.rs
@@ -72,7 +72,7 @@ fn is_literal_aligned(cx: &LateContext<'_>, lit: &Spanned<LitKind>, to: &Ty<'_>)
     cx.tcx
         .layout_of(cx.typing_env().as_query_input(to_mid_ty))
         .is_ok_and(|layout| {
-            let align = u128::from(layout.align.abi.bytes());
+            let align = u128::from(layout.align.bytes());
             u128::from(val) <= align
         })
 }
diff --git a/src/tools/clippy/clippy_lints/src/lib.rs b/src/tools/clippy/clippy_lints/src/lib.rs
index c56fa257b06..b0083b99f17 100644
--- a/src/tools/clippy/clippy_lints/src/lib.rs
+++ b/src/tools/clippy/clippy_lints/src/lib.rs
@@ -7,7 +7,6 @@
 #![feature(iter_intersperse)]
 #![feature(iter_partition_in_place)]
 #![feature(never_type)]
-#![cfg_attr(bootstrap, feature(round_char_boundary))]
 #![feature(rustc_private)]
 #![feature(stmt_expr_attributes)]
 #![feature(unwrap_infallible)]
diff --git a/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs b/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs
index 2bda6d50373..cc98fac45c7 100644
--- a/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs
+++ b/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs
@@ -141,7 +141,8 @@ fn check_rvalue<'tcx>(
             | CastKind::FloatToFloat
             | CastKind::FnPtrToPtr
             | CastKind::PtrToPtr
-            | CastKind::PointerCoercion(PointerCoercion::MutToConstPointer | PointerCoercion::ArrayToPointer, _),
+            | CastKind::PointerCoercion(PointerCoercion::MutToConstPointer | PointerCoercion::ArrayToPointer, _)
+            | CastKind::Subtype,
             operand,
             _,
         ) => check_operand(cx, operand, span, body, msrv),
@@ -312,7 +313,6 @@ fn check_place<'tcx>(
             | ProjectionElem::OpaqueCast(..)
             | ProjectionElem::Downcast(..)
             | ProjectionElem::Subslice { .. }
-            | ProjectionElem::Subtype(_)
             | ProjectionElem::Index(_)
             | ProjectionElem::UnwrapUnsafeBinder(_) => {},
         }
diff --git a/src/tools/clippy/tests/missing-test-files.rs b/src/tools/clippy/tests/missing-test-files.rs
index 63f960c92fa..9fff3132498 100644
--- a/src/tools/clippy/tests/missing-test-files.rs
+++ b/src/tools/clippy/tests/missing-test-files.rs
@@ -1,6 +1,5 @@
 #![warn(rust_2018_idioms, unused_lifetimes)]
 #![allow(clippy::assertions_on_constants)]
-#![cfg_attr(bootstrap, feature(path_file_prefix))]
 
 use std::cmp::Ordering;
 use std::ffi::OsStr;
diff --git a/src/tools/clippy/tests/ui/author/macro_in_closure.stdout b/src/tools/clippy/tests/ui/author/macro_in_closure.stdout
index 49595e2fec2..786c61e0c01 100644
--- a/src/tools/clippy/tests/ui/author/macro_in_closure.stdout
+++ b/src/tools/clippy/tests/ui/author/macro_in_closure.stdout
@@ -10,34 +10,42 @@ if let StmtKind::Let(local) = stmt.kind
     && paths::STD_IO_STDIO__PRINT.matches_path(cx, func) // Add the path to `clippy_utils::paths` if needed
     && args.len() == 1
     && let ExprKind::Block(block1, None) = args[0].kind
-    && block1.stmts.len() == 1
+    && block1.stmts.len() == 2
     && let StmtKind::Let(local1) = block1.stmts[0].kind
     && let Some(init1) = local1.init
-    && let ExprKind::Array(elements) = init1.kind
+    && let ExprKind::Tup(elements) = init1.kind
     && elements.len() == 1
-    && let ExprKind::Call(func1, args1) = elements[0].kind
-    && paths::CORE_FMT_RT_ARGUMENT_NEW_DISPLAY.matches_path(cx, func1) // Add the path to `clippy_utils::paths` if needed
-    && args1.len() == 1
-    && let ExprKind::AddrOf(BorrowKind::Ref, Mutability::Not, inner) = args1[0].kind
+    && let ExprKind::AddrOf(BorrowKind::Ref, Mutability::Not, inner) = elements[0].kind
     && let PatKind::Binding(BindingMode::NONE, _, name, None) = local1.pat.kind
     && name.as_str() == "args"
+    && let StmtKind::Let(local2) = block1.stmts[1].kind
+    && let Some(init2) = local2.init
+    && let ExprKind::Array(elements1) = init2.kind
+    && elements1.len() == 1
+    && let ExprKind::Call(func1, args1) = elements1[0].kind
+    && paths::CORE_FMT_RT_ARGUMENT_NEW_DISPLAY.matches_path(cx, func1) // Add the path to `clippy_utils::paths` if needed
+    && args1.len() == 1
+    && let ExprKind::Field(object, field_name) = args1[0].kind
+    && field_name.as_str() == "0"
+    && let PatKind::Binding(BindingMode::NONE, _, name1, None) = local2.pat.kind
+    && name1.as_str() == "args"
     && let Some(trailing_expr) = block1.expr
     && let ExprKind::Call(func2, args2) = trailing_expr.kind
     && paths::CORE_FMT_RT_NEW_V1.matches_path(cx, func2) // Add the path to `clippy_utils::paths` if needed
     && args2.len() == 2
     && let ExprKind::AddrOf(BorrowKind::Ref, Mutability::Not, inner1) = args2[0].kind
-    && let ExprKind::Array(elements1) = inner1.kind
-    && elements1.len() == 2
-    && let ExprKind::Lit(ref lit) = elements1[0].kind
+    && let ExprKind::Array(elements2) = inner1.kind
+    && elements2.len() == 2
+    && let ExprKind::Lit(ref lit) = elements2[0].kind
     && let LitKind::Str(s, _) = lit.node
     && s.as_str() == ""
-    && let ExprKind::Lit(ref lit1) = elements1[1].kind
+    && let ExprKind::Lit(ref lit1) = elements2[1].kind
     && let LitKind::Str(s1, _) = lit1.node
     && s1.as_str() == "\n"
     && let ExprKind::AddrOf(BorrowKind::Ref, Mutability::Not, inner2) = args2[1].kind
     && block.expr.is_none()
-    && let PatKind::Binding(BindingMode::NONE, _, name1, None) = local.pat.kind
-    && name1.as_str() == "print_text"
+    && let PatKind::Binding(BindingMode::NONE, _, name2, None) = local.pat.kind
+    && name2.as_str() == "print_text"
 {
     // report your lint here
 }
diff --git a/src/tools/clippy/tests/ui/author/macro_in_loop.stdout b/src/tools/clippy/tests/ui/author/macro_in_loop.stdout
index 4fc7b49464d..80717900b52 100644
--- a/src/tools/clippy/tests/ui/author/macro_in_loop.stdout
+++ b/src/tools/clippy/tests/ui/author/macro_in_loop.stdout
@@ -20,28 +20,36 @@ if let Some(higher::ForLoop { pat: pat, arg: arg, body: body, .. }) = higher::Fo
     && paths::STD_IO_STDIO__PRINT.matches_path(cx, func) // Add the path to `clippy_utils::paths` if needed
     && args.len() == 1
     && let ExprKind::Block(block2, None) = args[0].kind
-    && block2.stmts.len() == 1
+    && block2.stmts.len() == 2
     && let StmtKind::Let(local) = block2.stmts[0].kind
     && let Some(init) = local.init
-    && let ExprKind::Array(elements) = init.kind
+    && let ExprKind::Tup(elements) = init.kind
     && elements.len() == 1
-    && let ExprKind::Call(func1, args1) = elements[0].kind
-    && paths::CORE_FMT_RT_ARGUMENT_NEW_DISPLAY.matches_path(cx, func1) // Add the path to `clippy_utils::paths` if needed
-    && args1.len() == 1
-    && let ExprKind::AddrOf(BorrowKind::Ref, Mutability::Not, inner) = args1[0].kind
+    && let ExprKind::AddrOf(BorrowKind::Ref, Mutability::Not, inner) = elements[0].kind
     && let PatKind::Binding(BindingMode::NONE, _, name1, None) = local.pat.kind
     && name1.as_str() == "args"
+    && let StmtKind::Let(local1) = block2.stmts[1].kind
+    && let Some(init1) = local1.init
+    && let ExprKind::Array(elements1) = init1.kind
+    && elements1.len() == 1
+    && let ExprKind::Call(func1, args1) = elements1[0].kind
+    && paths::CORE_FMT_RT_ARGUMENT_NEW_DISPLAY.matches_path(cx, func1) // Add the path to `clippy_utils::paths` if needed
+    && args1.len() == 1
+    && let ExprKind::Field(object, field_name) = args1[0].kind
+    && field_name.as_str() == "0"
+    && let PatKind::Binding(BindingMode::NONE, _, name2, None) = local1.pat.kind
+    && name2.as_str() == "args"
     && let Some(trailing_expr) = block2.expr
     && let ExprKind::Call(func2, args2) = trailing_expr.kind
     && paths::CORE_FMT_RT_NEW_V1.matches_path(cx, func2) // Add the path to `clippy_utils::paths` if needed
     && args2.len() == 2
     && let ExprKind::AddrOf(BorrowKind::Ref, Mutability::Not, inner1) = args2[0].kind
-    && let ExprKind::Array(elements1) = inner1.kind
-    && elements1.len() == 2
-    && let ExprKind::Lit(ref lit2) = elements1[0].kind
+    && let ExprKind::Array(elements2) = inner1.kind
+    && elements2.len() == 2
+    && let ExprKind::Lit(ref lit2) = elements2[0].kind
     && let LitKind::Str(s, _) = lit2.node
     && s.as_str() == ""
-    && let ExprKind::Lit(ref lit3) = elements1[1].kind
+    && let ExprKind::Lit(ref lit3) = elements2[1].kind
     && let LitKind::Str(s1, _) = lit3.node
     && s1.as_str() == "\n"
     && let ExprKind::AddrOf(BorrowKind::Ref, Mutability::Not, inner2) = args2[1].kind
diff --git a/src/tools/clippy/tests/ui/useless_attribute.fixed b/src/tools/clippy/tests/ui/useless_attribute.fixed
index 15070dd9c2c..e0bc23e0788 100644
--- a/src/tools/clippy/tests/ui/useless_attribute.fixed
+++ b/src/tools/clippy/tests/ui/useless_attribute.fixed
@@ -153,7 +153,7 @@ pub mod redundant_imports_issue {
         () => {};
     }
 
-    #[expect(redundant_imports)]
+    #[expect(unused_imports)]
     pub(crate) use empty;
 
     empty!();
diff --git a/src/tools/clippy/tests/ui/useless_attribute.rs b/src/tools/clippy/tests/ui/useless_attribute.rs
index 3f530de7fd8..30a4c354b23 100644
--- a/src/tools/clippy/tests/ui/useless_attribute.rs
+++ b/src/tools/clippy/tests/ui/useless_attribute.rs
@@ -153,7 +153,7 @@ pub mod redundant_imports_issue {
         () => {};
     }
 
-    #[expect(redundant_imports)]
+    #[expect(unused_imports)]
     pub(crate) use empty;
 
     empty!();
diff --git a/src/tools/compiletest/src/common.rs b/src/tools/compiletest/src/common.rs
index 6da102b1b5f..6d959948918 100644
--- a/src/tools/compiletest/src/common.rs
+++ b/src/tools/compiletest/src/common.rs
@@ -661,18 +661,10 @@ pub struct Config {
     pub builtin_cfg_names: OnceLock<HashSet<String>>,
     pub supported_crate_types: OnceLock<HashSet<String>>,
 
-    /// FIXME: this is why we still need to depend on *staged* `std`, it's because we currently rely
-    /// on `#![feature(internal_output_capture)]` for [`std::io::set_output_capture`] to implement
-    /// `libtest`-esque `--no-capture`.
-    ///
     /// FIXME: rename this to the more canonical `no_capture`, or better, invert this to `capture`
     /// to avoid `!nocapture` double-negatives.
     pub nocapture: bool,
 
-    /// True if the experimental new output-capture implementation should be
-    /// used, avoiding the need for `#![feature(internal_output_capture)]`.
-    pub new_output_capture: bool,
-
     /// Needed both to construct [`build_helper::git::GitConfig`].
     pub nightly_branch: String,
     pub git_merge_commit_email: String,
@@ -790,7 +782,6 @@ impl Config {
             builtin_cfg_names: Default::default(),
             supported_crate_types: Default::default(),
             nocapture: Default::default(),
-            new_output_capture: Default::default(),
             nightly_branch: Default::default(),
             git_merge_commit_email: Default::default(),
             profiler_runtime: Default::default(),
diff --git a/src/tools/compiletest/src/directives.rs b/src/tools/compiletest/src/directives.rs
index e84a2278766..e6916610190 100644
--- a/src/tools/compiletest/src/directives.rs
+++ b/src/tools/compiletest/src/directives.rs
@@ -63,9 +63,10 @@ impl EarlyProps {
             &mut poisoned,
             testfile,
             rdr,
-            &mut |DirectiveLine { line_number, raw_directive: ln, .. }| {
-                parse_and_update_aux(config, ln, testfile, line_number, &mut props.aux);
-                config.parse_and_update_revisions(testfile, line_number, ln, &mut props.revisions);
+            // (dummy comment to force args into vertical layout)
+            &mut |ref ln: DirectiveLine<'_>| {
+                parse_and_update_aux(config, ln, testfile, &mut props.aux);
+                config.parse_and_update_revisions(testfile, ln, &mut props.revisions);
             },
         );
 
@@ -367,8 +368,8 @@ impl TestProps {
                 &mut poisoned,
                 testfile,
                 file,
-                &mut |directive @ DirectiveLine { line_number, raw_directive: ln, .. }| {
-                    if !directive.applies_to_test_revision(test_revision) {
+                &mut |ref ln: DirectiveLine<'_>| {
+                    if !ln.applies_to_test_revision(test_revision) {
                         return;
                     }
 
@@ -378,7 +379,6 @@ impl TestProps {
                         ln,
                         ERROR_PATTERN,
                         testfile,
-                        line_number,
                         &mut self.error_patterns,
                         |r| r,
                     );
@@ -386,7 +386,6 @@ impl TestProps {
                         ln,
                         REGEX_ERROR_PATTERN,
                         testfile,
-                        line_number,
                         &mut self.regex_error_patterns,
                         |r| r,
                     );
@@ -395,7 +394,6 @@ impl TestProps {
                         ln,
                         DOC_FLAGS,
                         testfile,
-                        line_number,
                         &mut self.doc_flags,
                         |r| r,
                     );
@@ -414,7 +412,7 @@ impl TestProps {
                     }
 
                     if let Some(flags) =
-                        config.parse_name_value_directive(ln, COMPILE_FLAGS, testfile, line_number)
+                        config.parse_name_value_directive(ln, COMPILE_FLAGS, testfile)
                     {
                         let flags = split_flags(&flags);
                         for flag in &flags {
@@ -425,39 +423,28 @@ impl TestProps {
                         self.compile_flags.extend(flags);
                     }
                     if config
-                        .parse_name_value_directive(
-                            ln,
-                            INCORRECT_COMPILER_FLAGS,
-                            testfile,
-                            line_number,
-                        )
+                        .parse_name_value_directive(ln, INCORRECT_COMPILER_FLAGS, testfile)
                         .is_some()
                     {
                         panic!("`compiler-flags` directive should be spelled `compile-flags`");
                     }
 
-                    if let Some(edition) = config.parse_edition(ln, testfile, line_number) {
+                    if let Some(edition) = config.parse_edition(ln, testfile) {
                         // 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;
                     }
 
-                    config.parse_and_update_revisions(
-                        testfile,
-                        line_number,
-                        ln,
-                        &mut self.revisions,
-                    );
+                    config.parse_and_update_revisions(testfile, ln, &mut self.revisions);
 
-                    if let Some(flags) =
-                        config.parse_name_value_directive(ln, RUN_FLAGS, testfile, line_number)
+                    if let Some(flags) = config.parse_name_value_directive(ln, RUN_FLAGS, testfile)
                     {
                         self.run_flags.extend(split_flags(&flags));
                     }
 
                     if self.pp_exact.is_none() {
-                        self.pp_exact = config.parse_pp_exact(ln, testfile, line_number);
+                        self.pp_exact = config.parse_pp_exact(ln, testfile);
                     }
 
                     config.set_name_directive(ln, SHOULD_ICE, &mut self.should_ice);
@@ -479,9 +466,7 @@ impl TestProps {
                     );
                     config.set_name_directive(ln, NO_PREFER_DYNAMIC, &mut self.no_prefer_dynamic);
 
-                    if let Some(m) =
-                        config.parse_name_value_directive(ln, PRETTY_MODE, testfile, line_number)
-                    {
+                    if let Some(m) = config.parse_name_value_directive(ln, PRETTY_MODE, testfile) {
                         self.pretty_mode = m;
                     }
 
@@ -492,13 +477,12 @@ impl TestProps {
                     );
 
                     // Call a helper method to deal with aux-related directives.
-                    parse_and_update_aux(config, ln, testfile, line_number, &mut self.aux);
+                    parse_and_update_aux(config, ln, testfile, &mut self.aux);
 
                     config.push_name_value_directive(
                         ln,
                         EXEC_ENV,
                         testfile,
-                        line_number,
                         &mut self.exec_env,
                         Config::parse_env,
                     );
@@ -506,7 +490,6 @@ impl TestProps {
                         ln,
                         UNSET_EXEC_ENV,
                         testfile,
-                        line_number,
                         &mut self.unset_exec_env,
                         |r| r.trim().to_owned(),
                     );
@@ -514,7 +497,6 @@ impl TestProps {
                         ln,
                         RUSTC_ENV,
                         testfile,
-                        line_number,
                         &mut self.rustc_env,
                         Config::parse_env,
                     );
@@ -522,7 +504,6 @@ impl TestProps {
                         ln,
                         UNSET_RUSTC_ENV,
                         testfile,
-                        line_number,
                         &mut self.unset_rustc_env,
                         |r| r.trim().to_owned(),
                     );
@@ -530,7 +511,6 @@ impl TestProps {
                         ln,
                         FORBID_OUTPUT,
                         testfile,
-                        line_number,
                         &mut self.forbid_output,
                         |r| r,
                     );
@@ -566,7 +546,7 @@ impl TestProps {
                     }
 
                     if let Some(code) = config
-                        .parse_name_value_directive(ln, FAILURE_STATUS, testfile, line_number)
+                        .parse_name_value_directive(ln, FAILURE_STATUS, testfile)
                         .and_then(|code| code.trim().parse::<i32>().ok())
                     {
                         self.failure_status = Some(code);
@@ -588,7 +568,6 @@ impl TestProps {
                         ln,
                         ASSEMBLY_OUTPUT,
                         testfile,
-                        line_number,
                         &mut self.assembly_output,
                         |r| r.trim().to_string(),
                     );
@@ -602,7 +581,7 @@ impl TestProps {
                     // Unlike the other `name_value_directive`s this needs to be handled manually,
                     // because it sets a `bool` flag.
                     if let Some(known_bug) =
-                        config.parse_name_value_directive(ln, KNOWN_BUG, testfile, line_number)
+                        config.parse_name_value_directive(ln, KNOWN_BUG, testfile)
                     {
                         let known_bug = known_bug.trim();
                         if known_bug == "unknown"
@@ -632,24 +611,20 @@ impl TestProps {
                         ln,
                         TEST_MIR_PASS,
                         testfile,
-                        line_number,
                         &mut self.mir_unit_test,
                         |s| s.trim().to_string(),
                     );
                     config.set_name_directive(ln, REMAP_SRC_BASE, &mut self.remap_src_base);
 
                     if let Some(flags) =
-                        config.parse_name_value_directive(ln, LLVM_COV_FLAGS, testfile, line_number)
+                        config.parse_name_value_directive(ln, LLVM_COV_FLAGS, testfile)
                     {
                         self.llvm_cov_flags.extend(split_flags(&flags));
                     }
 
-                    if let Some(flags) = config.parse_name_value_directive(
-                        ln,
-                        FILECHECK_FLAGS,
-                        testfile,
-                        line_number,
-                    ) {
+                    if let Some(flags) =
+                        config.parse_name_value_directive(ln, FILECHECK_FLAGS, testfile)
+                    {
                         self.filecheck_flags.extend(split_flags(&flags));
                     }
 
@@ -661,7 +636,6 @@ impl TestProps {
                         ln,
                         directives::CORE_STUBS_COMPILE_FLAGS,
                         testfile,
-                        line_number,
                     ) {
                         let flags = split_flags(&flags);
                         for flag in &flags {
@@ -672,12 +646,9 @@ impl TestProps {
                         self.core_stubs_compile_flags.extend(flags);
                     }
 
-                    if let Some(err_kind) = config.parse_name_value_directive(
-                        ln,
-                        DONT_REQUIRE_ANNOTATIONS,
-                        testfile,
-                        line_number,
-                    ) {
+                    if let Some(err_kind) =
+                        config.parse_name_value_directive(ln, DONT_REQUIRE_ANNOTATIONS, testfile)
+                    {
                         self.dont_require_annotations
                             .insert(ErrorKind::expect_from_user_str(err_kind.trim()));
                     }
@@ -734,7 +705,7 @@ impl TestProps {
         }
     }
 
-    fn update_fail_mode(&mut self, ln: &str, config: &Config) {
+    fn update_fail_mode(&mut self, ln: &DirectiveLine<'_>, config: &Config) {
         let check_ui = |mode: &str| {
             // Mode::Crashes may need build-fail in order to trigger llvm errors or stack overflows
             if config.mode != TestMode::Ui && config.mode != TestMode::Crashes {
@@ -769,7 +740,12 @@ impl TestProps {
         }
     }
 
-    fn update_pass_mode(&mut self, ln: &str, revision: Option<&str>, config: &Config) {
+    fn update_pass_mode(
+        &mut self,
+        ln: &DirectiveLine<'_>,
+        revision: Option<&str>,
+        config: &Config,
+    ) {
         let check_no_run = |s| match (config.mode, s) {
             (TestMode::Ui, _) => (),
             (TestMode::Crashes, _) => (),
@@ -814,7 +790,7 @@ impl TestProps {
         self.pass_mode
     }
 
-    pub fn update_add_core_stubs(&mut self, ln: &str, config: &Config) {
+    fn update_add_core_stubs(&mut self, ln: &DirectiveLine<'_>, config: &Config) {
         let add_core_stubs = config.parse_name_directive(ln, directives::ADD_CORE_STUBS);
         if add_core_stubs {
             if !matches!(config.mode, TestMode::Ui | TestMode::Codegen | TestMode::Assembly) {
@@ -905,10 +881,12 @@ pub(crate) struct CheckDirectiveResult<'ln> {
     trailing_directive: Option<&'ln str>,
 }
 
-pub(crate) fn check_directive<'a>(
-    directive_ln: &'a str,
+fn check_directive<'a>(
+    directive_ln: &DirectiveLine<'a>,
     mode: TestMode,
 ) -> CheckDirectiveResult<'a> {
+    let &DirectiveLine { raw_directive: directive_ln, .. } = directive_ln;
+
     let (directive_name, post) = directive_ln.split_once([':', ' ']).unwrap_or((directive_ln, ""));
 
     let is_known_directive = KNOWN_DIRECTIVE_NAMES.contains(&directive_name)
@@ -980,7 +958,7 @@ fn iter_directives(
         // Perform unknown directive check on Rust files.
         if testfile.extension() == Some("rs") {
             let CheckDirectiveResult { is_known_directive, trailing_directive } =
-                check_directive(directive_line.raw_directive, mode);
+                check_directive(&directive_line, mode);
 
             if !is_known_directive {
                 *poisoned = true;
@@ -1014,8 +992,7 @@ impl Config {
     fn parse_and_update_revisions(
         &self,
         testfile: &Utf8Path,
-        line_number: usize,
-        line: &str,
+        line: &DirectiveLine<'_>,
         existing: &mut Vec<String>,
     ) {
         const FORBIDDEN_REVISION_NAMES: [&str; 2] = [
@@ -1028,8 +1005,7 @@ impl Config {
         const FILECHECK_FORBIDDEN_REVISION_NAMES: [&str; 9] =
             ["CHECK", "COM", "NEXT", "SAME", "EMPTY", "NOT", "COUNT", "DAG", "LABEL"];
 
-        if let Some(raw) = self.parse_name_value_directive(line, "revisions", testfile, line_number)
-        {
+        if let Some(raw) = self.parse_name_value_directive(line, "revisions", testfile) {
             if self.mode == TestMode::RunMake {
                 panic!("`run-make` mode tests do not support revisions: {}", testfile);
             }
@@ -1074,13 +1050,8 @@ impl Config {
         (name.to_owned(), value.to_owned())
     }
 
-    fn parse_pp_exact(
-        &self,
-        line: &str,
-        testfile: &Utf8Path,
-        line_number: usize,
-    ) -> Option<Utf8PathBuf> {
-        if let Some(s) = self.parse_name_value_directive(line, "pp-exact", testfile, line_number) {
+    fn parse_pp_exact(&self, line: &DirectiveLine<'_>, testfile: &Utf8Path) -> Option<Utf8PathBuf> {
+        if let Some(s) = self.parse_name_value_directive(line, "pp-exact", testfile) {
             Some(Utf8PathBuf::from(&s))
         } else if self.parse_name_directive(line, "pp-exact") {
             testfile.file_name().map(Utf8PathBuf::from)
@@ -1089,7 +1060,9 @@ impl Config {
         }
     }
 
-    fn parse_custom_normalization(&self, raw_directive: &str) -> Option<NormalizeRule> {
+    fn parse_custom_normalization(&self, line: &DirectiveLine<'_>) -> Option<NormalizeRule> {
+        let &DirectiveLine { raw_directive, .. } = line;
+
         // FIXME(Zalathar): Integrate name/value splitting into `DirectiveLine`
         // instead of doing it here.
         let (directive_name, raw_value) = raw_directive.split_once(':')?;
@@ -1110,24 +1083,23 @@ impl Config {
         Some(NormalizeRule { kind, regex, replacement })
     }
 
-    fn parse_name_directive(&self, line: &str, directive: &str) -> bool {
+    fn parse_name_directive(&self, line: &DirectiveLine<'_>, directive: &str) -> bool {
+        let &DirectiveLine { raw_directive: line, .. } = line;
+
         // Ensure the directive is a whole word. Do not match "ignore-x86" when
         // the line says "ignore-x86_64".
         line.starts_with(directive)
             && matches!(line.as_bytes().get(directive.len()), None | Some(&b' ') | Some(&b':'))
     }
 
-    fn parse_negative_name_directive(&self, line: &str, directive: &str) -> bool {
-        line.starts_with("no-") && self.parse_name_directive(&line[3..], directive)
-    }
-
-    pub fn parse_name_value_directive(
+    fn parse_name_value_directive(
         &self,
-        line: &str,
+        line: &DirectiveLine<'_>,
         directive: &str,
         testfile: &Utf8Path,
-        line_number: usize,
     ) -> Option<String> {
+        let &DirectiveLine { line_number, raw_directive: line, .. } = line;
+
         let colon = directive.len();
         if line.starts_with(directive) && line.as_bytes().get(colon) == Some(&b':') {
             let value = line[(colon + 1)..].to_owned();
@@ -1144,52 +1116,37 @@ impl Config {
         }
     }
 
-    fn parse_edition(&self, line: &str, testfile: &Utf8Path, line_number: usize) -> Option<String> {
-        self.parse_name_value_directive(line, "edition", testfile, line_number)
+    fn parse_edition(&self, line: &DirectiveLine<'_>, testfile: &Utf8Path) -> Option<String> {
+        self.parse_name_value_directive(line, "edition", testfile)
     }
 
-    fn set_name_directive(&self, line: &str, directive: &str, value: &mut bool) {
-        match value {
-            true => {
-                if self.parse_negative_name_directive(line, directive) {
-                    *value = false;
-                }
-            }
-            false => {
-                if self.parse_name_directive(line, directive) {
-                    *value = true;
-                }
-            }
-        }
+    fn set_name_directive(&self, line: &DirectiveLine<'_>, directive: &str, value: &mut bool) {
+        // If the flag is already true, don't bother looking at the directive.
+        *value = *value || self.parse_name_directive(line, directive);
     }
 
     fn set_name_value_directive<T>(
         &self,
-        line: &str,
+        line: &DirectiveLine<'_>,
         directive: &str,
         testfile: &Utf8Path,
-        line_number: usize,
         value: &mut Option<T>,
         parse: impl FnOnce(String) -> T,
     ) {
         if value.is_none() {
-            *value =
-                self.parse_name_value_directive(line, directive, testfile, line_number).map(parse);
+            *value = self.parse_name_value_directive(line, directive, testfile).map(parse);
         }
     }
 
     fn push_name_value_directive<T>(
         &self,
-        line: &str,
+        line: &DirectiveLine<'_>,
         directive: &str,
         testfile: &Utf8Path,
-        line_number: usize,
         values: &mut Vec<T>,
         parse: impl FnOnce(String) -> T,
     ) {
-        if let Some(value) =
-            self.parse_name_value_directive(line, directive, testfile, line_number).map(parse)
-        {
+        if let Some(value) = self.parse_name_value_directive(line, directive, testfile).map(parse) {
             values.push(value);
         }
     }
@@ -1482,8 +1439,8 @@ pub(crate) fn make_test_description<R: Read>(
         &mut local_poisoned,
         path,
         src,
-        &mut |directive @ DirectiveLine { line_number, raw_directive: ln, .. }| {
-            if !directive.applies_to_test_revision(test_revision) {
+        &mut |ref ln @ DirectiveLine { line_number, .. }| {
+            if !ln.applies_to_test_revision(test_revision) {
                 return;
             }
 
@@ -1507,9 +1464,9 @@ pub(crate) fn make_test_description<R: Read>(
             decision!(cfg::handle_ignore(config, ln));
             decision!(cfg::handle_only(config, ln));
             decision!(needs::handle_needs(&cache.needs, config, ln));
-            decision!(ignore_llvm(config, path, ln, line_number));
-            decision!(ignore_backends(config, path, ln, line_number));
-            decision!(needs_backends(config, path, ln, line_number));
+            decision!(ignore_llvm(config, path, ln));
+            decision!(ignore_backends(config, path, ln));
+            decision!(needs_backends(config, path, ln));
             decision!(ignore_cdb(config, ln));
             decision!(ignore_gdb(config, ln));
             decision!(ignore_lldb(config, ln));
@@ -1549,7 +1506,9 @@ pub(crate) fn make_test_description<R: Read>(
     }
 }
 
-fn ignore_cdb(config: &Config, line: &str) -> IgnoreDecision {
+fn ignore_cdb(config: &Config, line: &DirectiveLine<'_>) -> IgnoreDecision {
+    let &DirectiveLine { raw_directive: line, .. } = line;
+
     if config.debugger != Some(Debugger::Cdb) {
         return IgnoreDecision::Continue;
     }
@@ -1572,7 +1531,9 @@ fn ignore_cdb(config: &Config, line: &str) -> IgnoreDecision {
     IgnoreDecision::Continue
 }
 
-fn ignore_gdb(config: &Config, line: &str) -> IgnoreDecision {
+fn ignore_gdb(config: &Config, line: &DirectiveLine<'_>) -> IgnoreDecision {
+    let &DirectiveLine { raw_directive: line, .. } = line;
+
     if config.debugger != Some(Debugger::Gdb) {
         return IgnoreDecision::Continue;
     }
@@ -1620,7 +1581,9 @@ fn ignore_gdb(config: &Config, line: &str) -> IgnoreDecision {
     IgnoreDecision::Continue
 }
 
-fn ignore_lldb(config: &Config, line: &str) -> IgnoreDecision {
+fn ignore_lldb(config: &Config, line: &DirectiveLine<'_>) -> IgnoreDecision {
+    let &DirectiveLine { raw_directive: line, .. } = line;
+
     if config.debugger != Some(Debugger::Lldb) {
         return IgnoreDecision::Continue;
     }
@@ -1642,14 +1605,9 @@ fn ignore_lldb(config: &Config, line: &str) -> IgnoreDecision {
     IgnoreDecision::Continue
 }
 
-fn ignore_backends(
-    config: &Config,
-    path: &Utf8Path,
-    line: &str,
-    line_number: usize,
-) -> IgnoreDecision {
+fn ignore_backends(config: &Config, path: &Utf8Path, line: &DirectiveLine<'_>) -> IgnoreDecision {
     if let Some(backends_to_ignore) =
-        config.parse_name_value_directive(line, "ignore-backends", path, line_number)
+        config.parse_name_value_directive(line, "ignore-backends", path)
     {
         for backend in backends_to_ignore.split_whitespace().map(|backend| {
             match CodegenBackend::try_from(backend) {
@@ -1669,15 +1627,8 @@ fn ignore_backends(
     IgnoreDecision::Continue
 }
 
-fn needs_backends(
-    config: &Config,
-    path: &Utf8Path,
-    line: &str,
-    line_number: usize,
-) -> IgnoreDecision {
-    if let Some(needed_backends) =
-        config.parse_name_value_directive(line, "needs-backends", path, line_number)
-    {
+fn needs_backends(config: &Config, path: &Utf8Path, line: &DirectiveLine<'_>) -> IgnoreDecision {
+    if let Some(needed_backends) = config.parse_name_value_directive(line, "needs-backends", path) {
         if !needed_backends
             .split_whitespace()
             .map(|backend| match CodegenBackend::try_from(backend) {
@@ -1699,9 +1650,9 @@ fn needs_backends(
     IgnoreDecision::Continue
 }
 
-fn ignore_llvm(config: &Config, path: &Utf8Path, line: &str, line_number: usize) -> IgnoreDecision {
+fn ignore_llvm(config: &Config, path: &Utf8Path, line: &DirectiveLine<'_>) -> IgnoreDecision {
     if let Some(needed_components) =
-        config.parse_name_value_directive(line, "needs-llvm-components", path, line_number)
+        config.parse_name_value_directive(line, "needs-llvm-components", path)
     {
         let components: HashSet<_> = config.llvm_components.split_whitespace().collect();
         if let Some(missing_component) = needed_components
@@ -1723,7 +1674,7 @@ fn ignore_llvm(config: &Config, path: &Utf8Path, line: &str, line_number: usize)
         // Note that these `min` versions will check for not just major versions.
 
         if let Some(version_string) =
-            config.parse_name_value_directive(line, "min-llvm-version", path, line_number)
+            config.parse_name_value_directive(line, "min-llvm-version", path)
         {
             let min_version = extract_llvm_version(&version_string);
             // Ignore if actual version is smaller than the minimum required version.
@@ -1735,7 +1686,7 @@ fn ignore_llvm(config: &Config, path: &Utf8Path, line: &str, line_number: usize)
                 };
             }
         } else if let Some(version_string) =
-            config.parse_name_value_directive(line, "max-llvm-major-version", path, line_number)
+            config.parse_name_value_directive(line, "max-llvm-major-version", path)
         {
             let max_version = extract_llvm_version(&version_string);
             // Ignore if actual major version is larger than the maximum required major version.
@@ -1749,7 +1700,7 @@ fn ignore_llvm(config: &Config, path: &Utf8Path, line: &str, line_number: usize)
                 };
             }
         } else if let Some(version_string) =
-            config.parse_name_value_directive(line, "min-system-llvm-version", path, line_number)
+            config.parse_name_value_directive(line, "min-system-llvm-version", path)
         {
             let min_version = extract_llvm_version(&version_string);
             // Ignore if using system LLVM and actual version
@@ -1762,7 +1713,7 @@ fn ignore_llvm(config: &Config, path: &Utf8Path, line: &str, line_number: usize)
                 };
             }
         } else if let Some(version_range) =
-            config.parse_name_value_directive(line, "ignore-llvm-version", path, line_number)
+            config.parse_name_value_directive(line, "ignore-llvm-version", path)
         {
             // Syntax is: "ignore-llvm-version: <version1> [- <version2>]"
             let (v_min, v_max) =
@@ -1788,7 +1739,7 @@ fn ignore_llvm(config: &Config, path: &Utf8Path, line: &str, line_number: usize)
                 }
             }
         } else if let Some(version_string) =
-            config.parse_name_value_directive(line, "exact-llvm-major-version", path, line_number)
+            config.parse_name_value_directive(line, "exact-llvm-major-version", path)
         {
             // Syntax is "exact-llvm-major-version: <version>"
             let version = extract_llvm_version(&version_string);
diff --git a/src/tools/compiletest/src/directives/auxiliary.rs b/src/tools/compiletest/src/directives/auxiliary.rs
index 7c1ed2e7006..0675a6feac3 100644
--- a/src/tools/compiletest/src/directives/auxiliary.rs
+++ b/src/tools/compiletest/src/directives/auxiliary.rs
@@ -7,6 +7,7 @@ use camino::Utf8Path;
 
 use super::directives::{AUX_BIN, AUX_BUILD, AUX_CODEGEN_BACKEND, AUX_CRATE, PROC_MACRO};
 use crate::common::Config;
+use crate::directives::DirectiveLine;
 
 /// Properties parsed from `aux-*` test directives.
 #[derive(Clone, Debug, Default)]
@@ -45,40 +46,28 @@ impl AuxProps {
 /// and update [`AuxProps`] accordingly.
 pub(super) fn parse_and_update_aux(
     config: &Config,
-    ln: &str,
+    directive_line: &DirectiveLine<'_>,
     testfile: &Utf8Path,
-    line_number: usize,
     aux: &mut AuxProps,
 ) {
+    let &DirectiveLine { raw_directive: ln, .. } = directive_line;
+
     if !(ln.starts_with("aux-") || ln.starts_with("proc-macro")) {
         return;
     }
 
-    config.push_name_value_directive(ln, AUX_BUILD, testfile, line_number, &mut aux.builds, |r| {
+    let ln = directive_line;
+
+    config.push_name_value_directive(ln, AUX_BUILD, testfile, &mut aux.builds, |r| {
         r.trim().to_string()
     });
-    config.push_name_value_directive(ln, AUX_BIN, testfile, line_number, &mut aux.bins, |r| {
+    config
+        .push_name_value_directive(ln, AUX_BIN, testfile, &mut aux.bins, |r| r.trim().to_string());
+    config.push_name_value_directive(ln, AUX_CRATE, testfile, &mut aux.crates, parse_aux_crate);
+    config.push_name_value_directive(ln, PROC_MACRO, testfile, &mut aux.proc_macros, |r| {
         r.trim().to_string()
     });
-    config.push_name_value_directive(
-        ln,
-        AUX_CRATE,
-        testfile,
-        line_number,
-        &mut aux.crates,
-        parse_aux_crate,
-    );
-    config.push_name_value_directive(
-        ln,
-        PROC_MACRO,
-        testfile,
-        line_number,
-        &mut aux.proc_macros,
-        |r| r.trim().to_string(),
-    );
-    if let Some(r) =
-        config.parse_name_value_directive(ln, AUX_CODEGEN_BACKEND, testfile, line_number)
-    {
+    if let Some(r) = config.parse_name_value_directive(ln, AUX_CODEGEN_BACKEND, testfile) {
         aux.codegen_backend = Some(r.trim().to_owned());
     }
 }
diff --git a/src/tools/compiletest/src/directives/cfg.rs b/src/tools/compiletest/src/directives/cfg.rs
index 802a1d63d1f..62a4b88a33a 100644
--- a/src/tools/compiletest/src/directives/cfg.rs
+++ b/src/tools/compiletest/src/directives/cfg.rs
@@ -1,12 +1,14 @@
 use std::collections::HashSet;
 
 use crate::common::{CompareMode, Config, Debugger};
-use crate::directives::IgnoreDecision;
+use crate::directives::{DirectiveLine, IgnoreDecision};
 
 const EXTRA_ARCHS: &[&str] = &["spirv"];
 
-pub(super) fn handle_ignore(config: &Config, line: &str) -> IgnoreDecision {
+pub(super) fn handle_ignore(config: &Config, line: &DirectiveLine<'_>) -> IgnoreDecision {
     let parsed = parse_cfg_name_directive(config, line, "ignore");
+    let &DirectiveLine { raw_directive: line, .. } = line;
+
     match parsed.outcome {
         MatchOutcome::NoMatch => IgnoreDecision::Continue,
         MatchOutcome::Match => IgnoreDecision::Ignore {
@@ -21,8 +23,10 @@ pub(super) fn handle_ignore(config: &Config, line: &str) -> IgnoreDecision {
     }
 }
 
-pub(super) fn handle_only(config: &Config, line: &str) -> IgnoreDecision {
+pub(super) fn handle_only(config: &Config, line: &DirectiveLine<'_>) -> IgnoreDecision {
     let parsed = parse_cfg_name_directive(config, line, "only");
+    let &DirectiveLine { raw_directive: line, .. } = line;
+
     match parsed.outcome {
         MatchOutcome::Match => IgnoreDecision::Continue,
         MatchOutcome::NoMatch => IgnoreDecision::Ignore {
@@ -43,9 +47,11 @@ pub(super) fn handle_only(config: &Config, line: &str) -> IgnoreDecision {
 /// or `only-windows`.
 fn parse_cfg_name_directive<'a>(
     config: &Config,
-    line: &'a str,
+    line: &'a DirectiveLine<'a>,
     prefix: &str,
 ) -> ParsedNameDirective<'a> {
+    let &DirectiveLine { raw_directive: line, .. } = line;
+
     if !line.as_bytes().starts_with(prefix.as_bytes()) {
         return ParsedNameDirective::not_a_directive();
     }
diff --git a/src/tools/compiletest/src/directives/needs.rs b/src/tools/compiletest/src/directives/needs.rs
index 3b7a9478717..c8a729d8aab 100644
--- a/src/tools/compiletest/src/directives/needs.rs
+++ b/src/tools/compiletest/src/directives/needs.rs
@@ -1,10 +1,10 @@
 use crate::common::{Config, KNOWN_CRATE_TYPES, KNOWN_TARGET_HAS_ATOMIC_WIDTHS, Sanitizer};
-use crate::directives::{IgnoreDecision, llvm_has_libzstd};
+use crate::directives::{DirectiveLine, IgnoreDecision, llvm_has_libzstd};
 
 pub(super) fn handle_needs(
     cache: &CachedNeedsConditions,
     config: &Config,
-    ln: &str,
+    ln: &DirectiveLine<'_>,
 ) -> IgnoreDecision {
     // 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.
@@ -181,6 +181,8 @@ pub(super) fn handle_needs(
         },
     ];
 
+    let &DirectiveLine { raw_directive: ln, .. } = ln;
+
     let (name, rest) = match ln.split_once([':', ' ']) {
         Some((name, rest)) => (name, Some(rest)),
         None => (ln, None),
diff --git a/src/tools/compiletest/src/executor.rs b/src/tools/compiletest/src/executor.rs
index c8e13d44573..c7aca6d1c5a 100644
--- a/src/tools/compiletest/src/executor.rs
+++ b/src/tools/compiletest/src/executor.rs
@@ -9,8 +9,8 @@ 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 std::sync::{Arc, mpsc};
+use std::{env, hint, mem, panic, thread};
 
 use camino::Utf8PathBuf;
 
@@ -130,10 +130,6 @@ fn run_test_inner(
         panic_hook::set_capture_buf(Default::default());
     }
 
-    if let CaptureKind::Old { ref buf } = capture {
-        io::set_output_capture(Some(Arc::clone(buf)));
-    }
-
     let stdout = capture.stdout();
     let stderr = capture.stderr();
 
@@ -144,9 +140,6 @@ fn run_test_inner(
         // Forward any captured panic message to (captured) stderr.
         write!(stderr, "{panic_buf}");
     }
-    if matches!(capture, CaptureKind::Old { .. }) {
-        io::set_output_capture(None);
-    }
 
     let outcome = match (should_panic, panic_payload) {
         (ShouldPanic::No, None) | (ShouldPanic::Yes, Some(_)) => TestOutcome::Succeeded,
@@ -167,31 +160,24 @@ enum CaptureKind {
     /// runners, whose output is always captured.)
     None,
 
-    /// Use the old output-capture implementation, which relies on the unstable
-    /// library feature `#![feature(internal_output_capture)]`.
-    Old { buf: Arc<Mutex<Vec<u8>>> },
-
-    /// Use the new output-capture implementation, which only uses stable Rust.
-    New { buf: output_capture::CaptureBuf },
+    /// Capture all console output that would be printed by test runners via
+    /// their `stdout` and `stderr` trait objects, or via the custom panic hook.
+    Capture { buf: output_capture::CaptureBuf },
 }
 
 impl CaptureKind {
     fn for_config(config: &Config) -> Self {
         if config.nocapture {
             Self::None
-        } else if config.new_output_capture {
-            Self::New { buf: output_capture::CaptureBuf::new() }
         } else {
-            // Create a capure buffer for `io::set_output_capture`.
-            Self::Old { buf: Default::default() }
+            Self::Capture { buf: output_capture::CaptureBuf::new() }
         }
     }
 
     fn should_set_panic_hook(&self) -> bool {
         match self {
             Self::None => false,
-            Self::Old { .. } => true,
-            Self::New { .. } => true,
+            Self::Capture { .. } => true,
         }
     }
 
@@ -205,16 +191,15 @@ impl CaptureKind {
 
     fn capture_buf_or<'a>(&'a self, fallback: &'a dyn ConsoleOut) -> &'a dyn ConsoleOut {
         match self {
-            Self::None | Self::Old { .. } => fallback,
-            Self::New { buf } => buf,
+            Self::None => fallback,
+            Self::Capture { buf } => buf,
         }
     }
 
     fn into_inner(self) -> Option<Vec<u8>> {
         match self {
             Self::None => None,
-            Self::Old { buf } => Some(buf.lock().unwrap_or_else(|e| e.into_inner()).to_vec()),
-            Self::New { buf } => Some(buf.into_inner().into()),
+            Self::Capture { buf } => Some(buf.into_inner().into()),
         }
     }
 }
diff --git a/src/tools/compiletest/src/lib.rs b/src/tools/compiletest/src/lib.rs
index ce2a3d4b5fb..15e31dadf97 100644
--- a/src/tools/compiletest/src/lib.rs
+++ b/src/tools/compiletest/src/lib.rs
@@ -1,9 +1,4 @@
 #![crate_name = "compiletest"]
-// Needed by the "new" test executor that does not depend on libtest.
-// FIXME(Zalathar): We should be able to get rid of `internal_output_capture`,
-// by having `runtest` manually capture all of its println-like output instead.
-// That would result in compiletest being written entirely in stable Rust!
-#![feature(internal_output_capture)]
 
 #[cfg(test)]
 mod tests;
@@ -178,12 +173,6 @@ pub fn parse_config(args: Vec<String>) -> Config {
         // FIXME: Temporarily retained so we can point users to `--no-capture`
         .optflag("", "nocapture", "")
         .optflag("", "no-capture", "don't capture stdout/stderr of tests")
-        .optopt(
-            "N",
-            "new-output-capture",
-            "enables or disables the new output-capture implementation",
-            "off|on",
-        )
         .optflag("", "profiler-runtime", "is the profiler runtime enabled for this target")
         .optflag("h", "help", "show this message")
         .reqopt("", "channel", "current Rust channel", "CHANNEL")
@@ -480,14 +469,6 @@ pub fn parse_config(args: Vec<String>) -> Config {
         supported_crate_types: OnceLock::new(),
 
         nocapture: matches.opt_present("no-capture"),
-        new_output_capture: {
-            let value = matches
-                .opt_str("new-output-capture")
-                .or_else(|| env::var("COMPILETEST_NEW_OUTPUT_CAPTURE").ok())
-                .unwrap_or_else(|| "on".to_owned());
-            parse_bool_option(&value)
-                .unwrap_or_else(|| panic!("unknown `--new-output-capture` value `{value}` given"))
-        },
 
         nightly_branch: matches.opt_str("nightly-branch").unwrap(),
         git_merge_commit_email: matches.opt_str("git-merge-commit-email").unwrap(),
@@ -503,19 +484,6 @@ pub fn parse_config(args: Vec<String>) -> Config {
     }
 }
 
-/// Parses the same set of boolean values accepted by rustc command-line arguments.
-///
-/// Accepting all of these values is more complicated than just picking one
-/// pair, but has the advantage that contributors who are used to rustc
-/// shouldn't have to think about which values are legal.
-fn parse_bool_option(value: &str) -> Option<bool> {
-    match value {
-        "off" | "no" | "n" | "false" => Some(false),
-        "on" | "yes" | "y" | "true" => Some(true),
-        _ => None,
-    }
-}
-
 pub fn opt_str(maybestr: &Option<String>) -> &str {
     match *maybestr {
         None => "(none)",
diff --git a/src/tools/compiletest/src/panic_hook.rs b/src/tools/compiletest/src/panic_hook.rs
index 1661ca6dabe..4f1e2547518 100644
--- a/src/tools/compiletest/src/panic_hook.rs
+++ b/src/tools/compiletest/src/panic_hook.rs
@@ -42,7 +42,7 @@ fn custom_panic_hook(default_hook: &PanicHook, info: &panic::PanicHookInfo<'_>)
 
     let thread = thread::current().name().unwrap_or("(test runner)").to_owned();
     let location = get_location(info);
-    let payload = payload_as_str(info).unwrap_or("Box<dyn Any>");
+    let payload = info.payload_as_str().unwrap_or("Box<dyn Any>");
     let backtrace = Backtrace::capture();
 
     writeln!(out, "\nthread '{thread}' panicked at {location}:\n{payload}").unwrap();
@@ -72,19 +72,6 @@ fn get_location<'a>(info: &'a PanicHookInfo<'_>) -> &'a dyn Display {
     }
 }
 
-/// FIXME(Zalathar): Replace with `PanicHookInfo::payload_as_str` when that's
-/// stable in beta.
-fn payload_as_str<'a>(info: &'a PanicHookInfo<'_>) -> Option<&'a str> {
-    let payload = info.payload();
-    if let Some(s) = payload.downcast_ref::<&str>() {
-        Some(s)
-    } else if let Some(s) = payload.downcast_ref::<String>() {
-        Some(s)
-    } else {
-        None
-    }
-}
-
 fn rust_backtrace_full() -> bool {
     static RUST_BACKTRACE_FULL: LazyLock<bool> =
         LazyLock::new(|| matches!(env::var("RUST_BACKTRACE").as_deref(), Ok("full")));
diff --git a/src/tools/compiletest/src/runtest/debugger.rs b/src/tools/compiletest/src/runtest/debugger.rs
index ba824124e87..3d439e98eb7 100644
--- a/src/tools/compiletest/src/runtest/debugger.rs
+++ b/src/tools/compiletest/src/runtest/debugger.rs
@@ -4,7 +4,6 @@ use std::io::{BufRead, BufReader};
 
 use camino::{Utf8Path, Utf8PathBuf};
 
-use crate::common::Config;
 use crate::runtest::ProcRes;
 
 /// Representation of information to invoke a debugger and check its output
@@ -20,11 +19,7 @@ pub(super) struct DebuggerCommands {
 }
 
 impl DebuggerCommands {
-    pub fn parse_from(
-        file: &Utf8Path,
-        config: &Config,
-        debugger_prefix: &str,
-    ) -> Result<Self, String> {
+    pub fn parse_from(file: &Utf8Path, debugger_prefix: &str) -> Result<Self, String> {
         let command_directive = format!("{debugger_prefix}-command");
         let check_directive = format!("{debugger_prefix}-check");
 
@@ -47,14 +42,10 @@ impl DebuggerCommands {
                 continue;
             };
 
-            if let Some(command) =
-                config.parse_name_value_directive(&line, &command_directive, file, line_no)
-            {
+            if let Some(command) = parse_name_value(&line, &command_directive) {
                 commands.push(command);
             }
-            if let Some(pattern) =
-                config.parse_name_value_directive(&line, &check_directive, file, line_no)
-            {
+            if let Some(pattern) = parse_name_value(&line, &check_directive) {
                 check_lines.push((line_no, pattern));
             }
         }
@@ -114,6 +105,18 @@ impl DebuggerCommands {
     }
 }
 
+/// Split off from the main `parse_name_value_directive`, so that improvements
+/// to directive handling aren't held back by debuginfo test commands.
+fn parse_name_value(line: &str, name: &str) -> Option<String> {
+    if let Some(after_name) = line.strip_prefix(name)
+        && let Some(value) = after_name.strip_prefix(':')
+    {
+        Some(value.to_owned())
+    } else {
+        None
+    }
+}
+
 /// Check that the pattern in `check_line` applies to `line`. Returns `true` if they do match.
 fn check_single_line(line: &str, check_line: &str) -> bool {
     // Allow check lines to leave parts unspecified (e.g., uninitialized
diff --git a/src/tools/compiletest/src/runtest/debuginfo.rs b/src/tools/compiletest/src/runtest/debuginfo.rs
index 071c0863b7e..9175a38ffa5 100644
--- a/src/tools/compiletest/src/runtest/debuginfo.rs
+++ b/src/tools/compiletest/src/runtest/debuginfo.rs
@@ -59,7 +59,7 @@ impl TestCx<'_> {
         }
 
         // Parse debugger commands etc from test files
-        let dbg_cmds = DebuggerCommands::parse_from(&self.testpaths.file, self.config, "cdb")
+        let dbg_cmds = DebuggerCommands::parse_from(&self.testpaths.file, "cdb")
             .unwrap_or_else(|e| self.fatal(&e));
 
         // https://docs.microsoft.com/en-us/windows-hardware/drivers/debugger/debugger-commands
@@ -130,7 +130,7 @@ impl TestCx<'_> {
     }
 
     fn run_debuginfo_gdb_test_no_opt(&self) {
-        let dbg_cmds = DebuggerCommands::parse_from(&self.testpaths.file, self.config, "gdb")
+        let dbg_cmds = DebuggerCommands::parse_from(&self.testpaths.file, "gdb")
             .unwrap_or_else(|e| self.fatal(&e));
         let mut cmds = dbg_cmds.commands.join("\n");
 
@@ -397,7 +397,7 @@ impl TestCx<'_> {
         }
 
         // Parse debugger commands etc from test files
-        let dbg_cmds = DebuggerCommands::parse_from(&self.testpaths.file, self.config, "lldb")
+        let dbg_cmds = DebuggerCommands::parse_from(&self.testpaths.file, "lldb")
             .unwrap_or_else(|e| self.fatal(&e));
 
         // Write debugger script:
diff --git a/src/tools/miri/src/lib.rs b/src/tools/miri/src/lib.rs
index 7f5f25b9f66..1f82f154b0b 100644
--- a/src/tools/miri/src/lib.rs
+++ b/src/tools/miri/src/lib.rs
@@ -1,4 +1,3 @@
-#![cfg_attr(bootstrap, feature(strict_overflow_ops))]
 #![feature(abort_unwind)]
 #![feature(cfg_select)]
 #![feature(rustc_private)]
diff --git a/src/tools/miri/src/machine.rs b/src/tools/miri/src/machine.rs
index d307636e782..412640a112c 100644
--- a/src/tools/miri/src/machine.rs
+++ b/src/tools/miri/src/machine.rs
@@ -1341,7 +1341,7 @@ impl<'tcx> Machine<'tcx> for MiriMachine<'tcx> {
                     name = ecx.tcx.def_path_str(def_id),
                     krate = ecx.tcx.crate_name(def_id.krate),
                     decl_size = extern_decl_layout.size.bytes(),
-                    decl_align = extern_decl_layout.align.abi.bytes(),
+                    decl_align = extern_decl_layout.align.bytes(),
                     shim_size = info.size.bytes(),
                     shim_align = info.align.bytes(),
                 )
diff --git a/src/tools/miri/tests/panic/mir-validation.rs b/src/tools/miri/tests/panic/mir-validation.rs
index b9097f2e8c5..2d0d530754d 100644
--- a/src/tools/miri/tests/panic/mir-validation.rs
+++ b/src/tools/miri/tests/panic/mir-validation.rs
@@ -9,11 +9,6 @@
 // and we don't even get a regular panic; rustc aborts with a different exit code instead.
 //@ignore-host: windows
 
-// FIXME: this tests a crash in rustc. For stage1, rustc is built with the downloaded standard
-// library which doesn't yet print the thread ID. Normalization can be removed at the stage bump.
-// For the grep: cfg(bootstrap)
-//@normalize-stderr-test: "thread 'rustc' panicked" -> "thread 'rustc' ($$TID) panicked"
-
 #![feature(custom_mir, core_intrinsics)]
 use core::intrinsics::mir::*;
 
diff --git a/src/tools/miri/tests/pass/both_borrows/smallvec.rs b/src/tools/miri/tests/pass/both_borrows/smallvec.rs
index f48815e37be..fa5cfb03de2 100644
--- a/src/tools/miri/tests/pass/both_borrows/smallvec.rs
+++ b/src/tools/miri/tests/pass/both_borrows/smallvec.rs
@@ -25,7 +25,7 @@ impl<T, const N: usize> RawSmallVec<T, N> {
     }
 
     const fn as_mut_ptr_inline(&mut self) -> *mut T {
-        (unsafe { &raw mut self.inline }) as *mut T
+        &raw mut self.inline as *mut T
     }
 
     const unsafe fn as_mut_ptr_heap(&mut self) -> *mut T {
diff --git a/src/tools/miri/tests/pass/vec.rs b/src/tools/miri/tests/pass/vec.rs
index 3e526813bb4..8b1b1e143b1 100644
--- a/src/tools/miri/tests/pass/vec.rs
+++ b/src/tools/miri/tests/pass/vec.rs
@@ -169,6 +169,15 @@ fn miri_issue_2759() {
     input.replace_range(0..0, "0");
 }
 
+/// This was skirting the edge of UB, let's make sure it remains on the sound side.
+/// Context: <https://github.com/rust-lang/rust/pull/141032>.
+fn extract_if() {
+    let mut v = vec![Box::new(0u64), Box::new(1u64)];
+    for item in v.extract_if(.., |x| **x == 0) {
+        drop(item);
+    }
+}
+
 fn main() {
     assert_eq!(vec_reallocate().len(), 5);
 
@@ -199,4 +208,5 @@ fn main() {
     swap_remove();
     reverse();
     miri_issue_2759();
+    extract_if();
 }
diff --git a/src/tools/run-make-support/src/external_deps/rustc.rs b/src/tools/run-make-support/src/external_deps/rustc.rs
index b74b1d5e166..b461a24a061 100644
--- a/src/tools/run-make-support/src/external_deps/rustc.rs
+++ b/src/tools/run-make-support/src/external_deps/rustc.rs
@@ -366,6 +366,13 @@ impl Rustc {
         self
     }
 
+    pub fn split_dwarf_out_dir(&mut self, out_dir: Option<&str>) -> &mut Self {
+        if let Some(out_dir) = out_dir {
+            self.cmd.arg(format!("-Zsplit-dwarf-out-dir={out_dir}"));
+        }
+        self
+    }
+
     /// Pass the `--verbose` flag.
     pub fn verbose(&mut self) -> &mut Self {
         self.cmd.arg("--verbose");
diff --git a/src/tools/rust-analyzer/.github/workflows/ci.yaml b/src/tools/rust-analyzer/.github/workflows/ci.yaml
index 770652494f4..0eb57a605f8 100644
--- a/src/tools/rust-analyzer/.github/workflows/ci.yaml
+++ b/src/tools/rust-analyzer/.github/workflows/ci.yaml
@@ -56,8 +56,8 @@ jobs:
       # Install a pinned rustc commit to avoid surprises
       - name: Install Rust toolchain
         run: |
-          RUSTC_VERSION=`cat rust-version`
-          rustup-toolchain-install-master ${RUSTC_VERSION} -c rust-src -c rustfmt
+          RUSTC_VERSION=$(cat rust-version)
+          rustup-toolchain-install-master ${RUSTC_VERSION} -c cargo -c rust-src -c rustfmt
           rustup default ${RUSTC_VERSION}
 
       # Emulate a nightly toolchain, because the toolchain installed above does not have "nightly"
@@ -98,9 +98,9 @@ jobs:
         run: |
           rustup update --no-self-update stable
           rustup default stable
-          rustup component add --toolchain stable rust-src clippy
-          # We always use a nightly rustfmt, regardless of channel, because we need
-          # --file-lines.
+          rustup component add --toolchain stable rust-src clippy rustfmt
+          # We also install a nightly rustfmt, because we use `--file-lines` in
+          # a test.
           rustup toolchain install nightly --profile minimal --component rustfmt
       # https://github.com/actions-rust-lang/setup-rust-toolchain/blob/main/rust.json
       - name: Install Rust Problem Matcher
diff --git a/src/tools/rust-analyzer/Cargo.lock b/src/tools/rust-analyzer/Cargo.lock
index 17dea1ba4cd..086f38f06a5 100644
--- a/src/tools/rust-analyzer/Cargo.lock
+++ b/src/tools/rust-analyzer/Cargo.lock
@@ -546,6 +546,12 @@ dependencies = [
 ]
 
 [[package]]
+name = "fixedbitset"
+version = "0.5.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1d674e81391d1e1ab681a28d99df07927c6d4aa5b027d7da16ba32d1d21ecd99"
+
+[[package]]
 name = "flate2"
 version = "1.1.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -775,6 +781,7 @@ dependencies = [
  "itertools",
  "la-arena 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "oorandom",
+ "petgraph",
  "project-model",
  "query-group-macro",
  "ra-ap-rustc_abi",
@@ -1327,9 +1334,9 @@ dependencies = [
 
 [[package]]
 name = "memchr"
-version = "2.7.5"
+version = "2.7.6"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "32a282da65faaf38286cf3be983213fcf1d2e2a58700e808f83f4ea9a4804bc0"
+checksum = "f52b00d39961fc5b2736ea853c9cc86238e165017a493d1d5c8eac6bdc4cc273"
 
 [[package]]
 name = "memmap2"
@@ -1595,6 +1602,17 @@ dependencies = [
 ]
 
 [[package]]
+name = "petgraph"
+version = "0.8.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "54acf3a685220b533e437e264e4d932cfbdc4cc7ec0cd232ed73c08d03b8a7ca"
+dependencies = [
+ "fixedbitset",
+ "hashbrown 0.15.4",
+ "indexmap",
+]
+
+[[package]]
 name = "pin-project-lite"
 version = "0.2.16"
 source = "registry+https://github.com/rust-lang/crates.io-index"
diff --git a/src/tools/rust-analyzer/Cargo.toml b/src/tools/rust-analyzer/Cargo.toml
index 0401367f786..d3a4e375613 100644
--- a/src/tools/rust-analyzer/Cargo.toml
+++ b/src/tools/rust-analyzer/Cargo.toml
@@ -170,6 +170,7 @@ tracing-subscriber = { version = "0.3.20", default-features = false, features =
 triomphe = { version = "0.1.14", default-features = false, features = ["std"] }
 url = "2.5.4"
 xshell = "0.2.7"
+petgraph = { version = "0.8.2", default-features = false }
 
 # We need to freeze the version of the crate, as the raw-api feature is considered unstable
 dashmap = { version = "=6.1.0", features = ["raw-api", "inline"] }
diff --git a/src/tools/rust-analyzer/crates/hir-expand/src/builtin/derive_macro.rs b/src/tools/rust-analyzer/crates/hir-expand/src/builtin/derive_macro.rs
index 15e68ff95cd..0fa412ad7fa 100644
--- a/src/tools/rust-analyzer/crates/hir-expand/src/builtin/derive_macro.rs
+++ b/src/tools/rust-analyzer/crates/hir-expand/src/builtin/derive_macro.rs
@@ -12,7 +12,7 @@ use tracing::debug;
 
 use crate::{
     ExpandError, ExpandResult, MacroCallId,
-    builtin::quote::{dollar_crate, quote},
+    builtin::quote::dollar_crate,
     db::ExpandDatabase,
     hygiene::span_with_def_site_ctxt,
     name::{self, AsName, Name},
diff --git a/src/tools/rust-analyzer/crates/hir-expand/src/builtin/fn_macro.rs b/src/tools/rust-analyzer/crates/hir-expand/src/builtin/fn_macro.rs
index ec344613761..6fe63f249cd 100644
--- a/src/tools/rust-analyzer/crates/hir-expand/src/builtin/fn_macro.rs
+++ b/src/tools/rust-analyzer/crates/hir-expand/src/builtin/fn_macro.rs
@@ -19,7 +19,7 @@ use syntax_bridge::syntax_node_to_token_tree;
 
 use crate::{
     EditionedFileId, ExpandError, ExpandResult, Lookup as _, MacroCallId,
-    builtin::quote::{WithDelimiter, dollar_crate, quote},
+    builtin::quote::{WithDelimiter, dollar_crate},
     db::ExpandDatabase,
     hygiene::{span_with_call_site_ctxt, span_with_def_site_ctxt},
     name,
diff --git a/src/tools/rust-analyzer/crates/hir-expand/src/builtin/quote.rs b/src/tools/rust-analyzer/crates/hir-expand/src/builtin/quote.rs
index 70c38d4d7c7..84dd4a24d90 100644
--- a/src/tools/rust-analyzer/crates/hir-expand/src/builtin/quote.rs
+++ b/src/tools/rust-analyzer/crates/hir-expand/src/builtin/quote.rs
@@ -229,8 +229,6 @@ mod tests {
     use span::{Edition, ROOT_ERASED_FILE_AST_ID, SpanAnchor, SyntaxContext};
     use syntax::{TextRange, TextSize};
 
-    use super::quote;
-
     const DUMMY: tt::Span = tt::Span {
         range: TextRange::empty(TextSize::new(0)),
         anchor: SpanAnchor {
diff --git a/src/tools/rust-analyzer/crates/hir-ty/Cargo.toml b/src/tools/rust-analyzer/crates/hir-ty/Cargo.toml
index 138d02e5a61..4013d19ad08 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/Cargo.toml
+++ b/src/tools/rust-analyzer/crates/hir-ty/Cargo.toml
@@ -34,6 +34,7 @@ rustc_apfloat = "0.2.3"
 query-group.workspace = true
 salsa.workspace = true
 salsa-macros.workspace = true
+petgraph.workspace = true
 
 ra-ap-rustc_abi.workspace = true
 ra-ap-rustc_index.workspace = true
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/autoderef.rs b/src/tools/rust-analyzer/crates/hir-ty/src/autoderef.rs
index fd60ffcf24b..21a86d3e437 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/autoderef.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/autoderef.rs
@@ -32,11 +32,11 @@ const AUTODEREF_RECURSION_LIMIT: usize = 20;
 /// - the yielded types don't contain inference variables (but may contain `TyKind::Error`).
 /// - a type won't be yielded more than once; in other words, the returned iterator will stop if it
 ///   detects a cycle in the deref chain.
-pub fn autoderef(
-    db: &dyn HirDatabase,
-    env: Arc<TraitEnvironment>,
+pub fn autoderef<'db>(
+    db: &'db dyn HirDatabase,
+    env: Arc<TraitEnvironment<'db>>,
     ty: crate::Canonical<crate::Ty>,
-) -> impl Iterator<Item = crate::Ty> {
+) -> impl Iterator<Item = crate::Ty> + use<> {
     let mut table = InferenceTable::new(db, env);
     let interner = table.interner;
     let ty = table.instantiate_canonical(ty);
@@ -298,7 +298,7 @@ fn structurally_normalize_ty<'db>(
 ) -> Option<(Ty<'db>, PredicateObligations<'db>)> {
     let mut ocx = ObligationCtxt::new(&table.infer_ctxt);
     let Ok(normalized_ty) =
-        ocx.structurally_normalize_ty(&ObligationCause::misc(), table.param_env, ty)
+        ocx.structurally_normalize_ty(&ObligationCause::misc(), table.trait_env.env, ty)
     else {
         // We shouldn't have errors here in the old solver, except for
         // evaluate/fulfill mismatches, but that's not a reason for an ICE.
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/builder.rs b/src/tools/rust-analyzer/crates/hir-ty/src/builder.rs
index 3755175cf51..5511587c71a 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/builder.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/builder.rs
@@ -3,17 +3,20 @@
 use chalk_ir::{
     AdtId, DebruijnIndex, Scalar,
     cast::{Cast, CastTo, Caster},
-    fold::TypeFoldable,
-    interner::HasInterner,
 };
 use hir_def::{GenericDefId, GenericParamId, TraitId, TypeAliasId, builtin_type::BuiltinType};
 use smallvec::SmallVec;
 
 use crate::{
-    Binders, BoundVar, CallableSig, GenericArg, GenericArgData, Interner, ProjectionTy,
-    Substitution, TraitRef, Ty, TyDefId, TyExt, TyKind, consteval::unknown_const_as_generic,
-    db::HirDatabase, error_lifetime, generics::generics, infer::unify::InferenceTable, primitive,
-    to_assoc_type_id, to_chalk_trait_id,
+    BoundVar, CallableSig, GenericArg, GenericArgData, Interner, ProjectionTy, Substitution,
+    TraitRef, Ty, TyDefId, TyExt, TyKind,
+    consteval::unknown_const_as_generic,
+    db::HirDatabase,
+    error_lifetime,
+    generics::generics,
+    infer::unify::InferenceTable,
+    next_solver::{DbInterner, EarlyBinder, mapping::ChalkToNextSolver},
+    primitive, to_assoc_type_id, to_chalk_trait_id,
 };
 
 #[derive(Debug, Clone, PartialEq, Eq)]
@@ -345,19 +348,20 @@ impl TyBuilder<TypeAliasId> {
     }
 }
 
-impl<T: HasInterner<Interner = Interner> + TypeFoldable<Interner>> TyBuilder<Binders<T>> {
-    pub fn build(self) -> T {
+impl<'db, T: rustc_type_ir::TypeFoldable<DbInterner<'db>>> TyBuilder<EarlyBinder<'db, T>> {
+    pub fn build(self, interner: DbInterner<'db>) -> T {
         let (b, subst) = self.build_internal();
-        b.substitute(Interner, &subst)
+        let args: crate::next_solver::GenericArgs<'db> = subst.to_nextsolver(interner);
+        b.instantiate(interner, args)
     }
 }
 
-impl TyBuilder<Binders<Ty>> {
+impl<'db> TyBuilder<EarlyBinder<'db, crate::next_solver::Ty<'db>>> {
     pub fn def_ty(
-        db: &dyn HirDatabase,
+        db: &'db dyn HirDatabase,
         def: TyDefId,
         parent_subst: Option<Substitution>,
-    ) -> TyBuilder<Binders<Ty>> {
+    ) -> TyBuilder<EarlyBinder<'db, crate::next_solver::Ty<'db>>> {
         let poly_ty = db.ty(def);
         let id: GenericDefId = match def {
             TyDefId::BuiltinType(_) => {
@@ -370,7 +374,10 @@ impl TyBuilder<Binders<Ty>> {
         TyBuilder::subst_for_def(db, id, parent_subst).with_data(poly_ty)
     }
 
-    pub fn impl_self_ty(db: &dyn HirDatabase, def: hir_def::ImplId) -> TyBuilder<Binders<Ty>> {
+    pub fn impl_self_ty(
+        db: &'db dyn HirDatabase,
+        def: hir_def::ImplId,
+    ) -> TyBuilder<EarlyBinder<'db, crate::next_solver::Ty<'db>>> {
         TyBuilder::subst_for_def(db, def, None).with_data(db.impl_self_ty(def))
     }
 }
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/chalk_ext.rs b/src/tools/rust-analyzer/crates/hir-ty/src/chalk_ext.rs
index 1faf9f66dc5..6956a0a1232 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/chalk_ext.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/chalk_ext.rs
@@ -15,8 +15,13 @@ use crate::{
     AdtId, AliasEq, AliasTy, Binders, CallableDefId, CallableSig, Canonical, CanonicalVarKinds,
     ClosureId, DynTy, FnPointer, ImplTraitId, InEnvironment, Interner, Lifetime, ProjectionTy,
     QuantifiedWhereClause, Substitution, ToChalk, TraitRef, Ty, TyBuilder, TyKind, TypeFlags,
-    WhereClause, db::HirDatabase, from_assoc_type_id, from_chalk_trait_id, from_foreign_def_id,
-    from_placeholder_idx, generics::generics, to_chalk_trait_id, utils::ClosureSubst,
+    WhereClause,
+    db::HirDatabase,
+    from_assoc_type_id, from_chalk_trait_id, from_foreign_def_id, from_placeholder_idx,
+    generics::generics,
+    next_solver::{DbInterner, mapping::NextSolverToChalk},
+    to_chalk_trait_id,
+    utils::ClosureSubst,
 };
 
 pub trait TyExt {
@@ -372,7 +377,10 @@ impl TyExt for Ty {
         let trait_ref = TyBuilder::trait_ref(db, copy_trait).push(self).build();
         let env = db.trait_environment_for_body(owner);
         let goal = Canonical {
-            value: InEnvironment::new(&env.env, trait_ref.cast(Interner)),
+            value: InEnvironment::new(
+                &env.env.to_chalk(DbInterner::new_with(db, Some(env.krate), env.block)),
+                trait_ref.cast(Interner),
+            ),
             binders: CanonicalVarKinds::empty(Interner),
         };
         !db.trait_solve(crate_id, None, goal).no_solution()
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/consteval.rs b/src/tools/rust-analyzer/crates/hir-ty/src/consteval.rs
index 0f2cc17f563..b2daed425ef 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/consteval.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/consteval.rs
@@ -229,7 +229,7 @@ pub(crate) fn const_eval_cycle_result(
     _: &dyn HirDatabase,
     _: GeneralConstId,
     _: Substitution,
-    _: Option<Arc<TraitEnvironment>>,
+    _: Option<Arc<TraitEnvironment<'_>>>,
 ) -> Result<Const, ConstEvalError> {
     Err(ConstEvalError::MirLowerError(MirLowerError::Loop))
 }
@@ -252,7 +252,7 @@ pub(crate) fn const_eval_query(
     db: &dyn HirDatabase,
     def: GeneralConstId,
     subst: Substitution,
-    trait_env: Option<Arc<TraitEnvironment>>,
+    trait_env: Option<Arc<TraitEnvironment<'_>>>,
 ) -> Result<Const, ConstEvalError> {
     let body = match def {
         GeneralConstId::ConstId(c) => {
@@ -327,7 +327,7 @@ pub(crate) fn eval_to_const(
     debruijn: DebruijnIndex,
 ) -> Const {
     let db = ctx.db;
-    let infer = ctx.clone().resolve_all();
+    let infer = ctx.fixme_resolve_all_clone();
     fn has_closure(body: &Body, expr: ExprId) -> bool {
         if matches!(body[expr], Expr::Closure { .. }) {
             return true;
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/consteval/tests.rs b/src/tools/rust-analyzer/crates/hir-ty/src/consteval/tests.rs
index 299b73a7d6c..1586846bbe5 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/consteval/tests.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/consteval/tests.rs
@@ -36,12 +36,12 @@ fn check_fail(
     error: impl FnOnce(ConstEvalError) -> bool,
 ) {
     let (db, file_id) = TestDB::with_single_file(ra_fixture);
-    match eval_goal(&db, file_id) {
+    salsa::attach(&db, || match eval_goal(&db, file_id) {
         Ok(_) => panic!("Expected fail, but it succeeded"),
         Err(e) => {
-            assert!(error(simplify(e.clone())), "Actual error was: {}", pretty_print_err(e, db))
+            assert!(error(simplify(e.clone())), "Actual error was: {}", pretty_print_err(e, &db))
         }
-    }
+    })
 }
 
 #[track_caller]
@@ -79,36 +79,38 @@ fn check_answer(
     check: impl FnOnce(&[u8], &MemoryMap<'_>),
 ) {
     let (db, file_ids) = TestDB::with_many_files(ra_fixture);
-    let file_id = *file_ids.last().unwrap();
-    let r = match eval_goal(&db, file_id) {
-        Ok(t) => t,
-        Err(e) => {
-            let err = pretty_print_err(e, db);
-            panic!("Error in evaluating goal: {err}");
-        }
-    };
-    match &r.data(Interner).value {
-        chalk_ir::ConstValue::Concrete(c) => match &c.interned {
-            ConstScalar::Bytes(b, mm) => {
-                check(b, mm);
+    salsa::attach(&db, || {
+        let file_id = *file_ids.last().unwrap();
+        let r = match eval_goal(&db, file_id) {
+            Ok(t) => t,
+            Err(e) => {
+                let err = pretty_print_err(e, &db);
+                panic!("Error in evaluating goal: {err}");
             }
-            x => panic!("Expected number but found {x:?}"),
-        },
-        _ => panic!("result of const eval wasn't a concrete const"),
-    }
+        };
+        match &r.data(Interner).value {
+            chalk_ir::ConstValue::Concrete(c) => match &c.interned {
+                ConstScalar::Bytes(b, mm) => {
+                    check(b, mm);
+                }
+                x => panic!("Expected number but found {x:?}"),
+            },
+            _ => panic!("result of const eval wasn't a concrete const"),
+        }
+    });
 }
 
-fn pretty_print_err(e: ConstEvalError, db: TestDB) -> String {
+fn pretty_print_err(e: ConstEvalError, db: &TestDB) -> String {
     let mut err = String::new();
     let span_formatter = |file, range| format!("{file:?} {range:?}");
     let display_target =
-        DisplayTarget::from_crate(&db, *db.all_crates().last().expect("no crate graph present"));
+        DisplayTarget::from_crate(db, *db.all_crates().last().expect("no crate graph present"));
     match e {
         ConstEvalError::MirLowerError(e) => {
-            e.pretty_print(&mut err, &db, span_formatter, display_target)
+            e.pretty_print(&mut err, db, span_formatter, display_target)
         }
         ConstEvalError::MirEvalError(e) => {
-            e.pretty_print(&mut err, &db, span_formatter, display_target)
+            e.pretty_print(&mut err, db, span_formatter, display_target)
         }
     }
     .unwrap();
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/consteval_nextsolver.rs b/src/tools/rust-analyzer/crates/hir-ty/src/consteval_nextsolver.rs
index 6e07d3afe55..155f1336e41 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/consteval_nextsolver.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/consteval_nextsolver.rs
@@ -222,7 +222,7 @@ pub(crate) fn const_eval_discriminant_variant(
 // and make this function private. See the fixme comment on `InferenceContext::resolve_all`.
 pub(crate) fn eval_to_const<'db>(expr: ExprId, ctx: &mut InferenceContext<'db>) -> Const<'db> {
     let interner = DbInterner::new_with(ctx.db, None, None);
-    let infer = ctx.clone().resolve_all();
+    let infer = ctx.fixme_resolve_all_clone();
     fn has_closure(body: &Body, expr: ExprId) -> bool {
         if matches!(body[expr], Expr::Closure { .. }) {
             return true;
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/db.rs b/src/tools/rust-analyzer/crates/hir-ty/src/db.rs
index 448fc4aede0..71fb3d44fb7 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/db.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/db.rs
@@ -16,8 +16,8 @@ use smallvec::SmallVec;
 use triomphe::Arc;
 
 use crate::{
-    Binders, Const, ImplTraitId, ImplTraits, InferenceResult, PolyFnSig, Substitution,
-    TraitEnvironment, TraitRef, Ty, TyDefId, ValueTyDefId, chalk_db,
+    Binders, Const, ImplTraitId, ImplTraits, InferenceResult, Substitution, TraitEnvironment, Ty,
+    TyDefId, ValueTyDefId, chalk_db,
     consteval::ConstEvalError,
     drop::DropGlue,
     dyn_compatibility::DynCompatibilityViolation,
@@ -49,7 +49,7 @@ pub trait HirDatabase: DefDatabase + std::fmt::Debug {
         &self,
         def: DefWithBodyId,
         subst: Substitution,
-        env: Arc<TraitEnvironment>,
+        env: Arc<TraitEnvironment<'_>>,
     ) -> Result<Arc<MirBody>, MirLowerError>;
 
     #[salsa::invoke(crate::mir::monomorphized_mir_body_for_closure_query)]
@@ -57,7 +57,7 @@ pub trait HirDatabase: DefDatabase + std::fmt::Debug {
         &self,
         def: InternedClosureId,
         subst: Substitution,
-        env: Arc<TraitEnvironment>,
+        env: Arc<TraitEnvironment<'_>>,
     ) -> Result<Arc<MirBody>, MirLowerError>;
 
     #[salsa::invoke(crate::mir::borrowck_query)]
@@ -70,7 +70,7 @@ pub trait HirDatabase: DefDatabase + std::fmt::Debug {
         &self,
         def: GeneralConstId,
         subst: Substitution,
-        trait_env: Option<Arc<TraitEnvironment>>,
+        trait_env: Option<Arc<TraitEnvironment<'_>>>,
     ) -> Result<Const, ConstEvalError>;
 
     #[salsa::invoke(crate::consteval::const_eval_static_query)]
@@ -84,7 +84,7 @@ pub trait HirDatabase: DefDatabase + std::fmt::Debug {
     #[salsa::invoke(crate::method_resolution::lookup_impl_method_query)]
     fn lookup_impl_method(
         &self,
-        env: Arc<TraitEnvironment>,
+        env: Arc<TraitEnvironment<'_>>,
         func: FunctionId,
         fn_subst: Substitution,
     ) -> (FunctionId, Substitution);
@@ -97,7 +97,7 @@ pub trait HirDatabase: DefDatabase + std::fmt::Debug {
         &'db self,
         def: AdtId,
         args: crate::next_solver::GenericArgs<'db>,
-        trait_env: Arc<TraitEnvironment>,
+        trait_env: Arc<TraitEnvironment<'db>>,
     ) -> Result<Arc<Layout>, LayoutError>;
 
     #[salsa::invoke(crate::layout::layout_of_ty_query)]
@@ -105,7 +105,7 @@ pub trait HirDatabase: DefDatabase + std::fmt::Debug {
     fn layout_of_ty<'db>(
         &'db self,
         ty: crate::next_solver::Ty<'db>,
-        env: Arc<TraitEnvironment>,
+        env: Arc<TraitEnvironment<'db>>,
     ) -> Result<Arc<Layout>, LayoutError>;
 
     #[salsa::invoke(crate::layout::target_data_layout_query)]
@@ -114,55 +114,94 @@ pub trait HirDatabase: DefDatabase + std::fmt::Debug {
     #[salsa::invoke(crate::dyn_compatibility::dyn_compatibility_of_trait_query)]
     fn dyn_compatibility_of_trait(&self, trait_: TraitId) -> Option<DynCompatibilityViolation>;
 
-    #[salsa::invoke(crate::lower::ty_query)]
+    #[salsa::invoke(crate::lower_nextsolver::ty_query)]
     #[salsa::transparent]
-    fn ty(&self, def: TyDefId) -> Binders<Ty>;
+    fn ty<'db>(
+        &'db self,
+        def: TyDefId,
+    ) -> crate::next_solver::EarlyBinder<'db, crate::next_solver::Ty<'db>>;
 
-    #[salsa::invoke(crate::lower::type_for_type_alias_with_diagnostics_query)]
-    #[salsa::cycle(cycle_result = crate::lower::type_for_type_alias_with_diagnostics_cycle_result)]
-    fn type_for_type_alias_with_diagnostics(&self, def: TypeAliasId) -> (Binders<Ty>, Diagnostics);
+    #[salsa::invoke(crate::lower_nextsolver::type_for_type_alias_with_diagnostics_query)]
+    #[salsa::cycle(cycle_result = crate::lower_nextsolver::type_for_type_alias_with_diagnostics_cycle_result)]
+    fn type_for_type_alias_with_diagnostics<'db>(
+        &'db self,
+        def: TypeAliasId,
+    ) -> (crate::next_solver::EarlyBinder<'db, crate::next_solver::Ty<'db>>, Diagnostics);
 
     /// Returns the type of the value of the given constant, or `None` if the `ValueTyDefId` is
     /// a `StructId` or `EnumVariantId` with a record constructor.
-    #[salsa::invoke(crate::lower::value_ty_query)]
-    fn value_ty(&self, def: ValueTyDefId) -> Option<Binders<Ty>>;
+    #[salsa::invoke(crate::lower_nextsolver::value_ty_query)]
+    fn value_ty<'db>(
+        &'db self,
+        def: ValueTyDefId,
+    ) -> Option<crate::next_solver::EarlyBinder<'db, crate::next_solver::Ty<'db>>>;
 
-    #[salsa::invoke(crate::lower::impl_self_ty_with_diagnostics_query)]
-    #[salsa::cycle(cycle_result = crate::lower::impl_self_ty_with_diagnostics_cycle_result)]
-    fn impl_self_ty_with_diagnostics(&self, def: ImplId) -> (Binders<Ty>, Diagnostics);
+    #[salsa::invoke(crate::lower_nextsolver::impl_self_ty_with_diagnostics_query)]
+    #[salsa::cycle(cycle_result = crate::lower_nextsolver::impl_self_ty_with_diagnostics_cycle_result)]
+    fn impl_self_ty_with_diagnostics<'db>(
+        &'db self,
+        def: ImplId,
+    ) -> (crate::next_solver::EarlyBinder<'db, crate::next_solver::Ty<'db>>, Diagnostics);
 
-    #[salsa::invoke(crate::lower::impl_self_ty_query)]
+    #[salsa::invoke(crate::lower_nextsolver::impl_self_ty_query)]
     #[salsa::transparent]
-    fn impl_self_ty(&self, def: ImplId) -> Binders<Ty>;
+    fn impl_self_ty<'db>(
+        &'db self,
+        def: ImplId,
+    ) -> crate::next_solver::EarlyBinder<'db, crate::next_solver::Ty<'db>>;
 
     // FIXME: Make this a non-interned query.
-    #[salsa::invoke_interned(crate::lower::const_param_ty_with_diagnostics_query)]
-    #[salsa::cycle(cycle_result = crate::lower::const_param_ty_with_diagnostics_cycle_result)]
-    fn const_param_ty_with_diagnostics(&self, def: ConstParamId) -> (Ty, Diagnostics);
+    #[salsa::invoke_interned(crate::lower_nextsolver::const_param_ty_with_diagnostics_query)]
+    #[salsa::cycle(cycle_result = crate::lower_nextsolver::const_param_ty_with_diagnostics_cycle_result)]
+    fn const_param_ty_with_diagnostics<'db>(
+        &'db self,
+        def: ConstParamId,
+    ) -> (crate::next_solver::Ty<'db>, Diagnostics);
 
-    #[salsa::invoke(crate::lower::const_param_ty_query)]
-    #[salsa::transparent]
+    // FIXME: Make this a non-interned query.
+    #[salsa::invoke_interned(crate::lower::const_param_ty_query)]
+    #[salsa::cycle(cycle_result = crate::lower::const_param_ty_cycle_result)]
     fn const_param_ty(&self, def: ConstParamId) -> Ty;
 
-    #[salsa::invoke(crate::lower::impl_trait_with_diagnostics_query)]
-    fn impl_trait_with_diagnostics(&self, def: ImplId) -> Option<(Binders<TraitRef>, Diagnostics)>;
+    #[salsa::invoke(crate::lower_nextsolver::impl_trait_with_diagnostics_query)]
+    fn impl_trait_with_diagnostics<'db>(
+        &'db self,
+        def: ImplId,
+    ) -> Option<(
+        crate::next_solver::EarlyBinder<'db, crate::next_solver::TraitRef<'db>>,
+        Diagnostics,
+    )>;
 
-    #[salsa::invoke(crate::lower::impl_trait_query)]
+    #[salsa::invoke(crate::lower_nextsolver::impl_trait_query)]
     #[salsa::transparent]
-    fn impl_trait(&self, def: ImplId) -> Option<Binders<TraitRef>>;
+    fn impl_trait<'db>(
+        &'db self,
+        def: ImplId,
+    ) -> Option<crate::next_solver::EarlyBinder<'db, crate::next_solver::TraitRef<'db>>>;
 
-    #[salsa::invoke(crate::lower::field_types_with_diagnostics_query)]
-    fn field_types_with_diagnostics(
-        &self,
+    #[salsa::invoke(crate::lower_nextsolver::field_types_with_diagnostics_query)]
+    fn field_types_with_diagnostics<'db>(
+        &'db self,
         var: VariantId,
-    ) -> (Arc<ArenaMap<LocalFieldId, Binders<Ty>>>, Diagnostics);
+    ) -> (
+        Arc<
+            ArenaMap<
+                LocalFieldId,
+                crate::next_solver::EarlyBinder<'db, crate::next_solver::Ty<'db>>,
+            >,
+        >,
+        Diagnostics,
+    );
 
     #[salsa::invoke(crate::lower::field_types_query)]
     #[salsa::transparent]
     fn field_types(&self, var: VariantId) -> Arc<ArenaMap<LocalFieldId, Binders<Ty>>>;
 
-    #[salsa::invoke(crate::lower::callable_item_signature_query)]
-    fn callable_item_signature(&self, def: CallableDefId) -> PolyFnSig;
+    #[salsa::invoke(crate::lower_nextsolver::callable_item_signature_query)]
+    fn callable_item_signature<'db>(
+        &'db self,
+        def: CallableDefId,
+    ) -> crate::next_solver::EarlyBinder<'db, crate::next_solver::PolyFnSig<'db>>;
 
     #[salsa::invoke(crate::lower::return_type_impl_traits)]
     fn return_type_impl_traits(&self, def: FunctionId) -> Option<Arc<Binders<ImplTraits>>>;
@@ -182,12 +221,28 @@ pub trait HirDatabase: DefDatabase + std::fmt::Debug {
     #[salsa::invoke(crate::lower::generic_predicates_query)]
     fn generic_predicates(&self, def: GenericDefId) -> GenericPredicates;
 
-    #[salsa::invoke(crate::lower::trait_environment_for_body_query)]
+    #[salsa::invoke(
+        crate::lower_nextsolver::generic_predicates_without_parent_with_diagnostics_query
+    )]
+    fn generic_predicates_without_parent_with_diagnostics<'db>(
+        &'db self,
+        def: GenericDefId,
+    ) -> (crate::lower_nextsolver::GenericPredicates<'db>, Diagnostics);
+
+    #[salsa::invoke(crate::lower_nextsolver::generic_predicates_without_parent_query)]
+    #[salsa::transparent]
+    fn generic_predicates_without_parent<'db>(
+        &'db self,
+        def: GenericDefId,
+    ) -> crate::lower_nextsolver::GenericPredicates<'db>;
+
+    #[salsa::invoke(crate::lower_nextsolver::trait_environment_for_body_query)]
     #[salsa::transparent]
-    fn trait_environment_for_body(&self, def: DefWithBodyId) -> Arc<TraitEnvironment>;
+    fn trait_environment_for_body<'db>(&'db self, def: DefWithBodyId)
+    -> Arc<TraitEnvironment<'db>>;
 
-    #[salsa::invoke(crate::lower::trait_environment_query)]
-    fn trait_environment(&self, def: GenericDefId) -> Arc<TraitEnvironment>;
+    #[salsa::invoke(crate::lower_nextsolver::trait_environment_query)]
+    fn trait_environment<'db>(&'db self, def: GenericDefId) -> Arc<TraitEnvironment<'db>>;
 
     #[salsa::invoke(crate::lower::generic_defaults_with_diagnostics_query)]
     #[salsa::cycle(cycle_result = crate::lower::generic_defaults_with_diagnostics_cycle_result)]
@@ -258,7 +313,7 @@ pub trait HirDatabase: DefDatabase + std::fmt::Debug {
     fn normalize_projection(
         &self,
         projection: crate::ProjectionTy,
-        env: Arc<TraitEnvironment>,
+        env: Arc<TraitEnvironment<'_>>,
     ) -> Ty;
 
     #[salsa::invoke(crate::traits::trait_solve_query)]
@@ -272,87 +327,14 @@ pub trait HirDatabase: DefDatabase + std::fmt::Debug {
 
     #[salsa::invoke(crate::drop::has_drop_glue)]
     #[salsa::cycle(cycle_result = crate::drop::has_drop_glue_cycle_result)]
-    fn has_drop_glue(&self, ty: Ty, env: Arc<TraitEnvironment>) -> DropGlue;
+    fn has_drop_glue(&self, ty: Ty, env: Arc<TraitEnvironment<'_>>) -> DropGlue;
 
     // next trait solver
 
-    #[salsa::invoke(crate::lower_nextsolver::ty_query)]
-    #[salsa::transparent]
-    fn ty_ns<'db>(
-        &'db self,
-        def: TyDefId,
-    ) -> crate::next_solver::EarlyBinder<'db, crate::next_solver::Ty<'db>>;
-
-    /// Returns the type of the value of the given constant, or `None` if the `ValueTyDefId` is
-    /// a `StructId` or `EnumVariantId` with a record constructor.
-    #[salsa::invoke(crate::lower_nextsolver::value_ty_query)]
-    fn value_ty_ns<'db>(
-        &'db self,
-        def: ValueTyDefId,
-    ) -> Option<crate::next_solver::EarlyBinder<'db, crate::next_solver::Ty<'db>>>;
-
-    #[salsa::invoke(crate::lower_nextsolver::type_for_type_alias_with_diagnostics_query)]
-    #[salsa::cycle(cycle_result = crate::lower_nextsolver::type_for_type_alias_with_diagnostics_cycle_result)]
-    fn type_for_type_alias_with_diagnostics_ns<'db>(
-        &'db self,
-        def: TypeAliasId,
-    ) -> (crate::next_solver::EarlyBinder<'db, crate::next_solver::Ty<'db>>, Diagnostics);
-
-    #[salsa::invoke(crate::lower_nextsolver::impl_self_ty_with_diagnostics_query)]
-    #[salsa::cycle(cycle_result = crate::lower_nextsolver::impl_self_ty_with_diagnostics_cycle_result)]
-    fn impl_self_ty_with_diagnostics_ns<'db>(
-        &'db self,
-        def: ImplId,
-    ) -> (crate::next_solver::EarlyBinder<'db, crate::next_solver::Ty<'db>>, Diagnostics);
-
-    #[salsa::invoke(crate::lower_nextsolver::impl_self_ty_query)]
-    #[salsa::transparent]
-    fn impl_self_ty_ns<'db>(
-        &'db self,
-        def: ImplId,
-    ) -> crate::next_solver::EarlyBinder<'db, crate::next_solver::Ty<'db>>;
-
-    // FIXME: Make this a non-interned query.
-    #[salsa::invoke_interned(crate::lower_nextsolver::const_param_ty_with_diagnostics_query)]
-    fn const_param_ty_with_diagnostics_ns<'db>(
-        &'db self,
-        def: ConstParamId,
-    ) -> (crate::next_solver::Ty<'db>, Diagnostics);
-
     #[salsa::invoke(crate::lower_nextsolver::const_param_ty_query)]
     #[salsa::transparent]
     fn const_param_ty_ns<'db>(&'db self, def: ConstParamId) -> crate::next_solver::Ty<'db>;
 
-    #[salsa::invoke(crate::lower_nextsolver::impl_trait_with_diagnostics_query)]
-    fn impl_trait_with_diagnostics_ns<'db>(
-        &'db self,
-        def: ImplId,
-    ) -> Option<(
-        crate::next_solver::EarlyBinder<'db, crate::next_solver::TraitRef<'db>>,
-        Diagnostics,
-    )>;
-
-    #[salsa::invoke(crate::lower_nextsolver::impl_trait_query)]
-    #[salsa::transparent]
-    fn impl_trait_ns<'db>(
-        &'db self,
-        def: ImplId,
-    ) -> Option<crate::next_solver::EarlyBinder<'db, crate::next_solver::TraitRef<'db>>>;
-
-    #[salsa::invoke(crate::lower_nextsolver::field_types_with_diagnostics_query)]
-    fn field_types_with_diagnostics_ns<'db>(
-        &'db self,
-        var: VariantId,
-    ) -> (
-        Arc<
-            ArenaMap<
-                LocalFieldId,
-                crate::next_solver::EarlyBinder<'db, crate::next_solver::Ty<'db>>,
-            >,
-        >,
-        Diagnostics,
-    );
-
     #[salsa::invoke(crate::lower_nextsolver::field_types_query)]
     #[salsa::transparent]
     fn field_types_ns<'db>(
@@ -362,12 +344,6 @@ pub trait HirDatabase: DefDatabase + std::fmt::Debug {
         ArenaMap<LocalFieldId, crate::next_solver::EarlyBinder<'db, crate::next_solver::Ty<'db>>>,
     >;
 
-    #[salsa::invoke(crate::lower_nextsolver::callable_item_signature_query)]
-    fn callable_item_signature_ns<'db>(
-        &'db self,
-        def: CallableDefId,
-    ) -> crate::next_solver::EarlyBinder<'db, crate::next_solver::PolyFnSig<'db>>;
-
     #[salsa::invoke(crate::lower_nextsolver::return_type_impl_traits)]
     fn return_type_impl_traits_ns<'db>(
         &'db self,
@@ -394,21 +370,6 @@ pub trait HirDatabase: DefDatabase + std::fmt::Debug {
         &'db self,
         def: GenericDefId,
     ) -> crate::lower_nextsolver::GenericPredicates<'db>;
-
-    #[salsa::invoke(
-        crate::lower_nextsolver::generic_predicates_without_parent_with_diagnostics_query
-    )]
-    fn generic_predicates_without_parent_with_diagnostics_ns<'db>(
-        &'db self,
-        def: GenericDefId,
-    ) -> (crate::lower_nextsolver::GenericPredicates<'db>, Diagnostics);
-
-    #[salsa::invoke(crate::lower_nextsolver::generic_predicates_without_parent_query)]
-    #[salsa::transparent]
-    fn generic_predicates_without_parent_ns<'db>(
-        &'db self,
-        def: GenericDefId,
-    ) -> crate::lower_nextsolver::GenericPredicates<'db>;
 }
 
 #[test]
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/expr.rs b/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/expr.rs
index 403ea05a4f5..d05814e0e7e 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/expr.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/expr.rs
@@ -81,17 +81,17 @@ impl BodyValidationDiagnostic {
     }
 }
 
-struct ExprValidator {
+struct ExprValidator<'db> {
     owner: DefWithBodyId,
     body: Arc<Body>,
     infer: Arc<InferenceResult>,
-    env: Arc<TraitEnvironment>,
+    env: Arc<TraitEnvironment<'db>>,
     diagnostics: Vec<BodyValidationDiagnostic>,
     validate_lints: bool,
 }
 
-impl ExprValidator {
-    fn validate_body(&mut self, db: &dyn HirDatabase) {
+impl<'db> ExprValidator<'db> {
+    fn validate_body(&mut self, db: &'db dyn HirDatabase) {
         let mut filter_map_next_checker = None;
         // we'll pass &mut self while iterating over body.exprs, so they need to be disjoint
         let body = Arc::clone(&self.body);
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/match_check/pat_analysis.rs b/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/match_check/pat_analysis.rs
index 56fd12e1f2b..eb20d3c51ff 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/match_check/pat_analysis.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/match_check/pat_analysis.rs
@@ -70,7 +70,7 @@ pub(crate) struct MatchCheckCtx<'db> {
     body: DefWithBodyId,
     pub(crate) db: &'db dyn HirDatabase,
     exhaustive_patterns: bool,
-    env: Arc<TraitEnvironment>,
+    env: Arc<TraitEnvironment<'db>>,
 }
 
 impl<'db> MatchCheckCtx<'db> {
@@ -78,7 +78,7 @@ impl<'db> MatchCheckCtx<'db> {
         module: ModuleId,
         body: DefWithBodyId,
         db: &'db dyn HirDatabase,
-        env: Arc<TraitEnvironment>,
+        env: Arc<TraitEnvironment<'db>>,
     ) -> Self {
         let def_map = module.crate_def_map(db);
         let exhaustive_patterns = def_map.is_unstable_feature_enabled(&sym::exhaustive_patterns);
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/unsafe_check.rs b/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/unsafe_check.rs
index 3f04b72c2fc..3c78f5ef387 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/unsafe_check.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/unsafe_check.rs
@@ -315,6 +315,22 @@ impl<'db> UnsafeVisitor<'db> {
                     }
                     _ => (),
                 }
+
+                let mut peeled = *expr;
+                while let Expr::Field { expr: lhs, .. } = &self.body[peeled] {
+                    if let Some(Either::Left(FieldId { parent: VariantId::UnionId(_), .. })) =
+                        self.infer.field_resolution(peeled)
+                    {
+                        peeled = *lhs;
+                    } else {
+                        break;
+                    }
+                }
+
+                // Walk the peeled expression (the LHS of the union field chain)
+                self.walk_expr(peeled);
+                // Return so we don't recurse directly onto the union field access(es)
+                return;
             }
             Expr::MethodCall { .. } => {
                 if let Some((func, _)) = self.infer.method_resolution(current) {
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/display.rs b/src/tools/rust-analyzer/crates/hir-ty/src/display.rs
index 519e4b59237..e11ce51cdb8 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/display.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/display.rs
@@ -46,8 +46,8 @@ use span::Edition;
 use stdx::never;
 use triomphe::Arc;
 
-use crate::next_solver::infer::DbInternerInferExt;
 use crate::next_solver::infer::traits::ObligationCause;
+use crate::next_solver::{infer::DbInternerInferExt, mapping::NextSolverToChalk};
 use crate::{
     AliasEq, AliasTy, Binders, CallableDefId, CallableSig, ConcreteConst, Const, ConstScalar,
     ConstValue, DomainGoal, FnAbi, GenericArg, ImplTraitId, Interner, Lifetime, LifetimeData,
@@ -792,19 +792,16 @@ fn render_const_scalar_ns(
     let trait_env = TraitEnvironment::empty(f.krate());
     let interner = DbInterner::new_with(f.db, Some(trait_env.krate), trait_env.block);
     let infcx = interner.infer_ctxt().build(rustc_type_ir::TypingMode::PostAnalysis);
-    let ty = infcx
-        .at(&ObligationCause::new(), trait_env.env.to_nextsolver(interner))
-        .deeply_normalize(ty)
-        .unwrap_or(ty);
+    let ty = infcx.at(&ObligationCause::new(), trait_env.env).deeply_normalize(ty).unwrap_or(ty);
     render_const_scalar_inner(f, b, memory_map, ty, trait_env)
 }
 
-fn render_const_scalar_inner(
+fn render_const_scalar_inner<'db>(
     f: &mut HirFormatter<'_>,
     b: &[u8],
     memory_map: &MemoryMap<'_>,
-    ty: crate::next_solver::Ty<'_>,
-    trait_env: Arc<TraitEnvironment>,
+    ty: crate::next_solver::Ty<'db>,
+    trait_env: Arc<TraitEnvironment<'db>>,
 ) -> Result<(), HirDisplayError> {
     use rustc_type_ir::TyKind;
     match ty.kind() {
@@ -1068,11 +1065,11 @@ fn render_const_scalar_inner(
     }
 }
 
-fn render_variant_after_name(
+fn render_variant_after_name<'db>(
     data: &VariantFields,
     f: &mut HirFormatter<'_>,
     field_types: &ArenaMap<LocalFieldId, Binders<Ty>>,
-    trait_env: Arc<TraitEnvironment>,
+    trait_env: Arc<TraitEnvironment<'db>>,
     layout: &Layout,
     args: GenericArgs<'_>,
     b: &[u8],
@@ -1301,7 +1298,9 @@ impl<'db> HirDisplay for crate::next_solver::Ty<'db> {
                 let def = def.0;
                 let sig = db
                     .callable_item_signature(def)
-                    .substitute(Interner, &convert_args_for_result(interner, args.as_slice()));
+                    .instantiate(interner, args)
+                    .skip_binder()
+                    .to_chalk(interner);
 
                 if f.display_kind.is_source_code() {
                     // `FnDef` is anonymous and there's no surface syntax for it. Show it as a
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/drop.rs b/src/tools/rust-analyzer/crates/hir-ty/src/drop.rs
index f5c2f41069e..413f70532a5 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/drop.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/drop.rs
@@ -7,6 +7,8 @@ use hir_def::signatures::StructFlags;
 use stdx::never;
 use triomphe::Arc;
 
+use crate::next_solver::DbInterner;
+use crate::next_solver::mapping::NextSolverToChalk;
 use crate::{
     AliasTy, Canonical, CanonicalVarKinds, ConcreteConst, ConstScalar, ConstValue, InEnvironment,
     Interner, ProjectionTy, TraitEnvironment, Ty, TyBuilder, TyKind, db::HirDatabase,
@@ -43,7 +45,11 @@ pub enum DropGlue {
     HasDropGlue,
 }
 
-pub(crate) fn has_drop_glue(db: &dyn HirDatabase, ty: Ty, env: Arc<TraitEnvironment>) -> DropGlue {
+pub(crate) fn has_drop_glue(
+    db: &dyn HirDatabase,
+    ty: Ty,
+    env: Arc<TraitEnvironment<'_>>,
+) -> DropGlue {
     match ty.kind(Interner) {
         TyKind::Adt(adt, subst) => {
             if has_destructor(db, adt.0) {
@@ -165,7 +171,7 @@ pub(crate) fn has_drop_glue(db: &dyn HirDatabase, ty: Ty, env: Arc<TraitEnvironm
 
 fn projection_has_drop_glue(
     db: &dyn HirDatabase,
-    env: Arc<TraitEnvironment>,
+    env: Arc<TraitEnvironment<'_>>,
     projection: ProjectionTy,
     ty: Ty,
 ) -> DropGlue {
@@ -178,13 +184,16 @@ fn projection_has_drop_glue(
     }
 }
 
-fn is_copy(db: &dyn HirDatabase, ty: Ty, env: Arc<TraitEnvironment>) -> bool {
+fn is_copy(db: &dyn HirDatabase, ty: Ty, env: Arc<TraitEnvironment<'_>>) -> bool {
     let Some(copy_trait) = LangItem::Copy.resolve_trait(db, env.krate) else {
         return false;
     };
     let trait_ref = TyBuilder::trait_ref(db, copy_trait).push(ty).build();
     let goal = Canonical {
-        value: InEnvironment::new(&env.env, trait_ref.cast(Interner)),
+        value: InEnvironment::new(
+            &env.env.to_chalk(DbInterner::new_with(db, Some(env.krate), env.block)),
+            trait_ref.cast(Interner),
+        ),
         binders: CanonicalVarKinds::empty(Interner),
     };
     db.trait_solve(env.krate, env.block, goal).certain()
@@ -193,7 +202,7 @@ fn is_copy(db: &dyn HirDatabase, ty: Ty, env: Arc<TraitEnvironment>) -> bool {
 pub(crate) fn has_drop_glue_cycle_result(
     _db: &dyn HirDatabase,
     _ty: Ty,
-    _env: Arc<TraitEnvironment>,
+    _env: Arc<TraitEnvironment<'_>>,
 ) -> DropGlue {
     DropGlue::None
 }
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/dyn_compatibility.rs b/src/tools/rust-analyzer/crates/hir-ty/src/dyn_compatibility.rs
index b87c9982177..b2406a08895 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/dyn_compatibility.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/dyn_compatibility.rs
@@ -329,7 +329,7 @@ where
         cb(MethodViolationCode::AsyncFn)?;
     }
 
-    let sig = db.callable_item_signature_ns(func.into());
+    let sig = db.callable_item_signature(func.into());
     if sig
         .skip_binder()
         .inputs()
@@ -364,7 +364,7 @@ where
         cb(MethodViolationCode::UndispatchableReceiver)?;
     }
 
-    let predicates = &*db.generic_predicates_without_parent_ns(func.into());
+    let predicates = &*db.generic_predicates_without_parent(func.into());
     for pred in predicates {
         let pred = pred.kind().skip_binder();
 
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/infer.rs b/src/tools/rust-analyzer/crates/hir-ty/src/infer.rs
index 017119781a7..0282b7a9363 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/infer.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/infer.rs
@@ -19,6 +19,7 @@ pub(crate) mod closure;
 mod coerce;
 pub(crate) mod diagnostics;
 mod expr;
+mod fallback;
 mod mutability;
 mod pat;
 mod path;
@@ -53,16 +54,16 @@ use indexmap::IndexSet;
 use intern::sym;
 use la_arena::{ArenaMap, Entry};
 use rustc_hash::{FxHashMap, FxHashSet};
+use rustc_type_ir::inherent::Ty as _;
 use stdx::{always, never};
 use triomphe::Arc;
 
-use crate::db::InternedClosureId;
 use crate::{
     AliasEq, AliasTy, Binders, ClosureId, Const, DomainGoal, GenericArg, ImplTraitId, ImplTraitIdx,
     IncorrectGenericsLenKind, Interner, Lifetime, OpaqueTyId, ParamLoweringMode,
     PathLoweringDiagnostic, ProjectionTy, Substitution, TargetFeatures, TraitEnvironment, Ty,
     TyBuilder, TyExt,
-    db::HirDatabase,
+    db::{HirDatabase, InternedClosureId},
     fold_tys,
     generics::Generics,
     infer::{
@@ -75,6 +76,7 @@ use crate::{
     mir::MirSpan,
     next_solver::{
         self, DbInterner,
+        infer::{DefineOpaqueTypes, traits::ObligationCause},
         mapping::{ChalkToNextSolver, NextSolverToChalk},
     },
     static_lifetime, to_assoc_type_id,
@@ -138,6 +140,20 @@ pub(crate) fn infer_query(db: &dyn HirDatabase, def: DefWithBodyId) -> Arc<Infer
 
     ctx.infer_mut_body();
 
+    ctx.type_inference_fallback();
+
+    // Comment from rustc:
+    // Even though coercion casts provide type hints, we check casts after fallback for
+    // backwards compatibility. This makes fallback a stronger type hint than a cast coercion.
+    let cast_checks = std::mem::take(&mut ctx.deferred_cast_checks);
+    for mut cast in cast_checks.into_iter() {
+        if let Err(diag) = cast.check(&mut ctx) {
+            ctx.diagnostics.push(diag);
+        }
+    }
+
+    ctx.table.select_obligations_where_possible();
+
     ctx.infer_closures();
 
     Arc::new(ctx.resolve_all())
@@ -152,7 +168,7 @@ pub(crate) fn infer_cycle_result(_: &dyn HirDatabase, _: DefWithBodyId) -> Arc<I
 /// This is appropriate to use only after type-check: it assumes
 /// that normalization will succeed, for example.
 #[tracing::instrument(level = "debug", skip(db))]
-pub(crate) fn normalize(db: &dyn HirDatabase, trait_env: Arc<TraitEnvironment>, ty: Ty) -> Ty {
+pub(crate) fn normalize(db: &dyn HirDatabase, trait_env: Arc<TraitEnvironment<'_>>, ty: Ty) -> Ty {
     // FIXME: TypeFlags::HAS_CT_PROJECTION is not implemented in chalk, so TypeFlags::HAS_PROJECTION only
     // works for the type case, so we check array unconditionally. Remove the array part
     // when the bug in chalk becomes fixed.
@@ -165,7 +181,6 @@ pub(crate) fn normalize(db: &dyn HirDatabase, trait_env: Arc<TraitEnvironment>,
 
     let ty_with_vars = table.normalize_associated_types_in(ty);
     table.select_obligations_where_possible();
-    table.propagate_diverging_flag();
     table.resolve_completely(ty_with_vars)
 }
 
@@ -632,6 +647,26 @@ impl InferenceResult {
     pub fn binding_mode(&self, id: PatId) -> Option<BindingMode> {
         self.binding_modes.get(id).copied()
     }
+
+    // This method is consumed by external tools to run rust-analyzer as a library. Don't remove, please.
+    pub fn expression_types(&self) -> impl Iterator<Item = (ExprId, &Ty)> {
+        self.type_of_expr.iter()
+    }
+
+    // This method is consumed by external tools to run rust-analyzer as a library. Don't remove, please.
+    pub fn pattern_types(&self) -> impl Iterator<Item = (PatId, &Ty)> {
+        self.type_of_pat.iter()
+    }
+
+    // This method is consumed by external tools to run rust-analyzer as a library. Don't remove, please.
+    pub fn binding_types(&self) -> impl Iterator<Item = (BindingId, &Ty)> {
+        self.type_of_binding.iter()
+    }
+
+    // This method is consumed by external tools to run rust-analyzer as a library. Don't remove, please.
+    pub fn return_position_impl_trait_types(&self) -> impl Iterator<Item = (ImplTraitIdx, &Ty)> {
+        self.type_of_rpit.iter()
+    }
 }
 
 impl Index<ExprId> for InferenceResult {
@@ -666,6 +701,25 @@ impl Index<BindingId> for InferenceResult {
     }
 }
 
+#[derive(Debug, Clone)]
+struct InternedStandardTypesNextSolver<'db> {
+    unit: crate::next_solver::Ty<'db>,
+    never: crate::next_solver::Ty<'db>,
+    i32: crate::next_solver::Ty<'db>,
+    f64: crate::next_solver::Ty<'db>,
+}
+
+impl<'db> InternedStandardTypesNextSolver<'db> {
+    fn new(interner: DbInterner<'db>) -> Self {
+        Self {
+            unit: crate::next_solver::Ty::new_unit(interner),
+            never: crate::next_solver::Ty::new(interner, crate::next_solver::TyKind::Never),
+            i32: crate::next_solver::Ty::new_int(interner, rustc_type_ir::IntTy::I32),
+            f64: crate::next_solver::Ty::new_float(interner, rustc_type_ir::FloatTy::F64),
+        }
+    }
+}
+
 /// The inference context contains all information needed during type inference.
 #[derive(Clone, Debug)]
 pub(crate) struct InferenceContext<'db> {
@@ -698,6 +752,7 @@ pub(crate) struct InferenceContext<'db> {
     resume_yield_tys: Option<(Ty, Ty)>,
     diverges: Diverges,
     breakables: Vec<BreakableContext<'db>>,
+    types: InternedStandardTypesNextSolver<'db>,
 
     /// Whether we are inside the pattern of a destructuring assignment.
     inside_assignment: bool,
@@ -778,11 +833,13 @@ impl<'db> InferenceContext<'db> {
         resolver: Resolver<'db>,
     ) -> Self {
         let trait_env = db.trait_environment_for_body(owner);
+        let table = unify::InferenceTable::new(db, trait_env);
         InferenceContext {
+            types: InternedStandardTypesNextSolver::new(table.interner),
             target_features: OnceCell::new(),
             generics: OnceCell::new(),
             result: InferenceResult::default(),
-            table: unify::InferenceTable::new(db, trait_env),
+            table,
             tuple_field_accesses_rev: Default::default(),
             return_ty: TyKind::Error.intern(Interner), // set in collect_* calls
             resume_yield_tys: None,
@@ -845,24 +902,33 @@ impl<'db> InferenceContext<'db> {
         self.result.has_errors = true;
     }
 
-    // FIXME: This function should be private in module. It is currently only used in the consteval, since we need
-    // `InferenceResult` in the middle of inference. See the fixme comment in `consteval::eval_to_const`. If you
-    // used this function for another workaround, mention it here. If you really need this function and believe that
-    // there is no problem in it being `pub(crate)`, remove this comment.
-    pub(crate) fn resolve_all(mut self) -> InferenceResult {
-        self.table.select_obligations_where_possible();
-        self.table.fallback_if_possible();
+    /// Clones `self` and calls `resolve_all()` on it.
+    // FIXME: Remove this.
+    pub(crate) fn fixme_resolve_all_clone(&self) -> InferenceResult {
+        let mut ctx = self.clone();
+
+        ctx.type_inference_fallback();
 
         // Comment from rustc:
         // Even though coercion casts provide type hints, we check casts after fallback for
         // backwards compatibility. This makes fallback a stronger type hint than a cast coercion.
-        let cast_checks = std::mem::take(&mut self.deferred_cast_checks);
+        let cast_checks = std::mem::take(&mut ctx.deferred_cast_checks);
         for mut cast in cast_checks.into_iter() {
-            if let Err(diag) = cast.check(&mut self) {
-                self.diagnostics.push(diag);
+            if let Err(diag) = cast.check(&mut ctx) {
+                ctx.diagnostics.push(diag);
             }
         }
 
+        ctx.table.select_obligations_where_possible();
+
+        ctx.resolve_all()
+    }
+
+    // FIXME: This function should be private in module. It is currently only used in the consteval, since we need
+    // `InferenceResult` in the middle of inference. See the fixme comment in `consteval::eval_to_const`. If you
+    // used this function for another workaround, mention it here. If you really need this function and believe that
+    // there is no problem in it being `pub(crate)`, remove this comment.
+    pub(crate) fn resolve_all(self) -> InferenceResult {
         let InferenceContext {
             mut table, mut result, tuple_field_accesses_rev, diagnostics, ..
         } = self;
@@ -894,11 +960,6 @@ impl<'db> InferenceContext<'db> {
             diagnostics: _,
         } = &mut result;
 
-        // FIXME resolve obligations as well (use Guidance if necessary)
-        table.select_obligations_where_possible();
-
-        // make sure diverging type variables are marked as such
-        table.propagate_diverging_flag();
         for ty in type_of_expr.values_mut() {
             *ty = table.resolve_completely(ty.clone());
             *has_errors = *has_errors || ty.contains_unknown();
@@ -1653,6 +1714,22 @@ impl<'db> InferenceContext<'db> {
         self.resolve_associated_type_with_params(inner_ty, assoc_ty, &[])
     }
 
+    fn demand_eqtype(
+        &mut self,
+        expected: crate::next_solver::Ty<'db>,
+        actual: crate::next_solver::Ty<'db>,
+    ) {
+        let result = self
+            .table
+            .infer_ctxt
+            .at(&ObligationCause::new(), self.table.trait_env.env)
+            .eq(DefineOpaqueTypes::Yes, expected, actual)
+            .map(|infer_ok| self.table.register_infer_ok(infer_ok));
+        if let Err(_err) = result {
+            // FIXME: Emit diagnostic.
+        }
+    }
+
     fn resolve_associated_type_with_params(
         &mut self,
         inner_ty: Ty,
@@ -1708,6 +1785,7 @@ impl<'db> InferenceContext<'db> {
             LifetimeElisionKind::Infer,
         );
         let mut path_ctx = ctx.at_path(path, node);
+        let interner = DbInterner::conjure();
         let (resolution, unresolved) = if value_ns {
             let Some(res) = path_ctx.resolve_path_in_value_ns(HygieneId::ROOT) else {
                 return (self.err_ty(), None);
@@ -1717,15 +1795,27 @@ impl<'db> InferenceContext<'db> {
                     ValueNs::EnumVariantId(var) => {
                         let substs = path_ctx.substs_from_path(var.into(), true, false);
                         drop(ctx);
-                        let ty = self.db.ty(var.lookup(self.db).parent.into());
-                        let ty = self.insert_type_vars(ty.substitute(Interner, &substs));
+                        let args: crate::next_solver::GenericArgs<'_> =
+                            substs.to_nextsolver(interner);
+                        let ty = self
+                            .db
+                            .ty(var.lookup(self.db).parent.into())
+                            .instantiate(interner, args)
+                            .to_chalk(interner);
+                        let ty = self.insert_type_vars(ty);
                         return (ty, Some(var.into()));
                     }
                     ValueNs::StructId(strukt) => {
                         let substs = path_ctx.substs_from_path(strukt.into(), true, false);
                         drop(ctx);
-                        let ty = self.db.ty(strukt.into());
-                        let ty = self.insert_type_vars(ty.substitute(Interner, &substs));
+                        let args: crate::next_solver::GenericArgs<'_> =
+                            substs.to_nextsolver(interner);
+                        let ty = self
+                            .db
+                            .ty(strukt.into())
+                            .instantiate(interner, args)
+                            .to_chalk(interner);
+                        let ty = self.insert_type_vars(ty);
                         return (ty, Some(strukt.into()));
                     }
                     ValueNs::ImplSelf(impl_id) => (TypeNs::SelfType(impl_id), None),
@@ -1746,28 +1836,37 @@ impl<'db> InferenceContext<'db> {
             TypeNs::AdtId(AdtId::StructId(strukt)) => {
                 let substs = path_ctx.substs_from_path(strukt.into(), true, false);
                 drop(ctx);
-                let ty = self.db.ty(strukt.into());
-                let ty = self.insert_type_vars(ty.substitute(Interner, &substs));
+                let args: crate::next_solver::GenericArgs<'_> = substs.to_nextsolver(interner);
+                let ty = self.db.ty(strukt.into()).instantiate(interner, args).to_chalk(interner);
+                let ty = self.insert_type_vars(ty);
                 forbid_unresolved_segments((ty, Some(strukt.into())), unresolved)
             }
             TypeNs::AdtId(AdtId::UnionId(u)) => {
                 let substs = path_ctx.substs_from_path(u.into(), true, false);
                 drop(ctx);
-                let ty = self.db.ty(u.into());
-                let ty = self.insert_type_vars(ty.substitute(Interner, &substs));
+                let args: crate::next_solver::GenericArgs<'_> = substs.to_nextsolver(interner);
+                let ty = self.db.ty(u.into()).instantiate(interner, args).to_chalk(interner);
+                let ty = self.insert_type_vars(ty);
                 forbid_unresolved_segments((ty, Some(u.into())), unresolved)
             }
             TypeNs::EnumVariantId(var) => {
                 let substs = path_ctx.substs_from_path(var.into(), true, false);
                 drop(ctx);
-                let ty = self.db.ty(var.lookup(self.db).parent.into());
-                let ty = self.insert_type_vars(ty.substitute(Interner, &substs));
+                let args: crate::next_solver::GenericArgs<'_> = substs.to_nextsolver(interner);
+                let ty = self
+                    .db
+                    .ty(var.lookup(self.db).parent.into())
+                    .instantiate(interner, args)
+                    .to_chalk(interner);
+                let ty = self.insert_type_vars(ty);
                 forbid_unresolved_segments((ty, Some(var.into())), unresolved)
             }
             TypeNs::SelfType(impl_id) => {
                 let generics = crate::generics::generics(self.db, impl_id.into());
                 let substs = generics.placeholder_subst(self.db);
-                let mut ty = self.db.impl_self_ty(impl_id).substitute(Interner, &substs);
+                let args: crate::next_solver::GenericArgs<'_> = substs.to_nextsolver(interner);
+                let mut ty =
+                    self.db.impl_self_ty(impl_id).instantiate(interner, args).to_chalk(interner);
 
                 let Some(remaining_idx) = unresolved else {
                     drop(ctx);
@@ -1844,8 +1943,10 @@ impl<'db> InferenceContext<'db> {
                 };
                 let substs = path_ctx.substs_from_path_segment(it.into(), true, None, false);
                 drop(ctx);
-                let ty = self.db.ty(it.into());
-                let ty = self.insert_type_vars(ty.substitute(Interner, &substs));
+                let interner = DbInterner::conjure();
+                let args: crate::next_solver::GenericArgs<'_> = substs.to_nextsolver(interner);
+                let ty = self.db.ty(it.into()).instantiate(interner, args).to_chalk(interner);
+                let ty = self.insert_type_vars(ty);
 
                 self.resolve_variant_on_alias(ty, unresolved, mod_path)
             }
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/infer/closure.rs b/src/tools/rust-analyzer/crates/hir-ty/src/infer/closure.rs
index 1d5d8dd13ed..4a57b2f3751 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/infer/closure.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/infer/closure.rs
@@ -318,7 +318,7 @@ impl<'db> InferenceContext<'db> {
                     _ = self
                         .table
                         .infer_ctxt
-                        .at(&ObligationCause::new(), self.table.param_env)
+                        .at(&ObligationCause::new(), self.table.trait_env.env)
                         .eq(DefineOpaqueTypes::Yes, inferred_fnptr_sig, generalized_fnptr_sig)
                         .map(|infer_ok| self.table.register_infer_ok(infer_ok));
 
@@ -703,7 +703,7 @@ impl<'db> InferenceContext<'db> {
                 let cause = ObligationCause::new();
                 let InferOk { value: (), obligations } = table
                     .infer_ctxt
-                    .at(&cause, table.param_env)
+                    .at(&cause, table.trait_env.env)
                     .eq(DefineOpaqueTypes::Yes, expected_ty, supplied_ty)?;
                 all_obligations.extend(obligations);
             }
@@ -711,7 +711,7 @@ impl<'db> InferenceContext<'db> {
             let supplied_output_ty = supplied_sig.output();
             let cause = ObligationCause::new();
             let InferOk { value: (), obligations } =
-                table.infer_ctxt.at(&cause, table.param_env).eq(
+                table.infer_ctxt.at(&cause, table.trait_env.env).eq(
                     DefineOpaqueTypes::Yes,
                     expected_sigs.liberated_sig.output(),
                     supplied_output_ty,
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/infer/coerce.rs b/src/tools/rust-analyzer/crates/hir-ty/src/infer/coerce.rs
index 7930d8b0ed6..62ce00a2e33 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/infer/coerce.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/infer/coerce.rs
@@ -144,7 +144,7 @@ impl<'a, 'b, 'db> Coerce<'a, 'b, 'db> {
     fn unify_raw(&mut self, a: Ty<'db>, b: Ty<'db>) -> InferResult<'db, Ty<'db>> {
         debug!("unify(a: {:?}, b: {:?}, use_lub: {})", a, b, self.use_lub);
         self.commit_if_ok(|this| {
-            let at = this.infer_ctxt().at(&this.cause, this.table.param_env);
+            let at = this.infer_ctxt().at(&this.cause, this.table.trait_env.env);
 
             let res = if this.use_lub {
                 at.lub(b, a)
@@ -210,9 +210,8 @@ impl<'a, 'b, 'db> Coerce<'a, 'b, 'db> {
         // Coercing from `!` to any type is allowed:
         if a.is_never() {
             // If we're coercing into an inference var, mark it as possibly diverging.
-            // FIXME: rustc does this differently.
-            if let TyKind::Infer(rustc_type_ir::TyVar(b)) = b.kind() {
-                self.table.set_diverging(b.as_u32().into(), chalk_ir::TyVariableKind::General);
+            if b.is_infer() {
+                self.table.set_diverging(b);
             }
 
             if self.coerce_never {
@@ -330,7 +329,7 @@ impl<'a, 'b, 'db> Coerce<'a, 'b, 'db> {
                     obligations.push(Obligation::new(
                         self.interner(),
                         self.cause.clone(),
-                        self.table.param_env,
+                        self.table.trait_env.env,
                         Binder::dummy(PredicateKind::Coerce(CoercePredicate {
                             a: source_ty,
                             b: target_ty,
@@ -718,7 +717,7 @@ impl<'a, 'b, 'db> Coerce<'a, 'b, 'db> {
         let mut queue: SmallVec<[PredicateObligation<'db>; 4]> = smallvec![Obligation::new(
             self.interner(),
             cause,
-            self.table.param_env,
+            self.table.trait_env.env,
             TraitRef::new(
                 self.interner(),
                 coerce_unsized_did.into(),
@@ -1114,8 +1113,12 @@ impl<'db> InferenceContext<'db> {
                         match self.table.commit_if_ok(|table| {
                             // We need to eagerly handle nested obligations due to lazy norm.
                             let mut ocx = ObligationCtxt::new(&table.infer_ctxt);
-                            let value =
-                                ocx.lub(&ObligationCause::new(), table.param_env, prev_ty, new_ty)?;
+                            let value = ocx.lub(
+                                &ObligationCause::new(),
+                                table.trait_env.env,
+                                prev_ty,
+                                new_ty,
+                            )?;
                             if ocx.select_where_possible().is_empty() {
                                 Ok(InferOk { value, obligations: ocx.into_pending_obligations() })
                             } else {
@@ -1158,7 +1161,7 @@ impl<'db> InferenceContext<'db> {
             let sig = self
                 .table
                 .infer_ctxt
-                .at(&ObligationCause::new(), self.table.param_env)
+                .at(&ObligationCause::new(), self.table.trait_env.env)
                 .lub(a_sig, b_sig)
                 .map(|ok| self.table.register_infer_ok(ok))?;
 
@@ -1248,7 +1251,7 @@ impl<'db> InferenceContext<'db> {
                         .commit_if_ok(|table| {
                             table
                                 .infer_ctxt
-                                .at(&ObligationCause::new(), table.param_env)
+                                .at(&ObligationCause::new(), table.trait_env.env)
                                 .lub(prev_ty, new_ty)
                         })
                         .unwrap_err())
@@ -1498,7 +1501,7 @@ impl<'db, 'exprs> CoerceMany<'db, 'exprs> {
             assert!(expression_ty.is_unit(), "if let hack without unit type");
             icx.table
                 .infer_ctxt
-                .at(cause, icx.table.param_env)
+                .at(cause, icx.table.trait_env.env)
                 .eq(
                     // needed for tests/ui/type-alias-impl-trait/issue-65679-inst-opaque-ty-from-val-twice.rs
                     DefineOpaqueTypes::Yes,
@@ -1564,9 +1567,9 @@ impl<'db, 'exprs> CoerceMany<'db, 'exprs> {
     }
 }
 
-pub fn could_coerce(
-    db: &dyn HirDatabase,
-    env: Arc<TraitEnvironment>,
+pub fn could_coerce<'db>(
+    db: &'db dyn HirDatabase,
+    env: Arc<TraitEnvironment<'db>>,
     tys: &crate::Canonical<(crate::Ty, crate::Ty)>,
 ) -> bool {
     coerce(db, env, tys).is_ok()
@@ -1574,7 +1577,7 @@ pub fn could_coerce(
 
 fn coerce<'db>(
     db: &'db dyn HirDatabase,
-    env: Arc<TraitEnvironment>,
+    env: Arc<TraitEnvironment<'db>>,
     tys: &crate::Canonical<(crate::Ty, crate::Ty)>,
 ) -> Result<(Vec<Adjustment>, crate::Ty), TypeError<DbInterner<'db>>> {
     let mut table = InferenceTable::new(db, env);
@@ -1609,16 +1612,21 @@ fn coerce<'db>(
             chalk_ir::GenericArgData::Const(c) => c.inference_var(Interner),
         } == Some(iv))
     };
-    let fallback = |iv, kind, default, binder| match kind {
-        chalk_ir::VariableKind::Ty(_ty_kind) => find_var(iv)
-            .map_or(default, |i| crate::BoundVar::new(binder, i).to_ty(Interner).cast(Interner)),
-        chalk_ir::VariableKind::Lifetime => find_var(iv).map_or(default, |i| {
-            crate::BoundVar::new(binder, i).to_lifetime(Interner).cast(Interner)
-        }),
-        chalk_ir::VariableKind::Const(ty) => find_var(iv).map_or(default, |i| {
-            crate::BoundVar::new(binder, i).to_const(Interner, ty).cast(Interner)
-        }),
+    let fallback = |iv, kind, binder| match kind {
+        chalk_ir::VariableKind::Ty(_ty_kind) => find_var(iv).map_or_else(
+            || chalk_ir::TyKind::Error.intern(Interner).cast(Interner),
+            |i| crate::BoundVar::new(binder, i).to_ty(Interner).cast(Interner),
+        ),
+        chalk_ir::VariableKind::Lifetime => find_var(iv).map_or_else(
+            || crate::LifetimeData::Error.intern(Interner).cast(Interner),
+            |i| crate::BoundVar::new(binder, i).to_lifetime(Interner).cast(Interner),
+        ),
+        chalk_ir::VariableKind::Const(ty) => find_var(iv).map_or_else(
+            || crate::unknown_const(ty.clone()).cast(Interner),
+            |i| crate::BoundVar::new(binder, i).to_const(Interner, ty.clone()).cast(Interner),
+        ),
     };
     // FIXME also map the types in the adjustments
+    // FIXME: We don't fallback correctly since this is done on `InferenceContext` and we only have `InferenceTable`.
     Ok((adjustments, table.resolve_with_fallback(ty.to_chalk(table.interner), &fallback)))
 }
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/infer/expr.rs b/src/tools/rust-analyzer/crates/hir-ty/src/infer/expr.rs
index c5a51dfc4cf..ddf632c1c81 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/infer/expr.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/infer/expr.rs
@@ -23,13 +23,13 @@ use syntax::ast::RangeOp;
 use tracing::debug;
 
 use crate::autoderef::overloaded_deref_ty;
-use crate::next_solver::ErrorGuaranteed;
 use crate::next_solver::infer::DefineOpaqueTypes;
 use crate::next_solver::obligation_ctxt::ObligationCtxt;
+use crate::next_solver::{DbInterner, ErrorGuaranteed};
 use crate::{
-    Adjust, Adjustment, AdtId, AutoBorrow, Binders, CallableDefId, CallableSig, DeclContext,
-    DeclOrigin, IncorrectGenericsLenKind, Interner, LifetimeElisionKind, Rawness, Scalar,
-    Substitution, TraitEnvironment, TraitRef, Ty, TyBuilder, TyExt, TyKind, consteval,
+    Adjust, Adjustment, AdtId, AutoBorrow, CallableDefId, CallableSig, DeclContext, DeclOrigin,
+    IncorrectGenericsLenKind, Interner, LifetimeElisionKind, Rawness, Scalar, Substitution,
+    TraitEnvironment, TraitRef, Ty, TyBuilder, TyExt, TyKind, consteval,
     generics::generics,
     infer::{
         AllowTwoPhase, BreakableKind,
@@ -1481,7 +1481,10 @@ impl<'db> InferenceContext<'db> {
 
         self.write_method_resolution(tgt_expr, func, subst.clone());
 
-        let method_ty = self.db.value_ty(func.into()).unwrap().substitute(Interner, &subst);
+        let interner = DbInterner::new_with(self.db, None, None);
+        let args: crate::next_solver::GenericArgs<'_> = subst.to_nextsolver(interner);
+        let method_ty =
+            self.db.value_ty(func.into()).unwrap().instantiate(interner, args).to_chalk(interner);
         self.register_obligations_for_call(&method_ty);
 
         self.infer_expr_coerce(rhs, &Expectation::has_type(rhs_ty.clone()), ExprIsRead::Yes);
@@ -1662,7 +1665,6 @@ impl<'db> InferenceContext<'db> {
             });
         self.resolver.reset_to_guard(g);
         if let Some(prev_env) = prev_env {
-            self.table.param_env = prev_env.env.to_nextsolver(self.table.interner);
             self.table.trait_env = prev_env;
         }
 
@@ -1801,11 +1803,17 @@ impl<'db> InferenceContext<'db> {
                         self.write_expr_adj(receiver, adjustments.into_boxed_slice());
                         self.write_method_resolution(tgt_expr, func, substs.clone());
 
+                        let interner = DbInterner::new_with(self.db, None, None);
+                        let args: crate::next_solver::GenericArgs<'_> =
+                            substs.to_nextsolver(interner);
                         self.check_method_call(
                             tgt_expr,
                             &[],
-                            self.db.value_ty(func.into()).unwrap(),
-                            substs,
+                            self.db
+                                .value_ty(func.into())
+                                .unwrap()
+                                .instantiate(interner, args)
+                                .to_chalk(interner),
                             ty,
                             expected,
                         )
@@ -1964,11 +1972,16 @@ impl<'db> InferenceContext<'db> {
 
                 let substs = self.substs_for_method_call(tgt_expr, func.into(), generic_args);
                 self.write_method_resolution(tgt_expr, func, substs.clone());
+                let interner = DbInterner::new_with(self.db, None, None);
+                let gen_args: crate::next_solver::GenericArgs<'_> = substs.to_nextsolver(interner);
                 self.check_method_call(
                     tgt_expr,
                     args,
-                    self.db.value_ty(func.into()).expect("we have a function def"),
-                    substs,
+                    self.db
+                        .value_ty(func.into())
+                        .expect("we have a function def")
+                        .instantiate(interner, gen_args)
+                        .to_chalk(interner),
                     ty,
                     expected,
                 )
@@ -2013,11 +2026,15 @@ impl<'db> InferenceContext<'db> {
                 let recovered = match assoc_func_with_same_name {
                     Some(f) => {
                         let substs = self.substs_for_method_call(tgt_expr, f.into(), generic_args);
+                        let interner = DbInterner::new_with(self.db, None, None);
+                        let args: crate::next_solver::GenericArgs<'_> =
+                            substs.to_nextsolver(interner);
                         let f = self
                             .db
                             .value_ty(f.into())
                             .expect("we have a function def")
-                            .substitute(Interner, &substs);
+                            .instantiate(interner, args)
+                            .to_chalk(interner);
                         let sig = f.callable_sig(self.db).expect("we have a function def");
                         Some((f, sig, true))
                     }
@@ -2057,12 +2074,10 @@ impl<'db> InferenceContext<'db> {
         &mut self,
         tgt_expr: ExprId,
         args: &[ExprId],
-        method_ty: Binders<Ty>,
-        substs: Substitution,
+        method_ty: Ty,
         receiver_ty: Ty,
         expected: &Expectation,
     ) -> Ty {
-        let method_ty = method_ty.substitute(Interner, &substs);
         self.register_obligations_for_call(&method_ty);
         let interner = self.table.interner;
         let ((formal_receiver_ty, param_tys), ret_ty, is_varargs) =
@@ -2132,7 +2147,7 @@ impl<'db> InferenceContext<'db> {
                         let origin = ObligationCause::new();
                         ocx.sup(
                             &origin,
-                            self.table.param_env,
+                            self.table.trait_env.env,
                             expected_output.to_nextsolver(interner),
                             formal_output,
                         )?;
@@ -2239,7 +2254,7 @@ impl<'db> InferenceContext<'db> {
             let formal_ty_error = this
                 .table
                 .infer_ctxt
-                .at(&ObligationCause::new(), this.table.param_env)
+                .at(&ObligationCause::new(), this.table.trait_env.env)
                 .eq(DefineOpaqueTypes::Yes, formal_input_ty, coerced_ty);
 
             // If neither check failed, the types are compatible
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/infer/fallback.rs b/src/tools/rust-analyzer/crates/hir-ty/src/infer/fallback.rs
new file mode 100644
index 00000000000..2022447ad43
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/infer/fallback.rs
@@ -0,0 +1,439 @@
+//! Fallback of infer vars to `!` and `i32`/`f64`.
+
+use intern::sym;
+use petgraph::{
+    Graph,
+    visit::{Dfs, Walker},
+};
+use rustc_hash::{FxBuildHasher, FxHashMap, FxHashSet};
+use rustc_type_ir::{
+    TyVid,
+    inherent::{IntoKind, Ty as _},
+};
+use tracing::debug;
+
+use crate::{
+    infer::InferenceContext,
+    next_solver::{CoercePredicate, PredicateKind, SubtypePredicate, Ty, TyKind},
+};
+
+#[derive(Copy, Clone)]
+pub(crate) enum DivergingFallbackBehavior {
+    /// Always fallback to `()` (aka "always spontaneous decay")
+    ToUnit,
+    /// Sometimes fallback to `!`, but mainly fallback to `()` so that most of the crates are not broken.
+    ContextDependent,
+    /// Always fallback to `!` (which should be equivalent to never falling back + not making
+    /// never-to-any coercions unless necessary)
+    ToNever,
+}
+
+impl<'db> InferenceContext<'db> {
+    pub(super) fn type_inference_fallback(&mut self) {
+        debug!(
+            "type-inference-fallback start obligations: {:#?}",
+            self.table.fulfillment_cx.pending_obligations()
+        );
+
+        // All type checking constraints were added, try to fallback unsolved variables.
+        self.table.select_obligations_where_possible();
+
+        debug!(
+            "type-inference-fallback post selection obligations: {:#?}",
+            self.table.fulfillment_cx.pending_obligations()
+        );
+
+        let fallback_occurred = self.fallback_types();
+
+        if !fallback_occurred {
+            return;
+        }
+
+        // We now see if we can make progress. This might cause us to
+        // unify inference variables for opaque types, since we may
+        // have unified some other type variables during the first
+        // phase of fallback. This means that we only replace
+        // inference variables with their underlying opaque types as a
+        // last resort.
+        //
+        // In code like this:
+        //
+        // ```rust
+        // type MyType = impl Copy;
+        // fn produce() -> MyType { true }
+        // fn bad_produce() -> MyType { panic!() }
+        // ```
+        //
+        // we want to unify the opaque inference variable in `bad_produce`
+        // with the diverging fallback for `panic!` (e.g. `()` or `!`).
+        // This will produce a nice error message about conflicting concrete
+        // types for `MyType`.
+        //
+        // If we had tried to fallback the opaque inference variable to `MyType`,
+        // we will generate a confusing type-check error that does not explicitly
+        // refer to opaque types.
+        self.table.select_obligations_where_possible();
+    }
+
+    fn diverging_fallback_behavior(&self) -> DivergingFallbackBehavior {
+        if self.krate().data(self.db).edition.at_least_2024() {
+            return DivergingFallbackBehavior::ToNever;
+        }
+
+        if self.resolver.def_map().is_unstable_feature_enabled(&sym::never_type_fallback) {
+            return DivergingFallbackBehavior::ContextDependent;
+        }
+
+        DivergingFallbackBehavior::ToUnit
+    }
+
+    fn fallback_types(&mut self) -> bool {
+        // Check if we have any unresolved variables. If not, no need for fallback.
+        let unresolved_variables = self.table.infer_ctxt.unresolved_variables();
+
+        if unresolved_variables.is_empty() {
+            return false;
+        }
+
+        let diverging_fallback_behavior = self.diverging_fallback_behavior();
+
+        let diverging_fallback =
+            self.calculate_diverging_fallback(&unresolved_variables, diverging_fallback_behavior);
+
+        // We do fallback in two passes, to try to generate
+        // better error messages.
+        // The first time, we do *not* replace opaque types.
+        let mut fallback_occurred = false;
+        for ty in unresolved_variables {
+            debug!("unsolved_variable = {:?}", ty);
+            fallback_occurred |= self.fallback_if_possible(ty, &diverging_fallback);
+        }
+
+        fallback_occurred
+    }
+
+    // Tries to apply a fallback to `ty` if it is an unsolved variable.
+    //
+    // - Unconstrained ints are replaced with `i32`.
+    //
+    // - Unconstrained floats are replaced with `f64`.
+    //
+    // - Non-numerics may get replaced with `()` or `!`, depending on
+    //   how they were categorized by `calculate_diverging_fallback`
+    //   (and the setting of `#![feature(never_type_fallback)]`).
+    //
+    // Fallback becomes very dubious if we have encountered
+    // type-checking errors. In that case, fallback to Error.
+    //
+    // Sets `FnCtxt::fallback_has_occurred` if fallback is performed
+    // during this call.
+    fn fallback_if_possible(
+        &mut self,
+        ty: Ty<'db>,
+        diverging_fallback: &FxHashMap<Ty<'db>, Ty<'db>>,
+    ) -> bool {
+        // Careful: we do NOT shallow-resolve `ty`. We know that `ty`
+        // is an unsolved variable, and we determine its fallback
+        // based solely on how it was created, not what other type
+        // variables it may have been unified with since then.
+        //
+        // The reason this matters is that other attempts at fallback
+        // may (in principle) conflict with this fallback, and we wish
+        // to generate a type error in that case. (However, this
+        // actually isn't true right now, because we're only using the
+        // builtin fallback rules. This would be true if we were using
+        // user-supplied fallbacks. But it's still useful to write the
+        // code to detect bugs.)
+        //
+        // (Note though that if we have a general type variable `?T`
+        // that is then unified with an integer type variable `?I`
+        // that ultimately never gets resolved to a special integral
+        // type, `?T` is not considered unsolved, but `?I` is. The
+        // same is true for float variables.)
+        let fallback = match ty.kind() {
+            TyKind::Infer(rustc_type_ir::IntVar(_)) => self.types.i32,
+            TyKind::Infer(rustc_type_ir::FloatVar(_)) => self.types.f64,
+            _ => match diverging_fallback.get(&ty) {
+                Some(&fallback_ty) => fallback_ty,
+                None => return false,
+            },
+        };
+        debug!("fallback_if_possible(ty={:?}): defaulting to `{:?}`", ty, fallback);
+
+        self.demand_eqtype(ty, fallback);
+        true
+    }
+
+    /// The "diverging fallback" system is rather complicated. This is
+    /// a result of our need to balance 'do the right thing' with
+    /// backwards compatibility.
+    ///
+    /// "Diverging" type variables are variables created when we
+    /// coerce a `!` type into an unbound type variable `?X`. If they
+    /// never wind up being constrained, the "right and natural" thing
+    /// is that `?X` should "fallback" to `!`. This means that e.g. an
+    /// expression like `Some(return)` will ultimately wind up with a
+    /// type like `Option<!>` (presuming it is not assigned or
+    /// constrained to have some other type).
+    ///
+    /// However, the fallback used to be `()` (before the `!` type was
+    /// added). Moreover, there are cases where the `!` type 'leaks
+    /// out' from dead code into type variables that affect live
+    /// code. The most common case is something like this:
+    ///
+    /// ```rust
+    /// # fn foo() -> i32 { 4 }
+    /// match foo() {
+    ///     22 => Default::default(), // call this type `?D`
+    ///     _ => return, // return has type `!`
+    /// } // call the type of this match `?M`
+    /// ```
+    ///
+    /// Here, coercing the type `!` into `?M` will create a diverging
+    /// type variable `?X` where `?X <: ?M`. We also have that `?D <:
+    /// ?M`. If `?M` winds up unconstrained, then `?X` will
+    /// fallback. If it falls back to `!`, then all the type variables
+    /// will wind up equal to `!` -- this includes the type `?D`
+    /// (since `!` doesn't implement `Default`, we wind up a "trait
+    /// not implemented" error in code like this). But since the
+    /// original fallback was `()`, this code used to compile with `?D
+    /// = ()`. This is somewhat surprising, since `Default::default()`
+    /// on its own would give an error because the types are
+    /// insufficiently constrained.
+    ///
+    /// Our solution to this dilemma is to modify diverging variables
+    /// so that they can *either* fallback to `!` (the default) or to
+    /// `()` (the backwards compatibility case). We decide which
+    /// fallback to use based on whether there is a coercion pattern
+    /// like this:
+    ///
+    /// ```ignore (not-rust)
+    /// ?Diverging -> ?V
+    /// ?NonDiverging -> ?V
+    /// ?V != ?NonDiverging
+    /// ```
+    ///
+    /// Here `?Diverging` represents some diverging type variable and
+    /// `?NonDiverging` represents some non-diverging type
+    /// variable. `?V` can be any type variable (diverging or not), so
+    /// long as it is not equal to `?NonDiverging`.
+    ///
+    /// Intuitively, what we are looking for is a case where a
+    /// "non-diverging" type variable (like `?M` in our example above)
+    /// is coerced *into* some variable `?V` that would otherwise
+    /// fallback to `!`. In that case, we make `?V` fallback to `!`,
+    /// along with anything that would flow into `?V`.
+    ///
+    /// The algorithm we use:
+    /// * Identify all variables that are coerced *into* by a
+    ///   diverging variable. Do this by iterating over each
+    ///   diverging, unsolved variable and finding all variables
+    ///   reachable from there. Call that set `D`.
+    /// * Walk over all unsolved, non-diverging variables, and find
+    ///   any variable that has an edge into `D`.
+    fn calculate_diverging_fallback(
+        &self,
+        unresolved_variables: &[Ty<'db>],
+        behavior: DivergingFallbackBehavior,
+    ) -> FxHashMap<Ty<'db>, Ty<'db>> {
+        debug!("calculate_diverging_fallback({:?})", unresolved_variables);
+
+        // Construct a coercion graph where an edge `A -> B` indicates
+        // a type variable is that is coerced
+        let coercion_graph = self.create_coercion_graph();
+
+        // Extract the unsolved type inference variable vids; note that some
+        // unsolved variables are integer/float variables and are excluded.
+        let unsolved_vids = unresolved_variables.iter().filter_map(|ty| ty.ty_vid());
+
+        // Compute the diverging root vids D -- that is, the root vid of
+        // those type variables that (a) are the target of a coercion from
+        // a `!` type and (b) have not yet been solved.
+        //
+        // These variables are the ones that are targets for fallback to
+        // either `!` or `()`.
+        let diverging_roots: FxHashSet<TyVid> = self
+            .table
+            .diverging_type_vars
+            .iter()
+            .map(|&ty| self.shallow_resolve(ty))
+            .filter_map(|ty| ty.ty_vid())
+            .map(|vid| self.table.infer_ctxt.root_var(vid))
+            .collect();
+        debug!(
+            "calculate_diverging_fallback: diverging_type_vars={:?}",
+            self.table.diverging_type_vars
+        );
+        debug!("calculate_diverging_fallback: diverging_roots={:?}", diverging_roots);
+
+        // Find all type variables that are reachable from a diverging
+        // type variable. These will typically default to `!`, unless
+        // we find later that they are *also* reachable from some
+        // other type variable outside this set.
+        let mut roots_reachable_from_diverging = Dfs::empty(&coercion_graph);
+        let mut diverging_vids = vec![];
+        let mut non_diverging_vids = vec![];
+        for unsolved_vid in unsolved_vids {
+            let root_vid = self.table.infer_ctxt.root_var(unsolved_vid);
+            debug!(
+                "calculate_diverging_fallback: unsolved_vid={:?} root_vid={:?} diverges={:?}",
+                unsolved_vid,
+                root_vid,
+                diverging_roots.contains(&root_vid),
+            );
+            if diverging_roots.contains(&root_vid) {
+                diverging_vids.push(unsolved_vid);
+                roots_reachable_from_diverging.move_to(root_vid.as_u32().into());
+
+                // drain the iterator to visit all nodes reachable from this node
+                while roots_reachable_from_diverging.next(&coercion_graph).is_some() {}
+            } else {
+                non_diverging_vids.push(unsolved_vid);
+            }
+        }
+
+        debug!(
+            "calculate_diverging_fallback: roots_reachable_from_diverging={:?}",
+            roots_reachable_from_diverging,
+        );
+
+        // Find all type variables N0 that are not reachable from a
+        // diverging variable, and then compute the set reachable from
+        // N0, which we call N. These are the *non-diverging* type
+        // variables. (Note that this set consists of "root variables".)
+        let mut roots_reachable_from_non_diverging = Dfs::empty(&coercion_graph);
+        for &non_diverging_vid in &non_diverging_vids {
+            let root_vid = self.table.infer_ctxt.root_var(non_diverging_vid);
+            if roots_reachable_from_diverging.discovered.contains(root_vid.as_usize()) {
+                continue;
+            }
+            roots_reachable_from_non_diverging.move_to(root_vid.as_u32().into());
+            while roots_reachable_from_non_diverging.next(&coercion_graph).is_some() {}
+        }
+        debug!(
+            "calculate_diverging_fallback: roots_reachable_from_non_diverging={:?}",
+            roots_reachable_from_non_diverging,
+        );
+
+        debug!("obligations: {:#?}", self.table.fulfillment_cx.pending_obligations());
+
+        // For each diverging variable, figure out whether it can
+        // reach a member of N. If so, it falls back to `()`. Else
+        // `!`.
+        let mut diverging_fallback =
+            FxHashMap::with_capacity_and_hasher(diverging_vids.len(), FxBuildHasher);
+
+        for &diverging_vid in &diverging_vids {
+            let diverging_ty = Ty::new_var(self.table.interner, diverging_vid);
+            let root_vid = self.table.infer_ctxt.root_var(diverging_vid);
+            let can_reach_non_diverging = Dfs::new(&coercion_graph, root_vid.as_u32().into())
+                .iter(&coercion_graph)
+                .any(|n| roots_reachable_from_non_diverging.discovered.contains(n.index()));
+
+            let mut fallback_to = |ty| {
+                diverging_fallback.insert(diverging_ty, ty);
+            };
+
+            match behavior {
+                DivergingFallbackBehavior::ToUnit => {
+                    debug!("fallback to () - legacy: {:?}", diverging_vid);
+                    fallback_to(self.types.unit);
+                }
+                DivergingFallbackBehavior::ContextDependent => {
+                    // FIXME: rustc does the following, but given this is only relevant when the unstable
+                    // `never_type_fallback` feature is active, I chose to not port this.
+                    // if found_infer_var_info.self_in_trait && found_infer_var_info.output {
+                    //     // This case falls back to () to ensure that the code pattern in
+                    //     // tests/ui/never_type/fallback-closure-ret.rs continues to
+                    //     // compile when never_type_fallback is enabled.
+                    //     //
+                    //     // This rule is not readily explainable from first principles,
+                    //     // but is rather intended as a patchwork fix to ensure code
+                    //     // which compiles before the stabilization of never type
+                    //     // fallback continues to work.
+                    //     //
+                    //     // Typically this pattern is encountered in a function taking a
+                    //     // closure as a parameter, where the return type of that closure
+                    //     // (checked by `relationship.output`) is expected to implement
+                    //     // some trait (checked by `relationship.self_in_trait`). This
+                    //     // can come up in non-closure cases too, so we do not limit this
+                    //     // rule to specifically `FnOnce`.
+                    //     //
+                    //     // When the closure's body is something like `panic!()`, the
+                    //     // return type would normally be inferred to `!`. However, it
+                    //     // needs to fall back to `()` in order to still compile, as the
+                    //     // trait is specifically implemented for `()` but not `!`.
+                    //     //
+                    //     // For details on the requirements for these relationships to be
+                    //     // set, see the relationship finding module in
+                    //     // compiler/rustc_trait_selection/src/traits/relationships.rs.
+                    //     debug!("fallback to () - found trait and projection: {:?}", diverging_vid);
+                    //     fallback_to(self.types.unit);
+                    // }
+                    if can_reach_non_diverging {
+                        debug!("fallback to () - reached non-diverging: {:?}", diverging_vid);
+                        fallback_to(self.types.unit);
+                    } else {
+                        debug!("fallback to ! - all diverging: {:?}", diverging_vid);
+                        fallback_to(self.types.never);
+                    }
+                }
+                DivergingFallbackBehavior::ToNever => {
+                    debug!(
+                        "fallback to ! - `rustc_never_type_mode = \"fallback_to_never\")`: {:?}",
+                        diverging_vid
+                    );
+                    fallback_to(self.types.never);
+                }
+            }
+        }
+
+        diverging_fallback
+    }
+
+    /// Returns a graph whose nodes are (unresolved) inference variables and where
+    /// an edge `?A -> ?B` indicates that the variable `?A` is coerced to `?B`.
+    fn create_coercion_graph(&self) -> Graph<(), ()> {
+        let pending_obligations = self.table.fulfillment_cx.pending_obligations();
+        let pending_obligations_len = pending_obligations.len();
+        debug!("create_coercion_graph: pending_obligations={:?}", pending_obligations);
+        let coercion_edges = pending_obligations
+            .into_iter()
+            .filter_map(|obligation| {
+                // The predicates we are looking for look like `Coerce(?A -> ?B)`.
+                // They will have no bound variables.
+                obligation.predicate.kind().no_bound_vars()
+            })
+            .filter_map(|atom| {
+                // We consider both subtyping and coercion to imply 'flow' from
+                // some position in the code `a` to a different position `b`.
+                // This is then used to determine which variables interact with
+                // live code, and as such must fall back to `()` to preserve
+                // soundness.
+                //
+                // In practice currently the two ways that this happens is
+                // coercion and subtyping.
+                let (a, b) = match atom {
+                    PredicateKind::Coerce(CoercePredicate { a, b }) => (a, b),
+                    PredicateKind::Subtype(SubtypePredicate { a_is_expected: _, a, b }) => (a, b),
+                    _ => return None,
+                };
+
+                let a_vid = self.root_vid(a)?;
+                let b_vid = self.root_vid(b)?;
+                Some((a_vid.as_u32(), b_vid.as_u32()))
+            });
+        let num_ty_vars = self.table.infer_ctxt.num_ty_vars();
+        let mut graph = Graph::with_capacity(num_ty_vars, pending_obligations_len);
+        for _ in 0..num_ty_vars {
+            graph.add_node(());
+        }
+        graph.extend_with_edges(coercion_edges);
+        graph
+    }
+
+    /// If `ty` is an unresolved type variable, returns its root vid.
+    fn root_vid(&self, ty: Ty<'db>) -> Option<TyVid> {
+        Some(self.table.infer_ctxt.root_var(self.shallow_resolve(ty).ty_vid()?))
+    }
+}
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/infer/path.rs b/src/tools/rust-analyzer/crates/hir-ty/src/infer/path.rs
index 80f7324e58b..733f3c27880 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/infer/path.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/infer/path.rs
@@ -17,7 +17,10 @@ use crate::{
     generics::generics,
     infer::diagnostics::InferenceTyLoweringContext as TyLoweringContext,
     method_resolution::{self, VisibleFromModule},
-    next_solver::mapping::ChalkToNextSolver,
+    next_solver::{
+        DbInterner,
+        mapping::{ChalkToNextSolver, NextSolverToChalk},
+    },
     to_chalk_trait_id,
 };
 
@@ -36,7 +39,9 @@ impl<'db> InferenceContext<'db> {
 
         self.add_required_obligations_for_value_path(generic_def, &substs);
 
-        let ty = self.db.value_ty(value_def)?.substitute(Interner, &substs);
+        let interner = DbInterner::new_with(self.db, None, None);
+        let args: crate::next_solver::GenericArgs<'_> = substs.to_nextsolver(interner);
+        let ty = self.db.value_ty(value_def)?.instantiate(interner, args).to_chalk(interner);
         let ty = self.process_remote_user_written_ty(ty);
         Some(ty)
     }
@@ -69,8 +74,11 @@ impl<'db> InferenceContext<'db> {
             }
             ValueNs::ImplSelf(impl_id) => {
                 let generics = crate::generics::generics(self.db, impl_id.into());
+                let interner = DbInterner::new_with(self.db, None, None);
                 let substs = generics.placeholder_subst(self.db);
-                let ty = self.db.impl_self_ty(impl_id).substitute(Interner, &substs);
+                let args: crate::next_solver::GenericArgs<'_> = substs.to_nextsolver(interner);
+                let ty =
+                    self.db.impl_self_ty(impl_id).instantiate(interner, args).to_chalk(interner);
                 return if let Some((AdtId::StructId(struct_id), substs)) = ty.as_adt() {
                     Some(ValuePathResolution::GenericDef(
                         struct_id.into(),
@@ -89,9 +97,9 @@ impl<'db> InferenceContext<'db> {
 
         let generic_def = value_def.to_generic_def_id(self.db);
         if let GenericDefId::StaticId(_) = generic_def {
+            let interner = DbInterner::new_with(self.db, None, None);
             // `Static` is the kind of item that can never be generic currently. We can just skip the binders to get its type.
-            let (ty, binders) = self.db.value_ty(value_def)?.into_value_and_skipped_binders();
-            stdx::always!(binders.is_empty(Interner), "non-empty binders for non-generic def",);
+            let ty = self.db.value_ty(value_def)?.skip_binder().to_chalk(interner);
             return Some(ValuePathResolution::NonGeneric(ty));
         };
 
@@ -354,10 +362,13 @@ impl<'db> InferenceContext<'db> {
         };
         let substs = match container {
             ItemContainerId::ImplId(impl_id) => {
+                let interner = DbInterner::new_with(self.db, None, None);
                 let impl_substs = TyBuilder::subst_for_def(self.db, impl_id, None)
                     .fill_with_inference_vars(&mut self.table)
                     .build();
-                let impl_self_ty = self.db.impl_self_ty(impl_id).substitute(Interner, &impl_substs);
+                let args: crate::next_solver::GenericArgs<'_> = impl_substs.to_nextsolver(interner);
+                let impl_self_ty =
+                    self.db.impl_self_ty(impl_id).instantiate(interner, args).to_chalk(interner);
                 self.unify(&impl_self_ty, &ty);
                 impl_substs
             }
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/infer/unify.rs b/src/tools/rust-analyzer/crates/hir-ty/src/infer/unify.rs
index 1687857ae1a..108cf5b1a2b 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/infer/unify.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/infer/unify.rs
@@ -3,47 +3,42 @@
 use std::fmt;
 
 use chalk_ir::{
-    CanonicalVarKind, FloatTy, IntTy, TyVariableKind, cast::Cast, fold::TypeFoldable,
-    interner::HasInterner,
+    CanonicalVarKind, TyVariableKind, cast::Cast, fold::TypeFoldable, interner::HasInterner,
 };
 use either::Either;
 use hir_def::{AdtId, lang_item::LangItem};
 use hir_expand::name::Name;
 use intern::sym;
 use rustc_hash::{FxHashMap, FxHashSet};
-use rustc_type_ir::inherent::Ty as _;
 use rustc_type_ir::{
-    FloatVid, IntVid, TyVid, TypeVisitableExt,
-    inherent::{IntoKind, Span, Term as _},
+    TyVid, TypeVisitableExt, UpcastFrom,
+    inherent::{IntoKind, Span, Term as _, Ty as _},
     relate::{Relate, solver_relating::RelateExt},
-    solve::{Certainty, GoalSource, NoSolution},
+    solve::{Certainty, GoalSource},
 };
 use smallvec::SmallVec;
 use triomphe::Arc;
 
 use super::{InferResult, InferenceContext, TypeError};
-use crate::next_solver::ErrorGuaranteed;
 use crate::{
     AliasTy, BoundVar, Canonical, Const, ConstValue, DebruijnIndex, GenericArg, GenericArgData,
-    Goal, GoalData, InEnvironment, InferenceVar, Interner, Lifetime, OpaqueTyId, ParamKind,
-    ProjectionTy, Scalar, Substitution, TraitEnvironment, TraitRef, Ty, TyBuilder, TyExt, TyKind,
-    VariableKind, WhereClause,
+    InferenceVar, Interner, Lifetime, OpaqueTyId, ProjectionTy, Substitution, TraitEnvironment, Ty,
+    TyExt, TyKind, VariableKind,
     consteval::unknown_const,
     db::HirDatabase,
     fold_generic_args, fold_tys_and_consts,
-    next_solver::infer::InferOk,
     next_solver::{
-        self, ClauseKind, DbInterner, ParamEnv, Predicate, PredicateKind, SolverDefIds, Term,
+        self, ClauseKind, DbInterner, ErrorGuaranteed, Predicate, PredicateKind, SolverDefIds,
+        Term, TraitRef,
         fulfill::FulfillmentCtxt,
         infer::{
-            DbInternerInferExt, InferCtxt,
+            DbInternerInferExt, InferCtxt, InferOk,
             snapshot::CombinedSnapshot,
             traits::{Obligation, ObligationCause},
         },
         inspect::{InspectConfig, InspectGoal, ProofTreeVisitor},
         mapping::{ChalkToNextSolver, NextSolverToChalk},
     },
-    to_chalk_trait_id,
     traits::{
         FnTrait, NextTraitSolveResult, next_trait_solve_canonical_in_ctxt, next_trait_solve_in_ctxt,
     },
@@ -125,7 +120,7 @@ impl<'a, 'db> ProofTreeVisitor<'db> for NestedObligationsForSelfTy<'a, 'db> {
 /// unresolved goal `T = U`.
 pub fn could_unify(
     db: &dyn HirDatabase,
-    env: Arc<TraitEnvironment>,
+    env: Arc<TraitEnvironment<'_>>,
     tys: &Canonical<(Ty, Ty)>,
 ) -> bool {
     unify(db, env, tys).is_some()
@@ -137,7 +132,7 @@ pub fn could_unify(
 /// them. For example `Option<T>` and `Option<U>` do not unify as we cannot show that `T = U`
 pub fn could_unify_deeply(
     db: &dyn HirDatabase,
-    env: Arc<TraitEnvironment>,
+    env: Arc<TraitEnvironment<'_>>,
     tys: &Canonical<(Ty, Ty)>,
 ) -> bool {
     let mut table = InferenceTable::new(db, env);
@@ -147,7 +142,6 @@ pub fn could_unify_deeply(
     let ty1_with_vars = table.normalize_associated_types_in(ty1_with_vars);
     let ty2_with_vars = table.normalize_associated_types_in(ty2_with_vars);
     table.select_obligations_where_possible();
-    table.propagate_diverging_flag();
     let ty1_with_vars = table.resolve_completely(ty1_with_vars);
     let ty2_with_vars = table.resolve_completely(ty2_with_vars);
     table.unify_deeply(&ty1_with_vars, &ty2_with_vars)
@@ -155,7 +149,7 @@ pub fn could_unify_deeply(
 
 pub(crate) fn unify(
     db: &dyn HirDatabase,
-    env: Arc<TraitEnvironment>,
+    env: Arc<TraitEnvironment<'_>>,
     tys: &Canonical<(Ty, Ty)>,
 ) -> Option<Substitution> {
     let mut table = InferenceTable::new(db, env);
@@ -174,13 +168,19 @@ pub(crate) fn unify(
             GenericArgData::Const(c) => c.inference_var(Interner),
         } == Some(iv))
     };
-    let fallback = |iv, kind, default, binder| match kind {
-        chalk_ir::VariableKind::Ty(_ty_kind) => find_var(iv)
-            .map_or(default, |i| BoundVar::new(binder, i).to_ty(Interner).cast(Interner)),
-        chalk_ir::VariableKind::Lifetime => find_var(iv)
-            .map_or(default, |i| BoundVar::new(binder, i).to_lifetime(Interner).cast(Interner)),
-        chalk_ir::VariableKind::Const(ty) => find_var(iv)
-            .map_or(default, |i| BoundVar::new(binder, i).to_const(Interner, ty).cast(Interner)),
+    let fallback = |iv, kind, binder| match kind {
+        chalk_ir::VariableKind::Ty(_ty_kind) => find_var(iv).map_or_else(
+            || TyKind::Error.intern(Interner).cast(Interner),
+            |i| BoundVar::new(binder, i).to_ty(Interner).cast(Interner),
+        ),
+        chalk_ir::VariableKind::Lifetime => find_var(iv).map_or_else(
+            || crate::error_lifetime().cast(Interner),
+            |i| BoundVar::new(binder, i).to_lifetime(Interner).cast(Interner),
+        ),
+        chalk_ir::VariableKind::Const(ty) => find_var(iv).map_or_else(
+            || crate::unknown_const(ty.clone()).cast(Interner),
+            |i| BoundVar::new(binder, i).to_const(Interner, ty.clone()).cast(Interner),
+        ),
     };
     Some(Substitution::from_iter(
         Interner,
@@ -216,22 +216,20 @@ bitflags::bitflags! {
 pub(crate) struct InferenceTable<'db> {
     pub(crate) db: &'db dyn HirDatabase,
     pub(crate) interner: DbInterner<'db>,
-    pub(crate) trait_env: Arc<TraitEnvironment>,
-    pub(crate) param_env: ParamEnv<'db>,
+    pub(crate) trait_env: Arc<TraitEnvironment<'db>>,
     pub(crate) tait_coercion_table: Option<FxHashMap<OpaqueTyId, Ty>>,
     pub(crate) infer_ctxt: InferCtxt<'db>,
-    diverging_tys: FxHashSet<Ty>,
     pub(super) fulfillment_cx: FulfillmentCtxt<'db>,
+    pub(super) diverging_type_vars: FxHashSet<crate::next_solver::Ty<'db>>,
 }
 
 pub(crate) struct InferenceTableSnapshot<'db> {
     ctxt_snapshot: CombinedSnapshot,
     obligations: FulfillmentCtxt<'db>,
-    diverging_tys: FxHashSet<Ty>,
 }
 
 impl<'db> InferenceTable<'db> {
-    pub(crate) fn new(db: &'db dyn HirDatabase, trait_env: Arc<TraitEnvironment>) -> Self {
+    pub(crate) fn new(db: &'db dyn HirDatabase, trait_env: Arc<TraitEnvironment<'db>>) -> Self {
         let interner = DbInterner::new_with(db, Some(trait_env.krate), trait_env.block);
         let infer_ctxt = interner.infer_ctxt().build(rustc_type_ir::TypingMode::Analysis {
             defining_opaque_types_and_generators: SolverDefIds::new_from_iter(interner, []),
@@ -239,12 +237,11 @@ impl<'db> InferenceTable<'db> {
         InferenceTable {
             db,
             interner,
-            param_env: trait_env.env.to_nextsolver(interner),
             trait_env,
             tait_coercion_table: None,
             fulfillment_cx: FulfillmentCtxt::new(&infer_ctxt),
             infer_ctxt,
-            diverging_tys: FxHashSet::default(),
+            diverging_type_vars: FxHashSet::default(),
         }
     }
 
@@ -327,74 +324,8 @@ impl<'db> InferenceTable<'db> {
         }
     }
 
-    /// Chalk doesn't know about the `diverging` flag, so when it unifies two
-    /// type variables of which one is diverging, the chosen root might not be
-    /// diverging and we have no way of marking it as such at that time. This
-    /// function goes through all type variables and make sure their root is
-    /// marked as diverging if necessary, so that resolving them gives the right
-    /// result.
-    pub(super) fn propagate_diverging_flag(&mut self) {
-        let mut new_tys = FxHashSet::default();
-        for ty in self.diverging_tys.iter() {
-            match ty.kind(Interner) {
-                TyKind::InferenceVar(var, kind) => match kind {
-                    TyVariableKind::General => {
-                        let root = InferenceVar::from(
-                            self.infer_ctxt.root_var(TyVid::from_u32(var.index())).as_u32(),
-                        );
-                        if root.index() != var.index() {
-                            new_tys.insert(TyKind::InferenceVar(root, *kind).intern(Interner));
-                        }
-                    }
-                    TyVariableKind::Integer => {
-                        let root = InferenceVar::from(
-                            self.infer_ctxt
-                                .inner
-                                .borrow_mut()
-                                .int_unification_table()
-                                .find(IntVid::from_usize(var.index() as usize))
-                                .as_u32(),
-                        );
-                        if root.index() != var.index() {
-                            new_tys.insert(TyKind::InferenceVar(root, *kind).intern(Interner));
-                        }
-                    }
-                    TyVariableKind::Float => {
-                        let root = InferenceVar::from(
-                            self.infer_ctxt
-                                .inner
-                                .borrow_mut()
-                                .float_unification_table()
-                                .find(FloatVid::from_usize(var.index() as usize))
-                                .as_u32(),
-                        );
-                        if root.index() != var.index() {
-                            new_tys.insert(TyKind::InferenceVar(root, *kind).intern(Interner));
-                        }
-                    }
-                },
-                _ => {}
-            }
-        }
-        self.diverging_tys.extend(new_tys);
-    }
-
-    pub(super) fn set_diverging(&mut self, iv: InferenceVar, kind: TyVariableKind) {
-        self.diverging_tys.insert(TyKind::InferenceVar(iv, kind).intern(Interner));
-    }
-
-    fn fallback_value(&self, iv: InferenceVar, kind: TyVariableKind) -> Ty {
-        let is_diverging =
-            self.diverging_tys.contains(&TyKind::InferenceVar(iv, kind).intern(Interner));
-        if is_diverging {
-            return TyKind::Never.intern(Interner);
-        }
-        match kind {
-            TyVariableKind::General => TyKind::Error,
-            TyVariableKind::Integer => TyKind::Scalar(Scalar::Int(IntTy::I32)),
-            TyVariableKind::Float => TyKind::Scalar(Scalar::Float(FloatTy::F64)),
-        }
-        .intern(Interner)
+    pub(super) fn set_diverging(&mut self, ty: crate::next_solver::Ty<'db>) {
+        self.diverging_type_vars.insert(ty);
     }
 
     pub(crate) fn canonicalize<T>(&mut self, t: T) -> rustc_type_ir::Canonical<DbInterner<'db>, T>
@@ -430,7 +361,7 @@ impl<'db> InferenceTable<'db> {
     {
         let ty = self.resolve_vars_with_obligations(ty);
         self.infer_ctxt
-            .at(&ObligationCause::new(), self.param_env)
+            .at(&ObligationCause::new(), self.trait_env.env)
             .deeply_normalize(ty.clone())
             .unwrap_or(ty)
     }
@@ -535,7 +466,7 @@ impl<'db> InferenceTable<'db> {
 
         let ty = var.to_ty(Interner, kind);
         if diverging {
-            self.diverging_tys.insert(ty.clone());
+            self.diverging_type_vars.insert(ty.to_nextsolver(self.interner));
         }
         ty
     }
@@ -579,7 +510,7 @@ impl<'db> InferenceTable<'db> {
     pub(crate) fn resolve_with_fallback<T>(
         &mut self,
         t: T,
-        fallback: &dyn Fn(InferenceVar, VariableKind, GenericArg, DebruijnIndex) -> GenericArg,
+        fallback: &dyn Fn(InferenceVar, VariableKind, DebruijnIndex) -> GenericArg,
     ) -> T
     where
         T: HasInterner<Interner = Interner> + TypeFoldable<Interner>,
@@ -621,7 +552,7 @@ impl<'db> InferenceTable<'db> {
     fn resolve_with_fallback_inner<T>(
         &mut self,
         t: T,
-        fallback: &dyn Fn(InferenceVar, VariableKind, GenericArg, DebruijnIndex) -> GenericArg,
+        fallback: &dyn Fn(InferenceVar, VariableKind, DebruijnIndex) -> GenericArg,
     ) -> T
     where
         T: HasInterner<Interner = Interner> + TypeFoldable<Interner>,
@@ -638,53 +569,15 @@ impl<'db> InferenceTable<'db> {
         T: HasInterner<Interner = Interner> + TypeFoldable<Interner> + ChalkToNextSolver<'db, U>,
         U: NextSolverToChalk<'db, T> + rustc_type_ir::TypeFoldable<DbInterner<'db>>,
     {
-        let t = self.resolve_with_fallback(t, &|_, _, d, _| d);
-        let t = self.normalize_associated_types_in(t);
-        // let t = self.resolve_opaque_tys_in(t);
-        // Resolve again, because maybe normalization inserted infer vars.
-        self.resolve_with_fallback(t, &|_, _, d, _| d)
-    }
+        let value = t.to_nextsolver(self.interner);
+        let value = self.infer_ctxt.resolve_vars_if_possible(value);
 
-    /// Apply a fallback to unresolved scalar types. Integer type variables and float type
-    /// variables are replaced with i32 and f64, respectively.
-    ///
-    /// This method is only intended to be called just before returning inference results (i.e. in
-    /// `InferenceContext::resolve_all()`).
-    ///
-    /// FIXME: This method currently doesn't apply fallback to unconstrained general type variables
-    /// whereas rustc replaces them with `()` or `!`.
-    pub(super) fn fallback_if_possible(&mut self) {
-        let int_fallback = TyKind::Scalar(Scalar::Int(IntTy::I32)).intern(Interner);
-        let float_fallback = TyKind::Scalar(Scalar::Float(FloatTy::F64)).intern(Interner);
-
-        let int_vars = self.infer_ctxt.inner.borrow_mut().int_unification_table().len();
-        for v in 0..int_vars {
-            let var = InferenceVar::from(v as u32).to_ty(Interner, TyVariableKind::Integer);
-            let maybe_resolved = self.resolve_ty_shallow(&var);
-            if let TyKind::InferenceVar(_, kind) = maybe_resolved.kind(Interner) {
-                // I don't think we can ever unify these vars with float vars, but keep this here for now
-                let fallback = match kind {
-                    TyVariableKind::Integer => &int_fallback,
-                    TyVariableKind::Float => &float_fallback,
-                    TyVariableKind::General => unreachable!(),
-                };
-                self.unify(&var, fallback);
-            }
-        }
-        let float_vars = self.infer_ctxt.inner.borrow_mut().float_unification_table().len();
-        for v in 0..float_vars {
-            let var = InferenceVar::from(v as u32).to_ty(Interner, TyVariableKind::Float);
-            let maybe_resolved = self.resolve_ty_shallow(&var);
-            if let TyKind::InferenceVar(_, kind) = maybe_resolved.kind(Interner) {
-                // I don't think we can ever unify these vars with float vars, but keep this here for now
-                let fallback = match kind {
-                    TyVariableKind::Integer => &int_fallback,
-                    TyVariableKind::Float => &float_fallback,
-                    TyVariableKind::General => unreachable!(),
-                };
-                self.unify(&var, fallback);
-            }
-        }
+        let mut goals = vec![];
+        let value = value.fold_with(&mut resolve_completely::Resolver::new(self, true, &mut goals));
+
+        // FIXME(next-solver): Handle `goals`.
+
+        value.to_chalk(self.interner)
     }
 
     /// Unify two relatable values (e.g. `Ty`) and register new trait goals that arise from that.
@@ -745,7 +638,7 @@ impl<'db> InferenceTable<'db> {
     ) -> InferResult<'db, ()> {
         let variance = rustc_type_ir::Variance::Invariant;
         let span = crate::next_solver::Span::dummy();
-        match self.infer_ctxt.relate(self.param_env, lhs, variance, rhs, span) {
+        match self.infer_ctxt.relate(self.trait_env.env, lhs, variance, rhs, span) {
             Ok(goals) => Ok(crate::infer::InferOk { goals, value: () }),
             Err(_) => Err(TypeError),
         }
@@ -786,7 +679,7 @@ impl<'db> InferenceTable<'db> {
     }
 
     pub(crate) fn structurally_resolve_type(&mut self, ty: &Ty) -> Ty {
-        if let TyKind::Alias(..) = ty.kind(Interner) {
+        if let TyKind::Alias(chalk_ir::AliasTy::Projection(..)) = ty.kind(Interner) {
             self.structurally_normalize_ty(ty)
         } else {
             self.resolve_vars_with_obligations(ty.to_nextsolver(self.interner))
@@ -802,7 +695,7 @@ impl<'db> InferenceTable<'db> {
 
     fn structurally_normalize_term(&mut self, term: Term<'db>) -> Term<'db> {
         self.infer_ctxt
-            .at(&ObligationCause::new(), self.param_env)
+            .at(&ObligationCause::new(), self.trait_env.env)
             .structurally_normalize_term(term, &mut self.fulfillment_cx)
             .unwrap_or(term)
     }
@@ -822,7 +715,7 @@ impl<'db> InferenceTable<'db> {
             // in a reentrant borrow, causing an ICE.
             let result = self
                 .infer_ctxt
-                .at(&ObligationCause::misc(), self.param_env)
+                .at(&ObligationCause::misc(), self.trait_env.env)
                 .structurally_normalize_ty(ty, &mut self.fulfillment_cx);
             match result {
                 Ok(normalized_ty) => normalized_ty,
@@ -835,15 +728,13 @@ impl<'db> InferenceTable<'db> {
 
     pub(crate) fn snapshot(&mut self) -> InferenceTableSnapshot<'db> {
         let ctxt_snapshot = self.infer_ctxt.start_snapshot();
-        let diverging_tys = self.diverging_tys.clone();
         let obligations = self.fulfillment_cx.clone();
-        InferenceTableSnapshot { ctxt_snapshot, diverging_tys, obligations }
+        InferenceTableSnapshot { ctxt_snapshot, obligations }
     }
 
     #[tracing::instrument(skip_all)]
     pub(crate) fn rollback_to(&mut self, snapshot: InferenceTableSnapshot<'db>) {
         self.infer_ctxt.rollback_to(snapshot.ctxt_snapshot);
-        self.diverging_tys = snapshot.diverging_tys;
         self.fulfillment_cx = snapshot.obligations;
     }
 
@@ -877,26 +768,15 @@ impl<'db> InferenceTable<'db> {
     /// whether a trait *might* be implemented before deciding to 'lock in' the
     /// choice (during e.g. method resolution or deref).
     #[tracing::instrument(level = "debug", skip(self))]
-    pub(crate) fn try_obligation(&mut self, goal: Goal) -> NextTraitSolveResult {
-        let in_env = InEnvironment::new(&self.trait_env.env, goal);
-        let canonicalized = self.canonicalize(in_env.to_nextsolver(self.interner));
+    pub(crate) fn try_obligation(&mut self, predicate: Predicate<'db>) -> NextTraitSolveResult {
+        let goal = next_solver::Goal { param_env: self.trait_env.env, predicate };
+        let canonicalized = self.canonicalize(goal);
 
         next_trait_solve_canonical_in_ctxt(&self.infer_ctxt, canonicalized)
     }
 
-    #[tracing::instrument(level = "debug", skip(self))]
-    pub(crate) fn solve_obligation(&mut self, goal: Goal) -> Result<Certainty, NoSolution> {
-        let goal = InEnvironment::new(&self.trait_env.env, goal);
-        let goal = goal.to_nextsolver(self.interner);
-        let result = next_trait_solve_in_ctxt(&self.infer_ctxt, goal);
-        result.map(|m| m.1)
-    }
-
     pub(crate) fn register_obligation(&mut self, predicate: Predicate<'db>) {
-        let goal = next_solver::Goal {
-            param_env: self.trait_env.env.to_nextsolver(self.interner),
-            predicate,
-        };
+        let goal = next_solver::Goal { param_env: self.trait_env.env, predicate };
         self.register_obligation_in_env(goal)
     }
 
@@ -984,7 +864,7 @@ impl<'db> InferenceTable<'db> {
         &mut self,
         ty: &Ty,
         num_args: usize,
-    ) -> Option<(FnTrait, Vec<crate::next_solver::Ty<'db>>, crate::next_solver::Ty<'db>)> {
+    ) -> Option<(FnTrait, Vec<next_solver::Ty<'db>>, next_solver::Ty<'db>)> {
         for (fn_trait_name, output_assoc_name, subtraits) in [
             (FnTrait::FnOnce, sym::Output, &[FnTrait::Fn, FnTrait::FnMut][..]),
             (FnTrait::AsyncFnMut, sym::CallRefFuture, &[FnTrait::AsyncFn]),
@@ -997,42 +877,34 @@ impl<'db> InferenceTable<'db> {
                 trait_data.associated_type_by_name(&Name::new_symbol_root(output_assoc_name))?;
 
             let mut arg_tys = Vec::with_capacity(num_args);
-            let arg_ty = TyBuilder::tuple(num_args)
-                .fill(|it| {
-                    let arg = match it {
-                        ParamKind::Type => self.new_type_var(),
-                        ParamKind::Lifetime => unreachable!("Tuple with lifetime parameter"),
-                        ParamKind::Const(_) => unreachable!("Tuple with const parameter"),
-                    };
-                    arg_tys.push(arg.to_nextsolver(self.interner));
-                    arg.cast(Interner)
+            let arg_ty = next_solver::Ty::new_tup_from_iter(
+                self.interner,
+                std::iter::repeat_with(|| {
+                    let ty = self.next_ty_var();
+                    arg_tys.push(ty);
+                    ty
                 })
-                .build();
-
-            let b = TyBuilder::trait_ref(self.db, fn_trait);
-            if b.remaining() != 2 {
-                return None;
-            }
-            let mut trait_ref = b.push(ty.clone()).push(arg_ty).build();
-
-            let projection = TyBuilder::assoc_type_projection(
-                self.db,
-                output_assoc_type,
-                Some(trait_ref.substitution.clone()),
-            )
-            .fill_with_unknown()
-            .build();
-
-            let goal: Goal = trait_ref.clone().cast(Interner);
-            if !self.try_obligation(goal.clone()).no_solution() {
-                self.register_obligation(goal.to_nextsolver(self.interner));
-                let return_ty =
-                    self.normalize_projection_ty(projection).to_nextsolver(self.interner);
+                .take(num_args),
+            );
+            let args = [ty.to_nextsolver(self.interner), arg_ty];
+            let trait_ref = crate::next_solver::TraitRef::new(self.interner, fn_trait.into(), args);
+
+            let projection = crate::next_solver::Ty::new_alias(
+                self.interner,
+                rustc_type_ir::AliasTyKind::Projection,
+                crate::next_solver::AliasTy::new(self.interner, output_assoc_type.into(), args),
+            );
+
+            let pred = crate::next_solver::Predicate::upcast_from(trait_ref, self.interner);
+            if !self.try_obligation(pred).no_solution() {
+                self.register_obligation(pred);
+                let return_ty = self.normalize_alias_ty(projection);
                 for &fn_x in subtraits {
                     let fn_x_trait = fn_x.get_id(self.db, krate)?;
-                    trait_ref.trait_id = to_chalk_trait_id(fn_x_trait);
-                    let goal = trait_ref.clone().cast(Interner);
-                    if !self.try_obligation(goal).no_solution() {
+                    let trait_ref =
+                        crate::next_solver::TraitRef::new(self.interner, fn_x_trait.into(), args);
+                    let pred = crate::next_solver::Predicate::upcast_from(trait_ref, self.interner);
+                    if !self.try_obligation(pred).no_solution() {
                         return Some((fn_x, arg_tys, return_ty));
                     }
                 }
@@ -1171,12 +1043,11 @@ impl<'db> InferenceTable<'db> {
         let Some(sized) = LangItem::Sized.resolve_trait(self.db, self.trait_env.krate) else {
             return false;
         };
-        let sized_pred = WhereClause::Implemented(TraitRef {
-            trait_id: to_chalk_trait_id(sized),
-            substitution: Substitution::from1(Interner, ty),
-        });
-        let goal = GoalData::DomainGoal(chalk_ir::DomainGoal::Holds(sized_pred)).intern(Interner);
-        self.try_obligation(goal).certain()
+        let sized_pred = Predicate::upcast_from(
+            TraitRef::new(self.interner, sized.into(), [ty.to_nextsolver(self.interner)]),
+            self.interner,
+        );
+        self.try_obligation(sized_pred).certain()
     }
 }
 
@@ -1192,14 +1063,10 @@ impl fmt::Debug for InferenceTable<'_> {
 mod resolve {
     use super::InferenceTable;
     use crate::{
-        ConcreteConst, Const, ConstData, ConstScalar, ConstValue, DebruijnIndex, GenericArg,
-        InferenceVar, Interner, Lifetime, Ty, TyVariableKind, VariableKind,
-        next_solver::mapping::NextSolverToChalk,
-    };
-    use chalk_ir::{
-        cast::Cast,
-        fold::{TypeFoldable, TypeFolder},
+        Const, DebruijnIndex, GenericArg, InferenceVar, Interner, Lifetime, Ty, TyVariableKind,
+        VariableKind, next_solver::mapping::NextSolverToChalk,
     };
+    use chalk_ir::fold::{TypeFoldable, TypeFolder};
     use rustc_type_ir::{FloatVid, IntVid, TyVid};
 
     #[derive(Debug, Copy, Clone, PartialEq, Eq)]
@@ -1213,7 +1080,7 @@ mod resolve {
     pub(super) struct Resolver<
         'a,
         'b,
-        F: Fn(InferenceVar, VariableKind, GenericArg, DebruijnIndex) -> GenericArg,
+        F: Fn(InferenceVar, VariableKind, DebruijnIndex) -> GenericArg,
     > {
         pub(super) table: &'a mut InferenceTable<'b>,
         pub(super) var_stack: &'a mut Vec<(InferenceVar, VarKind)>,
@@ -1221,7 +1088,7 @@ mod resolve {
     }
     impl<F> TypeFolder<Interner> for Resolver<'_, '_, F>
     where
-        F: Fn(InferenceVar, VariableKind, GenericArg, DebruijnIndex) -> GenericArg,
+        F: Fn(InferenceVar, VariableKind, DebruijnIndex) -> GenericArg,
     {
         fn as_dyn(&mut self) -> &mut dyn TypeFolder<Interner> {
             self
@@ -1243,8 +1110,7 @@ mod resolve {
                     let var = InferenceVar::from(vid.as_u32());
                     if self.var_stack.contains(&(var, VarKind::Ty(kind))) {
                         // recursive type
-                        let default = self.table.fallback_value(var, kind).cast(Interner);
-                        return (self.fallback)(var, VariableKind::Ty(kind), default, outer_binder)
+                        return (self.fallback)(var, VariableKind::Ty(kind), outer_binder)
                             .assert_ty_ref(Interner)
                             .clone();
                     }
@@ -1256,8 +1122,7 @@ mod resolve {
                         self.var_stack.pop();
                         result
                     } else {
-                        let default = self.table.fallback_value(var, kind).cast(Interner);
-                        (self.fallback)(var, VariableKind::Ty(kind), default, outer_binder)
+                        (self.fallback)(var, VariableKind::Ty(kind), outer_binder)
                             .assert_ty_ref(Interner)
                             .clone()
                     }
@@ -1273,8 +1138,7 @@ mod resolve {
                     let var = InferenceVar::from(vid.as_u32());
                     if self.var_stack.contains(&(var, VarKind::Ty(kind))) {
                         // recursive type
-                        let default = self.table.fallback_value(var, kind).cast(Interner);
-                        return (self.fallback)(var, VariableKind::Ty(kind), default, outer_binder)
+                        return (self.fallback)(var, VariableKind::Ty(kind), outer_binder)
                             .assert_ty_ref(Interner)
                             .clone();
                     }
@@ -1286,8 +1150,7 @@ mod resolve {
                         self.var_stack.pop();
                         result
                     } else {
-                        let default = self.table.fallback_value(var, kind).cast(Interner);
-                        (self.fallback)(var, VariableKind::Ty(kind), default, outer_binder)
+                        (self.fallback)(var, VariableKind::Ty(kind), outer_binder)
                             .assert_ty_ref(Interner)
                             .clone()
                     }
@@ -1303,8 +1166,7 @@ mod resolve {
                     let var = InferenceVar::from(vid.as_u32());
                     if self.var_stack.contains(&(var, VarKind::Ty(kind))) {
                         // recursive type
-                        let default = self.table.fallback_value(var, kind).cast(Interner);
-                        return (self.fallback)(var, VariableKind::Ty(kind), default, outer_binder)
+                        return (self.fallback)(var, VariableKind::Ty(kind), outer_binder)
                             .assert_ty_ref(Interner)
                             .clone();
                     }
@@ -1316,8 +1178,7 @@ mod resolve {
                         self.var_stack.pop();
                         result
                     } else {
-                        let default = self.table.fallback_value(var, kind).cast(Interner);
-                        (self.fallback)(var, VariableKind::Ty(kind), default, outer_binder)
+                        (self.fallback)(var, VariableKind::Ty(kind), outer_binder)
                             .assert_ty_ref(Interner)
                             .clone()
                     }
@@ -1336,15 +1197,9 @@ mod resolve {
                 .infer_ctxt
                 .root_const_var(rustc_type_ir::ConstVid::from_u32(var.index()));
             let var = InferenceVar::from(vid.as_u32());
-            let default = ConstData {
-                ty: ty.clone(),
-                value: ConstValue::Concrete(ConcreteConst { interned: ConstScalar::Unknown }),
-            }
-            .intern(Interner)
-            .cast(Interner);
             if self.var_stack.contains(&(var, VarKind::Const)) {
                 // recursive
-                return (self.fallback)(var, VariableKind::Const(ty), default, outer_binder)
+                return (self.fallback)(var, VariableKind::Const(ty), outer_binder)
                     .assert_const_ref(Interner)
                     .clone();
             }
@@ -1356,7 +1211,7 @@ mod resolve {
                 self.var_stack.pop();
                 result
             } else {
-                (self.fallback)(var, VariableKind::Const(ty), default, outer_binder)
+                (self.fallback)(var, VariableKind::Const(ty), outer_binder)
                     .assert_const_ref(Interner)
                     .clone()
             }
@@ -1375,3 +1230,124 @@ mod resolve {
         }
     }
 }
+
+mod resolve_completely {
+    use rustc_type_ir::{
+        DebruijnIndex, Flags, TypeFolder, TypeSuperFoldable,
+        inherent::{Const as _, Ty as _},
+    };
+
+    use crate::next_solver::Region;
+    use crate::{
+        infer::unify::InferenceTable,
+        next_solver::{
+            Const, DbInterner, ErrorGuaranteed, Goal, Predicate, Term, Ty,
+            infer::traits::ObligationCause,
+            normalize::deeply_normalize_with_skipped_universes_and_ambiguous_coroutine_goals,
+        },
+    };
+
+    pub(super) struct Resolver<'a, 'db> {
+        ctx: &'a mut InferenceTable<'db>,
+        /// Whether we should normalize, disabled when resolving predicates.
+        should_normalize: bool,
+        nested_goals: &'a mut Vec<Goal<'db, Predicate<'db>>>,
+    }
+
+    impl<'a, 'db> Resolver<'a, 'db> {
+        pub(super) fn new(
+            ctx: &'a mut InferenceTable<'db>,
+            should_normalize: bool,
+            nested_goals: &'a mut Vec<Goal<'db, Predicate<'db>>>,
+        ) -> Resolver<'a, 'db> {
+            Resolver { ctx, nested_goals, should_normalize }
+        }
+
+        fn handle_term<T>(
+            &mut self,
+            value: T,
+            outer_exclusive_binder: impl FnOnce(T) -> DebruijnIndex,
+        ) -> T
+        where
+            T: Into<Term<'db>> + TypeSuperFoldable<DbInterner<'db>> + Copy,
+        {
+            let value = if self.should_normalize {
+                let cause = ObligationCause::new();
+                let at = self.ctx.infer_ctxt.at(&cause, self.ctx.trait_env.env);
+                let universes = vec![None; outer_exclusive_binder(value).as_usize()];
+                match deeply_normalize_with_skipped_universes_and_ambiguous_coroutine_goals(
+                    at, value, universes,
+                ) {
+                    Ok((value, goals)) => {
+                        self.nested_goals.extend(goals);
+                        value
+                    }
+                    Err(_errors) => {
+                        // FIXME: Report the error.
+                        value
+                    }
+                }
+            } else {
+                value
+            };
+
+            value.fold_with(&mut ReplaceInferWithError { interner: self.ctx.interner })
+        }
+    }
+
+    impl<'cx, 'db> TypeFolder<DbInterner<'db>> for Resolver<'cx, 'db> {
+        fn cx(&self) -> DbInterner<'db> {
+            self.ctx.interner
+        }
+
+        fn fold_region(&mut self, r: Region<'db>) -> Region<'db> {
+            if r.is_var() { Region::error(self.ctx.interner) } else { r }
+        }
+
+        fn fold_ty(&mut self, ty: Ty<'db>) -> Ty<'db> {
+            self.handle_term(ty, |it| it.outer_exclusive_binder())
+        }
+
+        fn fold_const(&mut self, ct: Const<'db>) -> Const<'db> {
+            self.handle_term(ct, |it| it.outer_exclusive_binder())
+        }
+
+        fn fold_predicate(&mut self, predicate: Predicate<'db>) -> Predicate<'db> {
+            assert!(
+                !self.should_normalize,
+                "normalizing predicates in writeback is not generally sound"
+            );
+            predicate.super_fold_with(self)
+        }
+    }
+
+    struct ReplaceInferWithError<'db> {
+        interner: DbInterner<'db>,
+    }
+
+    impl<'db> TypeFolder<DbInterner<'db>> for ReplaceInferWithError<'db> {
+        fn cx(&self) -> DbInterner<'db> {
+            self.interner
+        }
+
+        fn fold_ty(&mut self, t: Ty<'db>) -> Ty<'db> {
+            if t.is_infer() {
+                Ty::new_error(self.interner, ErrorGuaranteed)
+            } else {
+                t.super_fold_with(self)
+            }
+        }
+
+        fn fold_const(&mut self, c: Const<'db>) -> Const<'db> {
+            if c.is_ct_infer() {
+                Const::new_error(self.interner, ErrorGuaranteed)
+            } else {
+                c.super_fold_with(self)
+            }
+        }
+
+        fn fold_region(&mut self, r: Region<'db>) -> Region<'db> {
+            if r.is_var() { Region::error(self.interner) } else { r }
+        }
+    }
+}
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/inhabitedness.rs b/src/tools/rust-analyzer/crates/hir-ty/src/inhabitedness.rs
index b16b6a11784..bdebe41b299 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/inhabitedness.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/inhabitedness.rs
@@ -20,7 +20,7 @@ pub(crate) fn is_ty_uninhabited_from(
     db: &dyn HirDatabase,
     ty: &Ty,
     target_mod: ModuleId,
-    env: Arc<TraitEnvironment>,
+    env: Arc<TraitEnvironment<'_>>,
 ) -> bool {
     let _p = tracing::info_span!("is_ty_uninhabited_from", ?ty).entered();
     let mut uninhabited_from =
@@ -36,7 +36,7 @@ pub(crate) fn is_enum_variant_uninhabited_from(
     variant: EnumVariantId,
     subst: &Substitution,
     target_mod: ModuleId,
-    env: Arc<TraitEnvironment>,
+    env: Arc<TraitEnvironment<'_>>,
 ) -> bool {
     let _p = tracing::info_span!("is_enum_variant_uninhabited_from").entered();
 
@@ -52,7 +52,7 @@ struct UninhabitedFrom<'a> {
     // guard for preventing stack overflow in non trivial non terminating types
     max_depth: usize,
     db: &'a dyn HirDatabase,
-    env: Arc<TraitEnvironment>,
+    env: Arc<TraitEnvironment<'a>>,
 }
 
 const CONTINUE_OPAQUELY_INHABITED: ControlFlow<VisiblyUninhabited> = Continue(());
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/layout.rs b/src/tools/rust-analyzer/crates/hir-ty/src/layout.rs
index f21673c732e..4071b9a1d5e 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/layout.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/layout.rs
@@ -132,7 +132,7 @@ fn layout_of_simd_ty<'db>(
     id: StructId,
     repr_packed: bool,
     args: &GenericArgs<'db>,
-    env: Arc<TraitEnvironment>,
+    env: Arc<TraitEnvironment<'db>>,
     dl: &TargetDataLayout,
 ) -> Result<Arc<Layout>, LayoutError> {
     // Supported SIMD vectors are homogeneous ADTs with exactly one array field:
@@ -160,7 +160,7 @@ fn layout_of_simd_ty<'db>(
 pub fn layout_of_ty_query<'db>(
     db: &'db dyn HirDatabase,
     ty: Ty<'db>,
-    trait_env: Arc<TraitEnvironment>,
+    trait_env: Arc<TraitEnvironment<'db>>,
 ) -> Result<Arc<Layout>, LayoutError> {
     let krate = trait_env.krate;
     let interner = DbInterner::new_with(db, Some(krate), trait_env.block);
@@ -371,7 +371,7 @@ pub fn layout_of_ty_query<'db>(
 pub(crate) fn layout_of_ty_cycle_result<'db>(
     _: &dyn HirDatabase,
     _: Ty<'db>,
-    _: Arc<TraitEnvironment>,
+    _: Arc<TraitEnvironment<'db>>,
 ) -> Result<Arc<Layout>, LayoutError> {
     Err(LayoutError::RecursiveTypeWithoutIndirection)
 }
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/layout/adt.rs b/src/tools/rust-analyzer/crates/hir-ty/src/layout/adt.rs
index 9a746ca8885..a8f04bf8c13 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/layout/adt.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/layout/adt.rs
@@ -23,7 +23,7 @@ pub fn layout_of_adt_query<'db>(
     db: &'db dyn HirDatabase,
     def: AdtId,
     args: GenericArgs<'db>,
-    trait_env: Arc<TraitEnvironment>,
+    trait_env: Arc<TraitEnvironment<'db>>,
 ) -> Result<Arc<Layout>, LayoutError> {
     let krate = trait_env.krate;
     let Ok(target) = db.target_data_layout(krate) else {
@@ -99,7 +99,7 @@ pub(crate) fn layout_of_adt_cycle_result<'db>(
     _: &'db dyn HirDatabase,
     _def: AdtId,
     _args: GenericArgs<'db>,
-    _trait_env: Arc<TraitEnvironment>,
+    _trait_env: Arc<TraitEnvironment<'db>>,
 ) -> Result<Arc<Layout>, LayoutError> {
     Err(LayoutError::RecursiveTypeWithoutIndirection)
 }
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/layout/tests.rs b/src/tools/rust-analyzer/crates/hir-ty/src/layout/tests.rs
index 523ddad9466..275ad841f4b 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/layout/tests.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/layout/tests.rs
@@ -1,18 +1,17 @@
 use base_db::target::TargetData;
-use chalk_ir::{AdtId, TyKind};
 use either::Either;
 use hir_def::db::DefDatabase;
 use project_model::{Sysroot, toolchain_info::QueryConfig};
 use rustc_hash::FxHashMap;
+use rustc_type_ir::inherent::{GenericArgs as _, Ty as _};
 use syntax::ToSmolStr;
 use test_fixture::WithFixture;
 use triomphe::Arc;
 
 use crate::{
-    Interner, Substitution,
     db::HirDatabase,
     layout::{Layout, LayoutError},
-    next_solver::{DbInterner, mapping::ChalkToNextSolver},
+    next_solver::{AdtDef, DbInterner, GenericArgs, mapping::ChalkToNextSolver},
     setup_tracing,
     test_db::TestDB,
 };
@@ -80,18 +79,18 @@ fn eval_goal(
             Some(adt_or_type_alias_id)
         })
         .unwrap();
-    let goal_ty = match adt_or_type_alias_id {
-        Either::Left(adt_id) => {
-            TyKind::Adt(AdtId(adt_id), Substitution::empty(Interner)).intern(Interner)
-        }
-        Either::Right(ty_id) => {
-            db.ty(ty_id.into()).substitute(Interner, &Substitution::empty(Interner))
-        }
-    };
     salsa::attach(&db, || {
         let interner = DbInterner::new_with(&db, None, None);
+        let goal_ty = match adt_or_type_alias_id {
+            Either::Left(adt_id) => crate::next_solver::Ty::new_adt(
+                interner,
+                AdtDef::new(adt_id, interner),
+                GenericArgs::identity_for_item(interner, adt_id.into()),
+            ),
+            Either::Right(ty_id) => db.ty(ty_id.into()).instantiate_identity(),
+        };
         db.layout_of_ty(
-            goal_ty.to_nextsolver(interner),
+            goal_ty,
             db.trait_environment(match adt_or_type_alias_id {
                 Either::Left(adt) => hir_def::GenericDefId::AdtId(adt),
                 Either::Right(ty) => hir_def::GenericDefId::TypeAliasId(ty),
@@ -150,7 +149,7 @@ fn check_size_and_align(
 ) {
     let l = eval_goal(ra_fixture, minicore).unwrap();
     assert_eq!(l.size.bytes(), size, "size mismatch");
-    assert_eq!(l.align.abi.bytes(), align, "align mismatch");
+    assert_eq!(l.align.bytes(), align, "align mismatch");
 }
 
 #[track_caller]
@@ -162,7 +161,7 @@ fn check_size_and_align_expr(
 ) {
     let l = eval_expr(ra_fixture, minicore).unwrap();
     assert_eq!(l.size.bytes(), size, "size mismatch");
-    assert_eq!(l.align.abi.bytes(), align, "align mismatch");
+    assert_eq!(l.align.bytes(), align, "align mismatch");
 }
 
 #[track_caller]
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/lib.rs b/src/tools/rust-analyzer/crates/hir-ty/src/lib.rs
index 2e59a488e67..281cf6b2d4b 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/lib.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/lib.rs
@@ -72,7 +72,10 @@ use intern::{Symbol, sym};
 use la_arena::{Arena, Idx};
 use mir::{MirEvalError, VTableMap};
 use rustc_hash::{FxBuildHasher, FxHashMap, FxHashSet};
-use rustc_type_ir::inherent::SliceLike;
+use rustc_type_ir::{
+    UpcastFrom,
+    inherent::{SliceLike, Ty as _},
+};
 use syntax::ast::{ConstArg, make};
 use traits::FnTrait;
 use triomphe::Arc;
@@ -85,7 +88,7 @@ use crate::{
     infer::unify::InferenceTable,
     next_solver::{
         DbInterner,
-        mapping::{ChalkToNextSolver, convert_ty_for_result},
+        mapping::{ChalkToNextSolver, NextSolverToChalk, convert_ty_for_result},
     },
 };
 
@@ -554,8 +557,10 @@ impl CallableSig {
 
     pub fn from_def(db: &dyn HirDatabase, def: FnDefId, substs: &Substitution) -> CallableSig {
         let callable_def = ToChalk::from_chalk(db, def);
+        let interner = DbInterner::new_with(db, None, None);
+        let args: crate::next_solver::GenericArgs<'_> = substs.to_nextsolver(interner);
         let sig = db.callable_item_signature(callable_def);
-        sig.substitute(Interner, substs)
+        sig.instantiate(interner, args).skip_binder().to_chalk(interner)
     }
     pub fn from_fn_ptr(fn_ptr: &FnPointer) -> CallableSig {
         CallableSig {
@@ -916,10 +921,10 @@ where
     Canonical { value, binders: chalk_ir::CanonicalVarKinds::from_iter(Interner, kinds) }
 }
 
-pub fn callable_sig_from_fn_trait(
+pub fn callable_sig_from_fn_trait<'db>(
     self_ty: &Ty,
-    trait_env: Arc<TraitEnvironment>,
-    db: &dyn HirDatabase,
+    trait_env: Arc<TraitEnvironment<'db>>,
+    db: &'db dyn HirDatabase,
 ) -> Option<(FnTrait, CallableSig)> {
     let krate = trait_env.krate;
     let fn_once_trait = FnTrait::FnOnce.get_id(db, krate)?;
@@ -936,26 +941,32 @@ pub fn callable_sig_from_fn_trait(
     // Register two obligations:
     // - Self: FnOnce<?args_ty>
     // - <Self as FnOnce<?args_ty>>::Output == ?ret_ty
-    let args_ty = table.new_type_var();
-    let mut trait_ref = b.push(self_ty.clone()).push(args_ty.clone()).build();
-    let projection = TyBuilder::assoc_type_projection(
-        db,
-        output_assoc_type,
-        Some(trait_ref.substitution.clone()),
-    )
-    .build();
-
-    let goal: Goal = trait_ref.clone().cast(Interner);
-    let pred = goal.to_nextsolver(table.interner);
-    if !table.try_obligation(goal).no_solution() {
+    let args_ty = table.next_ty_var();
+    let args = [self_ty.to_nextsolver(table.interner), args_ty];
+    let trait_ref = crate::next_solver::TraitRef::new(table.interner, fn_once_trait.into(), args);
+    let projection = crate::next_solver::Ty::new_alias(
+        table.interner,
+        rustc_type_ir::AliasTyKind::Projection,
+        crate::next_solver::AliasTy::new(table.interner, output_assoc_type.into(), args),
+    );
+
+    let pred = crate::next_solver::Predicate::upcast_from(trait_ref, table.interner);
+    if !table.try_obligation(pred).no_solution() {
         table.register_obligation(pred);
-        let return_ty = table.normalize_projection_ty(projection);
+        let return_ty = table.normalize_alias_ty(projection);
         for fn_x in [FnTrait::Fn, FnTrait::FnMut, FnTrait::FnOnce] {
             let fn_x_trait = fn_x.get_id(db, krate)?;
-            trait_ref.trait_id = to_chalk_trait_id(fn_x_trait);
-            if !table.try_obligation(trait_ref.clone().cast(Interner)).no_solution() {
-                let ret_ty = table.resolve_completely(return_ty);
-                let args_ty = table.resolve_completely(args_ty);
+            let trait_ref =
+                crate::next_solver::TraitRef::new(table.interner, fn_x_trait.into(), args);
+            if !table
+                .try_obligation(crate::next_solver::Predicate::upcast_from(
+                    trait_ref,
+                    table.interner,
+                ))
+                .no_solution()
+            {
+                let ret_ty = table.resolve_completely(return_ty.to_chalk(table.interner));
+                let args_ty = table.resolve_completely(args_ty.to_chalk(table.interner));
                 let params = args_ty
                     .as_tuple()?
                     .iter(Interner)
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/lower.rs b/src/tools/rust-analyzer/crates/hir-ty/src/lower.rs
index 4d5172fd4f2..0c197b27034 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/lower.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/lower.rs
@@ -24,19 +24,18 @@ use chalk_ir::{
 
 use either::Either;
 use hir_def::{
-    AdtId, AssocItemId, CallableDefId, ConstId, ConstParamId, DefWithBodyId, EnumId, EnumVariantId,
-    FunctionId, GenericDefId, GenericParamId, HasModule, ImplId, ItemContainerId, LocalFieldId,
-    Lookup, StaticId, StructId, TypeAliasId, TypeOrConstParamId, UnionId, VariantId,
+    AdtId, AssocItemId, ConstId, ConstParamId, EnumId, EnumVariantId, FunctionId, GenericDefId,
+    GenericParamId, ItemContainerId, LocalFieldId, Lookup, StaticId, StructId, TypeAliasId,
+    TypeOrConstParamId, UnionId, VariantId,
     builtin_type::BuiltinType,
     expr_store::{ExpressionStore, path::Path},
     hir::generics::{GenericParamDataRef, TypeOrConstParamData, WherePredicate},
-    item_tree::FieldsShape,
     lang_item::LangItem,
     resolver::{HasResolver, LifetimeNs, Resolver, TypeNs},
-    signatures::{FunctionSignature, TraitFlags, TypeAliasFlags},
+    signatures::{FunctionSignature, TraitFlags},
     type_ref::{
-        ConstRef, LifetimeRefId, LiteralConstRef, PathId, TraitBoundModifier,
-        TraitRef as HirTraitRef, TypeBound, TypeRef, TypeRefId,
+        ConstRef, LifetimeRefId, LiteralConstRef, PathId, TraitBoundModifier, TypeBound, TypeRef,
+        TypeRefId,
     },
 };
 use hir_expand::name::Name;
@@ -46,11 +45,10 @@ use stdx::{impl_from, never};
 use triomphe::{Arc, ThinArc};
 
 use crate::{
-    AliasTy, Binders, BoundVar, CallableSig, Const, DebruijnIndex, DomainGoal, DynTy, FnAbi,
-    FnPointer, FnSig, FnSubst, ImplTrait, ImplTraitId, ImplTraits, Interner, Lifetime,
-    LifetimeData, LifetimeOutlives, PolyFnSig, QuantifiedWhereClause, QuantifiedWhereClauses,
-    Substitution, TraitEnvironment, TraitRef, TraitRefExt, Ty, TyBuilder, TyKind, WhereClause,
-    all_super_traits,
+    AliasTy, Binders, BoundVar, Const, DebruijnIndex, DynTy, FnAbi, FnPointer, FnSig, FnSubst,
+    ImplTrait, ImplTraitId, ImplTraits, Interner, Lifetime, LifetimeData, LifetimeOutlives,
+    QuantifiedWhereClause, QuantifiedWhereClauses, Substitution, TraitRef, TraitRefExt, Ty,
+    TyBuilder, TyKind, WhereClause, all_super_traits,
     consteval::{intern_const_ref, path_to_const, unknown_const, unknown_const_as_generic},
     db::HirDatabase,
     error_lifetime,
@@ -60,7 +58,11 @@ use crate::{
         path::{PathDiagnosticCallback, PathLoweringContext},
     },
     make_binders,
-    mapping::{ToChalk, from_chalk_trait_id, lt_to_placeholder_idx},
+    mapping::{from_chalk_trait_id, lt_to_placeholder_idx},
+    next_solver::{
+        DbInterner,
+        mapping::{ChalkToNextSolver, NextSolverToChalk},
+    },
     static_lifetime, to_chalk_trait_id, to_placeholder_idx,
     utils::all_super_trait_refs,
     variable_kinds_from_iter,
@@ -567,14 +569,6 @@ impl<'a> TyLoweringContext<'a> {
         Some((ctx.lower_trait_ref_from_resolved_path(resolved, explicit_self_ty, false), ctx))
     }
 
-    fn lower_trait_ref(
-        &mut self,
-        trait_ref: &HirTraitRef,
-        explicit_self_ty: Ty,
-    ) -> Option<TraitRef> {
-        self.lower_trait_ref_from_path(trait_ref.path, explicit_self_ty).map(|it| it.0)
-    }
-
     /// When lowering predicates from parents (impl, traits) for children defs (fns, consts, types), `generics` should
     /// contain the `Generics` for the **child**, while `predicate_owner` should contain the `GenericDefId` of the
     /// **parent**. This is important so we generate the correct bound var/placeholder.
@@ -826,15 +820,6 @@ impl<'a> TyLoweringContext<'a> {
     }
 }
 
-/// Build the signature of a callable item (function, struct or enum variant).
-pub(crate) fn callable_item_signature_query(db: &dyn HirDatabase, def: CallableDefId) -> PolyFnSig {
-    match def {
-        CallableDefId::FunctionId(f) => fn_sig_for_fn(db, f),
-        CallableDefId::StructId(s) => fn_sig_for_struct_constructor(db, s),
-        CallableDefId::EnumVariantId(e) => fn_sig_for_enum_variant_constructor(db, e),
-    }
-}
-
 fn named_associated_type_shorthand_candidates<R>(
     db: &dyn HirDatabase,
     // If the type parameter is defined in an impl and we're in a method, there
@@ -862,21 +847,21 @@ fn named_associated_type_shorthand_candidates<R>(
         })
     };
 
+    let interner = DbInterner::new_with(db, None, None);
     match res {
         TypeNs::SelfType(impl_id) => {
-            // we're _in_ the impl -- the binders get added back later. Correct,
-            // but it would be nice to make this more explicit
-            let trait_ref = db.impl_trait(impl_id)?.into_value_and_skipped_binders().0;
+            let trait_ref = db.impl_trait(impl_id)?;
 
             let impl_id_as_generic_def: GenericDefId = impl_id.into();
             if impl_id_as_generic_def != def {
                 let subst = TyBuilder::subst_for_def(db, impl_id, None)
                     .fill_with_bound_vars(DebruijnIndex::INNERMOST, 0)
                     .build();
-                let trait_ref = subst.apply(trait_ref, Interner);
+                let args: crate::next_solver::GenericArgs<'_> = subst.to_nextsolver(interner);
+                let trait_ref = trait_ref.instantiate(interner, args).to_chalk(interner);
                 search(trait_ref)
             } else {
-                search(trait_ref)
+                search(trait_ref.skip_binder().to_chalk(interner))
             }
         }
         TypeNs::GenericParam(param_id) => {
@@ -919,7 +904,7 @@ pub(crate) fn field_types_query(
     db: &dyn HirDatabase,
     variant_id: VariantId,
 ) -> Arc<ArenaMap<LocalFieldId, Binders<Ty>>> {
-    db.field_types_with_diagnostics(variant_id).0
+    field_types_with_diagnostics_query(db, variant_id).0
 }
 
 /// Build the type of all specific fields of a struct or enum variant.
@@ -1086,102 +1071,6 @@ pub(crate) fn generic_predicates_for_param_cycle_result(
     GenericPredicates(None)
 }
 
-pub(crate) fn trait_environment_for_body_query(
-    db: &dyn HirDatabase,
-    def: DefWithBodyId,
-) -> Arc<TraitEnvironment> {
-    let Some(def) = def.as_generic_def_id(db) else {
-        let krate = def.module(db).krate();
-        return TraitEnvironment::empty(krate);
-    };
-    db.trait_environment(def)
-}
-
-pub(crate) fn trait_environment_query(
-    db: &dyn HirDatabase,
-    def: GenericDefId,
-) -> Arc<TraitEnvironment> {
-    let generics = generics(db, def);
-    if generics.has_no_predicates() && generics.is_empty() {
-        return TraitEnvironment::empty(def.krate(db));
-    }
-
-    let resolver = def.resolver(db);
-    let mut ctx = TyLoweringContext::new(
-        db,
-        &resolver,
-        generics.store(),
-        def,
-        LifetimeElisionKind::AnonymousReportError,
-    )
-    .with_type_param_mode(ParamLoweringMode::Placeholder);
-    let mut traits_in_scope = Vec::new();
-    let mut clauses = Vec::new();
-    for maybe_parent_generics in
-        std::iter::successors(Some(&generics), |generics| generics.parent_generics())
-    {
-        ctx.store = maybe_parent_generics.store();
-        for pred in maybe_parent_generics.where_predicates() {
-            for pred in ctx.lower_where_predicate(pred, false) {
-                if let WhereClause::Implemented(tr) = pred.skip_binders() {
-                    traits_in_scope
-                        .push((tr.self_type_parameter(Interner).clone(), tr.hir_trait_id()));
-                }
-                let program_clause: Binders<DomainGoal> =
-                    pred.map(|pred| pred.into_from_env_goal(Interner).cast(Interner));
-                clauses.push(program_clause);
-            }
-        }
-    }
-
-    if let Some(trait_id) = def.assoc_trait_container(db) {
-        // add `Self: Trait<T1, T2, ...>` to the environment in trait
-        // function default implementations (and speculative code
-        // inside consts or type aliases)
-        cov_mark::hit!(trait_self_implements_self);
-        let substs = TyBuilder::placeholder_subst(db, trait_id);
-        let trait_ref = TraitRef { trait_id: to_chalk_trait_id(trait_id), substitution: substs };
-        let pred = WhereClause::Implemented(trait_ref);
-        clauses.push(Binders::empty(
-            Interner,
-            pred.cast::<DomainGoal>(Interner).into_from_env_goal(Interner),
-        ));
-    }
-
-    let subst = generics.placeholder_subst(db);
-    if !subst.is_empty(Interner) {
-        let explicitly_unsized_tys = ctx.unsized_types;
-        if let Some(implicitly_sized_clauses) =
-            implicitly_sized_clauses(db, def, &explicitly_unsized_tys, &subst, &resolver)
-        {
-            clauses.extend(implicitly_sized_clauses.map(|pred| {
-                Binders::empty(
-                    Interner,
-                    pred.into_from_env_goal(Interner).cast::<DomainGoal>(Interner),
-                )
-            }));
-        };
-    }
-
-    let clauses = chalk_ir::ProgramClauses::from_iter(
-        Interner,
-        clauses.into_iter().map(|g| {
-            chalk_ir::ProgramClause::new(
-                Interner,
-                chalk_ir::ProgramClauseData(g.map(|g| chalk_ir::ProgramClauseImplication {
-                    consequence: g,
-                    conditions: chalk_ir::Goals::empty(Interner),
-                    constraints: chalk_ir::Constraints::empty(Interner),
-                    priority: chalk_ir::ClausePriority::High,
-                })),
-            )
-        }),
-    );
-    let env = chalk_ir::Environment { clauses };
-
-    TraitEnvironment::new(resolver.krate(), None, traits_in_scope.into_boxed_slice(), env)
-}
-
 #[derive(Debug, Clone, PartialEq, Eq, Hash)]
 pub struct GenericPredicates(Option<Arc<[Binders<QuantifiedWhereClause>]>>);
 
@@ -1410,208 +1299,6 @@ pub(crate) fn generic_defaults_with_diagnostics_cycle_result(
     (GenericDefaults(None), None)
 }
 
-fn fn_sig_for_fn(db: &dyn HirDatabase, def: FunctionId) -> PolyFnSig {
-    let data = db.function_signature(def);
-    let resolver = def.resolver(db);
-    let mut ctx_params = TyLoweringContext::new(
-        db,
-        &resolver,
-        &data.store,
-        def.into(),
-        LifetimeElisionKind::for_fn_params(&data),
-    )
-    .with_type_param_mode(ParamLoweringMode::Variable);
-    let params = data.params.iter().map(|&tr| ctx_params.lower_ty(tr));
-
-    let ret = match data.ret_type {
-        Some(ret_type) => {
-            let mut ctx_ret = TyLoweringContext::new(
-                db,
-                &resolver,
-                &data.store,
-                def.into(),
-                LifetimeElisionKind::for_fn_ret(),
-            )
-            .with_impl_trait_mode(ImplTraitLoweringMode::Opaque)
-            .with_type_param_mode(ParamLoweringMode::Variable);
-            ctx_ret.lower_ty(ret_type)
-        }
-        None => TyKind::Tuple(0, Substitution::empty(Interner)).intern(Interner),
-    };
-    let generics = generics(db, def.into());
-    let sig = CallableSig::from_params_and_return(
-        params,
-        ret,
-        data.is_varargs(),
-        if data.is_unsafe() { Safety::Unsafe } else { Safety::Safe },
-        data.abi.as_ref().map_or(FnAbi::Rust, FnAbi::from_symbol),
-    );
-    make_binders(db, &generics, sig)
-}
-
-/// Build the declared type of a function. This should not need to look at the
-/// function body.
-fn type_for_fn(db: &dyn HirDatabase, def: FunctionId) -> Binders<Ty> {
-    let generics = generics(db, def.into());
-    let substs = generics.bound_vars_subst(db, DebruijnIndex::INNERMOST);
-    make_binders(
-        db,
-        &generics,
-        TyKind::FnDef(CallableDefId::FunctionId(def).to_chalk(db), substs).intern(Interner),
-    )
-}
-
-/// Build the declared type of a const.
-fn type_for_const(db: &dyn HirDatabase, def: ConstId) -> Binders<Ty> {
-    let data = db.const_signature(def);
-    let generics = generics(db, def.into());
-    let resolver = def.resolver(db);
-    let parent = def.loc(db).container;
-    let mut ctx = TyLoweringContext::new(
-        db,
-        &resolver,
-        &data.store,
-        def.into(),
-        LifetimeElisionKind::for_const(parent),
-    )
-    .with_type_param_mode(ParamLoweringMode::Variable);
-
-    make_binders(db, &generics, ctx.lower_ty(data.type_ref))
-}
-
-/// Build the declared type of a static.
-fn type_for_static(db: &dyn HirDatabase, def: StaticId) -> Binders<Ty> {
-    let data = db.static_signature(def);
-    let resolver = def.resolver(db);
-    let mut ctx = TyLoweringContext::new(
-        db,
-        &resolver,
-        &data.store,
-        def.into(),
-        LifetimeElisionKind::Elided(static_lifetime()),
-    );
-
-    Binders::empty(Interner, ctx.lower_ty(data.type_ref))
-}
-
-fn fn_sig_for_struct_constructor(db: &dyn HirDatabase, def: StructId) -> PolyFnSig {
-    let field_tys = db.field_types(def.into());
-    let params = field_tys.iter().map(|(_, ty)| ty.skip_binders().clone());
-    let (ret, binders) = type_for_adt(db, def.into()).into_value_and_skipped_binders();
-    Binders::new(
-        binders,
-        CallableSig::from_params_and_return(params, ret, false, Safety::Safe, FnAbi::RustCall),
-    )
-}
-
-/// Build the type of a tuple struct constructor.
-fn type_for_struct_constructor(db: &dyn HirDatabase, def: StructId) -> Option<Binders<Ty>> {
-    let struct_data = def.fields(db);
-    match struct_data.shape {
-        FieldsShape::Record => None,
-        FieldsShape::Unit => Some(type_for_adt(db, def.into())),
-        FieldsShape::Tuple => {
-            let generics = generics(db, AdtId::from(def).into());
-            let substs = generics.bound_vars_subst(db, DebruijnIndex::INNERMOST);
-            Some(make_binders(
-                db,
-                &generics,
-                TyKind::FnDef(CallableDefId::StructId(def).to_chalk(db), substs).intern(Interner),
-            ))
-        }
-    }
-}
-
-fn fn_sig_for_enum_variant_constructor(db: &dyn HirDatabase, def: EnumVariantId) -> PolyFnSig {
-    let field_tys = db.field_types(def.into());
-    let params = field_tys.iter().map(|(_, ty)| ty.skip_binders().clone());
-    let parent = def.lookup(db).parent;
-    let (ret, binders) = type_for_adt(db, parent.into()).into_value_and_skipped_binders();
-    Binders::new(
-        binders,
-        CallableSig::from_params_and_return(params, ret, false, Safety::Safe, FnAbi::RustCall),
-    )
-}
-
-/// Build the type of a tuple enum variant constructor.
-fn type_for_enum_variant_constructor(
-    db: &dyn HirDatabase,
-    def: EnumVariantId,
-) -> Option<Binders<Ty>> {
-    let e = def.lookup(db).parent;
-    match def.fields(db).shape {
-        FieldsShape::Record => None,
-        FieldsShape::Unit => Some(type_for_adt(db, e.into())),
-        FieldsShape::Tuple => {
-            let generics = generics(db, e.into());
-            let substs = generics.bound_vars_subst(db, DebruijnIndex::INNERMOST);
-            Some(make_binders(
-                db,
-                &generics,
-                TyKind::FnDef(CallableDefId::EnumVariantId(def).to_chalk(db), substs)
-                    .intern(Interner),
-            ))
-        }
-    }
-}
-
-#[salsa_macros::tracked(cycle_result = type_for_adt_cycle_result)]
-fn type_for_adt_tracked(db: &dyn HirDatabase, adt: AdtId) -> Binders<Ty> {
-    type_for_adt(db, adt)
-}
-
-fn type_for_adt_cycle_result(db: &dyn HirDatabase, adt: AdtId) -> Binders<Ty> {
-    let generics = generics(db, adt.into());
-    make_binders(db, &generics, TyKind::Error.intern(Interner))
-}
-
-fn type_for_adt(db: &dyn HirDatabase, adt: AdtId) -> Binders<Ty> {
-    let generics = generics(db, adt.into());
-    let subst = generics.bound_vars_subst(db, DebruijnIndex::INNERMOST);
-    let ty = TyKind::Adt(crate::AdtId(adt), subst).intern(Interner);
-    make_binders(db, &generics, ty)
-}
-
-pub(crate) fn type_for_type_alias_with_diagnostics_query(
-    db: &dyn HirDatabase,
-    t: TypeAliasId,
-) -> (Binders<Ty>, Diagnostics) {
-    let generics = generics(db, t.into());
-    let type_alias_data = db.type_alias_signature(t);
-    let mut diags = None;
-    let inner = if type_alias_data.flags.contains(TypeAliasFlags::IS_EXTERN) {
-        TyKind::Foreign(crate::to_foreign_def_id(t)).intern(Interner)
-    } else {
-        let resolver = t.resolver(db);
-        let alias = db.type_alias_signature(t);
-        let mut ctx = TyLoweringContext::new(
-            db,
-            &resolver,
-            &alias.store,
-            t.into(),
-            LifetimeElisionKind::AnonymousReportError,
-        )
-        .with_impl_trait_mode(ImplTraitLoweringMode::Opaque)
-        .with_type_param_mode(ParamLoweringMode::Variable);
-        let res = alias
-            .ty
-            .map(|type_ref| ctx.lower_ty(type_ref))
-            .unwrap_or_else(|| TyKind::Error.intern(Interner));
-        diags = create_diagnostics(ctx.diagnostics);
-        res
-    };
-
-    (make_binders(db, &generics, inner), diags)
-}
-
-pub(crate) fn type_for_type_alias_with_diagnostics_cycle_result(
-    db: &dyn HirDatabase,
-    adt: TypeAliasId,
-) -> (Binders<Ty>, Diagnostics) {
-    let generics = generics(db, adt.into());
-    (make_binders(db, &generics, TyKind::Error.intern(Interner)), None)
-}
-
 #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
 pub enum TyDefId {
     BuiltinType(BuiltinType),
@@ -1644,64 +1331,8 @@ impl ValueTyDefId {
     }
 }
 
-/// Build the declared type of an item. This depends on the namespace; e.g. for
-/// `struct Foo(usize)`, we have two types: The type of the struct itself, and
-/// the constructor function `(usize) -> Foo` which lives in the values
-/// namespace.
-pub(crate) fn ty_query(db: &dyn HirDatabase, def: TyDefId) -> Binders<Ty> {
-    match def {
-        TyDefId::BuiltinType(it) => Binders::empty(Interner, TyBuilder::builtin(it)),
-        TyDefId::AdtId(it) => type_for_adt_tracked(db, it),
-        TyDefId::TypeAliasId(it) => db.type_for_type_alias_with_diagnostics(it).0,
-    }
-}
-
-pub(crate) fn value_ty_query(db: &dyn HirDatabase, def: ValueTyDefId) -> Option<Binders<Ty>> {
-    match def {
-        ValueTyDefId::FunctionId(it) => Some(type_for_fn(db, it)),
-        ValueTyDefId::StructId(it) => type_for_struct_constructor(db, it),
-        ValueTyDefId::UnionId(it) => Some(type_for_adt(db, it.into())),
-        ValueTyDefId::EnumVariantId(it) => type_for_enum_variant_constructor(db, it),
-        ValueTyDefId::ConstId(it) => Some(type_for_const(db, it)),
-        ValueTyDefId::StaticId(it) => Some(type_for_static(db, it)),
-    }
-}
-
-pub(crate) fn impl_self_ty_query(db: &dyn HirDatabase, impl_id: ImplId) -> Binders<Ty> {
-    db.impl_self_ty_with_diagnostics(impl_id).0
-}
-
-pub(crate) fn impl_self_ty_with_diagnostics_query(
-    db: &dyn HirDatabase,
-    impl_id: ImplId,
-) -> (Binders<Ty>, Diagnostics) {
-    let impl_data = db.impl_signature(impl_id);
-    let resolver = impl_id.resolver(db);
-    let generics = generics(db, impl_id.into());
-    let mut ctx = TyLoweringContext::new(
-        db,
-        &resolver,
-        &impl_data.store,
-        impl_id.into(),
-        LifetimeElisionKind::AnonymousCreateParameter { report_in_path: true },
-    )
-    .with_type_param_mode(ParamLoweringMode::Variable);
-    (
-        make_binders(db, &generics, ctx.lower_ty(impl_data.self_ty)),
-        create_diagnostics(ctx.diagnostics),
-    )
-}
-
-pub(crate) fn impl_self_ty_with_diagnostics_cycle_result(
-    db: &dyn HirDatabase,
-    impl_id: ImplId,
-) -> (Binders<Ty>, Diagnostics) {
-    let generics = generics(db, impl_id.into());
-    (make_binders(db, &generics, TyKind::Error.intern(Interner)), None)
-}
-
 pub(crate) fn const_param_ty_query(db: &dyn HirDatabase, def: ConstParamId) -> Ty {
-    db.const_param_ty_with_diagnostics(def).0
+    const_param_ty_with_diagnostics_query(db, def).0
 }
 
 // returns None if def is a type arg
@@ -1729,36 +1360,12 @@ pub(crate) fn const_param_ty_with_diagnostics_query(
     (ty, create_diagnostics(ctx.diagnostics))
 }
 
-pub(crate) fn const_param_ty_with_diagnostics_cycle_result(
+pub(crate) fn const_param_ty_cycle_result(
     _: &dyn HirDatabase,
     _: crate::db::HirDatabaseData,
     _: ConstParamId,
-) -> (Ty, Diagnostics) {
-    (TyKind::Error.intern(Interner), None)
-}
-
-pub(crate) fn impl_trait_query(db: &dyn HirDatabase, impl_id: ImplId) -> Option<Binders<TraitRef>> {
-    db.impl_trait_with_diagnostics(impl_id).map(|it| it.0)
-}
-
-pub(crate) fn impl_trait_with_diagnostics_query(
-    db: &dyn HirDatabase,
-    impl_id: ImplId,
-) -> Option<(Binders<TraitRef>, Diagnostics)> {
-    let impl_data = db.impl_signature(impl_id);
-    let resolver = impl_id.resolver(db);
-    let mut ctx = TyLoweringContext::new(
-        db,
-        &resolver,
-        &impl_data.store,
-        impl_id.into(),
-        LifetimeElisionKind::AnonymousCreateParameter { report_in_path: true },
-    )
-    .with_type_param_mode(ParamLoweringMode::Variable);
-    let (self_ty, binders) = db.impl_self_ty(impl_id).into_value_and_skipped_binders();
-    let target_trait = impl_data.target_trait.as_ref()?;
-    let trait_ref = Binders::new(binders, ctx.lower_trait_ref(target_trait, self_ty)?);
-    Some((trait_ref, create_diagnostics(ctx.diagnostics)))
+) -> Ty {
+    TyKind::Error.intern(Interner)
 }
 
 pub(crate) fn return_type_impl_traits(
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/lower/path.rs b/src/tools/rust-analyzer/crates/hir-ty/src/lower/path.rs
index b0132e4dcbc..da9dd21183e 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/lower/path.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/lower/path.rs
@@ -28,6 +28,10 @@ use crate::{
     error_lifetime,
     generics::{Generics, generics},
     lower::{LifetimeElisionKind, named_associated_type_shorthand_candidates},
+    next_solver::{
+        DbInterner,
+        mapping::{ChalkToNextSolver, NextSolverToChalk},
+    },
     static_lifetime, to_assoc_type_id, to_chalk_trait_id, to_placeholder_idx,
     utils::associated_type_by_name_including_super_traits,
 };
@@ -251,12 +255,20 @@ impl<'a, 'b> PathLoweringContext<'a, 'b> {
                         // `def` can be either impl itself or item within, and we need impl itself
                         // now.
                         let generics = generics.parent_or_self();
+                        let interner = DbInterner::new_with(self.ctx.db, None, None);
                         let subst = generics.placeholder_subst(self.ctx.db);
-                        self.ctx.db.impl_self_ty(impl_id).substitute(Interner, &subst)
+                        let args: crate::next_solver::GenericArgs<'_> =
+                            subst.to_nextsolver(interner);
+                        self.ctx
+                            .db
+                            .impl_self_ty(impl_id)
+                            .instantiate(interner, args)
+                            .to_chalk(interner)
                     }
                     ParamLoweringMode::Variable => TyBuilder::impl_self_ty(self.ctx.db, impl_id)
                         .fill_with_bound_vars(self.ctx.in_binders, 0)
-                        .build(),
+                        .build(DbInterner::conjure())
+                        .to_chalk(DbInterner::conjure()),
                 }
             }
             TypeNs::AdtSelfType(adt) => {
@@ -267,7 +279,9 @@ impl<'a, 'b> PathLoweringContext<'a, 'b> {
                         generics.bound_vars_subst(self.ctx.db, self.ctx.in_binders)
                     }
                 };
-                self.ctx.db.ty(adt.into()).substitute(Interner, &substs)
+                let interner = DbInterner::conjure();
+                let args: crate::next_solver::GenericArgs<'_> = substs.to_nextsolver(interner);
+                self.ctx.db.ty(adt.into()).instantiate(interner, args).to_chalk(interner)
             }
 
             TypeNs::AdtId(it) => self.lower_path_inner(it.into(), infer_args),
@@ -537,7 +551,9 @@ impl<'a, 'b> PathLoweringContext<'a, 'b> {
             TyDefId::TypeAliasId(it) => it.into(),
         };
         let substs = self.substs_from_path_segment(generic_def, infer_args, None, false);
-        self.ctx.db.ty(typeable).substitute(Interner, &substs)
+        let interner = DbInterner::conjure();
+        let args: crate::next_solver::GenericArgs<'_> = substs.to_nextsolver(interner);
+        self.ctx.db.ty(typeable).instantiate(interner, args).to_chalk(interner)
     }
 
     /// Collect generic arguments from a path into a `Substs`. See also
@@ -603,7 +619,7 @@ impl<'a, 'b> PathLoweringContext<'a, 'b> {
         explicit_self_ty: Option<Ty>,
         lowering_assoc_type_generics: bool,
     ) -> Substitution {
-        let mut lifetime_elision = self.ctx.lifetime_elision.clone();
+        let old_lifetime_elision = self.ctx.lifetime_elision.clone();
 
         if let Some(args) = self.current_or_prev_segment.args_and_bindings
             && args.parenthesized != GenericArgsParentheses::No
@@ -633,19 +649,21 @@ impl<'a, 'b> PathLoweringContext<'a, 'b> {
             }
 
             // `Fn()`-style generics are treated like functions for the purpose of lifetime elision.
-            lifetime_elision =
+            self.ctx.lifetime_elision =
                 LifetimeElisionKind::AnonymousCreateParameter { report_in_path: false };
         }
 
-        self.substs_from_args_and_bindings(
+        let result = self.substs_from_args_and_bindings(
             self.current_or_prev_segment.args_and_bindings,
             def,
             infer_args,
             explicit_self_ty,
             PathGenericsSource::Segment(self.current_segment_u32()),
             lowering_assoc_type_generics,
-            lifetime_elision,
-        )
+            self.ctx.lifetime_elision.clone(),
+        );
+        self.ctx.lifetime_elision = old_lifetime_elision;
+        result
     }
 
     pub(super) fn substs_from_args_and_bindings(
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/lower_nextsolver.rs b/src/tools/rust-analyzer/crates/hir-ty/src/lower_nextsolver.rs
index 0076446a958..84cd216b812 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/lower_nextsolver.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/lower_nextsolver.rs
@@ -19,9 +19,9 @@ use base_db::Crate;
 use either::Either;
 use hir_def::item_tree::FieldsShape;
 use hir_def::{
-    AdtId, AssocItemId, CallableDefId, ConstParamId, EnumVariantId, FunctionId, GenericDefId,
-    GenericParamId, ImplId, ItemContainerId, LocalFieldId, Lookup, StructId, TraitId, TypeAliasId,
-    TypeOrConstParamId, VariantId,
+    AdtId, AssocItemId, CallableDefId, ConstParamId, DefWithBodyId, EnumVariantId, FunctionId,
+    GenericDefId, GenericParamId, HasModule, ImplId, ItemContainerId, LocalFieldId, Lookup,
+    StructId, TraitId, TypeAliasId, TypeOrConstParamId, VariantId,
     expr_store::{
         ExpressionStore,
         path::{GenericArg, Path},
@@ -57,7 +57,7 @@ use triomphe::Arc;
 
 use crate::ValueTyDefId;
 use crate::{
-    FnAbi, ImplTraitId, Interner, ParamKind, TyDefId, TyLoweringDiagnostic,
+    FnAbi, ImplTraitId, Interner, ParamKind, TraitEnvironment, TyDefId, TyLoweringDiagnostic,
     TyLoweringDiagnosticKind,
     consteval_nextsolver::{intern_const_ref, path_to_const, unknown_const_as_generic},
     db::HirDatabase,
@@ -66,8 +66,10 @@ use crate::{
     next_solver::{
         AdtDef, AliasTy, Binder, BoundExistentialPredicates, BoundRegionKind, BoundTyKind,
         BoundVarKind, BoundVarKinds, Clause, Clauses, Const, DbInterner, EarlyBinder,
-        EarlyParamRegion, ErrorGuaranteed, GenericArgs, PolyFnSig, Predicate, Region, SolverDefId,
-        TraitPredicate, TraitRef, Ty, Tys, abi::Safety, mapping::ChalkToNextSolver,
+        EarlyParamRegion, ErrorGuaranteed, GenericArgs, ParamEnv, PolyFnSig, Predicate, Region,
+        SolverDefId, TraitPredicate, TraitRef, Ty, Tys,
+        abi::Safety,
+        mapping::{ChalkToNextSolver, convert_ty_for_result},
     },
 };
 
@@ -902,7 +904,7 @@ pub(crate) fn impl_trait_query<'db>(
     db: &'db dyn HirDatabase,
     impl_id: ImplId,
 ) -> Option<EarlyBinder<'db, TraitRef<'db>>> {
-    db.impl_trait_with_diagnostics_ns(impl_id).map(|it| it.0)
+    db.impl_trait_with_diagnostics(impl_id).map(|it| it.0)
 }
 
 pub(crate) fn impl_trait_with_diagnostics_query<'db>(
@@ -918,7 +920,7 @@ pub(crate) fn impl_trait_with_diagnostics_query<'db>(
         impl_id.into(),
         LifetimeElisionKind::AnonymousCreateParameter { report_in_path: true },
     );
-    let self_ty = db.impl_self_ty_ns(impl_id).skip_binder();
+    let self_ty = db.impl_self_ty(impl_id).skip_binder();
     let target_trait = impl_data.target_trait.as_ref()?;
     let trait_ref = EarlyBinder::bind(ctx.lower_trait_ref(target_trait, self_ty)?);
     Some((trait_ref, create_diagnostics(ctx.diagnostics)))
@@ -984,7 +986,7 @@ pub(crate) fn ty_query<'db>(db: &'db dyn HirDatabase, def: TyDefId) -> EarlyBind
             AdtDef::new(it, interner),
             GenericArgs::identity_for_item(interner, it.into()),
         )),
-        TyDefId::TypeAliasId(it) => db.type_for_type_alias_with_diagnostics_ns(it).0,
+        TyDefId::TypeAliasId(it) => db.type_for_type_alias_with_diagnostics(it).0,
     }
 }
 
@@ -1129,7 +1131,7 @@ pub(crate) fn impl_self_ty_query<'db>(
     db: &'db dyn HirDatabase,
     impl_id: ImplId,
 ) -> EarlyBinder<'db, Ty<'db>> {
-    db.impl_self_ty_with_diagnostics_ns(impl_id).0
+    db.impl_self_ty_with_diagnostics(impl_id).0
 }
 
 pub(crate) fn impl_self_ty_with_diagnostics_query<'db>(
@@ -1160,7 +1162,7 @@ pub(crate) fn impl_self_ty_with_diagnostics_cycle_result(
 }
 
 pub(crate) fn const_param_ty_query<'db>(db: &'db dyn HirDatabase, def: ConstParamId) -> Ty<'db> {
-    db.const_param_ty_with_diagnostics_ns(def).0
+    db.const_param_ty_with_diagnostics(def).0
 }
 
 // returns None if def is a type arg
@@ -1189,11 +1191,21 @@ pub(crate) fn const_param_ty_with_diagnostics_query<'db>(
     (ty, create_diagnostics(ctx.diagnostics))
 }
 
+pub(crate) fn const_param_ty_with_diagnostics_cycle_result<'db>(
+    db: &'db dyn HirDatabase,
+    _: crate::db::HirDatabaseData,
+    def: ConstParamId,
+) -> (Ty<'db>, Diagnostics) {
+    let resolver = def.parent().resolver(db);
+    let interner = DbInterner::new_with(db, Some(resolver.krate()), None);
+    (Ty::new_error(interner, ErrorGuaranteed), None)
+}
+
 pub(crate) fn field_types_query<'db>(
     db: &'db dyn HirDatabase,
     variant_id: VariantId,
 ) -> Arc<ArenaMap<LocalFieldId, EarlyBinder<'db, Ty<'db>>>> {
-    db.field_types_with_diagnostics_ns(variant_id).0
+    db.field_types_with_diagnostics(variant_id).0
 }
 
 /// Build the type of all specific fields of a struct or enum variant.
@@ -1355,6 +1367,18 @@ pub(crate) fn generic_predicates_for_param_cycle_result(
 #[derive(Debug, Clone, PartialEq, Eq, Hash)]
 pub struct GenericPredicates<'db>(Option<Arc<[Clause<'db>]>>);
 
+impl<'db> GenericPredicates<'db> {
+    pub fn instantiate(
+        &self,
+        interner: DbInterner<'db>,
+        args: GenericArgs<'db>,
+    ) -> Option<impl Iterator<Item = Clause<'db>>> {
+        self.0
+            .as_ref()
+            .map(|it| EarlyBinder::bind(it.iter().copied()).iter_instantiated(interner, args))
+    }
+}
+
 impl<'db> ops::Deref for GenericPredicates<'db> {
     type Target = [Clause<'db>];
 
@@ -1363,6 +1387,122 @@ impl<'db> ops::Deref for GenericPredicates<'db> {
     }
 }
 
+pub(crate) fn trait_environment_for_body_query(
+    db: &dyn HirDatabase,
+    def: DefWithBodyId,
+) -> Arc<TraitEnvironment<'_>> {
+    let Some(def) = def.as_generic_def_id(db) else {
+        let krate = def.module(db).krate();
+        return TraitEnvironment::empty(krate);
+    };
+    db.trait_environment(def)
+}
+
+pub(crate) fn trait_environment_query<'db>(
+    db: &'db dyn HirDatabase,
+    def: GenericDefId,
+) -> Arc<TraitEnvironment<'db>> {
+    let generics = generics(db, def);
+    if generics.has_no_predicates() && generics.is_empty() {
+        return TraitEnvironment::empty(def.krate(db));
+    }
+
+    let interner = DbInterner::new_with(db, Some(def.krate(db)), None);
+    let resolver = def.resolver(db);
+    let mut ctx = TyLoweringContext::new(
+        db,
+        &resolver,
+        generics.store(),
+        def,
+        LifetimeElisionKind::AnonymousReportError,
+    );
+    let mut traits_in_scope = Vec::new();
+    let mut clauses = Vec::new();
+    for maybe_parent_generics in
+        std::iter::successors(Some(&generics), |generics| generics.parent_generics())
+    {
+        ctx.store = maybe_parent_generics.store();
+        for pred in maybe_parent_generics.where_predicates() {
+            for pred in ctx.lower_where_predicate(pred, false, &generics, PredicateFilter::All) {
+                if let rustc_type_ir::ClauseKind::Trait(tr) = pred.kind().skip_binder() {
+                    traits_in_scope
+                        .push((convert_ty_for_result(interner, tr.self_ty()), tr.def_id().0));
+                }
+                clauses.push(pred);
+            }
+        }
+    }
+
+    if let Some(trait_id) = def.assoc_trait_container(db) {
+        // add `Self: Trait<T1, T2, ...>` to the environment in trait
+        // function default implementations (and speculative code
+        // inside consts or type aliases)
+        cov_mark::hit!(trait_self_implements_self);
+        let trait_ref = TraitRef::identity(ctx.interner, trait_id.into());
+        let clause = Clause(Predicate::new(
+            ctx.interner,
+            Binder::dummy(rustc_type_ir::PredicateKind::Clause(rustc_type_ir::ClauseKind::Trait(
+                TraitPredicate { trait_ref, polarity: rustc_type_ir::PredicatePolarity::Positive },
+            ))),
+        ));
+        clauses.push(clause);
+    }
+
+    let explicitly_unsized_tys = ctx.unsized_types;
+
+    let sized_trait = LangItem::Sized.resolve_trait(db, resolver.krate());
+    if let Some(sized_trait) = sized_trait {
+        let (mut generics, mut def_id) =
+            (crate::next_solver::generics::generics(db, def.into()), def);
+        loop {
+            let self_idx = trait_self_param_idx(db, def_id);
+            for (idx, p) in generics.own_params.iter().enumerate() {
+                if let Some(self_idx) = self_idx
+                    && p.index() as usize == self_idx
+                {
+                    continue;
+                }
+                let GenericParamId::TypeParamId(param_id) = p.id else {
+                    continue;
+                };
+                let idx = idx as u32 + generics.parent_count as u32;
+                let param_ty = Ty::new_param(ctx.interner, param_id, idx, p.name.clone());
+                if explicitly_unsized_tys.contains(&param_ty) {
+                    continue;
+                }
+                let trait_ref = TraitRef::new_from_args(
+                    ctx.interner,
+                    sized_trait.into(),
+                    GenericArgs::new_from_iter(ctx.interner, [param_ty.into()]),
+                );
+                let clause = Clause(Predicate::new(
+                    ctx.interner,
+                    Binder::dummy(rustc_type_ir::PredicateKind::Clause(
+                        rustc_type_ir::ClauseKind::Trait(TraitPredicate {
+                            trait_ref,
+                            polarity: rustc_type_ir::PredicatePolarity::Positive,
+                        }),
+                    )),
+                ));
+                clauses.push(clause);
+            }
+
+            if let Some(g) = generics.parent {
+                generics = crate::next_solver::generics::generics(db, g.into());
+                def_id = g;
+            } else {
+                break;
+            }
+        }
+    }
+
+    let clauses = rustc_type_ir::elaborate::elaborate(ctx.interner, clauses);
+    let clauses = Clauses::new_from_iter(ctx.interner, clauses);
+    let env = ParamEnv { clauses };
+
+    TraitEnvironment::new(resolver.krate(), None, traits_in_scope.into_boxed_slice(), env)
+}
+
 #[derive(Copy, Clone, Debug)]
 pub(crate) enum PredicateFilter {
     SelfTrait,
@@ -1830,7 +1970,8 @@ fn named_associated_type_shorthand_candidates<'db, R>(
     let mut search = |t: TraitRef<'db>| -> Option<R> {
         let trait_id = t.def_id.0;
         let mut checked_traits = FxHashSet::default();
-        let mut check_trait = |trait_id: TraitId| {
+        let mut check_trait = |trait_ref: TraitRef<'db>| {
+            let trait_id = trait_ref.def_id.0;
             let name = &db.trait_signature(trait_id).name;
             tracing::debug!(?trait_id, ?name);
             if !checked_traits.insert(trait_id) {
@@ -1841,37 +1982,39 @@ fn named_associated_type_shorthand_candidates<'db, R>(
             tracing::debug!(?data.items);
             for (name, assoc_id) in &data.items {
                 if let &AssocItemId::TypeAliasId(alias) = assoc_id
-                    && let Some(ty) = check_alias(name, t, alias)
+                    && let Some(ty) = check_alias(name, trait_ref, alias)
                 {
                     return Some(ty);
                 }
             }
             None
         };
-        let mut stack: SmallVec<[_; 4]> = smallvec![trait_id];
-        while let Some(trait_def_id) = stack.pop() {
-            if let Some(alias) = check_trait(trait_def_id) {
+        let mut stack: SmallVec<[_; 4]> = smallvec![t];
+        while let Some(trait_ref) = stack.pop() {
+            if let Some(alias) = check_trait(trait_ref) {
                 return Some(alias);
             }
             for pred in generic_predicates_filtered_by(
                 db,
-                GenericDefId::TraitId(trait_def_id),
+                GenericDefId::TraitId(trait_ref.def_id.0),
                 PredicateFilter::SelfTrait,
                 // We are likely in the midst of lowering generic predicates of `def`.
                 // So, if we allow `pred == def` we might fall into an infinite recursion.
                 // Actually, we have already checked for the case `pred == def` above as we started
                 // with a stack including `trait_id`
-                |pred| pred != def && pred == GenericDefId::TraitId(trait_def_id),
+                |pred| pred != def && pred == GenericDefId::TraitId(trait_ref.def_id.0),
             )
             .0
             .deref()
             {
                 tracing::debug!(?pred);
-                let trait_id = match pred.kind().skip_binder() {
-                    rustc_type_ir::ClauseKind::Trait(pred) => pred.def_id(),
+                let sup_trait_ref = match pred.kind().skip_binder() {
+                    rustc_type_ir::ClauseKind::Trait(pred) => pred.trait_ref,
                     _ => continue,
                 };
-                stack.push(trait_id.0);
+                let sup_trait_ref =
+                    EarlyBinder::bind(sup_trait_ref).instantiate(interner, trait_ref.args);
+                stack.push(sup_trait_ref);
             }
             tracing::debug!(?stack);
         }
@@ -1881,7 +2024,7 @@ fn named_associated_type_shorthand_candidates<'db, R>(
 
     match res {
         TypeNs::SelfType(impl_id) => {
-            let trait_ref = db.impl_trait_ns(impl_id)?;
+            let trait_ref = db.impl_trait(impl_id)?;
 
             // FIXME(next-solver): same method in `lower` checks for impl or not
             // Is that needed here?
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/lower_nextsolver/path.rs b/src/tools/rust-analyzer/crates/hir-ty/src/lower_nextsolver/path.rs
index 7d6734303c4..0a9f34c9dab 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/lower_nextsolver/path.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/lower_nextsolver/path.rs
@@ -287,7 +287,7 @@ impl<'a, 'b, 'db> PathLoweringContext<'a, 'b, 'db> {
                     }
                 }
             }
-            TypeNs::SelfType(impl_id) => self.ctx.db.impl_self_ty_ns(impl_id).skip_binder(),
+            TypeNs::SelfType(impl_id) => self.ctx.db.impl_self_ty(impl_id).skip_binder(),
             TypeNs::AdtSelfType(adt) => {
                 let args = crate::next_solver::GenericArgs::identity_for_item(
                     self.ctx.interner,
@@ -616,7 +616,7 @@ impl<'a, 'b, 'db> PathLoweringContext<'a, 'b, 'db> {
         explicit_self_ty: Option<Ty<'db>>,
         lowering_assoc_type_generics: bool,
     ) -> crate::next_solver::GenericArgs<'db> {
-        let mut lifetime_elision = self.ctx.lifetime_elision.clone();
+        let old_lifetime_elision = self.ctx.lifetime_elision.clone();
 
         if let Some(args) = self.current_or_prev_segment.args_and_bindings
             && args.parenthesized != GenericArgsParentheses::No
@@ -646,19 +646,21 @@ impl<'a, 'b, 'db> PathLoweringContext<'a, 'b, 'db> {
             }
 
             // `Fn()`-style generics are treated like functions for the purpose of lifetime elision.
-            lifetime_elision =
+            self.ctx.lifetime_elision =
                 LifetimeElisionKind::AnonymousCreateParameter { report_in_path: false };
         }
 
-        self.substs_from_args_and_bindings(
+        let result = self.substs_from_args_and_bindings(
             self.current_or_prev_segment.args_and_bindings,
             def,
             infer_args,
             explicit_self_ty,
             PathGenericsSource::Segment(self.current_segment_u32()),
             lowering_assoc_type_generics,
-            lifetime_elision,
-        )
+            self.ctx.lifetime_elision.clone(),
+        );
+        self.ctx.lifetime_elision = old_lifetime_elision;
+        result
     }
 
     pub(super) fn substs_from_args_and_bindings(
@@ -915,22 +917,36 @@ impl<'a, 'b, 'db> PathLoweringContext<'a, 'b, 'db> {
                     binding.type_ref.as_ref().map_or(0, |_| 1) + binding.bounds.len(),
                 );
                 if let Some(type_ref) = binding.type_ref {
-                    match (&self.ctx.store[type_ref], self.ctx.impl_trait_mode.mode) {
-                        (TypeRef::ImplTrait(_), ImplTraitLoweringMode::Disallowed) => (),
-                        (_, ImplTraitLoweringMode::Disallowed | ImplTraitLoweringMode::Opaque) => {
-                            let ty = self.ctx.lower_ty(type_ref);
-                            let pred = Clause(Predicate::new(
-                                interner,
-                                Binder::dummy(rustc_type_ir::PredicateKind::Clause(
-                                    rustc_type_ir::ClauseKind::Projection(ProjectionPredicate {
-                                        projection_term,
-                                        term: ty.into(),
-                                    }),
-                                )),
-                            ));
-                            predicates.push(pred);
+                    let lifetime_elision =
+                        if args_and_bindings.parenthesized == GenericArgsParentheses::ParenSugar {
+                            // `Fn()`-style generics are elided like functions. This is `Output` (we lower to it in hir-def).
+                            LifetimeElisionKind::for_fn_ret(self.ctx.interner)
+                        } else {
+                            self.ctx.lifetime_elision.clone()
+                        };
+                    self.with_lifetime_elision(lifetime_elision, |this| {
+                        match (&this.ctx.store[type_ref], this.ctx.impl_trait_mode.mode) {
+                            (TypeRef::ImplTrait(_), ImplTraitLoweringMode::Disallowed) => (),
+                            (
+                                _,
+                                ImplTraitLoweringMode::Disallowed | ImplTraitLoweringMode::Opaque,
+                            ) => {
+                                let ty = this.ctx.lower_ty(type_ref);
+                                let pred = Clause(Predicate::new(
+                                    interner,
+                                    Binder::dummy(rustc_type_ir::PredicateKind::Clause(
+                                        rustc_type_ir::ClauseKind::Projection(
+                                            ProjectionPredicate {
+                                                projection_term,
+                                                term: ty.into(),
+                                            },
+                                        ),
+                                    )),
+                                ));
+                                predicates.push(pred);
+                            }
                         }
-                    }
+                    })
                 }
                 for bound in binding.bounds.iter() {
                     predicates.extend(self.ctx.lower_type_bound(
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/method_resolution.rs b/src/tools/rust-analyzer/crates/hir-ty/src/method_resolution.rs
index 7fa3d31fe5f..61d3091a0c1 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/method_resolution.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/method_resolution.rs
@@ -31,10 +31,13 @@ use crate::{
     infer::{Adjust, Adjustment, OverloadedDeref, PointerCast, unify::InferenceTable},
     lang_items::is_box,
     next_solver::{
-        self, SolverDefId,
-        fulfill::FulfillmentCtxt,
-        infer::DefineOpaqueTypes,
+        self, DbInterner, SolverDefId,
+        infer::{
+            DefineOpaqueTypes,
+            traits::{ObligationCause, PredicateObligation},
+        },
         mapping::{ChalkToNextSolver, NextSolverToChalk},
+        obligation_ctxt::ObligationCtxt,
     },
     primitive::{FloatTy, IntTy, UintTy},
     to_chalk_trait_id,
@@ -294,11 +297,12 @@ impl TraitImpls {
                     continue;
                 }
                 let target_trait = match db.impl_trait(impl_id) {
-                    Some(tr) => tr.skip_binders().hir_trait_id(),
+                    Some(tr) => tr.skip_binder().def_id.0,
                     None => continue,
                 };
-                let self_ty = db.impl_self_ty(impl_id);
-                let self_ty_fp = TyFingerprint::for_trait_impl(self_ty.skip_binders());
+                let interner = DbInterner::new_with(db, None, None);
+                let self_ty = db.impl_self_ty(impl_id).instantiate_identity().to_chalk(interner);
+                let self_ty_fp = TyFingerprint::for_trait_impl(&self_ty);
                 map.entry(target_trait).or_default().entry(self_ty_fp).or_default().push(impl_id);
             }
 
@@ -411,8 +415,8 @@ impl InherentImpls {
                     continue;
                 }
 
-                let self_ty = db.impl_self_ty(impl_id);
-                let self_ty = self_ty.skip_binders();
+                let interner = DbInterner::new_with(db, None, None);
+                let self_ty = &db.impl_self_ty(impl_id).instantiate_identity().to_chalk(interner);
 
                 match is_inherent_impl_coherent(db, def_map, impl_id, self_ty) {
                     true => {
@@ -542,7 +546,7 @@ pub fn def_crates(db: &dyn HirDatabase, ty: &Ty, cur_crate: Crate) -> Option<Sma
 pub(crate) fn lookup_method<'db>(
     db: &'db dyn HirDatabase,
     ty: &next_solver::Canonical<'db, crate::next_solver::Ty<'db>>,
-    env: Arc<TraitEnvironment>,
+    env: Arc<TraitEnvironment<'db>>,
     traits_in_scope: &FxHashSet<TraitId>,
     visible_from_module: VisibleFromModule,
     name: &Name,
@@ -711,7 +715,7 @@ impl ReceiverAdjustments {
 pub(crate) fn iterate_method_candidates<'db, T>(
     ty: &next_solver::Canonical<'db, crate::next_solver::Ty<'db>>,
     db: &'db dyn HirDatabase,
-    env: Arc<TraitEnvironment>,
+    env: Arc<TraitEnvironment<'db>>,
     traits_in_scope: &FxHashSet<TraitId>,
     visible_from_module: VisibleFromModule,
     name: Option<&Name>,
@@ -739,9 +743,9 @@ pub(crate) fn iterate_method_candidates<'db, T>(
     slot
 }
 
-pub fn lookup_impl_const(
-    db: &dyn HirDatabase,
-    env: Arc<TraitEnvironment>,
+pub fn lookup_impl_const<'db>(
+    db: &'db dyn HirDatabase,
+    env: Arc<TraitEnvironment<'db>>,
     const_id: ConstId,
     subs: Substitution,
 ) -> (ConstId, Substitution) {
@@ -767,9 +771,9 @@ pub fn lookup_impl_const(
 
 /// Checks if the self parameter of `Trait` method is the `dyn Trait` and we should
 /// call the method using the vtable.
-pub fn is_dyn_method(
-    db: &dyn HirDatabase,
-    _env: Arc<TraitEnvironment>,
+pub fn is_dyn_method<'db>(
+    db: &'db dyn HirDatabase,
+    _env: Arc<TraitEnvironment<'db>>,
     func: FunctionId,
     fn_subst: Substitution,
 ) -> Option<usize> {
@@ -809,9 +813,9 @@ pub fn is_dyn_method(
 /// Looks up the impl method that actually runs for the trait method `func`.
 ///
 /// Returns `func` if it's not a method defined in a trait or the lookup failed.
-pub(crate) fn lookup_impl_method_query(
-    db: &dyn HirDatabase,
-    env: Arc<TraitEnvironment>,
+pub(crate) fn lookup_impl_method_query<'db>(
+    db: &'db dyn HirDatabase,
+    env: Arc<TraitEnvironment<'db>>,
     func: FunctionId,
     fn_subst: Substitution,
 ) -> (FunctionId, Substitution) {
@@ -842,10 +846,10 @@ pub(crate) fn lookup_impl_method_query(
     )
 }
 
-fn lookup_impl_assoc_item_for_trait_ref(
+fn lookup_impl_assoc_item_for_trait_ref<'db>(
     trait_ref: TraitRef,
-    db: &dyn HirDatabase,
-    env: Arc<TraitEnvironment>,
+    db: &'db dyn HirDatabase,
+    env: Arc<TraitEnvironment<'db>>,
     name: &Name,
 ) -> Option<(AssocItemId, Substitution)> {
     let hir_trait_id = trait_ref.hir_trait_id();
@@ -894,10 +898,13 @@ fn find_matching_impl(
         table.run_in_snapshot(|table| {
             let impl_substs =
                 TyBuilder::subst_for_def(db, impl_, None).fill_with_inference_vars(table).build();
+            let args: crate::next_solver::GenericArgs<'_> =
+                impl_substs.to_nextsolver(table.interner);
             let trait_ref = db
                 .impl_trait(impl_)
                 .expect("non-trait method in find_matching_impl")
-                .substitute(Interner, &impl_substs);
+                .instantiate(table.interner, args)
+                .to_chalk(table.interner);
 
             if !table.unify(&trait_ref, &actual_trait_ref) {
                 return None;
@@ -907,10 +914,11 @@ fn find_matching_impl(
                 .into_iter()
                 .map(|b| -> Goal { b.cast(Interner) });
             for goal in wcs {
-                if table.try_obligation(goal.clone()).no_solution() {
+                let goal = goal.to_nextsolver(table.interner);
+                if table.try_obligation(goal).no_solution() {
                     return None;
                 }
-                table.register_obligation(goal.to_nextsolver(table.interner));
+                table.register_obligation(goal);
             }
             Some((
                 impl_.impl_items(db),
@@ -1014,7 +1022,9 @@ pub fn check_orphan_rules(db: &dyn HirDatabase, impl_: ImplId) -> bool {
     let local_crate = impl_.lookup(db).container.krate();
     let is_local = |tgt_crate| tgt_crate == local_crate;
 
-    let trait_ref = impl_trait.substitute(Interner, &substs);
+    let interner = DbInterner::new_with(db, None, None);
+    let args: crate::next_solver::GenericArgs<'_> = substs.to_nextsolver(interner);
+    let trait_ref = impl_trait.instantiate(interner, args).to_chalk(interner);
     let trait_id = from_chalk_trait_id(trait_ref.trait_id);
     if is_local(trait_id.module(db).krate()) {
         // trait to be implemented is local
@@ -1063,7 +1073,7 @@ pub fn check_orphan_rules(db: &dyn HirDatabase, impl_: ImplId) -> bool {
 pub fn iterate_path_candidates<'db>(
     ty: &next_solver::Canonical<'db, crate::next_solver::Ty<'db>>,
     db: &'db dyn HirDatabase,
-    env: Arc<TraitEnvironment>,
+    env: Arc<TraitEnvironment<'db>>,
     traits_in_scope: &FxHashSet<TraitId>,
     visible_from_module: VisibleFromModule,
     name: Option<&Name>,
@@ -1085,7 +1095,7 @@ pub fn iterate_path_candidates<'db>(
 pub fn iterate_method_candidates_dyn<'db>(
     ty: &next_solver::Canonical<'db, crate::next_solver::Ty<'db>>,
     db: &'db dyn HirDatabase,
-    env: Arc<TraitEnvironment>,
+    env: Arc<TraitEnvironment<'db>>,
     traits_in_scope: &FxHashSet<TraitId>,
     visible_from_module: VisibleFromModule,
     name: Option<&Name>,
@@ -1347,7 +1357,7 @@ fn iterate_method_candidates_by_receiver<'db>(
 fn iterate_method_candidates_for_self_ty<'db>(
     self_ty: &next_solver::Canonical<'db, crate::next_solver::Ty<'db>>,
     db: &'db dyn HirDatabase,
-    env: Arc<TraitEnvironment>,
+    env: Arc<TraitEnvironment<'db>>,
     traits_in_scope: &FxHashSet<TraitId>,
     visible_from_module: VisibleFromModule,
     name: Option<&Name>,
@@ -1395,7 +1405,7 @@ fn iterate_trait_method_candidates(
     let db = table.db;
 
     let canonical_self_ty = table.canonicalize(self_ty.clone().to_nextsolver(table.interner));
-    let TraitEnvironment { krate, .. } = *table.trait_env;
+    let krate = table.trait_env.krate;
 
     'traits: for &t in traits_in_scope {
         let data = db.trait_signature(t);
@@ -1635,7 +1645,6 @@ pub(crate) fn resolve_indexing_op<'db>(
     let ty = table.instantiate_canonical_ns(ty);
     let deref_chain = autoderef_method_receiver(table, ty);
     for (ty, adj) in deref_chain {
-        //let goal = generic_implements_goal_ns(db, &table.trait_env, index_trait, &ty);
         let goal = generic_implements_goal_ns(table, index_trait, ty);
         if !next_trait_solve_canonical_in_ctxt(&table.infer_ctxt, goal).no_solution() {
             return Some(adj);
@@ -1694,8 +1703,10 @@ fn is_valid_impl_method_candidate(
                 return IsValidCandidate::NotVisible;
             }
             let self_ty_matches = table.run_in_snapshot(|table| {
-                let expected_self_ty =
-                    TyBuilder::impl_self_ty(db, impl_id).fill_with_inference_vars(table).build();
+                let expected_self_ty = TyBuilder::impl_self_ty(db, impl_id)
+                    .fill_with_inference_vars(table)
+                    .build(DbInterner::conjure())
+                    .to_chalk(DbInterner::conjure());
                 table.unify(&expected_self_ty, self_ty)
             });
             if !self_ty_matches {
@@ -1741,9 +1752,13 @@ fn is_valid_trait_method_candidate(
                         .fill_with_inference_vars(table)
                         .build();
 
+                    let args: crate::next_solver::GenericArgs<'_> =
+                        fn_subst.to_nextsolver(table.interner);
                     let sig = db.callable_item_signature(fn_id.into());
-                    let expected_receiver =
-                        sig.map(|s| s.params()[0].clone()).substitute(Interner, &fn_subst);
+                    let expected_receiver = sig
+                        .map_bound(|s| s.skip_binder().inputs_and_output.as_slice()[0])
+                        .instantiate(table.interner, args)
+                        .to_chalk(table.interner);
 
                     // FIXME: Clean up this mess with some context struct like rustc's `ProbeContext`
                     let variance = match mode {
@@ -1754,7 +1769,7 @@ fn is_valid_trait_method_candidate(
                         .infer_ctxt
                         .at(
                             &next_solver::infer::traits::ObligationCause::dummy(),
-                            table.trait_env.env.to_nextsolver(table.interner),
+                            table.trait_env.env,
                         )
                         .relate(
                             DefineOpaqueTypes::No,
@@ -1767,12 +1782,10 @@ fn is_valid_trait_method_candidate(
                     };
 
                     if !infer_ok.obligations.is_empty() {
-                        let mut ctxt = FulfillmentCtxt::new(&table.infer_ctxt);
-                        for pred in infer_ok.into_obligations() {
-                            ctxt.register_predicate_obligation(&table.infer_ctxt, pred);
-                        }
+                        let mut ctxt = ObligationCtxt::new(&table.infer_ctxt);
+                        ctxt.register_obligations(infer_ok.into_obligations());
                         // FIXME: Are we doing this correctly? Probably better to follow rustc more closely.
-                        check_that!(ctxt.select_where_possible(&table.infer_ctxt).is_empty());
+                        check_that!(ctxt.select_where_possible().is_empty());
                     }
 
                     check_that!(table.unify(receiver_ty, &expected_receiver));
@@ -1815,9 +1828,11 @@ fn is_valid_impl_fn_candidate(
     }
     table.run_in_snapshot(|table| {
         let _p = tracing::info_span!("subst_for_def").entered();
-        let impl_subst =
-            TyBuilder::subst_for_def(db, impl_id, None).fill_with_inference_vars(table).build();
-        let expect_self_ty = db.impl_self_ty(impl_id).substitute(Interner, &impl_subst);
+        let impl_subst = table.infer_ctxt.fresh_args_for_item(impl_id.into());
+        let expect_self_ty = db
+            .impl_self_ty(impl_id)
+            .instantiate(table.interner, &impl_subst)
+            .to_chalk(table.interner);
 
         check_that!(table.unify(&expect_self_ty, self_ty));
 
@@ -1825,65 +1840,49 @@ fn is_valid_impl_fn_candidate(
             let _p = tracing::info_span!("check_receiver_ty").entered();
             check_that!(data.has_self_param());
 
-            let fn_subst = TyBuilder::subst_for_def(db, fn_id, Some(impl_subst.clone()))
-                .fill_with_inference_vars(table)
-                .build();
+            let fn_subst: crate::Substitution =
+                table.infer_ctxt.fresh_args_for_item(fn_id.into()).to_chalk(table.interner);
 
+            let args: crate::next_solver::GenericArgs<'_> = fn_subst.to_nextsolver(table.interner);
             let sig = db.callable_item_signature(fn_id.into());
-            let expected_receiver =
-                sig.map(|s| s.params()[0].clone()).substitute(Interner, &fn_subst);
+            let expected_receiver = sig
+                .map_bound(|s| s.skip_binder().inputs_and_output.as_slice()[0])
+                .instantiate(table.interner, args)
+                .to_chalk(table.interner);
 
             check_that!(table.unify(receiver_ty, &expected_receiver));
         }
 
         // We need to consider the bounds on the impl to distinguish functions of the same name
         // for a type.
-        let predicates = db.generic_predicates(impl_id.into());
-        let goals = predicates.iter().map(|p| {
-            let (p, b) = p
-                .clone()
-                .substitute(Interner, &impl_subst)
-                // Skipping the inner binders is ok, as we don't handle quantified where
-                // clauses yet.
-                .into_value_and_skipped_binders();
-            stdx::always!(b.len(Interner) == 0);
-
-            p.cast::<Goal>(Interner)
-        });
-
-        for goal in goals.clone() {
-            match table.solve_obligation(goal) {
-                Ok(_) => {}
-                Err(_) => {
-                    return IsValidCandidate::No;
-                }
-            }
-        }
+        let predicates = db.generic_predicates_ns(impl_id.into());
+        let Some(predicates) = predicates.instantiate(table.interner, impl_subst) else {
+            return IsValidCandidate::Yes;
+        };
 
-        for goal in goals {
-            if table.try_obligation(goal).no_solution() {
-                return IsValidCandidate::No;
-            }
-        }
+        let mut ctxt = ObligationCtxt::new(&table.infer_ctxt);
 
-        IsValidCandidate::Yes
-    })
-}
+        ctxt.register_obligations(predicates.into_iter().map(|p| {
+            PredicateObligation::new(
+                table.interner,
+                ObligationCause::new(),
+                table.trait_env.env,
+                p.0,
+            )
+        }));
 
-pub fn implements_trait(
-    ty: &Canonical<Ty>,
-    db: &dyn HirDatabase,
-    env: &TraitEnvironment,
-    trait_: TraitId,
-) -> bool {
-    let goal = generic_implements_goal(db, env, trait_, ty);
-    !db.trait_solve(env.krate, env.block, goal.cast(Interner)).no_solution()
+        if ctxt.select_where_possible().is_empty() {
+            IsValidCandidate::Yes
+        } else {
+            IsValidCandidate::No
+        }
+    })
 }
 
-pub fn implements_trait_unique(
+pub fn implements_trait_unique<'db>(
     ty: &Canonical<Ty>,
-    db: &dyn HirDatabase,
-    env: &TraitEnvironment,
+    db: &'db dyn HirDatabase,
+    env: &TraitEnvironment<'db>,
     trait_: TraitId,
 ) -> bool {
     let goal = generic_implements_goal(db, env, trait_, ty);
@@ -1891,11 +1890,11 @@ pub fn implements_trait_unique(
 }
 
 /// This creates Substs for a trait with the given Self type and type variables
-/// for all other parameters, to query Chalk with it.
+/// for all other parameters, to query next solver with it.
 #[tracing::instrument(skip_all)]
-fn generic_implements_goal(
-    db: &dyn HirDatabase,
-    env: &TraitEnvironment,
+fn generic_implements_goal<'db>(
+    db: &'db dyn HirDatabase,
+    env: &TraitEnvironment<'db>,
     trait_: TraitId,
     self_ty: &Canonical<Ty>,
 ) -> Canonical<InEnvironment<super::DomainGoal>> {
@@ -1917,7 +1916,10 @@ fn generic_implements_goal(
     let binders = CanonicalVarKinds::from_iter(Interner, kinds);
 
     let obligation = trait_ref.cast(Interner);
-    let value = InEnvironment::new(&env.env, obligation);
+    let value = InEnvironment::new(
+        &env.env.to_chalk(DbInterner::new_with(db, Some(env.krate), env.block)),
+        obligation,
+    );
     Canonical { binders, value }
 }
 
@@ -1934,11 +1936,7 @@ fn generic_implements_goal_ns<'db>(
     let trait_ref =
         rustc_type_ir::TraitRef::new_from_args(table.infer_ctxt.interner, trait_.into(), args)
             .with_replaced_self_ty(table.infer_ctxt.interner, self_ty);
-    let goal = next_solver::Goal::new(
-        table.infer_ctxt.interner,
-        table.trait_env.env.to_nextsolver(table.infer_ctxt.interner),
-        trait_ref,
-    );
+    let goal = next_solver::Goal::new(table.infer_ctxt.interner, table.trait_env.env, trait_ref);
 
     table.canonicalize(goal)
 }
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval.rs b/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval.rs
index 3e658cb93ed..c93165a04c0 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval.rs
@@ -165,7 +165,7 @@ enum MirOrDynIndex {
 
 pub struct Evaluator<'a> {
     db: &'a dyn HirDatabase,
-    trait_env: Arc<TraitEnvironment>,
+    trait_env: Arc<TraitEnvironment<'a>>,
     target_data_layout: Arc<TargetDataLayout>,
     stack: Vec<u8>,
     heap: Vec<u8>,
@@ -432,9 +432,12 @@ impl MirEvalError {
                 let self_ = match func.lookup(db).container {
                     ItemContainerId::ImplId(impl_id) => Some({
                         let generics = crate::generics::generics(db, impl_id.into());
+                        let interner = DbInterner::new_with(db, None, None);
                         let substs = generics.placeholder_subst(db);
+                        let args: crate::next_solver::GenericArgs<'_> =
+                            substs.to_nextsolver(interner);
                         db.impl_self_ty(impl_id)
-                            .substitute(Interner, &substs)
+                            .instantiate(interner, args)
                             .display(db, display_target)
                             .to_string()
                     }),
@@ -582,8 +585,8 @@ impl MirOutput {
     }
 }
 
-pub fn interpret_mir(
-    db: &dyn HirDatabase,
+pub fn interpret_mir<'db>(
+    db: &'db dyn HirDatabase,
     body: Arc<MirBody>,
     // FIXME: This is workaround. Ideally, const generics should have a separate body (issue #7434), but now
     // they share their body with their parent, so in MIR lowering we have locals of the parent body, which
@@ -591,7 +594,7 @@ pub fn interpret_mir(
     // a zero size, hoping that they are all outside of our current body. Even without a fix for #7434, we can
     // (and probably should) do better here, for example by excluding bindings outside of the target expression.
     assert_placeholder_ty_is_unused: bool,
-    trait_env: Option<Arc<TraitEnvironment>>,
+    trait_env: Option<Arc<TraitEnvironment<'db>>>,
 ) -> Result<(Result<Const>, MirOutput)> {
     let ty = body.locals[return_slot()].ty.clone();
     let mut evaluator = Evaluator::new(db, body.owner, assert_placeholder_ty_is_unused, trait_env)?;
@@ -632,11 +635,11 @@ const EXECUTION_LIMIT: usize = 10_000_000;
 
 impl<'db> Evaluator<'db> {
     pub fn new(
-        db: &dyn HirDatabase,
+        db: &'db dyn HirDatabase,
         owner: DefWithBodyId,
         assert_placeholder_ty_is_unused: bool,
-        trait_env: Option<Arc<TraitEnvironment>>,
-    ) -> Result<Evaluator<'_>> {
+        trait_env: Option<Arc<TraitEnvironment<'db>>>,
+    ) -> Result<Evaluator<'db>> {
         let crate_id = owner.module(db).krate();
         let target_data_layout = match db.target_data_layout(crate_id) {
             Ok(target_data_layout) => target_data_layout,
@@ -2085,7 +2088,7 @@ impl<'db> Evaluator<'db> {
         if let Some(layout) = self.layout_cache.borrow().get(&ty.to_nextsolver(interner)) {
             return Ok(layout
                 .is_sized()
-                .then(|| (layout.size.bytes_usize(), layout.align.abi.bytes() as usize)));
+                .then(|| (layout.size.bytes_usize(), layout.align.bytes() as usize)));
         }
         if let DefWithBodyId::VariantId(f) = locals.body.owner
             && let Some((AdtId::EnumId(e), _)) = ty.as_adt()
@@ -2104,7 +2107,7 @@ impl<'db> Evaluator<'db> {
         let layout = layout?;
         Ok(layout
             .is_sized()
-            .then(|| (layout.size.bytes_usize(), layout.align.abi.bytes() as usize)))
+            .then(|| (layout.size.bytes_usize(), layout.align.bytes() as usize)))
     }
 
     /// A version of `self.size_of` which returns error if the type is unsized. `what` argument should
@@ -2797,7 +2800,7 @@ impl<'db> Evaluator<'db> {
                     )?;
                     // FIXME: there is some leak here
                     let size = layout.size.bytes_usize();
-                    let addr = self.heap_allocate(size, layout.align.abi.bytes() as usize)?;
+                    let addr = self.heap_allocate(size, layout.align.bytes() as usize)?;
                     self.write_memory(addr, &result)?;
                     IntervalAndTy { interval: Interval { addr, size }, ty }
                 };
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval/shim.rs b/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval/shim.rs
index f67778b0f12..40d76bf42e9 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval/shim.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval/shim.rs
@@ -14,6 +14,7 @@ use hir_expand::name::Name;
 use intern::{Symbol, sym};
 use stdx::never;
 
+use crate::next_solver::mapping::NextSolverToChalk;
 use crate::{
     DropGlue,
     display::DisplayTarget,
@@ -767,7 +768,7 @@ impl Evaluator<'_> {
                         "align_of generic arg is not provided".into(),
                     ));
                 };
-                let align = self.layout(ty.to_nextsolver(interner))?.align.abi.bytes();
+                let align = self.layout(ty.to_nextsolver(interner))?.align.bytes();
                 destination.write_from_bytes(self, &align.to_le_bytes()[0..destination.size])
             }
             "size_of_val" => {
@@ -1371,9 +1372,8 @@ impl Evaluator<'_> {
                     result = (l as i8).cmp(&(r as i8));
                 }
                 if let Some(e) = LangItem::Ordering.resolve_enum(self.db, self.crate_id) {
-                    let ty = self.db.ty(e.into());
-                    let r = self
-                        .compute_discriminant(ty.skip_binders().clone(), &[result as i8 as u8])?;
+                    let ty = self.db.ty(e.into()).skip_binder().to_chalk(interner);
+                    let r = self.compute_discriminant(ty.clone(), &[result as i8 as u8])?;
                     destination.write_from_bytes(self, &r.to_le_bytes()[0..destination.size])?;
                     Ok(())
                 } else {
@@ -1431,7 +1431,7 @@ impl Evaluator<'_> {
                     field_types.iter().next_back().unwrap().1.clone().substitute(Interner, subst);
                 let sized_part_size =
                     layout.fields.offset(field_types.iter().count() - 1).bytes_usize();
-                let sized_part_align = layout.align.abi.bytes() as usize;
+                let sized_part_align = layout.align.bytes() as usize;
                 let (unsized_part_size, unsized_part_align) =
                     self.size_align_of_unsized(&last_field_ty, metadata, locals)?;
                 let align = sized_part_align.max(unsized_part_align) as isize;
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/mir/lower.rs b/src/tools/rust-analyzer/crates/hir-ty/src/mir/lower.rs
index 50e416a66a6..3e44e8c68dd 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/mir/lower.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/mir/lower.rs
@@ -43,7 +43,10 @@ use crate::{
         Terminator, TerminatorKind, TupleFieldId, Ty, UnOp, VariantId, intern_const_scalar,
         return_slot,
     },
-    next_solver::{DbInterner, mapping::ChalkToNextSolver},
+    next_solver::{
+        DbInterner,
+        mapping::{ChalkToNextSolver, NextSolverToChalk},
+    },
     static_lifetime,
     traits::FnTrait,
     utils::ClosureSubst,
@@ -82,7 +85,7 @@ struct MirLowerCtx<'db> {
     infer: &'db InferenceResult,
     resolver: Resolver<'db>,
     drop_scopes: Vec<DropScope>,
-    env: Arc<TraitEnvironment>,
+    env: Arc<TraitEnvironment<'db>>,
 }
 
 // FIXME: Make this smaller, its stored in database queries
@@ -2207,8 +2210,13 @@ pub fn lower_to_mir(
             // otherwise it's an inline const, and has no parameter
             if let DefWithBodyId::FunctionId(fid) = owner {
                 let substs = TyBuilder::placeholder_subst(db, fid);
-                let callable_sig =
-                    db.callable_item_signature(fid.into()).substitute(Interner, &substs);
+                let interner = DbInterner::new_with(db, None, None);
+                let args: crate::next_solver::GenericArgs<'_> = substs.to_nextsolver(interner);
+                let callable_sig = db
+                    .callable_item_signature(fid.into())
+                    .instantiate(interner, args)
+                    .skip_binder()
+                    .to_chalk(interner);
                 let mut params = callable_sig.params().iter();
                 let self_param = body.self_param.and_then(|id| Some((id, params.next()?.clone())));
                 break 'b ctx.lower_params_and_bindings(
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/mir/monomorphization.rs b/src/tools/rust-analyzer/crates/hir-ty/src/mir/monomorphization.rs
index 555b8785092..f293f38c769 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/mir/monomorphization.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/mir/monomorphization.rs
@@ -35,7 +35,7 @@ macro_rules! not_supported {
 
 struct Filler<'a> {
     db: &'a dyn HirDatabase,
-    trait_env: Arc<TraitEnvironment>,
+    trait_env: Arc<TraitEnvironment<'a>>,
     subst: &'a Substitution,
     generics: Option<Generics>,
 }
@@ -301,11 +301,11 @@ impl Filler<'_> {
     }
 }
 
-pub fn monomorphized_mir_body_query(
-    db: &dyn HirDatabase,
+pub fn monomorphized_mir_body_query<'db>(
+    db: &'db dyn HirDatabase,
     owner: DefWithBodyId,
     subst: Substitution,
-    trait_env: Arc<crate::TraitEnvironment>,
+    trait_env: Arc<crate::TraitEnvironment<'db>>,
 ) -> Result<Arc<MirBody>, MirLowerError> {
     let generics = owner.as_generic_def_id(db).map(|g_def| generics(db, g_def));
     let filler = &mut Filler { db, subst: &subst, trait_env, generics };
@@ -315,20 +315,20 @@ pub fn monomorphized_mir_body_query(
     Ok(Arc::new(body))
 }
 
-pub(crate) fn monomorphized_mir_body_cycle_result(
-    _db: &dyn HirDatabase,
+pub(crate) fn monomorphized_mir_body_cycle_result<'db>(
+    _db: &'db dyn HirDatabase,
     _: DefWithBodyId,
     _: Substitution,
-    _: Arc<crate::TraitEnvironment>,
+    _: Arc<crate::TraitEnvironment<'db>>,
 ) -> Result<Arc<MirBody>, MirLowerError> {
     Err(MirLowerError::Loop)
 }
 
-pub fn monomorphized_mir_body_for_closure_query(
-    db: &dyn HirDatabase,
+pub fn monomorphized_mir_body_for_closure_query<'db>(
+    db: &'db dyn HirDatabase,
     closure: InternedClosureId,
     subst: Substitution,
-    trait_env: Arc<crate::TraitEnvironment>,
+    trait_env: Arc<crate::TraitEnvironment<'db>>,
 ) -> Result<Arc<MirBody>, MirLowerError> {
     let InternedClosure(owner, _) = db.lookup_intern_closure(closure);
     let generics = owner.as_generic_def_id(db).map(|g_def| generics(db, g_def));
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver.rs b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver.rs
index 073a02908de..ab167e88af2 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver.rs
@@ -13,7 +13,7 @@ pub(crate) mod inspect;
 pub mod interner;
 mod ir_print;
 pub mod mapping;
-mod normalize;
+pub mod normalize;
 pub mod obligation_ctxt;
 mod opaques;
 pub mod predicate;
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/interner.rs b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/interner.rs
index 9cf56bef957..b72504a19cf 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/interner.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/interner.rs
@@ -1091,23 +1091,21 @@ impl<'db> rustc_type_ir::Interner for DbInterner<'db> {
                     ItemContainerId::ImplId(it) => it,
                     _ => panic!("assoc ty value should be in impl"),
                 };
-                self.db().ty_ns(id.into())
+                self.db().ty(id.into())
             }
-            SolverDefId::AdtId(id) => self.db().ty_ns(id.into()),
+            SolverDefId::AdtId(id) => self.db().ty(id.into()),
             // FIXME(next-solver): This uses the types of `query mir_borrowck` in rustc.
             //
             // We currently always use the type from HIR typeck which ignores regions. This
             // should be fine.
             SolverDefId::InternedOpaqueTyId(_) => self.type_of_opaque_hir_typeck(def_id),
-            SolverDefId::FunctionId(id) => self.db.value_ty_ns(id.into()).unwrap(),
+            SolverDefId::FunctionId(id) => self.db.value_ty(id.into()).unwrap(),
             SolverDefId::Ctor(id) => {
                 let id = match id {
                     Ctor::Struct(id) => id.into(),
                     Ctor::Enum(id) => id.into(),
                 };
-                self.db
-                    .value_ty_ns(id)
-                    .expect("`SolverDefId::Ctor` should have a function-like ctor")
+                self.db.value_ty(id).expect("`SolverDefId::Ctor` should have a function-like ctor")
             }
             _ => panic!("Unexpected def_id `{def_id:?}` provided for `type_of`"),
         }
@@ -1227,7 +1225,7 @@ impl<'db> rustc_type_ir::Interner for DbInterner<'db> {
         self,
         def_id: Self::FunctionId,
     ) -> EarlyBinder<Self, rustc_type_ir::Binder<Self, rustc_type_ir::FnSig<Self>>> {
-        self.db().callable_item_signature_ns(def_id.0)
+        self.db().callable_item_signature(def_id.0)
     }
 
     fn coroutine_movability(self, def_id: Self::CoroutineId) -> rustc_ast_ir::Movability {
@@ -1322,7 +1320,7 @@ impl<'db> rustc_type_ir::Interner for DbInterner<'db> {
         self,
         def_id: Self::DefId,
     ) -> EarlyBinder<Self, impl IntoIterator<Item = Self::Clause>> {
-        let predicates = self.db().generic_predicates_without_parent_ns(def_id.try_into().unwrap());
+        let predicates = self.db().generic_predicates_without_parent(def_id.try_into().unwrap());
         let predicates: Vec<_> = predicates.iter().cloned().collect();
         EarlyBinder::bind(predicates.into_iter())
     }
@@ -1396,7 +1394,7 @@ impl<'db> rustc_type_ir::Interner for DbInterner<'db> {
         self,
         impl_id: Self::ImplId,
     ) -> EarlyBinder<Self, impl IntoIterator<Item = Self::Clause>> {
-        let trait_ref = self.db().impl_trait_ns(impl_id.0).expect("expected an impl of trait");
+        let trait_ref = self.db().impl_trait(impl_id.0).expect("expected an impl of trait");
         trait_ref.map_bound(|trait_ref| {
             let clause: Clause<'_> = trait_ref.upcast(self);
             Clauses::new_from_iter(
@@ -1635,7 +1633,7 @@ impl<'db> rustc_type_ir::Interner for DbInterner<'db> {
                 |impls| {
                     for i in impls.for_trait(trait_) {
                         use rustc_type_ir::TypeVisitable;
-                        let contains_errors = self.db().impl_trait_ns(i).map_or(false, |b| {
+                        let contains_errors = self.db().impl_trait(i).map_or(false, |b| {
                             b.skip_binder().visit_with(&mut ContainsTypeErrors).is_break()
                         });
                         if contains_errors {
@@ -1658,7 +1656,7 @@ impl<'db> rustc_type_ir::Interner for DbInterner<'db> {
                     for fp in fps {
                         for i in impls.for_trait_and_self_ty(trait_, *fp) {
                             use rustc_type_ir::TypeVisitable;
-                            let contains_errors = self.db().impl_trait_ns(i).map_or(false, |b| {
+                            let contains_errors = self.db().impl_trait(i).map_or(false, |b| {
                                 b.skip_binder().visit_with(&mut ContainsTypeErrors).is_break()
                             });
                             if contains_errors {
@@ -1704,7 +1702,7 @@ impl<'db> rustc_type_ir::Interner for DbInterner<'db> {
         impl_id: Self::ImplId,
     ) -> EarlyBinder<Self, rustc_type_ir::TraitRef<Self>> {
         let db = self.db();
-        db.impl_trait_ns(impl_id.0)
+        db.impl_trait(impl_id.0)
             // ImplIds for impls where the trait ref can't be resolved should never reach trait solving
             .expect("invalid impl passed to trait solver")
     }
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/mapping.rs b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/mapping.rs
index b24b996b092..f3f74f67c04 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/mapping.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/mapping.rs
@@ -575,6 +575,17 @@ impl<
     }
 }
 
+impl<'db, T: NextSolverToChalk<'db, U>, U: HasInterner<Interner = Interner>>
+    NextSolverToChalk<'db, chalk_ir::Binders<U>> for rustc_type_ir::Binder<DbInterner<'db>, T>
+{
+    fn to_chalk(self, interner: DbInterner<'db>) -> chalk_ir::Binders<U> {
+        chalk_ir::Binders::new(
+            self.bound_vars().to_chalk(interner),
+            self.skip_binder().to_chalk(interner),
+        )
+    }
+}
+
 impl<'db> ChalkToNextSolver<'db, BoundVarKinds> for chalk_ir::VariableKinds<Interner> {
     fn to_nextsolver(&self, interner: DbInterner<'db>) -> BoundVarKinds {
         BoundVarKinds::new_from_iter(
@@ -584,6 +595,12 @@ impl<'db> ChalkToNextSolver<'db, BoundVarKinds> for chalk_ir::VariableKinds<Inte
     }
 }
 
+impl<'db> NextSolverToChalk<'db, chalk_ir::VariableKinds<Interner>> for BoundVarKinds {
+    fn to_chalk(self, interner: DbInterner<'db>) -> chalk_ir::VariableKinds<Interner> {
+        chalk_ir::VariableKinds::from_iter(Interner, self.iter().map(|v| v.to_chalk(interner)))
+    }
+}
+
 impl<'db> ChalkToNextSolver<'db, BoundVarKind> for chalk_ir::VariableKind<Interner> {
     fn to_nextsolver(&self, interner: DbInterner<'db>) -> BoundVarKind {
         match self {
@@ -594,6 +611,18 @@ impl<'db> ChalkToNextSolver<'db, BoundVarKind> for chalk_ir::VariableKind<Intern
     }
 }
 
+impl<'db> NextSolverToChalk<'db, chalk_ir::VariableKind<Interner>> for BoundVarKind {
+    fn to_chalk(self, interner: DbInterner<'db>) -> chalk_ir::VariableKind<Interner> {
+        match self {
+            BoundVarKind::Ty(_) => chalk_ir::VariableKind::Ty(chalk_ir::TyVariableKind::General),
+            BoundVarKind::Region(_) => chalk_ir::VariableKind::Lifetime,
+            BoundVarKind::Const => {
+                chalk_ir::VariableKind::Const(chalk_ir::TyKind::Error.intern(Interner))
+            }
+        }
+    }
+}
+
 impl<'db> ChalkToNextSolver<'db, GenericArg<'db>> for chalk_ir::GenericArg<Interner> {
     fn to_nextsolver(&self, interner: DbInterner<'db>) -> GenericArg<'db> {
         match self.data(Interner) {
@@ -1233,6 +1262,22 @@ where
     }
 }
 
+impl<'db> NextSolverToChalk<'db, crate::CallableSig> for rustc_type_ir::FnSig<DbInterner<'db>> {
+    fn to_chalk(self, interner: DbInterner<'db>) -> crate::CallableSig {
+        crate::CallableSig {
+            abi: self.abi,
+            is_varargs: self.c_variadic,
+            safety: match self.safety {
+                super::abi::Safety::Safe => chalk_ir::Safety::Safe,
+                super::abi::Safety::Unsafe => chalk_ir::Safety::Unsafe,
+            },
+            params_and_return: triomphe::Arc::from_iter(
+                self.inputs_and_output.iter().map(|ty| convert_ty_for_result(interner, ty)),
+            ),
+        }
+    }
+}
+
 pub fn convert_canonical_args_for_result<'db>(
     interner: DbInterner<'db>,
     args: Canonical<'db, Vec<GenericArg<'db>>>,
@@ -1266,7 +1311,7 @@ pub fn convert_args_for_result<'db>(
     Substitution::from_iter(Interner, substs)
 }
 
-pub(crate) fn convert_ty_for_result<'db>(interner: DbInterner<'db>, ty: Ty<'db>) -> crate::Ty {
+pub fn convert_ty_for_result<'db>(interner: DbInterner<'db>, ty: Ty<'db>) -> crate::Ty {
     use crate::{Scalar, TyKind};
     use chalk_ir::{FloatTy, IntTy, UintTy};
     match ty.kind() {
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/region.rs b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/region.rs
index d6214d99156..0bfd2b8003d 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/region.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/region.rs
@@ -15,7 +15,7 @@ use super::{
     interner::{BoundVarKind, DbInterner, Placeholder},
 };
 
-type RegionKind<'db> = rustc_type_ir::RegionKind<DbInterner<'db>>;
+pub type RegionKind<'db> = rustc_type_ir::RegionKind<DbInterner<'db>>;
 
 #[salsa::interned(constructor = new_, debug)]
 pub struct Region<'db> {
@@ -53,6 +53,10 @@ impl<'db> Region<'db> {
         Region::new(interner, RegionKind::ReVar(v))
     }
 
+    pub fn new_erased(interner: DbInterner<'db>) -> Region<'db> {
+        Region::new(interner, RegionKind::ReErased)
+    }
+
     pub fn is_placeholder(&self) -> bool {
         matches!(self.inner(), RegionKind::RePlaceholder(..))
     }
@@ -61,6 +65,10 @@ impl<'db> Region<'db> {
         matches!(self.inner(), RegionKind::ReStatic)
     }
 
+    pub fn is_var(&self) -> bool {
+        matches!(self.inner(), RegionKind::ReVar(_))
+    }
+
     pub fn error(interner: DbInterner<'db>) -> Self {
         Region::new(interner, RegionKind::ReError(ErrorGuaranteed))
     }
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/solver.rs b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/solver.rs
index 946e57e6cb7..a161423da4d 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/solver.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/solver.rs
@@ -156,16 +156,16 @@ impl<'db> SolverDelegate for SolverContext<'db> {
             SolverDefId::TypeAliasId(id) => id,
             _ => panic!("Unexpected SolverDefId"),
         };
-        let trait_ref = self
+        let trait_ = self
             .0
             .interner
             .db()
             .impl_trait(impl_id.0)
             // ImplIds for impls where the trait ref can't be resolved should never reach solver
             .expect("invalid impl passed to next-solver")
-            .into_value_and_skipped_binders()
+            .skip_binder()
+            .def_id
             .0;
-        let trait_ = trait_ref.hir_trait_id();
         let trait_data = trait_.trait_items(self.0.interner.db());
         let id =
             impl_id.0.impl_items(self.0.interner.db()).items.iter().find_map(|item| -> Option<_> {
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/ty.rs b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/ty.rs
index 70139e86669..a25996ab485 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/ty.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/ty.rs
@@ -7,6 +7,7 @@ use hir_def::{GenericDefId, TypeOrConstParamId, TypeParamId};
 use intern::{Interned, Symbol, sym};
 use rustc_abi::{Float, Integer, Size};
 use rustc_ast_ir::{Mutability, try_visit, visit::VisitorResult};
+use rustc_type_ir::TyVid;
 use rustc_type_ir::{
     BoundVar, ClosureKind, CollectAndApply, FlagComputation, Flags, FloatTy, FloatVid, InferTy,
     IntTy, IntVid, Interner, TypeFoldable, TypeSuperFoldable, TypeSuperVisitable, TypeVisitable,
@@ -336,6 +337,14 @@ impl<'db> Ty<'db> {
         matches!(self.kind(), TyKind::Tuple(tys) if tys.inner().is_empty())
     }
 
+    #[inline]
+    pub fn ty_vid(self) -> Option<TyVid> {
+        match self.kind() {
+            TyKind::Infer(rustc_type_ir::TyVar(vid)) => Some(vid),
+            _ => None,
+        }
+    }
+
     /// Given a `fn` type, returns an equivalent `unsafe fn` type;
     /// that is, a `fn` type that is equivalent in every way for being
     /// unsafe.
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/tests/incremental.rs b/src/tools/rust-analyzer/crates/hir-ty/src/tests/incremental.rs
index c0b930e5e12..8587c13e87f 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/tests/incremental.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/tests/incremental.rs
@@ -511,7 +511,6 @@ impl SomeStruct {
                 "struct_signature_shim",
                 "struct_signature_with_source_map_shim",
                 "attrs_shim",
-                "type_for_adt_tracked",
             ]
         "#]],
     );
@@ -609,9 +608,6 @@ fn main() {
                 "trait_impls_in_crate_shim",
                 "impl_trait_with_diagnostics_shim",
                 "impl_self_ty_with_diagnostics_shim",
-                "type_for_adt_tracked",
-                "impl_trait_with_diagnostics_ns_shim",
-                "impl_self_ty_with_diagnostics_ns_shim",
                 "generic_predicates_ns_shim",
                 "value_ty_shim",
                 "generic_predicates_shim",
@@ -700,8 +696,6 @@ fn main() {
                 "trait_impls_in_crate_shim",
                 "impl_trait_with_diagnostics_shim",
                 "impl_self_ty_with_diagnostics_shim",
-                "impl_trait_with_diagnostics_ns_shim",
-                "impl_self_ty_with_diagnostics_ns_shim",
                 "generic_predicates_ns_shim",
                 "generic_predicates_shim",
             ]
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/tests/method_resolution.rs b/src/tools/rust-analyzer/crates/hir-ty/src/tests/method_resolution.rs
index b14ce35aa99..2f8f6664756 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/tests/method_resolution.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/tests/method_resolution.rs
@@ -2050,10 +2050,10 @@ impl dyn Error + Send {
     /// Attempts to downcast the box to a concrete type.
     pub fn downcast<T: Error + 'static>(self: Box<Self>) -> Result<Box<T>, Box<dyn Error + Send>> {
         let err: Box<dyn Error> = self;
-                               // ^^^^ expected Box<dyn Error + '?>, got Box<dyn Error + Send + '?>
+                               // ^^^^ expected Box<dyn Error + '?>, got Box<dyn Error + Send + 'static>
                                // FIXME, type mismatch should not occur
         <dyn Error>::downcast(err).map_err(|_| loop {})
-      //^^^^^^^^^^^^^^^^^^^^^ type: fn downcast<{unknown}>(Box<dyn Error + '?>) -> Result<Box<{unknown}>, Box<dyn Error + '?>>
+      //^^^^^^^^^^^^^^^^^^^^^ type: fn downcast<{unknown}>(Box<dyn Error + 'static>) -> Result<Box<{unknown}>, Box<dyn Error + 'static>>
     }
 }
 "#,
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/tests/never_type.rs b/src/tools/rust-analyzer/crates/hir-ty/src/tests/never_type.rs
index af5290d7203..4d68179a88b 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/tests/never_type.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/tests/never_type.rs
@@ -14,8 +14,6 @@ fn test() {
     );
 }
 
-// FIXME(next-solver): The never type fallback implemented in r-a no longer works properly because of
-// `Coerce` predicates. We should reimplement fallback like rustc.
 #[test]
 fn infer_never2() {
     check_types(
@@ -26,7 +24,7 @@ fn test() {
     let a = gen();
     if false { a } else { loop {} };
     a;
-} //^ {unknown}
+} //^ !
 "#,
     );
 }
@@ -41,7 +39,7 @@ fn test() {
     let a = gen();
     if false { loop {} } else { a };
     a;
-  //^ {unknown}
+  //^ !
 }
 "#,
     );
@@ -56,7 +54,7 @@ enum Option<T> { None, Some(T) }
 fn test() {
     let a = if true { Option::None } else { Option::Some(return) };
     a;
-} //^ Option<{unknown}>
+} //^ Option<!>
 "#,
     );
 }
@@ -220,7 +218,7 @@ fn test(a: i32) {
         _ => loop {},
     };
     i;
-} //^ {unknown}
+} //^ !
 "#,
     );
 }
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/tests/regression.rs b/src/tools/rust-analyzer/crates/hir-ty/src/tests/regression.rs
index 2ba1e2341b2..00835aa0313 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/tests/regression.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/tests/regression.rs
@@ -632,7 +632,7 @@ fn issue_4053_diesel_where_clauses() {
             488..522 '{     ...     }': <SelectStatement<F, S, D, W, O, LOf, {unknown}, {unknown}> as BoxedDsl<DB>>::Output
             498..502 'self': SelectStatement<F, S, D, W, O, LOf, {unknown}, {unknown}>
             498..508 'self.order': O
-            498..515 'self.o...into()': dyn QueryFragment<DB> + '?
+            498..515 'self.o...into()': dyn QueryFragment<DB> + 'static
         "#]],
     );
 }
@@ -1951,7 +1951,7 @@ fn main() {
     Alias::Braced;
   //^^^^^^^^^^^^^ {unknown}
     let Alias::Braced = loop {};
-      //^^^^^^^^^^^^^ {unknown}
+      //^^^^^^^^^^^^^ !
   let Alias::Braced(..) = loop {};
     //^^^^^^^^^^^^^^^^^ Enum
 
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/tests/regression/new_solver.rs b/src/tools/rust-analyzer/crates/hir-ty/src/tests/regression/new_solver.rs
index ead79a8f5b9..adc35cc9bc1 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/tests/regression/new_solver.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/tests/regression/new_solver.rs
@@ -1,6 +1,6 @@
 use expect_test::expect;
 
-use crate::tests::{check_infer, check_no_mismatches};
+use crate::tests::{check_infer, check_no_mismatches, check_types};
 
 #[test]
 fn regression_20365() {
@@ -418,3 +418,57 @@ fn foo() {
         "#]],
     );
 }
+
+#[test]
+fn regression_19637() {
+    check_no_mismatches(
+        r#"
+//- minicore: coerce_unsized
+pub trait Any {}
+
+impl<T: 'static> Any for T {}
+
+pub trait Trait: Any {
+    type F;
+}
+
+pub struct TT {}
+
+impl Trait for TT {
+    type F = f32;
+}
+
+pub fn coercion(x: &mut dyn Any) -> &mut dyn Any {
+    x
+}
+
+fn main() {
+    let mut t = TT {};
+    let tt = &mut t as &mut dyn Trait<F = f32>;
+    let st = coercion(tt);
+}
+    "#,
+    );
+}
+
+#[test]
+fn double_into_iter() {
+    check_types(
+        r#"
+//- minicore: iterator
+
+fn intoiter_issue<A, B>(foo: A)
+where
+    A: IntoIterator<Item = B>,
+    B: IntoIterator<Item = usize>,
+{
+    for x in foo {
+    //  ^ B
+        for m in x {
+        //  ^ usize
+        }
+    }
+}
+"#,
+    );
+}
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/tests/traits.rs b/src/tools/rust-analyzer/crates/hir-ty/src/tests/traits.rs
index 41f8d4ed555..66faac09cc2 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/tests/traits.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/tests/traits.rs
@@ -1487,8 +1487,8 @@ fn test(x: Box<dyn Trait<u64>>, y: &dyn Trait<u64>) {
             268..269 'x': Box<dyn Trait<u64> + '?>
             275..276 'y': &'? (dyn Trait<u64> + '?)
             286..287 'z': Box<dyn Trait<u64> + '?>
-            290..293 'bar': fn bar() -> Box<dyn Trait<u64> + '?>
-            290..295 'bar()': Box<dyn Trait<u64> + '?>
+            290..293 'bar': fn bar() -> Box<dyn Trait<u64> + 'static>
+            290..295 'bar()': Box<dyn Trait<u64> + 'static>
             301..302 'x': Box<dyn Trait<u64> + '?>
             301..308 'x.foo()': u64
             314..315 'y': &'? (dyn Trait<u64> + '?)
@@ -1535,7 +1535,7 @@ fn test(s: S<u32, i32>) {
             251..252 's': S<u32, i32>
             267..289 '{     ...z(); }': ()
             273..274 's': S<u32, i32>
-            273..280 's.bar()': &'? (dyn Trait<u32, i32> + '?)
+            273..280 's.bar()': &'? (dyn Trait<u32, i32> + 'static)
             273..286 's.bar().baz()': (u32, i32)
         "#]],
     );
@@ -1568,8 +1568,8 @@ fn test(x: Trait, y: &Trait) -> u64 {
             106..107 'x': dyn Trait + '?
             113..114 'y': &'? (dyn Trait + '?)
             124..125 'z': dyn Trait + '?
-            128..131 'bar': fn bar() -> dyn Trait + '?
-            128..133 'bar()': dyn Trait + '?
+            128..131 'bar': fn bar() -> dyn Trait + 'static
+            128..133 'bar()': dyn Trait + 'static
             139..140 'x': dyn Trait + '?
             139..146 'x.foo()': u64
             152..153 'y': &'? (dyn Trait + '?)
@@ -1597,7 +1597,7 @@ fn main() {
             47..48 '_': &'? (dyn Fn(S) + '?)
             58..60 '{}': ()
             71..105 '{     ...()); }': ()
-            77..78 'f': fn f(&'? (dyn Fn(S) + '?))
+            77..78 'f': fn f(&'? (dyn Fn(S) + 'static))
             77..102 'f(&|nu...foo())': ()
             79..101 '&|numb....foo()': &'? impl Fn(S)
             80..101 '|numbe....foo()': impl Fn(S)
@@ -2952,7 +2952,7 @@ fn test(x: &dyn Foo) {
             34..36 '{}': ()
             46..47 'x': &'? (dyn Foo + '?)
             59..74 '{     foo(x); }': ()
-            65..68 'foo': fn foo(&'? (dyn Foo + '?))
+            65..68 'foo': fn foo(&'? (dyn Foo + 'static))
             65..71 'foo(x)': ()
             69..70 'x': &'? (dyn Foo + '?)
         "#]],
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/traits.rs b/src/tools/rust-analyzer/crates/hir-ty/src/traits.rs
index 8095d702be4..8ac152341e7 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/traits.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/traits.rs
@@ -1,4 +1,4 @@
-//! Trait solving using Chalk.
+//! Trait solving using next trait solver.
 
 use core::fmt;
 use std::hash::Hash;
@@ -25,7 +25,7 @@ use crate::{
     db::HirDatabase,
     infer::unify::InferenceTable,
     next_solver::{
-        DbInterner, GenericArg, Predicate, SolverContext, Span,
+        DbInterner, GenericArg, ParamEnv, Predicate, SolverContext, Span,
         infer::{DbInternerInferExt, InferCtxt},
         mapping::{ChalkToNextSolver, convert_canonical_args_for_result},
         util::mini_canonicalize,
@@ -39,21 +39,21 @@ use crate::{
 /// ```
 /// we assume that `T: Default`.
 #[derive(Debug, Clone, PartialEq, Eq, Hash)]
-pub struct TraitEnvironment {
+pub struct TraitEnvironment<'db> {
     pub krate: Crate,
     pub block: Option<BlockId>,
     // FIXME make this a BTreeMap
     traits_from_clauses: Box<[(Ty, TraitId)]>,
-    pub env: chalk_ir::Environment<Interner>,
+    pub env: ParamEnv<'db>,
 }
 
-impl TraitEnvironment {
+impl<'db> TraitEnvironment<'db> {
     pub fn empty(krate: Crate) -> Arc<Self> {
         Arc::new(TraitEnvironment {
             krate,
             block: None,
             traits_from_clauses: Box::default(),
-            env: chalk_ir::Environment::new(Interner),
+            env: ParamEnv::empty(),
         })
     }
 
@@ -61,7 +61,7 @@ impl TraitEnvironment {
         krate: Crate,
         block: Option<BlockId>,
         traits_from_clauses: Box<[(Ty, TraitId)]>,
-        env: chalk_ir::Environment<Interner>,
+        env: ParamEnv<'db>,
     ) -> Arc<Self> {
         Arc::new(TraitEnvironment { krate, block, traits_from_clauses, env })
     }
@@ -78,10 +78,10 @@ impl TraitEnvironment {
     }
 }
 
-pub(crate) fn normalize_projection_query(
-    db: &dyn HirDatabase,
+pub(crate) fn normalize_projection_query<'db>(
+    db: &'db dyn HirDatabase,
     projection: ProjectionTy,
-    env: Arc<TraitEnvironment>,
+    env: Arc<TraitEnvironment<'db>>,
 ) -> Ty {
     if projection.substitution.iter(Interner).any(|arg| {
         arg.ty(Interner)
@@ -128,7 +128,7 @@ fn identity_subst(
     chalk_ir::Canonical { binders, value: identity_subst }
 }
 
-/// Solve a trait goal using Chalk.
+/// Solve a trait goal using next trait solver.
 pub(crate) fn trait_solve_query(
     db: &dyn HirDatabase,
     krate: Crate,
@@ -325,7 +325,7 @@ pub fn next_trait_solve_canonical_in_ctxt<'db>(
     }
 }
 
-/// Solve a trait goal using Chalk.
+/// Solve a trait goal using next trait solver.
 pub fn next_trait_solve_in_ctxt<'db, 'a>(
     infer_ctxt: &'a InferCtxt<'db>,
     goal: crate::next_solver::Goal<'db, crate::next_solver::Predicate<'db>>,
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/variance.rs b/src/tools/rust-analyzer/crates/hir-ty/src/variance.rs
index 8593dba301b..a17cf378270 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/variance.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/variance.rs
@@ -15,6 +15,8 @@
 
 use crate::db::HirDatabase;
 use crate::generics::{Generics, generics};
+use crate::next_solver::DbInterner;
+use crate::next_solver::mapping::{ChalkToNextSolver, NextSolverToChalk};
 use crate::{
     AliasTy, Const, ConstScalar, DynTyExt, GenericArg, GenericArgData, Interner, Lifetime,
     LifetimeData, Ty, TyKind,
@@ -238,14 +240,15 @@ impl Context<'_> {
             }
             GenericDefId::FunctionId(f) => {
                 let subst = self.generics.placeholder_subst(self.db);
-                self.add_constraints_from_sig(
-                    self.db
-                        .callable_item_signature(f.into())
-                        .substitute(Interner, &subst)
-                        .params_and_return
-                        .iter(),
-                    Variance::Covariant,
-                );
+                let interner = DbInterner::new_with(self.db, None, None);
+                let args: crate::next_solver::GenericArgs<'_> = subst.to_nextsolver(interner);
+                let sig = self
+                    .db
+                    .callable_item_signature(f.into())
+                    .instantiate(interner, args)
+                    .skip_binder()
+                    .to_chalk(interner);
+                self.add_constraints_from_sig(sig.params_and_return.iter(), Variance::Covariant);
             }
             _ => {}
         }
diff --git a/src/tools/rust-analyzer/crates/hir/src/display.rs b/src/tools/rust-analyzer/crates/hir/src/display.rs
index 833a9ef0306..2bf9bb85e50 100644
--- a/src/tools/rust-analyzer/crates/hir/src/display.rs
+++ b/src/tools/rust-analyzer/crates/hir/src/display.rs
@@ -24,7 +24,7 @@ use crate::{
     Adt, AsAssocItem, AssocItem, AssocItemContainer, Const, ConstParam, Crate, Enum,
     ExternCrateDecl, Field, Function, GenericParam, HasCrate, HasVisibility, Impl, LifetimeParam,
     Macro, Module, SelfParam, Static, Struct, StructKind, Trait, TraitRef, TupleField, TyBuilder,
-    Type, TypeAlias, TypeOrConstParam, TypeParam, Union, Variant,
+    Type, TypeAlias, TypeNs, TypeOrConstParam, TypeParam, Union, Variant,
 };
 
 impl HirDisplay for Function {
@@ -437,6 +437,12 @@ impl HirDisplay for Type<'_> {
     }
 }
 
+impl HirDisplay for TypeNs<'_> {
+    fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> {
+        self.ty.hir_fmt(f)
+    }
+}
+
 impl HirDisplay for ExternCrateDecl {
     fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> {
         write_visibility(self.module(f.db).id, self.visibility(f.db), f)?;
diff --git a/src/tools/rust-analyzer/crates/hir/src/lib.rs b/src/tools/rust-analyzer/crates/hir/src/lib.rs
index 027a386abe8..4342624dd64 100644
--- a/src/tools/rust-analyzer/crates/hir/src/lib.rs
+++ b/src/tools/rust-analyzer/crates/hir/src/lib.rs
@@ -82,7 +82,9 @@ use hir_ty::{
     method_resolution,
     mir::{MutBorrowKind, interpret_mir},
     next_solver::{
-        ClauseKind, DbInterner, GenericArgs, infer::InferCtxt, mapping::ChalkToNextSolver,
+        ClauseKind, DbInterner, GenericArgs,
+        infer::InferCtxt,
+        mapping::{ChalkToNextSolver, NextSolverToChalk, convert_ty_for_result},
     },
     primitive::UintTy,
     traits::FnTrait,
@@ -863,10 +865,13 @@ impl Module {
                     .collect();
 
                 if !missing.is_empty() {
-                    let self_ty = db.impl_self_ty(impl_def.id).substitute(
-                        Interner,
-                        &hir_ty::generics::generics(db, impl_def.id.into()).placeholder_subst(db),
-                    );
+                    let interner = DbInterner::new_with(db, None, None);
+                    let args: crate::next_solver::GenericArgs<'_> =
+                        hir_ty::generics::generics(db, impl_def.id.into())
+                            .placeholder_subst(db)
+                            .to_nextsolver(interner);
+                    let self_ty =
+                        db.impl_self_ty(impl_def.id).instantiate(interner, args).to_chalk(interner);
                     let self_ty = if let TyKind::Alias(AliasTy::Projection(projection)) =
                         self_ty.kind(Interner)
                     {
@@ -1342,19 +1347,12 @@ impl Field {
         u32::from(self.id.into_raw()) as usize
     }
 
-    /// Returns the type as in the signature of the struct (i.e., with
-    /// placeholder types for type parameters). Only use this in the context of
-    /// the field definition.
-    pub fn ty<'db>(&self, db: &'db dyn HirDatabase) -> Type<'db> {
+    /// Returns the type as in the signature of the struct. Only use this in the
+    /// context of the field definition.
+    pub fn ty<'db>(&self, db: &'db dyn HirDatabase) -> TypeNs<'db> {
         let var_id = self.parent.into();
-        let generic_def_id: GenericDefId = match self.parent {
-            VariantDef::Struct(it) => it.id.into(),
-            VariantDef::Union(it) => it.id.into(),
-            VariantDef::Variant(it) => it.id.lookup(db).parent.into(),
-        };
-        let substs = TyBuilder::placeholder_subst(db, generic_def_id);
-        let ty = db.field_types(var_id)[self.id].clone().substitute(Interner, &substs);
-        Type::new(db, var_id, ty)
+        let ty = db.field_types_ns(var_id)[self.id].skip_binder();
+        TypeNs::new(db, var_id, ty)
     }
 
     // FIXME: Find better API to also handle const generics
@@ -1384,9 +1382,8 @@ impl Field {
     }
 
     pub fn layout(&self, db: &dyn HirDatabase) -> Result<Layout, LayoutError> {
-        let interner = DbInterner::new_with(db, None, None);
         db.layout_of_ty(
-            self.ty(db).ty.to_nextsolver(interner),
+            self.ty(db).ty,
             db.trait_environment(match hir_def::VariantId::from(self.parent) {
                 hir_def::VariantId::EnumVariantId(id) => {
                     GenericDefId::AdtId(id.lookup(db).parent.into())
@@ -1506,7 +1503,7 @@ impl<'db> InstantiatedStruct<'db> {
         let krate = self.inner.krate(db);
         let interner = DbInterner::new_with(db, Some(krate.base()), None);
 
-        let ty = db.ty_ns(self.inner.id.into());
+        let ty = db.ty(self.inner.id.into());
         TypeNs::new(db, self.inner.id, ty.instantiate(interner, self.args))
     }
 }
@@ -1666,7 +1663,7 @@ impl<'db> InstantiatedEnum<'db> {
         let krate = self.inner.krate(db);
         let interner = DbInterner::new_with(db, Some(krate.base()), None);
 
-        let ty = db.ty_ns(self.inner.id.into());
+        let ty = db.ty(self.inner.id.into());
         TypeNs::new(db, self.inner.id, ty.instantiate(interner, self.args))
     }
 }
@@ -1853,7 +1850,8 @@ impl Adt {
                     ParamKind::Lifetime => error_lifetime().cast(Interner),
                 }
             })
-            .build();
+            .build(DbInterner::conjure())
+            .to_chalk(DbInterner::conjure());
         Type::new(db, id, ty)
     }
 
@@ -2288,7 +2286,13 @@ impl Function {
     pub fn fn_ptr_type(self, db: &dyn HirDatabase) -> Type<'_> {
         let resolver = self.id.resolver(db);
         let substs = TyBuilder::placeholder_subst(db, self.id);
-        let callable_sig = db.callable_item_signature(self.id.into()).substitute(Interner, &substs);
+        let interner = DbInterner::new_with(db, None, None);
+        let args: crate::next_solver::GenericArgs<'_> = substs.to_nextsolver(interner);
+        let callable_sig = db
+            .callable_item_signature(self.id.into())
+            .instantiate(interner, args)
+            .skip_binder()
+            .to_chalk(interner);
         let ty = TyKind::Function(callable_sig.to_fn_ptr()).intern(Interner);
         Type::new_with_resolver_inner(db, &resolver, ty)
     }
@@ -2297,8 +2301,14 @@ impl Function {
     pub fn ret_type(self, db: &dyn HirDatabase) -> Type<'_> {
         let resolver = self.id.resolver(db);
         let substs = TyBuilder::placeholder_subst(db, self.id);
-        let callable_sig = db.callable_item_signature(self.id.into()).substitute(Interner, &substs);
-        let ty = callable_sig.ret().clone();
+        let interner = DbInterner::new_with(db, None, None);
+        let args: crate::next_solver::GenericArgs<'_> = substs.to_nextsolver(interner);
+        let ty = db
+            .callable_item_signature(self.id.into())
+            .instantiate(interner, args)
+            .skip_binder()
+            .output()
+            .to_chalk(interner);
         Type::new_with_resolver_inner(db, &resolver, ty)
     }
 
@@ -2327,8 +2337,14 @@ impl Function {
             parent_id.map(|id| TyBuilder::subst_for_def(db, id, None).fill(&mut filler).build());
         let substs = TyBuilder::subst_for_def(db, self.id, parent_substs).fill(&mut filler).build();
 
-        let callable_sig = db.callable_item_signature(self.id.into()).substitute(Interner, &substs);
-        let ty = callable_sig.ret().clone();
+        let interner = DbInterner::new_with(db, None, None);
+        let args: crate::next_solver::GenericArgs<'_> = substs.to_nextsolver(interner);
+        let ty = db
+            .callable_item_signature(self.id.into())
+            .instantiate(interner, args)
+            .skip_binder()
+            .output()
+            .to_chalk(interner);
         Type::new_with_resolver_inner(db, &resolver, ty)
     }
 
@@ -2338,8 +2354,14 @@ impl Function {
         }
         let resolver = self.id.resolver(db);
         let substs = TyBuilder::placeholder_subst(db, self.id);
-        let callable_sig = db.callable_item_signature(self.id.into()).substitute(Interner, &substs);
-        let ret_ty = callable_sig.ret().clone();
+        let interner = DbInterner::new_with(db, None, None);
+        let args: crate::next_solver::GenericArgs<'_> = substs.to_nextsolver(interner);
+        let ret_ty = db
+            .callable_item_signature(self.id.into())
+            .instantiate(interner, args)
+            .skip_binder()
+            .output()
+            .to_chalk(interner);
         for pred in ret_ty.impl_trait_bounds(db).into_iter().flatten() {
             if let WhereClause::AliasEq(output_eq) = pred.into_value_and_skipped_binders().0 {
                 return Type::new_with_resolver_inner(db, &resolver, output_eq.ty).into();
@@ -2359,7 +2381,13 @@ impl Function {
     pub fn assoc_fn_params(self, db: &dyn HirDatabase) -> Vec<Param<'_>> {
         let environment = db.trait_environment(self.id.into());
         let substs = TyBuilder::placeholder_subst(db, self.id);
-        let callable_sig = db.callable_item_signature(self.id.into()).substitute(Interner, &substs);
+        let interner = DbInterner::new_with(db, None, None);
+        let args: crate::next_solver::GenericArgs<'_> = substs.to_nextsolver(interner);
+        let callable_sig = db
+            .callable_item_signature(self.id.into())
+            .instantiate(interner, args)
+            .skip_binder()
+            .to_chalk(interner);
         callable_sig
             .params()
             .iter()
@@ -2387,7 +2415,13 @@ impl Function {
     pub fn params_without_self(self, db: &dyn HirDatabase) -> Vec<Param<'_>> {
         let environment = db.trait_environment(self.id.into());
         let substs = TyBuilder::placeholder_subst(db, self.id);
-        let callable_sig = db.callable_item_signature(self.id.into()).substitute(Interner, &substs);
+        let interner = DbInterner::new_with(db, None, None);
+        let args: crate::next_solver::GenericArgs<'_> = substs.to_nextsolver(interner);
+        let callable_sig = db
+            .callable_item_signature(self.id.into())
+            .instantiate(interner, args)
+            .skip_binder()
+            .to_chalk(interner);
         let skip = if db.function_signature(self.id).has_self_param() { 1 } else { 0 };
         callable_sig
             .params()
@@ -2437,7 +2471,13 @@ impl Function {
                 GenericArg::new(Interner, GenericArgData::Ty(ty))
             })
             .build();
-        let callable_sig = db.callable_item_signature(self.id.into()).substitute(Interner, &substs);
+        let interner = DbInterner::new_with(db, None, None);
+        let args: crate::next_solver::GenericArgs<'_> = substs.to_nextsolver(interner);
+        let callable_sig = db
+            .callable_item_signature(self.id.into())
+            .instantiate(interner, args)
+            .skip_binder()
+            .to_chalk(interner);
         let skip = if db.function_signature(self.id).has_self_param() { 1 } else { 0 };
         callable_sig
             .params()
@@ -2732,8 +2772,13 @@ impl SelfParam {
 
     pub fn ty<'db>(&self, db: &'db dyn HirDatabase) -> Type<'db> {
         let substs = TyBuilder::placeholder_subst(db, self.func);
-        let callable_sig =
-            db.callable_item_signature(self.func.into()).substitute(Interner, &substs);
+        let interner = DbInterner::new_with(db, None, None);
+        let args: crate::next_solver::GenericArgs<'_> = substs.to_nextsolver(interner);
+        let callable_sig = db
+            .callable_item_signature(self.func.into())
+            .instantiate(interner, args)
+            .skip_binder()
+            .to_chalk(interner);
         let environment = db.trait_environment(self.func.into());
         let ty = callable_sig.params()[0].clone();
         Type { env: environment, ty, _pd: PhantomCovariantLifetime::new() }
@@ -2765,8 +2810,13 @@ impl SelfParam {
         let parent_substs = TyBuilder::subst_for_def(db, parent_id, None).fill(&mut filler).build();
         let substs =
             TyBuilder::subst_for_def(db, self.func, Some(parent_substs)).fill(&mut filler).build();
-        let callable_sig =
-            db.callable_item_signature(self.func.into()).substitute(Interner, &substs);
+        let interner = DbInterner::new_with(db, None, None);
+        let args: crate::next_solver::GenericArgs<'_> = substs.to_nextsolver(interner);
+        let callable_sig = db
+            .callable_item_signature(self.func.into())
+            .instantiate(interner, args)
+            .skip_binder()
+            .to_chalk(interner);
         let environment = db.trait_environment(self.func.into());
         let ty = callable_sig.params()[0].clone();
         Type { env: environment, ty, _pd: PhantomCovariantLifetime::new() }
@@ -3770,7 +3820,7 @@ impl GenericDef {
         push_ty_diagnostics(
             db,
             acc,
-            db.generic_predicates_without_parent_with_diagnostics_ns(def).1,
+            db.generic_predicates_without_parent_with_diagnostics(def).1,
             &source_map,
         );
         for (param_id, param) in generics.iter_type_or_consts() {
@@ -3810,12 +3860,12 @@ impl GenericDef {
 pub struct GenericSubstitution<'db> {
     def: GenericDefId,
     subst: Substitution,
-    env: Arc<TraitEnvironment>,
+    env: Arc<TraitEnvironment<'db>>,
     _pd: PhantomCovariantLifetime<'db>,
 }
 
 impl<'db> GenericSubstitution<'db> {
-    fn new(def: GenericDefId, subst: Substitution, env: Arc<TraitEnvironment>) -> Self {
+    fn new(def: GenericDefId, subst: Substitution, env: Arc<TraitEnvironment<'db>>) -> Self {
         Self { def, subst, env, _pd: PhantomCovariantLifetime::new() }
     }
 
@@ -4495,21 +4545,23 @@ impl Impl {
     }
 
     pub fn trait_(self, db: &dyn HirDatabase) -> Option<Trait> {
-        let trait_ref = db.impl_trait_ns(self.id)?;
+        let trait_ref = db.impl_trait(self.id)?;
         let id = trait_ref.skip_binder().def_id;
         Some(Trait { id: id.0 })
     }
 
     pub fn trait_ref(self, db: &dyn HirDatabase) -> Option<TraitRef<'_>> {
-        let trait_ref = db.impl_trait_ns(self.id)?.instantiate_identity();
+        let trait_ref = db.impl_trait(self.id)?.instantiate_identity();
         let resolver = self.id.resolver(db);
         Some(TraitRef::new_with_resolver(db, &resolver, trait_ref))
     }
 
     pub fn self_ty(self, db: &dyn HirDatabase) -> Type<'_> {
         let resolver = self.id.resolver(db);
+        let interner = DbInterner::new_with(db, Some(resolver.krate()), None);
         let substs = TyBuilder::placeholder_subst(db, self.id);
-        let ty = db.impl_self_ty(self.id).substitute(Interner, &substs);
+        let args: crate::next_solver::GenericArgs<'_> = substs.to_nextsolver(interner);
+        let ty = db.impl_self_ty(self.id).instantiate(interner, args).to_chalk(interner);
         Type::new_with_resolver_inner(db, &resolver, ty)
     }
 
@@ -4569,7 +4621,7 @@ impl Impl {
 
 #[derive(Clone, PartialEq, Eq, Debug, Hash)]
 pub struct TraitRef<'db> {
-    env: Arc<TraitEnvironment>,
+    env: Arc<TraitEnvironment<'db>>,
     trait_ref: hir_ty::next_solver::TraitRef<'db>,
     _pd: PhantomCovariantLifetime<'db>,
 }
@@ -4792,7 +4844,7 @@ impl CaptureUsageSource {
 
 #[derive(Clone, PartialEq, Eq, Debug, Hash)]
 pub struct Type<'db> {
-    env: Arc<TraitEnvironment>,
+    env: Arc<TraitEnvironment<'db>>,
     ty: Ty,
     _pd: PhantomCovariantLifetime<'db>,
 }
@@ -4830,32 +4882,40 @@ impl<'db> Type<'db> {
     }
 
     fn from_def(db: &'db dyn HirDatabase, def: impl Into<TyDefId> + HasResolver) -> Self {
+        let interner = DbInterner::new_with(db, None, None);
         let ty = db.ty(def.into());
         let substs = TyBuilder::unknown_subst(
             db,
             match def.into() {
                 TyDefId::AdtId(it) => GenericDefId::AdtId(it),
                 TyDefId::TypeAliasId(it) => GenericDefId::TypeAliasId(it),
-                TyDefId::BuiltinType(_) => return Type::new(db, def, ty.skip_binders().clone()),
+                TyDefId::BuiltinType(_) => {
+                    return Type::new(db, def, ty.skip_binder().to_chalk(interner));
+                }
             },
         );
-        Type::new(db, def, ty.substitute(Interner, &substs))
+        let args: hir_ty::next_solver::GenericArgs<'_> = substs.to_nextsolver(interner);
+        Type::new(db, def, ty.instantiate(interner, args).to_chalk(interner))
     }
 
     fn from_def_placeholders(
         db: &'db dyn HirDatabase,
         def: impl Into<TyDefId> + HasResolver,
     ) -> Self {
+        let interner = DbInterner::new_with(db, None, None);
         let ty = db.ty(def.into());
         let substs = TyBuilder::placeholder_subst(
             db,
             match def.into() {
                 TyDefId::AdtId(it) => GenericDefId::AdtId(it),
                 TyDefId::TypeAliasId(it) => GenericDefId::TypeAliasId(it),
-                TyDefId::BuiltinType(_) => return Type::new(db, def, ty.skip_binders().clone()),
+                TyDefId::BuiltinType(_) => {
+                    return Type::new(db, def, ty.skip_binder().to_chalk(interner));
+                }
             },
         );
-        Type::new(db, def, ty.substitute(Interner, &substs))
+        let args: hir_ty::next_solver::GenericArgs<'_> = substs.to_nextsolver(interner);
+        Type::new(db, def, ty.instantiate(interner, args).to_chalk(interner))
     }
 
     fn from_value_def(
@@ -4865,6 +4925,7 @@ impl<'db> Type<'db> {
         let Some(ty) = db.value_ty(def.into()) else {
             return Type::new(db, def, TyKind::Error.intern(Interner));
         };
+        let interner = DbInterner::new_with(db, None, None);
         let substs = TyBuilder::unknown_subst(
             db,
             match def.into() {
@@ -4875,10 +4936,13 @@ impl<'db> Type<'db> {
                 ValueTyDefId::EnumVariantId(it) => {
                     GenericDefId::AdtId(AdtId::EnumId(it.lookup(db).parent))
                 }
-                ValueTyDefId::StaticId(_) => return Type::new(db, def, ty.skip_binders().clone()),
+                ValueTyDefId::StaticId(_) => {
+                    return Type::new(db, def, ty.skip_binder().to_chalk(interner));
+                }
             },
         );
-        Type::new(db, def, ty.substitute(Interner, &substs))
+        let args: crate::next_solver::GenericArgs<'_> = substs.to_nextsolver(interner);
+        Type::new(db, def, ty.instantiate(interner, args).to_chalk(interner))
     }
 
     pub fn new_slice(ty: Self) -> Self {
@@ -5173,7 +5237,14 @@ impl<'db> Type<'db> {
             .build();
 
         let goal = Canonical {
-            value: hir_ty::InEnvironment::new(&self.env.env, trait_ref.cast(Interner)),
+            value: hir_ty::InEnvironment::new(
+                &self.env.env.to_chalk(DbInterner::new_with(
+                    db,
+                    Some(self.env.krate),
+                    self.env.block,
+                )),
+                trait_ref.cast(Interner),
+            ),
             binders: CanonicalVarKinds::empty(Interner),
         };
 
@@ -5947,7 +6018,7 @@ impl<'db> Type<'db> {
 
 #[derive(Clone, PartialEq, Eq, Debug, Hash)]
 pub struct TypeNs<'db> {
-    env: Arc<TraitEnvironment>,
+    env: Arc<TraitEnvironment<'db>>,
     ty: hir_ty::next_solver::Ty<'db>,
     _pd: PhantomCovariantLifetime<'db>,
 }
@@ -5965,6 +6036,11 @@ impl<'db> TypeNs<'db> {
         TypeNs { env: environment, ty, _pd: PhantomCovariantLifetime::new() }
     }
 
+    pub fn to_type(&self, db: &'db dyn HirDatabase) -> Type<'db> {
+        let interner = DbInterner::new_with(db, Some(self.env.krate), self.env.block);
+        Type { env: self.env.clone(), ty: convert_ty_for_result(interner, self.ty), _pd: self._pd }
+    }
+
     // FIXME: Find better API that also handles const generics
     pub fn impls_trait(&self, infcx: InferCtxt<'db>, trait_: Trait, args: &[TypeNs<'db>]) -> bool {
         let args = GenericArgs::new_from_iter(
@@ -5988,6 +6064,10 @@ impl<'db> TypeNs<'db> {
         let res = hir_ty::traits::next_trait_solve_in_ctxt(&infcx, goal);
         res.map_or(false, |res| matches!(res.1, rustc_type_ir::solve::Certainty::Yes))
     }
+
+    pub fn is_bool(&self) -> bool {
+        matches!(self.ty.kind(), rustc_type_ir::TyKind::Bool)
+    }
 }
 
 #[derive(Debug, PartialEq, Eq, Copy, Clone, Hash)]
@@ -6094,7 +6174,7 @@ impl Layout {
     }
 
     pub fn align(&self) -> u64 {
-        self.0.align.abi.bytes()
+        self.0.align.bytes()
     }
 
     pub fn niches(&self) -> Option<u128> {
diff --git a/src/tools/rust-analyzer/crates/hir/src/source_analyzer.rs b/src/tools/rust-analyzer/crates/hir/src/source_analyzer.rs
index 539b25387ae..c6b7e84dc20 100644
--- a/src/tools/rust-analyzer/crates/hir/src/source_analyzer.rs
+++ b/src/tools/rust-analyzer/crates/hir/src/source_analyzer.rs
@@ -46,6 +46,10 @@ use hir_ty::{
     from_assoc_type_id,
     lang_items::lang_items_for_bin_op,
     method_resolution,
+    next_solver::{
+        DbInterner,
+        mapping::{ChalkToNextSolver, NextSolverToChalk},
+    },
 };
 use intern::sym;
 use itertools::Itertools;
@@ -219,7 +223,7 @@ impl<'db> SourceAnalyzer<'db> {
         })
     }
 
-    fn trait_environment(&self, db: &'db dyn HirDatabase) -> Arc<TraitEnvironment> {
+    fn trait_environment(&self, db: &'db dyn HirDatabase) -> Arc<TraitEnvironment<'db>> {
         self.body_().map(|(def, ..)| def).map_or_else(
             || TraitEnvironment::empty(self.resolver.krate()),
             |def| db.trait_environment_for_body(def),
@@ -372,8 +376,10 @@ impl<'db> SourceAnalyzer<'db> {
     ) -> Option<Callable<'db>> {
         let expr_id = self.expr_id(call.clone().into())?.as_expr()?;
         let (func, substs) = self.infer()?.method_resolution(expr_id)?;
-        let ty = db.value_ty(func.into())?.substitute(Interner, &substs);
-        let ty = Type::new_with_resolver(db, &self.resolver, ty);
+        let interner = DbInterner::new_with(db, None, None);
+        let args: hir_ty::next_solver::GenericArgs<'_> = substs.to_nextsolver(interner);
+        let ty = db.value_ty(func.into())?.instantiate(interner, args);
+        let ty = Type::new_with_resolver(db, &self.resolver, ty.to_chalk(interner));
         let mut res = ty.as_callable(db)?;
         res.is_bound_method = true;
         Some(res)
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/add_braces.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/add_braces.rs
index 745ae67f309..5af622eaf28 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/add_braces.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/add_braces.rs
@@ -1,3 +1,4 @@
+use either::Either;
 use syntax::{
     AstNode,
     ast::{self, edit_in_place::Indent, syntax_factory::SyntaxFactory},
@@ -59,7 +60,8 @@ enum ParentType {
 }
 
 fn get_replacement_node(ctx: &AssistContext<'_>) -> Option<(ParentType, ast::Expr)> {
-    if let Some(match_arm) = ctx.find_node_at_offset::<ast::MatchArm>() {
+    let node = ctx.find_node_at_offset::<Either<ast::MatchArm, ast::ClosureExpr>>()?;
+    if let Either::Left(match_arm) = &node {
         let match_arm_expr = match_arm.expr()?;
 
         if matches!(match_arm_expr, ast::Expr::BlockExpr(_)) {
@@ -67,7 +69,7 @@ fn get_replacement_node(ctx: &AssistContext<'_>) -> Option<(ParentType, ast::Exp
         }
 
         return Some((ParentType::MatchArmExpr, match_arm_expr));
-    } else if let Some(closure_expr) = ctx.find_node_at_offset::<ast::ClosureExpr>() {
+    } else if let Either::Right(closure_expr) = &node {
         let body = closure_expr.body()?;
 
         if matches!(body, ast::Expr::BlockExpr(_)) {
@@ -106,6 +108,33 @@ fn foo() {
     }
 
     #[test]
+    fn suggest_add_braces_for_closure_in_match() {
+        check_assist(
+            add_braces,
+            r#"
+fn foo() {
+    match () {
+        () => {
+            t(|n|$0 n + 100);
+        }
+    }
+}
+"#,
+            r#"
+fn foo() {
+    match () {
+        () => {
+            t(|n| {
+                n + 100
+            });
+        }
+    }
+}
+"#,
+        );
+    }
+
+    #[test]
     fn no_assist_for_closures_with_braces() {
         check_assist_not_applicable(
             add_braces,
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/add_missing_match_arms.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/add_missing_match_arms.rs
index 4d3212c515f..3910921fbe0 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/add_missing_match_arms.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/add_missing_match_arms.rs
@@ -521,7 +521,7 @@ fn build_pat(
                 hir::StructKind::Tuple => {
                     let mut name_generator = suggest_name::NameGenerator::default();
                     let pats = fields.into_iter().map(|f| {
-                        let name = name_generator.for_type(&f.ty(db), db, edition);
+                        let name = name_generator.for_type(&f.ty(db).to_type(db), db, edition);
                         match name {
                             Some(name) => make::ext::simple_ident_pat(make.name(&name)).into(),
                             None => make.wildcard_pat().into(),
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/apply_demorgan.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/apply_demorgan.rs
index 753a9e56c35..53a0a11998a 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/apply_demorgan.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/apply_demorgan.rs
@@ -6,7 +6,7 @@ use ide_db::{
     syntax_helpers::node_ext::{for_each_tail_expr, walk_expr},
 };
 use syntax::{
-    SyntaxKind, T,
+    NodeOrToken, SyntaxKind, T,
     ast::{
         self, AstNode,
         Expr::BinExpr,
@@ -38,15 +38,27 @@ use crate::{AssistContext, AssistId, Assists, utils::invert_boolean_expression};
 // }
 // ```
 pub(crate) fn apply_demorgan(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<()> {
-    let mut bin_expr = ctx.find_node_at_offset::<ast::BinExpr>()?;
+    let mut bin_expr = if let Some(not) = ctx.find_token_syntax_at_offset(T![!])
+        && let Some(NodeOrToken::Node(next)) = not.next_sibling_or_token()
+        && let Some(paren) = ast::ParenExpr::cast(next)
+        && let Some(ast::Expr::BinExpr(bin_expr)) = paren.expr()
+    {
+        bin_expr
+    } else {
+        let bin_expr = ctx.find_node_at_offset::<ast::BinExpr>()?;
+        let op_range = bin_expr.op_token()?.text_range();
+
+        // Is the cursor on the expression's logical operator?
+        if !op_range.contains_range(ctx.selection_trimmed()) {
+            return None;
+        }
+
+        bin_expr
+    };
+
     let op = bin_expr.op_kind()?;
     let op_range = bin_expr.op_token()?.text_range();
 
-    // Is the cursor on the expression's logical operator?
-    if !op_range.contains_range(ctx.selection_trimmed()) {
-        return None;
-    }
-
     // Walk up the tree while we have the same binary operator
     while let Some(parent_expr) = bin_expr.syntax().parent().and_then(ast::BinExpr::cast) {
         match parent_expr.op_kind() {
@@ -367,6 +379,15 @@ fn f() { !(S <= S || S < S) }
     }
 
     #[test]
+    fn demorgan_on_not() {
+        check_assist(
+            apply_demorgan,
+            "fn f() { $0!(1 || 3 && 4 || 5) }",
+            "fn f() { !1 && !(3 && 4) && !5 }",
+        )
+    }
+
+    #[test]
     fn demorgan_keep_pars_for_op_precedence() {
         check_assist(
             apply_demorgan,
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/bind_unused_param.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/bind_unused_param.rs
index 00c7d25b257..1b24f7fe7ff 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/bind_unused_param.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/bind_unused_param.rs
@@ -2,7 +2,7 @@ use crate::assist_context::{AssistContext, Assists};
 use ide_db::{LineIndexDatabase, assists::AssistId, defs::Definition};
 use syntax::{
     AstNode,
-    ast::{self, edit_in_place::Indent},
+    ast::{self, HasName, edit_in_place::Indent},
 };
 
 // Assist: bind_unused_param
@@ -22,6 +22,7 @@ pub(crate) fn bind_unused_param(acc: &mut Assists, ctx: &AssistContext<'_>) -> O
     let param: ast::Param = ctx.find_node_at_offset()?;
 
     let Some(ast::Pat::IdentPat(ident_pat)) = param.pat() else { return None };
+    let name = ident_pat.name().filter(|n| !n.text().starts_with('_'))?;
 
     let param_def = {
         let local = ctx.sema.to_def(&ident_pat)?;
@@ -39,14 +40,14 @@ pub(crate) fn bind_unused_param(acc: &mut Assists, ctx: &AssistContext<'_>) -> O
 
     acc.add(
         AssistId::quick_fix("bind_unused_param"),
-        format!("Bind as `let _ = {ident_pat};`"),
+        format!("Bind as `let _ = {name};`"),
         param.syntax().text_range(),
         |builder| {
             let line_index = ctx.db().line_index(ctx.vfs_file_id());
 
             let indent = func.indent_level();
             let text_indent = indent + 1;
-            let mut text = format!("\n{text_indent}let _ = {ident_pat};");
+            let mut text = format!("\n{text_indent}let _ = {name};");
 
             let left_line = line_index.line_col(l_curly_range.end()).line;
             let right_line = line_index.line_col(r_curly_range.start()).line;
@@ -84,6 +85,22 @@ fn foo(y: i32) {
     }
 
     #[test]
+    fn bind_unused_ref_ident_pat() {
+        cov_mark::check!(single_line);
+        check_assist(
+            bind_unused_param,
+            r#"
+fn foo(ref $0y: i32) {}
+"#,
+            r#"
+fn foo(ref y: i32) {
+    let _ = y;
+}
+"#,
+        );
+    }
+
+    #[test]
     fn bind_unused_empty_block_with_newline() {
         check_assist(
             bind_unused_param,
@@ -152,4 +169,14 @@ fn foo(x: i32, $0y: i32) { y; }
 "#,
         );
     }
+
+    #[test]
+    fn keep_underscore_used() {
+        check_assist_not_applicable(
+            bind_unused_param,
+            r#"
+fn foo($0_x: i32, y: i32) {}
+"#,
+        );
+    }
 }
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_to_guarded_return.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_to_guarded_return.rs
index 2ea032fb62b..82213ae3217 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_to_guarded_return.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_to_guarded_return.rs
@@ -1,13 +1,12 @@
 use std::iter::once;
 
-use ide_db::{
-    syntax_helpers::node_ext::{is_pattern_cond, single_let},
-    ty_filter::TryEnum,
-};
+use either::Either;
+use hir::{Semantics, TypeInfo};
+use ide_db::{RootDatabase, ty_filter::TryEnum};
 use syntax::{
     AstNode,
-    SyntaxKind::{FN, FOR_EXPR, LOOP_EXPR, WHILE_EXPR, WHITESPACE},
-    T,
+    SyntaxKind::{CLOSURE_EXPR, FN, FOR_EXPR, LOOP_EXPR, WHILE_EXPR, WHITESPACE},
+    SyntaxNode, T,
     ast::{
         self,
         edit::{AstNodeEdit, IndentLevel},
@@ -44,12 +43,9 @@ use crate::{
 // }
 // ```
 pub(crate) fn convert_to_guarded_return(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<()> {
-    if let Some(let_stmt) = ctx.find_node_at_offset() {
-        let_stmt_to_guarded_return(let_stmt, acc, ctx)
-    } else if let Some(if_expr) = ctx.find_node_at_offset() {
-        if_expr_to_guarded_return(if_expr, acc, ctx)
-    } else {
-        None
+    match ctx.find_node_at_offset::<Either<ast::LetStmt, ast::IfExpr>>()? {
+        Either::Left(let_stmt) => let_stmt_to_guarded_return(let_stmt, acc, ctx),
+        Either::Right(if_expr) => if_expr_to_guarded_return(if_expr, acc, ctx),
     }
 }
 
@@ -73,13 +69,7 @@ fn if_expr_to_guarded_return(
         return None;
     }
 
-    // Check if there is an IfLet that we can handle.
-    let (if_let_pat, cond_expr) = if is_pattern_cond(cond.clone()) {
-        let let_ = single_let(cond)?;
-        (Some(let_.pat()?), let_.expr()?)
-    } else {
-        (None, cond)
-    };
+    let let_chains = flat_let_chain(cond);
 
     let then_block = if_expr.then_branch()?;
     let then_block = then_block.stmt_list()?;
@@ -106,11 +96,7 @@ fn if_expr_to_guarded_return(
 
     let parent_container = parent_block.syntax().parent()?;
 
-    let early_expression: ast::Expr = match parent_container.kind() {
-        WHILE_EXPR | LOOP_EXPR | FOR_EXPR => make::expr_continue(None),
-        FN => make::expr_return(None),
-        _ => return None,
-    };
+    let early_expression: ast::Expr = early_expression(parent_container, &ctx.sema)?;
 
     then_block.syntax().first_child_or_token().map(|t| t.kind() == T!['{'])?;
 
@@ -132,32 +118,42 @@ fn if_expr_to_guarded_return(
         target,
         |edit| {
             let if_indent_level = IndentLevel::from_node(if_expr.syntax());
-            let replacement = match if_let_pat {
-                None => {
-                    // If.
-                    let new_expr = {
-                        let then_branch =
-                            make::block_expr(once(make::expr_stmt(early_expression).into()), None);
-                        let cond = invert_boolean_expression_legacy(cond_expr);
-                        make::expr_if(cond, then_branch, None).indent(if_indent_level)
-                    };
-                    new_expr.syntax().clone()
-                }
-                Some(pat) => {
+            let replacement = let_chains.into_iter().map(|expr| {
+                if let ast::Expr::LetExpr(let_expr) = &expr
+                    && let (Some(pat), Some(expr)) = (let_expr.pat(), let_expr.expr())
+                {
                     // If-let.
                     let let_else_stmt = make::let_else_stmt(
                         pat,
                         None,
-                        cond_expr,
-                        ast::make::tail_only_block_expr(early_expression),
+                        expr,
+                        ast::make::tail_only_block_expr(early_expression.clone()),
                     );
                     let let_else_stmt = let_else_stmt.indent(if_indent_level);
                     let_else_stmt.syntax().clone()
+                } else {
+                    // If.
+                    let new_expr = {
+                        let then_branch = make::block_expr(
+                            once(make::expr_stmt(early_expression.clone()).into()),
+                            None,
+                        );
+                        let cond = invert_boolean_expression_legacy(expr);
+                        make::expr_if(cond, then_branch, None).indent(if_indent_level)
+                    };
+                    new_expr.syntax().clone()
                 }
-            };
+            });
 
+            let newline = &format!("\n{if_indent_level}");
             let then_statements = replacement
-                .children_with_tokens()
+                .enumerate()
+                .flat_map(|(i, node)| {
+                    (i != 0)
+                        .then(|| make::tokens::whitespace(newline).into())
+                        .into_iter()
+                        .chain(node.children_with_tokens())
+                })
                 .chain(
                     then_block_items
                         .syntax()
@@ -201,11 +197,7 @@ fn let_stmt_to_guarded_return(
             let_stmt.syntax().parent()?.ancestors().find_map(ast::BlockExpr::cast)?;
         let parent_container = parent_block.syntax().parent()?;
 
-        match parent_container.kind() {
-            WHILE_EXPR | LOOP_EXPR | FOR_EXPR => make::expr_continue(None),
-            FN => make::expr_return(None),
-            _ => return None,
-        }
+        early_expression(parent_container, &ctx.sema)?
     };
 
     acc.add(
@@ -232,6 +224,54 @@ fn let_stmt_to_guarded_return(
     )
 }
 
+fn early_expression(
+    parent_container: SyntaxNode,
+    sema: &Semantics<'_, RootDatabase>,
+) -> Option<ast::Expr> {
+    let return_none_expr = || {
+        let none_expr = make::expr_path(make::ext::ident_path("None"));
+        make::expr_return(Some(none_expr))
+    };
+    if let Some(fn_) = ast::Fn::cast(parent_container.clone())
+        && let Some(fn_def) = sema.to_def(&fn_)
+        && let Some(TryEnum::Option) = TryEnum::from_ty(sema, &fn_def.ret_type(sema.db))
+    {
+        return Some(return_none_expr());
+    }
+    if let Some(body) = ast::ClosureExpr::cast(parent_container.clone()).and_then(|it| it.body())
+        && let Some(ret_ty) = sema.type_of_expr(&body).map(TypeInfo::original)
+        && let Some(TryEnum::Option) = TryEnum::from_ty(sema, &ret_ty)
+    {
+        return Some(return_none_expr());
+    }
+
+    Some(match parent_container.kind() {
+        WHILE_EXPR | LOOP_EXPR | FOR_EXPR => make::expr_continue(None),
+        FN | CLOSURE_EXPR => make::expr_return(None),
+        _ => return None,
+    })
+}
+
+fn flat_let_chain(mut expr: ast::Expr) -> Vec<ast::Expr> {
+    let mut chains = vec![];
+
+    while let ast::Expr::BinExpr(bin_expr) = &expr
+        && bin_expr.op_kind() == Some(ast::BinaryOp::LogicOp(ast::LogicOp::And))
+        && let (Some(lhs), Some(rhs)) = (bin_expr.lhs(), bin_expr.rhs())
+    {
+        if let Some(last) = chains.pop_if(|last| !matches!(last, ast::Expr::LetExpr(_))) {
+            chains.push(make::expr_bin_op(rhs, ast::BinaryOp::LogicOp(ast::LogicOp::And), last));
+        } else {
+            chains.push(rhs);
+        }
+        expr = lhs;
+    }
+
+    chains.push(expr);
+    chains.reverse();
+    chains
+}
+
 #[cfg(test)]
 mod tests {
     use crate::tests::{check_assist, check_assist_not_applicable};
@@ -269,6 +309,71 @@ fn main() {
     }
 
     #[test]
+    fn convert_inside_fn_return_option() {
+        check_assist(
+            convert_to_guarded_return,
+            r#"
+//- minicore: option
+fn ret_option() -> Option<()> {
+    bar();
+    if$0 true {
+        foo();
+
+        // comment
+        bar();
+    }
+}
+"#,
+            r#"
+fn ret_option() -> Option<()> {
+    bar();
+    if false {
+        return None;
+    }
+    foo();
+
+    // comment
+    bar();
+}
+"#,
+        );
+    }
+
+    #[test]
+    fn convert_inside_closure() {
+        check_assist(
+            convert_to_guarded_return,
+            r#"
+fn main() {
+    let _f = || {
+        bar();
+        if$0 true {
+            foo();
+
+            // comment
+            bar();
+        }
+    }
+}
+"#,
+            r#"
+fn main() {
+    let _f = || {
+        bar();
+        if false {
+            return;
+        }
+        foo();
+
+        // comment
+        bar();
+    }
+}
+"#,
+        );
+    }
+
+    #[test]
     fn convert_let_inside_fn() {
         check_assist(
             convert_to_guarded_return,
@@ -317,6 +422,82 @@ fn main() {
     }
 
     #[test]
+    fn convert_if_let_result_inside_let() {
+        check_assist(
+            convert_to_guarded_return,
+            r#"
+fn main() {
+    let _x = loop {
+        if$0 let Ok(x) = Err(92) {
+            foo(x);
+        }
+    };
+}
+"#,
+            r#"
+fn main() {
+    let _x = loop {
+        let Ok(x) = Err(92) else { continue };
+        foo(x);
+    };
+}
+"#,
+        );
+    }
+
+    #[test]
+    fn convert_if_let_chain_result() {
+        check_assist(
+            convert_to_guarded_return,
+            r#"
+fn main() {
+    if$0 let Ok(x) = Err(92)
+        && x < 30
+        && let Some(y) = Some(8)
+    {
+        foo(x, y);
+    }
+}
+"#,
+            r#"
+fn main() {
+    let Ok(x) = Err(92) else { return };
+    if x >= 30 {
+        return;
+    }
+    let Some(y) = Some(8) else { return };
+    foo(x, y);
+}
+"#,
+        );
+
+        check_assist(
+            convert_to_guarded_return,
+            r#"
+fn main() {
+    if$0 let Ok(x) = Err(92)
+        && x < 30
+        && y < 20
+        && let Some(y) = Some(8)
+    {
+        foo(x, y);
+    }
+}
+"#,
+            r#"
+fn main() {
+    let Ok(x) = Err(92) else { return };
+    if !(x < 30 && y < 20) {
+        return;
+    }
+    let Some(y) = Some(8) else { return };
+    foo(x, y);
+}
+"#,
+        );
+    }
+
+    #[test]
     fn convert_let_ok_inside_fn() {
         check_assist(
             convert_to_guarded_return,
@@ -561,6 +742,32 @@ fn main() {
     }
 
     #[test]
+    fn convert_let_stmt_inside_fn_return_option() {
+        check_assist(
+            convert_to_guarded_return,
+            r#"
+//- minicore: option
+fn foo() -> Option<i32> {
+    None
+}
+
+fn ret_option() -> Option<i32> {
+    let x$0 = foo();
+}
+"#,
+            r#"
+fn foo() -> Option<i32> {
+    None
+}
+
+fn ret_option() -> Option<i32> {
+    let Some(x) = foo() else { return None };
+}
+"#,
+        );
+    }
+
+    #[test]
     fn convert_let_stmt_inside_loop() {
         check_assist(
             convert_to_guarded_return,
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/destructure_struct_binding.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/destructure_struct_binding.rs
index 397327cb4ff..27755db93c8 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/destructure_struct_binding.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/destructure_struct_binding.rs
@@ -7,7 +7,7 @@ use ide_db::{
     search::{FileReference, SearchScope},
 };
 use itertools::Itertools;
-use syntax::ast::syntax_factory::SyntaxFactory;
+use syntax::ast::{HasName, syntax_factory::SyntaxFactory};
 use syntax::syntax_editor::SyntaxEditor;
 use syntax::{AstNode, Edition, SmolStr, SyntaxNode, ToSmolStr, ast};
 
@@ -71,13 +71,14 @@ fn destructure_struct_binding_impl(
 
 struct StructEditData {
     ident_pat: ast::IdentPat,
+    name: ast::Name,
     kind: hir::StructKind,
     struct_def_path: hir::ModPath,
     visible_fields: Vec<hir::Field>,
     usages: Vec<FileReference>,
     names_in_scope: FxHashSet<SmolStr>,
     has_private_members: bool,
-    is_nested: bool,
+    need_record_field_name: bool,
     is_ref: bool,
     edition: Edition,
 }
@@ -114,7 +115,11 @@ fn collect_data(ident_pat: ast::IdentPat, ctx: &AssistContext<'_>) -> Option<Str
     }
 
     let is_ref = ty.is_reference();
-    let is_nested = ident_pat.syntax().parent().and_then(ast::RecordPatField::cast).is_some();
+    let need_record_field_name = ident_pat
+        .syntax()
+        .parent()
+        .and_then(ast::RecordPatField::cast)
+        .is_some_and(|field| field.colon_token().is_none());
 
     let usages = ctx
         .sema
@@ -133,6 +138,7 @@ fn collect_data(ident_pat: ast::IdentPat, ctx: &AssistContext<'_>) -> Option<Str
     let names_in_scope = get_names_in_scope(ctx, &ident_pat, &usages).unwrap_or_default();
 
     Some(StructEditData {
+        name: ident_pat.name()?,
         ident_pat,
         kind,
         struct_def_path,
@@ -140,7 +146,7 @@ fn collect_data(ident_pat: ast::IdentPat, ctx: &AssistContext<'_>) -> Option<Str
         has_private_members,
         visible_fields,
         names_in_scope,
-        is_nested,
+        need_record_field_name,
         is_ref,
         edition: module.krate().edition(ctx.db()),
     })
@@ -177,6 +183,7 @@ fn destructure_pat(
     field_names: &[(SmolStr, SmolStr)],
 ) {
     let ident_pat = &data.ident_pat;
+    let name = &data.name;
 
     let struct_path = mod_path_to_ast(&data.struct_def_path, data.edition);
     let is_ref = ident_pat.ref_token().is_some();
@@ -194,9 +201,9 @@ fn destructure_pat(
         hir::StructKind::Record => {
             let fields = field_names.iter().map(|(old_name, new_name)| {
                 // Use shorthand syntax if possible
-                if old_name == new_name && !is_mut {
+                if old_name == new_name {
                     make.record_pat_field_shorthand(
-                        make.ident_pat(false, false, make.name(old_name)).into(),
+                        make.ident_pat(is_ref, is_mut, make.name(old_name)).into(),
                     )
                 } else {
                     make.record_pat_field(
@@ -215,8 +222,8 @@ fn destructure_pat(
 
     // If the binding is nested inside a record, we need to wrap the new
     // destructured pattern in a non-shorthand record field
-    let destructured_pat = if data.is_nested {
-        make.record_pat_field(make.name_ref(&ident_pat.to_string()), new_pat).syntax().clone()
+    let destructured_pat = if data.need_record_field_name {
+        make.record_pat_field(make.name_ref(&name.to_string()), new_pat).syntax().clone()
     } else {
         new_pat.syntax().clone()
     };
@@ -288,7 +295,7 @@ fn build_usage_edit(
         Some(field_expr) => Some({
             let field_name: SmolStr = field_expr.name_ref()?.to_string().into();
             let new_field_name = field_names.get(&field_name)?;
-            let new_expr = make.expr_path(ast::make::ext::ident_path(new_field_name));
+            let new_expr = ast::make::expr_path(ast::make::ext::ident_path(new_field_name));
 
             // If struct binding is a reference, we might need to deref field usages
             if data.is_ref {
@@ -298,7 +305,7 @@ fn build_usage_edit(
                     ref_data.wrap_expr(new_expr).syntax().clone_for_update(),
                 )
             } else {
-                (field_expr.syntax().clone(), new_expr.syntax().clone())
+                (field_expr.syntax().clone(), new_expr.syntax().clone_for_update())
             }
         }),
         None => Some((
@@ -579,7 +586,7 @@ mod tests {
             struct Foo { bar: i32, baz: i32 }
 
             fn main() {
-                let Foo { bar: mut bar, baz: mut baz } = Foo { bar: 1, baz: 2 };
+                let Foo { mut bar, mut baz } = Foo { bar: 1, baz: 2 };
                 let bar2 = bar;
                 let baz2 = &baz;
             }
@@ -588,6 +595,86 @@ mod tests {
     }
 
     #[test]
+    fn mut_record_field() {
+        check_assist(
+            destructure_struct_binding,
+            r#"
+            struct Foo { x: () }
+            struct Bar { foo: Foo }
+            fn f(Bar { mut $0foo }: Bar) {}
+            "#,
+            r#"
+            struct Foo { x: () }
+            struct Bar { foo: Foo }
+            fn f(Bar { foo: Foo { mut x } }: Bar) {}
+            "#,
+        )
+    }
+
+    #[test]
+    fn ref_record_field() {
+        check_assist(
+            destructure_struct_binding,
+            r#"
+            struct Foo { x: () }
+            struct Bar { foo: Foo }
+            fn f(Bar { ref $0foo }: Bar) {
+                let _ = foo.x;
+            }
+            "#,
+            r#"
+            struct Foo { x: () }
+            struct Bar { foo: Foo }
+            fn f(Bar { foo: Foo { ref x } }: Bar) {
+                let _ = *x;
+            }
+            "#,
+        )
+    }
+
+    #[test]
+    fn ref_mut_record_field() {
+        check_assist(
+            destructure_struct_binding,
+            r#"
+            struct Foo { x: () }
+            struct Bar { foo: Foo }
+            fn f(Bar { ref mut $0foo }: Bar) {
+                let _ = foo.x;
+            }
+            "#,
+            r#"
+            struct Foo { x: () }
+            struct Bar { foo: Foo }
+            fn f(Bar { foo: Foo { ref mut x } }: Bar) {
+                let _ = *x;
+            }
+            "#,
+        )
+    }
+
+    #[test]
+    fn ref_mut_record_renamed_field() {
+        check_assist(
+            destructure_struct_binding,
+            r#"
+            struct Foo { x: () }
+            struct Bar { foo: Foo }
+            fn f(Bar { foo: ref mut $0foo1 }: Bar) {
+                let _ = foo1.x;
+            }
+            "#,
+            r#"
+            struct Foo { x: () }
+            struct Bar { foo: Foo }
+            fn f(Bar { foo: Foo { ref mut x } }: Bar) {
+                let _ = *x;
+            }
+            "#,
+        )
+    }
+
+    #[test]
     fn mut_ref() {
         check_assist(
             destructure_struct_binding,
@@ -611,6 +698,52 @@ mod tests {
     }
 
     #[test]
+    fn ref_not_add_parenthesis_and_deref_record() {
+        check_assist(
+            destructure_struct_binding,
+            r#"
+            struct Foo { bar: i32, baz: i32 }
+
+            fn main() {
+                let $0foo = &Foo { bar: 1, baz: 2 };
+                let _ = &foo.bar;
+            }
+            "#,
+            r#"
+            struct Foo { bar: i32, baz: i32 }
+
+            fn main() {
+                let Foo { bar, baz } = &Foo { bar: 1, baz: 2 };
+                let _ = bar;
+            }
+            "#,
+        )
+    }
+
+    #[test]
+    fn ref_not_add_parenthesis_and_deref_tuple() {
+        check_assist(
+            destructure_struct_binding,
+            r#"
+            struct Foo(i32, i32);
+
+            fn main() {
+                let $0foo = &Foo(1, 2);
+                let _ = &foo.0;
+            }
+            "#,
+            r#"
+            struct Foo(i32, i32);
+
+            fn main() {
+                let Foo(_0, _1) = &Foo(1, 2);
+                let _ = _0;
+            }
+            "#,
+        )
+    }
+
+    #[test]
     fn record_struct_name_collision() {
         check_assist(
             destructure_struct_binding,
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/expand_rest_pattern.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/expand_rest_pattern.rs
index c80b78fd970..b746099e727 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/expand_rest_pattern.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/expand_rest_pattern.rs
@@ -24,7 +24,7 @@ use crate::{AssistContext, AssistId, Assists};
 // struct Bar { y: Y, z: Z }
 //
 // fn foo(bar: Bar) {
-//     let Bar { y, z  } = bar;
+//     let Bar { y, z } = bar;
 // }
 // ```
 fn expand_record_rest_pattern(
@@ -53,18 +53,17 @@ fn expand_record_rest_pattern(
         |builder| {
             let make = SyntaxFactory::with_mappings();
             let mut editor = builder.make_editor(rest_pat.syntax());
-            let new_field_list = make.record_pat_field_list(old_field_list.fields(), None);
-            for (f, _) in missing_fields.iter() {
-                let field = make.record_pat_field_shorthand(
+            let new_fields = old_field_list.fields().chain(missing_fields.iter().map(|(f, _)| {
+                make.record_pat_field_shorthand(
                     make.ident_pat(
                         false,
                         false,
                         make.name(&f.name(ctx.sema.db).display_no_db(edition).to_smolstr()),
                     )
                     .into(),
-                );
-                new_field_list.add_field(field);
-            }
+                )
+            }));
+            let new_field_list = make.record_pat_field_list(new_fields, None);
 
             editor.replace(old_field_list.syntax(), new_field_list.syntax());
 
@@ -114,9 +113,7 @@ fn expand_tuple_struct_rest_pattern(
     };
 
     let rest_pat = rest_pat.into();
-    let mut pats = pat.fields();
-    let prefix_count = pats.by_ref().position(|p| p == rest_pat)?;
-    let suffix_count = pats.count();
+    let (prefix_count, suffix_count) = calculate_counts(&rest_pat, pat.fields())?;
 
     if fields.len().saturating_sub(prefix_count).saturating_sub(suffix_count) == 0 {
         cov_mark::hit!(no_missing_fields_tuple_struct);
@@ -142,16 +139,13 @@ fn expand_tuple_struct_rest_pattern(
                 pat.fields()
                     .take(prefix_count)
                     .chain(fields[prefix_count..fields.len() - suffix_count].iter().map(|f| {
-                        make.ident_pat(
-                            false,
-                            false,
-                            match name_gen.for_type(&f.ty(ctx.sema.db), ctx.sema.db, ctx.edition())
-                            {
-                                Some(name) => make.name(&name),
-                                None => make.name(&format!("_{}", f.index())),
-                            },
+                        gen_unnamed_pat(
+                            ctx,
+                            &make,
+                            &mut name_gen,
+                            &f.ty(ctx.db()).to_type(ctx.sema.db),
+                            f.index(),
                         )
-                        .into()
                     }))
                     .chain(pat.fields().skip(prefix_count + 1)),
             );
@@ -164,6 +158,134 @@ fn expand_tuple_struct_rest_pattern(
     )
 }
 
+// Assist: expand_tuple_rest_pattern
+//
+// Fills fields by replacing rest pattern in tuple patterns.
+//
+// ```
+// fn foo(bar: (char, i32, i32)) {
+//     let (ch, ..$0) = bar;
+// }
+// ```
+// ->
+// ```
+// fn foo(bar: (char, i32, i32)) {
+//     let (ch, _1, _2) = bar;
+// }
+// ```
+fn expand_tuple_rest_pattern(
+    acc: &mut Assists,
+    ctx: &AssistContext<'_>,
+    pat: ast::TuplePat,
+    rest_pat: ast::RestPat,
+) -> Option<()> {
+    let fields = ctx.sema.type_of_pat(&pat.clone().into())?.original.tuple_fields(ctx.db());
+    let len = fields.len();
+
+    let rest_pat = rest_pat.into();
+    let (prefix_count, suffix_count) = calculate_counts(&rest_pat, pat.fields())?;
+
+    if len.saturating_sub(prefix_count).saturating_sub(suffix_count) == 0 {
+        cov_mark::hit!(no_missing_fields_tuple);
+        return None;
+    }
+
+    let old_range = ctx.sema.original_range_opt(pat.syntax())?;
+    if old_range.file_id != ctx.file_id() {
+        return None;
+    }
+
+    acc.add(
+        AssistId::refactor_rewrite("expand_tuple_rest_pattern"),
+        "Fill tuple fields",
+        rest_pat.syntax().text_range(),
+        |builder| {
+            let make = SyntaxFactory::with_mappings();
+            let mut editor = builder.make_editor(rest_pat.syntax());
+
+            let mut name_gen = NameGenerator::new_from_scope_locals(ctx.sema.scope(pat.syntax()));
+            let new_pat = make.tuple_pat(
+                pat.fields()
+                    .take(prefix_count)
+                    .chain(fields[prefix_count..len - suffix_count].iter().enumerate().map(
+                        |(index, ty)| {
+                            gen_unnamed_pat(ctx, &make, &mut name_gen, ty, prefix_count + index)
+                        },
+                    ))
+                    .chain(pat.fields().skip(prefix_count + 1)),
+            );
+
+            editor.replace(pat.syntax(), new_pat.syntax());
+
+            editor.add_mappings(make.finish_with_mappings());
+            builder.add_file_edits(ctx.vfs_file_id(), editor);
+        },
+    )
+}
+
+// Assist: expand_slice_rest_pattern
+//
+// Fills fields by replacing rest pattern in slice patterns.
+//
+// ```
+// fn foo(bar: [i32; 3]) {
+//     let [first, ..$0] = bar;
+// }
+// ```
+// ->
+// ```
+// fn foo(bar: [i32; 3]) {
+//     let [first, _1, _2] = bar;
+// }
+// ```
+fn expand_slice_rest_pattern(
+    acc: &mut Assists,
+    ctx: &AssistContext<'_>,
+    pat: ast::SlicePat,
+    rest_pat: ast::RestPat,
+) -> Option<()> {
+    let (ty, len) = ctx.sema.type_of_pat(&pat.clone().into())?.original.as_array(ctx.db())?;
+
+    let rest_pat = rest_pat.into();
+    let (prefix_count, suffix_count) = calculate_counts(&rest_pat, pat.pats())?;
+
+    if len.saturating_sub(prefix_count).saturating_sub(suffix_count) == 0 {
+        cov_mark::hit!(no_missing_fields_slice);
+        return None;
+    }
+
+    let old_range = ctx.sema.original_range_opt(pat.syntax())?;
+    if old_range.file_id != ctx.file_id() {
+        return None;
+    }
+
+    acc.add(
+        AssistId::refactor_rewrite("expand_slice_rest_pattern"),
+        "Fill slice fields",
+        rest_pat.syntax().text_range(),
+        |builder| {
+            let make = SyntaxFactory::with_mappings();
+            let mut editor = builder.make_editor(rest_pat.syntax());
+
+            let mut name_gen = NameGenerator::new_from_scope_locals(ctx.sema.scope(pat.syntax()));
+            let new_pat = make.slice_pat(
+                pat.pats()
+                    .take(prefix_count)
+                    .chain(
+                        (prefix_count..len - suffix_count)
+                            .map(|index| gen_unnamed_pat(ctx, &make, &mut name_gen, &ty, index)),
+                    )
+                    .chain(pat.pats().skip(prefix_count + 1)),
+            );
+
+            editor.replace(pat.syntax(), new_pat.syntax());
+
+            editor.add_mappings(make.finish_with_mappings());
+            builder.add_file_edits(ctx.vfs_file_id(), editor);
+        },
+    )
+}
+
 pub(crate) fn expand_rest_pattern(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<()> {
     let rest_pat = ctx.find_node_at_offset::<ast::RestPat>()?;
     let parent = rest_pat.syntax().parent()?;
@@ -171,15 +293,40 @@ pub(crate) fn expand_rest_pattern(acc: &mut Assists, ctx: &AssistContext<'_>) ->
         match parent {
             ast::RecordPatFieldList(it) => expand_record_rest_pattern(acc, ctx, it.syntax().parent().and_then(ast::RecordPat::cast)?, rest_pat),
             ast::TupleStructPat(it) => expand_tuple_struct_rest_pattern(acc, ctx, it, rest_pat),
-            // FIXME
-            // ast::TuplePat(it) => (),
-            // FIXME
-            // ast::SlicePat(it) => (),
+            ast::TuplePat(it) => expand_tuple_rest_pattern(acc, ctx, it, rest_pat),
+            ast::SlicePat(it) => expand_slice_rest_pattern(acc, ctx, it, rest_pat),
             _ => None,
         }
     }
 }
 
+fn gen_unnamed_pat(
+    ctx: &AssistContext<'_>,
+    make: &SyntaxFactory,
+    name_gen: &mut NameGenerator,
+    ty: &hir::Type<'_>,
+    index: usize,
+) -> ast::Pat {
+    make.ident_pat(
+        false,
+        false,
+        match name_gen.for_type(ty, ctx.sema.db, ctx.edition()) {
+            Some(name) => make.name(&name),
+            None => make.name(&format!("_{index}")),
+        },
+    )
+    .into()
+}
+
+fn calculate_counts(
+    rest_pat: &ast::Pat,
+    mut pats: ast::AstChildren<ast::Pat>,
+) -> Option<(usize, usize)> {
+    let prefix_count = pats.by_ref().position(|p| p == *rest_pat)?;
+    let suffix_count = pats.count();
+    Some((prefix_count, suffix_count))
+}
+
 #[cfg(test)]
 mod tests {
     use super::*;
@@ -211,7 +358,7 @@ enum Foo {
 fn bar(foo: Foo) {
     match foo {
         Foo::A(_) => false,
-        Foo::B{ y, z  } => true,
+        Foo::B{ y, z } => true,
     };
 }
 "#,
@@ -272,7 +419,7 @@ struct Bar {
 }
 
 fn foo(bar: Bar) {
-    let Bar { y, z  } = bar;
+    let Bar { y, z } = bar;
 }
 "#,
         );
@@ -350,6 +497,79 @@ fn foo(bar: Bar) {
     }
 
     #[test]
+    fn fill_tuple_with_fields() {
+        check_assist(
+            expand_rest_pattern,
+            r#"
+fn foo(bar: (char, i32, i32)) {
+    let (ch, ..$0) = bar;
+}
+"#,
+            r#"
+fn foo(bar: (char, i32, i32)) {
+    let (ch, _1, _2) = bar;
+}
+"#,
+        );
+        check_assist(
+            expand_rest_pattern,
+            r#"
+fn foo(bar: (char, i32, i32)) {
+    let (ch, ..$0, end) = bar;
+}
+"#,
+            r#"
+fn foo(bar: (char, i32, i32)) {
+    let (ch, _1, end) = bar;
+}
+"#,
+        );
+    }
+
+    #[test]
+    fn fill_array_with_fields() {
+        check_assist(
+            expand_rest_pattern,
+            r#"
+fn foo(bar: [i32; 4]) {
+    let [first, ..$0] = bar;
+}
+"#,
+            r#"
+fn foo(bar: [i32; 4]) {
+    let [first, _1, _2, _3] = bar;
+}
+"#,
+        );
+        check_assist(
+            expand_rest_pattern,
+            r#"
+fn foo(bar: [i32; 4]) {
+    let [first, second, ..$0] = bar;
+}
+"#,
+            r#"
+fn foo(bar: [i32; 4]) {
+    let [first, second, _2, _3] = bar;
+}
+"#,
+        );
+        check_assist(
+            expand_rest_pattern,
+            r#"
+fn foo(bar: [i32; 4]) {
+    let [first, second, ..$0, end] = bar;
+}
+"#,
+            r#"
+fn foo(bar: [i32; 4]) {
+    let [first, second, _2, end] = bar;
+}
+"#,
+        );
+    }
+
+    #[test]
     fn fill_fields_struct_generated_by_macro() {
         check_assist(
             expand_rest_pattern,
@@ -376,7 +596,7 @@ macro_rules! position {
 position!(usize);
 
 fn macro_call(pos: Pos) {
-    let Pos { x, y  } = pos;
+    let Pos { x, y } = pos;
 }
 "#,
         );
@@ -420,7 +640,7 @@ enum_gen!(usize);
 fn macro_call(foo: Foo) {
     match foo {
         Foo::A(_) => false,
-        Foo::B{ x, y  } => true,
+        Foo::B{ x, y } => true,
     }
 }
 "#,
@@ -484,6 +704,8 @@ fn bar(foo: Foo) {
         // This is still possible even though it's meaningless
         cov_mark::check!(no_missing_fields);
         cov_mark::check!(no_missing_fields_tuple_struct);
+        cov_mark::check!(no_missing_fields_tuple);
+        cov_mark::check!(no_missing_fields_slice);
         check_assist_not_applicable(
             expand_rest_pattern,
             r#"
@@ -523,5 +745,21 @@ fn foo(bar: Bar) {
 }
 "#,
         );
+        check_assist_not_applicable(
+            expand_rest_pattern,
+            r#"
+fn foo(bar: (i32, i32)) {
+    let (y, ..$0, z) = bar;
+}
+"#,
+        );
+        check_assist_not_applicable(
+            expand_rest_pattern,
+            r#"
+fn foo(bar: [i32; 2]) {
+    let [y, ..$0, z] = bar;
+}
+"#,
+        );
     }
 }
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_variable.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_variable.rs
index bd88e8b09ce..da596262962 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_variable.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_variable.rs
@@ -285,7 +285,7 @@ fn peel_parens(mut expr: ast::Expr) -> ast::Expr {
 /// In general that's true for any expression, but in some cases that would produce invalid code.
 fn valid_target_expr(node: SyntaxNode) -> Option<ast::Expr> {
     match node.kind() {
-        SyntaxKind::PATH_EXPR | SyntaxKind::LOOP_EXPR => None,
+        SyntaxKind::PATH_EXPR | SyntaxKind::LOOP_EXPR | SyntaxKind::LET_EXPR => None,
         SyntaxKind::BREAK_EXPR => ast::BreakExpr::cast(node).and_then(|e| e.expr()),
         SyntaxKind::RETURN_EXPR => ast::ReturnExpr::cast(node).and_then(|e| e.expr()),
         SyntaxKind::BLOCK_EXPR => {
@@ -1404,6 +1404,25 @@ fn main() {
     }
 
     #[test]
+    fn extract_var_let_expr() {
+        check_assist_by_label(
+            extract_variable,
+            r#"
+fn main() {
+    if $0let$0 Some(x) = Some(2+2) {}
+}
+"#,
+            r#"
+fn main() {
+    let $0var_name = Some(2+2);
+    if let Some(x) = var_name {}
+}
+"#,
+            "Extract into variable",
+        );
+    }
+
+    #[test]
     fn extract_var_for_cast() {
         check_assist_by_label(
             extract_variable,
@@ -1739,6 +1758,14 @@ fn main() {
     }
 
     #[test]
+    fn extract_var_for_let_expr_not_applicable() {
+        check_assist_not_applicable(
+            extract_variable,
+            "fn main() { if $0let Some(x) = Some(2+2) {} }",
+        );
+    }
+
+    #[test]
     fn extract_var_unit_expr_not_applicable() {
         check_assist_not_applicable(
             extract_variable,
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_default_from_enum_variant.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_default_from_enum_variant.rs
index 6198dbc4ed9..056edb00b68 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_default_from_enum_variant.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_default_from_enum_variant.rs
@@ -39,6 +39,9 @@ pub(crate) fn generate_default_from_enum_variant(
         cov_mark::hit!(test_gen_default_on_non_unit_variant_not_implemented);
         return None;
     }
+    if !variant.syntax().text_range().contains_range(ctx.selection_trimmed()) {
+        return None;
+    }
 
     if existing_default_impl(&ctx.sema, &variant).is_some() {
         cov_mark::hit!(test_gen_default_impl_already_exists);
@@ -115,6 +118,49 @@ impl Default for Variant {
     }
 
     #[test]
+    fn test_generate_default_selected_variant() {
+        check_assist(
+            generate_default_from_enum_variant,
+            r#"
+//- minicore: default
+enum Variant {
+    Undefined,
+    $0Minor$0,
+    Major,
+}
+"#,
+            r#"
+enum Variant {
+    Undefined,
+    Minor,
+    Major,
+}
+
+impl Default for Variant {
+    fn default() -> Self {
+        Self::Minor
+    }
+}
+"#,
+        );
+    }
+
+    #[test]
+    fn test_generate_default_not_applicable_with_multiple_variant_selection() {
+        check_assist_not_applicable(
+            generate_default_from_enum_variant,
+            r#"
+//- minicore: default
+enum Variant {
+    Undefined,
+    $0Minor,
+    M$0ajor,
+}
+"#,
+        );
+    }
+
+    #[test]
     fn test_generate_default_already_implemented() {
         cov_mark::check!(test_gen_default_impl_already_exists);
         check_assist_not_applicable(
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/invert_if.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/invert_if.rs
index d198870b023..7576d2fab97 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/invert_if.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/invert_if.rs
@@ -125,6 +125,18 @@ mod tests {
     }
 
     #[test]
+    fn invert_if_doesnt_apply_with_if_let_chain() {
+        check_assist_not_applicable(
+            invert_if,
+            "fn f() { i$0f x && let Some(_) = Some(1) { 1 } else { 0 } }",
+        );
+        check_assist_not_applicable(
+            invert_if,
+            "fn f() { i$0f let Some(_) = Some(1) && x { 1 } else { 0 } }",
+        );
+    }
+
+    #[test]
     fn invert_if_option_case() {
         check_assist(
             invert_if,
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/pull_assignment_up.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/pull_assignment_up.rs
index 21debf6745a..00902fafe82 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/pull_assignment_up.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/pull_assignment_up.rs
@@ -53,6 +53,10 @@ pub(crate) fn pull_assignment_up(acc: &mut Assists, ctx: &AssistContext<'_>) ->
     };
 
     let tgt: ast::Expr = if let Some(if_expr) = ctx.find_node_at_offset::<ast::IfExpr>() {
+        let if_expr = std::iter::successors(Some(if_expr), |it| {
+            it.syntax().parent().and_then(ast::IfExpr::cast)
+        })
+        .last()?;
         collector.collect_if(&if_expr)?;
         if_expr.into()
     } else if let Some(match_expr) = ctx.find_node_at_offset::<ast::MatchExpr>() {
@@ -238,6 +242,37 @@ fn foo() {
     }
 
     #[test]
+    fn test_pull_assignment_up_inner_if() {
+        check_assist(
+            pull_assignment_up,
+            r#"
+fn foo() {
+    let mut a = 1;
+
+    if true {
+        a = 2;
+    } else if true {
+        $0a = 3;
+    } else {
+        a = 4;
+    }
+}"#,
+            r#"
+fn foo() {
+    let mut a = 1;
+
+    a = if true {
+        2
+    } else if true {
+        3
+    } else {
+        4
+    };
+}"#,
+        );
+    }
+
+    #[test]
     fn test_pull_assignment_up_match() {
         check_assist(
             pull_assignment_up,
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/remove_dbg.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/remove_dbg.rs
index 414f6746d44..08779a3ed1f 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/remove_dbg.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/remove_dbg.rs
@@ -83,7 +83,9 @@ fn compute_dbg_replacement(
     let input_expressions = input_expressions
         .into_iter()
         .filter_map(|(is_sep, group)| (!is_sep).then_some(group))
-        .map(|mut tokens| syntax::hacks::parse_expr_from_str(&tokens.join(""), Edition::CURRENT))
+        .map(|tokens| tokens.collect::<Vec<_>>())
+        .filter(|tokens| !tokens.iter().all(|it| it.kind().is_trivia()))
+        .map(|tokens| syntax::hacks::parse_expr_from_str(&tokens.iter().join(""), Edition::CURRENT))
         .collect::<Option<Vec<ast::Expr>>>()?;
 
     let parent = macro_expr.syntax().parent()?;
@@ -268,6 +270,8 @@ fn foo() {
     dbg!('x');
     dbg!(&n);
     dbg!(n);
+    dbg!(n,);
+    dbg!(n, );
     // needless comment
     dbg!("foo");$0
 }
@@ -282,6 +286,17 @@ fn foo() {
     }
 
     #[test]
+    fn test_remove_trailing_comma_dbg() {
+        check("$0dbg!(1 + 1,)", "1 + 1");
+        check("$0dbg!(1 + 1, )", "1 + 1");
+        check("$0dbg!(1 + 1,\n)", "1 + 1");
+        check("$0dbg!(1 + 1, 2 + 3)", "(1 + 1, 2 + 3)");
+        check("$0dbg!(1 + 1, 2 + 3 )", "(1 + 1, 2 + 3)");
+        check("$0dbg!(1 + 1, 2 + 3, )", "(1 + 1, 2 + 3)");
+        check("$0dbg!(1 + 1, 2 + 3 ,)", "(1 + 1, 2 + 3)");
+    }
+
+    #[test]
     fn test_remove_dbg_not_applicable() {
         check_assist_not_applicable(remove_dbg, "fn main() {$0vec![1, 2, 3]}");
         check_assist_not_applicable(remove_dbg, "fn main() {$0dbg(5, 6, 7)}");
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_arith_op.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_arith_op.rs
index 440ab4d4604..a3fb851fb0e 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_arith_op.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_arith_op.rs
@@ -1,7 +1,7 @@
 use ide_db::assists::{AssistId, GroupLabel};
 use syntax::{
-    AstNode, TextRange,
-    ast::{self, ArithOp, BinaryOp},
+    AstNode,
+    ast::{self, ArithOp, BinaryOp, syntax_factory::SyntaxFactory},
 };
 
 use crate::assist_context::{AssistContext, Assists};
@@ -71,24 +71,31 @@ pub(crate) fn replace_arith_with_wrapping(
 
 fn replace_arith(acc: &mut Assists, ctx: &AssistContext<'_>, kind: ArithKind) -> Option<()> {
     let (lhs, op, rhs) = parse_binary_op(ctx)?;
+    let op_expr = lhs.syntax().parent()?;
 
     if !is_primitive_int(ctx, &lhs) || !is_primitive_int(ctx, &rhs) {
         return None;
     }
 
-    let start = lhs.syntax().text_range().start();
-    let end = rhs.syntax().text_range().end();
-    let range = TextRange::new(start, end);
-
     acc.add_group(
         &GroupLabel("Replace arithmetic...".into()),
         kind.assist_id(),
         kind.label(),
-        range,
+        op_expr.text_range(),
         |builder| {
+            let mut edit = builder.make_editor(rhs.syntax());
+            let make = SyntaxFactory::with_mappings();
             let method_name = kind.method_name(op);
 
-            builder.replace(range, format!("{lhs}.{method_name}({rhs})"))
+            let needs_parentheses =
+                lhs.precedence().needs_parentheses_in(ast::prec::ExprPrecedence::Postfix);
+            let receiver = if needs_parentheses { make.expr_paren(lhs).into() } else { lhs };
+            let arith_expr =
+                make.expr_method_call(receiver, make.name_ref(&method_name), make.arg_list([rhs]));
+            edit.replace(op_expr, arith_expr.syntax());
+
+            edit.add_mappings(make.finish_with_mappings());
+            builder.add_file_edits(ctx.vfs_file_id(), edit);
         },
     )
 }
@@ -228,6 +235,23 @@ fn main() {
     }
 
     #[test]
+    fn replace_arith_with_wrapping_add_add_parenthesis() {
+        check_assist(
+            replace_arith_with_wrapping,
+            r#"
+fn main() {
+    let x = 1*x $0+ 2;
+}
+"#,
+            r#"
+fn main() {
+    let x = (1*x).wrapping_add(2);
+}
+"#,
+        )
+    }
+
+    #[test]
     fn replace_arith_not_applicable_with_non_empty_selection() {
         check_assist_not_applicable(
             replace_arith_with_checked,
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_if_let_with_match.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_if_let_with_match.rs
index dd244375dc9..3b815a467bc 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_if_let_with_match.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_if_let_with_match.rs
@@ -328,7 +328,14 @@ fn pick_pattern_and_expr_order(
         (pat, pat2) => match (binds_name(sema, &pat), binds_name(sema, &pat2)) {
             (true, true) => return None,
             (true, false) => (pat, guard, expr, expr2),
-            (false, true) => (pat2, guard2, expr2, expr),
+            (false, true) => {
+                // This pattern triggers an invalid transformation.
+                // See issues #11373, #19443
+                if let ast::Pat::IdentPat(_) = pat2 {
+                    return None;
+                }
+                (pat2, guard2, expr2, expr)
+            }
             _ if is_sad_pat(sema, &pat) => (pat2, guard2, expr2, expr),
             (false, false) => (pat, guard, expr, expr2),
         },
@@ -1892,4 +1899,19 @@ fn main() {
 "#,
         )
     }
+
+    #[test]
+    fn test_replace_match_with_if_let_not_applicable_pat2_is_ident_pat() {
+        check_assist_not_applicable(
+            replace_match_with_if_let,
+            r"
+fn test(a: i32) {
+    match$0 a {
+        1 => code(),
+        other => code(other),
+    }
+}
+",
+        )
+    }
 }
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_is_method_with_if_let_method.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_is_method_with_if_let_method.rs
index 5ef8ba46b9e..f507cae1bb0 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_is_method_with_if_let_method.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_is_method_with_if_let_method.rs
@@ -31,6 +31,9 @@ pub(crate) fn replace_is_method_with_if_let_method(
         ast::Expr::MethodCallExpr(call) => call,
         _ => return None,
     };
+    if ctx.offset() > if_expr.then_branch()?.stmt_list()?.l_curly_token()?.text_range().end() {
+        return None;
+    }
 
     let name_ref = call_expr.name_ref()?;
     match name_ref.text().as_str() {
@@ -191,4 +194,19 @@ fn main() {
 "#,
         );
     }
+
+    #[test]
+    fn replace_is_some_with_if_let_some_not_applicable_after_l_curly() {
+        check_assist_not_applicable(
+            replace_is_method_with_if_let_method,
+            r#"
+fn main() {
+    let x = Some(1);
+    if x.is_some() {
+        ()$0
+    }
+}
+"#,
+        );
+    }
 }
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/tests/generated.rs b/src/tools/rust-analyzer/crates/ide-assists/src/tests/generated.rs
index 91348be97eb..e7f91ff3fbc 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/tests/generated.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/tests/generated.rs
@@ -1035,7 +1035,41 @@ fn foo(bar: Bar) {
 struct Bar { y: Y, z: Z }
 
 fn foo(bar: Bar) {
-    let Bar { y, z  } = bar;
+    let Bar { y, z } = bar;
+}
+"#####,
+    )
+}
+
+#[test]
+fn doctest_expand_slice_rest_pattern() {
+    check_doc_test(
+        "expand_slice_rest_pattern",
+        r#####"
+fn foo(bar: [i32; 3]) {
+    let [first, ..$0] = bar;
+}
+"#####,
+        r#####"
+fn foo(bar: [i32; 3]) {
+    let [first, _1, _2] = bar;
+}
+"#####,
+    )
+}
+
+#[test]
+fn doctest_expand_tuple_rest_pattern() {
+    check_doc_test(
+        "expand_tuple_rest_pattern",
+        r#####"
+fn foo(bar: (char, i32, i32)) {
+    let (ch, ..$0) = bar;
+}
+"#####,
+        r#####"
+fn foo(bar: (char, i32, i32)) {
+    let (ch, _1, _2) = bar;
 }
 "#####,
     )
diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/completions.rs b/src/tools/rust-analyzer/crates/ide-completion/src/completions.rs
index e36e0e57045..eb2bb31f963 100644
--- a/src/tools/rust-analyzer/crates/ide-completion/src/completions.rs
+++ b/src/tools/rust-analyzer/crates/ide-completion/src/completions.rs
@@ -691,6 +691,9 @@ pub(super) fn complete_name(
         NameKind::RecordField => {
             field::complete_field_list_record_variant(acc, ctx);
         }
+        NameKind::TypeParam => {
+            acc.add_keyword_snippet(ctx, "const", "const $1: $0");
+        }
         NameKind::ConstParam
         | NameKind::Enum
         | NameKind::MacroDef
@@ -700,7 +703,6 @@ pub(super) fn complete_name(
         | NameKind::Static
         | NameKind::Struct
         | NameKind::Trait
-        | NameKind::TypeParam
         | NameKind::Union
         | NameKind::Variant => (),
     }
diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/completions/attribute.rs b/src/tools/rust-analyzer/crates/ide-completion/src/completions/attribute.rs
index c542e140df5..e174b0c8922 100644
--- a/src/tools/rust-analyzer/crates/ide-completion/src/completions/attribute.rs
+++ b/src/tools/rust-analyzer/crates/ide-completion/src/completions/attribute.rs
@@ -70,7 +70,7 @@ pub(crate) fn complete_known_attribute_input(
 
             lint::complete_lint(acc, ctx, colon_prefix, &existing_lints, &lints);
         }
-        ["cfg"] => cfg::complete_cfg(acc, ctx),
+        ["cfg"] | ["cfg_attr"] => cfg::complete_cfg(acc, ctx),
         ["macro_use"] => macro_use::complete_macro_use(
             acc,
             ctx,
diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/completions/attribute/cfg.rs b/src/tools/rust-analyzer/crates/ide-completion/src/completions/attribute/cfg.rs
index 1676a8467c8..b2e8efde8be 100644
--- a/src/tools/rust-analyzer/crates/ide-completion/src/completions/attribute/cfg.rs
+++ b/src/tools/rust-analyzer/crates/ide-completion/src/completions/attribute/cfg.rs
@@ -53,15 +53,33 @@ pub(crate) fn complete_cfg(acc: &mut Completions, ctx: &CompletionContext<'_>) {
                 acc.add(item.build(ctx.db));
             }),
         },
-        None => ctx.krate.potential_cfg(ctx.db).get_cfg_keys().cloned().unique().for_each(|s| {
-            let s = s.as_str();
-            let item =
-                CompletionItem::new(SymbolKind::BuiltinAttr, ctx.source_range(), s, ctx.edition);
-            acc.add(item.build(ctx.db));
-        }),
+        None => ctx
+            .krate
+            .potential_cfg(ctx.db)
+            .get_cfg_keys()
+            .unique()
+            .map(|s| (s.as_str(), ""))
+            .chain(CFG_CONDITION.iter().copied())
+            .for_each(|(s, snippet)| {
+                let mut item = CompletionItem::new(
+                    SymbolKind::BuiltinAttr,
+                    ctx.source_range(),
+                    s,
+                    ctx.edition,
+                );
+                if let Some(cap) = ctx.config.snippet_cap
+                    && !snippet.is_empty()
+                {
+                    item.insert_snippet(cap, snippet);
+                }
+                acc.add(item.build(ctx.db));
+            }),
     }
 }
 
+const CFG_CONDITION: &[(&str, &str)] =
+    &[("all", "all($0)"), ("any", "any($0)"), ("not", "not($0)")];
+
 const KNOWN_ARCH: [&str; 20] = [
     "aarch64",
     "arm",
diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/completions/expr.rs b/src/tools/rust-analyzer/crates/ide-completion/src/completions/expr.rs
index a7df0ab3863..080875e0163 100644
--- a/src/tools/rust-analyzer/crates/ide-completion/src/completions/expr.rs
+++ b/src/tools/rust-analyzer/crates/ide-completion/src/completions/expr.rs
@@ -59,6 +59,7 @@ pub(crate) fn complete_expr_path(
         in_block_expr,
         in_breakable,
         after_if_expr,
+        before_else_kw,
         in_condition,
         incomplete_let,
         after_incomplete_let,
@@ -386,7 +387,7 @@ pub(crate) fn complete_expr_path(
                         add_keyword("let", "let $1 = $0;");
                     }
 
-                    if after_if_expr || after_incomplete_let {
+                    if !before_else_kw && (after_if_expr || after_incomplete_let) {
                         add_keyword("else", "else {\n    $0\n}");
                     }
 
diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/completions/record.rs b/src/tools/rust-analyzer/crates/ide-completion/src/completions/record.rs
index 36f38a70db6..2f5abd18934 100644
--- a/src/tools/rust-analyzer/crates/ide-completion/src/completions/record.rs
+++ b/src/tools/rust-analyzer/crates/ide-completion/src/completions/record.rs
@@ -28,7 +28,11 @@ pub(crate) fn complete_record_pattern_fields(
                     record_pat.record_pat_field_list().and_then(|fl| fl.fields().next()).is_some();
 
                 match were_fields_specified {
-                    false => un.fields(ctx.db).into_iter().map(|f| (f, f.ty(ctx.db))).collect(),
+                    false => un
+                        .fields(ctx.db)
+                        .into_iter()
+                        .map(|f| (f, f.ty(ctx.db).to_type(ctx.db)))
+                        .collect(),
                     true => return,
                 }
             }
@@ -56,7 +60,11 @@ pub(crate) fn complete_record_expr_fields(
                 record_expr.record_expr_field_list().and_then(|fl| fl.fields().next()).is_some();
 
             match were_fields_specified {
-                false => un.fields(ctx.db).into_iter().map(|f| (f, f.ty(ctx.db))).collect(),
+                false => un
+                    .fields(ctx.db)
+                    .into_iter()
+                    .map(|f| (f, f.ty(ctx.db).to_type(ctx.db)))
+                    .collect(),
                 true => return,
             }
         }
diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/context.rs b/src/tools/rust-analyzer/crates/ide-completion/src/context.rs
index 007475688d2..9deaaf66312 100644
--- a/src/tools/rust-analyzer/crates/ide-completion/src/context.rs
+++ b/src/tools/rust-analyzer/crates/ide-completion/src/context.rs
@@ -144,6 +144,7 @@ pub(crate) struct PathExprCtx<'db> {
     pub(crate) in_block_expr: bool,
     pub(crate) in_breakable: BreakableKind,
     pub(crate) after_if_expr: bool,
+    pub(crate) before_else_kw: bool,
     /// Whether this expression is the direct condition of an if or while expression
     pub(crate) in_condition: bool,
     pub(crate) incomplete_let: bool,
diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/context/analysis.rs b/src/tools/rust-analyzer/crates/ide-completion/src/context/analysis.rs
index b33a547dee9..77a94403abb 100644
--- a/src/tools/rust-analyzer/crates/ide-completion/src/context/analysis.rs
+++ b/src/tools/rust-analyzer/crates/ide-completion/src/context/analysis.rs
@@ -1,6 +1,7 @@
 //! Module responsible for analyzing the code surrounding the cursor for completion.
 use std::iter;
 
+use base_db::salsa;
 use hir::{ExpandResult, InFile, Semantics, Type, TypeInfo, Variant};
 use ide_db::{RootDatabase, active_parameter::ActiveParameter};
 use itertools::Either;
@@ -85,9 +86,15 @@ pub(super) fn expand_and_analyze<'db>(
     let original_offset = expansion.original_offset + relative_offset;
     let token = expansion.original_file.token_at_offset(original_offset).left_biased()?;
 
-    analyze(sema, expansion, original_token, &token).map(|(analysis, expected, qualifier_ctx)| {
-        AnalysisResult { analysis, expected, qualifier_ctx, token, original_offset }
-    })
+    salsa::attach(sema.db, || analyze(sema, expansion, original_token, &token)).map(
+        |(analysis, expected, qualifier_ctx)| AnalysisResult {
+            analysis,
+            expected,
+            qualifier_ctx,
+            token,
+            original_offset,
+        },
+    )
 }
 
 fn token_at_offset_ignore_whitespace(file: &SyntaxNode, offset: TextSize) -> Option<SyntaxToken> {
@@ -637,6 +644,9 @@ fn expected_type_and_name<'db>(
                             .or_else(|| it.rhs().and_then(|rhs| sema.type_of_expr(&rhs)))
                             .map(TypeInfo::original);
                         (ty, None)
+                    } else if let Some(ast::BinaryOp::LogicOp(_)) = it.op_kind() {
+                        let ty = sema.type_of_expr(&it.clone().into()).map(TypeInfo::original);
+                        (ty, None)
                     } else {
                         (None, None)
                     }
@@ -707,9 +717,13 @@ fn expected_type_and_name<'db>(
                     (ty, None)
                 },
                 ast::IfExpr(it) => {
-                    let ty = it.condition()
-                        .and_then(|e| sema.type_of_expr(&e))
-                        .map(TypeInfo::original);
+                    let ty = if let Some(body) = it.then_branch()
+                        && token.text_range().end() > body.syntax().text_range().start()
+                    {
+                        sema.type_of_expr(&body.into())
+                    } else {
+                        it.condition().and_then(|e| sema.type_of_expr(&e))
+                    }.map(TypeInfo::original);
                     (ty, None)
                 },
                 ast::IdentPat(it) => {
@@ -1282,11 +1296,12 @@ fn classify_name_ref<'db>(
         let after_incomplete_let = after_incomplete_let(it.clone()).is_some();
         let incomplete_expr_stmt =
             it.parent().and_then(ast::ExprStmt::cast).map(|it| it.semicolon_token().is_none());
+        let before_else_kw = before_else_kw(it);
         let incomplete_let = it
             .parent()
             .and_then(ast::LetStmt::cast)
             .is_some_and(|it| it.semicolon_token().is_none())
-            || after_incomplete_let && incomplete_expr_stmt.unwrap_or(true) && !before_else_kw(it);
+            || after_incomplete_let && incomplete_expr_stmt.unwrap_or(true) && !before_else_kw;
         let in_value = it.parent().and_then(Either::<ast::LetStmt, ast::ArgList>::cast).is_some();
         let impl_ = fetch_immediate_impl(sema, original_file, expr.syntax());
 
@@ -1302,6 +1317,7 @@ fn classify_name_ref<'db>(
                 in_block_expr,
                 in_breakable: in_loop_body,
                 after_if_expr,
+                before_else_kw,
                 in_condition,
                 ref_expr_parent,
                 after_amp,
diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/context/tests.rs b/src/tools/rust-analyzer/crates/ide-completion/src/context/tests.rs
index 445afa75f3f..d9ec7915e3c 100644
--- a/src/tools/rust-analyzer/crates/ide-completion/src/context/tests.rs
+++ b/src/tools/rust-analyzer/crates/ide-completion/src/context/tests.rs
@@ -279,6 +279,62 @@ fn foo() {
 }
 
 #[test]
+fn expected_type_if_let_chain_bool() {
+    check_expected_type_and_name(
+        r#"
+fn foo() {
+    let f = Foo::Quux;
+    if let c = f && $0 { }
+}
+"#,
+        expect![[r#"ty: bool, name: ?"#]],
+    );
+}
+
+#[test]
+fn expected_type_if_condition() {
+    check_expected_type_and_name(
+        r#"
+fn foo() {
+    if a$0 { }
+}
+"#,
+        expect![[r#"ty: bool, name: ?"#]],
+    );
+}
+
+#[test]
+fn expected_type_if_body() {
+    check_expected_type_and_name(
+        r#"
+enum Foo { Bar, Baz, Quux }
+
+fn foo() {
+    let _: Foo = if true {
+        $0
+    };
+}
+"#,
+        expect![[r#"ty: Foo, name: ?"#]],
+    );
+
+    check_expected_type_and_name(
+        r#"
+enum Foo { Bar, Baz, Quux }
+
+fn foo() {
+    let _: Foo = if true {
+        Foo::Bar
+    } else {
+        $0
+    };
+}
+"#,
+        expect![[r#"ty: Foo, name: ?"#]],
+    );
+}
+
+#[test]
 fn expected_type_fn_ret_without_leading_char() {
     cov_mark::check!(expected_type_fn_ret_without_leading_char);
     check_expected_type_and_name(
@@ -526,3 +582,16 @@ fn foo() {
         expect![[r#"ty: State, name: ?"#]],
     );
 }
+
+#[test]
+fn expected_type_logic_op() {
+    check_expected_type_and_name(
+        r#"
+enum State { Stop }
+fn foo() {
+    true && $0;
+}
+"#,
+        expect![[r#"ty: bool, name: ?"#]],
+    );
+}
diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/render/pattern.rs b/src/tools/rust-analyzer/crates/ide-completion/src/render/pattern.rs
index 60ec1128233..312d3bd426f 100644
--- a/src/tools/rust-analyzer/crates/ide-completion/src/render/pattern.rs
+++ b/src/tools/rust-analyzer/crates/ide-completion/src/render/pattern.rs
@@ -163,6 +163,7 @@ fn render_pat(
         PatternContext {
             param_ctx: Some(ParamContext { kind: ParamKind::Function(_), .. }),
             has_type_ascription: false,
+            parent_pat: None,
             ..
         }
     );
diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/tests.rs b/src/tools/rust-analyzer/crates/ide-completion/src/tests.rs
index 809a26bf5de..b20b570c2b8 100644
--- a/src/tools/rust-analyzer/crates/ide-completion/src/tests.rs
+++ b/src/tools/rust-analyzer/crates/ide-completion/src/tests.rs
@@ -26,6 +26,7 @@ mod visibility;
 
 use base_db::{SourceDatabase, salsa};
 use expect_test::Expect;
+use hir::db::HirDatabase;
 use hir::{PrefixKind, setup_tracing};
 use ide_db::{
     FilePosition, RootDatabase, SnippetCap,
@@ -306,8 +307,11 @@ pub(crate) fn get_all_items(
     trigger_character: Option<char>,
 ) -> Vec<CompletionItem> {
     let (db, position) = position(code);
-    let res = salsa::attach(&db, || crate::completions(&db, &config, position, trigger_character))
-        .map_or_else(Vec::default, Into::into);
+    let res = salsa::attach(&db, || {
+        HirDatabase::zalsa_register_downcaster(&db);
+        crate::completions(&db, &config, position, trigger_character)
+    })
+    .map_or_else(Vec::default, Into::into);
     // validate
     res.iter().for_each(|it| {
         let sr = it.source_range;
diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/tests/attribute.rs b/src/tools/rust-analyzer/crates/ide-completion/src/tests/attribute.rs
index 46a36300459..1d2a9c7c8d3 100644
--- a/src/tools/rust-analyzer/crates/ide-completion/src/tests/attribute.rs
+++ b/src/tools/rust-analyzer/crates/ide-completion/src/tests/attribute.rs
@@ -815,7 +815,10 @@ mod cfg {
 #[cfg($0)]
 "#,
             expect![[r#"
+                ba all
+                ba any
                 ba dbg
+                ba not
                 ba opt_level
                 ba test
                 ba true
@@ -827,7 +830,74 @@ mod cfg {
 #[cfg(b$0)]
 "#,
             expect![[r#"
+                ba all
+                ba any
                 ba dbg
+                ba not
+                ba opt_level
+                ba test
+                ba true
+            "#]],
+        );
+    }
+
+    #[test]
+    fn inside_cfg_attr() {
+        check(
+            r#"
+//- /main.rs cfg:test,dbg=false,opt_level=2
+#[cfg_attr($0)]
+"#,
+            expect![[r#"
+                ba all
+                ba any
+                ba dbg
+                ba not
+                ba opt_level
+                ba test
+                ba true
+            "#]],
+        );
+        check(
+            r#"
+//- /main.rs cfg:test,dbg=false,opt_level=2
+#[cfg_attr(b$0)]
+"#,
+            expect![[r#"
+                ba all
+                ba any
+                ba dbg
+                ba not
+                ba opt_level
+                ba test
+                ba true
+            "#]],
+        );
+        check(
+            r#"
+//- /main.rs cfg:test,dbg=false,opt_level=2
+#[cfg_attr($0, allow(deprecated))]
+"#,
+            expect![[r#"
+                ba all
+                ba any
+                ba dbg
+                ba not
+                ba opt_level
+                ba test
+                ba true
+            "#]],
+        );
+        check(
+            r#"
+//- /main.rs cfg:test,dbg=false,opt_level=2
+#[cfg_attr(b$0, allow(deprecated))]
+"#,
+            expect![[r#"
+                ba all
+                ba any
+                ba dbg
+                ba not
                 ba opt_level
                 ba test
                 ba true
@@ -852,6 +922,20 @@ mod cfg {
             "#]],
         );
     }
+
+    #[test]
+    fn inside_conditional() {
+        check_edit(
+            "all",
+            r#"
+//- /main.rs cfg:test,dbg=false,opt_level=2
+#[cfg($0)]
+"#,
+            r#"
+#[cfg(all($0))]
+"#,
+        );
+    }
 }
 
 mod derive {
diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/tests/expression.rs b/src/tools/rust-analyzer/crates/ide-completion/src/tests/expression.rs
index 5cc72ef845b..98a6f95f334 100644
--- a/src/tools/rust-analyzer/crates/ide-completion/src/tests/expression.rs
+++ b/src/tools/rust-analyzer/crates/ide-completion/src/tests/expression.rs
@@ -271,8 +271,6 @@ fn complete_in_block() {
             sn macro_rules
             sn pd
             sn ppd
-            ex false
-            ex true
         "#]],
     )
 }
@@ -1668,12 +1666,138 @@ fn foo() { let x = if foo {} $0; let y = 92; }
 fn foo() { let x = if foo {} $0 else {}; }
 "#,
         expect![[r#"
-            fn foo    fn()
+            fn foo()  fn()
+            bt u32     u32
+            kw async
+            kw const
+            kw crate::
+            kw else if
+            kw enum
+            kw extern
+            kw false
+            kw fn
+            kw for
+            kw if
+            kw if let
+            kw impl
+            kw impl for
+            kw let
+            kw letm
+            kw loop
+            kw match
+            kw mod
+            kw return
+            kw self::
+            kw static
+            kw struct
+            kw trait
+            kw true
+            kw type
+            kw union
+            kw unsafe
+            kw use
+            kw while
+            kw while let
+            sn macro_rules
+            sn pd
+            sn ppd
+        "#]],
+    );
+    check(
+        r#"
+fn foo() { let x = if foo {} $0 else if true {}; }
+"#,
+        expect![[r#"
+            fn foo()  fn()
+            bt u32     u32
+            kw async
+            kw const
+            kw crate::
+            kw else if
+            kw enum
+            kw extern
+            kw false
+            kw fn
+            kw for
+            kw if
+            kw if let
+            kw impl
+            kw impl for
+            kw let
+            kw letm
+            kw loop
+            kw match
+            kw mod
+            kw return
+            kw self::
+            kw static
+            kw struct
+            kw trait
+            kw true
+            kw type
+            kw union
+            kw unsafe
+            kw use
+            kw while
+            kw while let
+            sn macro_rules
+            sn pd
+            sn ppd
+        "#]],
+    );
+    check(
+        r#"
+fn foo() { let x = if foo {} el$0 else if true {} else {}; }
+"#,
+        expect![[r#"
+            fn foo()  fn()
+            lc x        ()
+            bt u32     u32
+            kw async
+            kw const
+            kw crate::
+            kw else if
+            kw enum
+            kw extern
+            kw false
+            kw fn
+            kw for
+            kw if
+            kw if let
+            kw impl
+            kw impl for
+            kw let
+            kw letm
+            kw loop
+            kw match
+            kw mod
+            kw return
+            kw self::
+            kw static
+            kw struct
+            kw trait
+            kw true
+            kw type
+            kw union
+            kw unsafe
+            kw use
+            kw while
+            kw while let
+            sn macro_rules
+            sn pd
+            sn ppd
+        "#]],
+    );
+    check(
+        r#"
+fn foo() { let x = if foo {} $0 else if true {} else {}; }
+"#,
+        expect![[r#"
+            fn foo()  fn()
             bt u32     u32
             kw async
             kw const
             kw crate::
-            kw else
             kw else if
             kw enum
             kw extern
diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/tests/pattern.rs b/src/tools/rust-analyzer/crates/ide-completion/src/tests/pattern.rs
index 9ec27252fd7..6eb0b818d69 100644
--- a/src/tools/rust-analyzer/crates/ide-completion/src/tests/pattern.rs
+++ b/src/tools/rust-analyzer/crates/ide-completion/src/tests/pattern.rs
@@ -399,6 +399,25 @@ fn foo($0) {}
 }
 
 #[test]
+fn completes_in_fn_param_in_nested_pattern() {
+    check(
+        r#"
+struct Foo { num: u32 }
+struct Bar(Foo);
+fn foo(Bar($0)) {}
+"#,
+        expect![[r#"
+            st Bar
+            st Foo
+            bn Bar(…)        Bar($1)$0
+            bn Foo {…} Foo { num$1 }$0
+            kw mut
+            kw ref
+        "#]],
+    )
+}
+
+#[test]
 fn completes_in_closure_param() {
     check(
         r#"
diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/tests/special.rs b/src/tools/rust-analyzer/crates/ide-completion/src/tests/special.rs
index 84ddff8f617..c438ca78806 100644
--- a/src/tools/rust-analyzer/crates/ide-completion/src/tests/special.rs
+++ b/src/tools/rust-analyzer/crates/ide-completion/src/tests/special.rs
@@ -1510,3 +1510,28 @@ fn foo<T>() {
         "#]],
     );
 }
+
+#[test]
+fn fn_generic_params_const_param_snippet() {
+    check_edit("const", "fn foo<c$0>() {}", "fn foo<const $1: $0>() {}");
+    check_edit("const", "fn foo<T, c$0>() {}", "fn foo<T, const $1: $0>() {}");
+    check(
+        r#"
+fn foo<T: $0>() {}
+"#,
+        expect![[r#"
+            kw crate::
+            kw self::
+        "#]],
+    );
+    check(
+        r#"
+fn foo<const N: $0>() {}
+"#,
+        expect![[r#"
+            bt u32 u32
+            kw crate::
+            kw self::
+        "#]],
+    );
+}
diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/tests/type_pos.rs b/src/tools/rust-analyzer/crates/ide-completion/src/tests/type_pos.rs
index c7e2d058257..125e11e9e35 100644
--- a/src/tools/rust-analyzer/crates/ide-completion/src/tests/type_pos.rs
+++ b/src/tools/rust-analyzer/crates/ide-completion/src/tests/type_pos.rs
@@ -429,18 +429,18 @@ trait Tr<T> {
 impl Tr<$0
     "#,
         expect![[r#"
-            en Enum                    Enum
-            ma makro!(…) macro_rules! makro
+            en Enum                        Enum
+            ma makro!(…)     macro_rules! makro
             md module
-            sp Self       dyn Tr<{unknown}>
-            st Record                Record
-            st S                          S
-            st Tuple                  Tuple
-            st Unit                    Unit
+            sp Self dyn Tr<{unknown}> + 'static
+            st Record                    Record
+            st S                              S
+            st Tuple                      Tuple
+            st Unit                        Unit
             tt Tr
             tt Trait
-            un Union                  Union
-            bt u32                      u32
+            un Union                      Union
+            bt u32                          u32
             kw crate::
             kw self::
         "#]],
diff --git a/src/tools/rust-analyzer/crates/ide-db/src/syntax_helpers/node_ext.rs b/src/tools/rust-analyzer/crates/ide-db/src/syntax_helpers/node_ext.rs
index cefd8fd4967..e1d140730ed 100644
--- a/src/tools/rust-analyzer/crates/ide-db/src/syntax_helpers/node_ext.rs
+++ b/src/tools/rust-analyzer/crates/ide-db/src/syntax_helpers/node_ext.rs
@@ -265,10 +265,7 @@ pub fn is_pattern_cond(expr: ast::Expr) -> bool {
         ast::Expr::BinExpr(expr)
             if expr.op_kind() == Some(ast::BinaryOp::LogicOp(ast::LogicOp::And)) =>
         {
-            expr.lhs()
-                .map(is_pattern_cond)
-                .or_else(|| expr.rhs().map(is_pattern_cond))
-                .unwrap_or(false)
+            expr.lhs().map_or(false, is_pattern_cond) || expr.rhs().map_or(false, is_pattern_cond)
         }
         ast::Expr::ParenExpr(expr) => expr.expr().is_some_and(is_pattern_cond),
         ast::Expr::LetExpr(_) => true,
diff --git a/src/tools/rust-analyzer/crates/ide-db/src/syntax_helpers/suggest_name.rs b/src/tools/rust-analyzer/crates/ide-db/src/syntax_helpers/suggest_name.rs
index 995bf72dca1..2e03665765f 100644
--- a/src/tools/rust-analyzer/crates/ide-db/src/syntax_helpers/suggest_name.rs
+++ b/src/tools/rust-analyzer/crates/ide-db/src/syntax_helpers/suggest_name.rs
@@ -473,7 +473,7 @@ mod tests {
             frange.range,
             "selection is not an expression(yet contained in one)"
         );
-        let name = NameGenerator::default().for_variable(&expr, &sema);
+        let name = salsa::attach(sema.db, || NameGenerator::default().for_variable(&expr, &sema));
         assert_eq!(&name, expected);
     }
 
diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/missing_lifetime.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/missing_lifetime.rs
index 76b30745a04..b07f9e68f63 100644
--- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/missing_lifetime.rs
+++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/missing_lifetime.rs
@@ -88,4 +88,16 @@ fn bar<const F: Foo>() {}
         "#,
         );
     }
+
+    #[test]
+    fn fn_traits() {
+        check_diagnostics(
+            r#"
+//- minicore: fn
+struct WithLifetime<'a>(&'a ());
+
+fn foo<T: Fn(WithLifetime) -> WithLifetime>() {}
+        "#,
+        );
+    }
 }
diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/missing_unsafe.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/missing_unsafe.rs
index 4bb64747f5b..029ed18a4d3 100644
--- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/missing_unsafe.rs
+++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/missing_unsafe.rs
@@ -442,6 +442,49 @@ fn main() {
     }
 
     #[test]
+    fn raw_deref_on_union_field() {
+        check_diagnostics(
+            r#"
+fn main() {
+
+    union U {
+        a: u8
+    }
+    let x = U { a: 3 };
+
+    let a = &raw mut x.a;
+
+    union U1 {
+        a: u8
+    }
+    let x = U1 { a: 3 };
+
+    let a = x.a;
+         // ^^^ 💡 error: access to union field is unsafe and requires an unsafe function or block
+
+
+    let b = &raw const x.a;
+
+    let tmp = Vec::from([1, 2, 3]);
+
+    let c = &raw const tmp[x.a];
+                        // ^^^ 💡 error: access to union field is unsafe and requires an unsafe function or block
+
+    union URef {
+        p: &'static mut i32,
+    }
+
+    fn deref_union_field(u: URef) {
+        // Not an assignment but an access to the union field!
+        *(u.p) = 13;
+       // ^^^ 💡 error: access to union field is unsafe and requires an unsafe function or block
+    }
+}
+"#,
+        )
+    }
+
+    #[test]
     fn unsafe_expr_as_an_argument_of_a_method_call() {
         check_fix(
             r#"
diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unused_variables.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unused_variables.rs
index e6bbff05f7e..84e63acbc04 100644
--- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unused_variables.rs
+++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unused_variables.rs
@@ -6,7 +6,7 @@ use ide_db::{
     label::Label,
     source_change::SourceChange,
 };
-use syntax::{Edition, TextRange};
+use syntax::{AstNode, Edition, TextRange, ToSmolStr};
 
 use crate::{Diagnostic, DiagnosticCode, DiagnosticsContext};
 
@@ -24,15 +24,21 @@ pub(crate) fn unused_variables(
     }
     let diagnostic_range = ctx.sema.diagnostics_display_range(ast);
     // The range for the Actual Name. We don't want to replace the entire declaration. Using the diagnostic range causes issues within in Array Destructuring.
-    let name_range = d
-        .local
-        .primary_source(ctx.sema.db)
+    let primary_source = d.local.primary_source(ctx.sema.db);
+    let name_range = primary_source
         .name()
         .map(|v| v.syntax().original_file_range_rooted(ctx.sema.db))
         .filter(|it| {
             Some(it.file_id) == ast.file_id.file_id()
                 && diagnostic_range.range.contains_range(it.range)
         });
+    let is_shorthand_field = primary_source
+        .source
+        .value
+        .left()
+        .and_then(|name| name.syntax().parent())
+        .and_then(syntax::ast::RecordPatField::cast)
+        .is_some_and(|field| field.colon_token().is_none());
     let var_name = d.local.name(ctx.sema.db);
     Some(
         Diagnostic::new_with_syntax_node_ptr(
@@ -48,6 +54,7 @@ pub(crate) fn unused_variables(
                 it.range,
                 diagnostic_range,
                 ast.file_id.is_macro(),
+                is_shorthand_field,
                 ctx.edition,
             )
         })),
@@ -60,24 +67,24 @@ fn fixes(
     name_range: TextRange,
     diagnostic_range: FileRange,
     is_in_marco: bool,
+    is_shorthand_field: bool,
     edition: Edition,
 ) -> Option<Vec<Assist>> {
     if is_in_marco {
         return None;
     }
+    let name = var_name.display(db, edition).to_smolstr();
+    let name = name.strip_prefix("r#").unwrap_or(&name);
+    let new_name = if is_shorthand_field { format!("{name}: _{name}") } else { format!("_{name}") };
 
     Some(vec![Assist {
         id: AssistId::quick_fix("unscore_unused_variable_name"),
-        label: Label::new(format!(
-            "Rename unused {} to _{}",
-            var_name.display(db, edition),
-            var_name.display(db, edition)
-        )),
+        label: Label::new(format!("Rename unused {name} to {new_name}")),
         group: None,
         target: diagnostic_range.range,
         source_change: Some(SourceChange::from_text_edit(
             diagnostic_range.file_id,
-            TextEdit::replace(name_range, format!("_{}", var_name.display(db, edition))),
+            TextEdit::replace(name_range, new_name),
         )),
         command: None,
     }])
@@ -220,13 +227,26 @@ struct Foo { f1: i32, f2: i64 }
 fn main() {
     let f = Foo { f1: 0, f2: 0 };
     match f {
-        Foo { _f1, f2 } => {
+        Foo { f1: _f1, f2 } => {
             _ = f2;
         }
     }
 }
 "#,
         );
+
+        check_fix(
+            r#"
+fn main() {
+    let $0r#type = 2;
+}
+"#,
+            r#"
+fn main() {
+    let _type = 2;
+}
+"#,
+        );
     }
 
     #[test]
@@ -263,6 +283,46 @@ fn main() {
         );
     }
 
+    #[test]
+    fn unused_variable_in_record_field() {
+        check_fix(
+            r#"
+struct S { field : u32 }
+fn main() {
+    let s = S { field : 2 };
+    let S { field: $0x } = s
+}
+"#,
+            r#"
+struct S { field : u32 }
+fn main() {
+    let s = S { field : 2 };
+    let S { field: _x } = s
+}
+"#,
+        );
+    }
+
+    #[test]
+    fn unused_variable_in_shorthand_record_field() {
+        check_fix(
+            r#"
+struct S { field : u32 }
+fn main() {
+    let s = S { field : 2 };
+    let S { $0field } = s
+}
+"#,
+            r#"
+struct S { field : u32 }
+fn main() {
+    let s = S { field : 2 };
+    let S { field: _field } = s
+}
+"#,
+        );
+    }
+
     // regression test as we used to panic in this scenario
     #[test]
     fn unknown_struct_pattern_param_type() {
diff --git a/src/tools/rust-analyzer/crates/ide/src/goto_type_definition.rs b/src/tools/rust-analyzer/crates/ide/src/goto_type_definition.rs
index ffd144a827e..ae208fe1b56 100644
--- a/src/tools/rust-analyzer/crates/ide/src/goto_type_definition.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/goto_type_definition.rs
@@ -88,7 +88,7 @@ pub(crate) fn goto_type_definition(
                             ast::Pat(it) => sema.type_of_pat(&it)?.original,
                             ast::SelfParam(it) => sema.type_of_self(&it)?,
                             ast::Type(it) => sema.resolve_type(&it)?,
-                            ast::RecordField(it) => sema.to_def(&it)?.ty(db),
+                            ast::RecordField(it) => sema.to_def(&it)?.ty(db).to_type(db),
                             // can't match on RecordExprField directly as `ast::Expr` will match an iteration too early otherwise
                             ast::NameRef(it) => {
                                 if let Some(record_field) = ast::RecordExprField::for_name_ref(&it) {
diff --git a/src/tools/rust-analyzer/crates/ide/src/hover.rs b/src/tools/rust-analyzer/crates/ide/src/hover.rs
index 03b9b367751..c4fb6d1a5b4 100644
--- a/src/tools/rust-analyzer/crates/ide/src/hover.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/hover.rs
@@ -440,7 +440,7 @@ pub(crate) fn hover_for_definition(
         Definition::Local(it) => Some(it.ty(db)),
         Definition::GenericParam(hir::GenericParam::ConstParam(it)) => Some(it.ty(db)),
         Definition::GenericParam(hir::GenericParam::TypeParam(it)) => Some(it.ty(db)),
-        Definition::Field(field) => Some(field.ty(db)),
+        Definition::Field(field) => Some(field.ty(db).to_type(db)),
         Definition::TupleField(it) => Some(it.ty(db)),
         Definition::Function(it) => Some(it.ty(db)),
         Definition::Adt(it) => Some(it.ty(db)),
@@ -602,7 +602,7 @@ fn goto_type_action_for_def(
 
     let ty = match def {
         Definition::Local(it) => Some(it.ty(db)),
-        Definition::Field(field) => Some(field.ty(db)),
+        Definition::Field(field) => Some(field.ty(db).to_type(db)),
         Definition::TupleField(field) => Some(field.ty(db)),
         Definition::Const(it) => Some(it.ty(db)),
         Definition::Static(it) => Some(it.ty(db)),
diff --git a/src/tools/rust-analyzer/crates/ide/src/hover/render.rs b/src/tools/rust-analyzer/crates/ide/src/hover/render.rs
index 65375ed8f78..c5d695ccec3 100644
--- a/src/tools/rust-analyzer/crates/ide/src/hover/render.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/hover/render.rs
@@ -692,14 +692,14 @@ pub(super) fn definition(
         }
         let drop_info = match def {
             Definition::Field(field) => {
-                DropInfo { drop_glue: field.ty(db).drop_glue(db), has_dtor: None }
+                DropInfo { drop_glue: field.ty(db).to_type(db).drop_glue(db), has_dtor: None }
             }
             Definition::Adt(Adt::Struct(strukt)) => {
                 let struct_drop_glue = strukt.ty_placeholders(db).drop_glue(db);
                 let mut fields_drop_glue = strukt
                     .fields(db)
                     .iter()
-                    .map(|field| field.ty(db).drop_glue(db))
+                    .map(|field| field.ty(db).to_type(db).drop_glue(db))
                     .max()
                     .unwrap_or(DropGlue::None);
                 let has_dtor = match (fields_drop_glue, struct_drop_glue) {
@@ -727,7 +727,7 @@ pub(super) fn definition(
                         variant
                             .fields(db)
                             .iter()
-                            .map(|field| field.ty(db).drop_glue(db))
+                            .map(|field| field.ty(db).to_type(db).drop_glue(db))
                             .max()
                             .unwrap_or(DropGlue::None)
                     })
@@ -742,7 +742,7 @@ pub(super) fn definition(
                 let fields_drop_glue = variant
                     .fields(db)
                     .iter()
-                    .map(|field| field.ty(db).drop_glue(db))
+                    .map(|field| field.ty(db).to_type(db).drop_glue(db))
                     .max()
                     .unwrap_or(DropGlue::None);
                 DropInfo { drop_glue: fields_drop_glue, has_dtor: None }
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 1ea11a215f8..8bc0b3f6ab3 100644
--- a/src/tools/rust-analyzer/crates/ide/src/hover/tests.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/hover/tests.rs
@@ -4797,6 +4797,48 @@ fn main() {
 }
 
 #[test]
+fn const_generic_negative_literal_macro_expansion() {
+    // Test that negative literals work correctly in const generics
+    // when used through macro expansion. This ensures the transcriber
+    // doesn't wrap negative literals in parentheses, which would create
+    // invalid syntax like Foo::<(-1)> instead of Foo::<-1>.
+    check(
+        r#"
+struct Foo<const I: i16> {
+    pub value: i16,
+}
+
+impl<const I: i16> Foo<I> {
+    pub fn new(value: i16) -> Self {
+        Self { value }
+    }
+}
+
+macro_rules! create_foo {
+    ($val:expr) => {
+        Foo::<$val>::new($val)
+    };
+}
+
+fn main() {
+    let v$0alue = create_foo!(-1);
+}
+"#,
+        expect![[r#"
+            *value*
+
+            ```rust
+            let value: Foo<-1>
+            ```
+
+            ---
+
+            size = 2, align = 2, no Drop
+        "#]],
+    );
+}
+
+#[test]
 fn hover_self_param_shows_type() {
     check(
         r#"
diff --git a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/bind_pat.rs b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/bind_pat.rs
index 104740cbbf7..b7c12413960 100644
--- a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/bind_pat.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/bind_pat.rs
@@ -380,7 +380,7 @@ fn main() {
     let foo = foo4();
      // ^^^ &dyn Fn(f64, f64) -> u32
     let foo = foo5();
-     // ^^^ &dyn Fn(&dyn Fn(f64, f64) -> u32, f64) -> u32
+     // ^^^ &dyn Fn(&(dyn Fn(f64, f64) -> u32 + 'static), f64) -> u32
     let foo = foo6();
      // ^^^ impl Fn(f64, f64) -> u32
     let foo = foo7();
diff --git a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/closing_brace.rs b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/closing_brace.rs
index e80c9dc9d47..9d246eda57e 100644
--- a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/closing_brace.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/closing_brace.rs
@@ -191,7 +191,7 @@ impl Tr for () {
 //^ impl Tr for ()
 impl dyn Tr {
   }
-//^ impl dyn Tr
+//^ impl dyn Tr + 'static
 
 static S0: () = 0;
 static S1: () = {};
diff --git a/src/tools/rust-analyzer/crates/ide/src/signature_help.rs b/src/tools/rust-analyzer/crates/ide/src/signature_help.rs
index f45d096ac19..e74d997e97c 100644
--- a/src/tools/rust-analyzer/crates/ide/src/signature_help.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/signature_help.rs
@@ -526,7 +526,7 @@ fn signature_help_for_tuple_struct_pat(
         pat.syntax(),
         token,
         pat.fields(),
-        fields.into_iter().map(|it| it.ty(db)),
+        fields.into_iter().map(|it| it.ty(db).to_type(db)),
         display_target,
     ))
 }
diff --git a/src/tools/rust-analyzer/crates/ide/src/static_index.rs b/src/tools/rust-analyzer/crates/ide/src/static_index.rs
index 8214b4d1de2..9911b85799b 100644
--- a/src/tools/rust-analyzer/crates/ide/src/static_index.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/static_index.rs
@@ -278,7 +278,7 @@ impl StaticIndex<'_> {
         for token in tokens {
             let range = token.text_range();
             let node = token.parent().unwrap();
-            match get_definitions(&sema, token.clone()) {
+            match salsa::attach(self.db, || get_definitions(&sema, token.clone())) {
                 Some(it) => {
                     for i in it {
                         add_token(i, range, &node);
diff --git a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_unsafe.html b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_unsafe.html
index 828b8f762c5..8339daf3246 100644
--- a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_unsafe.html
+++ b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_unsafe.html
@@ -96,7 +96,7 @@ pre                 { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
 
         <span class="variable">u</span><span class="operator">.</span><span class="field unsafe">field</span><span class="semicolon">;</span>
         <span class="operator">&</span><span class="variable">u</span><span class="operator">.</span><span class="field unsafe">field</span><span class="semicolon">;</span>
-        <span class="operator">&</span><span class="keyword">raw</span> <span class="keyword const">const</span> <span class="variable">u</span><span class="operator">.</span><span class="field unsafe">field</span><span class="semicolon">;</span>
+        <span class="operator">&</span><span class="keyword">raw</span> <span class="keyword const">const</span> <span class="variable">u</span><span class="operator">.</span><span class="field">field</span><span class="semicolon">;</span>
         <span class="comment">// this should be safe!</span>
         <span class="keyword">let</span> <span class="union">Union</span> <span class="brace">{</span> <span class="field">field</span><span class="colon">:</span> <span class="punctuation">_</span> <span class="brace">}</span><span class="semicolon">;</span>
         <span class="comment">// but not these</span>
diff --git a/src/tools/rust-analyzer/crates/ide/src/view_memory_layout.rs b/src/tools/rust-analyzer/crates/ide/src/view_memory_layout.rs
index 950f3f6c647..ddd58a0a3c9 100644
--- a/src/tools/rust-analyzer/crates/ide/src/view_memory_layout.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/view_memory_layout.rs
@@ -94,14 +94,14 @@ pub(crate) fn view_memory_layout(
     let def = get_definition(&sema, token)?;
 
     let ty = match def {
-        Definition::Adt(it) => it.ty(db),
-        Definition::TypeAlias(it) => it.ty(db),
+        Definition::Adt(it) => salsa::attach(db, || it.ty(db)),
+        Definition::TypeAlias(it) => salsa::attach(db, || it.ty(db)),
         Definition::BuiltinType(it) => it.ty(db),
         Definition::SelfType(it) => it.self_ty(db),
         Definition::Local(it) => it.ty(db),
-        Definition::Field(it) => it.ty(db),
-        Definition::Const(it) => it.ty(db),
-        Definition::Static(it) => it.ty(db),
+        Definition::Field(it) => salsa::attach(db, || it.ty(db).to_type(db)),
+        Definition::Const(it) => salsa::attach(db, || it.ty(db)),
+        Definition::Static(it) => salsa::attach(db, || it.ty(db)),
         _ => return None,
     };
 
diff --git a/src/tools/rust-analyzer/crates/intern/src/symbol/symbols.rs b/src/tools/rust-analyzer/crates/intern/src/symbol/symbols.rs
index 1db4f8ecd6b..920bdd9568f 100644
--- a/src/tools/rust-analyzer/crates/intern/src/symbol/symbols.rs
+++ b/src/tools/rust-analyzer/crates/intern/src/symbol/symbols.rs
@@ -516,4 +516,5 @@ define_symbols! {
     flags,
     precision,
     width,
+    never_type_fallback,
 }
diff --git a/src/tools/rust-analyzer/crates/mbe/src/expander/transcriber.rs b/src/tools/rust-analyzer/crates/mbe/src/expander/transcriber.rs
index 2c046df10f5..3e4ab8bdc1d 100644
--- a/src/tools/rust-analyzer/crates/mbe/src/expander/transcriber.rs
+++ b/src/tools/rust-analyzer/crates/mbe/src/expander/transcriber.rs
@@ -401,7 +401,19 @@ fn expand_var(
                     let sub = sub.strip_invisible();
                     let mut span = id;
                     marker(&mut span);
-                    let wrap_in_parens = !matches!(sub.flat_tokens(), [tt::TokenTree::Leaf(_)])
+
+                    // Check if this is a simple negative literal (MINUS + LITERAL)
+                    // that should not be wrapped in parentheses
+                    let is_negative_literal = matches!(
+                        sub.flat_tokens(),
+                        [
+                            tt::TokenTree::Leaf(tt::Leaf::Punct(tt::Punct { char: '-', .. })),
+                            tt::TokenTree::Leaf(tt::Leaf::Literal(_))
+                        ]
+                    );
+
+                    let wrap_in_parens = !is_negative_literal
+                        && !matches!(sub.flat_tokens(), [tt::TokenTree::Leaf(_)])
                         && sub.try_into_subtree().is_none_or(|it| {
                             it.top_subtree().delimiter.kind == tt::DelimiterKind::Invisible
                         });
diff --git a/src/tools/rust-analyzer/crates/project-model/src/build_dependencies.rs b/src/tools/rust-analyzer/crates/project-model/src/build_dependencies.rs
index 203173c11be..5eda5af3ace 100644
--- a/src/tools/rust-analyzer/crates/project-model/src/build_dependencies.rs
+++ b/src/tools/rust-analyzer/crates/project-model/src/build_dependencies.rs
@@ -9,7 +9,7 @@
 use std::{cell::RefCell, io, mem, process::Command};
 
 use base_db::Env;
-use cargo_metadata::{Message, camino::Utf8Path};
+use cargo_metadata::{Message, PackageId, camino::Utf8Path};
 use cfg::CfgAtom;
 use itertools::Itertools;
 use la_arena::ArenaMap;
@@ -18,6 +18,7 @@ use rustc_hash::{FxHashMap, FxHashSet};
 use serde::Deserialize as _;
 use stdx::never;
 use toolchain::Tool;
+use triomphe::Arc;
 
 use crate::{
     CargoConfig, CargoFeatures, CargoWorkspace, InvocationStrategy, ManifestPath, Package, Sysroot,
@@ -284,7 +285,7 @@ impl WorkspaceBuildScripts {
         // NB: Cargo.toml could have been modified between `cargo metadata` and
         // `cargo check`. We shouldn't assume that package ids we see here are
         // exactly those from `config`.
-        let mut by_id: FxHashMap<String, Package> = FxHashMap::default();
+        let mut by_id: FxHashMap<Arc<PackageId>, Package> = FxHashMap::default();
         for package in workspace.packages() {
             outputs.insert(package, BuildScriptOutput::default());
             by_id.insert(workspace[package].id.clone(), package);
@@ -323,7 +324,7 @@ impl WorkspaceBuildScripts {
         // ideally this would be something like:
         // with_output_for: impl FnMut(&str, dyn FnOnce(&mut BuildScriptOutput)),
         // but owned trait objects aren't a thing
-        mut with_output_for: impl FnMut(&str, &mut dyn FnMut(&str, &mut BuildScriptOutput)),
+        mut with_output_for: impl FnMut(&PackageId, &mut dyn FnMut(&str, &mut BuildScriptOutput)),
         progress: &dyn Fn(String),
     ) -> io::Result<Option<String>> {
         let errors = RefCell::new(String::new());
@@ -346,7 +347,7 @@ impl WorkspaceBuildScripts {
 
                 match message {
                     Message::BuildScriptExecuted(mut message) => {
-                        with_output_for(&message.package_id.repr, &mut |name, data| {
+                        with_output_for(&message.package_id, &mut |name, data| {
                             progress(format!("build script {name} run"));
                             let cfgs = {
                                 let mut acc = Vec::new();
@@ -377,7 +378,7 @@ impl WorkspaceBuildScripts {
                         });
                     }
                     Message::CompilerArtifact(message) => {
-                        with_output_for(&message.package_id.repr, &mut |name, data| {
+                        with_output_for(&message.package_id, &mut |name, data| {
                             progress(format!("proc-macro {name} built"));
                             if data.proc_macro_dylib_path == ProcMacroDylibPath::NotBuilt {
                                 data.proc_macro_dylib_path = ProcMacroDylibPath::NotProcMacro;
diff --git a/src/tools/rust-analyzer/crates/project-model/src/cargo_workspace.rs b/src/tools/rust-analyzer/crates/project-model/src/cargo_workspace.rs
index e613fd590c7..adc0cc50941 100644
--- a/src/tools/rust-analyzer/crates/project-model/src/cargo_workspace.rs
+++ b/src/tools/rust-analyzer/crates/project-model/src/cargo_workspace.rs
@@ -5,7 +5,7 @@ use std::str::from_utf8;
 
 use anyhow::Context;
 use base_db::Env;
-use cargo_metadata::{CargoOpt, MetadataCommand};
+use cargo_metadata::{CargoOpt, MetadataCommand, PackageId};
 use la_arena::{Arena, Idx};
 use paths::{AbsPath, AbsPathBuf, Utf8Path, Utf8PathBuf};
 use rustc_hash::{FxHashMap, FxHashSet};
@@ -14,6 +14,7 @@ use serde_json::from_value;
 use span::Edition;
 use stdx::process::spawn_with_streaming_output;
 use toolchain::Tool;
+use triomphe::Arc;
 
 use crate::cargo_config_file::make_lockfile_copy;
 use crate::{CfgOverrides, InvocationStrategy};
@@ -155,8 +156,8 @@ pub struct PackageData {
     pub features: FxHashMap<String, Vec<String>>,
     /// List of features enabled on this package
     pub active_features: Vec<String>,
-    /// String representation of package id
-    pub id: String,
+    /// Package id
+    pub id: Arc<PackageId>,
     /// Authors as given in the `Cargo.toml`
     pub authors: Vec<String>,
     /// Description as given in the `Cargo.toml`
@@ -173,6 +174,10 @@ pub struct PackageData {
     pub rust_version: Option<semver::Version>,
     /// The contents of [package.metadata.rust-analyzer]
     pub metadata: RustAnalyzerPackageMetaData,
+    /// If this package is a member of the workspace, store all direct and transitive
+    /// dependencies as long as they are workspace members, to track dependency relationships
+    /// between members.
+    pub all_member_deps: Option<FxHashSet<Package>>,
 }
 
 #[derive(Deserialize, Default, Debug, Clone, Eq, PartialEq)]
@@ -334,6 +339,8 @@ impl CargoWorkspace {
         let mut is_virtual_workspace = true;
         let mut requires_rustc_private = false;
 
+        let mut members = FxHashSet::default();
+
         meta.packages.sort_by(|a, b| a.id.cmp(&b.id));
         for meta_pkg in meta.packages {
             let cargo_metadata::Package {
@@ -356,6 +363,7 @@ impl CargoWorkspace {
                 rust_version,
                 ..
             } = meta_pkg;
+            let id = Arc::new(id);
             let meta = from_value::<PackageMetadata>(metadata).unwrap_or_default();
             let edition = match edition {
                 cargo_metadata::Edition::E2015 => Edition::Edition2015,
@@ -375,7 +383,7 @@ impl CargoWorkspace {
             let manifest = ManifestPath::try_from(AbsPathBuf::assert(manifest_path)).unwrap();
             is_virtual_workspace &= manifest != ws_manifest_path;
             let pkg = packages.alloc(PackageData {
-                id: id.repr.clone(),
+                id: id.clone(),
                 name: name.to_string(),
                 version,
                 manifest: manifest.clone(),
@@ -395,7 +403,11 @@ impl CargoWorkspace {
                 features: features.into_iter().collect(),
                 active_features: Vec::new(),
                 metadata: meta.rust_analyzer.unwrap_or_default(),
+                all_member_deps: None,
             });
+            if is_member {
+                members.insert(pkg);
+            }
             let pkg_data = &mut packages[pkg];
             requires_rustc_private |= pkg_data.metadata.rustc_private;
             pkg_by_id.insert(id, pkg);
@@ -440,6 +452,43 @@ impl CargoWorkspace {
                 .extend(node.features.into_iter().map(|it| it.to_string()));
         }
 
+        fn saturate_all_member_deps(
+            packages: &mut Arena<PackageData>,
+            to_visit: Package,
+            visited: &mut FxHashSet<Package>,
+            members: &FxHashSet<Package>,
+        ) {
+            let pkg_data = &mut packages[to_visit];
+
+            if !visited.insert(to_visit) {
+                return;
+            }
+
+            let deps: Vec<_> = pkg_data
+                .dependencies
+                .iter()
+                .filter_map(|dep| {
+                    let pkg = dep.pkg;
+                    if members.contains(&pkg) { Some(pkg) } else { None }
+                })
+                .collect();
+
+            let mut all_member_deps = FxHashSet::from_iter(deps.iter().copied());
+            for dep in deps {
+                saturate_all_member_deps(packages, dep, visited, members);
+                if let Some(transitives) = &packages[dep].all_member_deps {
+                    all_member_deps.extend(transitives);
+                }
+            }
+
+            packages[to_visit].all_member_deps = Some(all_member_deps);
+        }
+
+        let mut visited = FxHashSet::default();
+        for member in members.iter() {
+            saturate_all_member_deps(&mut packages, *member, &mut visited, &members);
+        }
+
         CargoWorkspace {
             packages,
             targets,
diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/config.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/config.rs
index 6b489d51143..a88d228fcb6 100644
--- a/src/tools/rust-analyzer/crates/rust-analyzer/src/config.rs
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/config.rs
@@ -267,6 +267,8 @@ config_data! {
         inlayHints_lifetimeElisionHints_useParameterNames: bool = false,
 
         /// Maximum length for inlay hints. Set to null to have an unlimited length.
+        ///
+        /// **Note:** This is mostly a hint, and we don't guarantee to strictly follow the limit.
         inlayHints_maxLength: Option<usize> = Some(25),
 
         /// Show function parameter name inlay hints at the call site.
diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/diagnostics.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/diagnostics.rs
index ee50237c405..4bfad98b399 100644
--- a/src/tools/rust-analyzer/crates/rust-analyzer/src/diagnostics.rs
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/diagnostics.rs
@@ -120,6 +120,29 @@ impl DiagnosticCollection {
         }
     }
 
+    pub(crate) fn clear_check_older_than_for_package(
+        &mut self,
+        flycheck_id: usize,
+        package_id: Arc<PackageId>,
+        generation: DiagnosticsGeneration,
+    ) {
+        let Some(check) = self.check.get_mut(flycheck_id) else {
+            return;
+        };
+        let package_id = Some(package_id);
+        let Some((_, checks)) = check
+            .per_package
+            .extract_if(|k, v| *k == package_id && v.generation < generation)
+            .next()
+        else {
+            return;
+        };
+        self.changes.extend(checks.per_file.into_keys());
+        if let Some(fixes) = Arc::make_mut(&mut self.check_fixes).get_mut(flycheck_id) {
+            fixes.remove(&package_id);
+        }
+    }
+
     pub(crate) fn clear_native_for(&mut self, file_id: FileId) {
         self.native_syntax.remove(&file_id);
         self.native_semantic.remove(&file_id);
diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/flycheck.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/flycheck.rs
index 315c45d5b63..cded34be14a 100644
--- a/src/tools/rust-analyzer/crates/rust-analyzer/src/flycheck.rs
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/flycheck.rs
@@ -180,17 +180,27 @@ impl FlycheckHandle {
     pub(crate) fn restart_workspace(&self, saved_file: Option<AbsPathBuf>) {
         let generation = self.generation.fetch_add(1, Ordering::Relaxed) + 1;
         self.sender
-            .send(StateChange::Restart { generation, package: None, saved_file, target: None })
+            .send(StateChange::Restart {
+                generation,
+                scope: FlycheckScope::Workspace,
+                saved_file,
+                target: None,
+            })
             .unwrap();
     }
 
     /// Schedule a re-start of the cargo check worker to do a package wide check.
-    pub(crate) fn restart_for_package(&self, package: String, target: Option<Target>) {
+    pub(crate) fn restart_for_package(
+        &self,
+        package: Arc<PackageId>,
+        target: Option<Target>,
+        workspace_deps: Option<FxHashSet<Arc<PackageId>>>,
+    ) {
         let generation = self.generation.fetch_add(1, Ordering::Relaxed) + 1;
         self.sender
             .send(StateChange::Restart {
                 generation,
-                package: Some(package),
+                scope: FlycheckScope::Package { package, workspace_deps },
                 saved_file: None,
                 target,
             })
@@ -213,8 +223,13 @@ impl FlycheckHandle {
 
 #[derive(Debug)]
 pub(crate) enum ClearDiagnosticsKind {
-    All,
-    OlderThan(DiagnosticsGeneration),
+    All(ClearScope),
+    OlderThan(DiagnosticsGeneration, ClearScope),
+}
+
+#[derive(Debug)]
+pub(crate) enum ClearScope {
+    Workspace,
     Package(Arc<PackageId>),
 }
 
@@ -275,10 +290,15 @@ pub(crate) enum Progress {
     DidFailToRestart(String),
 }
 
+enum FlycheckScope {
+    Workspace,
+    Package { package: Arc<PackageId>, workspace_deps: Option<FxHashSet<Arc<PackageId>>> },
+}
+
 enum StateChange {
     Restart {
         generation: DiagnosticsGeneration,
-        package: Option<String>,
+        scope: FlycheckScope,
         saved_file: Option<AbsPathBuf>,
         target: Option<Target>,
     },
@@ -298,6 +318,7 @@ struct FlycheckActor {
     /// or the project root of the project.
     root: Arc<AbsPathBuf>,
     sysroot_root: Option<AbsPathBuf>,
+    scope: FlycheckScope,
     /// CargoHandle exists to wrap around the communication needed to be able to
     /// run `cargo check` without blocking. Currently the Rust standard library
     /// doesn't provide a way to read sub-process output without blocking, so we
@@ -343,6 +364,7 @@ impl FlycheckActor {
             config,
             sysroot_root,
             root: Arc::new(workspace_root),
+            scope: FlycheckScope::Workspace,
             manifest_path,
             command_handle: None,
             command_receiver: None,
@@ -376,7 +398,7 @@ impl FlycheckActor {
                 }
                 Event::RequestStateChange(StateChange::Restart {
                     generation,
-                    package,
+                    scope,
                     saved_file,
                     target,
                 }) => {
@@ -389,11 +411,11 @@ impl FlycheckActor {
                         }
                     }
 
+                    let command = self.check_command(&scope, saved_file.as_deref(), target);
+                    self.scope = scope;
                     self.generation = generation;
 
-                    let Some(command) =
-                        self.check_command(package.as_deref(), saved_file.as_deref(), target)
-                    else {
+                    let Some(command) = command else {
                         continue;
                     };
 
@@ -435,19 +457,55 @@ impl FlycheckActor {
                         tracing::trace!(flycheck_id = self.id, "clearing diagnostics");
                         // We finished without receiving any diagnostics.
                         // Clear everything for good measure
-                        self.send(FlycheckMessage::ClearDiagnostics {
-                            id: self.id,
-                            kind: ClearDiagnosticsKind::All,
-                        });
+                        match &self.scope {
+                            FlycheckScope::Workspace => {
+                                self.send(FlycheckMessage::ClearDiagnostics {
+                                    id: self.id,
+                                    kind: ClearDiagnosticsKind::All(ClearScope::Workspace),
+                                });
+                            }
+                            FlycheckScope::Package { package, workspace_deps } => {
+                                for pkg in
+                                    std::iter::once(package).chain(workspace_deps.iter().flatten())
+                                {
+                                    self.send(FlycheckMessage::ClearDiagnostics {
+                                        id: self.id,
+                                        kind: ClearDiagnosticsKind::All(ClearScope::Package(
+                                            pkg.clone(),
+                                        )),
+                                    });
+                                }
+                            }
+                        }
                     } else if res.is_ok() {
                         // We clear diagnostics for packages on
                         // `[CargoCheckMessage::CompilerArtifact]` but there seem to be setups where
                         // cargo may not report an artifact to our runner at all. To handle such
                         // cases, clear stale diagnostics when flycheck completes successfully.
-                        self.send(FlycheckMessage::ClearDiagnostics {
-                            id: self.id,
-                            kind: ClearDiagnosticsKind::OlderThan(self.generation),
-                        });
+                        match &self.scope {
+                            FlycheckScope::Workspace => {
+                                self.send(FlycheckMessage::ClearDiagnostics {
+                                    id: self.id,
+                                    kind: ClearDiagnosticsKind::OlderThan(
+                                        self.generation,
+                                        ClearScope::Workspace,
+                                    ),
+                                });
+                            }
+                            FlycheckScope::Package { package, workspace_deps } => {
+                                for pkg in
+                                    std::iter::once(package).chain(workspace_deps.iter().flatten())
+                                {
+                                    self.send(FlycheckMessage::ClearDiagnostics {
+                                        id: self.id,
+                                        kind: ClearDiagnosticsKind::OlderThan(
+                                            self.generation,
+                                            ClearScope::Package(pkg.clone()),
+                                        ),
+                                    });
+                                }
+                            }
+                        }
                     }
                     self.clear_diagnostics_state();
 
@@ -475,7 +533,7 @@ impl FlycheckActor {
                             );
                             self.send(FlycheckMessage::ClearDiagnostics {
                                 id: self.id,
-                                kind: ClearDiagnosticsKind::Package(package_id),
+                                kind: ClearDiagnosticsKind::All(ClearScope::Package(package_id)),
                             });
                         }
                     }
@@ -498,7 +556,9 @@ impl FlycheckActor {
                                 );
                                 self.send(FlycheckMessage::ClearDiagnostics {
                                     id: self.id,
-                                    kind: ClearDiagnosticsKind::Package(package_id.clone()),
+                                    kind: ClearDiagnosticsKind::All(ClearScope::Package(
+                                        package_id.clone(),
+                                    )),
                                 });
                             }
                         } else if self.diagnostics_received
@@ -507,7 +567,7 @@ impl FlycheckActor {
                             self.diagnostics_received = DiagnosticsReceived::YesAndClearedForAll;
                             self.send(FlycheckMessage::ClearDiagnostics {
                                 id: self.id,
-                                kind: ClearDiagnosticsKind::All,
+                                kind: ClearDiagnosticsKind::All(ClearScope::Workspace),
                             });
                         }
                         self.send(FlycheckMessage::AddDiagnostic {
@@ -548,7 +608,7 @@ impl FlycheckActor {
     /// return None.
     fn check_command(
         &self,
-        package: Option<&str>,
+        scope: &FlycheckScope,
         saved_file: Option<&AbsPath>,
         target: Option<Target>,
     ) -> Option<Command> {
@@ -564,9 +624,9 @@ impl FlycheckActor {
                 }
                 cmd.arg(command);
 
-                match package {
-                    Some(pkg) => cmd.arg("-p").arg(pkg),
-                    None => cmd.arg("--workspace"),
+                match scope {
+                    FlycheckScope::Workspace => cmd.arg("--workspace"),
+                    FlycheckScope::Package { package, .. } => cmd.arg("-p").arg(&package.repr),
                 };
 
                 if let Some(tgt) = target {
diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/global_state.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/global_state.rs
index 89d6fb8edc2..ce6644f725c 100644
--- a/src/tools/rust-analyzer/crates/rust-analyzer/src/global_state.rs
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/global_state.rs
@@ -9,6 +9,7 @@ use std::{
     time::{Duration, Instant},
 };
 
+use cargo_metadata::PackageId;
 use crossbeam_channel::{Receiver, Sender, unbounded};
 use hir::ChangeWithProcMacros;
 use ide::{Analysis, AnalysisHost, Cancellable, FileId, SourceRootId};
@@ -784,6 +785,7 @@ impl GlobalStateSnapshot {
                         cargo_toml: package_data.manifest.clone(),
                         crate_id,
                         package: cargo.package_flag(package_data),
+                        package_id: package_data.id.clone(),
                         target: target_data.name.clone(),
                         target_kind: target_data.kind,
                         required_features: target_data.required_features.clone(),
@@ -812,6 +814,27 @@ impl GlobalStateSnapshot {
         None
     }
 
+    pub(crate) fn all_workspace_dependencies_for_package(
+        &self,
+        package: &Arc<PackageId>,
+    ) -> Option<FxHashSet<Arc<PackageId>>> {
+        for workspace in self.workspaces.iter() {
+            match &workspace.kind {
+                ProjectWorkspaceKind::Cargo { cargo, .. }
+                | ProjectWorkspaceKind::DetachedFile { cargo: Some((cargo, _, _)), .. } => {
+                    let package = cargo.packages().find(|p| cargo[*p].id == *package)?;
+
+                    return cargo[package]
+                        .all_member_deps
+                        .as_ref()
+                        .map(|deps| deps.iter().map(|dep| cargo[*dep].id.clone()).collect());
+                }
+                _ => {}
+            }
+        }
+        None
+    }
+
     pub(crate) fn file_exists(&self, file_id: FileId) -> bool {
         self.vfs.read().0.exists(file_id)
     }
diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/handlers/notification.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/handlers/notification.rs
index 68c91a65394..87be09dcbd2 100644
--- a/src/tools/rust-analyzer/crates/rust-analyzer/src/handlers/notification.rs
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/handlers/notification.rs
@@ -331,7 +331,7 @@ fn run_flycheck(state: &mut GlobalState, vfs_path: VfsPath) -> bool {
                         let target = TargetSpec::for_file(&world, file_id)?.and_then(|it| {
                             let tgt_kind = it.target_kind();
                             let (tgt_name, root, package) = match it {
-                                TargetSpec::Cargo(c) => (c.target, c.workspace_root, c.package),
+                                TargetSpec::Cargo(c) => (c.target, c.workspace_root, c.package_id),
                                 _ => return None,
                             };
 
@@ -368,7 +368,13 @@ fn run_flycheck(state: &mut GlobalState, vfs_path: VfsPath) -> bool {
                                         _ => false,
                                     });
                                 if let Some(idx) = package_workspace_idx {
-                                    world.flycheck[idx].restart_for_package(package, target);
+                                    let workspace_deps =
+                                        world.all_workspace_dependencies_for_package(&package);
+                                    world.flycheck[idx].restart_for_package(
+                                        package,
+                                        target,
+                                        workspace_deps,
+                                    );
                                 }
                             }
                         }
diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/main_loop.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/main_loop.rs
index c6762f31832..3e80e8b7bdf 100644
--- a/src/tools/rust-analyzer/crates/rust-analyzer/src/main_loop.rs
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/main_loop.rs
@@ -20,7 +20,7 @@ use crate::{
     config::Config,
     diagnostics::{DiagnosticsGeneration, NativeDiagnosticsFetchKind, fetch_native_diagnostics},
     discover::{DiscoverArgument, DiscoverCommand, DiscoverProjectMessage},
-    flycheck::{self, ClearDiagnosticsKind, FlycheckMessage},
+    flycheck::{self, ClearDiagnosticsKind, ClearScope, FlycheckMessage},
     global_state::{
         FetchBuildDataResponse, FetchWorkspaceRequest, FetchWorkspaceResponse, GlobalState,
         file_id_to_url, url_to_file_id,
@@ -1042,17 +1042,22 @@ impl GlobalState {
                     };
                 }
             }
-            FlycheckMessage::ClearDiagnostics { id, kind: ClearDiagnosticsKind::All } => {
-                self.diagnostics.clear_check(id)
-            }
             FlycheckMessage::ClearDiagnostics {
                 id,
-                kind: ClearDiagnosticsKind::OlderThan(generation),
-            } => self.diagnostics.clear_check_older_than(id, generation),
+                kind: ClearDiagnosticsKind::All(ClearScope::Workspace),
+            } => self.diagnostics.clear_check(id),
             FlycheckMessage::ClearDiagnostics {
                 id,
-                kind: ClearDiagnosticsKind::Package(package_id),
+                kind: ClearDiagnosticsKind::All(ClearScope::Package(package_id)),
             } => self.diagnostics.clear_check_for_package(id, package_id),
+            FlycheckMessage::ClearDiagnostics {
+                id,
+                kind: ClearDiagnosticsKind::OlderThan(generation, ClearScope::Workspace),
+            } => self.diagnostics.clear_check_older_than(id, generation),
+            FlycheckMessage::ClearDiagnostics {
+                id,
+                kind: ClearDiagnosticsKind::OlderThan(generation, ClearScope::Package(package_id)),
+            } => self.diagnostics.clear_check_older_than_for_package(id, package_id, generation),
             FlycheckMessage::Progress { id, progress } => {
                 let (state, message) = match progress {
                     flycheck::Progress::DidStart => (Progress::Begin, None),
diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/target_spec.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/target_spec.rs
index 7132e09146e..e532d155536 100644
--- a/src/tools/rust-analyzer/crates/rust-analyzer/src/target_spec.rs
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/target_spec.rs
@@ -2,12 +2,14 @@
 
 use std::mem;
 
+use cargo_metadata::PackageId;
 use cfg::{CfgAtom, CfgExpr};
 use hir::sym;
 use ide::{Cancellable, Crate, FileId, RunnableKind, TestId};
 use project_model::project_json::Runnable;
 use project_model::{CargoFeatures, ManifestPath, TargetKind};
 use rustc_hash::FxHashSet;
+use triomphe::Arc;
 use vfs::AbsPathBuf;
 
 use crate::global_state::GlobalStateSnapshot;
@@ -52,6 +54,7 @@ pub(crate) struct CargoTargetSpec {
     pub(crate) workspace_root: AbsPathBuf,
     pub(crate) cargo_toml: ManifestPath,
     pub(crate) package: String,
+    pub(crate) package_id: Arc<PackageId>,
     pub(crate) target: String,
     pub(crate) target_kind: TargetKind,
     pub(crate) crate_id: Crate,
diff --git a/src/tools/rust-analyzer/crates/stdx/src/lib.rs b/src/tools/rust-analyzer/crates/stdx/src/lib.rs
index 978c50d807b..5fa00741637 100644
--- a/src/tools/rust-analyzer/crates/stdx/src/lib.rs
+++ b/src/tools/rust-analyzer/crates/stdx/src/lib.rs
@@ -187,11 +187,19 @@ pub fn is_upper_snake_case(s: &str) -> bool {
 }
 
 pub fn replace(buf: &mut String, from: char, to: &str) {
-    if !buf.contains(from) {
+    let replace_count = buf.chars().filter(|&ch| ch == from).count();
+    if replace_count == 0 {
         return;
     }
-    // FIXME: do this in place.
-    *buf = buf.replace(from, to);
+    let from_len = from.len_utf8();
+    let additional = to.len().saturating_sub(from_len);
+    buf.reserve(additional * replace_count);
+
+    let mut end = buf.len();
+    while let Some(i) = buf[..end].rfind(from) {
+        buf.replace_range(i..i + from_len, to);
+        end = i;
+    }
 }
 
 #[must_use]
@@ -343,4 +351,34 @@ mod tests {
             "fn main() {\n    return 92;\n}\n"
         );
     }
+
+    #[test]
+    fn test_replace() {
+        #[track_caller]
+        fn test_replace(src: &str, from: char, to: &str, expected: &str) {
+            let mut s = src.to_owned();
+            replace(&mut s, from, to);
+            assert_eq!(s, expected, "from: {from:?}, to: {to:?}");
+        }
+
+        test_replace("", 'a', "b", "");
+        test_replace("", 'a', "😀", "");
+        test_replace("", '😀', "a", "");
+        test_replace("a", 'a', "b", "b");
+        test_replace("aa", 'a', "b", "bb");
+        test_replace("ada", 'a', "b", "bdb");
+        test_replace("a", 'a', "😀", "😀");
+        test_replace("😀", '😀', "a", "a");
+        test_replace("😀x", '😀', "a", "ax");
+        test_replace("y😀x", '😀', "a", "yax");
+        test_replace("a,b,c", ',', ".", "a.b.c");
+        test_replace("a,b,c", ',', "..", "a..b..c");
+        test_replace("a.b.c", '.', "..", "a..b..c");
+        test_replace("a.b.c", '.', "..", "a..b..c");
+        test_replace("a😀b😀c", '😀', ".", "a.b.c");
+        test_replace("a.b.c", '.', "😀", "a😀b😀c");
+        test_replace("a.b.c", '.', "😀😀", "a😀😀b😀😀c");
+        test_replace(".a.b.c.", '.', "()", "()a()b()c()");
+        test_replace(".a.b.c.", '.', "", "abc");
+    }
 }
diff --git a/src/tools/rust-analyzer/crates/syntax/src/syntax_error.rs b/src/tools/rust-analyzer/crates/syntax/src/syntax_error.rs
index dc6130bd641..1c902893abc 100644
--- a/src/tools/rust-analyzer/crates/syntax/src/syntax_error.rs
+++ b/src/tools/rust-analyzer/crates/syntax/src/syntax_error.rs
@@ -42,3 +42,5 @@ impl fmt::Display for SyntaxError {
         self.0.fmt(f)
     }
 }
+
+impl std::error::Error for SyntaxError {}
diff --git a/src/tools/rust-analyzer/docs/book/src/configuration_generated.md b/src/tools/rust-analyzer/docs/book/src/configuration_generated.md
index 50dacd88f40..e78f1b4ba35 100644
--- a/src/tools/rust-analyzer/docs/book/src/configuration_generated.md
+++ b/src/tools/rust-analyzer/docs/book/src/configuration_generated.md
@@ -1046,6 +1046,8 @@ Default: `25`
 
 Maximum length for inlay hints. Set to null to have an unlimited length.
 
+**Note:** This is mostly a hint, and we don't guarantee to strictly follow the limit.
+
 
 ## rust-analyzer.inlayHints.parameterHints.enable {#inlayHints.parameterHints.enable}
 
diff --git a/src/tools/rust-analyzer/editors/code/package-lock.json b/src/tools/rust-analyzer/editors/code/package-lock.json
index ad8708e00c5..e35a159cbc3 100644
--- a/src/tools/rust-analyzer/editors/code/package-lock.json
+++ b/src/tools/rust-analyzer/editors/code/package-lock.json
@@ -6405,9 +6405,9 @@
             }
         },
         "node_modules/tar-fs": {
-            "version": "2.1.3",
-            "resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-2.1.3.tgz",
-            "integrity": "sha512-090nwYJDmlhwFwEW3QQl+vaNnxsO2yVsd45eTKRBzSzu+hlb1w2K9inVq5b0ngXuLVqQ4ApvsUHHnu/zQNkWAg==",
+            "version": "2.1.4",
+            "resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-2.1.4.tgz",
+            "integrity": "sha512-mDAjwmZdh7LTT6pNleZ05Yt65HC3E+NiQzl672vQG38jIrehtJk/J3mNwIg+vShQPcLF/LV7CMnDW6vjj6sfYQ==",
             "dev": true,
             "license": "MIT",
             "optional": true,
diff --git a/src/tools/rust-analyzer/editors/code/package.json b/src/tools/rust-analyzer/editors/code/package.json
index 1d27a120535..745e0da4efe 100644
--- a/src/tools/rust-analyzer/editors/code/package.json
+++ b/src/tools/rust-analyzer/editors/code/package.json
@@ -2355,7 +2355,7 @@
                 "title": "Inlay Hints",
                 "properties": {
                     "rust-analyzer.inlayHints.maxLength": {
-                        "markdownDescription": "Maximum length for inlay hints. Set to null to have an unlimited length.",
+                        "markdownDescription": "Maximum length for inlay hints. Set to null to have an unlimited length.\n\n**Note:** This is mostly a hint, and we don't guarantee to strictly follow the limit.",
                         "default": 25,
                         "type": [
                             "null",
diff --git a/src/tools/rust-analyzer/rust-version b/src/tools/rust-analyzer/rust-version
index 02b217f7d80..1f90d4e5e49 100644
--- a/src/tools/rust-analyzer/rust-version
+++ b/src/tools/rust-analyzer/rust-version
@@ -1 +1 @@
-21a19c297d4f5a03501d92ca251bd7a17073c08a
+f957826bff7a68b267ce75b1ea56352aed0cca0a
diff --git a/src/tools/rustfmt/src/config/mod.rs b/src/tools/rustfmt/src/config/mod.rs
index 6b63108c037..525953bf445 100644
--- a/src/tools/rustfmt/src/config/mod.rs
+++ b/src/tools/rustfmt/src/config/mod.rs
@@ -516,7 +516,6 @@ mod test {
     #[allow(dead_code)]
     mod mock {
         use super::super::*;
-        use crate::config_option_with_style_edition_default;
         use rustfmt_config_proc_macro::config_type;
 
         #[config_type]
diff --git a/src/tools/tidy/src/lib.rs b/src/tools/tidy/src/lib.rs
index 0bfee93796b..874a758bd9b 100644
--- a/src/tools/tidy/src/lib.rs
+++ b/src/tools/tidy/src/lib.rs
@@ -167,12 +167,16 @@ pub fn ensure_version_or_cargo_install(
     bin_name: &str,
     version: &str,
 ) -> io::Result<PathBuf> {
+    let tool_root_dir = build_dir.join("misc-tools");
+    let tool_bin_dir = tool_root_dir.join("bin");
+    let bin_path = tool_bin_dir.join(bin_name).with_extension(env::consts::EXE_EXTENSION);
+
     // ignore the process exit code here and instead just let the version number check fail.
     // we also importantly don't return if the program wasn't installed,
     // instead we want to continue to the fallback.
     'ck: {
         // FIXME: rewrite as if-let chain once this crate is 2024 edition.
-        let Ok(output) = Command::new(bin_name).arg("--version").output() else {
+        let Ok(output) = Command::new(&bin_path).arg("--version").output() else {
             break 'ck;
         };
         let Ok(s) = str::from_utf8(&output.stdout) else {
@@ -182,12 +186,10 @@ pub fn ensure_version_or_cargo_install(
             break 'ck;
         };
         if v == version {
-            return Ok(PathBuf::from(bin_name));
+            return Ok(bin_path);
         }
     }
 
-    let tool_root_dir = build_dir.join("misc-tools");
-    let tool_bin_dir = tool_root_dir.join("bin");
     eprintln!("building external tool {bin_name} from package {pkg_name}@{version}");
     // use --force to ensure that if the required version is bumped, we update it.
     // use --target-dir to ensure we have a build cache so repeated invocations aren't slow.
@@ -213,7 +215,6 @@ pub fn ensure_version_or_cargo_install(
     if !cargo_exit_code.success() {
         return Err(io::Error::other("cargo install failed"));
     }
-    let bin_path = tool_bin_dir.join(bin_name).with_extension(env::consts::EXE_EXTENSION);
     assert!(
         matches!(bin_path.try_exists(), Ok(true)),
         "cargo install did not produce the expected binary"