about summary refs log tree commit diff
diff options
context:
space:
mode:
authorThe Miri Conjob Bot <miri@cron.bot>2024-02-19 05:12:20 +0000
committerThe Miri Conjob Bot <miri@cron.bot>2024-02-19 05:12:20 +0000
commite118c3e8af2ee5c0d20d21e8bf08c1a254a317fb (patch)
treecf3e5436c033a6b38daa21eb498b7f53d417936c
parent6b6da93e51851d098574b5e6f39b6d187e78f34a (diff)
parentd5735645753e990a72446094f703df9b5e421555 (diff)
downloadrust-e118c3e8af2ee5c0d20d21e8bf08c1a254a317fb.tar.gz
rust-e118c3e8af2ee5c0d20d21e8bf08c1a254a317fb.zip
Merge from rustc
-rw-r--r--Cargo.lock80
-rw-r--r--compiler/rustc_codegen_cranelift/example/mini_core_hello_world.rs4
-rw-r--r--compiler/rustc_codegen_gcc/example/mini_core_hello_world.rs4
-rw-r--r--compiler/rustc_codegen_ssa/Cargo.toml2
-rw-r--r--compiler/rustc_codegen_ssa/src/errors.rs7
-rw-r--r--compiler/rustc_data_structures/Cargo.toml2
-rw-r--r--compiler/rustc_data_structures/src/flock/windows.rs1
-rw-r--r--compiler/rustc_data_structures/src/owned_slice.rs12
-rw-r--r--compiler/rustc_data_structures/src/profiling.rs6
-rw-r--r--compiler/rustc_driver_impl/Cargo.toml2
-rw-r--r--compiler/rustc_error_codes/src/error_codes/E0796.md26
-rw-r--r--compiler/rustc_errors/Cargo.toml2
-rw-r--r--compiler/rustc_errors/src/lock.rs6
-rw-r--r--compiler/rustc_expand/messages.ftl5
-rw-r--r--compiler/rustc_expand/src/errors.rs10
-rw-r--r--compiler/rustc_expand/src/lib.rs1
-rw-r--r--compiler/rustc_expand/src/mbe/quoted.rs18
-rw-r--r--compiler/rustc_expand/src/mbe/transcribe.rs55
-rw-r--r--compiler/rustc_hir/src/hir.rs6
-rw-r--r--compiler/rustc_hir_analysis/messages.ftl34
-rw-r--r--compiler/rustc_hir_analysis/src/astconv/bounds.rs164
-rw-r--r--compiler/rustc_hir_analysis/src/astconv/errors.rs45
-rw-r--r--compiler/rustc_hir_analysis/src/astconv/mod.rs91
-rw-r--r--compiler/rustc_hir_analysis/src/check/check.rs26
-rw-r--r--compiler/rustc_hir_analysis/src/check/errs.rs28
-rw-r--r--compiler/rustc_hir_analysis/src/coherence/inherent_impls.rs31
-rw-r--r--compiler/rustc_hir_analysis/src/collect.rs10
-rw-r--r--compiler/rustc_hir_analysis/src/collect/predicates_of.rs2
-rw-r--r--compiler/rustc_hir_analysis/src/constrained_generic_params.rs43
-rw-r--r--compiler/rustc_hir_analysis/src/errors.rs36
-rw-r--r--compiler/rustc_hir_analysis/src/impl_wf_check.rs4
-rw-r--r--compiler/rustc_hir_analysis/src/impl_wf_check/min_specialization.rs8
-rw-r--r--compiler/rustc_hir_analysis/src/structured_errors/missing_cast_for_variadic_arg.rs2
-rw-r--r--compiler/rustc_hir_analysis/src/structured_errors/sized_unsized_cast.rs2
-rw-r--r--compiler/rustc_hir_analysis/src/structured_errors/wrong_number_of_generic_args.rs4
-rw-r--r--compiler/rustc_hir_typeck/src/errors.rs2
-rw-r--r--compiler/rustc_hir_typeck/src/expr.rs2
-rw-r--r--compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs2
-rw-r--r--compiler/rustc_hir_typeck/src/lib.rs2
-rw-r--r--compiler/rustc_incremental/src/persist/fs.rs2
-rw-r--r--compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs2
-rw-r--r--compiler/rustc_lint/src/context/diagnostics.rs4
-rw-r--r--compiler/rustc_lint/src/lib.rs1
-rw-r--r--compiler/rustc_lint_defs/src/builtin.rs8
-rw-r--r--compiler/rustc_metadata/src/rmeta/decoder.rs2
-rw-r--r--compiler/rustc_middle/src/mir/syntax.rs2
-rw-r--r--compiler/rustc_mir_transform/src/const_prop.rs161
-rw-r--r--compiler/rustc_mir_transform/src/const_prop_lint.rs132
-rw-r--r--compiler/rustc_mir_transform/src/dataflow_const_prop.rs27
-rw-r--r--compiler/rustc_mir_transform/src/lib.rs1
-rw-r--r--compiler/rustc_parse/src/errors.rs2
-rw-r--r--compiler/rustc_resolve/src/build_reduced_graph.rs14
-rw-r--r--compiler/rustc_resolve/src/check_unused.rs46
-rw-r--r--compiler/rustc_resolve/src/def_collector.rs2
-rw-r--r--compiler/rustc_resolve/src/diagnostics.rs4
-rw-r--r--compiler/rustc_resolve/src/ident.rs10
-rw-r--r--compiler/rustc_resolve/src/imports.rs75
-rw-r--r--compiler/rustc_resolve/src/late.rs13
-rw-r--r--compiler/rustc_resolve/src/lib.rs51
-rw-r--r--compiler/rustc_resolve/src/macros.rs4
-rw-r--r--compiler/rustc_session/Cargo.toml2
-rw-r--r--compiler/rustc_session/src/filesearch.rs1
-rw-r--r--compiler/rustc_session/src/session.rs2
-rw-r--r--compiler/rustc_session/src/utils.rs20
-rw-r--r--compiler/rustc_span/src/lib.rs73
-rw-r--r--compiler/rustc_span/src/source_map/tests.rs2
-rw-r--r--compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs20
-rw-r--r--config.example.toml2
-rw-r--r--library/alloc/src/raw_vec.rs4
-rw-r--r--library/panic_unwind/src/seh.rs10
-rw-r--r--library/portable-simd/crates/core_simd/src/intrinsics.rs169
-rw-r--r--library/portable-simd/crates/core_simd/src/lib.rs22
-rw-r--r--library/portable-simd/crates/core_simd/src/masks.rs41
-rw-r--r--library/portable-simd/crates/core_simd/src/masks/bitmask.rs9
-rw-r--r--library/portable-simd/crates/core_simd/src/masks/full_masks.rs27
-rw-r--r--library/portable-simd/crates/core_simd/src/mod.rs4
-rw-r--r--library/portable-simd/crates/core_simd/src/ops.rs6
-rw-r--r--library/portable-simd/crates/core_simd/src/ops/unary.rs3
-rw-r--r--library/portable-simd/crates/core_simd/src/select.rs3
-rw-r--r--library/portable-simd/crates/core_simd/src/simd/cmp/eq.rs9
-rw-r--r--library/portable-simd/crates/core_simd/src/simd/cmp/ord.rs25
-rw-r--r--library/portable-simd/crates/core_simd/src/simd/num/float.rs20
-rw-r--r--library/portable-simd/crates/core_simd/src/simd/num/int.rs26
-rw-r--r--library/portable-simd/crates/core_simd/src/simd/num/uint.rs30
-rw-r--r--library/portable-simd/crates/core_simd/src/simd/ptr/const_ptr.rs14
-rw-r--r--library/portable-simd/crates/core_simd/src/simd/ptr/mut_ptr.rs14
-rw-r--r--library/portable-simd/crates/core_simd/src/swizzle.rs5
-rw-r--r--library/portable-simd/crates/core_simd/src/swizzle_dyn.rs44
-rw-r--r--library/portable-simd/crates/core_simd/src/vector.rs15
-rw-r--r--library/portable-simd/crates/core_simd/tests/masks.rs42
-rw-r--r--library/portable-simd/crates/std_float/src/lib.rs38
-rw-r--r--library/portable-simd/crates/test_helpers/src/lib.rs6
-rw-r--r--library/std/src/env.rs3
-rw-r--r--library/std/src/ffi/mod.rs7
-rw-r--r--library/std/src/ffi/os_str.rs43
-rw-r--r--library/std/src/ffi/os_str/tests.rs68
-rw-r--r--library/std/src/fs.rs18
-rw-r--r--library/std/src/os/unix/fs.rs1
-rw-r--r--library/std/src/os/wasi/fs.rs14
-rw-r--r--library/std/src/panicking.rs5
-rw-r--r--library/std/src/sys/os_str/bytes.rs43
-rw-r--r--library/std/src/sys/os_str/wtf8.rs7
-rw-r--r--library/std/src/sys/pal/common/small_c_string.rs29
-rw-r--r--library/std/src/sys/pal/common/tests.rs12
-rw-r--r--library/std/src/sys/pal/common/thread_local/fast_local.rs5
-rw-r--r--library/std/src/sys/pal/common/thread_local/static_local.rs5
-rw-r--r--library/std/src/sys/pal/hermit/fs.rs4
-rw-r--r--library/std/src/sys/pal/solid/os.rs8
-rw-r--r--library/std/src/sys/pal/unix/fs.rs42
-rw-r--r--library/std/src/sys/pal/unix/os.rs10
-rw-r--r--library/std/src/sys/pal/wasi/fs.rs2
-rw-r--r--library/std/src/sys/pal/wasi/os.rs10
-rw-r--r--library/std/src/sys_common/net.rs2
-rw-r--r--library/std/src/sys_common/wtf8.rs36
-rw-r--r--library/std/src/sys_common/wtf8/tests.rs62
-rw-r--r--library/std/src/thread/local.rs4
-rw-r--r--src/librustdoc/clean/inline.rs19
-rw-r--r--src/librustdoc/config.rs4
-rw-r--r--src/librustdoc/html/format.rs454
-rw-r--r--src/librustdoc/html/static/css/rustdoc.css7
-rw-r--r--src/librustdoc/html/static/js/main.js2
-rw-r--r--src/tools/clippy/src/driver.rs1
-rw-r--r--src/tools/compiletest/Cargo.toml2
-rw-r--r--src/tools/miri/tests/fail/shims/fs/isolated_file.stderr5
-rw-r--r--src/tools/miri/tests/fail/tls/tls_static_dealloc.rs4
-rw-r--r--src/tools/miri/tests/pass/static_mut.rs4
-rw-r--r--src/tools/miri/tests/pass/tls/tls_static.rs4
-rw-r--r--src/tools/opt-dist/Cargo.toml2
-rw-r--r--src/tools/rust-analyzer/.github/rust.json33
-rw-r--r--src/tools/rust-analyzer/.github/workflows/autopublish.yaml2
-rw-r--r--src/tools/rust-analyzer/.github/workflows/ci.yaml20
-rw-r--r--src/tools/rust-analyzer/.github/workflows/fuzz.yml2
-rw-r--r--src/tools/rust-analyzer/.github/workflows/metrics.yaml16
-rw-r--r--src/tools/rust-analyzer/.github/workflows/publish-libs.yaml2
-rw-r--r--src/tools/rust-analyzer/.github/workflows/release.yaml14
-rw-r--r--src/tools/rust-analyzer/.github/workflows/rustdoc.yaml2
-rw-r--r--src/tools/rust-analyzer/Cargo.lock17
-rw-r--r--src/tools/rust-analyzer/Cargo.toml2
-rw-r--r--src/tools/rust-analyzer/crates/base-db/src/input.rs230
-rw-r--r--src/tools/rust-analyzer/crates/base-db/src/lib.rs14
-rw-r--r--src/tools/rust-analyzer/crates/flycheck/src/lib.rs79
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/attr.rs42
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/body/lower.rs11
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/body/pretty.rs8
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/body/scope.rs1
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/data.rs12
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/expander.rs6
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/find_path.rs63
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/hir.rs9
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/import_map.rs2
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/item_tree/lower.rs8
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/item_tree/pretty.rs5
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/mbe/matching.rs2
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/mbe/meta_syntax.rs42
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/mbe/metavar_expr.rs6
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/mbe/regression.rs54
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/mbe/tt_conversion.rs4
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/mod.rs1
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/nameres.rs2
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/nameres/collector.rs95
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/nameres/diagnostics.rs3
-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/change.rs34
-rw-r--r--src/tools/rust-analyzer/crates/hir-expand/src/db.rs154
-rw-r--r--src/tools/rust-analyzer/crates/hir-expand/src/declarative.rs14
-rw-r--r--src/tools/rust-analyzer/crates/hir-expand/src/lib.rs26
-rw-r--r--src/tools/rust-analyzer/crates/hir-expand/src/mod_path.rs15
-rw-r--r--src/tools/rust-analyzer/crates/hir-expand/src/proc_macro.rs46
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/expr.rs13
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/match_check/pat_analysis.rs46
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/match_check/pat_util.rs2
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/infer.rs133
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/infer/closure.rs4
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/infer/expr.rs23
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/infer/mutability.rs4
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/infer/unify.rs83
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/layout/target.rs8
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/layout/tests.rs12
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/lib.rs4
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/mir/borrowck.rs185
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/mir/eval/shim.rs6
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/mir/lower.rs14
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/mir/lower/pattern_matching.rs2
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/tests/diagnostics.rs42
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/tests/simple.rs3
-rw-r--r--src/tools/rust-analyzer/crates/hir/src/lib.rs246
-rw-r--r--src/tools/rust-analyzer/crates/hir/src/term_search.rs298
-rw-r--r--src/tools/rust-analyzer/crates/hir/src/term_search/expr.rs468
-rw-r--r--src/tools/rust-analyzer/crates/hir/src/term_search/tactics.rs859
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/handlers/fix_visibility.rs4
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_delegate_methods.rs2
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_trait_from_impl.rs104
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/handlers/term_search.rs253
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/lib.rs7
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/tests/generated.rs4
-rw-r--r--src/tools/rust-analyzer/crates/ide-completion/src/completions.rs10
-rw-r--r--src/tools/rust-analyzer/crates/ide-completion/src/completions/expr.rs56
-rw-r--r--src/tools/rust-analyzer/crates/ide-completion/src/completions/flyimport.rs2
-rw-r--r--src/tools/rust-analyzer/crates/ide-completion/src/completions/item_list/trait_impl.rs2
-rw-r--r--src/tools/rust-analyzer/crates/ide-completion/src/completions/type.rs20
-rw-r--r--src/tools/rust-analyzer/crates/ide-completion/src/config.rs1
-rw-r--r--src/tools/rust-analyzer/crates/ide-completion/src/context.rs3
-rw-r--r--src/tools/rust-analyzer/crates/ide-completion/src/item.rs50
-rw-r--r--src/tools/rust-analyzer/crates/ide-completion/src/render.rs443
-rw-r--r--src/tools/rust-analyzer/crates/ide-completion/src/render/function.rs50
-rw-r--r--src/tools/rust-analyzer/crates/ide-completion/src/tests.rs1
-rw-r--r--src/tools/rust-analyzer/crates/ide-completion/src/tests/expression.rs32
-rw-r--r--src/tools/rust-analyzer/crates/ide-completion/src/tests/flyimport.rs19
-rw-r--r--src/tools/rust-analyzer/crates/ide-completion/src/tests/record.rs2
-rw-r--r--src/tools/rust-analyzer/crates/ide-completion/src/tests/special.rs40
-rw-r--r--src/tools/rust-analyzer/crates/ide-completion/src/tests/type_pos.rs40
-rw-r--r--src/tools/rust-analyzer/crates/ide-db/src/famous_defs.rs8
-rw-r--r--src/tools/rust-analyzer/crates/ide-db/src/path_transform.rs2
-rw-r--r--src/tools/rust-analyzer/crates/ide-db/src/rename.rs5
-rw-r--r--src/tools/rust-analyzer/crates/ide-db/src/source_change.rs68
-rw-r--r--src/tools/rust-analyzer/crates/ide-db/src/symbol_index.rs2
-rw-r--r--src/tools/rust-analyzer/crates/ide-db/src/syntax_helpers/node_ext.rs1
-rw-r--r--src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/incorrect_case.rs2
-rw-r--r--src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/macro_error.rs2
-rw-r--r--src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/missing_match_arms.rs18
-rw-r--r--src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/remove_trailing_return.rs12
-rw-r--r--src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/type_mismatch.rs3
-rw-r--r--src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/typed_hole.rs256
-rw-r--r--src/tools/rust-analyzer/crates/ide-diagnostics/src/tests.rs85
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/doc_links.rs2
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/hover/tests.rs8
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/lib.rs12
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/parent_module.rs2
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/rename.rs41
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/shuffle_crate_graph.rs2
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/static_index.rs23
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/status.rs8
-rw-r--r--src/tools/rust-analyzer/crates/load-cargo/src/lib.rs74
-rw-r--r--src/tools/rust-analyzer/crates/mbe/src/expander/transcriber.rs18
-rw-r--r--src/tools/rust-analyzer/crates/mbe/src/syntax_bridge.rs6
-rw-r--r--src/tools/rust-analyzer/crates/parser/src/grammar/expressions.rs29
-rw-r--r--src/tools/rust-analyzer/crates/parser/src/grammar/expressions/atom.rs14
-rw-r--r--src/tools/rust-analyzer/crates/parser/src/grammar/generic_params.rs10
-rw-r--r--src/tools/rust-analyzer/crates/parser/src/grammar/patterns.rs9
-rw-r--r--src/tools/rust-analyzer/crates/parser/src/syntax_kind/generated.rs6
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/0014_record_literal_before_ellipsis_recovery.rast36
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/0032_record_literal_field_eq_recovery.rast41
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/0032_record_literal_field_eq_recovery.rs3
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/0033_record_pat_field_eq_recovery.rast43
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/0033_record_pat_field_eq_recovery.rs3
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0209_become_expr.rast31
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0209_become_expr.rs3
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0211_async_trait_bound.rast43
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0211_async_trait_bound.rs1
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0212_const_trait_bound.rast34
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0212_const_trait_bound.rs1
-rw-r--r--src/tools/rust-analyzer/crates/proc-macro-api/src/lib.rs8
-rw-r--r--src/tools/rust-analyzer/crates/proc-macro-api/src/process.rs25
-rw-r--r--src/tools/rust-analyzer/crates/proc-macro-srv/Cargo.toml1
-rw-r--r--src/tools/rust-analyzer/crates/proc-macro-srv/src/lib.rs5
-rw-r--r--src/tools/rust-analyzer/crates/proc-macro-srv/src/server/rust_analyzer_span.rs55
-rw-r--r--src/tools/rust-analyzer/crates/proc-macro-srv/src/server/token_id.rs55
-rw-r--r--src/tools/rust-analyzer/crates/proc-macro-srv/src/tests/mod.rs18
-rw-r--r--src/tools/rust-analyzer/crates/project-model/src/build_scripts.rs25
-rw-r--r--src/tools/rust-analyzer/crates/project-model/src/cargo_workspace.rs39
-rw-r--r--src/tools/rust-analyzer/crates/project-model/src/project_json.rs3
-rw-r--r--src/tools/rust-analyzer/crates/project-model/src/rustc_cfg.rs46
-rw-r--r--src/tools/rust-analyzer/crates/project-model/src/sysroot.rs124
-rw-r--r--src/tools/rust-analyzer/crates/project-model/src/target_data_layout.rs60
-rw-r--r--src/tools/rust-analyzer/crates/project-model/src/tests.rs71
-rw-r--r--src/tools/rust-analyzer/crates/project-model/src/workspace.rs549
-rw-r--r--src/tools/rust-analyzer/crates/project-model/test_data/output/cargo_hello_world_project_model.txt27
-rw-r--r--src/tools/rust-analyzer/crates/project-model/test_data/output/cargo_hello_world_project_model_with_selective_overrides.txt27
-rw-r--r--src/tools/rust-analyzer/crates/project-model/test_data/output/cargo_hello_world_project_model_with_wildcard_overrides.txt27
-rw-r--r--src/tools/rust-analyzer/crates/project-model/test_data/output/rust_project_hello_world_project_model.txt60
-rw-r--r--src/tools/rust-analyzer/crates/rust-analyzer/src/bin/main.rs28
-rw-r--r--src/tools/rust-analyzer/crates/rust-analyzer/src/bin/rustc_wrapper.rs19
-rw-r--r--src/tools/rust-analyzer/crates/rust-analyzer/src/cargo_target_spec.rs4
-rw-r--r--src/tools/rust-analyzer/crates/rust-analyzer/src/cli/analysis_stats.rs216
-rw-r--r--src/tools/rust-analyzer/crates/rust-analyzer/src/cli/flags.rs7
-rw-r--r--src/tools/rust-analyzer/crates/rust-analyzer/src/cli/lsif.rs2
-rw-r--r--src/tools/rust-analyzer/crates/rust-analyzer/src/cli/scip.rs31
-rw-r--r--src/tools/rust-analyzer/crates/rust-analyzer/src/config.rs19
-rw-r--r--src/tools/rust-analyzer/crates/rust-analyzer/src/global_state.rs41
-rw-r--r--src/tools/rust-analyzer/crates/rust-analyzer/src/handlers/notification.rs22
-rw-r--r--src/tools/rust-analyzer/crates/rust-analyzer/src/handlers/request.rs11
-rw-r--r--src/tools/rust-analyzer/crates/rust-analyzer/src/integrated_benchmarks.rs3
-rw-r--r--src/tools/rust-analyzer/crates/rust-analyzer/src/lib.rs4
-rw-r--r--src/tools/rust-analyzer/crates/rust-analyzer/src/lsp/to_proto.rs673
-rw-r--r--src/tools/rust-analyzer/crates/rust-analyzer/src/main_loop.rs41
-rw-r--r--src/tools/rust-analyzer/crates/rust-analyzer/src/reload.rs193
-rw-r--r--src/tools/rust-analyzer/crates/rust-analyzer/tests/crate_graph.rs118
-rw-r--r--src/tools/rust-analyzer/crates/rust-analyzer/tests/slow-tests/main.rs16
-rw-r--r--src/tools/rust-analyzer/crates/rust-analyzer/tests/slow-tests/support.rs9
-rw-r--r--src/tools/rust-analyzer/crates/rust-analyzer/tests/slow-tests/tidy.rs21
-rw-r--r--src/tools/rust-analyzer/crates/rust-analyzer/tests/test_data/deduplication_crate_graph_A.json (renamed from src/tools/rust-analyzer/crates/project-model/test_data/deduplication_crate_graph_A.json)0
-rw-r--r--src/tools/rust-analyzer/crates/rust-analyzer/tests/test_data/deduplication_crate_graph_B.json (renamed from src/tools/rust-analyzer/crates/project-model/test_data/deduplication_crate_graph_B.json)0
-rw-r--r--src/tools/rust-analyzer/crates/salsa/salsa-macros/src/query_group.rs1
-rw-r--r--src/tools/rust-analyzer/crates/salsa/src/debug.rs1
-rw-r--r--src/tools/rust-analyzer/crates/salsa/src/derived.rs1
-rw-r--r--src/tools/rust-analyzer/crates/salsa/src/doctest.rs115
-rw-r--r--src/tools/rust-analyzer/crates/salsa/src/input.rs1
-rw-r--r--src/tools/rust-analyzer/crates/salsa/src/interned.rs1
-rw-r--r--src/tools/rust-analyzer/crates/salsa/src/lib.rs1
-rw-r--r--src/tools/rust-analyzer/crates/syntax/rust.ungram6
-rw-r--r--src/tools/rust-analyzer/crates/syntax/src/ast/edit_in_place.rs30
-rw-r--r--src/tools/rust-analyzer/crates/syntax/src/ast/generated/nodes.rs37
-rw-r--r--src/tools/rust-analyzer/crates/syntax/src/ast/make.rs2
-rw-r--r--src/tools/rust-analyzer/crates/syntax/src/ast/node_ext.rs20
-rw-r--r--src/tools/rust-analyzer/crates/syntax/src/ast/prec.rs8
-rw-r--r--src/tools/rust-analyzer/crates/syntax/src/lib.rs5
-rw-r--r--src/tools/rust-analyzer/crates/syntax/src/tests/ast_src.rs6
-rw-r--r--src/tools/rust-analyzer/crates/test-fixture/src/lib.rs90
-rw-r--r--src/tools/rust-analyzer/crates/test-utils/src/fixture.rs38
-rw-r--r--src/tools/rust-analyzer/crates/test-utils/src/minicore.rs33
-rw-r--r--src/tools/rust-analyzer/crates/toolchain/src/lib.rs42
-rw-r--r--src/tools/rust-analyzer/crates/tt/src/lib.rs1
-rw-r--r--src/tools/rust-analyzer/docs/user/generated_config.adoc17
-rw-r--r--src/tools/rust-analyzer/editors/code/.vscodeignore3
-rw-r--r--src/tools/rust-analyzer/editors/code/language-configuration-rustdoc.json37
-rw-r--r--src/tools/rust-analyzer/editors/code/package.json44
-rw-r--r--src/tools/rust-analyzer/editors/code/rustdoc-inject.json93
-rw-r--r--src/tools/rust-analyzer/editors/code/rustdoc.json82
-rw-r--r--src/tools/rust-analyzer/editors/code/src/rust_project.ts19
l---------src/tools/rust-analyzer/lib/lsp-server/LICENSE-APACHE1
l---------src/tools/rust-analyzer/lib/lsp-server/LICENSE-MIT1
-rw-r--r--src/tools/rust-analyzer/xtask/src/metrics.rs2
-rw-r--r--src/tools/tidy/src/deps.rs1
-rw-r--r--tests/coverage/no_spans.cov-map8
-rw-r--r--tests/coverage/no_spans.coverage2
-rw-r--r--tests/coverage/no_spans_if_not.cov-map12
-rw-r--r--tests/coverage/no_spans_if_not.coverage8
-rw-r--r--tests/rustdoc-gui/mobile-crate-name.goml22
-rw-r--r--tests/rustdoc-gui/type-declation-overflow.goml4
-rw-r--r--tests/rustdoc/bounds.rs (renamed from tests/rustdoc/bounds-in-multiple-parts.rs)12
-rw-r--r--tests/rustdoc/const-generics/generic_const_exprs.rs2
-rw-r--r--tests/rustdoc/inline_cross/auxiliary/issue-76736-1.rs6
-rw-r--r--tests/rustdoc/inline_cross/auxiliary/issue-76736-2.rs5
-rw-r--r--tests/rustdoc/inline_cross/issue-76736-1.rs15
-rw-r--r--tests/rustdoc/inline_cross/issue-76736-2.rs16
-rw-r--r--tests/rustdoc/inline_cross/issue-76736-3.rs16
-rw-r--r--tests/ui/abi/statics/static-mut-foreign.rs4
-rw-r--r--tests/ui/abi/statics/static-mut-foreign.stderr22
-rw-r--r--tests/ui/anon-params/anon-params-edition-hygiene.rs4
-rw-r--r--tests/ui/anon-params/anon-params-edition-hygiene.stderr23
-rw-r--r--tests/ui/async-await/issue-72442.stderr5
-rw-r--r--tests/ui/async-await/suggest-switching-edition-on-await-cargo.rs2
-rw-r--r--tests/ui/borrowck/borrowck-access-permissions.rs2
-rw-r--r--tests/ui/borrowck/borrowck-access-permissions.stderr12
-rw-r--r--tests/ui/borrowck/borrowck-unsafe-static-mutable-borrows.rs2
-rw-r--r--tests/ui/borrowck/borrowck-unsafe-static-mutable-borrows.stderr12
-rw-r--r--tests/ui/borrowck/issue-20801.rs2
-rw-r--r--tests/ui/borrowck/issue-20801.stderr12
-rw-r--r--tests/ui/borrowck/issue-55492-borrowck-migrate-scans-parents.rs6
-rw-r--r--tests/ui/borrowck/issue-55492-borrowck-migrate-scans-parents.stderr32
-rw-r--r--tests/ui/check-cfg/cargo-feature.rs2
-rw-r--r--tests/ui/check-cfg/diagnotics.rs4
-rw-r--r--tests/ui/consts/const_let_assign2.rs2
-rw-r--r--tests/ui/consts/const_let_assign2.stderr12
-rw-r--r--tests/ui/consts/const_refs_to_static_fail_invalid.rs6
-rw-r--r--tests/ui/consts/const_refs_to_static_fail_invalid.stderr2
-rw-r--r--tests/ui/consts/issue-17718-const-bad-values.rs2
-rw-r--r--tests/ui/consts/miri_unleashed/const_refers_to_static_cross_crate.rs2
-rw-r--r--tests/ui/consts/miri_unleashed/extern-static.rs2
-rw-r--r--tests/ui/consts/miri_unleashed/mutable_references_err.32bit.stderr62
-rw-r--r--tests/ui/consts/miri_unleashed/mutable_references_err.64bit.stderr62
-rw-r--r--tests/ui/consts/miri_unleashed/mutable_references_err.rs13
-rw-r--r--tests/ui/consts/static-promoted-to-mutable-static.rs21
-rw-r--r--tests/ui/consts/static_mut_containing_mut_ref.rs2
-rw-r--r--tests/ui/consts/static_mut_containing_mut_ref2.rs2
-rw-r--r--tests/ui/crate-loading/missing-std.rs2
-rw-r--r--tests/ui/drop/issue-23338-ensure-param-drop-order.rs2
-rw-r--r--tests/ui/drop/issue-23338-ensure-param-drop-order.stderr12
-rw-r--r--tests/ui/editions/edition-keywords-2018-2018-parsing.rs4
-rw-r--r--tests/ui/editions/edition-keywords-2018-2018-parsing.stderr6
-rw-r--r--tests/ui/error-codes/E0017.rs2
-rw-r--r--tests/ui/error-codes/E0017.stderr12
-rw-r--r--tests/ui/error-codes/E0093.stderr2
-rw-r--r--tests/ui/error-should-say-copy-not-pod.stderr5
-rw-r--r--tests/ui/feature-gates/feature-gate-abi.stderr4
-rw-r--r--tests/ui/feature-gates/feature-gate-intrinsics.stderr4
-rw-r--r--tests/ui/fmt/format-args-capture-first-literal-is-macro.rs2
-rw-r--r--tests/ui/fmt/format-args-capture-first-literal-is-macro.stderr8
-rw-r--r--tests/ui/intrinsics-always-extern.stderr2
-rw-r--r--tests/ui/issues/issue-23611-enum-swap-in-drop.rs2
-rw-r--r--tests/ui/issues/issue-23611-enum-swap-in-drop.stderr12
-rw-r--r--tests/ui/issues/issue-54410.rs2
-rw-r--r--tests/ui/issues/issue-54410.stderr12
-rw-r--r--tests/ui/lazy-type-alias/constrained-params.rs27
-rw-r--r--tests/ui/lazy-type-alias/inherent-impls-conflicting.rs10
-rw-r--r--tests/ui/lazy-type-alias/inherent-impls-conflicting.stderr11
-rw-r--r--tests/ui/lazy-type-alias/inherent-impls-not-nominal.rs12
-rw-r--r--tests/ui/lazy-type-alias/inherent-impls-not-nominal.stderr11
-rw-r--r--tests/ui/lazy-type-alias/inherent-impls-overflow.classic.stderr43
-rw-r--r--tests/ui/lazy-type-alias/inherent-impls-overflow.next.stderr38
-rw-r--r--tests/ui/lazy-type-alias/inherent-impls-overflow.rs20
-rw-r--r--tests/ui/lazy-type-alias/inherent-impls.rs18
-rw-r--r--tests/ui/lazy-type-alias/unconstrained-param-due-to-overflow.rs8
-rw-r--r--tests/ui/lazy-type-alias/unconstrained-param-due-to-overflow.stderr9
-rw-r--r--tests/ui/lazy-type-alias/unconstrained-params.rs12
-rw-r--r--tests/ui/lazy-type-alias/unconstrained-params.stderr9
-rw-r--r--tests/ui/lint/unused/lint-unused-imports.rs2
-rw-r--r--tests/ui/lint/unused/lint-unused-imports.stderr26
-rw-r--r--tests/ui/lint/use-redundant/use-redundant-prelude-rust-2015.rs19
-rw-r--r--tests/ui/lint/use-redundant/use-redundant-prelude-rust-2015.stderr44
-rw-r--r--tests/ui/lint/use-redundant/use-redundant-prelude-rust-2021.rs11
-rw-r--r--tests/ui/lint/use-redundant/use-redundant-prelude-rust-2021.stderr26
-rw-r--r--tests/ui/lint/wide_pointer_comparisons.rs4
-rw-r--r--tests/ui/lint/wide_pointer_comparisons.stderr14
-rw-r--r--tests/ui/macros/invalid-fragment-specifier.rs10
-rw-r--r--tests/ui/macros/invalid-fragment-specifier.stderr18
-rw-r--r--tests/ui/macros/issue-118786.rs4
-rw-r--r--tests/ui/macros/issue-118786.stderr10
-rw-r--r--tests/ui/macros/macro-invalid-fragment-spec.rs8
-rw-r--r--tests/ui/macros/macro-invalid-fragment-spec.stderr10
-rw-r--r--tests/ui/methods/method-on-ambiguous-numeric-type.stderr4
-rw-r--r--tests/ui/nll/borrowck-thread-local-static-mut-borrow-outlives-fn.rs2
-rw-r--r--tests/ui/nll/borrowck-thread-local-static-mut-borrow-outlives-fn.stderr12
-rw-r--r--tests/ui/parser/issues/issue-44406.stderr2
-rw-r--r--tests/ui/parser/issues/issue-68091-unicode-ident-after-if.stderr5
-rw-r--r--tests/ui/parser/issues/issue-68092-unicode-ident-after-incomplete-expr.rs4
-rw-r--r--tests/ui/parser/issues/issue-68092-unicode-ident-after-incomplete-expr.stderr6
-rw-r--r--tests/ui/proc-macro/capture-macro-rules-invoke.stdout2
-rw-r--r--tests/ui/rust-2018/edition-lint-infer-outlives-macro.fixed16
-rw-r--r--tests/ui/rust-2018/edition-lint-infer-outlives-macro.rs12
-rw-r--r--tests/ui/rust-2018/edition-lint-infer-outlives-macro.stderr33
-rw-r--r--tests/ui/rust-2018/remove-extern-crate.fixed1
-rw-r--r--tests/ui/rust-2018/remove-extern-crate.rs1
-rw-r--r--tests/ui/rust-2018/remove-extern-crate.stderr6
-rw-r--r--tests/ui/span/macro-span-replacement.rs4
-rw-r--r--tests/ui/span/macro-span-replacement.stderr7
-rw-r--r--tests/ui/static/reference-of-mut-static-safe.e2021.stderr26
-rw-r--r--tests/ui/static/reference-of-mut-static-safe.e2024.stderr15
-rw-r--r--tests/ui/static/reference-of-mut-static-unsafe-fn.rs15
-rw-r--r--tests/ui/static/reference-of-mut-static-unsafe-fn.stderr70
-rw-r--r--tests/ui/static/reference-of-mut-static.e2021.stderr64
-rw-r--r--tests/ui/static/reference-of-mut-static.e2024.stderr48
-rw-r--r--tests/ui/static/reference-of-mut-static.rs26
-rw-r--r--tests/ui/static/reference-to-mut-static-safe.e2021.stderr26
-rw-r--r--tests/ui/static/reference-to-mut-static-safe.e2024.stderr15
-rw-r--r--tests/ui/static/reference-to-mut-static-safe.rs (renamed from tests/ui/static/reference-of-mut-static-safe.rs)4
-rw-r--r--tests/ui/static/reference-to-mut-static-unsafe-fn.rs26
-rw-r--r--tests/ui/static/reference-to-mut-static-unsafe-fn.stderr75
-rw-r--r--tests/ui/static/reference-to-mut-static.e2021.stderr91
-rw-r--r--tests/ui/static/reference-to-mut-static.e2024.stderr75
-rw-r--r--tests/ui/static/reference-to-mut-static.rs50
-rw-r--r--tests/ui/static/safe-extern-statics-mut.rs4
-rw-r--r--tests/ui/static/safe-extern-statics-mut.stderr22
-rw-r--r--tests/ui/statics/issue-15261.rs2
-rw-r--r--tests/ui/statics/issue-15261.stderr12
-rw-r--r--tests/ui/statics/static-mut-xc.rs4
-rw-r--r--tests/ui/statics/static-mut-xc.stderr22
-rw-r--r--tests/ui/statics/static-recursive.rs2
-rw-r--r--tests/ui/statics/static-recursive.stderr12
-rw-r--r--tests/ui/suggestions/issue-84973-blacklist.stderr5
-rw-r--r--tests/ui/thread-local/thread-local-static.rs2
-rw-r--r--tests/ui/trait-bounds/argument-with-unnecessary-method-call.rs11
-rw-r--r--tests/ui/trait-bounds/argument-with-unnecessary-method-call.stderr27
-rw-r--r--tests/ui/type/type-check/issue-88577-check-fn-with-more-than-65535-arguments.stderr4
-rw-r--r--tests/ui/typeck/issue-116473-ice-wrong-span-variant-args.rs4
-rw-r--r--tests/ui/typeck/issue-116473-ice-wrong-span-variant-args.stderr26
-rw-r--r--tests/ui/union/unnamed-fields/auxiliary/dep.rs18
-rw-r--r--tests/ui/union/unnamed-fields/restrict_type_hir.rs44
-rw-r--r--tests/ui/union/unnamed-fields/restrict_type_hir.stderr62
459 files changed, 10167 insertions, 3967 deletions
diff --git a/Cargo.lock b/Cargo.lock
index 7c6c10cdbd7..61f9c130e38 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -931,43 +931,19 @@ dependencies = [
 
 [[package]]
 name = "darling"
-version = "0.14.4"
+version = "0.20.6"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7b750cb3417fd1b327431a470f388520309479ab0bf5e323505daf0290cd3850"
+checksum = "c376d08ea6aa96aafe61237c7200d1241cb177b7d3a542d791f2d118e9cbb955"
 dependencies = [
- "darling_core 0.14.4",
- "darling_macro 0.14.4",
-]
-
-[[package]]
-name = "darling"
-version = "0.20.5"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "fc5d6b04b3fd0ba9926f945895de7d806260a2d7431ba82e7edaecb043c4c6b8"
-dependencies = [
- "darling_core 0.20.5",
- "darling_macro 0.20.5",
+ "darling_core",
+ "darling_macro",
 ]
 
 [[package]]
 name = "darling_core"
-version = "0.14.4"
+version = "0.20.6"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "109c1ca6e6b7f82cc233a97004ea8ed7ca123a9af07a8230878fcfda9b158bf0"
-dependencies = [
- "fnv",
- "ident_case",
- "proc-macro2",
- "quote",
- "strsim 0.10.0",
- "syn 1.0.109",
-]
-
-[[package]]
-name = "darling_core"
-version = "0.20.5"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "04e48a959bcd5c761246f5d090ebc2fbf7b9cd527a492b07a67510c108f1e7e3"
+checksum = "33043dcd19068b8192064c704b3f83eb464f91f1ff527b44a4e2b08d9cdb8855"
 dependencies = [
  "fnv",
  "ident_case",
@@ -979,22 +955,11 @@ dependencies = [
 
 [[package]]
 name = "darling_macro"
-version = "0.14.4"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a4aab4dbc9f7611d8b55048a3a16d2d010c2c8334e46304b40ac1cc14bf3b48e"
-dependencies = [
- "darling_core 0.14.4",
- "quote",
- "syn 1.0.109",
-]
-
-[[package]]
-name = "darling_macro"
-version = "0.20.5"
+version = "0.20.6"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1d1545d67a2149e1d93b7e5c7752dce5a7426eb5d1357ddcfd89336b94444f77"
+checksum = "c5a91391accf613803c2a9bf9abccdbaa07c54b4244a5b64883f9c3c137c86be"
 dependencies = [
- "darling_core 0.20.5",
+ "darling_core",
  "quote",
  "syn 2.0.48",
 ]
@@ -1036,33 +1001,33 @@ dependencies = [
 
 [[package]]
 name = "derive_builder"
-version = "0.12.0"
+version = "0.20.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8d67778784b508018359cbc8696edb3db78160bab2c2a28ba7f56ef6932997f8"
+checksum = "0350b5cb0331628a5916d6c5c0b72e97393b8b6b03b47a9284f4e7f5a405ffd7"
 dependencies = [
  "derive_builder_macro",
 ]
 
 [[package]]
 name = "derive_builder_core"
-version = "0.12.0"
+version = "0.20.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c11bdc11a0c47bc7d37d582b5285da6849c96681023680b906673c5707af7b0f"
+checksum = "d48cda787f839151732d396ac69e3473923d54312c070ee21e9effcaa8ca0b1d"
 dependencies = [
- "darling 0.14.4",
+ "darling",
  "proc-macro2",
  "quote",
- "syn 1.0.109",
+ "syn 2.0.48",
 ]
 
 [[package]]
 name = "derive_builder_macro"
-version = "0.12.0"
+version = "0.20.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ebcda35c7a396850a55ffeac740804b40ffec779b98fffbb1738f4033f0ee79e"
+checksum = "206868b8242f27cecce124c19fd88157fbd0dd334df2587f36417bafbc85097b"
 dependencies = [
  "derive_builder_core",
- "syn 1.0.109",
+ "syn 2.0.48",
 ]
 
 [[package]]
@@ -1084,7 +1049,7 @@ version = "0.1.6"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "4e8ef033054e131169b8f0f9a7af8f5533a9436fadf3c500ed547f730f07090d"
 dependencies = [
- "darling 0.20.5",
+ "darling",
  "proc-macro2",
  "quote",
  "syn 2.0.48",
@@ -6206,11 +6171,12 @@ checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
 
 [[package]]
 name = "windows"
-version = "0.48.0"
+version = "0.52.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e686886bc078bc1b0b600cac0147aadb815089b6e4da64016cbd754b6342700f"
+checksum = "e48a53791691ab099e5e2ad123536d0fff50652600abaf43bbf952894110d0be"
 dependencies = [
- "windows-targets 0.48.5",
+ "windows-core",
+ "windows-targets 0.52.0",
 ]
 
 [[package]]
diff --git a/compiler/rustc_codegen_cranelift/example/mini_core_hello_world.rs b/compiler/rustc_codegen_cranelift/example/mini_core_hello_world.rs
index 2a7b1107ffc..8b0b9123ac7 100644
--- a/compiler/rustc_codegen_cranelift/example/mini_core_hello_world.rs
+++ b/compiler/rustc_codegen_cranelift/example/mini_core_hello_world.rs
@@ -112,8 +112,8 @@ fn start<T: Termination + 'static>(
 
 static mut NUM: u8 = 6 * 7;
 
-// FIXME: Use `SyncUnsafeCell` instead of allowing `static_mut_ref` lint
-#[allow(static_mut_ref)]
+// FIXME: Use `SyncUnsafeCell` instead of allowing `static_mut_refs` lint
+#[allow(static_mut_refs)]
 static NUM_REF: &'static u8 = unsafe { &NUM };
 
 unsafe fn zeroed<T>() -> T {
diff --git a/compiler/rustc_codegen_gcc/example/mini_core_hello_world.rs b/compiler/rustc_codegen_gcc/example/mini_core_hello_world.rs
index 9827e299f2a..add77880716 100644
--- a/compiler/rustc_codegen_gcc/example/mini_core_hello_world.rs
+++ b/compiler/rustc_codegen_gcc/example/mini_core_hello_world.rs
@@ -99,8 +99,8 @@ fn start<T: Termination + 'static>(
 
 static mut NUM: u8 = 6 * 7;
 
-// FIXME: Use `SyncUnsafeCell` instead of allowing `static_mut_ref` lint
-#[allow(static_mut_ref)]
+// FIXME: Use `SyncUnsafeCell` instead of allowing `static_mut_refs` lint
+#[allow(static_mut_refs)]
 static NUM_REF: &'static u8 = unsafe { &NUM };
 
 macro_rules! assert {
diff --git a/compiler/rustc_codegen_ssa/Cargo.toml b/compiler/rustc_codegen_ssa/Cargo.toml
index c4aaf421444..e144b1dc1bd 100644
--- a/compiler/rustc_codegen_ssa/Cargo.toml
+++ b/compiler/rustc_codegen_ssa/Cargo.toml
@@ -51,5 +51,5 @@ default-features = false
 features = ["read_core", "elf", "macho", "pe", "xcoff", "unaligned", "archive", "write"]
 
 [target.'cfg(windows)'.dependencies.windows]
-version = "0.48.0"
+version = "0.52.0"
 features = ["Win32_Globalization"]
diff --git a/compiler/rustc_codegen_ssa/src/errors.rs b/compiler/rustc_codegen_ssa/src/errors.rs
index 3d7903b5efb..e42a8bd9ed9 100644
--- a/compiler/rustc_codegen_ssa/src/errors.rs
+++ b/compiler/rustc_codegen_ssa/src/errors.rs
@@ -362,8 +362,11 @@ impl<G: EmissionGuarantee> IntoDiagnostic<'_, G> for LinkingFailed<'_> {
         // which by now we have no way to translate.
         if contains_undefined_ref {
             diag.note(fluent::codegen_ssa_extern_funcs_not_found)
-                .note(fluent::codegen_ssa_specify_libraries_to_link)
-                .note(fluent::codegen_ssa_use_cargo_directive);
+                .note(fluent::codegen_ssa_specify_libraries_to_link);
+
+            if rustc_session::utils::was_invoked_from_cargo() {
+                diag.note(fluent::codegen_ssa_use_cargo_directive);
+            }
         }
         diag
     }
diff --git a/compiler/rustc_data_structures/Cargo.toml b/compiler/rustc_data_structures/Cargo.toml
index 0635d8552ae..80b6e72e49b 100644
--- a/compiler/rustc_data_structures/Cargo.toml
+++ b/compiler/rustc_data_structures/Cargo.toml
@@ -33,7 +33,7 @@ tracing = "0.1"
 version = "0.12"
 
 [target.'cfg(windows)'.dependencies.windows]
-version = "0.48.0"
+version = "0.52.0"
 features = [
     "Win32_Foundation",
     "Win32_Storage_FileSystem",
diff --git a/compiler/rustc_data_structures/src/flock/windows.rs b/compiler/rustc_data_structures/src/flock/windows.rs
index da128f464a6..9be1065135a 100644
--- a/compiler/rustc_data_structures/src/flock/windows.rs
+++ b/compiler/rustc_data_structures/src/flock/windows.rs
@@ -69,7 +69,6 @@ impl Lock {
                 &mut overlapped,
             )
         }
-        .ok()
         .map_err(|e| {
             let err = io::Error::from_raw_os_error(e.code().0);
             debug!("failed acquiring file lock: {}", err);
diff --git a/compiler/rustc_data_structures/src/owned_slice.rs b/compiler/rustc_data_structures/src/owned_slice.rs
index cbb3047d884..bb664795860 100644
--- a/compiler/rustc_data_structures/src/owned_slice.rs
+++ b/compiler/rustc_data_structures/src/owned_slice.rs
@@ -4,7 +4,7 @@ use crate::sync::Lrc;
 // Use our fake Send/Sync traits when on not parallel compiler,
 // so that `OwnedSlice` only implements/requires Send/Sync
 // for parallel compiler builds.
-use crate::sync::{Send, Sync};
+use crate::sync;
 
 /// An owned slice.
 ///
@@ -33,7 +33,7 @@ pub struct OwnedSlice {
     //       \/
     //      ⊂(´・◡・⊂ )∘˚˳° (I am the phantom remnant of #97770)
     #[expect(dead_code)]
-    owner: Lrc<dyn Send + Sync>,
+    owner: Lrc<dyn sync::Send + sync::Sync>,
 }
 
 /// Makes an [`OwnedSlice`] out of an `owner` and a `slicer` function.
@@ -60,7 +60,7 @@ pub struct OwnedSlice {
 /// ```
 pub fn slice_owned<O, F>(owner: O, slicer: F) -> OwnedSlice
 where
-    O: Send + Sync + 'static,
+    O: sync::Send + sync::Sync + 'static,
     F: FnOnce(&O) -> &[u8],
 {
     try_slice_owned(owner, |x| Ok::<_, !>(slicer(x))).into_ok()
@@ -71,7 +71,7 @@ where
 /// See [`slice_owned`] for the infallible version.
 pub fn try_slice_owned<O, F, E>(owner: O, slicer: F) -> Result<OwnedSlice, E>
 where
-    O: Send + Sync + 'static,
+    O: sync::Send + sync::Sync + 'static,
     F: FnOnce(&O) -> Result<&[u8], E>,
 {
     // We wrap the owner of the bytes in, so it doesn't move.
@@ -139,11 +139,11 @@ impl Borrow<[u8]> for OwnedSlice {
 
 // Safety: `OwnedSlice` is conceptually `(&'self.1 [u8], Arc<dyn Send + Sync>)`, which is `Send`
 #[cfg(parallel_compiler)]
-unsafe impl Send for OwnedSlice {}
+unsafe impl sync::Send for OwnedSlice {}
 
 // Safety: `OwnedSlice` is conceptually `(&'self.1 [u8], Arc<dyn Send + Sync>)`, which is `Sync`
 #[cfg(parallel_compiler)]
-unsafe impl Sync for OwnedSlice {}
+unsafe impl sync::Sync for OwnedSlice {}
 
 #[cfg(test)]
 mod tests;
diff --git a/compiler/rustc_data_structures/src/profiling.rs b/compiler/rustc_data_structures/src/profiling.rs
index e29d4811980..2569684df3f 100644
--- a/compiler/rustc_data_structures/src/profiling.rs
+++ b/compiler/rustc_data_structures/src/profiling.rs
@@ -866,16 +866,14 @@ cfg_match! {
             use std::mem;
 
             use windows::{
-                // FIXME: change back to K32GetProcessMemoryInfo when windows crate
-                // updated to 0.49.0+ to drop dependency on psapi.dll
-                Win32::System::ProcessStatus::{GetProcessMemoryInfo, PROCESS_MEMORY_COUNTERS},
+                Win32::System::ProcessStatus::{K32GetProcessMemoryInfo, PROCESS_MEMORY_COUNTERS},
                 Win32::System::Threading::GetCurrentProcess,
             };
 
             let mut pmc = PROCESS_MEMORY_COUNTERS::default();
             let pmc_size = mem::size_of_val(&pmc);
             unsafe {
-                GetProcessMemoryInfo(
+                K32GetProcessMemoryInfo(
                     GetCurrentProcess(),
                     &mut pmc,
                     pmc_size as u32,
diff --git a/compiler/rustc_driver_impl/Cargo.toml b/compiler/rustc_driver_impl/Cargo.toml
index bfdd871455c..242aa06fe3e 100644
--- a/compiler/rustc_driver_impl/Cargo.toml
+++ b/compiler/rustc_driver_impl/Cargo.toml
@@ -60,7 +60,7 @@ libc = "0.2"
 # tidy-alphabetical-end
 
 [target.'cfg(windows)'.dependencies.windows]
-version = "0.48.0"
+version = "0.52.0"
 features = [
     "Win32_System_Diagnostics_Debug",
 ]
diff --git a/compiler/rustc_error_codes/src/error_codes/E0796.md b/compiler/rustc_error_codes/src/error_codes/E0796.md
index cea18f8db85..7ac429e5215 100644
--- a/compiler/rustc_error_codes/src/error_codes/E0796.md
+++ b/compiler/rustc_error_codes/src/error_codes/E0796.md
@@ -1,22 +1,26 @@
-Reference of mutable static.
+You have created a reference to a mutable static.
 
 Erroneous code example:
 
 ```compile_fail,edition2024,E0796
 static mut X: i32 = 23;
-static mut Y: i32 = 24;
 
-unsafe {
-  let y = &X;
-  let ref x = X;
-  let (x, y) = (&X, &Y);
-  foo(&X);
+fn work() {
+  let _val = unsafe { X };
 }
 
-fn foo<'a>(_x: &'a i32) {}
+let x_ref = unsafe { &mut X };
+work();
+// The next line has Undefined Behavior!
+// `x_ref` is a mutable reference and allows no aliases,
+// but `work` has been reading the reference between
+// the moment `x_ref` was created and when it was used.
+// This violates the uniqueness of `x_ref`.
+*x_ref = 42;
 ```
 
-Mutable statics can be written to by multiple threads: aliasing violations or
-data races will cause undefined behavior.
+A reference to a mutable static has lifetime `'static`. This is very dangerous
+as it is easy to accidentally overlap the lifetime of that reference with
+other, conflicting accesses to the same static.
 
-Reference of mutable static is a hard error from 2024 edition.
+References to mutable statics are a hard error in the 2024 edition.
diff --git a/compiler/rustc_errors/Cargo.toml b/compiler/rustc_errors/Cargo.toml
index a2d1fd2a924..cc114fdcd8c 100644
--- a/compiler/rustc_errors/Cargo.toml
+++ b/compiler/rustc_errors/Cargo.toml
@@ -30,7 +30,7 @@ unicode-width = "0.1.4"
 # tidy-alphabetical-end
 
 [target.'cfg(windows)'.dependencies.windows]
-version = "0.48.0"
+version = "0.52.0"
 features = [
     "Win32_Foundation",
     "Win32_Security",
diff --git a/compiler/rustc_errors/src/lock.rs b/compiler/rustc_errors/src/lock.rs
index bd5cf49b56b..0aeb511214b 100644
--- a/compiler/rustc_errors/src/lock.rs
+++ b/compiler/rustc_errors/src/lock.rs
@@ -27,7 +27,8 @@ pub fn acquire_global_lock(name: &str) -> Box<dyn Any> {
     impl Drop for Handle {
         fn drop(&mut self) {
             unsafe {
-                CloseHandle(self.0);
+                // FIXME can panic here
+                CloseHandle(self.0).unwrap();
             }
         }
     }
@@ -37,7 +38,8 @@ pub fn acquire_global_lock(name: &str) -> Box<dyn Any> {
     impl Drop for Guard {
         fn drop(&mut self) {
             unsafe {
-                ReleaseMutex((self.0).0);
+                // FIXME can panic here
+                ReleaseMutex((self.0).0).unwrap();
             }
         }
     }
diff --git a/compiler/rustc_expand/messages.ftl b/compiler/rustc_expand/messages.ftl
index 3e3b4814300..5a3303327db 100644
--- a/compiler/rustc_expand/messages.ftl
+++ b/compiler/rustc_expand/messages.ftl
@@ -61,6 +61,11 @@ expand_invalid_cfg_multiple_predicates = multiple `cfg` predicates are specified
 expand_invalid_cfg_no_parens = `cfg` is not followed by parentheses
 expand_invalid_cfg_no_predicate = `cfg` predicate is not specified
 expand_invalid_cfg_predicate_literal = `cfg` predicate key cannot be a literal
+
+expand_invalid_fragment_specifier =
+    invalid fragment specifier `{$fragment}`
+    .help = {$help}
+
 expand_macro_body_stability =
     macros cannot have body stability attributes
     .label = invalid body stability attribute
diff --git a/compiler/rustc_expand/src/errors.rs b/compiler/rustc_expand/src/errors.rs
index 2584ff62e98..929f3479466 100644
--- a/compiler/rustc_expand/src/errors.rs
+++ b/compiler/rustc_expand/src/errors.rs
@@ -408,3 +408,13 @@ pub struct DuplicateMatcherBinding {
     #[label(expand_label2)]
     pub prev: Span,
 }
+
+#[derive(Diagnostic)]
+#[diag(expand_invalid_fragment_specifier)]
+#[help]
+pub struct InvalidFragmentSpecifier {
+    #[primary_span]
+    pub span: Span,
+    pub fragment: Ident,
+    pub help: String,
+}
diff --git a/compiler/rustc_expand/src/lib.rs b/compiler/rustc_expand/src/lib.rs
index 4da86d77dc8..0e73abc9ed8 100644
--- a/compiler/rustc_expand/src/lib.rs
+++ b/compiler/rustc_expand/src/lib.rs
@@ -6,6 +6,7 @@
 #![feature(if_let_guard)]
 #![feature(let_chains)]
 #![feature(macro_metavar_expr)]
+#![feature(map_try_insert)]
 #![feature(proc_macro_diagnostic)]
 #![feature(proc_macro_internals)]
 #![feature(proc_macro_span)]
diff --git a/compiler/rustc_expand/src/mbe/quoted.rs b/compiler/rustc_expand/src/mbe/quoted.rs
index 4824b67d277..0fdfa563138 100644
--- a/compiler/rustc_expand/src/mbe/quoted.rs
+++ b/compiler/rustc_expand/src/mbe/quoted.rs
@@ -1,3 +1,4 @@
+use crate::errors;
 use crate::mbe::macro_parser::count_metavar_decls;
 use crate::mbe::{Delimited, KleeneOp, KleeneToken, MetaVarExpr, SequenceRepetition, TokenTree};
 
@@ -60,11 +61,11 @@ pub(super) fn parse(
                     Some(&tokenstream::TokenTree::Token(Token { kind: token::Colon, span }, _)) => {
                         match trees.next() {
                             Some(tokenstream::TokenTree::Token(token, _)) => match token.ident() {
-                                Some((frag, _)) => {
+                                Some((fragment, _)) => {
                                     let span = token.span.with_lo(start_sp.lo());
 
                                     let kind =
-                                        token::NonterminalKind::from_symbol(frag.name, || {
+                                        token::NonterminalKind::from_symbol(fragment.name, || {
                                             // FIXME(#85708) - once we properly decode a foreign
                                             // crate's `SyntaxContext::root`, then we can replace
                                             // this with just `span.edition()`. A
@@ -81,14 +82,13 @@ pub(super) fn parse(
                                         })
                                         .unwrap_or_else(
                                             || {
-                                                let msg = format!(
-                                                    "invalid fragment specifier `{}`",
-                                                    frag.name
+                                                sess.dcx().emit_err(
+                                                    errors::InvalidFragmentSpecifier {
+                                                        span,
+                                                        fragment,
+                                                        help: VALID_FRAGMENT_NAMES_MSG.into(),
+                                                    },
                                                 );
-                                                sess.dcx()
-                                                    .struct_span_err(span, msg)
-                                                    .with_help(VALID_FRAGMENT_NAMES_MSG)
-                                                    .emit();
                                                 token::NonterminalKind::Ident
                                             },
                                         );
diff --git a/compiler/rustc_expand/src/mbe/transcribe.rs b/compiler/rustc_expand/src/mbe/transcribe.rs
index 434891ebc76..519e4a634d8 100644
--- a/compiler/rustc_expand/src/mbe/transcribe.rs
+++ b/compiler/rustc_expand/src/mbe/transcribe.rs
@@ -13,7 +13,7 @@ use rustc_errors::DiagnosticBuilder;
 use rustc_errors::{pluralize, PResult};
 use rustc_span::hygiene::{LocalExpnId, Transparency};
 use rustc_span::symbol::{sym, Ident, MacroRulesNormalizedIdent};
-use rustc_span::{Span, SyntaxContext};
+use rustc_span::{with_metavar_spans, Span, SyntaxContext};
 
 use smallvec::{smallvec, SmallVec};
 use std::mem;
@@ -254,7 +254,8 @@ pub(super) fn transcribe<'a>(
                         MatchedTokenTree(tt) => {
                             // `tt`s are emitted into the output stream directly as "raw tokens",
                             // without wrapping them into groups.
-                            result.push(maybe_use_metavar_location(cx, &stack, sp, tt));
+                            let tt = maybe_use_metavar_location(cx, &stack, sp, tt, &mut marker);
+                            result.push(tt);
                         }
                         MatchedNonterminal(nt) => {
                             // Other variables are emitted into the output stream as groups with
@@ -319,6 +320,17 @@ pub(super) fn transcribe<'a>(
     }
 }
 
+/// Store the metavariable span for this original span into a side table.
+/// FIXME: Try to put the metavariable span into `SpanData` instead of a side table (#118517).
+/// An optimal encoding for inlined spans will need to be selected to minimize regressions.
+/// The side table approach is relatively good, but not perfect due to collisions.
+/// In particular, collisions happen when token is passed as an argument through several macro
+/// calls, like in recursive macros.
+/// The old heuristic below is used to improve spans in case of collisions, but diagnostics are
+/// still degraded sometimes in those cases.
+///
+/// The old heuristic:
+///
 /// Usually metavariables `$var` produce interpolated tokens, which have an additional place for
 /// keeping both the original span and the metavariable span. For `tt` metavariables that's not the
 /// case however, and there's no place for keeping a second span. So we try to give the single
@@ -338,15 +350,12 @@ pub(super) fn transcribe<'a>(
 ///   These are typically used for passing larger amounts of code, and tokens in that code usually
 ///   combine with each other and not with tokens outside of the sequence.
 /// - The metavariable span comes from a different crate, then we prefer the more local span.
-///
-/// FIXME: Find a way to keep both original and metavariable spans for all tokens without
-/// regressing compilation time too much. Several experiments for adding such spans were made in
-/// the past (PR #95580, #118517, #118671) and all showed some regressions.
 fn maybe_use_metavar_location(
     cx: &ExtCtxt<'_>,
     stack: &[Frame<'_>],
-    metavar_span: Span,
+    mut metavar_span: Span,
     orig_tt: &TokenTree,
+    marker: &mut Marker,
 ) -> TokenTree {
     let undelimited_seq = matches!(
         stack.last(),
@@ -357,18 +366,44 @@ fn maybe_use_metavar_location(
             ..
         })
     );
-    if undelimited_seq || cx.source_map().is_imported(metavar_span) {
+    if undelimited_seq {
+        // Do not record metavar spans for tokens from undelimited sequences, for perf reasons.
+        return orig_tt.clone();
+    }
+
+    let insert = |mspans: &mut FxHashMap<_, _>, s, ms| match mspans.try_insert(s, ms) {
+        Ok(_) => true,
+        Err(err) => *err.entry.get() == ms, // Tried to insert the same span, still success
+    };
+    marker.visit_span(&mut metavar_span);
+    let no_collision = match orig_tt {
+        TokenTree::Token(token, ..) => {
+            with_metavar_spans(|mspans| insert(mspans, token.span, metavar_span))
+        }
+        TokenTree::Delimited(dspan, ..) => with_metavar_spans(|mspans| {
+            insert(mspans, dspan.open, metavar_span)
+                && insert(mspans, dspan.close, metavar_span)
+                && insert(mspans, dspan.entire(), metavar_span)
+        }),
+    };
+    if no_collision || cx.source_map().is_imported(metavar_span) {
         return orig_tt.clone();
     }
 
+    // Setting metavar spans for the heuristic spans gives better opportunities for combining them
+    // with neighboring spans even despite their different syntactic contexts.
     match orig_tt {
         TokenTree::Token(Token { kind, span }, spacing) => {
             let span = metavar_span.with_ctxt(span.ctxt());
+            with_metavar_spans(|mspans| insert(mspans, span, metavar_span));
             TokenTree::Token(Token { kind: kind.clone(), span }, *spacing)
         }
         TokenTree::Delimited(dspan, dspacing, delimiter, tts) => {
-            let open = metavar_span.shrink_to_lo().with_ctxt(dspan.open.ctxt());
-            let close = metavar_span.shrink_to_hi().with_ctxt(dspan.close.ctxt());
+            let open = metavar_span.with_ctxt(dspan.open.ctxt());
+            let close = metavar_span.with_ctxt(dspan.close.ctxt());
+            with_metavar_spans(|mspans| {
+                insert(mspans, open, metavar_span) && insert(mspans, close, metavar_span)
+            });
             let dspan = DelimSpan::from_pair(open, close);
             TokenTree::Delimited(dspan, *dspacing, *delimiter, tts.clone())
         }
diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs
index 77044df9a40..fcb15925f6a 100644
--- a/compiler/rustc_hir/src/hir.rs
+++ b/compiler/rustc_hir/src/hir.rs
@@ -2998,6 +2998,12 @@ impl<'hir> Item<'hir> {
         ItemId { owner_id: self.owner_id }
     }
 
+    /// Check if this is an [`ItemKind::Enum`], [`ItemKind::Struct`] or
+    /// [`ItemKind::Union`].
+    pub fn is_adt(&self) -> bool {
+        matches!(self.kind, ItemKind::Enum(..) | ItemKind::Struct(..) | ItemKind::Union(..))
+    }
+
     expect_methods_self_kind! {
         expect_extern_crate, Option<Symbol>, ItemKind::ExternCrate(s), *s;
 
diff --git a/compiler/rustc_hir_analysis/messages.ftl b/compiler/rustc_hir_analysis/messages.ftl
index a61cfd0e4ce..89cd37e757f 100644
--- a/compiler/rustc_hir_analysis/messages.ftl
+++ b/compiler/rustc_hir_analysis/messages.ftl
@@ -198,6 +198,8 @@ hir_analysis_invalid_union_field =
 hir_analysis_invalid_union_field_sugg =
     wrap the field type in `ManuallyDrop<...>`
 
+hir_analysis_invalid_unnamed_field_ty = unnamed fields can only have struct or union types
+
 hir_analysis_late_bound_const_in_apit = `impl Trait` can only mention const parameters from an fn or impl
     .label = const parameter declared here
 
@@ -373,19 +375,24 @@ hir_analysis_start_not_target_feature = `#[start]` function is not allowed to ha
 hir_analysis_start_not_track_caller = `#[start]` function is not allowed to be `#[track_caller]`
     .label = `#[start]` function is not allowed to be `#[track_caller]`
 
-hir_analysis_static_mut_ref = reference of mutable static is disallowed
-    .label = reference of mutable static
-    .note = mutable statics can be written to by multiple threads: aliasing violations or data races will cause undefined behavior
-    .suggestion = shared references are dangerous since if there's any kind of mutation of that static while the reference lives, that's UB; use `addr_of!` instead to create a raw pointer
-    .suggestion_mut = mutable references are dangerous since if there's any other pointer or reference used for that static while the reference lives, that's UB; use `addr_of_mut!` instead to create a raw pointer
-
-hir_analysis_static_mut_ref_lint = {$shared}reference of mutable static is discouraged
-    .label = shared reference of mutable static
-    .label_mut = mutable reference of mutable static
-    .suggestion = shared references are dangerous since if there's any kind of mutation of that static while the reference lives, that's UB; use `addr_of!` instead to create a raw pointer
-    .suggestion_mut = mutable references are dangerous since if there's any other pointer or reference used for that static while the reference lives, that's UB; use `addr_of_mut!` instead to create a raw pointer
-    .note = reference of mutable static is a hard error from 2024 edition
-    .why_note = mutable statics can be written to by multiple threads: aliasing violations or data races will cause undefined behavior
+hir_analysis_static_mut_ref = creating a {$shared} reference to a mutable static
+    .label = {$shared} reference to mutable static
+    .note = {$shared ->
+        [shared] this shared reference has lifetime `'static`, but if the static ever gets mutated, or a mutable reference is created, then any further use of this shared reference is Undefined Behavior
+        *[mutable] this mutable reference has lifetime `'static`, but if the static gets accessed (read or written) by any other means, or any other reference is created, then any further use of this mutable reference is Undefined Behavior
+    }
+    .suggestion = use `addr_of!` instead to create a raw pointer
+    .suggestion_mut = use `addr_of_mut!` instead to create a raw pointer
+
+hir_analysis_static_mut_refs_lint = creating a {$shared} reference to mutable static is discouraged
+    .label = {$shared} reference to mutable static
+    .suggestion = use `addr_of!` instead to create a raw pointer
+    .suggestion_mut = use `addr_of_mut!` instead to create a raw pointer
+    .note = this will be a hard error in the 2024 edition
+    .why_note = {$shared ->
+        [shared] this shared reference has lifetime `'static`, but if the static ever gets mutated, or a mutable reference is created, then any further use of this shared reference is Undefined Behavior
+        *[mutable] this mutable reference has lifetime `'static`, but if the static gets accessed (read or written) by any other means, or any other reference is created, then any further use of this mutable reference is Undefined Behavior
+    }
 
 hir_analysis_static_specialize = cannot specialize on `'static` lifetime
 
@@ -462,6 +469,7 @@ hir_analysis_unrecognized_atomic_operation =
 hir_analysis_unrecognized_intrinsic_function =
     unrecognized intrinsic function: `{$name}`
     .label = unrecognized intrinsic
+    .help = if you're adding an intrinsic, be sure to update `check_intrinsic_type`
 
 hir_analysis_unused_associated_type_bounds =
     unnecessary associated type bound for not object safe associated type
diff --git a/compiler/rustc_hir_analysis/src/astconv/bounds.rs b/compiler/rustc_hir_analysis/src/astconv/bounds.rs
index dab1e2d5253..6940b4a5045 100644
--- a/compiler/rustc_hir_analysis/src/astconv/bounds.rs
+++ b/compiler/rustc_hir_analysis/src/astconv/bounds.rs
@@ -9,9 +9,7 @@ use rustc_span::{ErrorGuaranteed, Span};
 use rustc_trait_selection::traits;
 use smallvec::SmallVec;
 
-use crate::astconv::{
-    AstConv, ConvertedBinding, ConvertedBindingKind, OnlySelfBounds, PredicateFilter,
-};
+use crate::astconv::{AstConv, OnlySelfBounds, PredicateFilter};
 use crate::bounds::Bounds;
 use crate::errors;
 
@@ -238,7 +236,7 @@ impl<'tcx> dyn AstConv<'tcx> + '_ {
         &self,
         hir_ref_id: hir::HirId,
         trait_ref: ty::PolyTraitRef<'tcx>,
-        binding: &ConvertedBinding<'_, 'tcx>,
+        binding: &hir::TypeBinding<'tcx>,
         bounds: &mut Bounds<'tcx>,
         speculative: bool,
         dup_bindings: &mut FxIndexMap<DefId, Span>,
@@ -263,21 +261,20 @@ impl<'tcx> dyn AstConv<'tcx> + '_ {
 
         let tcx = self.tcx();
 
-        let assoc_kind =
-            if binding.gen_args.parenthesized == hir::GenericArgsParentheses::ReturnTypeNotation {
-                ty::AssocKind::Fn
-            } else if let ConvertedBindingKind::Equality(term) = binding.kind
-                && let ty::TermKind::Const(_) = term.node.unpack()
-            {
-                ty::AssocKind::Const
-            } else {
-                ty::AssocKind::Type
-            };
+        let assoc_kind = if binding.gen_args.parenthesized
+            == hir::GenericArgsParentheses::ReturnTypeNotation
+        {
+            ty::AssocKind::Fn
+        } else if let hir::TypeBindingKind::Equality { term: hir::Term::Const(_) } = binding.kind {
+            ty::AssocKind::Const
+        } else {
+            ty::AssocKind::Type
+        };
 
         let candidate = if self.trait_defines_associated_item_named(
             trait_ref.def_id(),
             assoc_kind,
-            binding.item_name,
+            binding.ident,
         ) {
             // Simple case: The assoc item is defined in the current trait.
             trait_ref
@@ -289,14 +286,14 @@ impl<'tcx> dyn AstConv<'tcx> + '_ {
                 trait_ref.skip_binder().print_only_trait_name(),
                 None,
                 assoc_kind,
-                binding.item_name,
+                binding.ident,
                 path_span,
-                Some(&binding),
+                Some(binding),
             )?
         };
 
         let (assoc_ident, def_scope) =
-            tcx.adjust_ident_and_get_scope(binding.item_name, candidate.def_id(), hir_ref_id);
+            tcx.adjust_ident_and_get_scope(binding.ident, candidate.def_id(), hir_ref_id);
 
         // We have already adjusted the item name above, so compare with `.normalize_to_macros_2_0()`
         // instead of calling `filter_by_name_and_kind` which would needlessly normalize the
@@ -312,7 +309,7 @@ impl<'tcx> dyn AstConv<'tcx> + '_ {
                 .dcx()
                 .struct_span_err(
                     binding.span,
-                    format!("{} `{}` is private", assoc_item.kind, binding.item_name),
+                    format!("{} `{}` is private", assoc_item.kind, binding.ident),
                 )
                 .with_span_label(binding.span, format!("private {}", assoc_item.kind))
                 .emit();
@@ -327,7 +324,7 @@ impl<'tcx> dyn AstConv<'tcx> + '_ {
                     tcx.dcx().emit_err(errors::ValueOfAssociatedStructAlreadySpecified {
                         span: binding.span,
                         prev_span: *prev_span,
-                        item_name: binding.item_name,
+                        item_name: binding.ident,
                         def_path: tcx.def_path_str(assoc_item.container_id(tcx)),
                     });
                 })
@@ -390,14 +387,12 @@ impl<'tcx> dyn AstConv<'tcx> + '_ {
             {
                 alias_ty
             } else {
-                return Err(self.tcx().dcx().emit_err(
-                    crate::errors::ReturnTypeNotationOnNonRpitit {
-                        span: binding.span,
-                        ty: tcx.liberate_late_bound_regions(assoc_item.def_id, output),
-                        fn_span: tcx.hir().span_if_local(assoc_item.def_id),
-                        note: (),
-                    },
-                ));
+                return Err(tcx.dcx().emit_err(crate::errors::ReturnTypeNotationOnNonRpitit {
+                    span: binding.span,
+                    ty: tcx.liberate_late_bound_regions(assoc_item.def_id, output),
+                    fn_span: tcx.hir().span_if_local(assoc_item.def_id),
+                    note: (),
+                }));
             };
 
             // Finally, move the fn return type's bound vars over to account for the early bound
@@ -410,9 +405,11 @@ impl<'tcx> dyn AstConv<'tcx> + '_ {
             let bound_vars = tcx.late_bound_vars(binding.hir_id);
             ty::Binder::bind_with_vars(instantiation_output, bound_vars)
         } else {
-            // Append the generic arguments of the associated type to the `trait_ref`.
+            // Create the generic arguments for the associated type or constant by joining the
+            // parent arguments (the arguments of the trait) and the own arguments (the ones of
+            // the associated item itself) and construct an alias type using them.
             candidate.map_bound(|trait_ref| {
-                let ident = Ident::new(assoc_item.name, binding.item_name.span);
+                let ident = Ident::new(assoc_item.name, binding.ident.span);
                 let item_segment = hir::PathSegment {
                     ident,
                     hir_id: binding.hir_id,
@@ -421,77 +418,82 @@ impl<'tcx> dyn AstConv<'tcx> + '_ {
                     infer_args: false,
                 };
 
-                let args_trait_ref_and_assoc_item = self.create_args_for_associated_item(
+                let alias_args = self.create_args_for_associated_item(
                     path_span,
                     assoc_item.def_id,
                     &item_segment,
                     trait_ref.args,
                 );
+                debug!(?alias_args);
 
-                debug!(?args_trait_ref_and_assoc_item);
-
-                ty::AliasTy::new(tcx, assoc_item.def_id, args_trait_ref_and_assoc_item)
+                // Note that we're indeed also using `AliasTy` (alias *type*) for associated
+                // *constants* to represent *const projections*. Alias *term* would be a more
+                // appropriate name but alas.
+                ty::AliasTy::new(tcx, assoc_item.def_id, alias_args)
             })
         };
 
-        if !speculative {
-            // Find any late-bound regions declared in `ty` that are not
-            // declared in the trait-ref or assoc_item. These are not well-formed.
-            //
-            // Example:
-            //
-            //     for<'a> <T as Iterator>::Item = &'a str // <-- 'a is bad
-            //     for<'a> <T as FnMut<(&'a u32,)>>::Output = &'a str // <-- 'a is ok
-            if let ConvertedBindingKind::Equality(ty) = binding.kind {
-                let late_bound_in_trait_ref =
-                    tcx.collect_constrained_late_bound_regions(&projection_ty);
-                let late_bound_in_ty =
-                    tcx.collect_referenced_late_bound_regions(&trait_ref.rebind(ty.node));
-                debug!(?late_bound_in_trait_ref);
-                debug!(?late_bound_in_ty);
-
-                // FIXME: point at the type params that don't have appropriate lifetimes:
-                // struct S1<F: for<'a> Fn(&i32, &i32) -> &'a i32>(F);
-                //                         ----  ----     ^^^^^^^
-                self.validate_late_bound_regions(
-                    late_bound_in_trait_ref,
-                    late_bound_in_ty,
-                    |br_name| {
-                        struct_span_code_err!(
-                            tcx.dcx(),
-                            binding.span,
-                            E0582,
-                            "binding for associated type `{}` references {}, \
-                             which does not appear in the trait input types",
-                            binding.item_name,
-                            br_name
-                        )
-                    },
-                );
-            }
-        }
-
         match binding.kind {
-            ConvertedBindingKind::Equality(..) if let ty::AssocKind::Fn = assoc_kind => {
-                return Err(self.tcx().dcx().emit_err(
-                    crate::errors::ReturnTypeNotationEqualityBound { span: binding.span },
-                ));
+            hir::TypeBindingKind::Equality { .. } if let ty::AssocKind::Fn = assoc_kind => {
+                return Err(tcx.dcx().emit_err(crate::errors::ReturnTypeNotationEqualityBound {
+                    span: binding.span,
+                }));
             }
-            ConvertedBindingKind::Equality(term) => {
+            hir::TypeBindingKind::Equality { term } => {
+                let term = match term {
+                    hir::Term::Ty(ty) => self.ast_ty_to_ty(ty).into(),
+                    hir::Term::Const(ct) => ty::Const::from_anon_const(tcx, ct.def_id).into(),
+                };
+
+                if !speculative {
+                    // Find any late-bound regions declared in `ty` that are not
+                    // declared in the trait-ref or assoc_item. These are not well-formed.
+                    //
+                    // Example:
+                    //
+                    //     for<'a> <T as Iterator>::Item = &'a str // <-- 'a is bad
+                    //     for<'a> <T as FnMut<(&'a u32,)>>::Output = &'a str // <-- 'a is ok
+                    let late_bound_in_projection_ty =
+                        tcx.collect_constrained_late_bound_regions(&projection_ty);
+                    let late_bound_in_term =
+                        tcx.collect_referenced_late_bound_regions(&trait_ref.rebind(term));
+                    debug!(?late_bound_in_projection_ty);
+                    debug!(?late_bound_in_term);
+
+                    // FIXME: point at the type params that don't have appropriate lifetimes:
+                    // struct S1<F: for<'a> Fn(&i32, &i32) -> &'a i32>(F);
+                    //                         ----  ----     ^^^^^^^
+                    // NOTE(associated_const_equality): This error should be impossible to trigger
+                    //                                  with associated const equality bounds.
+                    self.validate_late_bound_regions(
+                        late_bound_in_projection_ty,
+                        late_bound_in_term,
+                        |br_name| {
+                            struct_span_code_err!(
+                                tcx.dcx(),
+                                binding.span,
+                                E0582,
+                                "binding for associated type `{}` references {}, \
+                                 which does not appear in the trait input types",
+                                binding.ident,
+                                br_name
+                            )
+                        },
+                    );
+                }
+
                 // "Desugar" a constraint like `T: Iterator<Item = u32>` this to
                 // the "projection predicate" for:
                 //
                 // `<T as Iterator>::Item = u32`
                 bounds.push_projection_bound(
                     tcx,
-                    projection_ty.map_bound(|projection_ty| ty::ProjectionPredicate {
-                        projection_ty,
-                        term: term.node,
-                    }),
+                    projection_ty
+                        .map_bound(|projection_ty| ty::ProjectionPredicate { projection_ty, term }),
                     binding.span,
                 );
             }
-            ConvertedBindingKind::Constraint(ast_bounds) => {
+            hir::TypeBindingKind::Constraint { bounds: ast_bounds } => {
                 // "Desugar" a constraint like `T: Iterator<Item: Debug>` to
                 //
                 // `<T as Iterator>::Item: Debug`
diff --git a/compiler/rustc_hir_analysis/src/astconv/errors.rs b/compiler/rustc_hir_analysis/src/astconv/errors.rs
index ea8d364bba6..ad34c31ef8f 100644
--- a/compiler/rustc_hir_analysis/src/astconv/errors.rs
+++ b/compiler/rustc_hir_analysis/src/astconv/errors.rs
@@ -1,4 +1,4 @@
-use crate::astconv::{AstConv, ConvertedBindingKind};
+use crate::astconv::AstConv;
 use crate::errors::{
     self, AssocTypeBindingNotAllowed, ManualImplementation, MissingTypeParams,
     ParenthesizedFnTraitExpansion,
@@ -111,7 +111,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
         assoc_kind: ty::AssocKind,
         assoc_name: Ident,
         span: Span,
-        binding: Option<&super::ConvertedBinding<'_, 'tcx>>,
+        binding: Option<&hir::TypeBinding<'tcx>>,
     ) -> ErrorGuaranteed
     where
         I: Iterator<Item = ty::PolyTraitRef<'tcx>>,
@@ -243,7 +243,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
                         None,
                     ) && suggested_name != assoc_name.name
                     {
-                        // We suggested constraining a type parameter, but the associated type on it
+                        // We suggested constraining a type parameter, but the associated item on it
                         // was also not an exact match, so we also suggest changing it.
                         err.span_suggestion_verbose(
                             assoc_name.span,
@@ -258,16 +258,17 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
             }
         }
 
-        // If we still couldn't find any associated type, and only one associated type exists,
+        // If we still couldn't find any associated item, and only one associated item exists,
         // suggests using it.
         if let [candidate_name] = all_candidate_names.as_slice() {
-            // this should still compile, except on `#![feature(associated_type_defaults)]`
-            // where it could suggests `type A = Self::A`, thus recursing infinitely
-            let applicability = if tcx.features().associated_type_defaults {
-                Applicability::Unspecified
-            } else {
-                Applicability::MaybeIncorrect
-            };
+            // This should still compile, except on `#![feature(associated_type_defaults)]`
+            // where it could suggests `type A = Self::A`, thus recursing infinitely.
+            let applicability =
+                if assoc_kind == ty::AssocKind::Type && tcx.features().associated_type_defaults {
+                    Applicability::Unspecified
+                } else {
+                    Applicability::MaybeIncorrect
+                };
 
             err.sugg = Some(errors::AssocItemNotFoundSugg::Other {
                 span: assoc_name.span,
@@ -289,13 +290,13 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
         assoc_kind: ty::AssocKind,
         ident: Ident,
         span: Span,
-        binding: Option<&super::ConvertedBinding<'_, 'tcx>>,
+        binding: Option<&hir::TypeBinding<'tcx>>,
     ) -> ErrorGuaranteed {
         let tcx = self.tcx();
 
         let bound_on_assoc_const_label = if let ty::AssocKind::Const = assoc_item.kind
             && let Some(binding) = binding
-            && let ConvertedBindingKind::Constraint(_) = binding.kind
+            && let hir::TypeBindingKind::Constraint { .. } = binding.kind
         {
             let lo = if binding.gen_args.span_ext.is_dummy() {
                 ident.span
@@ -309,25 +310,29 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
 
         // FIXME(associated_const_equality): This has quite a few false positives and negatives.
         let wrap_in_braces_sugg = if let Some(binding) = binding
-            && let ConvertedBindingKind::Equality(term) = binding.kind
-            && let ty::TermKind::Ty(ty) = term.node.unpack()
+            && let hir::TypeBindingKind::Equality { term: hir::Term::Ty(hir_ty) } = binding.kind
+            && let ty = self.ast_ty_to_ty(hir_ty)
             && (ty.is_enum() || ty.references_error())
             && tcx.features().associated_const_equality
         {
             Some(errors::AssocKindMismatchWrapInBracesSugg {
-                lo: term.span.shrink_to_lo(),
-                hi: term.span.shrink_to_hi(),
+                lo: hir_ty.span.shrink_to_lo(),
+                hi: hir_ty.span.shrink_to_hi(),
             })
         } else {
             None
         };
 
         // For equality bounds, we want to blame the term (RHS) instead of the item (LHS) since
-        // one can argue that that's more “untuitive” to the user.
+        // one can argue that that's more “intuitive” to the user.
         let (span, expected_because_label, expected, got) = if let Some(binding) = binding
-            && let ConvertedBindingKind::Equality(term) = binding.kind
+            && let hir::TypeBindingKind::Equality { term } = binding.kind
         {
-            (term.span, Some(ident.span), assoc_item.kind, assoc_kind)
+            let span = match term {
+                hir::Term::Ty(ty) => ty.span,
+                hir::Term::Const(ct) => tcx.def_span(ct.def_id),
+            };
+            (span, Some(ident.span), assoc_item.kind, assoc_kind)
         } else {
             (ident.span, None, assoc_kind, assoc_item.kind)
         };
diff --git a/compiler/rustc_hir_analysis/src/astconv/mod.rs b/compiler/rustc_hir_analysis/src/astconv/mod.rs
index 94c49453cdc..3ccf78567ed 100644
--- a/compiler/rustc_hir_analysis/src/astconv/mod.rs
+++ b/compiler/rustc_hir_analysis/src/astconv/mod.rs
@@ -35,7 +35,6 @@ use rustc_middle::ty::{
 };
 use rustc_session::lint::builtin::AMBIGUOUS_ASSOCIATED_ITEMS;
 use rustc_span::edit_distance::find_best_match_for_name;
-use rustc_span::source_map::{respan, Spanned};
 use rustc_span::symbol::{kw, Ident, Symbol};
 use rustc_span::{sym, BytePos, Span, DUMMY_SP};
 use rustc_target::spec::abi;
@@ -151,21 +150,6 @@ pub trait AstConv<'tcx> {
     fn infcx(&self) -> Option<&InferCtxt<'tcx>>;
 }
 
-#[derive(Debug)]
-struct ConvertedBinding<'a, 'tcx> {
-    hir_id: hir::HirId,
-    item_name: Ident,
-    kind: ConvertedBindingKind<'a, 'tcx>,
-    gen_args: &'tcx GenericArgs<'tcx>,
-    span: Span,
-}
-
-#[derive(Debug)]
-enum ConvertedBindingKind<'a, 'tcx> {
-    Equality(Spanned<ty::Term<'tcx>>),
-    Constraint(&'a [hir::GenericBound<'tcx>]),
-}
-
 /// New-typed boolean indicating whether explicit late-bound lifetimes
 /// are present in a set of generic arguments.
 ///
@@ -316,7 +300,9 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
     /// Given the type/lifetime/const arguments provided to some path (along with
     /// an implicit `Self`, if this is a trait reference), returns the complete
     /// set of generic arguments. This may involve applying defaulted type parameters.
-    /// Constraints on associated types are created from `create_assoc_bindings_for_generic_args`.
+    ///
+    /// Constraints on associated types are not converted here but
+    /// separately in `add_predicates_for_ast_type_binding`.
     ///
     /// Example:
     ///
@@ -329,8 +315,8 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
     /// 2. The path in question is the path to the trait `std::ops::Index`,
     ///    which will have been resolved to a `def_id`
     /// 3. The `generic_args` contains info on the `<...>` contents. The `usize` type
-    ///    parameters are returned in the `GenericArgsRef`, the associated type bindings like
-    ///    `Output = u32` are returned from `create_assoc_bindings_for_generic_args`.
+    ///    parameters are returned in the `GenericArgsRef`
+    /// 4. Associated type bindings like `Output = u32` are contained in `generic_args.bindings`.
     ///
     /// Note that the type listing given here is *exactly* what the user provided.
     ///
@@ -591,52 +577,6 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
         (args, arg_count)
     }
 
-    fn create_assoc_bindings_for_generic_args<'a>(
-        &self,
-        generic_args: &'a hir::GenericArgs<'tcx>,
-    ) -> Vec<ConvertedBinding<'a, 'tcx>> {
-        // Convert associated-type bindings or constraints into a separate vector.
-        // Example: Given this:
-        //
-        //     T: Iterator<Item = u32>
-        //
-        // The `T` is passed in as a self-type; the `Item = u32` is
-        // not a "type parameter" of the `Iterator` trait, but rather
-        // a restriction on `<T as Iterator>::Item`, so it is passed
-        // back separately.
-        let assoc_bindings = generic_args
-            .bindings
-            .iter()
-            .map(|binding| {
-                let kind = match &binding.kind {
-                    hir::TypeBindingKind::Equality { term } => match term {
-                        hir::Term::Ty(ty) => ConvertedBindingKind::Equality(respan(
-                            ty.span,
-                            self.ast_ty_to_ty(ty).into(),
-                        )),
-                        hir::Term::Const(c) => {
-                            let span = self.tcx().def_span(c.def_id);
-                            let c = Const::from_anon_const(self.tcx(), c.def_id);
-                            ConvertedBindingKind::Equality(respan(span, c.into()))
-                        }
-                    },
-                    hir::TypeBindingKind::Constraint { bounds } => {
-                        ConvertedBindingKind::Constraint(bounds)
-                    }
-                };
-                ConvertedBinding {
-                    hir_id: binding.hir_id,
-                    item_name: binding.ident,
-                    kind,
-                    gen_args: binding.gen_args,
-                    span: binding.span,
-                }
-            })
-            .collect();
-
-        assoc_bindings
-    }
-
     pub fn create_args_for_associated_item(
         &self,
         span: Span,
@@ -742,18 +682,16 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
         let bound_vars = tcx.late_bound_vars(trait_ref.hir_ref_id);
         debug!(?bound_vars);
 
-        let assoc_bindings = self.create_assoc_bindings_for_generic_args(args);
-
         let poly_trait_ref = ty::Binder::bind_with_vars(
             ty::TraitRef::new(tcx, trait_def_id, generic_args),
             bound_vars,
         );
 
-        debug!(?poly_trait_ref, ?assoc_bindings);
+        debug!(?poly_trait_ref);
         bounds.push_trait_bound(tcx, poly_trait_ref, span, polarity);
 
         let mut dup_bindings = FxIndexMap::default();
-        for binding in &assoc_bindings {
+        for binding in args.bindings {
             // Don't register additional associated type bounds for negative bounds,
             // since we should have emitten an error for them earlier, and they will
             // not be well-formed!
@@ -1029,7 +967,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
         assoc_kind: ty::AssocKind,
         assoc_name: Ident,
         span: Span,
-        binding: Option<&ConvertedBinding<'_, 'tcx>>,
+        binding: Option<&hir::TypeBinding<'tcx>>,
     ) -> Result<ty::PolyTraitRef<'tcx>, ErrorGuaranteed>
     where
         I: Iterator<Item = ty::PolyTraitRef<'tcx>>,
@@ -1069,7 +1007,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
             // Provide a more specific error code index entry for equality bindings.
             err.code(
                 if let Some(binding) = binding
-                    && let ConvertedBindingKind::Equality(_) = binding.kind
+                    && let hir::TypeBindingKind::Equality { .. } = binding.kind
                 {
                     E0222
                 } else {
@@ -1094,16 +1032,21 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
                     );
                     if let Some(binding) = binding {
                         match binding.kind {
-                            ConvertedBindingKind::Equality(term) => {
+                            hir::TypeBindingKind::Equality { term } => {
+                                let term: ty::Term<'_> = match term {
+                                    hir::Term::Ty(ty) => self.ast_ty_to_ty(ty).into(),
+                                    hir::Term::Const(ct) => {
+                                        ty::Const::from_anon_const(tcx, ct.def_id).into()
+                                    }
+                                };
                                 // FIXME(#97583): This isn't syntactically well-formed!
                                 where_bounds.push(format!(
                                     "        T: {trait}::{assoc_name} = {term}",
                                     trait = bound.print_only_trait_path(),
-                                    term = term.node,
                                 ));
                             }
                             // FIXME: Provide a suggestion.
-                            ConvertedBindingKind::Constraint(_bounds) => {}
+                            hir::TypeBindingKind::Constraint { bounds: _ } => {}
                         }
                     } else {
                         err.span_suggestion_verbose(
diff --git a/compiler/rustc_hir_analysis/src/check/check.rs b/compiler/rustc_hir_analysis/src/check/check.rs
index 1410273e3bc..c3948b1b6bd 100644
--- a/compiler/rustc_hir_analysis/src/check/check.rs
+++ b/compiler/rustc_hir_analysis/src/check/check.rs
@@ -5,10 +5,9 @@ use super::compare_impl_item::check_type_bounds;
 use super::compare_impl_item::{compare_impl_method, compare_impl_ty};
 use super::*;
 use rustc_attr as attr;
-use rustc_errors::{codes::*, ErrorGuaranteed, MultiSpan};
+use rustc_errors::{codes::*, MultiSpan};
 use rustc_hir as hir;
 use rustc_hir::def::{CtorKind, DefKind};
-use rustc_hir::def_id::{DefId, LocalDefId};
 use rustc_hir::Node;
 use rustc_infer::infer::{RegionVariableOrigin, TyCtxtInferExt};
 use rustc_infer::traits::{Obligation, TraitEngineExt as _};
@@ -129,17 +128,20 @@ fn check_unnamed_fields(tcx: TyCtxt<'_>, def: ty::AdtDef<'_>) {
     for field in variant.fields.iter().filter(|f| f.is_unnamed()) {
         let field_ty = tcx.type_of(field.did).instantiate_identity();
         if let Some(adt) = field_ty.ty_adt_def()
-            && !adt.is_anonymous()
-            && !adt.repr().c()
+            && !adt.is_enum()
         {
-            let field_ty_span = tcx.def_span(adt.did());
-            tcx.dcx().emit_err(errors::UnnamedFieldsRepr::FieldMissingReprC {
-                span: tcx.def_span(field.did),
-                field_ty_span,
-                field_ty,
-                field_adt_kind: adt.descr(),
-                sugg_span: field_ty_span.shrink_to_lo(),
-            });
+            if !adt.is_anonymous() && !adt.repr().c() {
+                let field_ty_span = tcx.def_span(adt.did());
+                tcx.dcx().emit_err(errors::UnnamedFieldsRepr::FieldMissingReprC {
+                    span: tcx.def_span(field.did),
+                    field_ty_span,
+                    field_ty,
+                    field_adt_kind: adt.descr(),
+                    sugg_span: field_ty_span.shrink_to_lo(),
+                });
+            }
+        } else {
+            tcx.dcx().emit_err(errors::InvalidUnnamedFieldTy { span: tcx.def_span(field.did) });
         }
     }
 }
diff --git a/compiler/rustc_hir_analysis/src/check/errs.rs b/compiler/rustc_hir_analysis/src/check/errs.rs
index 87a1f3d3425..4a7ace274c5 100644
--- a/compiler/rustc_hir_analysis/src/check/errs.rs
+++ b/compiler/rustc_hir_analysis/src/check/errs.rs
@@ -1,6 +1,6 @@
 use rustc_hir as hir;
 use rustc_hir_pretty::qpath_to_string;
-use rustc_lint_defs::builtin::STATIC_MUT_REF;
+use rustc_lint_defs::builtin::STATIC_MUT_REFS;
 use rustc_middle::ty::TyCtxt;
 use rustc_span::Span;
 use rustc_type_ir::Mutability;
@@ -66,32 +66,24 @@ fn handle_static_mut_ref(
     hir_id: hir::HirId,
 ) {
     if e2024 {
-        let sugg = if mutable {
-            errors::StaticMutRefSugg::Mut { span, var }
+        let (sugg, shared) = if mutable {
+            (errors::StaticMutRefSugg::Mut { span, var }, "mutable")
         } else {
-            errors::StaticMutRefSugg::Shared { span, var }
+            (errors::StaticMutRefSugg::Shared { span, var }, "shared")
         };
-        tcx.sess.parse_sess.dcx.emit_err(errors::StaticMutRef { span, sugg });
+        tcx.sess.parse_sess.dcx.emit_err(errors::StaticMutRef { span, sugg, shared });
         return;
     }
 
-    let (label, sugg, shared) = if mutable {
-        (
-            errors::RefOfMutStaticLabel::Mut { span },
-            errors::RefOfMutStaticSugg::Mut { span, var },
-            "mutable ",
-        )
+    let (sugg, shared) = if mutable {
+        (errors::RefOfMutStaticSugg::Mut { span, var }, "mutable")
     } else {
-        (
-            errors::RefOfMutStaticLabel::Shared { span },
-            errors::RefOfMutStaticSugg::Shared { span, var },
-            "shared ",
-        )
+        (errors::RefOfMutStaticSugg::Shared { span, var }, "shared")
     };
     tcx.emit_node_span_lint(
-        STATIC_MUT_REF,
+        STATIC_MUT_REFS,
         hir_id,
         span,
-        errors::RefOfMutStatic { shared, why_note: (), label, sugg },
+        errors::RefOfMutStatic { span, sugg, shared },
     );
 }
diff --git a/compiler/rustc_hir_analysis/src/coherence/inherent_impls.rs b/compiler/rustc_hir_analysis/src/coherence/inherent_impls.rs
index 0df5a57bc2c..4823472cf96 100644
--- a/compiler/rustc_hir_analysis/src/coherence/inherent_impls.rs
+++ b/compiler/rustc_hir_analysis/src/coherence/inherent_impls.rs
@@ -144,6 +144,7 @@ impl<'tcx> InherentCollect<'tcx> {
         let id = id.owner_id.def_id;
         let item_span = self.tcx.def_span(id);
         let self_ty = self.tcx.type_of(id).instantiate_identity();
+        let self_ty = peel_off_weak_aliases(self.tcx, self_ty);
         match *self_ty.kind() {
             ty::Adt(def, _) => self.check_def_id(id, self_ty, def.did()),
             ty::Foreign(did) => self.check_def_id(id, self_ty, did),
@@ -166,7 +167,7 @@ impl<'tcx> InherentCollect<'tcx> {
             | ty::Never
             | ty::FnPtr(_)
             | ty::Tuple(..) => self.check_primitive_impl(id, self_ty),
-            ty::Alias(..) | ty::Param(_) => {
+            ty::Alias(ty::Projection | ty::Inherent | ty::Opaque, _) | ty::Param(_) => {
                 Err(self.tcx.dcx().emit_err(errors::InherentNominal { span: item_span }))
             }
             ty::FnDef(..)
@@ -174,6 +175,7 @@ impl<'tcx> InherentCollect<'tcx> {
             | ty::CoroutineClosure(..)
             | ty::Coroutine(..)
             | ty::CoroutineWitness(..)
+            | ty::Alias(ty::Weak, _)
             | ty::Bound(..)
             | ty::Placeholder(_)
             | ty::Infer(_) => {
@@ -184,3 +186,30 @@ impl<'tcx> InherentCollect<'tcx> {
         }
     }
 }
+
+/// Peel off all weak alias types in this type until there are none left.
+///
+/// <div class="warning">
+///
+/// This assumes that `ty` gets normalized later and that any overflows occurring
+/// during said normalization get reported.
+///
+/// </div>
+fn peel_off_weak_aliases<'tcx>(tcx: TyCtxt<'tcx>, mut ty: Ty<'tcx>) -> Ty<'tcx> {
+    let ty::Alias(ty::Weak, _) = ty.kind() else { return ty };
+
+    let limit = tcx.recursion_limit();
+    let mut depth = 0;
+
+    while let ty::Alias(ty::Weak, alias) = ty.kind() {
+        if !limit.value_within_limit(depth) {
+            let guar = tcx.dcx().delayed_bug("overflow expanding weak alias type");
+            return Ty::new_error(tcx, guar);
+        }
+
+        ty = tcx.type_of(alias.def_id).instantiate(tcx, alias.args);
+        depth += 1;
+    }
+
+    ty
+}
diff --git a/compiler/rustc_hir_analysis/src/collect.rs b/compiler/rustc_hir_analysis/src/collect.rs
index 43f0af5bd1d..a5ef1490bce 100644
--- a/compiler/rustc_hir_analysis/src/collect.rs
+++ b/compiler/rustc_hir_analysis/src/collect.rs
@@ -943,7 +943,15 @@ impl<'tcx> FieldUniquenessCheckContext<'tcx> {
                 }
             }
             hir::TyKind::Path(hir::QPath::Resolved(_, hir::Path { res, .. })) => {
-                self.check_field_in_nested_adt(self.tcx.adt_def(res.def_id()), field.span);
+                // If this is a direct path to an ADT, we can check it
+                // If this is a type alias or non-ADT, `check_unnamed_fields` should verify it
+                if let Some(def_id) = res.opt_def_id()
+                    && let Some(local) = def_id.as_local()
+                    && let Node::Item(item) = self.tcx.hir_node_by_def_id(local)
+                    && item.is_adt()
+                {
+                    self.check_field_in_nested_adt(self.tcx.adt_def(def_id), field.span);
+                }
             }
             // Abort due to errors (there must be an error if an unnamed field
             //  has any type kind other than an anonymous adt or a named adt)
diff --git a/compiler/rustc_hir_analysis/src/collect/predicates_of.rs b/compiler/rustc_hir_analysis/src/collect/predicates_of.rs
index 05755f98f20..351ac2eb770 100644
--- a/compiler/rustc_hir_analysis/src/collect/predicates_of.rs
+++ b/compiler/rustc_hir_analysis/src/collect/predicates_of.rs
@@ -307,7 +307,7 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Gen
             tcx,
             &mut predicates,
             trait_ref,
-            &mut cgp::parameters_for_impl(self_ty, trait_ref),
+            &mut cgp::parameters_for_impl(tcx, self_ty, trait_ref),
         );
     }
 
diff --git a/compiler/rustc_hir_analysis/src/constrained_generic_params.rs b/compiler/rustc_hir_analysis/src/constrained_generic_params.rs
index 05efad3ccb3..4ce43bb4887 100644
--- a/compiler/rustc_hir_analysis/src/constrained_generic_params.rs
+++ b/compiler/rustc_hir_analysis/src/constrained_generic_params.rs
@@ -1,4 +1,5 @@
 use rustc_data_structures::fx::FxHashSet;
+use rustc_data_structures::stack::ensure_sufficient_stack;
 use rustc_middle::ty::visit::{TypeSuperVisitable, TypeVisitable, TypeVisitor};
 use rustc_middle::ty::{self, Ty, TyCtxt};
 use rustc_span::Span;
@@ -27,12 +28,13 @@ impl From<ty::ParamConst> for Parameter {
 
 /// Returns the set of parameters constrained by the impl header.
 pub fn parameters_for_impl<'tcx>(
+    tcx: TyCtxt<'tcx>,
     impl_self_ty: Ty<'tcx>,
     impl_trait_ref: Option<ty::TraitRef<'tcx>>,
 ) -> FxHashSet<Parameter> {
     let vec = match impl_trait_ref {
-        Some(tr) => parameters_for(&tr, false),
-        None => parameters_for(&impl_self_ty, false),
+        Some(tr) => parameters_for(tcx, &tr, false),
+        None => parameters_for(tcx, &impl_self_ty, false),
     };
     vec.into_iter().collect()
 }
@@ -43,26 +45,47 @@ pub fn parameters_for_impl<'tcx>(
 /// of parameters whose values are needed in order to constrain `ty` - these
 /// differ, with the latter being a superset, in the presence of projections.
 pub fn parameters_for<'tcx>(
+    tcx: TyCtxt<'tcx>,
     t: &impl TypeVisitable<TyCtxt<'tcx>>,
     include_nonconstraining: bool,
 ) -> Vec<Parameter> {
-    let mut collector = ParameterCollector { parameters: vec![], include_nonconstraining };
+    let mut collector =
+        ParameterCollector { tcx, parameters: vec![], include_nonconstraining, depth: 0 };
     t.visit_with(&mut collector);
     collector.parameters
 }
 
-struct ParameterCollector {
+struct ParameterCollector<'tcx> {
+    tcx: TyCtxt<'tcx>,
     parameters: Vec<Parameter>,
     include_nonconstraining: bool,
+    depth: usize,
 }
 
-impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for ParameterCollector {
+impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for ParameterCollector<'tcx> {
     fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
         match *t.kind() {
-            ty::Alias(..) if !self.include_nonconstraining => {
-                // projections are not injective
+            ty::Alias(ty::Projection | ty::Inherent | ty::Opaque, _)
+                if !self.include_nonconstraining =>
+            {
+                // Projections are not injective in general.
                 return ControlFlow::Continue(());
             }
+            ty::Alias(ty::Weak, alias) if !self.include_nonconstraining => {
+                if !self.tcx.recursion_limit().value_within_limit(self.depth) {
+                    // Other constituent types may still constrain some generic params, consider
+                    // `<T> (Overflow, T)` for example. Therefore we want to continue instead of
+                    // breaking. Only affects diagnostics.
+                    return ControlFlow::Continue(());
+                }
+                self.depth += 1;
+                return ensure_sufficient_stack(|| {
+                    self.tcx
+                        .type_of(alias.def_id)
+                        .instantiate(self.tcx, alias.args)
+                        .visit_with(self)
+                });
+            }
             ty::Param(data) => {
                 self.parameters.push(Parameter::from(data));
             }
@@ -82,7 +105,7 @@ impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for ParameterCollector {
     fn visit_const(&mut self, c: ty::Const<'tcx>) -> ControlFlow<Self::BreakTy> {
         match c.kind() {
             ty::ConstKind::Unevaluated(..) if !self.include_nonconstraining => {
-                // Constant expressions are not injective
+                // Constant expressions are not injective in general.
                 return c.ty().visit_with(self);
             }
             ty::ConstKind::Param(data) => {
@@ -201,12 +224,12 @@ pub fn setup_constraining_predicates<'tcx>(
                 //     `<<T as Bar>::Baz as Iterator>::Output = <U as Iterator>::Output`
                 // Then the projection only applies if `T` is known, but it still
                 // does not determine `U`.
-                let inputs = parameters_for(&projection.projection_ty, true);
+                let inputs = parameters_for(tcx, &projection.projection_ty, true);
                 let relies_only_on_inputs = inputs.iter().all(|p| input_parameters.contains(p));
                 if !relies_only_on_inputs {
                     continue;
                 }
-                input_parameters.extend(parameters_for(&projection.term, false));
+                input_parameters.extend(parameters_for(tcx, &projection.term, false));
             } else {
                 continue;
             }
diff --git a/compiler/rustc_hir_analysis/src/errors.rs b/compiler/rustc_hir_analysis/src/errors.rs
index 6a505b96197..d217d16ed84 100644
--- a/compiler/rustc_hir_analysis/src/errors.rs
+++ b/compiler/rustc_hir_analysis/src/errors.rs
@@ -143,6 +143,7 @@ pub struct WrongNumberOfGenericArgumentsToIntrinsic<'a> {
 
 #[derive(Diagnostic)]
 #[diag(hir_analysis_unrecognized_intrinsic_function, code = E0093)]
+#[help]
 pub struct UnrecognizedIntrinsicFunction {
     #[primary_span]
     #[label]
@@ -662,6 +663,13 @@ pub(crate) struct InvalidUnionField {
 }
 
 #[derive(Diagnostic)]
+#[diag(hir_analysis_invalid_unnamed_field_ty)]
+pub struct InvalidUnnamedFieldTy {
+    #[primary_span]
+    pub span: Span,
+}
+
+#[derive(Diagnostic)]
 #[diag(hir_analysis_return_type_notation_on_non_rpitit)]
 pub(crate) struct ReturnTypeNotationOnNonRpitit<'tcx> {
     #[primary_span]
@@ -1455,12 +1463,13 @@ pub struct OnlyCurrentTraitsPointerSugg<'a> {
 #[derive(Diagnostic)]
 #[diag(hir_analysis_static_mut_ref, code = E0796)]
 #[note]
-pub struct StaticMutRef {
+pub struct StaticMutRef<'a> {
     #[primary_span]
     #[label]
     pub span: Span,
     #[subdiagnostic]
     pub sugg: StaticMutRefSugg,
+    pub shared: &'a str,
 }
 
 #[derive(Subdiagnostic)]
@@ -1491,30 +1500,15 @@ pub enum StaticMutRefSugg {
 
 // STATIC_MUT_REF lint
 #[derive(LintDiagnostic)]
-#[diag(hir_analysis_static_mut_ref_lint)]
+#[diag(hir_analysis_static_mut_refs_lint)]
 #[note]
+#[note(hir_analysis_why_note)]
 pub struct RefOfMutStatic<'a> {
-    pub shared: &'a str,
-    #[note(hir_analysis_why_note)]
-    pub why_note: (),
-    #[subdiagnostic]
-    pub label: RefOfMutStaticLabel,
+    #[label]
+    pub span: Span,
     #[subdiagnostic]
     pub sugg: RefOfMutStaticSugg,
-}
-
-#[derive(Subdiagnostic)]
-pub enum RefOfMutStaticLabel {
-    #[label(hir_analysis_label)]
-    Shared {
-        #[primary_span]
-        span: Span,
-    },
-    #[label(hir_analysis_label_mut)]
-    Mut {
-        #[primary_span]
-        span: Span,
-    },
+    pub shared: &'a str,
 }
 
 #[derive(Subdiagnostic)]
diff --git a/compiler/rustc_hir_analysis/src/impl_wf_check.rs b/compiler/rustc_hir_analysis/src/impl_wf_check.rs
index c072891e295..b4cec1d9882 100644
--- a/compiler/rustc_hir_analysis/src/impl_wf_check.rs
+++ b/compiler/rustc_hir_analysis/src/impl_wf_check.rs
@@ -94,7 +94,7 @@ fn enforce_impl_params_are_constrained(
     let impl_predicates = tcx.predicates_of(impl_def_id);
     let impl_trait_ref = tcx.impl_trait_ref(impl_def_id).map(ty::EarlyBinder::instantiate_identity);
 
-    let mut input_parameters = cgp::parameters_for_impl(impl_self_ty, impl_trait_ref);
+    let mut input_parameters = cgp::parameters_for_impl(tcx, impl_self_ty, impl_trait_ref);
     cgp::identify_constrained_generic_params(
         tcx,
         impl_predicates,
@@ -111,7 +111,7 @@ fn enforce_impl_params_are_constrained(
             match item.kind {
                 ty::AssocKind::Type => {
                     if item.defaultness(tcx).has_value() {
-                        cgp::parameters_for(&tcx.type_of(def_id).instantiate_identity(), true)
+                        cgp::parameters_for(tcx, &tcx.type_of(def_id).instantiate_identity(), true)
                     } else {
                         vec![]
                     }
diff --git a/compiler/rustc_hir_analysis/src/impl_wf_check/min_specialization.rs b/compiler/rustc_hir_analysis/src/impl_wf_check/min_specialization.rs
index c8dedb0f371..bd4fce81377 100644
--- a/compiler/rustc_hir_analysis/src/impl_wf_check/min_specialization.rs
+++ b/compiler/rustc_hir_analysis/src/impl_wf_check/min_specialization.rs
@@ -266,15 +266,15 @@ fn unconstrained_parent_impl_args<'tcx>(
                 continue;
             }
 
-            unconstrained_parameters.extend(cgp::parameters_for(&projection_ty, true));
+            unconstrained_parameters.extend(cgp::parameters_for(tcx, &projection_ty, true));
 
-            for param in cgp::parameters_for(&projected_ty, false) {
+            for param in cgp::parameters_for(tcx, &projected_ty, false) {
                 if !unconstrained_parameters.contains(&param) {
                     constrained_params.insert(param.0);
                 }
             }
 
-            unconstrained_parameters.extend(cgp::parameters_for(&projected_ty, true));
+            unconstrained_parameters.extend(cgp::parameters_for(tcx, &projected_ty, true));
         }
     }
 
@@ -312,7 +312,7 @@ fn check_duplicate_params<'tcx>(
     parent_args: &Vec<GenericArg<'tcx>>,
     span: Span,
 ) -> Result<(), ErrorGuaranteed> {
-    let mut base_params = cgp::parameters_for(parent_args, true);
+    let mut base_params = cgp::parameters_for(tcx, parent_args, true);
     base_params.sort_by_key(|param| param.0);
     if let (_, [duplicate, ..]) = base_params.partition_dedup() {
         let param = impl1_args[duplicate.0 as usize];
diff --git a/compiler/rustc_hir_analysis/src/structured_errors/missing_cast_for_variadic_arg.rs b/compiler/rustc_hir_analysis/src/structured_errors/missing_cast_for_variadic_arg.rs
index 50b4ef623ac..363b9ba6996 100644
--- a/compiler/rustc_hir_analysis/src/structured_errors/missing_cast_for_variadic_arg.rs
+++ b/compiler/rustc_hir_analysis/src/structured_errors/missing_cast_for_variadic_arg.rs
@@ -1,5 +1,5 @@
 use crate::{errors, structured_errors::StructuredDiagnostic};
-use rustc_errors::{codes::*, DiagnosticBuilder, ErrCode};
+use rustc_errors::{codes::*, DiagnosticBuilder};
 use rustc_middle::ty::{Ty, TypeVisitableExt};
 use rustc_session::Session;
 use rustc_span::Span;
diff --git a/compiler/rustc_hir_analysis/src/structured_errors/sized_unsized_cast.rs b/compiler/rustc_hir_analysis/src/structured_errors/sized_unsized_cast.rs
index 54d54a2af93..052c2807a2e 100644
--- a/compiler/rustc_hir_analysis/src/structured_errors/sized_unsized_cast.rs
+++ b/compiler/rustc_hir_analysis/src/structured_errors/sized_unsized_cast.rs
@@ -1,5 +1,5 @@
 use crate::{errors, structured_errors::StructuredDiagnostic};
-use rustc_errors::{codes::*, DiagnosticBuilder, ErrCode};
+use rustc_errors::{codes::*, DiagnosticBuilder};
 use rustc_middle::ty::{Ty, TypeVisitableExt};
 use rustc_session::Session;
 use rustc_span::Span;
diff --git a/compiler/rustc_hir_analysis/src/structured_errors/wrong_number_of_generic_args.rs b/compiler/rustc_hir_analysis/src/structured_errors/wrong_number_of_generic_args.rs
index 52ff8b2e45d..f9d57d402b1 100644
--- a/compiler/rustc_hir_analysis/src/structured_errors/wrong_number_of_generic_args.rs
+++ b/compiler/rustc_hir_analysis/src/structured_errors/wrong_number_of_generic_args.rs
@@ -1,7 +1,5 @@
 use crate::structured_errors::StructuredDiagnostic;
-use rustc_errors::{
-    codes::*, pluralize, Applicability, Diagnostic, DiagnosticBuilder, ErrCode, MultiSpan,
-};
+use rustc_errors::{codes::*, pluralize, Applicability, Diagnostic, DiagnosticBuilder, MultiSpan};
 use rustc_hir as hir;
 use rustc_middle::ty::{self as ty, AssocItems, AssocKind, TyCtxt};
 use rustc_session::Session;
diff --git a/compiler/rustc_hir_typeck/src/errors.rs b/compiler/rustc_hir_typeck/src/errors.rs
index 10e12d01b1f..1af0b75bd23 100644
--- a/compiler/rustc_hir_typeck/src/errors.rs
+++ b/compiler/rustc_hir_typeck/src/errors.rs
@@ -293,7 +293,7 @@ pub enum HelpUseLatestEdition {
 impl HelpUseLatestEdition {
     pub fn new() -> Self {
         let edition = LATEST_STABLE_EDITION;
-        if std::env::var_os("CARGO").is_some() {
+        if rustc_session::utils::was_invoked_from_cargo() {
             Self::Cargo { edition }
         } else {
             Self::Standalone { edition }
diff --git a/compiler/rustc_hir_typeck/src/expr.rs b/compiler/rustc_hir_typeck/src/expr.rs
index ed19d00d641..a946d59ff2b 100644
--- a/compiler/rustc_hir_typeck/src/expr.rs
+++ b/compiler/rustc_hir_typeck/src/expr.rs
@@ -27,7 +27,7 @@ use rustc_data_structures::stack::ensure_sufficient_stack;
 use rustc_data_structures::unord::UnordMap;
 use rustc_errors::{
     codes::*, pluralize, struct_span_code_err, AddToDiagnostic, Applicability, Diagnostic,
-    DiagnosticBuilder, ErrCode, ErrorGuaranteed, StashKey,
+    DiagnosticBuilder, ErrorGuaranteed, StashKey,
 };
 use rustc_hir as hir;
 use rustc_hir::def::{CtorKind, DefKind, Res};
diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs
index dd527666d55..d8d3d45dd40 100644
--- a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs
+++ b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs
@@ -13,7 +13,7 @@ use itertools::Itertools;
 use rustc_ast as ast;
 use rustc_data_structures::fx::FxIndexSet;
 use rustc_errors::{
-    codes::*, pluralize, Applicability, Diagnostic, ErrCode, ErrorGuaranteed, MultiSpan, StashKey,
+    codes::*, pluralize, Applicability, Diagnostic, ErrorGuaranteed, MultiSpan, StashKey,
 };
 use rustc_hir as hir;
 use rustc_hir::def::{CtorOf, DefKind, Res};
diff --git a/compiler/rustc_hir_typeck/src/lib.rs b/compiler/rustc_hir_typeck/src/lib.rs
index 629c2f2a971..70ddd6b2f4c 100644
--- a/compiler/rustc_hir_typeck/src/lib.rs
+++ b/compiler/rustc_hir_typeck/src/lib.rs
@@ -53,7 +53,7 @@ use crate::expectation::Expectation;
 use crate::fn_ctxt::LoweredTy;
 use crate::gather_locals::GatherLocalsVisitor;
 use rustc_data_structures::unord::UnordSet;
-use rustc_errors::{codes::*, struct_span_code_err, ErrCode, ErrorGuaranteed};
+use rustc_errors::{codes::*, struct_span_code_err, ErrorGuaranteed};
 use rustc_hir as hir;
 use rustc_hir::def::{DefKind, Res};
 use rustc_hir::intravisit::Visitor;
diff --git a/compiler/rustc_incremental/src/persist/fs.rs b/compiler/rustc_incremental/src/persist/fs.rs
index 2578f284dee..23d29916922 100644
--- a/compiler/rustc_incremental/src/persist/fs.rs
+++ b/compiler/rustc_incremental/src/persist/fs.rs
@@ -492,7 +492,7 @@ fn lock_directory(
                 lock_err,
                 session_dir,
                 is_unsupported_lock,
-                is_cargo: std::env::var_os("CARGO").map(|_| ()),
+                is_cargo: rustc_session::utils::was_invoked_from_cargo().then_some(()),
             }))
         }
     }
diff --git a/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs b/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs
index c637ab31cd2..af722b20626 100644
--- a/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs
+++ b/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs
@@ -5,7 +5,7 @@ use crate::errors::{
 use crate::infer::error_reporting::TypeErrCtxt;
 use crate::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
 use crate::infer::InferCtxt;
-use rustc_errors::{codes::*, DiagnosticBuilder, ErrCode, IntoDiagnosticArg};
+use rustc_errors::{codes::*, DiagnosticBuilder, IntoDiagnosticArg};
 use rustc_hir as hir;
 use rustc_hir::def::Res;
 use rustc_hir::def::{CtorOf, DefKind, Namespace};
diff --git a/compiler/rustc_lint/src/context/diagnostics.rs b/compiler/rustc_lint/src/context/diagnostics.rs
index 0fa61c5d87e..5af2b6daec1 100644
--- a/compiler/rustc_lint/src/context/diagnostics.rs
+++ b/compiler/rustc_lint/src/context/diagnostics.rs
@@ -205,7 +205,7 @@ pub(super) fn builtin(
                 Vec::new()
             };
 
-            let is_from_cargo = std::env::var_os("CARGO").is_some();
+            let is_from_cargo = rustc_session::utils::was_invoked_from_cargo();
             let mut is_feature_cfg = name == sym::feature;
 
             if is_feature_cfg && is_from_cargo {
@@ -340,7 +340,7 @@ pub(super) fn builtin(
                 .copied()
                 .flatten()
                 .collect();
-            let is_from_cargo = std::env::var_os("CARGO").is_some();
+            let is_from_cargo = rustc_session::utils::was_invoked_from_cargo();
 
             // Show the full list if all possible values for a given name, but don't do it
             // for names as the possibilities could be very long
diff --git a/compiler/rustc_lint/src/lib.rs b/compiler/rustc_lint/src/lib.rs
index 85f9d3bd63e..e50f4ca338b 100644
--- a/compiler/rustc_lint/src/lib.rs
+++ b/compiler/rustc_lint/src/lib.rs
@@ -325,6 +325,7 @@ fn register_builtins(store: &mut LintStore) {
     store.register_renamed("or_patterns_back_compat", "rust_2021_incompatible_or_patterns");
     store.register_renamed("non_fmt_panic", "non_fmt_panics");
     store.register_renamed("unused_tuple_struct_fields", "dead_code");
+    store.register_renamed("static_mut_ref", "static_mut_refs");
 
     // These were moved to tool lints, but rustc still sees them when compiling normally, before
     // tool lints are registered, so `check_tool_name_for_backwards_compat` doesn't work. Use
diff --git a/compiler/rustc_lint_defs/src/builtin.rs b/compiler/rustc_lint_defs/src/builtin.rs
index 6a2a2c1e48e..3f5d3c25971 100644
--- a/compiler/rustc_lint_defs/src/builtin.rs
+++ b/compiler/rustc_lint_defs/src/builtin.rs
@@ -89,7 +89,7 @@ declare_lint_pass! {
         SINGLE_USE_LIFETIMES,
         SOFT_UNSTABLE,
         STABLE_FEATURES,
-        STATIC_MUT_REF,
+        STATIC_MUT_REFS,
         SUSPICIOUS_AUTO_TRAIT_IMPLS,
         TEST_UNSTABLE_LINT,
         TEXT_DIRECTION_CODEPOINT_IN_COMMENT,
@@ -1769,7 +1769,7 @@ declare_lint! {
 }
 
 declare_lint! {
-    /// The `static_mut_ref` lint checks for shared or mutable references
+    /// The `static_mut_refs` lint checks for shared or mutable references
     /// of mutable static inside `unsafe` blocks and `unsafe` functions.
     ///
     /// ### Example
@@ -1807,9 +1807,9 @@ declare_lint! {
     /// Shared or mutable references of mutable static are almost always a mistake and
     /// can lead to undefined behavior and various other problems in your code.
     ///
-    /// This lint is "warn" by default on editions up to 2021, from 2024 there is
+    /// This lint is "warn" by default on editions up to 2021, in 2024 there is
     /// a hard error instead.
-    pub STATIC_MUT_REF,
+    pub STATIC_MUT_REFS,
     Warn,
     "shared references or mutable references of mutable static is discouraged",
     @future_incompatible = FutureIncompatibleInfo {
diff --git a/compiler/rustc_metadata/src/rmeta/decoder.rs b/compiler/rustc_metadata/src/rmeta/decoder.rs
index 2cfbaff35ef..e7c80639a0d 100644
--- a/compiler/rustc_metadata/src/rmeta/decoder.rs
+++ b/compiler/rustc_metadata/src/rmeta/decoder.rs
@@ -13,7 +13,7 @@ use rustc_data_structures::unhash::UnhashMap;
 use rustc_expand::base::{SyntaxExtension, SyntaxExtensionKind};
 use rustc_expand::proc_macro::{AttrProcMacro, BangProcMacro, DeriveProcMacro};
 use rustc_hir::def::Res;
-use rustc_hir::def_id::{DefIdMap, CRATE_DEF_INDEX, LOCAL_CRATE};
+use rustc_hir::def_id::{CRATE_DEF_INDEX, LOCAL_CRATE};
 use rustc_hir::definitions::{DefPath, DefPathData};
 use rustc_hir::diagnostic_items::DiagnosticItems;
 use rustc_index::Idx;
diff --git a/compiler/rustc_middle/src/mir/syntax.rs b/compiler/rustc_middle/src/mir/syntax.rs
index 40af453f6ce..5c9857b9c53 100644
--- a/compiler/rustc_middle/src/mir/syntax.rs
+++ b/compiler/rustc_middle/src/mir/syntax.rs
@@ -15,7 +15,7 @@ use crate::ty::{Region, UserTypeAnnotationIndex};
 use rustc_ast::{InlineAsmOptions, InlineAsmTemplatePiece};
 use rustc_data_structures::packed::Pu128;
 use rustc_hir::def_id::DefId;
-use rustc_hir::{self, CoroutineKind};
+use rustc_hir::CoroutineKind;
 use rustc_index::IndexVec;
 use rustc_span::source_map::Spanned;
 use rustc_target::abi::{FieldIdx, VariantIdx};
diff --git a/compiler/rustc_mir_transform/src/const_prop.rs b/compiler/rustc_mir_transform/src/const_prop.rs
deleted file mode 100644
index eba62aae60f..00000000000
--- a/compiler/rustc_mir_transform/src/const_prop.rs
+++ /dev/null
@@ -1,161 +0,0 @@
-//! Propagates constants for early reporting of statically known
-//! assertion failures
-
-use rustc_index::bit_set::BitSet;
-use rustc_index::IndexVec;
-use rustc_middle::mir::visit::{MutatingUseContext, NonMutatingUseContext, PlaceContext, Visitor};
-use rustc_middle::mir::*;
-use rustc_middle::ty::{ParamEnv, TyCtxt};
-use rustc_target::abi::Size;
-
-/// The maximum number of bytes that we'll allocate space for a local or the return value.
-/// Needed for #66397, because otherwise we eval into large places and that can cause OOM or just
-/// Severely regress performance.
-const MAX_ALLOC_LIMIT: u64 = 1024;
-
-/// Macro for machine-specific `InterpError` without allocation.
-/// (These will never be shown to the user, but they help diagnose ICEs.)
-pub(crate) macro throw_machine_stop_str($($tt:tt)*) {{
-    // We make a new local type for it. The type itself does not carry any information,
-    // but its vtable (for the `MachineStopType` trait) does.
-    #[derive(Debug)]
-    struct Zst;
-    // Printing this type shows the desired string.
-    impl std::fmt::Display for Zst {
-        fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
-            write!(f, $($tt)*)
-        }
-    }
-
-    impl rustc_middle::mir::interpret::MachineStopType for Zst {
-        fn diagnostic_message(&self) -> rustc_errors::DiagnosticMessage {
-            self.to_string().into()
-        }
-
-        fn add_args(
-            self: Box<Self>,
-            _: &mut dyn FnMut(rustc_errors::DiagnosticArgName, rustc_errors::DiagnosticArgValue),
-        ) {}
-    }
-    throw_machine_stop!(Zst)
-}}
-
-/// The mode that `ConstProp` is allowed to run in for a given `Local`.
-#[derive(Clone, Copy, Debug, PartialEq)]
-pub enum ConstPropMode {
-    /// The `Local` can be propagated into and reads of this `Local` can also be propagated.
-    FullConstProp,
-    /// The `Local` can only be propagated into and from its own block.
-    OnlyInsideOwnBlock,
-    /// The `Local` cannot be part of propagation at all. Any statement
-    /// referencing it either for reading or writing will not get propagated.
-    NoPropagation,
-}
-
-pub struct CanConstProp {
-    can_const_prop: IndexVec<Local, ConstPropMode>,
-    // False at the beginning. Once set, no more assignments are allowed to that local.
-    found_assignment: BitSet<Local>,
-}
-
-impl CanConstProp {
-    /// Returns true if `local` can be propagated
-    pub fn check<'tcx>(
-        tcx: TyCtxt<'tcx>,
-        param_env: ParamEnv<'tcx>,
-        body: &Body<'tcx>,
-    ) -> IndexVec<Local, ConstPropMode> {
-        let mut cpv = CanConstProp {
-            can_const_prop: IndexVec::from_elem(ConstPropMode::FullConstProp, &body.local_decls),
-            found_assignment: BitSet::new_empty(body.local_decls.len()),
-        };
-        for (local, val) in cpv.can_const_prop.iter_enumerated_mut() {
-            let ty = body.local_decls[local].ty;
-            match tcx.layout_of(param_env.and(ty)) {
-                Ok(layout) if layout.size < Size::from_bytes(MAX_ALLOC_LIMIT) => {}
-                // Either the layout fails to compute, then we can't use this local anyway
-                // or the local is too large, then we don't want to.
-                _ => {
-                    *val = ConstPropMode::NoPropagation;
-                    continue;
-                }
-            }
-        }
-        // Consider that arguments are assigned on entry.
-        for arg in body.args_iter() {
-            cpv.found_assignment.insert(arg);
-        }
-        cpv.visit_body(body);
-        cpv.can_const_prop
-    }
-}
-
-impl<'tcx> Visitor<'tcx> for CanConstProp {
-    fn visit_place(&mut self, place: &Place<'tcx>, mut context: PlaceContext, loc: Location) {
-        use rustc_middle::mir::visit::PlaceContext::*;
-
-        // Dereferencing just read the addess of `place.local`.
-        if place.projection.first() == Some(&PlaceElem::Deref) {
-            context = NonMutatingUse(NonMutatingUseContext::Copy);
-        }
-
-        self.visit_local(place.local, context, loc);
-        self.visit_projection(place.as_ref(), context, loc);
-    }
-
-    fn visit_local(&mut self, local: Local, context: PlaceContext, _: Location) {
-        use rustc_middle::mir::visit::PlaceContext::*;
-        match context {
-            // These are just stores, where the storing is not propagatable, but there may be later
-            // mutations of the same local via `Store`
-            | MutatingUse(MutatingUseContext::Call)
-            | MutatingUse(MutatingUseContext::AsmOutput)
-            | MutatingUse(MutatingUseContext::Deinit)
-            // Actual store that can possibly even propagate a value
-            | MutatingUse(MutatingUseContext::Store)
-            | MutatingUse(MutatingUseContext::SetDiscriminant) => {
-                if !self.found_assignment.insert(local) {
-                    match &mut self.can_const_prop[local] {
-                        // If the local can only get propagated in its own block, then we don't have
-                        // to worry about multiple assignments, as we'll nuke the const state at the
-                        // end of the block anyway, and inside the block we overwrite previous
-                        // states as applicable.
-                        ConstPropMode::OnlyInsideOwnBlock => {}
-                        ConstPropMode::NoPropagation => {}
-                        other @ ConstPropMode::FullConstProp => {
-                            trace!(
-                                "local {:?} can't be propagated because of multiple assignments. Previous state: {:?}",
-                                local, other,
-                            );
-                            *other = ConstPropMode::OnlyInsideOwnBlock;
-                        }
-                    }
-                }
-            }
-            // Reading constants is allowed an arbitrary number of times
-            NonMutatingUse(NonMutatingUseContext::Copy)
-            | NonMutatingUse(NonMutatingUseContext::Move)
-            | NonMutatingUse(NonMutatingUseContext::Inspect)
-            | NonMutatingUse(NonMutatingUseContext::PlaceMention)
-            | NonUse(_) => {}
-
-            // These could be propagated with a smarter analysis or just some careful thinking about
-            // whether they'd be fine right now.
-            MutatingUse(MutatingUseContext::Yield)
-            | MutatingUse(MutatingUseContext::Drop)
-            | MutatingUse(MutatingUseContext::Retag)
-            // These can't ever be propagated under any scheme, as we can't reason about indirect
-            // mutation.
-            | NonMutatingUse(NonMutatingUseContext::SharedBorrow)
-            | NonMutatingUse(NonMutatingUseContext::FakeBorrow)
-            | NonMutatingUse(NonMutatingUseContext::AddressOf)
-            | MutatingUse(MutatingUseContext::Borrow)
-            | MutatingUse(MutatingUseContext::AddressOf) => {
-                trace!("local {:?} can't be propagated because it's used: {:?}", local, context);
-                self.can_const_prop[local] = ConstPropMode::NoPropagation;
-            }
-            MutatingUse(MutatingUseContext::Projection)
-            | NonMutatingUse(NonMutatingUseContext::Projection) => bug!("visit_place should not pass {context:?} for {local:?}"),
-        }
-    }
-}
diff --git a/compiler/rustc_mir_transform/src/const_prop_lint.rs b/compiler/rustc_mir_transform/src/const_prop_lint.rs
index 6212155a8fe..6f2ef8f9a4f 100644
--- a/compiler/rustc_mir_transform/src/const_prop_lint.rs
+++ b/compiler/rustc_mir_transform/src/const_prop_lint.rs
@@ -9,17 +9,14 @@ use rustc_const_eval::interpret::{
 use rustc_data_structures::fx::FxHashSet;
 use rustc_hir::def::DefKind;
 use rustc_hir::HirId;
-use rustc_index::bit_set::BitSet;
-use rustc_index::{Idx, IndexVec};
-use rustc_middle::mir::visit::Visitor;
+use rustc_index::{bit_set::BitSet, Idx, IndexVec};
+use rustc_middle::mir::visit::{MutatingUseContext, NonMutatingUseContext, PlaceContext, Visitor};
 use rustc_middle::mir::*;
 use rustc_middle::ty::layout::{LayoutError, LayoutOf, LayoutOfHelpers, TyAndLayout};
 use rustc_middle::ty::{self, ConstInt, ParamEnv, ScalarInt, Ty, TyCtxt, TypeVisitableExt};
 use rustc_span::Span;
 use rustc_target::abi::{Abi, FieldIdx, HasDataLayout, Size, TargetDataLayout, VariantIdx};
 
-use crate::const_prop::CanConstProp;
-use crate::const_prop::ConstPropMode;
 use crate::dataflow_const_prop::DummyMachine;
 use crate::errors::{AssertLint, AssertLintKind};
 use crate::MirLint;
@@ -849,3 +846,128 @@ impl<'tcx> Visitor<'tcx> for ConstPropagator<'_, 'tcx> {
         }
     }
 }
+
+/// The maximum number of bytes that we'll allocate space for a local or the return value.
+/// Needed for #66397, because otherwise we eval into large places and that can cause OOM or just
+/// Severely regress performance.
+const MAX_ALLOC_LIMIT: u64 = 1024;
+
+/// The mode that `ConstProp` is allowed to run in for a given `Local`.
+#[derive(Clone, Copy, Debug, PartialEq)]
+pub enum ConstPropMode {
+    /// The `Local` can be propagated into and reads of this `Local` can also be propagated.
+    FullConstProp,
+    /// The `Local` can only be propagated into and from its own block.
+    OnlyInsideOwnBlock,
+    /// The `Local` cannot be part of propagation at all. Any statement
+    /// referencing it either for reading or writing will not get propagated.
+    NoPropagation,
+}
+
+pub struct CanConstProp {
+    can_const_prop: IndexVec<Local, ConstPropMode>,
+    // False at the beginning. Once set, no more assignments are allowed to that local.
+    found_assignment: BitSet<Local>,
+}
+
+impl CanConstProp {
+    /// Returns true if `local` can be propagated
+    pub fn check<'tcx>(
+        tcx: TyCtxt<'tcx>,
+        param_env: ParamEnv<'tcx>,
+        body: &Body<'tcx>,
+    ) -> IndexVec<Local, ConstPropMode> {
+        let mut cpv = CanConstProp {
+            can_const_prop: IndexVec::from_elem(ConstPropMode::FullConstProp, &body.local_decls),
+            found_assignment: BitSet::new_empty(body.local_decls.len()),
+        };
+        for (local, val) in cpv.can_const_prop.iter_enumerated_mut() {
+            let ty = body.local_decls[local].ty;
+            match tcx.layout_of(param_env.and(ty)) {
+                Ok(layout) if layout.size < Size::from_bytes(MAX_ALLOC_LIMIT) => {}
+                // Either the layout fails to compute, then we can't use this local anyway
+                // or the local is too large, then we don't want to.
+                _ => {
+                    *val = ConstPropMode::NoPropagation;
+                    continue;
+                }
+            }
+        }
+        // Consider that arguments are assigned on entry.
+        for arg in body.args_iter() {
+            cpv.found_assignment.insert(arg);
+        }
+        cpv.visit_body(body);
+        cpv.can_const_prop
+    }
+}
+
+impl<'tcx> Visitor<'tcx> for CanConstProp {
+    fn visit_place(&mut self, place: &Place<'tcx>, mut context: PlaceContext, loc: Location) {
+        use rustc_middle::mir::visit::PlaceContext::*;
+
+        // Dereferencing just read the addess of `place.local`.
+        if place.projection.first() == Some(&PlaceElem::Deref) {
+            context = NonMutatingUse(NonMutatingUseContext::Copy);
+        }
+
+        self.visit_local(place.local, context, loc);
+        self.visit_projection(place.as_ref(), context, loc);
+    }
+
+    fn visit_local(&mut self, local: Local, context: PlaceContext, _: Location) {
+        use rustc_middle::mir::visit::PlaceContext::*;
+        match context {
+            // These are just stores, where the storing is not propagatable, but there may be later
+            // mutations of the same local via `Store`
+            | MutatingUse(MutatingUseContext::Call)
+            | MutatingUse(MutatingUseContext::AsmOutput)
+            | MutatingUse(MutatingUseContext::Deinit)
+            // Actual store that can possibly even propagate a value
+            | MutatingUse(MutatingUseContext::Store)
+            | MutatingUse(MutatingUseContext::SetDiscriminant) => {
+                if !self.found_assignment.insert(local) {
+                    match &mut self.can_const_prop[local] {
+                        // If the local can only get propagated in its own block, then we don't have
+                        // to worry about multiple assignments, as we'll nuke the const state at the
+                        // end of the block anyway, and inside the block we overwrite previous
+                        // states as applicable.
+                        ConstPropMode::OnlyInsideOwnBlock => {}
+                        ConstPropMode::NoPropagation => {}
+                        other @ ConstPropMode::FullConstProp => {
+                            trace!(
+                                "local {:?} can't be propagated because of multiple assignments. Previous state: {:?}",
+                                local, other,
+                            );
+                            *other = ConstPropMode::OnlyInsideOwnBlock;
+                        }
+                    }
+                }
+            }
+            // Reading constants is allowed an arbitrary number of times
+            NonMutatingUse(NonMutatingUseContext::Copy)
+            | NonMutatingUse(NonMutatingUseContext::Move)
+            | NonMutatingUse(NonMutatingUseContext::Inspect)
+            | NonMutatingUse(NonMutatingUseContext::PlaceMention)
+            | NonUse(_) => {}
+
+            // These could be propagated with a smarter analysis or just some careful thinking about
+            // whether they'd be fine right now.
+            MutatingUse(MutatingUseContext::Yield)
+            | MutatingUse(MutatingUseContext::Drop)
+            | MutatingUse(MutatingUseContext::Retag)
+            // These can't ever be propagated under any scheme, as we can't reason about indirect
+            // mutation.
+            | NonMutatingUse(NonMutatingUseContext::SharedBorrow)
+            | NonMutatingUse(NonMutatingUseContext::FakeBorrow)
+            | NonMutatingUse(NonMutatingUseContext::AddressOf)
+            | MutatingUse(MutatingUseContext::Borrow)
+            | MutatingUse(MutatingUseContext::AddressOf) => {
+                trace!("local {:?} can't be propagated because it's used: {:?}", local, context);
+                self.can_const_prop[local] = ConstPropMode::NoPropagation;
+            }
+            MutatingUse(MutatingUseContext::Projection)
+            | NonMutatingUse(NonMutatingUseContext::Projection) => bug!("visit_place should not pass {context:?} for {local:?}"),
+        }
+    }
+}
diff --git a/compiler/rustc_mir_transform/src/dataflow_const_prop.rs b/compiler/rustc_mir_transform/src/dataflow_const_prop.rs
index 86e99a8a5b5..9dc7a50eca9 100644
--- a/compiler/rustc_mir_transform/src/dataflow_const_prop.rs
+++ b/compiler/rustc_mir_transform/src/dataflow_const_prop.rs
@@ -21,7 +21,32 @@ use rustc_span::def_id::DefId;
 use rustc_span::DUMMY_SP;
 use rustc_target::abi::{Abi, FieldIdx, Size, VariantIdx, FIRST_VARIANT};
 
-use crate::const_prop::throw_machine_stop_str;
+/// Macro for machine-specific `InterpError` without allocation.
+/// (These will never be shown to the user, but they help diagnose ICEs.)
+pub(crate) macro throw_machine_stop_str($($tt:tt)*) {{
+    // We make a new local type for it. The type itself does not carry any information,
+    // but its vtable (for the `MachineStopType` trait) does.
+    #[derive(Debug)]
+    struct Zst;
+    // Printing this type shows the desired string.
+    impl std::fmt::Display for Zst {
+        fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+            write!(f, $($tt)*)
+        }
+    }
+
+    impl rustc_middle::mir::interpret::MachineStopType for Zst {
+        fn diagnostic_message(&self) -> rustc_errors::DiagnosticMessage {
+            self.to_string().into()
+        }
+
+        fn add_args(
+            self: Box<Self>,
+            _: &mut dyn FnMut(rustc_errors::DiagnosticArgName, rustc_errors::DiagnosticArgValue),
+        ) {}
+    }
+    throw_machine_stop!(Zst)
+}}
 
 // These constants are somewhat random guesses and have not been optimized.
 // If `tcx.sess.mir_opt_level() >= 4`, we ignore the limits (this can become very expensive).
diff --git a/compiler/rustc_mir_transform/src/lib.rs b/compiler/rustc_mir_transform/src/lib.rs
index 7f0e6f90dbb..74b36eb5ee8 100644
--- a/compiler/rustc_mir_transform/src/lib.rs
+++ b/compiler/rustc_mir_transform/src/lib.rs
@@ -59,7 +59,6 @@ mod remove_place_mention;
 mod add_subtyping_projections;
 pub mod cleanup_post_borrowck;
 mod const_debuginfo;
-mod const_prop;
 mod const_prop_lint;
 mod copy_prop;
 mod coroutine;
diff --git a/compiler/rustc_parse/src/errors.rs b/compiler/rustc_parse/src/errors.rs
index 3c3a8d6fbb9..674f7218ea6 100644
--- a/compiler/rustc_parse/src/errors.rs
+++ b/compiler/rustc_parse/src/errors.rs
@@ -2545,7 +2545,7 @@ pub enum HelpUseLatestEdition {
 impl HelpUseLatestEdition {
     pub fn new() -> Self {
         let edition = LATEST_STABLE_EDITION;
-        if std::env::var_os("CARGO").is_some() {
+        if rustc_session::utils::was_invoked_from_cargo() {
             Self::Cargo { edition }
         } else {
             Self::Standalone { edition }
diff --git a/compiler/rustc_resolve/src/build_reduced_graph.rs b/compiler/rustc_resolve/src/build_reduced_graph.rs
index 469d15e4214..1c4aeefcbcf 100644
--- a/compiler/rustc_resolve/src/build_reduced_graph.rs
+++ b/compiler/rustc_resolve/src/build_reduced_graph.rs
@@ -8,11 +8,11 @@
 use crate::def_collector::collect_definitions;
 use crate::imports::{ImportData, ImportKind};
 use crate::macros::{MacroRulesBinding, MacroRulesScope, MacroRulesScopeRef};
-use crate::Namespace::{self, MacroNS, TypeNS, ValueNS};
+use crate::Namespace::{MacroNS, TypeNS, ValueNS};
 use crate::{errors, BindingKey, MacroData, NameBindingData};
 use crate::{Determinacy, ExternPreludeEntry, Finalize, Module, ModuleKind, ModuleOrUniformRoot};
-use crate::{NameBinding, NameBindingKind, ParentScope, PathResult, PerNS, ResolutionError};
-use crate::{Resolver, ResolverArenas, Segment, ToNameBinding, VisResolutionError};
+use crate::{NameBinding, NameBindingKind, ParentScope, PathResult, ResolutionError};
+use crate::{Resolver, ResolverArenas, Segment, ToNameBinding, Used, VisResolutionError};
 
 use rustc_ast::visit::{self, AssocCtxt, Visitor};
 use rustc_ast::{self as ast, AssocItem, AssocItemKind, MetaItemKind, StmtKind};
@@ -362,7 +362,7 @@ impl<'a, 'b, 'tcx> BuildReducedGraphVisitor<'a, 'b, 'tcx> {
             root_span,
             root_id,
             vis: Cell::new(Some(vis)),
-            used: Cell::new(false),
+            used: Default::default(),
         });
 
         self.r.indeterminate_imports.push(import);
@@ -885,7 +885,7 @@ impl<'a, 'b, 'tcx> BuildReducedGraphVisitor<'a, 'b, 'tcx> {
             span: item.span,
             module_path: Vec::new(),
             vis: Cell::new(Some(vis)),
-            used: Cell::new(used),
+            used: Cell::new(used.then_some(Used::Other)),
         });
         self.r.potentially_unused_imports.push(import);
         let imported_binding = self.r.import(binding, import);
@@ -1090,7 +1090,7 @@ impl<'a, 'b, 'tcx> BuildReducedGraphVisitor<'a, 'b, 'tcx> {
                 span,
                 module_path: Vec::new(),
                 vis: Cell::new(Some(ty::Visibility::Restricted(CRATE_DEF_ID))),
-                used: Cell::new(false),
+                used: Default::default(),
             })
         };
 
@@ -1261,7 +1261,7 @@ impl<'a, 'b, 'tcx> BuildReducedGraphVisitor<'a, 'b, 'tcx> {
                     span,
                     module_path: Vec::new(),
                     vis: Cell::new(Some(vis)),
-                    used: Cell::new(true),
+                    used: Cell::new(Some(Used::Other)),
                 });
                 let import_binding = self.r.import(binding, import);
                 self.r.define(self.r.graph_root, ident, MacroNS, import_binding);
diff --git a/compiler/rustc_resolve/src/check_unused.rs b/compiler/rustc_resolve/src/check_unused.rs
index c14788b841d..37cc50f6943 100644
--- a/compiler/rustc_resolve/src/check_unused.rs
+++ b/compiler/rustc_resolve/src/check_unused.rs
@@ -27,9 +27,10 @@ use crate::imports::ImportKind;
 use crate::module_to_string;
 use crate::Resolver;
 
+use crate::NameBindingKind;
 use rustc_ast as ast;
 use rustc_ast::visit::{self, Visitor};
-use rustc_data_structures::fx::{FxHashMap, FxIndexMap};
+use rustc_data_structures::fx::{FxHashMap, FxIndexMap, FxIndexSet};
 use rustc_data_structures::unord::UnordSet;
 use rustc_errors::{pluralize, MultiSpan};
 use rustc_hir::def::{DefKind, Res};
@@ -38,14 +39,14 @@ use rustc_session::lint::BuiltinLintDiagnostics;
 use rustc_span::symbol::{kw, Ident};
 use rustc_span::{Span, DUMMY_SP};
 
-struct UnusedImport<'a> {
-    use_tree: &'a ast::UseTree,
+struct UnusedImport {
+    use_tree: ast::UseTree,
     use_tree_id: ast::NodeId,
     item_span: Span,
     unused: UnordSet<ast::NodeId>,
 }
 
-impl<'a> UnusedImport<'a> {
+impl UnusedImport {
     fn add(&mut self, id: ast::NodeId) {
         self.unused.insert(id);
     }
@@ -54,7 +55,7 @@ impl<'a> UnusedImport<'a> {
 struct UnusedImportCheckVisitor<'a, 'b, 'tcx> {
     r: &'a mut Resolver<'b, 'tcx>,
     /// All the (so far) unused imports, grouped path list
-    unused_imports: FxIndexMap<ast::NodeId, UnusedImport<'a>>,
+    unused_imports: FxIndexMap<ast::NodeId, UnusedImport>,
     extern_crate_items: Vec<ExternCrateToLint>,
     base_use_tree: Option<&'a ast::UseTree>,
     base_id: ast::NodeId,
@@ -100,9 +101,9 @@ impl<'a, 'b, 'tcx> UnusedImportCheckVisitor<'a, 'b, 'tcx> {
         }
     }
 
-    fn unused_import(&mut self, id: ast::NodeId) -> &mut UnusedImport<'a> {
+    fn unused_import(&mut self, id: ast::NodeId) -> &mut UnusedImport {
         let use_tree_id = self.base_id;
-        let use_tree = self.base_use_tree.unwrap();
+        let use_tree = self.base_use_tree.unwrap().clone();
         let item_span = self.item_span;
 
         self.unused_imports.entry(id).or_insert_with(|| UnusedImport {
@@ -197,7 +198,7 @@ enum UnusedSpanResult {
 }
 
 fn calc_unused_spans(
-    unused_import: &UnusedImport<'_>,
+    unused_import: &UnusedImport,
     use_tree: &ast::UseTree,
     use_tree_id: ast::NodeId,
 ) -> UnusedSpanResult {
@@ -287,7 +288,7 @@ impl Resolver<'_, '_> {
 
         for import in self.potentially_unused_imports.iter() {
             match import.kind {
-                _ if import.used.get()
+                _ if import.used.get().is_some()
                     || import.expect_vis().is_public()
                     || import.span.is_dummy() =>
                 {
@@ -336,7 +337,7 @@ impl Resolver<'_, '_> {
 
         for unused in visitor.unused_imports.values() {
             let mut fixes = Vec::new();
-            let spans = match calc_unused_spans(unused, unused.use_tree, unused.use_tree_id) {
+            let spans = match calc_unused_spans(unused, &unused.use_tree, unused.use_tree_id) {
                 UnusedSpanResult::Used => continue,
                 UnusedSpanResult::FlatUnused(span, remove) => {
                     fixes.push((remove, String::new()));
@@ -483,5 +484,30 @@ impl Resolver<'_, '_> {
                 BuiltinLintDiagnostics::ExternCrateNotIdiomatic { vis_span, ident_span },
             );
         }
+
+        let unused_imports = visitor.unused_imports;
+        let mut check_redundant_imports = FxIndexSet::default();
+        for module in self.arenas.local_modules().iter() {
+            for (_key, resolution) in self.resolutions(*module).borrow().iter() {
+                let resolution = resolution.borrow();
+
+                if let Some(binding) = resolution.binding
+                    && let NameBindingKind::Import { import, .. } = binding.kind
+                    && let ImportKind::Single { id, .. } = import.kind
+                {
+                    if let Some(unused_import) = unused_imports.get(&import.root_id)
+                        && unused_import.unused.contains(&id)
+                    {
+                        continue;
+                    }
+
+                    check_redundant_imports.insert(import);
+                }
+            }
+        }
+
+        for import in check_redundant_imports {
+            self.check_for_redundant_imports(import);
+        }
     }
 }
diff --git a/compiler/rustc_resolve/src/def_collector.rs b/compiler/rustc_resolve/src/def_collector.rs
index 45aea585f97..12bf462a6fd 100644
--- a/compiler/rustc_resolve/src/def_collector.rs
+++ b/compiler/rustc_resolve/src/def_collector.rs
@@ -1,5 +1,5 @@
 use crate::{ImplTraitContext, Resolver};
-use rustc_ast::visit::{self, FnKind};
+use rustc_ast::visit::FnKind;
 use rustc_ast::*;
 use rustc_expand::expand::AstFragment;
 use rustc_hir::def::{CtorKind, CtorOf, DefKind};
diff --git a/compiler/rustc_resolve/src/diagnostics.rs b/compiler/rustc_resolve/src/diagnostics.rs
index 737481c78db..4b978fefa10 100644
--- a/compiler/rustc_resolve/src/diagnostics.rs
+++ b/compiler/rustc_resolve/src/diagnostics.rs
@@ -33,8 +33,8 @@ use crate::errors::{AddedMacroUse, ChangeImportBinding, ChangeImportBindingSugge
 use crate::errors::{ConsiderAddingADerive, ExplicitUnsafeTraits, MaybeMissingMacroRulesName};
 use crate::imports::{Import, ImportKind};
 use crate::late::{PatternSource, Rib};
-use crate::path_names_to_string;
 use crate::{errors as errs, BindingKey};
+use crate::{path_names_to_string, Used};
 use crate::{AmbiguityError, AmbiguityErrorMisc, AmbiguityKind, BindingError, Finalize};
 use crate::{HasGenericParams, MacroRulesScope, Module, ModuleKind, ModuleOrUniformRoot};
 use crate::{LexicalScopeBinding, NameBinding, NameBindingKind, PrivacyError, VisResolutionError};
@@ -1503,7 +1503,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
                         );
                         // Silence the 'unused import' warning we might get,
                         // since this diagnostic already covers that import.
-                        self.record_use(ident, binding, false);
+                        self.record_use(ident, binding, Used::Other);
                         return;
                     }
                 }
diff --git a/compiler/rustc_resolve/src/ident.rs b/compiler/rustc_resolve/src/ident.rs
index e47f2bdd4d2..4583f991cab 100644
--- a/compiler/rustc_resolve/src/ident.rs
+++ b/compiler/rustc_resolve/src/ident.rs
@@ -12,8 +12,8 @@ use rustc_span::Span;
 use crate::errors::{ParamKindInEnumDiscriminant, ParamKindInNonTrivialAnonConst};
 use crate::late::{ConstantHasGenerics, NoConstantGenericsReason, PathSource, Rib, RibKind};
 use crate::macros::{sub_namespace_match, MacroRulesScope};
-use crate::BindingKey;
 use crate::{errors, AmbiguityError, AmbiguityErrorMisc, AmbiguityKind, Determinacy, Finalize};
+use crate::{BindingKey, Used};
 use crate::{ImportKind, LexicalScopeBinding, Module, ModuleKind, ModuleOrUniformRoot};
 use crate::{NameBinding, NameBindingKind, ParentScope, PathResult, PrivacyError, Res};
 use crate::{ResolutionError, Resolver, Scope, ScopeSet, Segment, ToNameBinding, Weak};
@@ -339,7 +339,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
                 ident,
                 ns,
                 parent_scope,
-                finalize,
+                finalize.map(|finalize| Finalize { used: Used::Scope, ..finalize }),
                 ignore_binding,
             );
             if let Ok(binding) = item {
@@ -506,7 +506,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
                             ns,
                             adjusted_parent_scope,
                             !matches!(scope_set, ScopeSet::Late(..)),
-                            finalize,
+                            finalize.map(|finalize| Finalize { used: Used::Scope, ..finalize }),
                             ignore_binding,
                         );
                         match binding {
@@ -857,7 +857,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
             .into_iter()
             .find_map(|binding| if binding == ignore_binding { None } else { binding });
 
-        if let Some(Finalize { path_span, report_private, .. }) = finalize {
+        if let Some(Finalize { path_span, report_private, used, .. }) = finalize {
             let Some(binding) = binding else {
                 return Err((Determined, Weak::No));
             };
@@ -901,7 +901,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
                 }
             }
 
-            self.record_use(ident, binding, restricted_shadowing);
+            self.record_use(ident, binding, used);
             return Ok(binding);
         }
 
diff --git a/compiler/rustc_resolve/src/imports.rs b/compiler/rustc_resolve/src/imports.rs
index dcd01b9b334..9bfca0f1798 100644
--- a/compiler/rustc_resolve/src/imports.rs
+++ b/compiler/rustc_resolve/src/imports.rs
@@ -10,9 +10,9 @@ use crate::errors::{
 use crate::Determinacy::{self, *};
 use crate::Namespace::*;
 use crate::{module_to_string, names_to_string, ImportSuggestion};
-use crate::{AmbiguityKind, BindingKey, ModuleKind, ResolutionError, Resolver, Segment};
+use crate::{AmbiguityKind, BindingKey, ResolutionError, Resolver, Segment};
 use crate::{Finalize, Module, ModuleOrUniformRoot, ParentScope, PerNS, ScopeSet};
-use crate::{NameBinding, NameBindingData, NameBindingKind, PathResult};
+use crate::{NameBinding, NameBindingData, NameBindingKind, PathResult, Used};
 
 use rustc_ast::NodeId;
 use rustc_data_structures::fx::FxHashSet;
@@ -173,7 +173,7 @@ pub(crate) struct ImportData<'a> {
     /// The resolution of `module_path`.
     pub imported_module: Cell<Option<ModuleOrUniformRoot<'a>>>,
     pub vis: Cell<Option<ty::Visibility>>,
-    pub used: Cell<bool>,
+    pub used: Cell<Option<Used>>,
 }
 
 /// All imports are unique and allocated on a same arena,
@@ -286,7 +286,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
         }
 
         self.arenas.alloc_name_binding(NameBindingData {
-            kind: NameBindingKind::Import { binding, import, used: Cell::new(false) },
+            kind: NameBindingKind::Import { binding, import },
             ambiguity: None,
             warn_ambiguity: false,
             span: import.span,
@@ -485,9 +485,9 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
                     resolution.single_imports.remove(&import);
                 })
             });
-            self.record_use(target, dummy_binding, false);
+            self.record_use(target, dummy_binding, Used::Other);
         } else if import.imported_module.get().is_none() {
-            import.used.set(true);
+            import.used.set(Some(Used::Other));
             if let Some(id) = import.id() {
                 self.used_imports.insert(id);
             }
@@ -1056,11 +1056,12 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
                                     && initial_binding.is_extern_crate()
                                     && !initial_binding.is_import()
                                 {
-                                    this.record_use(
-                                        ident,
-                                        target_binding,
-                                        import.module_path.is_empty(),
-                                    );
+                                    let used = if import.module_path.is_empty() {
+                                        Used::Scope
+                                    } else {
+                                        Used::Other
+                                    };
+                                    this.record_use(ident, target_binding, used);
                                 }
                             }
                             initial_binding.res()
@@ -1299,22 +1300,23 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
             }
         });
 
-        self.check_for_redundant_imports(ident, import, source_bindings, target_bindings, target);
-
         debug!("(resolving single import) successfully resolved import");
         None
     }
 
-    fn check_for_redundant_imports(
-        &mut self,
-        ident: Ident,
-        import: Import<'a>,
-        source_bindings: &PerNS<Cell<Result<NameBinding<'a>, Determinacy>>>,
-        target_bindings: &PerNS<Cell<Option<NameBinding<'a>>>>,
-        target: Ident,
-    ) {
+    pub(crate) fn check_for_redundant_imports(&mut self, import: Import<'a>) {
         // This function is only called for single imports.
-        let ImportKind::Single { id, .. } = import.kind else { unreachable!() };
+        let ImportKind::Single {
+            source, target, ref source_bindings, ref target_bindings, id, ..
+        } = import.kind
+        else {
+            unreachable!()
+        };
+
+        // Skip if the import is of the form `use source as target` and source != target.
+        if source != target {
+            return;
+        }
 
         // Skip if the import was produced by a macro.
         if import.parent_scope.expansion != LocalExpnId::ROOT {
@@ -1323,16 +1325,20 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
 
         // Skip if we are inside a named module (in contrast to an anonymous
         // module defined by a block).
-        if let ModuleKind::Def(..) = import.parent_scope.module.kind {
+        // Skip if the import is public or was used through non scope-based resolution,
+        // e.g. through a module-relative path.
+        if import.used.get() == Some(Used::Other)
+            || self.effective_visibilities.is_exported(self.local_def_id(id))
+        {
             return;
         }
 
-        let mut is_redundant = PerNS { value_ns: None, type_ns: None, macro_ns: None };
+        let mut is_redundant = true;
 
         let mut redundant_span = PerNS { value_ns: None, type_ns: None, macro_ns: None };
 
         self.per_ns(|this, ns| {
-            if let Ok(binding) = source_bindings[ns].get() {
+            if is_redundant && let Ok(binding) = source_bindings[ns].get() {
                 if binding.res() == Res::Err {
                     return;
                 }
@@ -1346,18 +1352,19 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
                     target_bindings[ns].get(),
                 ) {
                     Ok(other_binding) => {
-                        is_redundant[ns] = Some(
-                            binding.res() == other_binding.res() && !other_binding.is_ambiguity(),
-                        );
-                        redundant_span[ns] = Some((other_binding.span, other_binding.is_import()));
+                        is_redundant =
+                            binding.res() == other_binding.res() && !other_binding.is_ambiguity();
+                        if is_redundant {
+                            redundant_span[ns] =
+                                Some((other_binding.span, other_binding.is_import()));
+                        }
                     }
-                    Err(_) => is_redundant[ns] = Some(false),
+                    Err(_) => is_redundant = false,
                 }
             }
         });
 
-        if !is_redundant.is_empty() && is_redundant.present_items().all(|is_redundant| is_redundant)
-        {
+        if is_redundant && !redundant_span.is_empty() {
             let mut redundant_spans: Vec<_> = redundant_span.present_items().collect();
             redundant_spans.sort();
             redundant_spans.dedup();
@@ -1365,8 +1372,8 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
                 UNUSED_IMPORTS,
                 id,
                 import.span,
-                format!("the item `{ident}` is imported redundantly"),
-                BuiltinLintDiagnostics::RedundantImport(redundant_spans, ident),
+                format!("the item `{source}` is imported redundantly"),
+                BuiltinLintDiagnostics::RedundantImport(redundant_spans, source),
             );
         }
     }
diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs
index 3ea4df1d2a4..1cf3fecc289 100644
--- a/compiler/rustc_resolve/src/late.rs
+++ b/compiler/rustc_resolve/src/late.rs
@@ -7,23 +7,22 @@
 //! `build_reduced_graph.rs`, `macros.rs` and `imports.rs`.
 
 use crate::errors::ImportsCannotReferTo;
-use crate::BindingKey;
 use crate::{path_names_to_string, rustdoc, BindingError, Finalize, LexicalScopeBinding};
+use crate::{BindingKey, Used};
 use crate::{Module, ModuleOrUniformRoot, NameBinding, ParentScope, PathResult};
 use crate::{ResolutionError, Resolver, Segment, UseError};
 
 use rustc_ast::ptr::P;
-use rustc_ast::visit::{self, AssocCtxt, BoundKind, FnCtxt, FnKind, Visitor};
+use rustc_ast::visit::{AssocCtxt, BoundKind, FnCtxt, FnKind, Visitor};
 use rustc_ast::*;
 use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexMap};
 use rustc_errors::{
-    codes::*, struct_span_code_err, Applicability, DiagnosticArgValue, ErrCode, IntoDiagnosticArg,
-    StashKey,
+    codes::*, struct_span_code_err, Applicability, DiagnosticArgValue, IntoDiagnosticArg, StashKey,
 };
 use rustc_hir::def::Namespace::{self, *};
 use rustc_hir::def::{self, CtorKind, DefKind, LifetimeRes, NonMacroAttrKind, PartialRes, PerNS};
 use rustc_hir::def_id::{DefId, LocalDefId, CRATE_DEF_ID, LOCAL_CRATE};
-use rustc_hir::{BindingAnnotation, PrimTy, TraitCandidate};
+use rustc_hir::{PrimTy, TraitCandidate};
 use rustc_metadata::creader::CStore;
 use rustc_middle::middle::resolve_bound_vars::Set1;
 use rustc_middle::{bug, span_bug};
@@ -3623,7 +3622,7 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> {
                 // whether they can be shadowed by fresh bindings or not, so force an error.
                 // issues/33118#issuecomment-233962221 (see below) still applies here,
                 // but we have to ignore it for backward compatibility.
-                self.r.record_use(ident, binding, false);
+                self.r.record_use(ident, binding, Used::Other);
                 return None;
             }
             LexicalScopeBinding::Item(binding) => (binding.res(), Some(binding)),
@@ -3638,7 +3637,7 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> {
             ) if is_syntactic_ambiguity => {
                 // Disambiguate in favor of a unit struct/variant or constant pattern.
                 if let Some(binding) = binding {
-                    self.r.record_use(ident, binding, false);
+                    self.r.record_use(ident, binding, Used::Other);
                 }
                 Some(res)
             }
diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs
index bf811c7a4bb..1c625f49e3e 100644
--- a/compiler/rustc_resolve/src/lib.rs
+++ b/compiler/rustc_resolve/src/lib.rs
@@ -175,6 +175,23 @@ enum ImplTraitContext {
     Universal,
 }
 
+/// Used for tracking import use types which will be used for redundant import checking.
+/// ### Used::Scope Example
+///  ```rust,compile_fail
+/// #![deny(unused_imports)]
+/// use std::mem::drop;
+/// fn main() {
+///     let s = Box::new(32);
+///     drop(s);
+/// }
+/// ```
+/// Used::Other is for other situations like module-relative uses.
+#[derive(Clone, Copy, PartialEq, PartialOrd, Debug)]
+enum Used {
+    Scope,
+    Other,
+}
+
 #[derive(Debug)]
 struct BindingError {
     name: Symbol,
@@ -695,7 +712,7 @@ impl<'a> ToNameBinding<'a> for NameBinding<'a> {
 enum NameBindingKind<'a> {
     Res(Res),
     Module(Module<'a>),
-    Import { binding: NameBinding<'a>, import: Import<'a>, used: Cell<bool> },
+    Import { binding: NameBinding<'a>, import: Import<'a> },
 }
 
 impl<'a> NameBindingKind<'a> {
@@ -1784,15 +1801,15 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
         false
     }
 
-    fn record_use(&mut self, ident: Ident, used_binding: NameBinding<'a>, is_lexical_scope: bool) {
-        self.record_use_inner(ident, used_binding, is_lexical_scope, used_binding.warn_ambiguity);
+    fn record_use(&mut self, ident: Ident, used_binding: NameBinding<'a>, used: Used) {
+        self.record_use_inner(ident, used_binding, used, used_binding.warn_ambiguity);
     }
 
     fn record_use_inner(
         &mut self,
         ident: Ident,
         used_binding: NameBinding<'a>,
-        is_lexical_scope: bool,
+        used: Used,
         warn_ambiguity: bool,
     ) {
         if let Some((b2, kind)) = used_binding.ambiguity {
@@ -1810,27 +1827,35 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
                 self.ambiguity_errors.push(ambiguity_error);
             }
         }
-        if let NameBindingKind::Import { import, binding, ref used } = used_binding.kind {
+        if let NameBindingKind::Import { import, binding } = used_binding.kind {
             if let ImportKind::MacroUse { warn_private: true } = import.kind {
                 let msg = format!("macro `{ident}` is private");
                 self.lint_buffer().buffer_lint(PRIVATE_MACRO_USE, import.root_id, ident.span, msg);
             }
             // Avoid marking `extern crate` items that refer to a name from extern prelude,
             // but not introduce it, as used if they are accessed from lexical scope.
-            if is_lexical_scope {
+            if used == Used::Scope {
                 if let Some(entry) = self.extern_prelude.get(&ident.normalize_to_macros_2_0()) {
                     if !entry.introduced_by_item && entry.binding == Some(used_binding) {
                         return;
                     }
                 }
             }
-            used.set(true);
-            import.used.set(true);
+            let old_used = import.used.get();
+            let new_used = Some(used);
+            if new_used > old_used {
+                import.used.set(new_used);
+            }
             if let Some(id) = import.id() {
                 self.used_imports.insert(id);
             }
             self.add_to_glob_map(import, ident);
-            self.record_use_inner(ident, binding, false, warn_ambiguity || binding.warn_ambiguity);
+            self.record_use_inner(
+                ident,
+                binding,
+                Used::Other,
+                warn_ambiguity || binding.warn_ambiguity,
+            );
         }
     }
 
@@ -1985,7 +2010,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
                     if !entry.is_import() {
                         self.crate_loader(|c| c.process_path_extern(ident.name, ident.span));
                     } else if entry.introduced_by_item {
-                        self.record_use(ident, binding, false);
+                        self.record_use(ident, binding, Used::Other);
                     }
                 }
                 binding
@@ -2115,7 +2140,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
         let is_import = name_binding.is_import();
         let span = name_binding.span;
         if let Res::Def(DefKind::Fn, _) = res {
-            self.record_use(ident, name_binding, false);
+            self.record_use(ident, name_binding, Used::Other);
         }
         self.main_def = Some(MainDefinition { res, is_import, span });
     }
@@ -2176,6 +2201,8 @@ struct Finalize {
     /// Whether to report privacy errors or silently return "no resolution" for them,
     /// similarly to speculative resolution.
     report_private: bool,
+    /// Tracks whether an item is used in scope or used relatively to a module.
+    used: Used,
 }
 
 impl Finalize {
@@ -2184,7 +2211,7 @@ impl Finalize {
     }
 
     fn with_root_span(node_id: NodeId, path_span: Span, root_span: Span) -> Finalize {
-        Finalize { node_id, path_span, root_span, report_private: true }
+        Finalize { node_id, path_span, root_span, report_private: true, used: Used::Other }
     }
 }
 
diff --git a/compiler/rustc_resolve/src/macros.rs b/compiler/rustc_resolve/src/macros.rs
index 170cc1268c3..3fccdec8aa0 100644
--- a/compiler/rustc_resolve/src/macros.rs
+++ b/compiler/rustc_resolve/src/macros.rs
@@ -5,7 +5,7 @@ use crate::errors::CannotDetermineMacroResolution;
 use crate::errors::{self, AddAsNonDerive, CannotFindIdentInThisScope};
 use crate::errors::{MacroExpectedFound, RemoveSurroundingDerive};
 use crate::Namespace::*;
-use crate::{BuiltinMacroState, Determinacy, MacroData};
+use crate::{BuiltinMacroState, Determinacy, MacroData, Used};
 use crate::{DeriveData, Finalize, ParentScope, ResolutionError, Resolver, ScopeSet};
 use crate::{ModuleKind, ModuleOrUniformRoot, NameBinding, PathResult, Segment, ToNameBinding};
 use rustc_ast::expand::StrippedCfgItem;
@@ -794,7 +794,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
             ) {
                 Ok(binding) => {
                     let initial_res = initial_binding.map(|initial_binding| {
-                        self.record_use(ident, initial_binding, false);
+                        self.record_use(ident, initial_binding, Used::Other);
                         initial_binding.res()
                     });
                     let res = binding.res();
diff --git a/compiler/rustc_session/Cargo.toml b/compiler/rustc_session/Cargo.toml
index ba8f67982f5..721a9275d01 100644
--- a/compiler/rustc_session/Cargo.toml
+++ b/compiler/rustc_session/Cargo.toml
@@ -30,7 +30,7 @@ libc = "0.2"
 # tidy-alphabetical-end
 
 [target.'cfg(windows)'.dependencies.windows]
-version = "0.48.0"
+version = "0.52.0"
 features = [
     "Win32_Foundation",
     "Win32_System_LibraryLoader",
diff --git a/compiler/rustc_session/src/filesearch.rs b/compiler/rustc_session/src/filesearch.rs
index 6e459ac45d3..2456b4b3a15 100644
--- a/compiler/rustc_session/src/filesearch.rs
+++ b/compiler/rustc_session/src/filesearch.rs
@@ -143,7 +143,6 @@ fn current_dll_path() -> Result<PathBuf, String> {
             &mut module,
         )
     }
-    .ok()
     .map_err(|e| e.to_string())?;
 
     let mut filename = vec![0; 1024];
diff --git a/compiler/rustc_session/src/session.rs b/compiler/rustc_session/src/session.rs
index 25c20be8e62..9d1133c487f 100644
--- a/compiler/rustc_session/src/session.rs
+++ b/compiler/rustc_session/src/session.rs
@@ -22,7 +22,7 @@ use rustc_errors::emitter::{DynEmitter, HumanEmitter, HumanReadableErrorType};
 use rustc_errors::json::JsonEmitter;
 use rustc_errors::registry::Registry;
 use rustc_errors::{
-    codes::*, fallback_fluent_bundle, DiagCtxt, DiagnosticBuilder, DiagnosticMessage, ErrCode,
+    codes::*, fallback_fluent_bundle, DiagCtxt, DiagnosticBuilder, DiagnosticMessage,
     ErrorGuaranteed, FatalAbort, FluentBundle, IntoDiagnostic, LazyFallbackBundle, TerminalUrl,
 };
 use rustc_macros::HashStable_Generic;
diff --git a/compiler/rustc_session/src/utils.rs b/compiler/rustc_session/src/utils.rs
index f76c69af526..50ebbdccf67 100644
--- a/compiler/rustc_session/src/utils.rs
+++ b/compiler/rustc_session/src/utils.rs
@@ -1,7 +1,10 @@
 use crate::session::Session;
 use rustc_data_structures::profiling::VerboseTimingGuard;
 use rustc_fs_util::try_canonicalize;
-use std::path::{Path, PathBuf};
+use std::{
+    path::{Path, PathBuf},
+    sync::OnceLock,
+};
 
 impl Session {
     pub fn timer(&self, what: &'static str) -> VerboseTimingGuard<'_> {
@@ -158,3 +161,18 @@ pub fn extra_compiler_flags() -> Option<(Vec<String>, bool)> {
 
     if !result.is_empty() { Some((result, excluded_cargo_defaults)) } else { None }
 }
+
+/// Returns whenever rustc was launched by Cargo as opposed to another build system.
+///
+/// To be used in diagnostics to avoid printing Cargo specific suggestions to other
+/// build systems (like Bazel, Buck2, Makefile, ...).
+pub fn was_invoked_from_cargo() -> bool {
+    static FROM_CARGO: OnceLock<bool> = OnceLock::new();
+
+    // To be able to detect Cargo, we use the simplest and least intrusive
+    // way: we check whenever the `CARGO_CRATE_NAME` env is set.
+    //
+    // Note that it is common in Makefiles to define the `CARGO` env even
+    // though we may not have been called by Cargo, so we avoid using it.
+    *FROM_CARGO.get_or_init(|| std::env::var_os("CARGO_CRATE_NAME").is_some())
+}
diff --git a/compiler/rustc_span/src/lib.rs b/compiler/rustc_span/src/lib.rs
index 49ae9f16c8e..616a7ccc7c6 100644
--- a/compiler/rustc_span/src/lib.rs
+++ b/compiler/rustc_span/src/lib.rs
@@ -72,6 +72,7 @@ pub mod fatal_error;
 
 pub mod profiling;
 
+use rustc_data_structures::fx::FxHashMap;
 use rustc_data_structures::stable_hasher::{Hash128, Hash64, HashStable, StableHasher};
 use rustc_data_structures::sync::{FreezeLock, FreezeWriteGuard, Lock, Lrc};
 
@@ -98,6 +99,9 @@ mod tests;
 pub struct SessionGlobals {
     symbol_interner: symbol::Interner,
     span_interner: Lock<span_encoding::SpanInterner>,
+    /// Maps a macro argument token into use of the corresponding metavariable in the macro body.
+    /// Collisions are possible and processed in `maybe_use_metavar_location` on best effort basis.
+    metavar_spans: Lock<FxHashMap<Span, Span>>,
     hygiene_data: Lock<hygiene::HygieneData>,
 
     /// A reference to the source map in the `Session`. It's an `Option`
@@ -115,6 +119,7 @@ impl SessionGlobals {
         SessionGlobals {
             symbol_interner: symbol::Interner::fresh(),
             span_interner: Lock::new(span_encoding::SpanInterner::default()),
+            metavar_spans: Default::default(),
             hygiene_data: Lock::new(hygiene::HygieneData::new(edition)),
             source_map: Lock::new(None),
         }
@@ -168,6 +173,11 @@ pub fn create_default_session_globals_then<R>(f: impl FnOnce() -> R) -> R {
 // deserialization.
 scoped_tls::scoped_thread_local!(static SESSION_GLOBALS: SessionGlobals);
 
+#[inline]
+pub fn with_metavar_spans<R>(f: impl FnOnce(&mut FxHashMap<Span, Span>) -> R) -> R {
+    with_session_globals(|session_globals| f(&mut session_globals.metavar_spans.lock()))
+}
+
 // FIXME: We should use this enum or something like it to get rid of the
 // use of magic `/rust/1.x/...` paths across the board.
 #[derive(Debug, Eq, PartialEq, Clone, Ord, PartialOrd, Decodable)]
@@ -824,29 +834,64 @@ impl Span {
         )
     }
 
+    /// Check if you can select metavar spans for the given spans to get matching contexts.
+    fn try_metavars(a: SpanData, b: SpanData, a_orig: Span, b_orig: Span) -> (SpanData, SpanData) {
+        let get = |mspans: &FxHashMap<_, _>, s| mspans.get(&s).copied();
+        match with_metavar_spans(|mspans| (get(mspans, a_orig), get(mspans, b_orig))) {
+            (None, None) => {}
+            (Some(meta_a), None) => {
+                let meta_a = meta_a.data();
+                if meta_a.ctxt == b.ctxt {
+                    return (meta_a, b);
+                }
+            }
+            (None, Some(meta_b)) => {
+                let meta_b = meta_b.data();
+                if a.ctxt == meta_b.ctxt {
+                    return (a, meta_b);
+                }
+            }
+            (Some(meta_a), Some(meta_b)) => {
+                let meta_b = meta_b.data();
+                if a.ctxt == meta_b.ctxt {
+                    return (a, meta_b);
+                }
+                let meta_a = meta_a.data();
+                if meta_a.ctxt == b.ctxt {
+                    return (meta_a, b);
+                } else if meta_a.ctxt == meta_b.ctxt {
+                    return (meta_a, meta_b);
+                }
+            }
+        }
+
+        (a, b)
+    }
+
     /// Prepare two spans to a combine operation like `to` or `between`.
-    /// FIXME: consider using declarative macro metavariable spans for the given spans if they are
-    /// better suitable for combining (#119412).
     fn prepare_to_combine(
         a_orig: Span,
         b_orig: Span,
     ) -> Result<(SpanData, SpanData, Option<LocalDefId>), Span> {
         let (a, b) = (a_orig.data(), b_orig.data());
+        if a.ctxt == b.ctxt {
+            return Ok((a, b, if a.parent == b.parent { a.parent } else { None }));
+        }
 
-        if a.ctxt != b.ctxt {
-            // Context mismatches usually happen when procedural macros combine spans copied from
-            // the macro input with spans produced by the macro (`Span::*_site`).
-            // In that case we consider the combined span to be produced by the macro and return
-            // the original macro-produced span as the result.
-            // Otherwise we just fall back to returning the first span.
-            // Combining locations typically doesn't make sense in case of context mismatches.
-            // `is_root` here is a fast path optimization.
-            let a_is_callsite = a.ctxt.is_root() || a.ctxt == b.span().source_callsite().ctxt();
-            return Err(if a_is_callsite { b_orig } else { a_orig });
+        let (a, b) = Span::try_metavars(a, b, a_orig, b_orig);
+        if a.ctxt == b.ctxt {
+            return Ok((a, b, if a.parent == b.parent { a.parent } else { None }));
         }
 
-        let parent = if a.parent == b.parent { a.parent } else { None };
-        Ok((a, b, parent))
+        // Context mismatches usually happen when procedural macros combine spans copied from
+        // the macro input with spans produced by the macro (`Span::*_site`).
+        // In that case we consider the combined span to be produced by the macro and return
+        // the original macro-produced span as the result.
+        // Otherwise we just fall back to returning the first span.
+        // Combining locations typically doesn't make sense in case of context mismatches.
+        // `is_root` here is a fast path optimization.
+        let a_is_callsite = a.ctxt.is_root() || a.ctxt == b.span().source_callsite().ctxt();
+        Err(if a_is_callsite { b_orig } else { a_orig })
     }
 
     /// This span, but in a larger context, may switch to the metavariable span if suitable.
diff --git a/compiler/rustc_span/src/source_map/tests.rs b/compiler/rustc_span/src/source_map/tests.rs
index 51f8aa04e8a..81a9e470688 100644
--- a/compiler/rustc_span/src/source_map/tests.rs
+++ b/compiler/rustc_span/src/source_map/tests.rs
@@ -1,7 +1,5 @@
 use super::*;
 
-use rustc_data_structures::sync::FreezeLock;
-
 fn init_source_map() -> SourceMap {
     let sm = SourceMap::new(FilePathMapping::empty());
     sm.new_source_file(PathBuf::from("blork.rs").into(), "first line.\nsecond line".to_string());
diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs
index 0472981086e..2d85f84f480 100644
--- a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs
+++ b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs
@@ -3689,6 +3689,24 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
         if let Node::Expr(expr) = tcx.hir_node(arg_hir_id)
             && let Some(typeck_results) = &self.typeck_results
         {
+            if let hir::Expr { kind: hir::ExprKind::MethodCall(_, rcvr, _, _), .. } = expr
+                && let Some(ty) = typeck_results.node_type_opt(rcvr.hir_id)
+                && let Some(failed_pred) = failed_pred.to_opt_poly_trait_pred()
+                && let pred = failed_pred.map_bound(|pred| pred.with_self_ty(tcx, ty))
+                && self.predicate_must_hold_modulo_regions(&Obligation::misc(
+                    tcx, expr.span, body_id, param_env, pred,
+                ))
+            {
+                err.span_suggestion_verbose(
+                    expr.span.with_lo(rcvr.span.hi()),
+                    format!(
+                        "consider removing this method call, as the receiver has type `{ty}` and \
+                         `{pred}` trivially holds",
+                    ),
+                    "",
+                    Applicability::MaybeIncorrect,
+                );
+            }
             if let hir::Expr { kind: hir::ExprKind::Block(block, _), .. } = expr {
                 let inner_expr = expr.peel_blocks();
                 let ty = typeck_results
@@ -3824,7 +3842,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
             }
         }
 
-        if let Node::Expr(expr) = tcx.hir_node(call_hir_id) {
+        if let Node::Expr(expr) = call_node {
             if let hir::ExprKind::Call(hir::Expr { span, .. }, _)
             | hir::ExprKind::MethodCall(
                 hir::PathSegment { ident: Ident { span, .. }, .. },
diff --git a/config.example.toml b/config.example.toml
index 098811195d7..975fcd71fc9 100644
--- a/config.example.toml
+++ b/config.example.toml
@@ -829,7 +829,7 @@
 # target triples containing `-none`, `nvptx`, `switch`, or `-uefi`.
 #no-std = <platform-specific> (bool)
 
-# This is an array of the codegen backends that will be compiled a rustc
+# This is an array of the codegen backends that will be
 # compiled for this target, overriding the global rust.codegen-backends option.
 # See that option for more info.
 #codegen-backends = rust.codegen-backends (array)
diff --git a/library/alloc/src/raw_vec.rs b/library/alloc/src/raw_vec.rs
index 49f5f53f9b3..dd8d6f6c7e6 100644
--- a/library/alloc/src/raw_vec.rs
+++ b/library/alloc/src/raw_vec.rs
@@ -261,7 +261,7 @@ impl<T, A: Allocator> RawVec<T, A> {
             // and could hypothetically handle differences between stride and size, but this memory
             // has already been allocated so we know it can't overflow and currently rust does not
             // support such types. So we can do better by skipping some checks and avoid an unwrap.
-            let _: () = const { assert!(mem::size_of::<T>() % mem::align_of::<T>() == 0) };
+            const { assert!(mem::size_of::<T>() % mem::align_of::<T>() == 0) };
             unsafe {
                 let align = mem::align_of::<T>();
                 let size = mem::size_of::<T>().unchecked_mul(self.cap.0);
@@ -465,7 +465,7 @@ impl<T, A: Allocator> RawVec<T, A> {
 
         let (ptr, layout) = if let Some(mem) = self.current_memory() { mem } else { return Ok(()) };
         // See current_memory() why this assert is here
-        let _: () = const { assert!(mem::size_of::<T>() % mem::align_of::<T>() == 0) };
+        const { assert!(mem::size_of::<T>() % mem::align_of::<T>() == 0) };
 
         // If shrinking to 0, deallocate the buffer. We don't reach this point
         // for the T::IS_ZST case since current_memory() will have returned
diff --git a/library/panic_unwind/src/seh.rs b/library/panic_unwind/src/seh.rs
index d3ba546d730..c4f4d2fbec9 100644
--- a/library/panic_unwind/src/seh.rs
+++ b/library/panic_unwind/src/seh.rs
@@ -261,8 +261,9 @@ cfg_if::cfg_if! {
    }
 }
 
-// FIXME: Use `SyncUnsafeCell` instead of allowing `static_mut_ref` lint
-#[allow(static_mut_ref)]
+// FIXME: Use `SyncUnsafeCell` instead of allowing `static_mut_refs` lint
+#[cfg_attr(bootstrap, allow(static_mut_ref))]
+#[cfg_attr(not(bootstrap), allow(static_mut_refs))]
 pub unsafe fn panic(data: Box<dyn Any + Send>) -> u32 {
     use core::intrinsics::atomic_store_seqcst;
 
@@ -324,8 +325,9 @@ pub unsafe fn panic(data: Box<dyn Any + Send>) -> u32 {
     _CxxThrowException(throw_ptr, &mut THROW_INFO as *mut _ as *mut _);
 }
 
-// FIXME: Use `SyncUnsafeCell` instead of allowing `static_mut_ref` lint
-#[allow(static_mut_ref)]
+// FIXME: Use `SyncUnsafeCell` instead of allowing `static_mut_refs` lint
+#[cfg_attr(bootstrap, allow(static_mut_ref))]
+#[cfg_attr(not(bootstrap), allow(static_mut_refs))]
 pub unsafe fn cleanup(payload: *mut u8) -> Box<dyn Any + Send> {
     // A null payload here means that we got here from the catch (...) of
     // __rust_try. This happens when a non-Rust foreign exception is caught.
diff --git a/library/portable-simd/crates/core_simd/src/intrinsics.rs b/library/portable-simd/crates/core_simd/src/intrinsics.rs
deleted file mode 100644
index b27893bc729..00000000000
--- a/library/portable-simd/crates/core_simd/src/intrinsics.rs
+++ /dev/null
@@ -1,169 +0,0 @@
-//! This module contains the LLVM intrinsics bindings that provide the functionality for this
-//! crate.
-//!
-//! The LLVM assembly language is documented here: <https://llvm.org/docs/LangRef.html>
-//!
-//! A quick glossary of jargon that may appear in this module, mostly paraphrasing LLVM's LangRef:
-//! - poison: "undefined behavior as a value". specifically, it is like uninit memory (such as padding bytes). it is "safe" to create poison, BUT
-//!   poison MUST NOT be observed from safe code, as operations on poison return poison, like NaN. unlike NaN, which has defined comparisons,
-//!   poison is neither true nor false, and LLVM may also convert it to undef (at which point it is both). so, it can't be conditioned on, either.
-//! - undef: "a value that is every value". functionally like poison, insofar as Rust is concerned. poison may become this. note:
-//!   this means that division by poison or undef is like division by zero, which means it inflicts...
-//! - "UB": poison and undef cover most of what people call "UB". "UB" means this operation immediately invalidates the program:
-//!   LLVM is allowed to lower it to `ud2` or other opcodes that may cause an illegal instruction exception, and this is the "good end".
-//!   The "bad end" is that LLVM may reverse time to the moment control flow diverged on a path towards undefined behavior,
-//!   and destroy the other branch, potentially deleting safe code and violating Rust's `unsafe` contract.
-//!
-//! Note that according to LLVM, vectors are not arrays, but they are equivalent when stored to and loaded from memory.
-//!
-//! Unless stated otherwise, all intrinsics for binary operations require SIMD vectors of equal types and lengths.
-
-// These intrinsics aren't linked directly from LLVM and are mostly undocumented, however they are
-// mostly lowered to the matching LLVM instructions by the compiler in a fairly straightforward manner.
-// The associated LLVM instruction or intrinsic is documented alongside each Rust intrinsic function.
-extern "platform-intrinsic" {
-    /// add/fadd
-    pub(crate) fn simd_add<T>(x: T, y: T) -> T;
-
-    /// sub/fsub
-    pub(crate) fn simd_sub<T>(lhs: T, rhs: T) -> T;
-
-    /// mul/fmul
-    pub(crate) fn simd_mul<T>(x: T, y: T) -> T;
-
-    /// udiv/sdiv/fdiv
-    /// ints and uints: {s,u}div incur UB if division by zero occurs.
-    /// ints: sdiv is UB for int::MIN / -1.
-    /// floats: fdiv is never UB, but may create NaNs or infinities.
-    pub(crate) fn simd_div<T>(lhs: T, rhs: T) -> T;
-
-    /// urem/srem/frem
-    /// ints and uints: {s,u}rem incur UB if division by zero occurs.
-    /// ints: srem is UB for int::MIN / -1.
-    /// floats: frem is equivalent to libm::fmod in the "default" floating point environment, sans errno.
-    pub(crate) fn simd_rem<T>(lhs: T, rhs: T) -> T;
-
-    /// shl
-    /// for (u)ints. poison if rhs >= lhs::BITS
-    pub(crate) fn simd_shl<T>(lhs: T, rhs: T) -> T;
-
-    /// ints: ashr
-    /// uints: lshr
-    /// poison if rhs >= lhs::BITS
-    pub(crate) fn simd_shr<T>(lhs: T, rhs: T) -> T;
-
-    /// and
-    pub(crate) fn simd_and<T>(x: T, y: T) -> T;
-
-    /// or
-    pub(crate) fn simd_or<T>(x: T, y: T) -> T;
-
-    /// xor
-    pub(crate) fn simd_xor<T>(x: T, y: T) -> T;
-
-    /// fptoui/fptosi/uitofp/sitofp
-    /// casting floats to integers is truncating, so it is safe to convert values like e.g. 1.5
-    /// but the truncated value must fit in the target type or the result is poison.
-    /// use `simd_as` instead for a cast that performs a saturating conversion.
-    pub(crate) fn simd_cast<T, U>(x: T) -> U;
-    /// follows Rust's `T as U` semantics, including saturating float casts
-    /// which amounts to the same as `simd_cast` for many cases
-    pub(crate) fn simd_as<T, U>(x: T) -> U;
-
-    /// neg/fneg
-    /// ints: ultimately becomes a call to cg_ssa's BuilderMethods::neg. cg_llvm equates this to `simd_sub(Simd::splat(0), x)`.
-    /// floats: LLVM's fneg, which changes the floating point sign bit. Some arches have instructions for it.
-    /// Rust panics for Neg::neg(int::MIN) due to overflow, but it is not UB in LLVM without `nsw`.
-    pub(crate) fn simd_neg<T>(x: T) -> T;
-
-    /// fabs
-    pub(crate) fn simd_fabs<T>(x: T) -> T;
-
-    // minnum/maxnum
-    pub(crate) fn simd_fmin<T>(x: T, y: T) -> T;
-    pub(crate) fn simd_fmax<T>(x: T, y: T) -> T;
-
-    // these return Simd<int, N> with the same BITS size as the inputs
-    pub(crate) fn simd_eq<T, U>(x: T, y: T) -> U;
-    pub(crate) fn simd_ne<T, U>(x: T, y: T) -> U;
-    pub(crate) fn simd_lt<T, U>(x: T, y: T) -> U;
-    pub(crate) fn simd_le<T, U>(x: T, y: T) -> U;
-    pub(crate) fn simd_gt<T, U>(x: T, y: T) -> U;
-    pub(crate) fn simd_ge<T, U>(x: T, y: T) -> U;
-
-    // shufflevector
-    // idx: LLVM calls it a "shuffle mask vector constant", a vector of i32s
-    pub(crate) fn simd_shuffle<T, U, V>(x: T, y: T, idx: U) -> V;
-
-    /// llvm.masked.gather
-    /// like a loop of pointer reads
-    /// val: vector of values to select if a lane is masked
-    /// ptr: vector of pointers to read from
-    /// mask: a "wide" mask of integers, selects as if simd_select(mask, read(ptr), val)
-    /// note, the LLVM intrinsic accepts a mask vector of `<N x i1>`
-    /// FIXME: review this if/when we fix up our mask story in general?
-    pub(crate) fn simd_gather<T, U, V>(val: T, ptr: U, mask: V) -> T;
-    /// llvm.masked.scatter
-    /// like gather, but more spicy, as it writes instead of reads
-    pub(crate) fn simd_scatter<T, U, V>(val: T, ptr: U, mask: V);
-
-    // {s,u}add.sat
-    pub(crate) fn simd_saturating_add<T>(x: T, y: T) -> T;
-
-    // {s,u}sub.sat
-    pub(crate) fn simd_saturating_sub<T>(lhs: T, rhs: T) -> T;
-
-    // reductions
-    // llvm.vector.reduce.{add,fadd}
-    pub(crate) fn simd_reduce_add_ordered<T, U>(x: T, y: U) -> U;
-    // llvm.vector.reduce.{mul,fmul}
-    pub(crate) fn simd_reduce_mul_ordered<T, U>(x: T, y: U) -> U;
-    #[allow(unused)]
-    pub(crate) fn simd_reduce_all<T>(x: T) -> bool;
-    #[allow(unused)]
-    pub(crate) fn simd_reduce_any<T>(x: T) -> bool;
-    pub(crate) fn simd_reduce_max<T, U>(x: T) -> U;
-    pub(crate) fn simd_reduce_min<T, U>(x: T) -> U;
-    pub(crate) fn simd_reduce_and<T, U>(x: T) -> U;
-    pub(crate) fn simd_reduce_or<T, U>(x: T) -> U;
-    pub(crate) fn simd_reduce_xor<T, U>(x: T) -> U;
-
-    // truncate integer vector to bitmask
-    // `fn simd_bitmask(vector) -> unsigned integer` takes a vector of integers and
-    // returns either an unsigned integer or array of `u8`.
-    // Every element in the vector becomes a single bit in the returned bitmask.
-    // If the vector has less than 8 lanes, a u8 is returned with zeroed trailing bits.
-    // The bit order of the result depends on the byte endianness. LSB-first for little
-    // endian and MSB-first for big endian.
-    //
-    // UB if called on a vector with values other than 0 and -1.
-    #[allow(unused)]
-    pub(crate) fn simd_bitmask<T, U>(x: T) -> U;
-
-    // select
-    // first argument is a vector of integers, -1 (all bits 1) is "true"
-    // logically equivalent to (yes & m) | (no & (m^-1),
-    // but you can use it on floats.
-    pub(crate) fn simd_select<M, T>(m: M, yes: T, no: T) -> T;
-    #[allow(unused)]
-    pub(crate) fn simd_select_bitmask<M, T>(m: M, yes: T, no: T) -> T;
-
-    /// getelementptr (without inbounds)
-    /// equivalent to wrapping_offset
-    pub(crate) fn simd_arith_offset<T, U>(ptr: T, offset: U) -> T;
-
-    /// equivalent to `T as U` semantics, specifically for pointers
-    pub(crate) fn simd_cast_ptr<T, U>(ptr: T) -> U;
-
-    /// expose a pointer as an address
-    pub(crate) fn simd_expose_addr<T, U>(ptr: T) -> U;
-
-    /// convert an exposed address back to a pointer
-    pub(crate) fn simd_from_exposed_addr<T, U>(addr: T) -> U;
-
-    // Integer operations
-    pub(crate) fn simd_bswap<T>(x: T) -> T;
-    pub(crate) fn simd_bitreverse<T>(x: T) -> T;
-    pub(crate) fn simd_ctlz<T>(x: T) -> T;
-    pub(crate) fn simd_cttz<T>(x: T) -> T;
-}
diff --git a/library/portable-simd/crates/core_simd/src/lib.rs b/library/portable-simd/crates/core_simd/src/lib.rs
index 64ba9705ef5..a25723e11ce 100644
--- a/library/portable-simd/crates/core_simd/src/lib.rs
+++ b/library/portable-simd/crates/core_simd/src/lib.rs
@@ -1,20 +1,38 @@
 #![no_std]
 #![feature(
+    const_intrinsic_copy,
     const_refs_to_cell,
     const_maybe_uninit_as_mut_ptr,
     const_mut_refs,
     convert_float_to_int,
+    core_intrinsics,
     decl_macro,
     inline_const,
     intra_doc_pointers,
-    platform_intrinsics,
     repr_simd,
     simd_ffi,
     staged_api,
-    stdsimd,
     strict_provenance,
     ptr_metadata
 )]
+#![cfg_attr(
+    all(
+        any(target_arch = "aarch64", target_arch = "arm",),
+        any(
+            all(target_feature = "v6", not(target_feature = "mclass")),
+            all(target_feature = "mclass", target_feature = "dsp"),
+        )
+    ),
+    feature(stdarch_arm_dsp)
+)]
+#![cfg_attr(
+    all(target_arch = "arm", target_feature = "v7"),
+    feature(stdarch_arm_neon_intrinsics)
+)]
+#![cfg_attr(
+    any(target_arch = "powerpc", target_arch = "powerpc64"),
+    feature(stdarch_powerpc)
+)]
 #![warn(missing_docs, clippy::missing_inline_in_public_items)] // basically all items, really
 #![deny(unsafe_op_in_unsafe_fn, clippy::undocumented_unsafe_blocks)]
 #![allow(internal_features)]
diff --git a/library/portable-simd/crates/core_simd/src/masks.rs b/library/portable-simd/crates/core_simd/src/masks.rs
index 0623d2bf3d1..e480c25a51e 100644
--- a/library/portable-simd/crates/core_simd/src/masks.rs
+++ b/library/portable-simd/crates/core_simd/src/masks.rs
@@ -12,9 +12,7 @@
 )]
 mod mask_impl;
 
-use crate::simd::{
-    cmp::SimdPartialEq, intrinsics, LaneCount, Simd, SimdCast, SimdElement, SupportedLaneCount,
-};
+use crate::simd::{LaneCount, Simd, SimdCast, SimdElement, SupportedLaneCount};
 use core::cmp::Ordering;
 use core::{fmt, mem};
 
@@ -35,7 +33,7 @@ mod sealed {
 
         fn eq(self, other: Self) -> bool;
 
-        fn as_usize(self) -> usize;
+        fn to_usize(self) -> usize;
 
         type Unsigned: SimdElement;
 
@@ -60,14 +58,23 @@ macro_rules! impl_element {
             where
                 LaneCount<N>: SupportedLaneCount,
             {
-                (value.simd_eq(Simd::splat(0 as _)) | value.simd_eq(Simd::splat(-1 as _))).all()
+                // We can't use `Simd` directly, because `Simd`'s functions call this function and
+                // we will end up with an infinite loop.
+                // Safety: `value` is an integer vector
+                unsafe {
+                    use core::intrinsics::simd;
+                    let falses: Simd<Self, N> = simd::simd_eq(value, Simd::splat(0 as _));
+                    let trues: Simd<Self, N> = simd::simd_eq(value, Simd::splat(-1 as _));
+                    let valid: Simd<Self, N> = simd::simd_or(falses, trues);
+                    simd::simd_reduce_all(valid)
+                }
             }
 
             #[inline]
             fn eq(self, other: Self) -> bool { self == other }
 
             #[inline]
-            fn as_usize(self) -> usize {
+            fn to_usize(self) -> usize {
                 self as usize
             }
 
@@ -141,8 +148,9 @@ where
         // but these are "dependently-sized" types, so copy elision it is!
         unsafe {
             let bytes: [u8; N] = mem::transmute_copy(&array);
-            let bools: Simd<i8, N> = intrinsics::simd_ne(Simd::from_array(bytes), Simd::splat(0u8));
-            Mask::from_int_unchecked(intrinsics::simd_cast(bools))
+            let bools: Simd<i8, N> =
+                core::intrinsics::simd::simd_ne(Simd::from_array(bytes), Simd::splat(0u8));
+            Mask::from_int_unchecked(core::intrinsics::simd::simd_cast(bools))
         }
     }
 
@@ -160,7 +168,7 @@ where
         // This would be hypothetically valid as an "in-place" transmute,
         // but these are "dependently-sized" types, so copy elision it is!
         unsafe {
-            let mut bytes: Simd<i8, N> = intrinsics::simd_cast(self.to_int());
+            let mut bytes: Simd<i8, N> = core::intrinsics::simd::simd_cast(self.to_int());
             bytes &= Simd::splat(1i8);
             mem::transmute_copy(&bytes)
         }
@@ -175,7 +183,10 @@ where
     #[must_use = "method returns a new mask and does not mutate the original value"]
     pub unsafe fn from_int_unchecked(value: Simd<T, N>) -> Self {
         // Safety: the caller must confirm this invariant
-        unsafe { Self(mask_impl::Mask::from_int_unchecked(value)) }
+        unsafe {
+            core::intrinsics::assume(<T as Sealed>::valid(value));
+            Self(mask_impl::Mask::from_int_unchecked(value))
+        }
     }
 
     /// Converts a vector of integers to a mask, where 0 represents `false` and -1
@@ -374,15 +385,17 @@ where
         );
 
         // Safety: the input and output are integer vectors
-        let index: Simd<T, N> = unsafe { intrinsics::simd_cast(index) };
+        let index: Simd<T, N> = unsafe { core::intrinsics::simd::simd_cast(index) };
 
         let masked_index = self.select(index, Self::splat(true).to_int());
 
         // Safety: the input and output are integer vectors
-        let masked_index: Simd<T::Unsigned, N> = unsafe { intrinsics::simd_cast(masked_index) };
+        let masked_index: Simd<T::Unsigned, N> =
+            unsafe { core::intrinsics::simd::simd_cast(masked_index) };
 
         // Safety: the input is an integer vector
-        let min_index: T::Unsigned = unsafe { intrinsics::simd_reduce_min(masked_index) };
+        let min_index: T::Unsigned =
+            unsafe { core::intrinsics::simd::simd_reduce_min(masked_index) };
 
         // Safety: the return value is the unsigned version of T
         let min_index: T = unsafe { core::mem::transmute_copy(&min_index) };
@@ -390,7 +403,7 @@ where
         if min_index.eq(T::TRUE) {
             None
         } else {
-            Some(min_index.as_usize())
+            Some(min_index.to_usize())
         }
     }
 }
diff --git a/library/portable-simd/crates/core_simd/src/masks/bitmask.rs b/library/portable-simd/crates/core_simd/src/masks/bitmask.rs
index 6ddff07fea2..96c553426ee 100644
--- a/library/portable-simd/crates/core_simd/src/masks/bitmask.rs
+++ b/library/portable-simd/crates/core_simd/src/masks/bitmask.rs
@@ -1,6 +1,5 @@
 #![allow(unused_imports)]
 use super::MaskElement;
-use crate::simd::intrinsics;
 use crate::simd::{LaneCount, Simd, SupportedLaneCount};
 use core::marker::PhantomData;
 
@@ -109,14 +108,18 @@ where
     #[must_use = "method returns a new vector and does not mutate the original value"]
     pub fn to_int(self) -> Simd<T, N> {
         unsafe {
-            intrinsics::simd_select_bitmask(self.0, Simd::splat(T::TRUE), Simd::splat(T::FALSE))
+            core::intrinsics::simd::simd_select_bitmask(
+                self.0,
+                Simd::splat(T::TRUE),
+                Simd::splat(T::FALSE),
+            )
         }
     }
 
     #[inline]
     #[must_use = "method returns a new mask and does not mutate the original value"]
     pub unsafe fn from_int_unchecked(value: Simd<T, N>) -> Self {
-        unsafe { Self(intrinsics::simd_bitmask(value), PhantomData) }
+        unsafe { Self(core::intrinsics::simd::simd_bitmask(value), PhantomData) }
     }
 
     #[inline]
diff --git a/library/portable-simd/crates/core_simd/src/masks/full_masks.rs b/library/portable-simd/crates/core_simd/src/masks/full_masks.rs
index 63964f455e0..87f031a9f36 100644
--- a/library/portable-simd/crates/core_simd/src/masks/full_masks.rs
+++ b/library/portable-simd/crates/core_simd/src/masks/full_masks.rs
@@ -1,6 +1,5 @@
 //! Masks that take up full SIMD vector registers.
 
-use crate::simd::intrinsics;
 use crate::simd::{LaneCount, MaskElement, Simd, SupportedLaneCount};
 
 #[repr(transparent)]
@@ -138,7 +137,7 @@ where
         U: MaskElement,
     {
         // Safety: masks are simply integer vectors of 0 and -1, and we can cast the element type.
-        unsafe { Mask(intrinsics::simd_cast(self.0)) }
+        unsafe { Mask(core::intrinsics::simd::simd_cast(self.0)) }
     }
 
     #[inline]
@@ -150,13 +149,16 @@ where
         unsafe {
             // Compute the bitmask
             let mut bytes: <LaneCount<N> as SupportedLaneCount>::BitMask =
-                intrinsics::simd_bitmask(self.0);
+                core::intrinsics::simd::simd_bitmask(self.0);
 
             // LLVM assumes bit order should match endianness
             if cfg!(target_endian = "big") {
                 for x in bytes.as_mut() {
                     *x = x.reverse_bits()
                 }
+                if N % 8 > 0 {
+                    bytes.as_mut()[N / 8] >>= 8 - N % 8;
+                }
             }
 
             bitmask.as_mut_array()[..bytes.as_ref().len()].copy_from_slice(bytes.as_ref());
@@ -180,10 +182,13 @@ where
                 for x in bytes.as_mut() {
                     *x = x.reverse_bits();
                 }
+                if N % 8 > 0 {
+                    bytes.as_mut()[N / 8] >>= 8 - N % 8;
+                }
             }
 
             // Compute the regular mask
-            Self::from_int_unchecked(intrinsics::simd_select_bitmask(
+            Self::from_int_unchecked(core::intrinsics::simd::simd_select_bitmask(
                 bytes,
                 Self::splat(true).to_int(),
                 Self::splat(false).to_int(),
@@ -199,7 +204,7 @@ where
         let resized = self.to_int().resize::<M>(T::FALSE);
 
         // Safety: `resized` is an integer vector with length M, which must match T
-        let bitmask: U = unsafe { intrinsics::simd_bitmask(resized) };
+        let bitmask: U = unsafe { core::intrinsics::simd::simd_bitmask(resized) };
 
         // LLVM assumes bit order should match endianness
         if cfg!(target_endian = "big") {
@@ -223,7 +228,7 @@ where
 
         // SAFETY: `mask` is the correct bitmask type for a u64 bitmask
         let mask: Simd<T, M> = unsafe {
-            intrinsics::simd_select_bitmask(
+            core::intrinsics::simd::simd_select_bitmask(
                 bitmask,
                 Simd::<T, M>::splat(T::TRUE),
                 Simd::<T, M>::splat(T::FALSE),
@@ -274,14 +279,14 @@ where
     #[must_use = "method returns a new bool and does not mutate the original value"]
     pub fn any(self) -> bool {
         // Safety: use `self` as an integer vector
-        unsafe { intrinsics::simd_reduce_any(self.to_int()) }
+        unsafe { core::intrinsics::simd::simd_reduce_any(self.to_int()) }
     }
 
     #[inline]
     #[must_use = "method returns a new vector and does not mutate the original value"]
     pub fn all(self) -> bool {
         // Safety: use `self` as an integer vector
-        unsafe { intrinsics::simd_reduce_all(self.to_int()) }
+        unsafe { core::intrinsics::simd::simd_reduce_all(self.to_int()) }
     }
 }
 
@@ -306,7 +311,7 @@ where
     #[must_use = "method returns a new mask and does not mutate the original value"]
     fn bitand(self, rhs: Self) -> Self {
         // Safety: `self` is an integer vector
-        unsafe { Self(intrinsics::simd_and(self.0, rhs.0)) }
+        unsafe { Self(core::intrinsics::simd::simd_and(self.0, rhs.0)) }
     }
 }
 
@@ -320,7 +325,7 @@ where
     #[must_use = "method returns a new mask and does not mutate the original value"]
     fn bitor(self, rhs: Self) -> Self {
         // Safety: `self` is an integer vector
-        unsafe { Self(intrinsics::simd_or(self.0, rhs.0)) }
+        unsafe { Self(core::intrinsics::simd::simd_or(self.0, rhs.0)) }
     }
 }
 
@@ -334,7 +339,7 @@ where
     #[must_use = "method returns a new mask and does not mutate the original value"]
     fn bitxor(self, rhs: Self) -> Self {
         // Safety: `self` is an integer vector
-        unsafe { Self(intrinsics::simd_xor(self.0, rhs.0)) }
+        unsafe { Self(core::intrinsics::simd::simd_xor(self.0, rhs.0)) }
     }
 }
 
diff --git a/library/portable-simd/crates/core_simd/src/mod.rs b/library/portable-simd/crates/core_simd/src/mod.rs
index fd016f1c6f7..45b1a0f9751 100644
--- a/library/portable-simd/crates/core_simd/src/mod.rs
+++ b/library/portable-simd/crates/core_simd/src/mod.rs
@@ -1,8 +1,6 @@
 #[macro_use]
 mod swizzle;
 
-pub(crate) mod intrinsics;
-
 mod alias;
 mod cast;
 mod fmt;
@@ -27,8 +25,6 @@ pub mod simd {
 
     pub mod cmp;
 
-    pub(crate) use crate::core_simd::intrinsics;
-
     pub use crate::core_simd::alias::*;
     pub use crate::core_simd::cast::*;
     pub use crate::core_simd::lane_count::{LaneCount, SupportedLaneCount};
diff --git a/library/portable-simd/crates/core_simd/src/ops.rs b/library/portable-simd/crates/core_simd/src/ops.rs
index 8a1b083f039..d8e10eeaa1a 100644
--- a/library/portable-simd/crates/core_simd/src/ops.rs
+++ b/library/portable-simd/crates/core_simd/src/ops.rs
@@ -37,7 +37,7 @@ where
 macro_rules! unsafe_base {
     ($lhs:ident, $rhs:ident, {$simd_call:ident}, $($_:tt)*) => {
         // Safety: $lhs and $rhs are vectors
-        unsafe { $crate::simd::intrinsics::$simd_call($lhs, $rhs) }
+        unsafe { core::intrinsics::simd::$simd_call($lhs, $rhs) }
     };
 }
 
@@ -55,7 +55,7 @@ macro_rules! wrap_bitshift {
         #[allow(clippy::suspicious_arithmetic_impl)]
         // Safety: $lhs and the bitand result are vectors
         unsafe {
-            $crate::simd::intrinsics::$simd_call(
+            core::intrinsics::simd::$simd_call(
                 $lhs,
                 $rhs.bitand(Simd::splat(<$int>::BITS as $int - 1)),
             )
@@ -97,7 +97,7 @@ macro_rules! int_divrem_guard {
                 $rhs
             };
             // Safety: $lhs and rhs are vectors
-            unsafe { $crate::simd::intrinsics::$simd_call($lhs, rhs) }
+            unsafe { core::intrinsics::simd::$simd_call($lhs, rhs) }
         }
     };
 }
diff --git a/library/portable-simd/crates/core_simd/src/ops/unary.rs b/library/portable-simd/crates/core_simd/src/ops/unary.rs
index a651aa73e95..bdae96332a3 100644
--- a/library/portable-simd/crates/core_simd/src/ops/unary.rs
+++ b/library/portable-simd/crates/core_simd/src/ops/unary.rs
@@ -1,4 +1,3 @@
-use crate::simd::intrinsics;
 use crate::simd::{LaneCount, Simd, SimdElement, SupportedLaneCount};
 use core::ops::{Neg, Not}; // unary ops
 
@@ -15,7 +14,7 @@ macro_rules! neg {
             #[must_use = "operator returns a new vector without mutating the input"]
             fn neg(self) -> Self::Output {
                 // Safety: `self` is a signed vector
-                unsafe { intrinsics::simd_neg(self) }
+                unsafe { core::intrinsics::simd::simd_neg(self) }
             }
         })*
     }
diff --git a/library/portable-simd/crates/core_simd/src/select.rs b/library/portable-simd/crates/core_simd/src/select.rs
index cdcf8eeec81..f33aa261a92 100644
--- a/library/portable-simd/crates/core_simd/src/select.rs
+++ b/library/portable-simd/crates/core_simd/src/select.rs
@@ -1,4 +1,3 @@
-use crate::simd::intrinsics;
 use crate::simd::{LaneCount, Mask, MaskElement, Simd, SimdElement, SupportedLaneCount};
 
 impl<T, const N: usize> Mask<T, N>
@@ -29,7 +28,7 @@ where
     {
         // Safety: The mask has been cast to a vector of integers,
         // and the operands to select between are vectors of the same type and length.
-        unsafe { intrinsics::simd_select(self.to_int(), true_values, false_values) }
+        unsafe { core::intrinsics::simd::simd_select(self.to_int(), true_values, false_values) }
     }
 
     /// Choose elements from two masks.
diff --git a/library/portable-simd/crates/core_simd/src/simd/cmp/eq.rs b/library/portable-simd/crates/core_simd/src/simd/cmp/eq.rs
index f132fa2cc0c..5b4615ce51d 100644
--- a/library/portable-simd/crates/core_simd/src/simd/cmp/eq.rs
+++ b/library/portable-simd/crates/core_simd/src/simd/cmp/eq.rs
@@ -1,5 +1,4 @@
 use crate::simd::{
-    intrinsics,
     ptr::{SimdConstPtr, SimdMutPtr},
     LaneCount, Mask, Simd, SimdElement, SupportedLaneCount,
 };
@@ -31,14 +30,14 @@ macro_rules! impl_number {
             fn simd_eq(self, other: Self) -> Self::Mask {
                 // Safety: `self` is a vector, and the result of the comparison
                 // is always a valid mask.
-                unsafe { Mask::from_int_unchecked(intrinsics::simd_eq(self, other)) }
+                unsafe { Mask::from_int_unchecked(core::intrinsics::simd::simd_eq(self, other)) }
             }
 
             #[inline]
             fn simd_ne(self, other: Self) -> Self::Mask {
                 // Safety: `self` is a vector, and the result of the comparison
                 // is always a valid mask.
-                unsafe { Mask::from_int_unchecked(intrinsics::simd_ne(self, other)) }
+                unsafe { Mask::from_int_unchecked(core::intrinsics::simd::simd_ne(self, other)) }
             }
         }
         )*
@@ -60,14 +59,14 @@ macro_rules! impl_mask {
             fn simd_eq(self, other: Self) -> Self::Mask {
                 // Safety: `self` is a vector, and the result of the comparison
                 // is always a valid mask.
-                unsafe { Self::from_int_unchecked(intrinsics::simd_eq(self.to_int(), other.to_int())) }
+                unsafe { Self::from_int_unchecked(core::intrinsics::simd::simd_eq(self.to_int(), other.to_int())) }
             }
 
             #[inline]
             fn simd_ne(self, other: Self) -> Self::Mask {
                 // Safety: `self` is a vector, and the result of the comparison
                 // is always a valid mask.
-                unsafe { Self::from_int_unchecked(intrinsics::simd_ne(self.to_int(), other.to_int())) }
+                unsafe { Self::from_int_unchecked(core::intrinsics::simd::simd_ne(self.to_int(), other.to_int())) }
             }
         }
         )*
diff --git a/library/portable-simd/crates/core_simd/src/simd/cmp/ord.rs b/library/portable-simd/crates/core_simd/src/simd/cmp/ord.rs
index 4e9d49ea221..899f00a8316 100644
--- a/library/portable-simd/crates/core_simd/src/simd/cmp/ord.rs
+++ b/library/portable-simd/crates/core_simd/src/simd/cmp/ord.rs
@@ -1,6 +1,5 @@
 use crate::simd::{
     cmp::SimdPartialEq,
-    intrinsics,
     ptr::{SimdConstPtr, SimdMutPtr},
     LaneCount, Mask, Simd, SupportedLaneCount,
 };
@@ -57,28 +56,28 @@ macro_rules! impl_integer {
             fn simd_lt(self, other: Self) -> Self::Mask {
                 // Safety: `self` is a vector, and the result of the comparison
                 // is always a valid mask.
-                unsafe { Mask::from_int_unchecked(intrinsics::simd_lt(self, other)) }
+                unsafe { Mask::from_int_unchecked(core::intrinsics::simd::simd_lt(self, other)) }
             }
 
             #[inline]
             fn simd_le(self, other: Self) -> Self::Mask {
                 // Safety: `self` is a vector, and the result of the comparison
                 // is always a valid mask.
-                unsafe { Mask::from_int_unchecked(intrinsics::simd_le(self, other)) }
+                unsafe { Mask::from_int_unchecked(core::intrinsics::simd::simd_le(self, other)) }
             }
 
             #[inline]
             fn simd_gt(self, other: Self) -> Self::Mask {
                 // Safety: `self` is a vector, and the result of the comparison
                 // is always a valid mask.
-                unsafe { Mask::from_int_unchecked(intrinsics::simd_gt(self, other)) }
+                unsafe { Mask::from_int_unchecked(core::intrinsics::simd::simd_gt(self, other)) }
             }
 
             #[inline]
             fn simd_ge(self, other: Self) -> Self::Mask {
                 // Safety: `self` is a vector, and the result of the comparison
                 // is always a valid mask.
-                unsafe { Mask::from_int_unchecked(intrinsics::simd_ge(self, other)) }
+                unsafe { Mask::from_int_unchecked(core::intrinsics::simd::simd_ge(self, other)) }
             }
         }
 
@@ -123,28 +122,28 @@ macro_rules! impl_float {
             fn simd_lt(self, other: Self) -> Self::Mask {
                 // Safety: `self` is a vector, and the result of the comparison
                 // is always a valid mask.
-                unsafe { Mask::from_int_unchecked(intrinsics::simd_lt(self, other)) }
+                unsafe { Mask::from_int_unchecked(core::intrinsics::simd::simd_lt(self, other)) }
             }
 
             #[inline]
             fn simd_le(self, other: Self) -> Self::Mask {
                 // Safety: `self` is a vector, and the result of the comparison
                 // is always a valid mask.
-                unsafe { Mask::from_int_unchecked(intrinsics::simd_le(self, other)) }
+                unsafe { Mask::from_int_unchecked(core::intrinsics::simd::simd_le(self, other)) }
             }
 
             #[inline]
             fn simd_gt(self, other: Self) -> Self::Mask {
                 // Safety: `self` is a vector, and the result of the comparison
                 // is always a valid mask.
-                unsafe { Mask::from_int_unchecked(intrinsics::simd_gt(self, other)) }
+                unsafe { Mask::from_int_unchecked(core::intrinsics::simd::simd_gt(self, other)) }
             }
 
             #[inline]
             fn simd_ge(self, other: Self) -> Self::Mask {
                 // Safety: `self` is a vector, and the result of the comparison
                 // is always a valid mask.
-                unsafe { Mask::from_int_unchecked(intrinsics::simd_ge(self, other)) }
+                unsafe { Mask::from_int_unchecked(core::intrinsics::simd::simd_ge(self, other)) }
             }
         }
         )*
@@ -164,28 +163,28 @@ macro_rules! impl_mask {
             fn simd_lt(self, other: Self) -> Self::Mask {
                 // Safety: `self` is a vector, and the result of the comparison
                 // is always a valid mask.
-                unsafe { Self::from_int_unchecked(intrinsics::simd_lt(self.to_int(), other.to_int())) }
+                unsafe { Self::from_int_unchecked(core::intrinsics::simd::simd_lt(self.to_int(), other.to_int())) }
             }
 
             #[inline]
             fn simd_le(self, other: Self) -> Self::Mask {
                 // Safety: `self` is a vector, and the result of the comparison
                 // is always a valid mask.
-                unsafe { Self::from_int_unchecked(intrinsics::simd_le(self.to_int(), other.to_int())) }
+                unsafe { Self::from_int_unchecked(core::intrinsics::simd::simd_le(self.to_int(), other.to_int())) }
             }
 
             #[inline]
             fn simd_gt(self, other: Self) -> Self::Mask {
                 // Safety: `self` is a vector, and the result of the comparison
                 // is always a valid mask.
-                unsafe { Self::from_int_unchecked(intrinsics::simd_gt(self.to_int(), other.to_int())) }
+                unsafe { Self::from_int_unchecked(core::intrinsics::simd::simd_gt(self.to_int(), other.to_int())) }
             }
 
             #[inline]
             fn simd_ge(self, other: Self) -> Self::Mask {
                 // Safety: `self` is a vector, and the result of the comparison
                 // is always a valid mask.
-                unsafe { Self::from_int_unchecked(intrinsics::simd_ge(self.to_int(), other.to_int())) }
+                unsafe { Self::from_int_unchecked(core::intrinsics::simd::simd_ge(self.to_int(), other.to_int())) }
             }
         }
 
diff --git a/library/portable-simd/crates/core_simd/src/simd/num/float.rs b/library/portable-simd/crates/core_simd/src/simd/num/float.rs
index fc0b99e87a6..59e43851ea8 100644
--- a/library/portable-simd/crates/core_simd/src/simd/num/float.rs
+++ b/library/portable-simd/crates/core_simd/src/simd/num/float.rs
@@ -1,7 +1,7 @@
 use super::sealed::Sealed;
 use crate::simd::{
     cmp::{SimdPartialEq, SimdPartialOrd},
-    intrinsics, LaneCount, Mask, Simd, SimdCast, SimdElement, SupportedLaneCount,
+    LaneCount, Mask, Simd, SimdCast, SimdElement, SupportedLaneCount,
 };
 
 /// Operations on SIMD vectors of floats.
@@ -259,7 +259,7 @@ macro_rules! impl_trait {
             fn cast<T: SimdCast>(self) -> Self::Cast<T>
             {
                 // Safety: supported types are guaranteed by SimdCast
-                unsafe { intrinsics::simd_as(self) }
+                unsafe { core::intrinsics::simd::simd_as(self) }
             }
 
             #[inline]
@@ -269,7 +269,7 @@ macro_rules! impl_trait {
                 Self::Scalar: core::convert::FloatToInt<I>,
             {
                 // Safety: supported types are guaranteed by SimdCast, the caller is responsible for the extra invariants
-                unsafe { intrinsics::simd_cast(self) }
+                unsafe { core::intrinsics::simd::simd_cast(self) }
             }
 
             #[inline]
@@ -289,7 +289,7 @@ macro_rules! impl_trait {
             #[inline]
             fn abs(self) -> Self {
                 // Safety: `self` is a float vector
-                unsafe { intrinsics::simd_fabs(self) }
+                unsafe { core::intrinsics::simd::simd_fabs(self) }
             }
 
             #[inline]
@@ -363,13 +363,13 @@ macro_rules! impl_trait {
             #[inline]
             fn simd_min(self, other: Self) -> Self {
                 // Safety: `self` and `other` are float vectors
-                unsafe { intrinsics::simd_fmin(self, other) }
+                unsafe { core::intrinsics::simd::simd_fmin(self, other) }
             }
 
             #[inline]
             fn simd_max(self, other: Self) -> Self {
                 // Safety: `self` and `other` are floating point vectors
-                unsafe { intrinsics::simd_fmax(self, other) }
+                unsafe { core::intrinsics::simd::simd_fmax(self, other) }
             }
 
             #[inline]
@@ -391,7 +391,7 @@ macro_rules! impl_trait {
                     self.as_array().iter().sum()
                 } else {
                     // Safety: `self` is a float vector
-                    unsafe { intrinsics::simd_reduce_add_ordered(self, 0.) }
+                    unsafe { core::intrinsics::simd::simd_reduce_add_ordered(self, 0.) }
                 }
             }
 
@@ -402,20 +402,20 @@ macro_rules! impl_trait {
                     self.as_array().iter().product()
                 } else {
                     // Safety: `self` is a float vector
-                    unsafe { intrinsics::simd_reduce_mul_ordered(self, 1.) }
+                    unsafe { core::intrinsics::simd::simd_reduce_mul_ordered(self, 1.) }
                 }
             }
 
             #[inline]
             fn reduce_max(self) -> Self::Scalar {
                 // Safety: `self` is a float vector
-                unsafe { intrinsics::simd_reduce_max(self) }
+                unsafe { core::intrinsics::simd::simd_reduce_max(self) }
             }
 
             #[inline]
             fn reduce_min(self) -> Self::Scalar {
                 // Safety: `self` is a float vector
-                unsafe { intrinsics::simd_reduce_min(self) }
+                unsafe { core::intrinsics::simd::simd_reduce_min(self) }
             }
         }
         )*
diff --git a/library/portable-simd/crates/core_simd/src/simd/num/int.rs b/library/portable-simd/crates/core_simd/src/simd/num/int.rs
index 1f1aa272782..d7598d9ceaf 100644
--- a/library/portable-simd/crates/core_simd/src/simd/num/int.rs
+++ b/library/portable-simd/crates/core_simd/src/simd/num/int.rs
@@ -1,6 +1,6 @@
 use super::sealed::Sealed;
 use crate::simd::{
-    cmp::SimdPartialOrd, intrinsics, num::SimdUint, LaneCount, Mask, Simd, SimdCast, SimdElement,
+    cmp::SimdPartialOrd, num::SimdUint, LaneCount, Mask, Simd, SimdCast, SimdElement,
     SupportedLaneCount,
 };
 
@@ -237,19 +237,19 @@ macro_rules! impl_trait {
             #[inline]
             fn cast<T: SimdCast>(self) -> Self::Cast<T> {
                 // Safety: supported types are guaranteed by SimdCast
-                unsafe { intrinsics::simd_as(self) }
+                unsafe { core::intrinsics::simd::simd_as(self) }
             }
 
             #[inline]
             fn saturating_add(self, second: Self) -> Self {
                 // Safety: `self` is a vector
-                unsafe { intrinsics::simd_saturating_add(self, second) }
+                unsafe { core::intrinsics::simd::simd_saturating_add(self, second) }
             }
 
             #[inline]
             fn saturating_sub(self, second: Self) -> Self {
                 // Safety: `self` is a vector
-                unsafe { intrinsics::simd_saturating_sub(self, second) }
+                unsafe { core::intrinsics::simd::simd_saturating_sub(self, second) }
             }
 
             #[inline]
@@ -293,55 +293,55 @@ macro_rules! impl_trait {
             #[inline]
             fn reduce_sum(self) -> Self::Scalar {
                 // Safety: `self` is an integer vector
-                unsafe { intrinsics::simd_reduce_add_ordered(self, 0) }
+                unsafe { core::intrinsics::simd::simd_reduce_add_ordered(self, 0) }
             }
 
             #[inline]
             fn reduce_product(self) -> Self::Scalar {
                 // Safety: `self` is an integer vector
-                unsafe { intrinsics::simd_reduce_mul_ordered(self, 1) }
+                unsafe { core::intrinsics::simd::simd_reduce_mul_ordered(self, 1) }
             }
 
             #[inline]
             fn reduce_max(self) -> Self::Scalar {
                 // Safety: `self` is an integer vector
-                unsafe { intrinsics::simd_reduce_max(self) }
+                unsafe { core::intrinsics::simd::simd_reduce_max(self) }
             }
 
             #[inline]
             fn reduce_min(self) -> Self::Scalar {
                 // Safety: `self` is an integer vector
-                unsafe { intrinsics::simd_reduce_min(self) }
+                unsafe { core::intrinsics::simd::simd_reduce_min(self) }
             }
 
             #[inline]
             fn reduce_and(self) -> Self::Scalar {
                 // Safety: `self` is an integer vector
-                unsafe { intrinsics::simd_reduce_and(self) }
+                unsafe { core::intrinsics::simd::simd_reduce_and(self) }
             }
 
             #[inline]
             fn reduce_or(self) -> Self::Scalar {
                 // Safety: `self` is an integer vector
-                unsafe { intrinsics::simd_reduce_or(self) }
+                unsafe { core::intrinsics::simd::simd_reduce_or(self) }
             }
 
             #[inline]
             fn reduce_xor(self) -> Self::Scalar {
                 // Safety: `self` is an integer vector
-                unsafe { intrinsics::simd_reduce_xor(self) }
+                unsafe { core::intrinsics::simd::simd_reduce_xor(self) }
             }
 
             #[inline]
             fn swap_bytes(self) -> Self {
                 // Safety: `self` is an integer vector
-                unsafe { intrinsics::simd_bswap(self) }
+                unsafe { core::intrinsics::simd::simd_bswap(self) }
             }
 
             #[inline]
             fn reverse_bits(self) -> Self {
                 // Safety: `self` is an integer vector
-                unsafe { intrinsics::simd_bitreverse(self) }
+                unsafe { core::intrinsics::simd::simd_bitreverse(self) }
             }
 
             #[inline]
diff --git a/library/portable-simd/crates/core_simd/src/simd/num/uint.rs b/library/portable-simd/crates/core_simd/src/simd/num/uint.rs
index c955ee8fe8b..53dd97f501c 100644
--- a/library/portable-simd/crates/core_simd/src/simd/num/uint.rs
+++ b/library/portable-simd/crates/core_simd/src/simd/num/uint.rs
@@ -1,5 +1,5 @@
 use super::sealed::Sealed;
-use crate::simd::{intrinsics, LaneCount, Simd, SimdCast, SimdElement, SupportedLaneCount};
+use crate::simd::{LaneCount, Simd, SimdCast, SimdElement, SupportedLaneCount};
 
 /// Operations on SIMD vectors of unsigned integers.
 pub trait SimdUint: Copy + Sealed {
@@ -117,7 +117,7 @@ macro_rules! impl_trait {
             #[inline]
             fn cast<T: SimdCast>(self) -> Self::Cast<T> {
                 // Safety: supported types are guaranteed by SimdCast
-                unsafe { intrinsics::simd_as(self) }
+                unsafe { core::intrinsics::simd::simd_as(self) }
             }
 
             #[inline]
@@ -129,79 +129,79 @@ macro_rules! impl_trait {
             #[inline]
             fn saturating_add(self, second: Self) -> Self {
                 // Safety: `self` is a vector
-                unsafe { intrinsics::simd_saturating_add(self, second) }
+                unsafe { core::intrinsics::simd::simd_saturating_add(self, second) }
             }
 
             #[inline]
             fn saturating_sub(self, second: Self) -> Self {
                 // Safety: `self` is a vector
-                unsafe { intrinsics::simd_saturating_sub(self, second) }
+                unsafe { core::intrinsics::simd::simd_saturating_sub(self, second) }
             }
 
             #[inline]
             fn reduce_sum(self) -> Self::Scalar {
                 // Safety: `self` is an integer vector
-                unsafe { intrinsics::simd_reduce_add_ordered(self, 0) }
+                unsafe { core::intrinsics::simd::simd_reduce_add_ordered(self, 0) }
             }
 
             #[inline]
             fn reduce_product(self) -> Self::Scalar {
                 // Safety: `self` is an integer vector
-                unsafe { intrinsics::simd_reduce_mul_ordered(self, 1) }
+                unsafe { core::intrinsics::simd::simd_reduce_mul_ordered(self, 1) }
             }
 
             #[inline]
             fn reduce_max(self) -> Self::Scalar {
                 // Safety: `self` is an integer vector
-                unsafe { intrinsics::simd_reduce_max(self) }
+                unsafe { core::intrinsics::simd::simd_reduce_max(self) }
             }
 
             #[inline]
             fn reduce_min(self) -> Self::Scalar {
                 // Safety: `self` is an integer vector
-                unsafe { intrinsics::simd_reduce_min(self) }
+                unsafe { core::intrinsics::simd::simd_reduce_min(self) }
             }
 
             #[inline]
             fn reduce_and(self) -> Self::Scalar {
                 // Safety: `self` is an integer vector
-                unsafe { intrinsics::simd_reduce_and(self) }
+                unsafe { core::intrinsics::simd::simd_reduce_and(self) }
             }
 
             #[inline]
             fn reduce_or(self) -> Self::Scalar {
                 // Safety: `self` is an integer vector
-                unsafe { intrinsics::simd_reduce_or(self) }
+                unsafe { core::intrinsics::simd::simd_reduce_or(self) }
             }
 
             #[inline]
             fn reduce_xor(self) -> Self::Scalar {
                 // Safety: `self` is an integer vector
-                unsafe { intrinsics::simd_reduce_xor(self) }
+                unsafe { core::intrinsics::simd::simd_reduce_xor(self) }
             }
 
             #[inline]
             fn swap_bytes(self) -> Self {
                 // Safety: `self` is an integer vector
-                unsafe { intrinsics::simd_bswap(self) }
+                unsafe { core::intrinsics::simd::simd_bswap(self) }
             }
 
             #[inline]
             fn reverse_bits(self) -> Self {
                 // Safety: `self` is an integer vector
-                unsafe { intrinsics::simd_bitreverse(self) }
+                unsafe { core::intrinsics::simd::simd_bitreverse(self) }
             }
 
             #[inline]
             fn leading_zeros(self) -> Self {
                 // Safety: `self` is an integer vector
-                unsafe { intrinsics::simd_ctlz(self) }
+                unsafe { core::intrinsics::simd::simd_ctlz(self) }
             }
 
             #[inline]
             fn trailing_zeros(self) -> Self {
                 // Safety: `self` is an integer vector
-                unsafe { intrinsics::simd_cttz(self) }
+                unsafe { core::intrinsics::simd::simd_cttz(self) }
             }
 
             #[inline]
diff --git a/library/portable-simd/crates/core_simd/src/simd/ptr/const_ptr.rs b/library/portable-simd/crates/core_simd/src/simd/ptr/const_ptr.rs
index 97fe3fb600d..e217d1c8c87 100644
--- a/library/portable-simd/crates/core_simd/src/simd/ptr/const_ptr.rs
+++ b/library/portable-simd/crates/core_simd/src/simd/ptr/const_ptr.rs
@@ -1,7 +1,5 @@
 use super::sealed::Sealed;
-use crate::simd::{
-    cmp::SimdPartialEq, intrinsics, num::SimdUint, LaneCount, Mask, Simd, SupportedLaneCount,
-};
+use crate::simd::{cmp::SimdPartialEq, num::SimdUint, LaneCount, Mask, Simd, SupportedLaneCount};
 
 /// Operations on SIMD vectors of constant pointers.
 pub trait SimdConstPtr: Copy + Sealed {
@@ -103,13 +101,13 @@ where
         assert_eq!(size_of::<<U as Pointee>::Metadata>(), 0);
 
         // Safety: pointers can be cast
-        unsafe { intrinsics::simd_cast_ptr(self) }
+        unsafe { core::intrinsics::simd::simd_cast_ptr(self) }
     }
 
     #[inline]
     fn cast_mut(self) -> Self::MutPtr {
         // Safety: pointers can be cast
-        unsafe { intrinsics::simd_cast_ptr(self) }
+        unsafe { core::intrinsics::simd::simd_cast_ptr(self) }
     }
 
     #[inline]
@@ -135,19 +133,19 @@ where
     #[inline]
     fn expose_addr(self) -> Self::Usize {
         // Safety: `self` is a pointer vector
-        unsafe { intrinsics::simd_expose_addr(self) }
+        unsafe { core::intrinsics::simd::simd_expose_addr(self) }
     }
 
     #[inline]
     fn from_exposed_addr(addr: Self::Usize) -> Self {
         // Safety: `self` is a pointer vector
-        unsafe { intrinsics::simd_from_exposed_addr(addr) }
+        unsafe { core::intrinsics::simd::simd_from_exposed_addr(addr) }
     }
 
     #[inline]
     fn wrapping_offset(self, count: Self::Isize) -> Self {
         // Safety: simd_arith_offset takes a vector of pointers and a vector of offsets
-        unsafe { intrinsics::simd_arith_offset(self, count) }
+        unsafe { core::intrinsics::simd::simd_arith_offset(self, count) }
     }
 
     #[inline]
diff --git a/library/portable-simd/crates/core_simd/src/simd/ptr/mut_ptr.rs b/library/portable-simd/crates/core_simd/src/simd/ptr/mut_ptr.rs
index e35633d0433..5cb27af4fde 100644
--- a/library/portable-simd/crates/core_simd/src/simd/ptr/mut_ptr.rs
+++ b/library/portable-simd/crates/core_simd/src/simd/ptr/mut_ptr.rs
@@ -1,7 +1,5 @@
 use super::sealed::Sealed;
-use crate::simd::{
-    cmp::SimdPartialEq, intrinsics, num::SimdUint, LaneCount, Mask, Simd, SupportedLaneCount,
-};
+use crate::simd::{cmp::SimdPartialEq, num::SimdUint, LaneCount, Mask, Simd, SupportedLaneCount};
 
 /// Operations on SIMD vectors of mutable pointers.
 pub trait SimdMutPtr: Copy + Sealed {
@@ -100,13 +98,13 @@ where
         assert_eq!(size_of::<<U as Pointee>::Metadata>(), 0);
 
         // Safety: pointers can be cast
-        unsafe { intrinsics::simd_cast_ptr(self) }
+        unsafe { core::intrinsics::simd::simd_cast_ptr(self) }
     }
 
     #[inline]
     fn cast_const(self) -> Self::ConstPtr {
         // Safety: pointers can be cast
-        unsafe { intrinsics::simd_cast_ptr(self) }
+        unsafe { core::intrinsics::simd::simd_cast_ptr(self) }
     }
 
     #[inline]
@@ -132,19 +130,19 @@ where
     #[inline]
     fn expose_addr(self) -> Self::Usize {
         // Safety: `self` is a pointer vector
-        unsafe { intrinsics::simd_expose_addr(self) }
+        unsafe { core::intrinsics::simd::simd_expose_addr(self) }
     }
 
     #[inline]
     fn from_exposed_addr(addr: Self::Usize) -> Self {
         // Safety: `self` is a pointer vector
-        unsafe { intrinsics::simd_from_exposed_addr(addr) }
+        unsafe { core::intrinsics::simd::simd_from_exposed_addr(addr) }
     }
 
     #[inline]
     fn wrapping_offset(self, count: Self::Isize) -> Self {
         // Safety: simd_arith_offset takes a vector of pointers and a vector of offsets
-        unsafe { intrinsics::simd_arith_offset(self, count) }
+        unsafe { core::intrinsics::simd::simd_arith_offset(self, count) }
     }
 
     #[inline]
diff --git a/library/portable-simd/crates/core_simd/src/swizzle.rs b/library/portable-simd/crates/core_simd/src/swizzle.rs
index ec8548d5574..71110bb2820 100644
--- a/library/portable-simd/crates/core_simd/src/swizzle.rs
+++ b/library/portable-simd/crates/core_simd/src/swizzle.rs
@@ -1,4 +1,3 @@
-use crate::simd::intrinsics;
 use crate::simd::{LaneCount, Mask, MaskElement, Simd, SimdElement, SupportedLaneCount};
 
 /// Constructs a new SIMD vector by copying elements from selected elements in other vectors.
@@ -88,7 +87,7 @@ pub trait Swizzle<const N: usize> {
     {
         // Safety: `vector` is a vector, and the index is a const array of u32.
         unsafe {
-            intrinsics::simd_shuffle(
+            core::intrinsics::simd::simd_shuffle(
                 vector,
                 vector,
                 const {
@@ -124,7 +123,7 @@ pub trait Swizzle<const N: usize> {
     {
         // Safety: `first` and `second` are vectors, and the index is a const array of u32.
         unsafe {
-            intrinsics::simd_shuffle(
+            core::intrinsics::simd::simd_shuffle(
                 first,
                 second,
                 const {
diff --git a/library/portable-simd/crates/core_simd/src/swizzle_dyn.rs b/library/portable-simd/crates/core_simd/src/swizzle_dyn.rs
index dac013cc98d..ae9ff6894b0 100644
--- a/library/portable-simd/crates/core_simd/src/swizzle_dyn.rs
+++ b/library/portable-simd/crates/core_simd/src/swizzle_dyn.rs
@@ -44,7 +44,7 @@ where
                 ))]
                 8 => transize(vtbl1_u8, self, idxs),
                 #[cfg(target_feature = "ssse3")]
-                16 => transize(x86::_mm_shuffle_epi8, self, idxs),
+                16 => transize(x86::_mm_shuffle_epi8, self, zeroing_idxs(idxs)),
                 #[cfg(target_feature = "simd128")]
                 16 => transize(wasm::i8x16_swizzle, self, idxs),
                 #[cfg(all(
@@ -54,9 +54,9 @@ where
                 ))]
                 16 => transize(vqtbl1q_u8, self, idxs),
                 #[cfg(all(target_feature = "avx2", not(target_feature = "avx512vbmi")))]
-                32 => transize_raw(avx2_pshufb, self, idxs),
+                32 => transize(avx2_pshufb, self, idxs),
                 #[cfg(all(target_feature = "avx512vl", target_feature = "avx512vbmi"))]
-                32 => transize(x86::_mm256_permutexvar_epi8, self, idxs),
+                32 => transize(x86::_mm256_permutexvar_epi8, zeroing_idxs(idxs), self),
                 // Notable absence: avx512bw shuffle
                 // If avx512bw is available, odds of avx512vbmi are good
                 // FIXME: initial AVX512VBMI variant didn't actually pass muster
@@ -129,45 +129,25 @@ unsafe fn avx2_pshufb(bytes: Simd<u8, 32>, idxs: Simd<u8, 32>) -> Simd<u8, 32> {
 #[inline(always)]
 unsafe fn transize<T, const N: usize>(
     f: unsafe fn(T, T) -> T,
-    bytes: Simd<u8, N>,
-    idxs: Simd<u8, N>,
+    a: Simd<u8, N>,
+    b: Simd<u8, N>,
 ) -> Simd<u8, N>
 where
     LaneCount<N>: SupportedLaneCount,
 {
-    let idxs = zeroing_idxs(idxs);
     // SAFETY: Same obligation to use this function as to use mem::transmute_copy.
-    unsafe { mem::transmute_copy(&f(mem::transmute_copy(&bytes), mem::transmute_copy(&idxs))) }
+    unsafe { mem::transmute_copy(&f(mem::transmute_copy(&a), mem::transmute_copy(&b))) }
 }
 
-/// Make indices that yield 0 for this architecture
+/// Make indices that yield 0 for x86
+#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
+#[allow(unused)]
 #[inline(always)]
 fn zeroing_idxs<const N: usize>(idxs: Simd<u8, N>) -> Simd<u8, N>
 where
     LaneCount<N>: SupportedLaneCount,
 {
-    // On x86, make sure the top bit is set.
-    #[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
-    let idxs = {
-        use crate::simd::cmp::SimdPartialOrd;
-        idxs.simd_lt(Simd::splat(N as u8))
-            .select(idxs, Simd::splat(u8::MAX))
-    };
-    // Simply do nothing on most architectures.
-    idxs
-}
-
-/// As transize but no implicit call to `zeroing_idxs`.
-#[allow(dead_code)]
-#[inline(always)]
-unsafe fn transize_raw<T, const N: usize>(
-    f: unsafe fn(T, T) -> T,
-    bytes: Simd<u8, N>,
-    idxs: Simd<u8, N>,
-) -> Simd<u8, N>
-where
-    LaneCount<N>: SupportedLaneCount,
-{
-    // SAFETY: Same obligation to use this function as to use mem::transmute_copy.
-    unsafe { mem::transmute_copy(&f(mem::transmute_copy(&bytes), mem::transmute_copy(&idxs))) }
+    use crate::simd::cmp::SimdPartialOrd;
+    idxs.simd_lt(Simd::splat(N as u8))
+        .select(idxs, Simd::splat(u8::MAX))
 }
diff --git a/library/portable-simd/crates/core_simd/src/vector.rs b/library/portable-simd/crates/core_simd/src/vector.rs
index 105c06741c5..9e97a3161bb 100644
--- a/library/portable-simd/crates/core_simd/src/vector.rs
+++ b/library/portable-simd/crates/core_simd/src/vector.rs
@@ -1,6 +1,5 @@
 use crate::simd::{
     cmp::SimdPartialOrd,
-    intrinsics,
     ptr::{SimdConstPtr, SimdMutPtr},
     LaneCount, Mask, MaskElement, SupportedLaneCount, Swizzle,
 };
@@ -194,7 +193,7 @@ where
     /// With padding, `read_unaligned` will read past the end of an array of N elements.
     ///
     /// # Safety
-    /// Reading `ptr` must be safe, as if by `<*const [T; N]>::read_unaligned`.
+    /// Reading `ptr` must be safe, as if by `<*const [T; N]>::read`.
     #[inline]
     const unsafe fn load(ptr: *const [T; N]) -> Self {
         // There are potentially simpler ways to write this function, but this should result in
@@ -215,7 +214,7 @@ where
     /// See `load` as to why this function is necessary.
     ///
     /// # Safety
-    /// Writing to `ptr` must be safe, as if by `<*mut [T; N]>::write_unaligned`.
+    /// Writing to `ptr` must be safe, as if by `<*mut [T; N]>::write`.
     #[inline]
     const unsafe fn store(self, ptr: *mut [T; N]) {
         // There are potentially simpler ways to write this function, but this should result in
@@ -491,7 +490,7 @@ where
         or: Self,
     ) -> Self {
         // Safety: The caller is responsible for upholding all invariants
-        unsafe { intrinsics::simd_gather(or, source, enable.to_int()) }
+        unsafe { core::intrinsics::simd::simd_gather(or, source, enable.to_int()) }
     }
 
     /// Writes the values in a SIMD vector to potentially discontiguous indices in `slice`.
@@ -650,7 +649,7 @@ where
     #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
     pub unsafe fn scatter_select_ptr(self, dest: Simd<*mut T, N>, enable: Mask<isize, N>) {
         // Safety: The caller is responsible for upholding all invariants
-        unsafe { intrinsics::simd_scatter(self, dest, enable.to_int()) }
+        unsafe { core::intrinsics::simd::simd_scatter(self, dest, enable.to_int()) }
     }
 }
 
@@ -692,7 +691,8 @@ where
     fn eq(&self, other: &Self) -> bool {
         // Safety: All SIMD vectors are SimdPartialEq, and the comparison produces a valid mask.
         let mask = unsafe {
-            let tfvec: Simd<<T as SimdElement>::Mask, N> = intrinsics::simd_eq(*self, *other);
+            let tfvec: Simd<<T as SimdElement>::Mask, N> =
+                core::intrinsics::simd::simd_eq(*self, *other);
             Mask::from_int_unchecked(tfvec)
         };
 
@@ -705,7 +705,8 @@ where
     fn ne(&self, other: &Self) -> bool {
         // Safety: All SIMD vectors are SimdPartialEq, and the comparison produces a valid mask.
         let mask = unsafe {
-            let tfvec: Simd<<T as SimdElement>::Mask, N> = intrinsics::simd_ne(*self, *other);
+            let tfvec: Simd<<T as SimdElement>::Mask, N> =
+                core::intrinsics::simd::simd_ne(*self, *other);
             Mask::from_int_unchecked(tfvec)
         };
 
diff --git a/library/portable-simd/crates/core_simd/tests/masks.rs b/library/portable-simd/crates/core_simd/tests/masks.rs
index 00fc2a24e27..fc6a3476b7c 100644
--- a/library/portable-simd/crates/core_simd/tests/masks.rs
+++ b/library/portable-simd/crates/core_simd/tests/masks.rs
@@ -99,6 +99,19 @@ macro_rules! test_mask_api {
                 assert_eq!(Mask::<$type, 2>::from_bitmask(bitmask), mask);
             }
 
+            #[cfg(feature = "all_lane_counts")]
+            #[test]
+            fn roundtrip_bitmask_conversion_odd() {
+                let values = [
+                    true, false, true, false, true, true, false, false, false, true, true,
+                ];
+                let mask = Mask::<$type, 11>::from_array(values);
+                let bitmask = mask.to_bitmask();
+                assert_eq!(bitmask, 0b11000110101);
+                assert_eq!(Mask::<$type, 11>::from_bitmask(bitmask), mask);
+            }
+
+
             #[test]
             fn cast() {
                 fn cast_impl<T: core_simd::simd::MaskElement>()
@@ -134,6 +147,35 @@ macro_rules! test_mask_api {
                 assert_eq!(bitmask.resize::<2>(0).to_ne_bytes()[..2], [0b01001001, 0b10000011]);
                 assert_eq!(Mask::<$type, 16>::from_bitmask_vector(bitmask), mask);
             }
+
+            // rust-lang/portable-simd#379
+            #[test]
+            fn roundtrip_bitmask_vector_conversion_small() {
+                use core_simd::simd::ToBytes;
+                let values = [
+                    true, false, true, true
+                ];
+                let mask = Mask::<$type, 4>::from_array(values);
+                let bitmask = mask.to_bitmask_vector();
+                assert_eq!(bitmask.resize::<1>(0).to_ne_bytes()[0], 0b00001101);
+                assert_eq!(Mask::<$type, 4>::from_bitmask_vector(bitmask), mask);
+            }
+
+            /* FIXME doesn't work with non-powers-of-two, yet
+            // rust-lang/portable-simd#379
+            #[cfg(feature = "all_lane_counts")]
+            #[test]
+            fn roundtrip_bitmask_vector_conversion_odd() {
+                use core_simd::simd::ToBytes;
+                let values = [
+                    true, false, true, false, true, true, false, false, false, true, true,
+                ];
+                let mask = Mask::<$type, 11>::from_array(values);
+                let bitmask = mask.to_bitmask_vector();
+                assert_eq!(bitmask.resize::<2>(0).to_ne_bytes()[..2], [0b00110101, 0b00000110]);
+                assert_eq!(Mask::<$type, 11>::from_bitmask_vector(bitmask), mask);
+            }
+            */
         }
     }
 }
diff --git a/library/portable-simd/crates/std_float/src/lib.rs b/library/portable-simd/crates/std_float/src/lib.rs
index 1fef17242ca..4c547777fde 100644
--- a/library/portable-simd/crates/std_float/src/lib.rs
+++ b/library/portable-simd/crates/std_float/src/lib.rs
@@ -1,7 +1,7 @@
 #![cfg_attr(feature = "as_crate", no_std)] // We are std!
 #![cfg_attr(
     feature = "as_crate",
-    feature(platform_intrinsics),
+    feature(core_intrinsics),
     feature(portable_simd),
     allow(internal_features)
 )]
@@ -10,6 +10,8 @@ use core::simd;
 #[cfg(feature = "as_crate")]
 use core_simd::simd;
 
+use core::intrinsics::simd as intrinsics;
+
 use simd::{LaneCount, Simd, SupportedLaneCount};
 
 #[cfg(feature = "as_crate")]
@@ -22,28 +24,6 @@ use experimental as sealed;
 
 use crate::sealed::Sealed;
 
-// "platform intrinsics" are essentially "codegen intrinsics"
-// each of these may be scalarized and lowered to a libm call
-extern "platform-intrinsic" {
-    // ceil
-    fn simd_ceil<T>(x: T) -> T;
-
-    // floor
-    fn simd_floor<T>(x: T) -> T;
-
-    // round
-    fn simd_round<T>(x: T) -> T;
-
-    // trunc
-    fn simd_trunc<T>(x: T) -> T;
-
-    // fsqrt
-    fn simd_fsqrt<T>(x: T) -> T;
-
-    // fma
-    fn simd_fma<T>(x: T, y: T, z: T) -> T;
-}
-
 /// This trait provides a possibly-temporary implementation of float functions
 /// that may, in the absence of hardware support, canonicalize to calling an
 /// operating system's `math.h` dynamically-loaded library (also known as a
@@ -74,7 +54,7 @@ pub trait StdFloat: Sealed + Sized {
     #[inline]
     #[must_use = "method returns a new vector and does not mutate the original value"]
     fn mul_add(self, a: Self, b: Self) -> Self {
-        unsafe { simd_fma(self, a, b) }
+        unsafe { intrinsics::simd_fma(self, a, b) }
     }
 
     /// Produces a vector where every lane has the square root value
@@ -82,35 +62,35 @@ pub trait StdFloat: Sealed + Sized {
     #[inline]
     #[must_use = "method returns a new vector and does not mutate the original value"]
     fn sqrt(self) -> Self {
-        unsafe { simd_fsqrt(self) }
+        unsafe { intrinsics::simd_fsqrt(self) }
     }
 
     /// Returns the smallest integer greater than or equal to each lane.
     #[must_use = "method returns a new vector and does not mutate the original value"]
     #[inline]
     fn ceil(self) -> Self {
-        unsafe { simd_ceil(self) }
+        unsafe { intrinsics::simd_ceil(self) }
     }
 
     /// Returns the largest integer value less than or equal to each lane.
     #[must_use = "method returns a new vector and does not mutate the original value"]
     #[inline]
     fn floor(self) -> Self {
-        unsafe { simd_floor(self) }
+        unsafe { intrinsics::simd_floor(self) }
     }
 
     /// Rounds to the nearest integer value. Ties round toward zero.
     #[must_use = "method returns a new vector and does not mutate the original value"]
     #[inline]
     fn round(self) -> Self {
-        unsafe { simd_round(self) }
+        unsafe { intrinsics::simd_round(self) }
     }
 
     /// Returns the floating point's integer value, with its fractional part removed.
     #[must_use = "method returns a new vector and does not mutate the original value"]
     #[inline]
     fn trunc(self) -> Self {
-        unsafe { simd_trunc(self) }
+        unsafe { intrinsics::simd_trunc(self) }
     }
 
     /// Returns the floating point's fractional value, with its integer part removed.
diff --git a/library/portable-simd/crates/test_helpers/src/lib.rs b/library/portable-simd/crates/test_helpers/src/lib.rs
index b80c745aaf2..51b860a8635 100644
--- a/library/portable-simd/crates/test_helpers/src/lib.rs
+++ b/library/portable-simd/crates/test_helpers/src/lib.rs
@@ -1,4 +1,8 @@
-#![feature(stdsimd, powerpc_target_feature)]
+#![feature(powerpc_target_feature)]
+#![cfg_attr(
+    any(target_arch = "powerpc", target_arch = "powerpc64"),
+    feature(stdarch_powerpc)
+)]
 
 pub mod array;
 
diff --git a/library/std/src/env.rs b/library/std/src/env.rs
index 30ac0512348..5bd20ebe208 100644
--- a/library/std/src/env.rs
+++ b/library/std/src/env.rs
@@ -78,7 +78,7 @@ pub fn current_dir() -> io::Result<PathBuf> {
 /// assert!(env::set_current_dir(&root).is_ok());
 /// println!("Successfully changed working directory to {}!", root.display());
 /// ```
-#[doc(alias = "chdir")]
+#[doc(alias = "chdir", alias = "SetCurrentDirectory", alias = "SetCurrentDirectoryW")]
 #[stable(feature = "env", since = "1.0.0")]
 pub fn set_current_dir<P: AsRef<Path>>(path: P) -> io::Result<()> {
     os_imp::chdir(path.as_ref())
@@ -655,6 +655,7 @@ pub fn home_dir() -> Option<PathBuf> {
 /// }
 /// ```
 #[must_use]
+#[doc(alias = "GetTempPath", alias = "GetTempPath2")]
 #[stable(feature = "env", since = "1.0.0")]
 pub fn temp_dir() -> PathBuf {
     os_imp::temp_dir()
diff --git a/library/std/src/ffi/mod.rs b/library/std/src/ffi/mod.rs
index 97e78d17786..818571ddaaa 100644
--- a/library/std/src/ffi/mod.rs
+++ b/library/std/src/ffi/mod.rs
@@ -127,6 +127,11 @@
 //! trait, which provides a [`from_wide`] method to convert a native Windows
 //! string (without the terminating nul character) to an [`OsString`].
 //!
+//! ## Other platforms
+//!
+//! Many other platforms provide their own extension traits in a
+//! `std::os::*::ffi` module.
+//!
 //! ## On all platforms
 //!
 //! On all platforms, [`OsStr`] consists of a sequence of bytes that is encoded as a superset of
@@ -135,6 +140,8 @@
 //! For limited, inexpensive conversions from and to bytes, see [`OsStr::as_encoded_bytes`] and
 //! [`OsStr::from_encoded_bytes_unchecked`].
 //!
+//! For basic string processing, see [`OsStr::slice_encoded_bytes`].
+//!
 //! [Unicode scalar value]: https://www.unicode.org/glossary/#unicode_scalar_value
 //! [Unicode code point]: https://www.unicode.org/glossary/#code_point
 //! [`env::set_var()`]: crate::env::set_var "env::set_var"
diff --git a/library/std/src/ffi/os_str.rs b/library/std/src/ffi/os_str.rs
index 81973182148..28747ad8f34 100644
--- a/library/std/src/ffi/os_str.rs
+++ b/library/std/src/ffi/os_str.rs
@@ -9,7 +9,7 @@ use crate::hash::{Hash, Hasher};
 use crate::ops::{self, Range};
 use crate::rc::Rc;
 use crate::slice;
-use crate::str::{from_utf8 as str_from_utf8, FromStr};
+use crate::str::FromStr;
 use crate::sync::Arc;
 
 use crate::sys::os_str::{Buf, Slice};
@@ -997,42 +997,15 @@ impl OsStr {
     /// ```
     #[unstable(feature = "os_str_slice", issue = "118485")]
     pub fn slice_encoded_bytes<R: ops::RangeBounds<usize>>(&self, range: R) -> &Self {
-        #[track_caller]
-        fn check_valid_boundary(bytes: &[u8], index: usize) {
-            if index == 0 || index == bytes.len() {
-                return;
-            }
-
-            // Fast path
-            if bytes[index - 1].is_ascii() || bytes[index].is_ascii() {
-                return;
-            }
-
-            let (before, after) = bytes.split_at(index);
-
-            // UTF-8 takes at most 4 bytes per codepoint, so we don't
-            // need to check more than that.
-            let after = after.get(..4).unwrap_or(after);
-            match str_from_utf8(after) {
-                Ok(_) => return,
-                Err(err) if err.valid_up_to() != 0 => return,
-                Err(_) => (),
-            }
-
-            for len in 2..=4.min(index) {
-                let before = &before[index - len..];
-                if str_from_utf8(before).is_ok() {
-                    return;
-                }
-            }
-
-            panic!("byte index {index} is not an OsStr boundary");
-        }
-
         let encoded_bytes = self.as_encoded_bytes();
         let Range { start, end } = slice::range(range, ..encoded_bytes.len());
-        check_valid_boundary(encoded_bytes, start);
-        check_valid_boundary(encoded_bytes, end);
+
+        // `check_public_boundary` should panic if the index does not lie on an
+        // `OsStr` boundary as described above. It's possible to do this in an
+        // encoding-agnostic way, but details of the internal encoding might
+        // permit a more efficient implementation.
+        self.inner.check_public_boundary(start);
+        self.inner.check_public_boundary(end);
 
         // SAFETY: `slice::range` ensures that `start` and `end` are valid
         let slice = unsafe { encoded_bytes.get_unchecked(start..end) };
diff --git a/library/std/src/ffi/os_str/tests.rs b/library/std/src/ffi/os_str/tests.rs
index 60cde376d32..b020e05eaab 100644
--- a/library/std/src/ffi/os_str/tests.rs
+++ b/library/std/src/ffi/os_str/tests.rs
@@ -194,15 +194,65 @@ fn slice_encoded_bytes() {
 }
 
 #[test]
-#[should_panic(expected = "byte index 2 is not an OsStr boundary")]
+#[should_panic]
+fn slice_out_of_bounds() {
+    let crab = OsStr::new("🦀");
+    let _ = crab.slice_encoded_bytes(..5);
+}
+
+#[test]
+#[should_panic]
 fn slice_mid_char() {
     let crab = OsStr::new("🦀");
     let _ = crab.slice_encoded_bytes(..2);
 }
 
+#[cfg(unix)]
+#[test]
+#[should_panic(expected = "byte index 1 is not an OsStr boundary")]
+fn slice_invalid_data() {
+    use crate::os::unix::ffi::OsStrExt;
+
+    let os_string = OsStr::from_bytes(b"\xFF\xFF");
+    let _ = os_string.slice_encoded_bytes(1..);
+}
+
+#[cfg(unix)]
+#[test]
+#[should_panic(expected = "byte index 1 is not an OsStr boundary")]
+fn slice_partial_utf8() {
+    use crate::os::unix::ffi::{OsStrExt, OsStringExt};
+
+    let part_crab = OsStr::from_bytes(&"🦀".as_bytes()[..3]);
+    let mut os_string = OsString::from_vec(vec![0xFF]);
+    os_string.push(part_crab);
+    let _ = os_string.slice_encoded_bytes(1..);
+}
+
+#[cfg(unix)]
+#[test]
+fn slice_invalid_edge() {
+    use crate::os::unix::ffi::{OsStrExt, OsStringExt};
+
+    let os_string = OsStr::from_bytes(b"a\xFFa");
+    assert_eq!(os_string.slice_encoded_bytes(..1), "a");
+    assert_eq!(os_string.slice_encoded_bytes(1..), OsStr::from_bytes(b"\xFFa"));
+    assert_eq!(os_string.slice_encoded_bytes(..2), OsStr::from_bytes(b"a\xFF"));
+    assert_eq!(os_string.slice_encoded_bytes(2..), "a");
+
+    let os_string = OsStr::from_bytes(&"abc🦀".as_bytes()[..6]);
+    assert_eq!(os_string.slice_encoded_bytes(..3), "abc");
+    assert_eq!(os_string.slice_encoded_bytes(3..), OsStr::from_bytes(b"\xF0\x9F\xA6"));
+
+    let mut os_string = OsString::from_vec(vec![0xFF]);
+    os_string.push("🦀");
+    assert_eq!(os_string.slice_encoded_bytes(..1), OsStr::from_bytes(b"\xFF"));
+    assert_eq!(os_string.slice_encoded_bytes(1..), "🦀");
+}
+
 #[cfg(windows)]
 #[test]
-#[should_panic(expected = "byte index 3 is not an OsStr boundary")]
+#[should_panic(expected = "byte index 3 lies between surrogate codepoints")]
 fn slice_between_surrogates() {
     use crate::os::windows::ffi::OsStringExt;
 
@@ -216,10 +266,14 @@ fn slice_between_surrogates() {
 fn slice_surrogate_edge() {
     use crate::os::windows::ffi::OsStringExt;
 
-    let os_string = OsString::from_wide(&[0xD800]);
-    let mut with_crab = os_string.clone();
-    with_crab.push("🦀");
+    let surrogate = OsString::from_wide(&[0xD800]);
+    let mut pre_crab = surrogate.clone();
+    pre_crab.push("🦀");
+    assert_eq!(pre_crab.slice_encoded_bytes(..3), surrogate);
+    assert_eq!(pre_crab.slice_encoded_bytes(3..), "🦀");
 
-    assert_eq!(with_crab.slice_encoded_bytes(..3), os_string);
-    assert_eq!(with_crab.slice_encoded_bytes(3..), "🦀");
+    let mut post_crab = OsString::from("🦀");
+    post_crab.push(&surrogate);
+    assert_eq!(post_crab.slice_encoded_bytes(..4), "🦀");
+    assert_eq!(post_crab.slice_encoded_bytes(4..), surrogate);
 }
diff --git a/library/std/src/fs.rs b/library/std/src/fs.rs
index db8de1b1e3d..6b1dd1b5af4 100644
--- a/library/std/src/fs.rs
+++ b/library/std/src/fs.rs
@@ -656,6 +656,7 @@ impl File {
     ///
     /// Note that this method alters the permissions of the underlying file,
     /// even though it takes `&self` rather than `&mut self`.
+    #[doc(alias = "fchmod", alias = "SetFileInformationByHandle")]
     #[stable(feature = "set_permissions_atomic", since = "1.16.0")]
     pub fn set_permissions(&self, perm: Permissions) -> io::Result<()> {
         self.inner.set_permissions(perm.0)
@@ -1314,6 +1315,7 @@ impl Metadata {
     ///     Ok(())
     /// }
     /// ```
+    #[doc(alias = "mtime", alias = "ftLastWriteTime")]
     #[stable(feature = "fs_time", since = "1.10.0")]
     pub fn modified(&self) -> io::Result<SystemTime> {
         self.0.modified().map(FromInner::from_inner)
@@ -1349,6 +1351,7 @@ impl Metadata {
     ///     Ok(())
     /// }
     /// ```
+    #[doc(alias = "atime", alias = "ftLastAccessTime")]
     #[stable(feature = "fs_time", since = "1.10.0")]
     pub fn accessed(&self) -> io::Result<SystemTime> {
         self.0.accessed().map(FromInner::from_inner)
@@ -1381,6 +1384,7 @@ impl Metadata {
     ///     Ok(())
     /// }
     /// ```
+    #[doc(alias = "btime", alias = "birthtime", alias = "ftCreationTime")]
     #[stable(feature = "fs_time", since = "1.10.0")]
     pub fn created(&self) -> io::Result<SystemTime> {
         self.0.created().map(FromInner::from_inner)
@@ -1879,6 +1883,7 @@ impl AsInner<fs_imp::DirEntry> for DirEntry {
 ///     Ok(())
 /// }
 /// ```
+#[doc(alias = "rm", alias = "unlink", alias = "DeleteFile")]
 #[stable(feature = "rust1", since = "1.0.0")]
 pub fn remove_file<P: AsRef<Path>>(path: P) -> io::Result<()> {
     fs_imp::unlink(path.as_ref())
@@ -1917,6 +1922,7 @@ pub fn remove_file<P: AsRef<Path>>(path: P) -> io::Result<()> {
 ///     Ok(())
 /// }
 /// ```
+#[doc(alias = "stat")]
 #[stable(feature = "rust1", since = "1.0.0")]
 pub fn metadata<P: AsRef<Path>>(path: P) -> io::Result<Metadata> {
     fs_imp::stat(path.as_ref()).map(Metadata)
@@ -1951,6 +1957,7 @@ pub fn metadata<P: AsRef<Path>>(path: P) -> io::Result<Metadata> {
 ///     Ok(())
 /// }
 /// ```
+#[doc(alias = "lstat")]
 #[stable(feature = "symlink_metadata", since = "1.1.0")]
 pub fn symlink_metadata<P: AsRef<Path>>(path: P) -> io::Result<Metadata> {
     fs_imp::lstat(path.as_ref()).map(Metadata)
@@ -1994,6 +2001,7 @@ pub fn symlink_metadata<P: AsRef<Path>>(path: P) -> io::Result<Metadata> {
 ///     Ok(())
 /// }
 /// ```
+#[doc(alias = "mv", alias = "MoveFile", alias = "MoveFileEx")]
 #[stable(feature = "rust1", since = "1.0.0")]
 pub fn rename<P: AsRef<Path>, Q: AsRef<Path>>(from: P, to: Q) -> io::Result<()> {
     fs_imp::rename(from.as_ref(), to.as_ref())
@@ -2052,6 +2060,9 @@ pub fn rename<P: AsRef<Path>, Q: AsRef<Path>>(from: P, to: Q) -> io::Result<()>
 ///     Ok(())
 /// }
 /// ```
+#[doc(alias = "cp")]
+#[doc(alias = "CopyFile", alias = "CopyFileEx")]
+#[doc(alias = "fclonefileat", alias = "fcopyfile")]
 #[stable(feature = "rust1", since = "1.0.0")]
 pub fn copy<P: AsRef<Path>, Q: AsRef<Path>>(from: P, to: Q) -> io::Result<u64> {
     fs_imp::copy(from.as_ref(), to.as_ref())
@@ -2096,6 +2107,7 @@ pub fn copy<P: AsRef<Path>, Q: AsRef<Path>>(from: P, to: Q) -> io::Result<u64> {
 ///     Ok(())
 /// }
 /// ```
+#[doc(alias = "CreateHardLink", alias = "linkat")]
 #[stable(feature = "rust1", since = "1.0.0")]
 pub fn hard_link<P: AsRef<Path>, Q: AsRef<Path>>(original: P, link: Q) -> io::Result<()> {
     fs_imp::link(original.as_ref(), link.as_ref())
@@ -2245,7 +2257,7 @@ pub fn canonicalize<P: AsRef<Path>>(path: P) -> io::Result<PathBuf> {
 ///     Ok(())
 /// }
 /// ```
-#[doc(alias = "mkdir")]
+#[doc(alias = "mkdir", alias = "CreateDirectory")]
 #[stable(feature = "rust1", since = "1.0.0")]
 #[cfg_attr(not(test), rustc_diagnostic_item = "fs_create_dir")]
 pub fn create_dir<P: AsRef<Path>>(path: P) -> io::Result<()> {
@@ -2326,7 +2338,7 @@ pub fn create_dir_all<P: AsRef<Path>>(path: P) -> io::Result<()> {
 ///     Ok(())
 /// }
 /// ```
-#[doc(alias = "rmdir")]
+#[doc(alias = "rmdir", alias = "RemoveDirectory")]
 #[stable(feature = "rust1", since = "1.0.0")]
 pub fn remove_dir<P: AsRef<Path>>(path: P) -> io::Result<()> {
     fs_imp::rmdir(path.as_ref())
@@ -2449,6 +2461,7 @@ pub fn remove_dir_all<P: AsRef<Path>>(path: P) -> io::Result<()> {
 ///     Ok(())
 /// }
 /// ```
+#[doc(alias = "ls", alias = "opendir", alias = "FindFirstFile", alias = "FindNextFile")]
 #[stable(feature = "rust1", since = "1.0.0")]
 pub fn read_dir<P: AsRef<Path>>(path: P) -> io::Result<ReadDir> {
     fs_imp::readdir(path.as_ref()).map(ReadDir)
@@ -2484,6 +2497,7 @@ pub fn read_dir<P: AsRef<Path>>(path: P) -> io::Result<ReadDir> {
 ///     Ok(())
 /// }
 /// ```
+#[doc(alias = "chmod", alias = "SetFileAttributes")]
 #[stable(feature = "set_permissions", since = "1.1.0")]
 pub fn set_permissions<P: AsRef<Path>>(path: P, perm: Permissions) -> io::Result<()> {
     fs_imp::set_perm(path.as_ref(), perm.0)
diff --git a/library/std/src/os/unix/fs.rs b/library/std/src/os/unix/fs.rs
index e995d5133f8..058e9b90cc7 100644
--- a/library/std/src/os/unix/fs.rs
+++ b/library/std/src/os/unix/fs.rs
@@ -397,7 +397,6 @@ pub trait OpenOptionsExt {
     ///
     /// ```no_run
     /// # #![feature(rustc_private)]
-    /// use libc;
     /// use std::fs::OpenOptions;
     /// use std::os::unix::fs::OpenOptionsExt;
     ///
diff --git a/library/std/src/os/wasi/fs.rs b/library/std/src/os/wasi/fs.rs
index 3da8c835511..4525c3aa914 100644
--- a/library/std/src/os/wasi/fs.rs
+++ b/library/std/src/os/wasi/fs.rs
@@ -173,51 +173,61 @@ pub trait FileExt {
     ///
     /// This corresponds to the `fd_tell` syscall and is similar to
     /// `seek` where you offset 0 bytes from the current position.
+    #[doc(alias = "fd_tell")]
     fn tell(&self) -> io::Result<u64>;
 
     /// Adjust the flags associated with this file.
     ///
     /// This corresponds to the `fd_fdstat_set_flags` syscall.
+    #[doc(alias = "fd_fdstat_set_flags")]
     fn fdstat_set_flags(&self, flags: u16) -> io::Result<()>;
 
     /// Adjust the rights associated with this file.
     ///
     /// This corresponds to the `fd_fdstat_set_rights` syscall.
+    #[doc(alias = "fd_fdstat_set_rights")]
     fn fdstat_set_rights(&self, rights: u64, inheriting: u64) -> io::Result<()>;
 
     /// Provide file advisory information on a file descriptor.
     ///
     /// This corresponds to the `fd_advise` syscall.
+    #[doc(alias = "fd_advise")]
     fn advise(&self, offset: u64, len: u64, advice: u8) -> io::Result<()>;
 
     /// Force the allocation of space in a file.
     ///
     /// This corresponds to the `fd_allocate` syscall.
+    #[doc(alias = "fd_allocate")]
     fn allocate(&self, offset: u64, len: u64) -> io::Result<()>;
 
     /// Create a directory.
     ///
     /// This corresponds to the `path_create_directory` syscall.
+    #[doc(alias = "path_create_directory")]
     fn create_directory<P: AsRef<Path>>(&self, dir: P) -> io::Result<()>;
 
     /// Read the contents of a symbolic link.
     ///
     /// This corresponds to the `path_readlink` syscall.
+    #[doc(alias = "path_readlink")]
     fn read_link<P: AsRef<Path>>(&self, path: P) -> io::Result<PathBuf>;
 
     /// Return the attributes of a file or directory.
     ///
     /// This corresponds to the `path_filestat_get` syscall.
+    #[doc(alias = "path_filestat_get")]
     fn metadata_at<P: AsRef<Path>>(&self, lookup_flags: u32, path: P) -> io::Result<Metadata>;
 
     /// Unlink a file.
     ///
     /// This corresponds to the `path_unlink_file` syscall.
+    #[doc(alias = "path_unlink_file")]
     fn remove_file<P: AsRef<Path>>(&self, path: P) -> io::Result<()>;
 
     /// Remove a directory.
     ///
     /// This corresponds to the `path_remove_directory` syscall.
+    #[doc(alias = "path_remove_directory")]
     fn remove_directory<P: AsRef<Path>>(&self, path: P) -> io::Result<()>;
 }
 
@@ -359,6 +369,7 @@ pub trait OpenOptionsExt {
     /// Open a file or directory.
     ///
     /// This corresponds to the `path_open` syscall.
+    #[doc(alias = "path_open")]
     fn open_at<P: AsRef<Path>>(&self, file: &File, path: P) -> io::Result<File>;
 }
 
@@ -500,6 +511,7 @@ impl DirEntryExt for fs::DirEntry {
 /// Create a hard link.
 ///
 /// This corresponds to the `path_link` syscall.
+#[doc(alias = "path_link")]
 pub fn link<P: AsRef<Path>, U: AsRef<Path>>(
     old_fd: &File,
     old_flags: u32,
@@ -518,6 +530,7 @@ pub fn link<P: AsRef<Path>, U: AsRef<Path>>(
 /// Rename a file or directory.
 ///
 /// This corresponds to the `path_rename` syscall.
+#[doc(alias = "path_rename")]
 pub fn rename<P: AsRef<Path>, U: AsRef<Path>>(
     old_fd: &File,
     old_path: P,
@@ -534,6 +547,7 @@ pub fn rename<P: AsRef<Path>, U: AsRef<Path>>(
 /// Create a symbolic link.
 ///
 /// This corresponds to the `path_symlink` syscall.
+#[doc(alias = "path_symlink")]
 pub fn symlink<P: AsRef<Path>, U: AsRef<Path>>(
     old_path: P,
     fd: &File,
diff --git a/library/std/src/panicking.rs b/library/std/src/panicking.rs
index 8294160b72c..c8306c1b597 100644
--- a/library/std/src/panicking.rs
+++ b/library/std/src/panicking.rs
@@ -337,8 +337,9 @@ pub mod panic_count {
 #[doc(hidden)]
 #[cfg(not(feature = "panic_immediate_abort"))]
 #[unstable(feature = "update_panic_count", issue = "none")]
-// FIXME: Use `SyncUnsafeCell` instead of allowing `static_mut_ref` lint
-#[allow(static_mut_ref)]
+// FIXME: Use `SyncUnsafeCell` instead of allowing `static_mut_refs` lint
+#[cfg_attr(bootstrap, allow(static_mut_ref))]
+#[cfg_attr(not(bootstrap), allow(static_mut_refs))]
 pub mod panic_count {
     use crate::cell::Cell;
     use crate::sync::atomic::{AtomicUsize, Ordering};
diff --git a/library/std/src/sys/os_str/bytes.rs b/library/std/src/sys/os_str/bytes.rs
index 3a75ce9ebb7..4ca3f1cd185 100644
--- a/library/std/src/sys/os_str/bytes.rs
+++ b/library/std/src/sys/os_str/bytes.rs
@@ -211,6 +211,49 @@ impl Slice {
         unsafe { mem::transmute(s) }
     }
 
+    #[track_caller]
+    #[inline]
+    pub fn check_public_boundary(&self, index: usize) {
+        if index == 0 || index == self.inner.len() {
+            return;
+        }
+        if index < self.inner.len()
+            && (self.inner[index - 1].is_ascii() || self.inner[index].is_ascii())
+        {
+            return;
+        }
+
+        slow_path(&self.inner, index);
+
+        /// We're betting that typical splits will involve an ASCII character.
+        ///
+        /// Putting the expensive checks in a separate function generates notably
+        /// better assembly.
+        #[track_caller]
+        #[inline(never)]
+        fn slow_path(bytes: &[u8], index: usize) {
+            let (before, after) = bytes.split_at(index);
+
+            // UTF-8 takes at most 4 bytes per codepoint, so we don't
+            // need to check more than that.
+            let after = after.get(..4).unwrap_or(after);
+            match str::from_utf8(after) {
+                Ok(_) => return,
+                Err(err) if err.valid_up_to() != 0 => return,
+                Err(_) => (),
+            }
+
+            for len in 2..=4.min(index) {
+                let before = &before[index - len..];
+                if str::from_utf8(before).is_ok() {
+                    return;
+                }
+            }
+
+            panic!("byte index {index} is not an OsStr boundary");
+        }
+    }
+
     #[inline]
     pub fn from_str(s: &str) -> &Slice {
         unsafe { Slice::from_encoded_bytes_unchecked(s.as_bytes()) }
diff --git a/library/std/src/sys/os_str/wtf8.rs b/library/std/src/sys/os_str/wtf8.rs
index 237854fac4e..352bd735903 100644
--- a/library/std/src/sys/os_str/wtf8.rs
+++ b/library/std/src/sys/os_str/wtf8.rs
@@ -6,7 +6,7 @@ use crate::fmt;
 use crate::mem;
 use crate::rc::Rc;
 use crate::sync::Arc;
-use crate::sys_common::wtf8::{Wtf8, Wtf8Buf};
+use crate::sys_common::wtf8::{check_utf8_boundary, Wtf8, Wtf8Buf};
 use crate::sys_common::{AsInner, FromInner, IntoInner};
 
 #[derive(Clone, Hash)]
@@ -171,6 +171,11 @@ impl Slice {
         mem::transmute(Wtf8::from_bytes_unchecked(s))
     }
 
+    #[track_caller]
+    pub fn check_public_boundary(&self, index: usize) {
+        check_utf8_boundary(&self.inner, index);
+    }
+
     #[inline]
     pub fn from_str(s: &str) -> &Slice {
         unsafe { mem::transmute(Wtf8::from_str(s)) }
diff --git a/library/std/src/sys/pal/common/small_c_string.rs b/library/std/src/sys/pal/common/small_c_string.rs
index af9b18e372d..37812fc0659 100644
--- a/library/std/src/sys/pal/common/small_c_string.rs
+++ b/library/std/src/sys/pal/common/small_c_string.rs
@@ -15,22 +15,28 @@ const NUL_ERR: io::Error =
     io::const_io_error!(io::ErrorKind::InvalidInput, "file name contained an unexpected NUL byte");
 
 #[inline]
-pub fn run_path_with_cstr<T, F>(path: &Path, f: F) -> io::Result<T>
-where
-    F: FnOnce(&CStr) -> io::Result<T>,
-{
+pub fn run_path_with_cstr<T>(path: &Path, f: &dyn Fn(&CStr) -> io::Result<T>) -> io::Result<T> {
     run_with_cstr(path.as_os_str().as_encoded_bytes(), f)
 }
 
 #[inline]
-pub fn run_with_cstr<T, F>(bytes: &[u8], f: F) -> io::Result<T>
-where
-    F: FnOnce(&CStr) -> io::Result<T>,
-{
+pub fn run_with_cstr<T>(bytes: &[u8], f: &dyn Fn(&CStr) -> io::Result<T>) -> io::Result<T> {
+    // Dispatch and dyn erase the closure type to prevent mono bloat.
+    // See https://github.com/rust-lang/rust/pull/121101.
     if bytes.len() >= MAX_STACK_ALLOCATION {
-        return run_with_cstr_allocating(bytes, f);
+        run_with_cstr_allocating(bytes, f)
+    } else {
+        unsafe { run_with_cstr_stack(bytes, f) }
     }
+}
 
+/// # Safety
+///
+/// `bytes` must have a length less than `MAX_STACK_ALLOCATION`.
+unsafe fn run_with_cstr_stack<T>(
+    bytes: &[u8],
+    f: &dyn Fn(&CStr) -> io::Result<T>,
+) -> io::Result<T> {
     let mut buf = MaybeUninit::<[u8; MAX_STACK_ALLOCATION]>::uninit();
     let buf_ptr = buf.as_mut_ptr() as *mut u8;
 
@@ -47,10 +53,7 @@ where
 
 #[cold]
 #[inline(never)]
-fn run_with_cstr_allocating<T, F>(bytes: &[u8], f: F) -> io::Result<T>
-where
-    F: FnOnce(&CStr) -> io::Result<T>,
-{
+fn run_with_cstr_allocating<T>(bytes: &[u8], f: &dyn Fn(&CStr) -> io::Result<T>) -> io::Result<T> {
     match CString::new(bytes) {
         Ok(s) => f(&s),
         Err(_) => Err(NUL_ERR),
diff --git a/library/std/src/sys/pal/common/tests.rs b/library/std/src/sys/pal/common/tests.rs
index 32dc18ee1cf..e72d02203da 100644
--- a/library/std/src/sys/pal/common/tests.rs
+++ b/library/std/src/sys/pal/common/tests.rs
@@ -7,7 +7,7 @@ use core::iter::repeat;
 #[test]
 fn stack_allocation_works() {
     let path = Path::new("abc");
-    let result = run_path_with_cstr(path, |p| {
+    let result = run_path_with_cstr(path, &|p| {
         assert_eq!(p, &*CString::new(path.as_os_str().as_encoded_bytes()).unwrap());
         Ok(42)
     });
@@ -17,14 +17,14 @@ fn stack_allocation_works() {
 #[test]
 fn stack_allocation_fails() {
     let path = Path::new("ab\0");
-    assert!(run_path_with_cstr::<(), _>(path, |_| unreachable!()).is_err());
+    assert!(run_path_with_cstr::<()>(path, &|_| unreachable!()).is_err());
 }
 
 #[test]
 fn heap_allocation_works() {
     let path = repeat("a").take(384).collect::<String>();
     let path = Path::new(&path);
-    let result = run_path_with_cstr(path, |p| {
+    let result = run_path_with_cstr(path, &|p| {
         assert_eq!(p, &*CString::new(path.as_os_str().as_encoded_bytes()).unwrap());
         Ok(42)
     });
@@ -36,7 +36,7 @@ fn heap_allocation_fails() {
     let mut path = repeat("a").take(384).collect::<String>();
     path.push('\0');
     let path = Path::new(&path);
-    assert!(run_path_with_cstr::<(), _>(path, |_| unreachable!()).is_err());
+    assert!(run_path_with_cstr::<()>(path, &|_| unreachable!()).is_err());
 }
 
 #[bench]
@@ -44,7 +44,7 @@ fn bench_stack_path_alloc(b: &mut test::Bencher) {
     let path = repeat("a").take(383).collect::<String>();
     let p = Path::new(&path);
     b.iter(|| {
-        run_path_with_cstr(p, |cstr| {
+        run_path_with_cstr(p, &|cstr| {
             black_box(cstr);
             Ok(())
         })
@@ -57,7 +57,7 @@ fn bench_heap_path_alloc(b: &mut test::Bencher) {
     let path = repeat("a").take(384).collect::<String>();
     let p = Path::new(&path);
     b.iter(|| {
-        run_path_with_cstr(p, |cstr| {
+        run_path_with_cstr(p, &|cstr| {
             black_box(cstr);
             Ok(())
         })
diff --git a/library/std/src/sys/pal/common/thread_local/fast_local.rs b/library/std/src/sys/pal/common/thread_local/fast_local.rs
index 04c0dd6f750..646dcd7f3a3 100644
--- a/library/std/src/sys/pal/common/thread_local/fast_local.rs
+++ b/library/std/src/sys/pal/common/thread_local/fast_local.rs
@@ -13,8 +13,9 @@ pub macro thread_local_inner {
     (@key $t:ty, const $init:expr) => {{
         #[inline]
         #[deny(unsafe_op_in_unsafe_fn)]
-        // FIXME: Use `SyncUnsafeCell` instead of allowing `static_mut_ref` lint
-        #[allow(static_mut_ref)]
+        // FIXME: Use `SyncUnsafeCell` instead of allowing `static_mut_refs` lint
+        #[cfg_attr(bootstrap, allow(static_mut_ref))]
+        #[cfg_attr(not(bootstrap), allow(static_mut_refs))]
         unsafe fn __getit(
             _init: $crate::option::Option<&mut $crate::option::Option<$t>>,
         ) -> $crate::option::Option<&'static $t> {
diff --git a/library/std/src/sys/pal/common/thread_local/static_local.rs b/library/std/src/sys/pal/common/thread_local/static_local.rs
index 0dde78b14db..4f2b6868962 100644
--- a/library/std/src/sys/pal/common/thread_local/static_local.rs
+++ b/library/std/src/sys/pal/common/thread_local/static_local.rs
@@ -11,8 +11,9 @@ pub macro thread_local_inner {
     (@key $t:ty, const $init:expr) => {{
         #[inline] // see comments below
         #[deny(unsafe_op_in_unsafe_fn)]
-        // FIXME: Use `SyncUnsafeCell` instead of allowing `static_mut_ref` lint
-        #[allow(static_mut_ref)]
+        // FIXME: Use `SyncUnsafeCell` instead of allowing `static_mut_refs` lint
+        #[cfg_attr(bootstrap, allow(static_mut_ref))]
+        #[cfg_attr(not(bootstrap), allow(static_mut_refs))]
         unsafe fn __getit(
             _init: $crate::option::Option<&mut $crate::option::Option<$t>>,
         ) -> $crate::option::Option<&'static $t> {
diff --git a/library/std/src/sys/pal/hermit/fs.rs b/library/std/src/sys/pal/hermit/fs.rs
index 694482a8a30..d4da53fd3df 100644
--- a/library/std/src/sys/pal/hermit/fs.rs
+++ b/library/std/src/sys/pal/hermit/fs.rs
@@ -269,7 +269,7 @@ impl OpenOptions {
 
 impl File {
     pub fn open(path: &Path, opts: &OpenOptions) -> io::Result<File> {
-        run_path_with_cstr(path, |path| File::open_c(&path, opts))
+        run_path_with_cstr(path, &|path| File::open_c(&path, opts))
     }
 
     pub fn open_c(path: &CStr, opts: &OpenOptions) -> io::Result<File> {
@@ -421,7 +421,7 @@ pub fn readdir(_p: &Path) -> io::Result<ReadDir> {
 }
 
 pub fn unlink(path: &Path) -> io::Result<()> {
-    run_path_with_cstr(path, |path| cvt(unsafe { abi::unlink(path.as_ptr()) }).map(|_| ()))
+    run_path_with_cstr(path, &|path| cvt(unsafe { abi::unlink(path.as_ptr()) }).map(|_| ()))
 }
 
 pub fn rename(_old: &Path, _new: &Path) -> io::Result<()> {
diff --git a/library/std/src/sys/pal/solid/os.rs b/library/std/src/sys/pal/solid/os.rs
index ff81544ba91..5ceab3b27e0 100644
--- a/library/std/src/sys/pal/solid/os.rs
+++ b/library/std/src/sys/pal/solid/os.rs
@@ -172,7 +172,7 @@ pub fn env() -> Env {
 pub fn getenv(k: &OsStr) -> Option<OsString> {
     // environment variables with a nul byte can't be set, so their value is
     // always None as well
-    run_with_cstr(k.as_bytes(), |k| {
+    run_with_cstr(k.as_bytes(), &|k| {
         let _guard = env_read_lock();
         let v = unsafe { libc::getenv(k.as_ptr()) } as *const libc::c_char;
 
@@ -190,8 +190,8 @@ pub fn getenv(k: &OsStr) -> Option<OsString> {
 }
 
 pub fn setenv(k: &OsStr, v: &OsStr) -> io::Result<()> {
-    run_with_cstr(k.as_bytes(), |k| {
-        run_with_cstr(v.as_bytes(), |v| {
+    run_with_cstr(k.as_bytes(), &|k| {
+        run_with_cstr(v.as_bytes(), &|v| {
             let _guard = ENV_LOCK.write();
             cvt_env(unsafe { libc::setenv(k.as_ptr(), v.as_ptr(), 1) }).map(drop)
         })
@@ -199,7 +199,7 @@ pub fn setenv(k: &OsStr, v: &OsStr) -> io::Result<()> {
 }
 
 pub fn unsetenv(n: &OsStr) -> io::Result<()> {
-    run_with_cstr(n.as_bytes(), |nbuf| {
+    run_with_cstr(n.as_bytes(), &|nbuf| {
         let _guard = ENV_LOCK.write();
         cvt_env(unsafe { libc::unsetenv(nbuf.as_ptr()) }).map(drop)
     })
diff --git a/library/std/src/sys/pal/unix/fs.rs b/library/std/src/sys/pal/unix/fs.rs
index 6d0b892ea2f..c75323ef775 100644
--- a/library/std/src/sys/pal/unix/fs.rs
+++ b/library/std/src/sys/pal/unix/fs.rs
@@ -1118,7 +1118,7 @@ impl OpenOptions {
 
 impl File {
     pub fn open(path: &Path, opts: &OpenOptions) -> io::Result<File> {
-        run_path_with_cstr(path, |path| File::open_c(path, opts))
+        run_path_with_cstr(path, &|path| File::open_c(path, opts))
     }
 
     pub fn open_c(path: &CStr, opts: &OpenOptions) -> io::Result<File> {
@@ -1394,7 +1394,7 @@ impl DirBuilder {
     }
 
     pub fn mkdir(&self, p: &Path) -> io::Result<()> {
-        run_path_with_cstr(p, |p| cvt(unsafe { libc::mkdir(p.as_ptr(), self.mode) }).map(|_| ()))
+        run_path_with_cstr(p, &|p| cvt(unsafe { libc::mkdir(p.as_ptr(), self.mode) }).map(|_| ()))
     }
 
     pub fn set_mode(&mut self, mode: u32) {
@@ -1575,7 +1575,7 @@ impl fmt::Debug for File {
 }
 
 pub fn readdir(path: &Path) -> io::Result<ReadDir> {
-    let ptr = run_path_with_cstr(path, |p| unsafe { Ok(libc::opendir(p.as_ptr())) })?;
+    let ptr = run_path_with_cstr(path, &|p| unsafe { Ok(libc::opendir(p.as_ptr())) })?;
     if ptr.is_null() {
         Err(Error::last_os_error())
     } else {
@@ -1586,27 +1586,27 @@ pub fn readdir(path: &Path) -> io::Result<ReadDir> {
 }
 
 pub fn unlink(p: &Path) -> io::Result<()> {
-    run_path_with_cstr(p, |p| cvt(unsafe { libc::unlink(p.as_ptr()) }).map(|_| ()))
+    run_path_with_cstr(p, &|p| cvt(unsafe { libc::unlink(p.as_ptr()) }).map(|_| ()))
 }
 
 pub fn rename(old: &Path, new: &Path) -> io::Result<()> {
-    run_path_with_cstr(old, |old| {
-        run_path_with_cstr(new, |new| {
+    run_path_with_cstr(old, &|old| {
+        run_path_with_cstr(new, &|new| {
             cvt(unsafe { libc::rename(old.as_ptr(), new.as_ptr()) }).map(|_| ())
         })
     })
 }
 
 pub fn set_perm(p: &Path, perm: FilePermissions) -> io::Result<()> {
-    run_path_with_cstr(p, |p| cvt_r(|| unsafe { libc::chmod(p.as_ptr(), perm.mode) }).map(|_| ()))
+    run_path_with_cstr(p, &|p| cvt_r(|| unsafe { libc::chmod(p.as_ptr(), perm.mode) }).map(|_| ()))
 }
 
 pub fn rmdir(p: &Path) -> io::Result<()> {
-    run_path_with_cstr(p, |p| cvt(unsafe { libc::rmdir(p.as_ptr()) }).map(|_| ()))
+    run_path_with_cstr(p, &|p| cvt(unsafe { libc::rmdir(p.as_ptr()) }).map(|_| ()))
 }
 
 pub fn readlink(p: &Path) -> io::Result<PathBuf> {
-    run_path_with_cstr(p, |c_path| {
+    run_path_with_cstr(p, &|c_path| {
         let p = c_path.as_ptr();
 
         let mut buf = Vec::with_capacity(256);
@@ -1635,16 +1635,16 @@ pub fn readlink(p: &Path) -> io::Result<PathBuf> {
 }
 
 pub fn symlink(original: &Path, link: &Path) -> io::Result<()> {
-    run_path_with_cstr(original, |original| {
-        run_path_with_cstr(link, |link| {
+    run_path_with_cstr(original, &|original| {
+        run_path_with_cstr(link, &|link| {
             cvt(unsafe { libc::symlink(original.as_ptr(), link.as_ptr()) }).map(|_| ())
         })
     })
 }
 
 pub fn link(original: &Path, link: &Path) -> io::Result<()> {
-    run_path_with_cstr(original, |original| {
-        run_path_with_cstr(link, |link| {
+    run_path_with_cstr(original, &|original| {
+        run_path_with_cstr(link, &|link| {
             cfg_if::cfg_if! {
                 if #[cfg(any(target_os = "vxworks", target_os = "redox", target_os = "android", target_os = "espidf", target_os = "horizon", target_os = "vita"))] {
                     // VxWorks, Redox and ESP-IDF lack `linkat`, so use `link` instead. POSIX leaves
@@ -1678,7 +1678,7 @@ pub fn link(original: &Path, link: &Path) -> io::Result<()> {
 }
 
 pub fn stat(p: &Path) -> io::Result<FileAttr> {
-    run_path_with_cstr(p, |p| {
+    run_path_with_cstr(p, &|p| {
         cfg_has_statx! {
             if let Some(ret) = unsafe { try_statx(
                 libc::AT_FDCWD,
@@ -1697,7 +1697,7 @@ pub fn stat(p: &Path) -> io::Result<FileAttr> {
 }
 
 pub fn lstat(p: &Path) -> io::Result<FileAttr> {
-    run_path_with_cstr(p, |p| {
+    run_path_with_cstr(p, &|p| {
         cfg_has_statx! {
             if let Some(ret) = unsafe { try_statx(
                 libc::AT_FDCWD,
@@ -1716,7 +1716,7 @@ pub fn lstat(p: &Path) -> io::Result<FileAttr> {
 }
 
 pub fn canonicalize(p: &Path) -> io::Result<PathBuf> {
-    let r = run_path_with_cstr(p, |path| unsafe {
+    let r = run_path_with_cstr(p, &|path| unsafe {
         Ok(libc::realpath(path.as_ptr(), ptr::null_mut()))
     })?;
     if r.is_null() {
@@ -1879,7 +1879,7 @@ pub fn copy(from: &Path, to: &Path) -> io::Result<u64> {
     // Opportunistically attempt to create a copy-on-write clone of `from`
     // using `fclonefileat`.
     if HAS_FCLONEFILEAT.load(Ordering::Relaxed) {
-        let clonefile_result = run_path_with_cstr(to, |to| {
+        let clonefile_result = run_path_with_cstr(to, &|to| {
             cvt(unsafe { fclonefileat(reader.as_raw_fd(), libc::AT_FDCWD, to.as_ptr(), 0) })
         });
         match clonefile_result {
@@ -1925,7 +1925,7 @@ pub fn copy(from: &Path, to: &Path) -> io::Result<u64> {
 }
 
 pub fn chown(path: &Path, uid: u32, gid: u32) -> io::Result<()> {
-    run_path_with_cstr(path, |path| {
+    run_path_with_cstr(path, &|path| {
         cvt(unsafe { libc::chown(path.as_ptr(), uid as libc::uid_t, gid as libc::gid_t) })
             .map(|_| ())
     })
@@ -1937,7 +1937,7 @@ pub fn fchown(fd: c_int, uid: u32, gid: u32) -> io::Result<()> {
 }
 
 pub fn lchown(path: &Path, uid: u32, gid: u32) -> io::Result<()> {
-    run_path_with_cstr(path, |path| {
+    run_path_with_cstr(path, &|path| {
         cvt(unsafe { libc::lchown(path.as_ptr(), uid as libc::uid_t, gid as libc::gid_t) })
             .map(|_| ())
     })
@@ -1945,7 +1945,7 @@ pub fn lchown(path: &Path, uid: u32, gid: u32) -> io::Result<()> {
 
 #[cfg(not(any(target_os = "fuchsia", target_os = "vxworks")))]
 pub fn chroot(dir: &Path) -> io::Result<()> {
-    run_path_with_cstr(dir, |dir| cvt(unsafe { libc::chroot(dir.as_ptr()) }).map(|_| ()))
+    run_path_with_cstr(dir, &|dir| cvt(unsafe { libc::chroot(dir.as_ptr()) }).map(|_| ()))
 }
 
 pub use remove_dir_impl::remove_dir_all;
@@ -2140,7 +2140,7 @@ mod remove_dir_impl {
         if attr.file_type().is_symlink() {
             crate::fs::remove_file(p)
         } else {
-            run_path_with_cstr(p, |p| remove_dir_all_recursive(None, &p))
+            run_path_with_cstr(p, &|p| remove_dir_all_recursive(None, &p))
         }
     }
 
diff --git a/library/std/src/sys/pal/unix/os.rs b/library/std/src/sys/pal/unix/os.rs
index 881b3a25c51..af2b9db4685 100644
--- a/library/std/src/sys/pal/unix/os.rs
+++ b/library/std/src/sys/pal/unix/os.rs
@@ -186,7 +186,7 @@ pub fn chdir(_p: &path::Path) -> io::Result<()> {
 
 #[cfg(not(target_os = "espidf"))]
 pub fn chdir(p: &path::Path) -> io::Result<()> {
-    let result = run_path_with_cstr(p, |p| unsafe { Ok(libc::chdir(p.as_ptr())) })?;
+    let result = run_path_with_cstr(p, &|p| unsafe { Ok(libc::chdir(p.as_ptr())) })?;
     if result == 0 { Ok(()) } else { Err(io::Error::last_os_error()) }
 }
 
@@ -643,7 +643,7 @@ pub fn env() -> Env {
 pub fn getenv(k: &OsStr) -> Option<OsString> {
     // environment variables with a nul byte can't be set, so their value is
     // always None as well
-    run_with_cstr(k.as_bytes(), |k| {
+    run_with_cstr(k.as_bytes(), &|k| {
         let _guard = env_read_lock();
         let v = unsafe { libc::getenv(k.as_ptr()) } as *const libc::c_char;
 
@@ -661,8 +661,8 @@ pub fn getenv(k: &OsStr) -> Option<OsString> {
 }
 
 pub fn setenv(k: &OsStr, v: &OsStr) -> io::Result<()> {
-    run_with_cstr(k.as_bytes(), |k| {
-        run_with_cstr(v.as_bytes(), |v| {
+    run_with_cstr(k.as_bytes(), &|k| {
+        run_with_cstr(v.as_bytes(), &|v| {
             let _guard = ENV_LOCK.write();
             cvt(unsafe { libc::setenv(k.as_ptr(), v.as_ptr(), 1) }).map(drop)
         })
@@ -670,7 +670,7 @@ pub fn setenv(k: &OsStr, v: &OsStr) -> io::Result<()> {
 }
 
 pub fn unsetenv(n: &OsStr) -> io::Result<()> {
-    run_with_cstr(n.as_bytes(), |nbuf| {
+    run_with_cstr(n.as_bytes(), &|nbuf| {
         let _guard = ENV_LOCK.write();
         cvt(unsafe { libc::unsetenv(nbuf.as_ptr()) }).map(drop)
     })
diff --git a/library/std/src/sys/pal/wasi/fs.rs b/library/std/src/sys/pal/wasi/fs.rs
index e8238665452..529b82e0198 100644
--- a/library/std/src/sys/pal/wasi/fs.rs
+++ b/library/std/src/sys/pal/wasi/fs.rs
@@ -698,7 +698,7 @@ fn open_at(fd: &WasiFd, path: &Path, opts: &OpenOptions) -> io::Result<File> {
 /// Note that this can fail if `p` doesn't look like it can be opened relative
 /// to any pre-opened file descriptor.
 fn open_parent(p: &Path) -> io::Result<(ManuallyDrop<WasiFd>, PathBuf)> {
-    run_path_with_cstr(p, |p| {
+    run_path_with_cstr(p, &|p| {
         let mut buf = Vec::<u8>::with_capacity(512);
         loop {
             unsafe {
diff --git a/library/std/src/sys/pal/wasi/os.rs b/library/std/src/sys/pal/wasi/os.rs
index 530d3602172..d62ff8a2f18 100644
--- a/library/std/src/sys/pal/wasi/os.rs
+++ b/library/std/src/sys/pal/wasi/os.rs
@@ -95,7 +95,7 @@ pub fn getcwd() -> io::Result<PathBuf> {
 }
 
 pub fn chdir(p: &path::Path) -> io::Result<()> {
-    let result = run_path_with_cstr(p, |p| unsafe { Ok(libc::chdir(p.as_ptr())) })?;
+    let result = run_path_with_cstr(p, &|p| unsafe { Ok(libc::chdir(p.as_ptr())) })?;
     match result == (0 as libc::c_int) {
         true => Ok(()),
         false => Err(io::Error::last_os_error()),
@@ -227,7 +227,7 @@ pub fn env() -> Env {
 pub fn getenv(k: &OsStr) -> Option<OsString> {
     // environment variables with a nul byte can't be set, so their value is
     // always None as well
-    run_with_cstr(k.as_bytes(), |k| {
+    run_with_cstr(k.as_bytes(), &|k| {
         let _guard = env_read_lock();
         let v = unsafe { libc::getenv(k.as_ptr()) } as *const libc::c_char;
 
@@ -245,8 +245,8 @@ pub fn getenv(k: &OsStr) -> Option<OsString> {
 }
 
 pub fn setenv(k: &OsStr, v: &OsStr) -> io::Result<()> {
-    run_with_cstr(k.as_bytes(), |k| {
-        run_with_cstr(v.as_bytes(), |v| unsafe {
+    run_with_cstr(k.as_bytes(), &|k| {
+        run_with_cstr(v.as_bytes(), &|v| unsafe {
             let _guard = env_write_lock();
             cvt(libc::setenv(k.as_ptr(), v.as_ptr(), 1)).map(drop)
         })
@@ -254,7 +254,7 @@ pub fn setenv(k: &OsStr, v: &OsStr) -> io::Result<()> {
 }
 
 pub fn unsetenv(n: &OsStr) -> io::Result<()> {
-    run_with_cstr(n.as_bytes(), |nbuf| unsafe {
+    run_with_cstr(n.as_bytes(), &|nbuf| unsafe {
         let _guard = env_write_lock();
         cvt(libc::unsetenv(nbuf.as_ptr())).map(drop)
     })
diff --git a/library/std/src/sys_common/net.rs b/library/std/src/sys_common/net.rs
index 8712bd2eca7..de7d31baaaf 100644
--- a/library/std/src/sys_common/net.rs
+++ b/library/std/src/sys_common/net.rs
@@ -199,7 +199,7 @@ impl<'a> TryFrom<(&'a str, u16)> for LookupHost {
     fn try_from((host, port): (&'a str, u16)) -> io::Result<LookupHost> {
         init();
 
-        run_with_cstr(host.as_bytes(), |c_host| {
+        run_with_cstr(host.as_bytes(), &|c_host| {
             let mut hints: c::addrinfo = unsafe { mem::zeroed() };
             hints.ai_socktype = c::SOCK_STREAM;
             let mut res = ptr::null_mut();
diff --git a/library/std/src/sys_common/wtf8.rs b/library/std/src/sys_common/wtf8.rs
index 67db5ebd89c..2dbd19d7171 100644
--- a/library/std/src/sys_common/wtf8.rs
+++ b/library/std/src/sys_common/wtf8.rs
@@ -885,15 +885,43 @@ fn decode_surrogate_pair(lead: u16, trail: u16) -> char {
     unsafe { char::from_u32_unchecked(code_point) }
 }
 
-/// Copied from core::str::StrPrelude::is_char_boundary
+/// Copied from str::is_char_boundary
 #[inline]
 pub fn is_code_point_boundary(slice: &Wtf8, index: usize) -> bool {
-    if index == slice.len() {
+    if index == 0 {
         return true;
     }
     match slice.bytes.get(index) {
-        None => false,
-        Some(&b) => b < 128 || b >= 192,
+        None => index == slice.len(),
+        Some(&b) => (b as i8) >= -0x40,
+    }
+}
+
+/// Verify that `index` is at the edge of either a valid UTF-8 codepoint
+/// (i.e. a codepoint that's not a surrogate) or of the whole string.
+///
+/// These are the cases currently permitted by `OsStr::slice_encoded_bytes`.
+/// Splitting between surrogates is valid as far as WTF-8 is concerned, but
+/// we do not permit it in the public API because WTF-8 is considered an
+/// implementation detail.
+#[track_caller]
+#[inline]
+pub fn check_utf8_boundary(slice: &Wtf8, index: usize) {
+    if index == 0 {
+        return;
+    }
+    match slice.bytes.get(index) {
+        Some(0xED) => (), // Might be a surrogate
+        Some(&b) if (b as i8) >= -0x40 => return,
+        Some(_) => panic!("byte index {index} is not a codepoint boundary"),
+        None if index == slice.len() => return,
+        None => panic!("byte index {index} is out of bounds"),
+    }
+    if slice.bytes[index + 1] >= 0xA0 {
+        // There's a surrogate after index. Now check before index.
+        if index >= 3 && slice.bytes[index - 3] == 0xED && slice.bytes[index - 2] >= 0xA0 {
+            panic!("byte index {index} lies between surrogate codepoints");
+        }
     }
 }
 
diff --git a/library/std/src/sys_common/wtf8/tests.rs b/library/std/src/sys_common/wtf8/tests.rs
index 28a426648e5..6a1cc41a8fb 100644
--- a/library/std/src/sys_common/wtf8/tests.rs
+++ b/library/std/src/sys_common/wtf8/tests.rs
@@ -663,3 +663,65 @@ fn wtf8_to_owned() {
     assert_eq!(string.bytes, b"\xED\xA0\x80");
     assert!(!string.is_known_utf8);
 }
+
+#[test]
+fn wtf8_valid_utf8_boundaries() {
+    let mut string = Wtf8Buf::from_str("aé 💩");
+    string.push(CodePoint::from_u32(0xD800).unwrap());
+    string.push(CodePoint::from_u32(0xD800).unwrap());
+    check_utf8_boundary(&string, 0);
+    check_utf8_boundary(&string, 1);
+    check_utf8_boundary(&string, 3);
+    check_utf8_boundary(&string, 4);
+    check_utf8_boundary(&string, 8);
+    check_utf8_boundary(&string, 14);
+    assert_eq!(string.len(), 14);
+
+    string.push_char('a');
+    check_utf8_boundary(&string, 14);
+    check_utf8_boundary(&string, 15);
+
+    let mut string = Wtf8Buf::from_str("a");
+    string.push(CodePoint::from_u32(0xD800).unwrap());
+    check_utf8_boundary(&string, 1);
+
+    let mut string = Wtf8Buf::from_str("\u{D7FF}");
+    string.push(CodePoint::from_u32(0xD800).unwrap());
+    check_utf8_boundary(&string, 3);
+
+    let mut string = Wtf8Buf::new();
+    string.push(CodePoint::from_u32(0xD800).unwrap());
+    string.push_char('\u{D7FF}');
+    check_utf8_boundary(&string, 3);
+}
+
+#[test]
+#[should_panic(expected = "byte index 4 is out of bounds")]
+fn wtf8_utf8_boundary_out_of_bounds() {
+    let string = Wtf8::from_str("aé");
+    check_utf8_boundary(&string, 4);
+}
+
+#[test]
+#[should_panic(expected = "byte index 1 is not a codepoint boundary")]
+fn wtf8_utf8_boundary_inside_codepoint() {
+    let string = Wtf8::from_str("é");
+    check_utf8_boundary(&string, 1);
+}
+
+#[test]
+#[should_panic(expected = "byte index 1 is not a codepoint boundary")]
+fn wtf8_utf8_boundary_inside_surrogate() {
+    let mut string = Wtf8Buf::new();
+    string.push(CodePoint::from_u32(0xD800).unwrap());
+    check_utf8_boundary(&string, 1);
+}
+
+#[test]
+#[should_panic(expected = "byte index 3 lies between surrogate codepoints")]
+fn wtf8_utf8_boundary_between_surrogates() {
+    let mut string = Wtf8Buf::new();
+    string.push(CodePoint::from_u32(0xD800).unwrap());
+    string.push(CodePoint::from_u32(0xD800).unwrap());
+    check_utf8_boundary(&string, 3);
+}
diff --git a/library/std/src/thread/local.rs b/library/std/src/thread/local.rs
index 83d5d63556f..d1213e2f166 100644
--- a/library/std/src/thread/local.rs
+++ b/library/std/src/thread/local.rs
@@ -180,8 +180,8 @@ impl<T: 'static> fmt::Debug for LocalKey<T> {
 #[stable(feature = "rust1", since = "1.0.0")]
 #[cfg_attr(not(test), rustc_diagnostic_item = "thread_local_macro")]
 #[allow_internal_unstable(thread_local_internals)]
-// FIXME: Use `SyncUnsafeCell` instead of allowing `static_mut_ref` lint
-#[allow(static_mut_ref)]
+// FIXME: Use `SyncUnsafeCell` instead of allowing `static_mut_refs` lint
+#[cfg_attr(not(bootstrap), allow(static_mut_refs))]
 macro_rules! thread_local {
     // empty (base case for the recursion)
     () => {};
diff --git a/src/librustdoc/clean/inline.rs b/src/librustdoc/clean/inline.rs
index e2f2c9a5e56..03f62f41a26 100644
--- a/src/librustdoc/clean/inline.rs
+++ b/src/librustdoc/clean/inline.rs
@@ -443,11 +443,13 @@ pub(crate) fn build_impl(
             return;
         }
 
-        if let Some(stab) = tcx.lookup_stability(did)
-            && stab.is_unstable()
-            && stab.feature == sym::rustc_private
-        {
-            return;
+        if !tcx.features().rustc_private && !cx.render_options.force_unstable_if_unmarked {
+            if let Some(stab) = tcx.lookup_stability(did)
+                && stab.is_unstable()
+                && stab.feature == sym::rustc_private
+            {
+                return;
+            }
         }
     }
 
@@ -477,8 +479,11 @@ pub(crate) fn build_impl(
                 return;
             }
 
-            if let Some(stab) = tcx.lookup_stability(did) {
-                if stab.is_unstable() && stab.feature == sym::rustc_private {
+            if !tcx.features().rustc_private && !cx.render_options.force_unstable_if_unmarked {
+                if let Some(stab) = tcx.lookup_stability(did)
+                    && stab.is_unstable()
+                    && stab.feature == sym::rustc_private
+                {
                     return;
                 }
             }
diff --git a/src/librustdoc/config.rs b/src/librustdoc/config.rs
index c46047aa0db..4b1a417b211 100644
--- a/src/librustdoc/config.rs
+++ b/src/librustdoc/config.rs
@@ -281,6 +281,8 @@ pub(crate) struct RenderOptions {
     pub(crate) no_emit_shared: bool,
     /// If `true`, HTML source code pages won't be generated.
     pub(crate) html_no_source: bool,
+    /// Whether `-Zforce-unstable-if-unmarked` unstable option is set
+    pub(crate) force_unstable_if_unmarked: bool,
 }
 
 #[derive(Copy, Clone, Debug, PartialEq, Eq)]
@@ -347,6 +349,7 @@ impl Options {
 
         let codegen_options = CodegenOptions::build(early_dcx, matches);
         let unstable_opts = UnstableOptions::build(early_dcx, matches);
+        let force_unstable_if_unmarked = unstable_opts.force_unstable_if_unmarked;
 
         let dcx = new_dcx(error_format, None, diagnostic_width, &unstable_opts);
 
@@ -760,6 +763,7 @@ impl Options {
             call_locations,
             no_emit_shared: false,
             html_no_source,
+            force_unstable_if_unmarked,
         };
         Some((options, render_options))
     }
diff --git a/src/librustdoc/html/format.rs b/src/librustdoc/html/format.rs
index 4ba1665bdc9..bb68c84f529 100644
--- a/src/librustdoc/html/format.rs
+++ b/src/librustdoc/html/format.rs
@@ -1,6 +1,6 @@
 //! HTML formatting module
 //!
-//! This module contains a large number of `fmt::Display` implementations for
+//! This module contains a large number of `Display` implementations for
 //! various types in `rustdoc::clean`.
 //!
 //! These implementations all emit HTML. As an internal implementation detail,
@@ -9,7 +9,7 @@
 
 use std::borrow::Cow;
 use std::cell::Cell;
-use std::fmt::{self, Write};
+use std::fmt::{self, Display, Write};
 use std::iter::{self, once};
 
 use rustc_ast as ast;
@@ -150,16 +150,16 @@ impl Buffer {
     }
 }
 
-pub(crate) fn comma_sep<T: fmt::Display>(
+pub(crate) fn comma_sep<T: Display>(
     items: impl Iterator<Item = T>,
     space_after_comma: bool,
-) -> impl fmt::Display {
+) -> impl Display {
     display_fn(move |f| {
         for (i, item) in items.enumerate() {
             if i != 0 {
                 write!(f, ",{}", if space_after_comma { " " } else { "" })?;
             }
-            fmt::Display::fmt(&item, f)?;
+            item.fmt(f)?;
         }
         Ok(())
     })
@@ -168,7 +168,7 @@ pub(crate) fn comma_sep<T: fmt::Display>(
 pub(crate) fn print_generic_bounds<'a, 'tcx: 'a>(
     bounds: &'a [clean::GenericBound],
     cx: &'a Context<'tcx>,
-) -> impl fmt::Display + 'a + Captures<'tcx> {
+) -> impl Display + 'a + Captures<'tcx> {
     display_fn(move |f| {
         let mut bounds_dup = FxHashSet::default();
 
@@ -176,7 +176,7 @@ pub(crate) fn print_generic_bounds<'a, 'tcx: 'a>(
             if i > 0 {
                 f.write_str(" + ")?;
             }
-            fmt::Display::fmt(&bound.print(cx), f)?;
+            bound.print(cx).fmt(f)?;
         }
         Ok(())
     })
@@ -186,7 +186,7 @@ impl clean::GenericParamDef {
     pub(crate) fn print<'a, 'tcx: 'a>(
         &'a self,
         cx: &'a Context<'tcx>,
-    ) -> impl fmt::Display + 'a + Captures<'tcx> {
+    ) -> impl Display + 'a + Captures<'tcx> {
         display_fn(move |f| match &self.kind {
             clean::GenericParamDefKind::Lifetime { outlives } => {
                 write!(f, "{}", self.name)?;
@@ -207,35 +207,27 @@ impl clean::GenericParamDef {
                 f.write_str(self.name.as_str())?;
 
                 if !bounds.is_empty() {
-                    if f.alternate() {
-                        write!(f, ": {:#}", print_generic_bounds(bounds, cx))?;
-                    } else {
-                        write!(f, ": {}", print_generic_bounds(bounds, cx))?;
-                    }
+                    f.write_str(": ")?;
+                    print_generic_bounds(bounds, cx).fmt(f)?;
                 }
 
                 if let Some(ref ty) = default {
-                    if f.alternate() {
-                        write!(f, " = {:#}", ty.print(cx))?;
-                    } else {
-                        write!(f, " = {}", ty.print(cx))?;
-                    }
+                    f.write_str(" = ")?;
+                    ty.print(cx).fmt(f)?;
                 }
 
                 Ok(())
             }
             clean::GenericParamDefKind::Const { ty, default, .. } => {
-                if f.alternate() {
-                    write!(f, "const {}: {:#}", self.name, ty.print(cx))?;
-                } else {
-                    write!(f, "const {}: {}", self.name, ty.print(cx))?;
-                }
+                write!(f, "const {}: ", self.name)?;
+                ty.print(cx).fmt(f)?;
 
                 if let Some(default) = default {
+                    f.write_str(" = ")?;
                     if f.alternate() {
-                        write!(f, " = {default:#}")?;
+                        write!(f, "{default}")?;
                     } else {
-                        write!(f, " = {default}")?;
+                        write!(f, "{}", Escape(default))?;
                     }
                 }
 
@@ -249,7 +241,7 @@ impl clean::Generics {
     pub(crate) fn print<'a, 'tcx: 'a>(
         &'a self,
         cx: &'a Context<'tcx>,
-    ) -> impl fmt::Display + 'a + Captures<'tcx> {
+    ) -> impl Display + 'a + Captures<'tcx> {
         display_fn(move |f| {
             let mut real_params = self.params.iter().filter(|p| !p.is_synthetic_param()).peekable();
             if real_params.peek().is_none() {
@@ -279,63 +271,50 @@ pub(crate) fn print_where_clause<'a, 'tcx: 'a>(
     cx: &'a Context<'tcx>,
     indent: usize,
     ending: Ending,
-) -> impl fmt::Display + 'a + Captures<'tcx> {
+) -> impl Display + 'a + Captures<'tcx> {
     display_fn(move |f| {
-        let mut where_predicates = gens.where_predicates.iter().filter(|pred| {
-            !matches!(pred, clean::WherePredicate::BoundPredicate { bounds, .. } if bounds.is_empty())
-        }).map(|pred| {
-            display_fn(move |f| {
-                if f.alternate() {
-                    f.write_str(" ")?;
-                } else {
-                    f.write_str("\n")?;
-                }
-
-                match pred {
-                    clean::WherePredicate::BoundPredicate { ty, bounds, bound_params } => {
-                        let ty_cx = ty.print(cx);
-                        let generic_bounds = print_generic_bounds(bounds, cx);
+        let mut where_predicates = gens
+            .where_predicates
+            .iter()
+            .map(|pred| {
+                display_fn(move |f| {
+                    if f.alternate() {
+                        f.write_str(" ")?;
+                    } else {
+                        f.write_str("\n")?;
+                    }
 
-                        if bound_params.is_empty() {
-                            if f.alternate() {
-                                write!(f, "{ty_cx:#}: {generic_bounds:#}")
-                            } else {
-                                write!(f, "{ty_cx}: {generic_bounds}")
+                    match pred {
+                        clean::WherePredicate::BoundPredicate { ty, bounds, bound_params } => {
+                            print_higher_ranked_params_with_space(bound_params, cx).fmt(f)?;
+                            ty.print(cx).fmt(f)?;
+                            f.write_str(":")?;
+                            if !bounds.is_empty() {
+                                f.write_str(" ")?;
+                                print_generic_bounds(bounds, cx).fmt(f)?;
                             }
-                        } else {
+                            Ok(())
+                        }
+                        clean::WherePredicate::RegionPredicate { lifetime, bounds } => {
+                            // We don't need to check `alternate` since we can be certain that neither
+                            // the lifetime nor the bounds contain any characters which need escaping.
+                            write!(f, "{}:", lifetime.print())?;
+                            if !bounds.is_empty() {
+                                write!(f, " {}", print_generic_bounds(bounds, cx))?;
+                            }
+                            Ok(())
+                        }
+                        clean::WherePredicate::EqPredicate { lhs, rhs } => {
                             if f.alternate() {
-                                write!(
-                                    f,
-                                    "for<{:#}> {ty_cx:#}: {generic_bounds:#}",
-                                    comma_sep(bound_params.iter().map(|lt| lt.print(cx)), true)
-                                )
+                                write!(f, "{:#} == {:#}", lhs.print(cx), rhs.print(cx))
                             } else {
-                                write!(
-                                    f,
-                                    "for&lt;{}&gt; {ty_cx}: {generic_bounds}",
-                                    comma_sep(bound_params.iter().map(|lt| lt.print(cx)), true)
-                                )
+                                write!(f, "{} == {}", lhs.print(cx), rhs.print(cx))
                             }
                         }
                     }
-                    clean::WherePredicate::RegionPredicate { lifetime, bounds } => {
-                        let mut bounds_display = String::new();
-                        for bound in bounds.iter().map(|b| b.print(cx)) {
-                            write!(bounds_display, "{bound} + ")?;
-                        }
-                        bounds_display.truncate(bounds_display.len() - " + ".len());
-                        write!(f, "{}: {bounds_display}", lifetime.print())
-                    }
-                    clean::WherePredicate::EqPredicate { lhs, rhs } => {
-                        if f.alternate() {
-                            write!(f, "{:#} == {:#}", lhs.print(cx), rhs.print(cx))
-                        } else {
-                            write!(f, "{} == {}", lhs.print(cx), rhs.print(cx))
-                        }
-                    }
-                }
+                })
             })
-        }).peekable();
+            .peekable();
 
         if where_predicates.peek().is_none() {
             return Ok(());
@@ -392,13 +371,13 @@ pub(crate) fn print_where_clause<'a, 'tcx: 'a>(
 }
 
 impl clean::Lifetime {
-    pub(crate) fn print(&self) -> impl fmt::Display + '_ {
+    pub(crate) fn print(&self) -> impl Display + '_ {
         self.0.as_str()
     }
 }
 
 impl clean::Constant {
-    pub(crate) fn print(&self, tcx: TyCtxt<'_>) -> impl fmt::Display + '_ {
+    pub(crate) fn print(&self, tcx: TyCtxt<'_>) -> impl Display + '_ {
         let expr = self.expr(tcx);
         display_fn(
             move |f| {
@@ -409,31 +388,10 @@ impl clean::Constant {
 }
 
 impl clean::PolyTrait {
-    fn print<'a, 'tcx: 'a>(
-        &'a self,
-        cx: &'a Context<'tcx>,
-    ) -> impl fmt::Display + 'a + Captures<'tcx> {
+    fn print<'a, 'tcx: 'a>(&'a self, cx: &'a Context<'tcx>) -> impl Display + 'a + Captures<'tcx> {
         display_fn(move |f| {
-            if !self.generic_params.is_empty() {
-                if f.alternate() {
-                    write!(
-                        f,
-                        "for<{:#}> ",
-                        comma_sep(self.generic_params.iter().map(|g| g.print(cx)), true)
-                    )?;
-                } else {
-                    write!(
-                        f,
-                        "for&lt;{}&gt; ",
-                        comma_sep(self.generic_params.iter().map(|g| g.print(cx)), true)
-                    )?;
-                }
-            }
-            if f.alternate() {
-                write!(f, "{:#}", self.trait_.print(cx))
-            } else {
-                write!(f, "{}", self.trait_.print(cx))
-            }
+            print_higher_ranked_params_with_space(&self.generic_params, cx).fmt(f)?;
+            self.trait_.print(cx).fmt(f)
         })
     }
 }
@@ -442,32 +400,25 @@ impl clean::GenericBound {
     pub(crate) fn print<'a, 'tcx: 'a>(
         &'a self,
         cx: &'a Context<'tcx>,
-    ) -> impl fmt::Display + 'a + Captures<'tcx> {
+    ) -> impl Display + 'a + Captures<'tcx> {
         display_fn(move |f| match self {
             clean::GenericBound::Outlives(lt) => write!(f, "{}", lt.print()),
             clean::GenericBound::TraitBound(ty, modifier) => {
-                let modifier_str = match modifier {
+                f.write_str(match modifier {
                     hir::TraitBoundModifier::None => "",
                     hir::TraitBoundModifier::Maybe => "?",
                     hir::TraitBoundModifier::Negative => "!",
                     // `const` and `~const` trait bounds are experimental; don't render them.
                     hir::TraitBoundModifier::Const | hir::TraitBoundModifier::MaybeConst => "",
-                };
-                if f.alternate() {
-                    write!(f, "{modifier_str}{ty:#}", ty = ty.print(cx))
-                } else {
-                    write!(f, "{modifier_str}{ty}", ty = ty.print(cx))
-                }
+                })?;
+                ty.print(cx).fmt(f)
             }
         })
     }
 }
 
 impl clean::GenericArgs {
-    fn print<'a, 'tcx: 'a>(
-        &'a self,
-        cx: &'a Context<'tcx>,
-    ) -> impl fmt::Display + 'a + Captures<'tcx> {
+    fn print<'a, 'tcx: 'a>(&'a self, cx: &'a Context<'tcx>) -> impl Display + 'a + Captures<'tcx> {
         display_fn(move |f| {
             match self {
                 clean::GenericArgs::AngleBracketed { args, bindings } => {
@@ -515,11 +466,7 @@ impl clean::GenericArgs {
                             f.write_str(", ")?;
                         }
                         comma = true;
-                        if f.alternate() {
-                            write!(f, "{:#}", ty.print(cx))?;
-                        } else {
-                            write!(f, "{}", ty.print(cx))?;
-                        }
+                        ty.print(cx).fmt(f)?;
                     }
                     f.write_str(")")?;
                     if let Some(ref ty) = *output {
@@ -973,31 +920,43 @@ fn primitive_link_fragment(
             None => {}
         }
     }
-    std::fmt::Display::fmt(&name, f)?;
+    Display::fmt(&name, f)?;
     if needs_termination {
         write!(f, "</a>")?;
     }
     Ok(())
 }
 
-/// Helper to render type parameters
 fn tybounds<'a, 'tcx: 'a>(
     bounds: &'a [clean::PolyTrait],
     lt: &'a Option<clean::Lifetime>,
     cx: &'a Context<'tcx>,
-) -> impl fmt::Display + 'a + Captures<'tcx> {
+) -> impl Display + 'a + Captures<'tcx> {
     display_fn(move |f| {
         for (i, bound) in bounds.iter().enumerate() {
             if i > 0 {
                 write!(f, " + ")?;
             }
-
-            fmt::Display::fmt(&bound.print(cx), f)?;
+            bound.print(cx).fmt(f)?;
         }
-
         if let Some(lt) = lt {
-            write!(f, " + ")?;
-            fmt::Display::fmt(&lt.print(), f)?;
+            // We don't need to check `alternate` since we can be certain that
+            // the lifetime doesn't contain any characters which need escaping.
+            write!(f, " + {}", lt.print())?;
+        }
+        Ok(())
+    })
+}
+
+fn print_higher_ranked_params_with_space<'a, 'tcx: 'a>(
+    params: &'a [clean::GenericParamDef],
+    cx: &'a Context<'tcx>,
+) -> impl Display + 'a + Captures<'tcx> {
+    display_fn(move |f| {
+        if !params.is_empty() {
+            f.write_str(if f.alternate() { "for<" } else { "for&lt;" })?;
+            comma_sep(params.iter().map(|lt| lt.print(cx)), true).fmt(f)?;
+            f.write_str(if f.alternate() { "> " } else { "&gt; " })?;
         }
         Ok(())
     })
@@ -1007,7 +966,7 @@ pub(crate) fn anchor<'a, 'cx: 'a>(
     did: DefId,
     text: Symbol,
     cx: &'cx Context<'_>,
-) -> impl fmt::Display + 'a {
+) -> impl Display + 'a {
     let parts = href(did, cx);
     display_fn(move |f| {
         if let Ok((url, short_ty, fqp)) = parts {
@@ -1039,7 +998,7 @@ fn fmt_type<'cx>(
         }
         clean::DynTrait(ref bounds, ref lt) => {
             f.write_str("dyn ")?;
-            fmt::Display::fmt(&tybounds(bounds, lt, cx), f)
+            tybounds(bounds, lt, cx).fmt(f)
         }
         clean::Infer => write!(f, "_"),
         clean::Primitive(clean::PrimitiveType::Never) => {
@@ -1049,80 +1008,62 @@ fn fmt_type<'cx>(
             primitive_link(f, prim, format_args!("{}", prim.as_sym().as_str()), cx)
         }
         clean::BareFunction(ref decl) => {
+            print_higher_ranked_params_with_space(&decl.generic_params, cx).fmt(f)?;
+            decl.unsafety.print_with_space().fmt(f)?;
+            print_abi_with_space(decl.abi).fmt(f)?;
             if f.alternate() {
-                write!(
-                    f,
-                    "{:#}{}{:#}fn{:#}",
-                    decl.print_hrtb_with_space(cx),
-                    decl.unsafety.print_with_space(),
-                    print_abi_with_space(decl.abi),
-                    decl.decl.print(cx),
-                )
+                f.write_str("fn")?;
             } else {
-                write!(
-                    f,
-                    "{}{}{}",
-                    decl.print_hrtb_with_space(cx),
-                    decl.unsafety.print_with_space(),
-                    print_abi_with_space(decl.abi)
-                )?;
                 primitive_link(f, PrimitiveType::Fn, format_args!("fn"), cx)?;
-                write!(f, "{}", decl.decl.print(cx))
             }
+            decl.decl.print(cx).fmt(f)
         }
-        clean::Tuple(ref typs) => {
-            match &typs[..] {
-                &[] => primitive_link(f, PrimitiveType::Unit, format_args!("()"), cx),
-                [one] => {
-                    if let clean::Generic(name) = one {
-                        primitive_link(f, PrimitiveType::Tuple, format_args!("({name},)"), cx)
-                    } else {
-                        write!(f, "(")?;
-                        // Carry `f.alternate()` into this display w/o branching manually.
-                        fmt::Display::fmt(&one.print(cx), f)?;
-                        write!(f, ",)")
-                    }
+        clean::Tuple(ref typs) => match &typs[..] {
+            &[] => primitive_link(f, PrimitiveType::Unit, format_args!("()"), cx),
+            [one] => {
+                if let clean::Generic(name) = one {
+                    primitive_link(f, PrimitiveType::Tuple, format_args!("({name},)"), cx)
+                } else {
+                    write!(f, "(")?;
+                    one.print(cx).fmt(f)?;
+                    write!(f, ",)")
                 }
-                many => {
-                    let generic_names: Vec<Symbol> = many
-                        .iter()
-                        .filter_map(|t| match t {
-                            clean::Generic(name) => Some(*name),
-                            _ => None,
-                        })
-                        .collect();
-                    let is_generic = generic_names.len() == many.len();
-                    if is_generic {
-                        primitive_link(
-                            f,
-                            PrimitiveType::Tuple,
-                            format_args!(
-                                "({})",
-                                generic_names.iter().map(|s| s.as_str()).join(", ")
-                            ),
-                            cx,
-                        )
-                    } else {
-                        write!(f, "(")?;
-                        for (i, item) in many.iter().enumerate() {
-                            if i != 0 {
-                                write!(f, ", ")?;
-                            }
-                            // Carry `f.alternate()` into this display w/o branching manually.
-                            fmt::Display::fmt(&item.print(cx), f)?;
+            }
+            many => {
+                let generic_names: Vec<Symbol> = many
+                    .iter()
+                    .filter_map(|t| match t {
+                        clean::Generic(name) => Some(*name),
+                        _ => None,
+                    })
+                    .collect();
+                let is_generic = generic_names.len() == many.len();
+                if is_generic {
+                    primitive_link(
+                        f,
+                        PrimitiveType::Tuple,
+                        format_args!("({})", generic_names.iter().map(|s| s.as_str()).join(", ")),
+                        cx,
+                    )
+                } else {
+                    write!(f, "(")?;
+                    for (i, item) in many.iter().enumerate() {
+                        if i != 0 {
+                            write!(f, ", ")?;
                         }
-                        write!(f, ")")
+                        item.print(cx).fmt(f)?;
                     }
+                    write!(f, ")")
                 }
             }
-        }
+        },
         clean::Slice(ref t) => match **t {
             clean::Generic(name) => {
                 primitive_link(f, PrimitiveType::Slice, format_args!("[{name}]"), cx)
             }
             _ => {
                 write!(f, "[")?;
-                fmt::Display::fmt(&t.print(cx), f)?;
+                t.print(cx).fmt(f)?;
                 write!(f, "]")
             }
         },
@@ -1135,7 +1076,7 @@ fn fmt_type<'cx>(
             ),
             _ => {
                 write!(f, "[")?;
-                fmt::Display::fmt(&t.print(cx), f)?;
+                t.print(cx).fmt(f)?;
                 if f.alternate() {
                     write!(f, "; {n}")?;
                 } else {
@@ -1175,7 +1116,7 @@ fn fmt_type<'cx>(
                 }
             } else {
                 primitive_link(f, clean::PrimitiveType::RawPointer, format_args!("*{m} "), cx)?;
-                fmt::Display::fmt(&t.print(cx), f)
+                t.print(cx).fmt(f)
             }
         }
         clean::BorrowedRef { lifetime: ref l, mutability, type_: ref ty } => {
@@ -1216,11 +1157,8 @@ fn fmt_type<'cx>(
             Ok(())
         }
         clean::ImplTrait(ref bounds) => {
-            if f.alternate() {
-                write!(f, "impl {:#}", print_generic_bounds(bounds, cx))
-            } else {
-                write!(f, "impl {}", print_generic_bounds(bounds, cx))
-            }
+            f.write_str("impl ")?;
+            print_generic_bounds(bounds, cx).fmt(f)
         }
         clean::QPath(box clean::QPathData {
             ref assoc,
@@ -1292,8 +1230,7 @@ fn fmt_type<'cx>(
                 write!(f, "{}", assoc.name)
             }?;
 
-            // Carry `f.alternate()` into this display w/o branching manually.
-            fmt::Display::fmt(&assoc.args.print(cx), f)
+            assoc.args.print(cx).fmt(f)
         }
     }
 }
@@ -1302,7 +1239,7 @@ impl clean::Type {
     pub(crate) fn print<'b, 'a: 'b, 'tcx: 'a>(
         &'a self,
         cx: &'a Context<'tcx>,
-    ) -> impl fmt::Display + 'b + Captures<'tcx> {
+    ) -> impl Display + 'b + Captures<'tcx> {
         display_fn(move |f| fmt_type(self, f, false, cx))
     }
 }
@@ -1311,7 +1248,7 @@ impl clean::Path {
     pub(crate) fn print<'b, 'a: 'b, 'tcx: 'a>(
         &'a self,
         cx: &'a Context<'tcx>,
-    ) -> impl fmt::Display + 'b + Captures<'tcx> {
+    ) -> impl Display + 'b + Captures<'tcx> {
         display_fn(move |f| resolved_path(f, self.def_id(), self, false, false, cx))
     }
 }
@@ -1321,20 +1258,18 @@ impl clean::Impl {
         &'a self,
         use_absolute: bool,
         cx: &'a Context<'tcx>,
-    ) -> impl fmt::Display + 'a + Captures<'tcx> {
+    ) -> impl Display + 'a + Captures<'tcx> {
         display_fn(move |f| {
-            if f.alternate() {
-                write!(f, "impl{:#} ", self.generics.print(cx))?;
-            } else {
-                write!(f, "impl{} ", self.generics.print(cx))?;
-            }
+            f.write_str("impl")?;
+            self.generics.print(cx).fmt(f)?;
+            f.write_str(" ")?;
 
             if let Some(ref ty) = self.trait_ {
                 match self.polarity {
                     ty::ImplPolarity::Positive | ty::ImplPolarity::Reservation => {}
                     ty::ImplPolarity::Negative => write!(f, "!")?,
                 }
-                fmt::Display::fmt(&ty.print(cx), f)?;
+                ty.print(cx).fmt(f)?;
                 write!(f, " for ")?;
             }
 
@@ -1359,14 +1294,9 @@ impl clean::Impl {
                 // Hardcoded anchor library/core/src/primitive_docs.rs
                 // Link should match `# Trait implementations`
 
-                let hrtb = bare_fn.print_hrtb_with_space(cx);
-                let unsafety = bare_fn.unsafety.print_with_space();
-                let abi = print_abi_with_space(bare_fn.abi);
-                if f.alternate() {
-                    write!(f, "{hrtb:#}{unsafety}{abi:#}",)?;
-                } else {
-                    write!(f, "{hrtb}{unsafety}{abi}",)?;
-                }
+                print_higher_ranked_params_with_space(&bare_fn.generic_params, cx).fmt(f)?;
+                bare_fn.unsafety.print_with_space().fmt(f)?;
+                print_abi_with_space(bare_fn.abi).fmt(f)?;
                 let ellipsis = if bare_fn.decl.c_variadic { ", ..." } else { "" };
                 primitive_link_fragment(
                     f,
@@ -1386,8 +1316,7 @@ impl clean::Impl {
                 fmt_type(&self.for_, f, use_absolute, cx)?;
             }
 
-            fmt::Display::fmt(&print_where_clause(&self.generics, cx, 0, Ending::Newline), f)?;
-            Ok(())
+            print_where_clause(&self.generics, cx, 0, Ending::Newline).fmt(f)
         })
     }
 }
@@ -1396,16 +1325,11 @@ impl clean::Arguments {
     pub(crate) fn print<'a, 'tcx: 'a>(
         &'a self,
         cx: &'a Context<'tcx>,
-    ) -> impl fmt::Display + 'a + Captures<'tcx> {
+    ) -> impl Display + 'a + Captures<'tcx> {
         display_fn(move |f| {
             for (i, input) in self.values.iter().enumerate() {
                 write!(f, "{}: ", input.name)?;
-
-                if f.alternate() {
-                    write!(f, "{:#}", input.type_.print(cx))?;
-                } else {
-                    write!(f, "{}", input.type_.print(cx))?;
-                }
+                input.type_.print(cx).fmt(f)?;
                 if i + 1 < self.values.len() {
                     write!(f, ", ")?;
                 }
@@ -1415,25 +1339,6 @@ impl clean::Arguments {
     }
 }
 
-impl clean::BareFunctionDecl {
-    fn print_hrtb_with_space<'a, 'tcx: 'a>(
-        &'a self,
-        cx: &'a Context<'tcx>,
-    ) -> impl fmt::Display + 'a + Captures<'tcx> {
-        display_fn(move |f| {
-            if !self.generic_params.is_empty() {
-                write!(
-                    f,
-                    "for&lt;{}&gt; ",
-                    comma_sep(self.generic_params.iter().map(|g| g.print(cx)), true)
-                )
-            } else {
-                Ok(())
-            }
-        })
-    }
-}
-
 // Implements Write but only counts the bytes "written".
 struct WriteCounter(usize);
 
@@ -1447,7 +1352,7 @@ impl std::fmt::Write for WriteCounter {
 // Implements Display by emitting the given number of spaces.
 struct Indent(usize);
 
-impl fmt::Display for Indent {
+impl Display for Indent {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
         (0..self.0).for_each(|_| {
             f.write_char(' ').unwrap();
@@ -1460,7 +1365,7 @@ impl clean::FnDecl {
     pub(crate) fn print<'b, 'a: 'b, 'tcx: 'a>(
         &'a self,
         cx: &'a Context<'tcx>,
-    ) -> impl fmt::Display + 'b + Captures<'tcx> {
+    ) -> impl Display + 'b + Captures<'tcx> {
         display_fn(move |f| {
             let ellipsis = if self.c_variadic { ", ..." } else { "" };
             if f.alternate() {
@@ -1494,7 +1399,7 @@ impl clean::FnDecl {
         header_len: usize,
         indent: usize,
         cx: &'a Context<'tcx>,
-    ) -> impl fmt::Display + 'a + Captures<'tcx> {
+    ) -> impl Display + 'a + Captures<'tcx> {
         display_fn(move |f| {
             // First, generate the text form of the declaration, with no line wrapping, and count the bytes.
             let mut counter = WriteCounter(0);
@@ -1554,7 +1459,7 @@ impl clean::FnDecl {
                     }
                     clean::SelfExplicit(ref typ) => {
                         write!(f, "self: ")?;
-                        fmt::Display::fmt(&typ.print(cx), f)?;
+                        typ.print(cx).fmt(f)?;
                     }
                 }
             } else {
@@ -1562,7 +1467,7 @@ impl clean::FnDecl {
                     write!(f, "const ")?;
                 }
                 write!(f, "{}: ", input.name)?;
-                fmt::Display::fmt(&input.type_.print(cx), f)?;
+                input.type_.print(cx).fmt(f)?;
             }
         }
 
@@ -1578,14 +1483,13 @@ impl clean::FnDecl {
             Some(n) => write!(f, "\n{})", Indent(n))?,
         };
 
-        fmt::Display::fmt(&self.print_output(cx), f)?;
-        Ok(())
+        self.print_output(cx).fmt(f)
     }
 
     fn print_output<'a, 'tcx: 'a>(
         &'a self,
         cx: &'a Context<'tcx>,
-    ) -> impl fmt::Display + 'a + Captures<'tcx> {
+    ) -> impl Display + 'a + Captures<'tcx> {
         display_fn(move |f| match &self.output {
             clean::Tuple(tys) if tys.is_empty() => Ok(()),
             ty if f.alternate() => {
@@ -1600,7 +1504,7 @@ pub(crate) fn visibility_print_with_space<'a, 'tcx: 'a>(
     visibility: Option<ty::Visibility<DefId>>,
     item_did: ItemId,
     cx: &'a Context<'tcx>,
-) -> impl fmt::Display + 'a + Captures<'tcx> {
+) -> impl Display + 'a + Captures<'tcx> {
     use std::fmt::Write as _;
 
     let to_print: Cow<'static, str> = match visibility {
@@ -1648,7 +1552,7 @@ pub(crate) fn visibility_to_src_with_space<'a, 'tcx: 'a>(
     visibility: Option<ty::Visibility<DefId>>,
     tcx: TyCtxt<'tcx>,
     item_did: DefId,
-) -> impl fmt::Display + 'a + Captures<'tcx> {
+) -> impl Display + 'a + Captures<'tcx> {
     let to_print: Cow<'static, str> = match visibility {
         None => "".into(),
         Some(ty::Visibility::Public) => "pub ".into(),
@@ -1727,7 +1631,7 @@ impl clean::Import {
     pub(crate) fn print<'a, 'tcx: 'a>(
         &'a self,
         cx: &'a Context<'tcx>,
-    ) -> impl fmt::Display + 'a + Captures<'tcx> {
+    ) -> impl Display + 'a + Captures<'tcx> {
         display_fn(move |f| match self.kind {
             clean::ImportKind::Simple(name) => {
                 if name == self.source.path.last() {
@@ -1751,7 +1655,7 @@ impl clean::ImportSource {
     pub(crate) fn print<'a, 'tcx: 'a>(
         &'a self,
         cx: &'a Context<'tcx>,
-    ) -> impl fmt::Display + 'a + Captures<'tcx> {
+    ) -> impl Display + 'a + Captures<'tcx> {
         display_fn(move |f| match self.did {
             Some(did) => resolved_path(f, did, &self.path, true, false, cx),
             _ => {
@@ -1779,29 +1683,19 @@ impl clean::TypeBinding {
     pub(crate) fn print<'a, 'tcx: 'a>(
         &'a self,
         cx: &'a Context<'tcx>,
-    ) -> impl fmt::Display + 'a + Captures<'tcx> {
+    ) -> impl Display + 'a + Captures<'tcx> {
         display_fn(move |f| {
             f.write_str(self.assoc.name.as_str())?;
-            if f.alternate() {
-                write!(f, "{:#}", self.assoc.args.print(cx))?;
-            } else {
-                write!(f, "{}", self.assoc.args.print(cx))?;
-            }
+            self.assoc.args.print(cx).fmt(f)?;
             match self.kind {
                 clean::TypeBindingKind::Equality { ref term } => {
-                    if f.alternate() {
-                        write!(f, " = {:#}", term.print(cx))?;
-                    } else {
-                        write!(f, " = {}", term.print(cx))?;
-                    }
+                    f.write_str(" = ")?;
+                    term.print(cx).fmt(f)?;
                 }
                 clean::TypeBindingKind::Constraint { ref bounds } => {
                     if !bounds.is_empty() {
-                        if f.alternate() {
-                            write!(f, ": {:#}", print_generic_bounds(bounds, cx))?;
-                        } else {
-                            write!(f, ": {}", print_generic_bounds(bounds, cx))?;
-                        }
+                        f.write_str(": ")?;
+                        print_generic_bounds(bounds, cx).fmt(f)?;
                     }
                 }
             }
@@ -1810,7 +1704,7 @@ impl clean::TypeBinding {
     }
 }
 
-pub(crate) fn print_abi_with_space(abi: Abi) -> impl fmt::Display {
+pub(crate) fn print_abi_with_space(abi: Abi) -> impl Display {
     display_fn(move |f| {
         let quot = if f.alternate() { "\"" } else { "&quot;" };
         match abi {
@@ -1828,34 +1722,32 @@ impl clean::GenericArg {
     pub(crate) fn print<'a, 'tcx: 'a>(
         &'a self,
         cx: &'a Context<'tcx>,
-    ) -> impl fmt::Display + 'a + Captures<'tcx> {
+    ) -> impl Display + 'a + Captures<'tcx> {
         display_fn(move |f| match self {
-            clean::GenericArg::Lifetime(lt) => fmt::Display::fmt(&lt.print(), f),
-            clean::GenericArg::Type(ty) => fmt::Display::fmt(&ty.print(cx), f),
-            clean::GenericArg::Const(ct) => fmt::Display::fmt(&ct.print(cx.tcx()), f),
-            clean::GenericArg::Infer => fmt::Display::fmt("_", f),
+            clean::GenericArg::Lifetime(lt) => lt.print().fmt(f),
+            clean::GenericArg::Type(ty) => ty.print(cx).fmt(f),
+            clean::GenericArg::Const(ct) => ct.print(cx.tcx()).fmt(f),
+            clean::GenericArg::Infer => Display::fmt("_", f),
         })
     }
 }
 
-impl clean::types::Term {
+impl clean::Term {
     pub(crate) fn print<'a, 'tcx: 'a>(
         &'a self,
         cx: &'a Context<'tcx>,
-    ) -> impl fmt::Display + 'a + Captures<'tcx> {
+    ) -> impl Display + 'a + Captures<'tcx> {
         display_fn(move |f| match self {
-            clean::types::Term::Type(ty) => fmt::Display::fmt(&ty.print(cx), f),
-            clean::types::Term::Constant(ct) => fmt::Display::fmt(&ct.print(cx.tcx()), f),
+            clean::Term::Type(ty) => ty.print(cx).fmt(f),
+            clean::Term::Constant(ct) => ct.print(cx.tcx()).fmt(f),
         })
     }
 }
 
-pub(crate) fn display_fn(
-    f: impl FnOnce(&mut fmt::Formatter<'_>) -> fmt::Result,
-) -> impl fmt::Display {
+pub(crate) fn display_fn(f: impl FnOnce(&mut fmt::Formatter<'_>) -> fmt::Result) -> impl Display {
     struct WithFormatter<F>(Cell<Option<F>>);
 
-    impl<F> fmt::Display for WithFormatter<F>
+    impl<F> Display for WithFormatter<F>
     where
         F: FnOnce(&mut fmt::Formatter<'_>) -> fmt::Result,
     {
diff --git a/src/librustdoc/html/static/css/rustdoc.css b/src/librustdoc/html/static/css/rustdoc.css
index c01a25534f9..9993dfb1d8c 100644
--- a/src/librustdoc/html/static/css/rustdoc.css
+++ b/src/librustdoc/html/static/css/rustdoc.css
@@ -1941,13 +1941,8 @@ in src-script.js and main.js
 		   pixels to avoid overflowing the topbar when the user sets a bigger
 		   font size. */
 		font-size: 24px;
-	}
-
-	.mobile-topbar h2 a {
-		display: block;
-		text-overflow: ellipsis;
-		overflow: hidden;
 		white-space: nowrap;
+		text-overflow: ellipsis;
 	}
 
 	.mobile-topbar .logo-container > img {
diff --git a/src/librustdoc/html/static/js/main.js b/src/librustdoc/html/static/js/main.js
index b46701b55ea..b26efb75ff6 100644
--- a/src/librustdoc/html/static/js/main.js
+++ b/src/librustdoc/html/static/js/main.js
@@ -45,7 +45,7 @@ function setMobileTopbar() {
         const mobileTitle = document.createElement("h2");
         mobileTitle.className = "location";
         if (hasClass(document.querySelector(".rustdoc"), "crate")) {
-            mobileTitle.innerText = `Crate ${window.currentCrate}`;
+            mobileTitle.innerHTML = `Crate <a href="#">${window.currentCrate}</a>`;
         } else if (locationTitle) {
             mobileTitle.innerHTML = locationTitle.innerHTML;
         }
diff --git a/src/tools/clippy/src/driver.rs b/src/tools/clippy/src/driver.rs
index bdf1cf0a224..85867d1511d 100644
--- a/src/tools/clippy/src/driver.rs
+++ b/src/tools/clippy/src/driver.rs
@@ -28,7 +28,6 @@ use std::fs::read_to_string;
 use std::ops::Deref;
 use std::path::Path;
 use std::process::exit;
-use std::string::ToString;
 
 use anstream::println;
 
diff --git a/src/tools/compiletest/Cargo.toml b/src/tools/compiletest/Cargo.toml
index 31c6353e675..62d0fcc1a60 100644
--- a/src/tools/compiletest/Cargo.toml
+++ b/src/tools/compiletest/Cargo.toml
@@ -34,7 +34,7 @@ libc = "0.2"
 miow = "0.6"
 
 [target.'cfg(windows)'.dependencies.windows]
-version = "0.48.0"
+version = "0.52.0"
 features = [
     "Win32_Foundation",
     "Win32_System_Diagnostics_Debug",
diff --git a/src/tools/miri/tests/fail/shims/fs/isolated_file.stderr b/src/tools/miri/tests/fail/shims/fs/isolated_file.stderr
index ec670c4a391..1f08649428a 100644
--- a/src/tools/miri/tests/fail/shims/fs/isolated_file.stderr
+++ b/src/tools/miri/tests/fail/shims/fs/isolated_file.stderr
@@ -11,8 +11,9 @@ LL |         let fd = cvt_r(|| unsafe { open64(path.as_ptr(), flags, opts.mode a
    = note: inside `std::sys::pal::PLATFORM::cvt_r::<i32, {closure@std::sys::pal::PLATFORM::fs::File::open_c::{closure#0}}>` at RUSTLIB/std/src/sys/pal/PLATFORM/mod.rs:LL:CC
    = note: inside `std::sys::pal::PLATFORM::fs::File::open_c` at RUSTLIB/std/src/sys/pal/PLATFORM/fs.rs:LL:CC
    = note: inside closure at RUSTLIB/std/src/sys/pal/PLATFORM/fs.rs:LL:CC
-   = note: inside `std::sys::pal::PLATFORM::small_c_string::run_with_cstr::<std::sys::pal::PLATFORM::fs::File, {closure@std::sys::pal::PLATFORM::fs::File::open::{closure#0}}>` at RUSTLIB/std/src/sys/pal/PLATFORM/small_c_string.rs:LL:CC
-   = note: inside `std::sys::pal::PLATFORM::small_c_string::run_path_with_cstr::<std::sys::pal::PLATFORM::fs::File, {closure@std::sys::pal::PLATFORM::fs::File::open::{closure#0}}>` at RUSTLIB/std/src/sys/pal/PLATFORM/small_c_string.rs:LL:CC
+   = note: inside `std::sys::pal::PLATFORM::small_c_string::run_with_cstr_stack::<std::sys::pal::PLATFORM::fs::File>` at RUSTLIB/std/src/sys/pal/PLATFORM/small_c_string.rs:LL:CC
+   = note: inside `std::sys::pal::PLATFORM::small_c_string::run_with_cstr::<std::sys::pal::PLATFORM::fs::File>` at RUSTLIB/std/src/sys/pal/PLATFORM/small_c_string.rs:LL:CC
+   = note: inside `std::sys::pal::PLATFORM::small_c_string::run_path_with_cstr::<std::sys::pal::PLATFORM::fs::File>` at RUSTLIB/std/src/sys/pal/PLATFORM/small_c_string.rs:LL:CC
    = note: inside `std::sys::pal::PLATFORM::fs::File::open` at RUSTLIB/std/src/sys/pal/PLATFORM/fs.rs:LL:CC
    = note: inside `std::fs::OpenOptions::_open` at RUSTLIB/std/src/fs.rs:LL:CC
    = note: inside `std::fs::OpenOptions::open::<&std::path::Path>` at RUSTLIB/std/src/fs.rs:LL:CC
diff --git a/src/tools/miri/tests/fail/tls/tls_static_dealloc.rs b/src/tools/miri/tests/fail/tls/tls_static_dealloc.rs
index 762a8d85314..d47a05d8475 100644
--- a/src/tools/miri/tests/fail/tls/tls_static_dealloc.rs
+++ b/src/tools/miri/tests/fail/tls/tls_static_dealloc.rs
@@ -1,8 +1,8 @@
 //! Ensure that thread-local statics get deallocated when the thread dies.
 
 #![feature(thread_local)]
-// FIXME: Use `SyncUnsafeCell` instead of allowing `static_mut_ref` lint
-#![allow(static_mut_ref)]
+// FIXME: Use `SyncUnsafeCell` instead of allowing `static_mut_refs` lint
+#![allow(static_mut_refs)]
 
 #[thread_local]
 static mut TLS: u8 = 0;
diff --git a/src/tools/miri/tests/pass/static_mut.rs b/src/tools/miri/tests/pass/static_mut.rs
index c1e58b70adb..6b0c0297726 100644
--- a/src/tools/miri/tests/pass/static_mut.rs
+++ b/src/tools/miri/tests/pass/static_mut.rs
@@ -1,7 +1,7 @@
 static mut FOO: i32 = 42;
 
-// FIXME: Use `SyncUnsafeCell` instead of allowing `static_mut_ref` lint
-#[allow(static_mut_ref)]
+// FIXME: Use `SyncUnsafeCell` instead of allowing `static_mut_refs` lint
+#[allow(static_mut_refs)]
 static BAR: Foo = Foo(unsafe { &FOO as *const _ });
 
 #[allow(dead_code)]
diff --git a/src/tools/miri/tests/pass/tls/tls_static.rs b/src/tools/miri/tests/pass/tls/tls_static.rs
index 9be00af47aa..fea5bb1db5e 100644
--- a/src/tools/miri/tests/pass/tls/tls_static.rs
+++ b/src/tools/miri/tests/pass/tls/tls_static.rs
@@ -8,8 +8,8 @@
 //! test, we also check that thread-locals act as per-thread statics.
 
 #![feature(thread_local)]
-// FIXME: Use `SyncUnsafeCell` instead of allowing `static_mut_ref` lint
-#![allow(static_mut_ref)]
+// FIXME: Use `SyncUnsafeCell` instead of allowing `static_mut_refs` lint
+#![allow(static_mut_refs)]
 
 use std::thread;
 
diff --git a/src/tools/opt-dist/Cargo.toml b/src/tools/opt-dist/Cargo.toml
index 9e852b0645a..eb6f889a6f3 100644
--- a/src/tools/opt-dist/Cargo.toml
+++ b/src/tools/opt-dist/Cargo.toml
@@ -21,6 +21,6 @@ serde = { version = "1", features = ["derive"] }
 serde_json = "1"
 glob = "0.3"
 tempfile = "3.5"
-derive_builder = "0.12"
+derive_builder = "0.20"
 clap = { version = "4", features = ["derive"] }
 tabled = { version = "0.13", default-features = false, features = ["std"] }
diff --git a/src/tools/rust-analyzer/.github/rust.json b/src/tools/rust-analyzer/.github/rust.json
new file mode 100644
index 00000000000..ddaa1b0824b
--- /dev/null
+++ b/src/tools/rust-analyzer/.github/rust.json
@@ -0,0 +1,33 @@
+{
+    "problemMatcher": [
+        {
+            "owner": "rustfmt",
+            "severity": "warning",
+            "pattern": [
+                {
+                    "regexp": "^(Diff in (.+)) at line (\\d+):$",
+                    "message": 1,
+                    "file": 2,
+                    "line": 3
+                }
+            ]
+        },
+        {
+            "owner": "clippy",
+            "pattern": [
+                {
+                    "regexp": "^(?:\\x1b\\[[\\d;]+m)*(warning|warn|error)(?:\\x1b\\[[\\d;]+m)*(\\[(.*)\\])?(?:\\x1b\\[[\\d;]+m)*:(?:\\x1b\\[[\\d;]+m)* ([^\\x1b]*)(?:\\x1b\\[[\\d;]+m)*$",
+                    "severity": 1,
+                    "message": 4,
+                    "code": 3
+                },
+                {
+                    "regexp": "^(?:\\x1b\\[[\\d;]+m)*\\s*(?:\\x1b\\[[\\d;]+m)*\\s*--> (?:\\x1b\\[[\\d;]+m)*(.*):(\\d*):(\\d*)(?:\\x1b\\[[\\d;]+m)*$",
+                    "file": 1,
+                    "line": 2,
+                    "column": 3
+                }
+            ]
+        }
+    ]
+}
diff --git a/src/tools/rust-analyzer/.github/workflows/autopublish.yaml b/src/tools/rust-analyzer/.github/workflows/autopublish.yaml
index 9a5015005b3..4b97637088c 100644
--- a/src/tools/rust-analyzer/.github/workflows/autopublish.yaml
+++ b/src/tools/rust-analyzer/.github/workflows/autopublish.yaml
@@ -15,7 +15,7 @@ jobs:
     runs-on: ubuntu-latest
     steps:
       - name: Checkout repository
-        uses: actions/checkout@v3
+        uses: actions/checkout@v4
         with:
           fetch-depth: 0
 
diff --git a/src/tools/rust-analyzer/.github/workflows/ci.yaml b/src/tools/rust-analyzer/.github/workflows/ci.yaml
index 964be478fa3..62fbd57abc1 100644
--- a/src/tools/rust-analyzer/.github/workflows/ci.yaml
+++ b/src/tools/rust-analyzer/.github/workflows/ci.yaml
@@ -27,7 +27,7 @@ jobs:
       typescript: ${{ steps.filter.outputs.typescript }}
       proc_macros: ${{ steps.filter.outputs.proc_macros }}
     steps:
-      - uses: actions/checkout@v3
+      - uses: actions/checkout@v4
       - uses: dorny/paths-filter@1441771bbfdd59dcd748680ee64ebd8faab1a242
         id: filter
         with:
@@ -56,7 +56,7 @@ jobs:
 
     steps:
       - name: Checkout repository
-        uses: actions/checkout@v3
+        uses: actions/checkout@v4
         with:
           ref: ${{ github.event.pull_request.head.sha }}
 
@@ -65,6 +65,10 @@ jobs:
           rustup update --no-self-update ${{ env.RUST_CHANNEL }}
           rustup component add --toolchain ${{ env.RUST_CHANNEL }} rustfmt rust-src
           rustup default ${{ env.RUST_CHANNEL }}
+      # https://github.com/actions-rust-lang/setup-rust-toolchain/blob/main/rust.json
+      - name: Install Rust Problem Matcher
+        if: matrix.os == 'ubuntu-latest'
+        run: echo "::add-matcher::.github/rust.json"
 
       - name: Cache Dependencies
         uses: Swatinem/rust-cache@988c164c3d0e93c4dbab36aaf5bbeb77425b2894
@@ -107,6 +111,10 @@ jobs:
         if: matrix.os == 'windows-latest'
         run: cargo clippy --all-targets -- -D clippy::disallowed_macros -D clippy::dbg_macro -D clippy::todo -D clippy::print_stdout -D clippy::print_stderr
 
+      - name: rustfmt
+        if: matrix.os == 'ubuntu-latest'
+        run: cargo fmt -- --check
+
   # Weird targets to catch non-portable code
   rust-cross:
     if: github.repository == 'rust-lang/rust-analyzer'
@@ -121,7 +129,7 @@ jobs:
 
     steps:
       - name: Checkout repository
-        uses: actions/checkout@v3
+        uses: actions/checkout@v4
 
       - name: Install Rust toolchain
         run: |
@@ -153,13 +161,13 @@ jobs:
 
     steps:
       - name: Checkout repository
-        uses: actions/checkout@v3
+        uses: actions/checkout@v4
         if: needs.changes.outputs.typescript == 'true'
 
       - name: Install Nodejs
-        uses: actions/setup-node@v3
+        uses: actions/setup-node@v4
         with:
-          node-version: 16
+          node-version: 18
         if: needs.changes.outputs.typescript == 'true'
 
       - name: Install xvfb
diff --git a/src/tools/rust-analyzer/.github/workflows/fuzz.yml b/src/tools/rust-analyzer/.github/workflows/fuzz.yml
index 5af8aa1f77a..f88c7f95d5c 100644
--- a/src/tools/rust-analyzer/.github/workflows/fuzz.yml
+++ b/src/tools/rust-analyzer/.github/workflows/fuzz.yml
@@ -27,7 +27,7 @@ jobs:
 
     steps:
       - name: Checkout repository
-        uses: actions/checkout@v3
+        uses: actions/checkout@v4
         with:
           ref: ${{ github.event.pull_request.head.sha }}
           fetch-depth: 1
diff --git a/src/tools/rust-analyzer/.github/workflows/metrics.yaml b/src/tools/rust-analyzer/.github/workflows/metrics.yaml
index e6a9917a0bf..be9f504e599 100644
--- a/src/tools/rust-analyzer/.github/workflows/metrics.yaml
+++ b/src/tools/rust-analyzer/.github/workflows/metrics.yaml
@@ -21,7 +21,7 @@ jobs:
           rustup component add rustfmt rust-src
           rustup default stable
       - name: Cache cargo
-        uses: actions/cache@v3
+        uses: actions/cache@v4
         with:
           path: |
             ~/.cargo/bin/
@@ -36,10 +36,10 @@ jobs:
 
     steps:
       - name: Checkout repository
-        uses: actions/checkout@v3
+        uses: actions/checkout@v4
 
       - name: Restore cargo cache
-        uses: actions/cache@v3
+        uses: actions/cache@v4
         with:
           path: |
             ~/.cargo/bin/
@@ -52,7 +52,7 @@ jobs:
         run: cargo xtask metrics build
 
       - name: Cache target
-        uses: actions/cache@v3
+        uses: actions/cache@v4
         with:
           path: target/
           key: ${{ runner.os }}-target-${{ github.sha }}
@@ -73,10 +73,10 @@ jobs:
 
     steps:
       - name: Checkout repository
-        uses: actions/checkout@v3
+        uses: actions/checkout@v4
 
       - name: Restore cargo cache
-        uses: actions/cache@v3
+        uses: actions/cache@v4
         with:
           path: |
             ~/.cargo/bin/
@@ -86,7 +86,7 @@ jobs:
           key: ${{ runner.os }}-cargo-${{ github.sha }}
 
       - name: Restore target cache
-        uses: actions/cache@v3
+        uses: actions/cache@v4
         with:
           path: target/
           key: ${{ runner.os }}-target-${{ github.sha }}
@@ -106,7 +106,7 @@ jobs:
     needs: [build_metrics, other_metrics]
     steps:
       - name: Checkout repository
-        uses: actions/checkout@v3
+        uses: actions/checkout@v4
 
       - name: Download build metrics
         uses: actions/download-artifact@v3
diff --git a/src/tools/rust-analyzer/.github/workflows/publish-libs.yaml b/src/tools/rust-analyzer/.github/workflows/publish-libs.yaml
index 6d026c9ad91..862373ec1cc 100644
--- a/src/tools/rust-analyzer/.github/workflows/publish-libs.yaml
+++ b/src/tools/rust-analyzer/.github/workflows/publish-libs.yaml
@@ -13,7 +13,7 @@ jobs:
     runs-on: ubuntu-latest
     steps:
       - name: Checkout repository
-        uses: actions/checkout@v3
+        uses: actions/checkout@v4
         with:
           fetch-depth: 0
 
diff --git a/src/tools/rust-analyzer/.github/workflows/release.yaml b/src/tools/rust-analyzer/.github/workflows/release.yaml
index 9077a9ac21e..adb1c850516 100644
--- a/src/tools/rust-analyzer/.github/workflows/release.yaml
+++ b/src/tools/rust-analyzer/.github/workflows/release.yaml
@@ -59,7 +59,7 @@ jobs:
 
     steps:
       - name: Checkout repository
-        uses: actions/checkout@v3
+        uses: actions/checkout@v4
         with:
           fetch-depth: ${{ env.FETCH_DEPTH }}
 
@@ -78,9 +78,9 @@ jobs:
           rustup component add rust-src
 
       - name: Install Node.js
-        uses: actions/setup-node@v3
+        uses: actions/setup-node@v4
         with:
-          node-version: 16
+          node-version: 18
 
       - name: Update apt repositories
         if: matrix.target == 'aarch64-unknown-linux-gnu' || matrix.target == 'arm-unknown-linux-gnueabihf'
@@ -154,7 +154,7 @@ jobs:
         run: apk add --no-cache git clang lld musl-dev nodejs npm
 
       - name: Checkout repository
-        uses: actions/checkout@v3
+        uses: actions/checkout@v4
         with:
           fetch-depth: ${{ env.FETCH_DEPTH }}
 
@@ -188,9 +188,9 @@ jobs:
     needs: ["dist", "dist-x86_64-unknown-linux-musl"]
     steps:
       - name: Install Nodejs
-        uses: actions/setup-node@v3
+        uses: actions/setup-node@v4
         with:
-          node-version: 16
+          node-version: 18
 
       - run: echo "TAG=$(date --iso -u)" >> $GITHUB_ENV
         if: github.ref == 'refs/heads/release'
@@ -199,7 +199,7 @@ jobs:
       - run: 'echo "TAG: $TAG"'
 
       - name: Checkout repository
-        uses: actions/checkout@v3
+        uses: actions/checkout@v4
         with:
           fetch-depth: ${{ env.FETCH_DEPTH }}
 
diff --git a/src/tools/rust-analyzer/.github/workflows/rustdoc.yaml b/src/tools/rust-analyzer/.github/workflows/rustdoc.yaml
index 05f3e254e5f..12a1a791fda 100644
--- a/src/tools/rust-analyzer/.github/workflows/rustdoc.yaml
+++ b/src/tools/rust-analyzer/.github/workflows/rustdoc.yaml
@@ -17,7 +17,7 @@ jobs:
 
     steps:
     - name: Checkout repository
-      uses: actions/checkout@v3
+      uses: actions/checkout@v4
 
     - name: Install Rust toolchain
       run: rustup update --no-self-update stable
diff --git a/src/tools/rust-analyzer/Cargo.lock b/src/tools/rust-analyzer/Cargo.lock
index dc2bf3a7694..7b29d7bb798 100644
--- a/src/tools/rust-analyzer/Cargo.lock
+++ b/src/tools/rust-analyzer/Cargo.lock
@@ -1329,6 +1329,7 @@ dependencies = [
  "paths",
  "proc-macro-api",
  "proc-macro-test",
+ "ra-ap-rustc_lexer",
  "span",
  "stdx",
  "tt",
@@ -1470,12 +1471,12 @@ dependencies = [
 
 [[package]]
 name = "ra-ap-rustc_index"
-version = "0.36.0"
+version = "0.37.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f8a41dee58608b1fc93779ea365edaa70ac9927e3335ae914b675be0fa063cd7"
+checksum = "df5a0ba0d08af366cf235dbe8eb7226cced7a4fe502c98aa434ccf416defd746"
 dependencies = [
  "arrayvec",
- "ra-ap-rustc_index_macros 0.36.0",
+ "ra-ap-rustc_index_macros 0.37.0",
  "smallvec",
 ]
 
@@ -1493,9 +1494,9 @@ dependencies = [
 
 [[package]]
 name = "ra-ap-rustc_index_macros"
-version = "0.36.0"
+version = "0.37.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "fbfe98def54c4337a2f7d8233850bd5d5349972b185fe8a0db2b979164b30ed8"
+checksum = "1971ebf9a701e0e68387c264a32517dcb4861ad3a4862f2e2803c1121ade20d5"
 dependencies = [
  "proc-macro2",
  "quote",
@@ -1525,11 +1526,11 @@ dependencies = [
 
 [[package]]
 name = "ra-ap-rustc_pattern_analysis"
-version = "0.36.0"
+version = "0.37.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b5529bffec7530b4a3425640bfdfd9b95d87c4c620f740266c0de6572561aab4"
+checksum = "2c3c0e7ca9c5bdc66e3b590688e237a22ac47a48e4eac7f46b05b2abbfaf0abd"
 dependencies = [
- "ra-ap-rustc_index 0.36.0",
+ "ra-ap-rustc_index 0.37.0",
  "rustc-hash",
  "rustc_apfloat",
  "smallvec",
diff --git a/src/tools/rust-analyzer/Cargo.toml b/src/tools/rust-analyzer/Cargo.toml
index 2b81f7b11b2..49c7d369190 100644
--- a/src/tools/rust-analyzer/Cargo.toml
+++ b/src/tools/rust-analyzer/Cargo.toml
@@ -84,7 +84,7 @@ ra-ap-rustc_lexer = { version = "0.35.0", default-features = false }
 ra-ap-rustc_parse_format = { version = "0.35.0", default-features = false }
 ra-ap-rustc_index = { version = "0.35.0", default-features = false }
 ra-ap-rustc_abi = { version = "0.35.0", default-features = false }
-ra-ap-rustc_pattern_analysis = { version = "0.36.0", default-features = false }
+ra-ap-rustc_pattern_analysis = { version = "0.37.0", default-features = false }
 
 # local crates that aren't published to crates.io. These should not have versions.
 sourcegen = { path = "./crates/sourcegen" }
diff --git a/src/tools/rust-analyzer/crates/base-db/src/input.rs b/src/tools/rust-analyzer/crates/base-db/src/input.rs
index 9560826e373..a817cd0c3ac 100644
--- a/src/tools/rust-analyzer/crates/base-db/src/input.rs
+++ b/src/tools/rust-analyzer/crates/base-db/src/input.rs
@@ -11,7 +11,6 @@ use std::{fmt, mem, ops, str::FromStr};
 use cfg::CfgOptions;
 use la_arena::{Arena, Idx, RawIdx};
 use rustc_hash::{FxHashMap, FxHashSet};
-use semver::Version;
 use syntax::SmolStr;
 use triomphe::Arc;
 use vfs::{file_set::FileSet, AbsPathBuf, AnchoredPath, FileId, VfsPath};
@@ -243,6 +242,7 @@ impl CrateDisplayName {
         CrateDisplayName { crate_name, canonical_name }
     }
 }
+
 pub type TargetLayoutLoadResult = Result<Arc<str>, Arc<str>>;
 
 #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
@@ -291,71 +291,6 @@ pub struct CrateData {
     pub dependencies: Vec<Dependency>,
     pub origin: CrateOrigin,
     pub is_proc_macro: bool,
-    // FIXME: These things should not be per crate! These are more per workspace crate graph level
-    // things. This info does need to be somewhat present though as to prevent deduplication from
-    // happening across different workspaces with different layouts.
-    pub target_layout: TargetLayoutLoadResult,
-    pub toolchain: Option<Version>,
-}
-
-impl CrateData {
-    /// Check if [`other`] is almost equal to [`self`] ignoring `CrateOrigin` value.
-    pub fn eq_ignoring_origin_and_deps(&self, other: &CrateData, ignore_dev_deps: bool) -> bool {
-        // This method has some obscure bits. These are mostly there to be compliant with
-        // some patches. References to the patches are given.
-        if self.root_file_id != other.root_file_id {
-            return false;
-        }
-
-        if self.display_name != other.display_name {
-            return false;
-        }
-
-        if self.is_proc_macro != other.is_proc_macro {
-            return false;
-        }
-
-        if self.edition != other.edition {
-            return false;
-        }
-
-        if self.version != other.version {
-            return false;
-        }
-
-        let mut opts = self.cfg_options.difference(&other.cfg_options);
-        if let Some(it) = opts.next() {
-            // Don't care if rust_analyzer CfgAtom is the only cfg in the difference set of self's and other's cfgs.
-            // https://github.com/rust-lang/rust-analyzer/blob/0840038f02daec6ba3238f05d8caa037d28701a0/crates/project-model/src/workspace.rs#L894
-            if it.to_string() != "rust_analyzer" {
-                return false;
-            }
-
-            if opts.next().is_some() {
-                return false;
-            }
-        }
-
-        if self.env != other.env {
-            return false;
-        }
-
-        let slf_deps = self.dependencies.iter();
-        let other_deps = other.dependencies.iter();
-
-        if ignore_dev_deps {
-            return slf_deps
-                .clone()
-                .filter(|it| it.kind != DependencyKind::Dev)
-                .eq(other_deps.clone().filter(|it| it.kind != DependencyKind::Dev));
-        }
-
-        slf_deps.eq(other_deps)
-    }
-
-    pub fn channel(&self) -> Option<ReleaseChannel> {
-        self.toolchain.as_ref().and_then(|v| ReleaseChannel::from_str(&v.pre))
-    }
 }
 
 #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
@@ -398,32 +333,22 @@ pub enum DependencyKind {
 pub struct Dependency {
     pub crate_id: CrateId,
     pub name: CrateName,
-    kind: DependencyKind,
     prelude: bool,
 }
 
 impl Dependency {
-    pub fn new(name: CrateName, crate_id: CrateId, kind: DependencyKind) -> Self {
-        Self { name, crate_id, prelude: true, kind }
+    pub fn new(name: CrateName, crate_id: CrateId) -> Self {
+        Self { name, crate_id, prelude: true }
     }
 
-    pub fn with_prelude(
-        name: CrateName,
-        crate_id: CrateId,
-        prelude: bool,
-        kind: DependencyKind,
-    ) -> Self {
-        Self { name, crate_id, prelude, kind }
+    pub fn with_prelude(name: CrateName, crate_id: CrateId, prelude: bool) -> Self {
+        Self { name, crate_id, prelude }
     }
 
     /// Whether this dependency is to be added to the depending crate's extern prelude.
     pub fn is_prelude(&self) -> bool {
         self.prelude
     }
-
-    pub fn kind(&self) -> DependencyKind {
-        self.kind
-    }
 }
 
 impl CrateGraph {
@@ -438,8 +363,6 @@ impl CrateGraph {
         env: Env,
         is_proc_macro: bool,
         origin: CrateOrigin,
-        target_layout: Result<Arc<str>, Arc<str>>,
-        toolchain: Option<Version>,
     ) -> CrateId {
         let data = CrateData {
             root_file_id,
@@ -451,9 +374,7 @@ impl CrateGraph {
             env,
             dependencies: Vec::new(),
             origin,
-            target_layout,
             is_proc_macro,
-            toolchain,
         };
         self.arena.alloc(data)
     }
@@ -523,6 +444,10 @@ impl CrateGraph {
         self.arena.is_empty()
     }
 
+    pub fn len(&self) -> usize {
+        self.arena.len()
+    }
+
     pub fn iter(&self) -> impl Iterator<Item = CrateId> + '_ {
         self.arena.iter().map(|(idx, _)| idx)
     }
@@ -623,13 +548,17 @@ impl CrateGraph {
     ///
     /// This will deduplicate the crates of the graph where possible.
     /// Note that for deduplication to fully work, `self`'s crate dependencies must be sorted by crate id.
-    /// If the crate dependencies were sorted, the resulting graph from this `extend` call will also have the crate dependencies sorted.
+    /// If the crate dependencies were sorted, the resulting graph from this `extend` call will also
+    /// have the crate dependencies sorted.
+    ///
+    /// Returns a mapping from `other`'s crate ids to the new crate ids in `self`.
     pub fn extend(
         &mut self,
         mut other: CrateGraph,
         proc_macros: &mut ProcMacroPaths,
-        on_finished: impl FnOnce(&FxHashMap<CrateId, CrateId>),
-    ) {
+        merge: impl Fn((CrateId, &mut CrateData), (CrateId, &CrateData)) -> bool,
+    ) -> FxHashMap<CrateId, CrateId> {
+        let m = self.len();
         let topo = other.crates_in_topological_order();
         let mut id_map: FxHashMap<CrateId, CrateId> = FxHashMap::default();
         for topo in topo {
@@ -637,51 +566,21 @@ impl CrateGraph {
 
             crate_data.dependencies.iter_mut().for_each(|dep| dep.crate_id = id_map[&dep.crate_id]);
             crate_data.dependencies.sort_by_key(|dep| dep.crate_id);
-            let res = self.arena.iter().find_map(|(id, data)| {
-                match (&data.origin, &crate_data.origin) {
-                    (a, b) if a == b => {
-                        if data.eq_ignoring_origin_and_deps(crate_data, false) {
-                            return Some((id, false));
-                        }
-                    }
-                    (a @ CrateOrigin::Local { .. }, CrateOrigin::Library { .. })
-                    | (a @ CrateOrigin::Library { .. }, CrateOrigin::Local { .. }) => {
-                        // If the origins differ, check if the two crates are equal without
-                        // considering the dev dependencies, if they are, they most likely are in
-                        // different loaded workspaces which may cause issues. We keep the local
-                        // version and discard the library one as the local version may have
-                        // dev-dependencies that we want to keep resolving. See #15656 for more
-                        // information.
-                        if data.eq_ignoring_origin_and_deps(crate_data, true) {
-                            return Some((id, !a.is_local()));
-                        }
-                    }
-                    (_, _) => return None,
-                }
-
-                None
-            });
-
-            if let Some((res, should_update_lib_to_local)) = res {
-                id_map.insert(topo, res);
-                if should_update_lib_to_local {
-                    assert!(self.arena[res].origin.is_lib());
-                    assert!(crate_data.origin.is_local());
-                    self.arena[res].origin = crate_data.origin.clone();
-
-                    // Move local's dev dependencies into the newly-local-formerly-lib crate.
-                    self.arena[res].dependencies = crate_data.dependencies.clone();
-                }
-            } else {
-                let id = self.arena.alloc(crate_data.clone());
-                id_map.insert(topo, id);
-            }
+            let res = self
+                .arena
+                .iter_mut()
+                .take(m)
+                .find_map(|(id, data)| merge((id, data), (topo, &crate_data)).then_some(id));
+
+            let new_id =
+                if let Some(res) = res { res } else { self.arena.alloc(crate_data.clone()) };
+            id_map.insert(topo, new_id);
         }
 
         *proc_macros =
             mem::take(proc_macros).into_iter().map(|(id, macros)| (id_map[&id], macros)).collect();
 
-        on_finished(&id_map);
+        id_map
     }
 
     fn find_path(
@@ -719,11 +618,9 @@ impl CrateGraph {
         match (cfg_if, std) {
             (Some(cfg_if), Some(std)) => {
                 self.arena[cfg_if].dependencies.clear();
-                self.arena[std].dependencies.push(Dependency::new(
-                    CrateName::new("cfg_if").unwrap(),
-                    cfg_if,
-                    DependencyKind::Normal,
-                ));
+                self.arena[std]
+                    .dependencies
+                    .push(Dependency::new(CrateName::new("cfg_if").unwrap(), cfg_if));
                 true
             }
             _ => false,
@@ -871,7 +768,7 @@ impl fmt::Display for CyclicDependenciesError {
 
 #[cfg(test)]
 mod tests {
-    use crate::{CrateOrigin, DependencyKind};
+    use crate::CrateOrigin;
 
     use super::{CrateGraph, CrateName, Dependency, Edition::Edition2018, Env, FileId};
 
@@ -888,8 +785,6 @@ mod tests {
             Env::default(),
             false,
             CrateOrigin::Local { repo: None, name: None },
-            Err("".into()),
-            None,
         );
         let crate2 = graph.add_crate_root(
             FileId::from_raw(2u32),
@@ -901,8 +796,6 @@ mod tests {
             Env::default(),
             false,
             CrateOrigin::Local { repo: None, name: None },
-            Err("".into()),
-            None,
         );
         let crate3 = graph.add_crate_root(
             FileId::from_raw(3u32),
@@ -914,26 +807,15 @@ mod tests {
             Env::default(),
             false,
             CrateOrigin::Local { repo: None, name: None },
-            Err("".into()),
-            None,
         );
         assert!(graph
-            .add_dep(
-                crate1,
-                Dependency::new(CrateName::new("crate2").unwrap(), crate2, DependencyKind::Normal)
-            )
+            .add_dep(crate1, Dependency::new(CrateName::new("crate2").unwrap(), crate2,))
             .is_ok());
         assert!(graph
-            .add_dep(
-                crate2,
-                Dependency::new(CrateName::new("crate3").unwrap(), crate3, DependencyKind::Normal)
-            )
+            .add_dep(crate2, Dependency::new(CrateName::new("crate3").unwrap(), crate3,))
             .is_ok());
         assert!(graph
-            .add_dep(
-                crate3,
-                Dependency::new(CrateName::new("crate1").unwrap(), crate1, DependencyKind::Normal)
-            )
+            .add_dep(crate3, Dependency::new(CrateName::new("crate1").unwrap(), crate1,))
             .is_err());
     }
 
@@ -950,8 +832,6 @@ mod tests {
             Env::default(),
             false,
             CrateOrigin::Local { repo: None, name: None },
-            Err("".into()),
-            None,
         );
         let crate2 = graph.add_crate_root(
             FileId::from_raw(2u32),
@@ -963,20 +843,12 @@ mod tests {
             Env::default(),
             false,
             CrateOrigin::Local { repo: None, name: None },
-            Err("".into()),
-            None,
         );
         assert!(graph
-            .add_dep(
-                crate1,
-                Dependency::new(CrateName::new("crate2").unwrap(), crate2, DependencyKind::Normal)
-            )
+            .add_dep(crate1, Dependency::new(CrateName::new("crate2").unwrap(), crate2,))
             .is_ok());
         assert!(graph
-            .add_dep(
-                crate2,
-                Dependency::new(CrateName::new("crate2").unwrap(), crate2, DependencyKind::Normal)
-            )
+            .add_dep(crate2, Dependency::new(CrateName::new("crate2").unwrap(), crate2,))
             .is_err());
     }
 
@@ -993,8 +865,6 @@ mod tests {
             Env::default(),
             false,
             CrateOrigin::Local { repo: None, name: None },
-            Err("".into()),
-            None,
         );
         let crate2 = graph.add_crate_root(
             FileId::from_raw(2u32),
@@ -1006,8 +876,6 @@ mod tests {
             Env::default(),
             false,
             CrateOrigin::Local { repo: None, name: None },
-            Err("".into()),
-            None,
         );
         let crate3 = graph.add_crate_root(
             FileId::from_raw(3u32),
@@ -1019,20 +887,12 @@ mod tests {
             Env::default(),
             false,
             CrateOrigin::Local { repo: None, name: None },
-            Err("".into()),
-            None,
         );
         assert!(graph
-            .add_dep(
-                crate1,
-                Dependency::new(CrateName::new("crate2").unwrap(), crate2, DependencyKind::Normal)
-            )
+            .add_dep(crate1, Dependency::new(CrateName::new("crate2").unwrap(), crate2,))
             .is_ok());
         assert!(graph
-            .add_dep(
-                crate2,
-                Dependency::new(CrateName::new("crate3").unwrap(), crate3, DependencyKind::Normal)
-            )
+            .add_dep(crate2, Dependency::new(CrateName::new("crate3").unwrap(), crate3,))
             .is_ok());
     }
 
@@ -1049,8 +909,6 @@ mod tests {
             Env::default(),
             false,
             CrateOrigin::Local { repo: None, name: None },
-            Err("".into()),
-            None,
         );
         let crate2 = graph.add_crate_root(
             FileId::from_raw(2u32),
@@ -1062,26 +920,16 @@ mod tests {
             Env::default(),
             false,
             CrateOrigin::Local { repo: None, name: None },
-            Err("".into()),
-            None,
         );
         assert!(graph
             .add_dep(
                 crate1,
-                Dependency::new(
-                    CrateName::normalize_dashes("crate-name-with-dashes"),
-                    crate2,
-                    DependencyKind::Normal
-                )
+                Dependency::new(CrateName::normalize_dashes("crate-name-with-dashes"), crate2,)
             )
             .is_ok());
         assert_eq!(
             graph[crate1].dependencies,
-            vec![Dependency::new(
-                CrateName::new("crate_name_with_dashes").unwrap(),
-                crate2,
-                DependencyKind::Normal
-            )]
+            vec![Dependency::new(CrateName::new("crate_name_with_dashes").unwrap(), crate2,)]
         );
     }
 }
diff --git a/src/tools/rust-analyzer/crates/base-db/src/lib.rs b/src/tools/rust-analyzer/crates/base-db/src/lib.rs
index d7fc9d4c95c..cb2e6cdaa28 100644
--- a/src/tools/rust-analyzer/crates/base-db/src/lib.rs
+++ b/src/tools/rust-analyzer/crates/base-db/src/lib.rs
@@ -62,6 +62,20 @@ pub trait SourceDatabase: FileLoader + std::fmt::Debug {
     /// The crate graph.
     #[salsa::input]
     fn crate_graph(&self) -> Arc<CrateGraph>;
+
+    // FIXME: Consider removing this, making HirDatabase::target_data_layout an input query
+    #[salsa::input]
+    fn data_layout(&self, krate: CrateId) -> TargetLayoutLoadResult;
+
+    #[salsa::input]
+    fn toolchain(&self, krate: CrateId) -> Option<Version>;
+
+    #[salsa::transparent]
+    fn toolchain_channel(&self, krate: CrateId) -> Option<ReleaseChannel>;
+}
+
+fn toolchain_channel(db: &dyn SourceDatabase, krate: CrateId) -> Option<ReleaseChannel> {
+    db.toolchain(krate).as_ref().and_then(|v| ReleaseChannel::from_str(&v.pre))
 }
 
 fn parse(db: &dyn SourceDatabase, file_id: FileId) -> Parse<ast::SourceFile> {
diff --git a/src/tools/rust-analyzer/crates/flycheck/src/lib.rs b/src/tools/rust-analyzer/crates/flycheck/src/lib.rs
index c59aff2a8bb..ee39a2790bc 100644
--- a/src/tools/rust-analyzer/crates/flycheck/src/lib.rs
+++ b/src/tools/rust-analyzer/crates/flycheck/src/lib.rs
@@ -14,7 +14,7 @@ use std::{
 
 use command_group::{CommandGroup, GroupChild};
 use crossbeam_channel::{never, select, unbounded, Receiver, Sender};
-use paths::AbsPathBuf;
+use paths::{AbsPath, AbsPathBuf};
 use rustc_hash::FxHashMap;
 use serde::Deserialize;
 use stdx::process::streaming_output;
@@ -23,6 +23,7 @@ pub use cargo_metadata::diagnostic::{
     Applicability, Diagnostic, DiagnosticCode, DiagnosticLevel, DiagnosticSpan,
     DiagnosticSpanMacroExpansion,
 };
+use toolchain::Tool;
 
 #[derive(Copy, Clone, Debug, Default, PartialEq, Eq)]
 pub enum InvocationStrategy {
@@ -89,9 +90,10 @@ impl FlycheckHandle {
         id: usize,
         sender: Box<dyn Fn(Message) + Send>,
         config: FlycheckConfig,
+        sysroot_root: Option<AbsPathBuf>,
         workspace_root: AbsPathBuf,
     ) -> FlycheckHandle {
-        let actor = FlycheckActor::new(id, sender, config, workspace_root);
+        let actor = FlycheckActor::new(id, sender, config, sysroot_root, workspace_root);
         let (sender, receiver) = unbounded::<StateChange>();
         let thread = stdx::thread::Builder::new(stdx::thread::ThreadIntent::Worker)
             .name("Flycheck".to_owned())
@@ -101,13 +103,15 @@ impl FlycheckHandle {
     }
 
     /// Schedule a re-start of the cargo check worker to do a workspace wide check.
-    pub fn restart_workspace(&self) {
-        self.sender.send(StateChange::Restart(None)).unwrap();
+    pub fn restart_workspace(&self, saved_file: Option<AbsPathBuf>) {
+        self.sender.send(StateChange::Restart { package: None, saved_file }).unwrap();
     }
 
     /// Schedule a re-start of the cargo check worker to do a package wide check.
     pub fn restart_for_package(&self, package: String) {
-        self.sender.send(StateChange::Restart(Some(package))).unwrap();
+        self.sender
+            .send(StateChange::Restart { package: Some(package), saved_file: None })
+            .unwrap();
     }
 
     /// Stop this cargo check worker.
@@ -158,7 +162,7 @@ pub enum Progress {
 }
 
 enum StateChange {
-    Restart(Option<String>),
+    Restart { package: Option<String>, saved_file: Option<AbsPathBuf> },
     Cancel,
 }
 
@@ -171,6 +175,7 @@ struct FlycheckActor {
     /// Either the workspace root of the workspace we are flychecking,
     /// or the project root of the project.
     root: AbsPathBuf,
+    sysroot_root: Option<AbsPathBuf>,
     /// 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
@@ -184,15 +189,25 @@ enum Event {
     CheckEvent(Option<CargoMessage>),
 }
 
+const SAVED_FILE_PLACEHOLDER: &str = "$saved_file";
+
 impl FlycheckActor {
     fn new(
         id: usize,
         sender: Box<dyn Fn(Message) + Send>,
         config: FlycheckConfig,
+        sysroot_root: Option<AbsPathBuf>,
         workspace_root: AbsPathBuf,
     ) -> FlycheckActor {
         tracing::info!(%id, ?workspace_root, "Spawning flycheck");
-        FlycheckActor { id, sender, config, root: workspace_root, command_handle: None }
+        FlycheckActor {
+            id,
+            sender,
+            config,
+            sysroot_root,
+            root: workspace_root,
+            command_handle: None,
+        }
     }
 
     fn report_progress(&self, progress: Progress) {
@@ -218,7 +233,7 @@ impl FlycheckActor {
                     tracing::debug!(flycheck_id = self.id, "flycheck cancelled");
                     self.cancel_check_process();
                 }
-                Event::RequestStateChange(StateChange::Restart(package)) => {
+                Event::RequestStateChange(StateChange::Restart { package, saved_file }) => {
                     // Cancel the previously spawned process
                     self.cancel_check_process();
                     while let Ok(restart) = inbox.recv_timeout(Duration::from_millis(50)) {
@@ -228,7 +243,11 @@ impl FlycheckActor {
                         }
                     }
 
-                    let command = self.check_command(package.as_deref());
+                    let command =
+                        match self.check_command(package.as_deref(), saved_file.as_deref()) {
+                            Some(c) => c,
+                            None => continue,
+                        };
                     let formatted_command = format!("{:?}", command);
 
                     tracing::debug!(?command, "will restart flycheck");
@@ -302,7 +321,14 @@ impl FlycheckActor {
         }
     }
 
-    fn check_command(&self, package: Option<&str>) -> Command {
+    /// Construct a `Command` object for checking the user's code. If the user
+    /// has specified a custom command with placeholders that we cannot fill,
+    /// return None.
+    fn check_command(
+        &self,
+        package: Option<&str>,
+        saved_file: Option<&AbsPath>,
+    ) -> Option<Command> {
         let (mut cmd, args) = match &self.config {
             FlycheckConfig::CargoCommand {
                 command,
@@ -316,7 +342,10 @@ impl FlycheckActor {
                 ansi_color_output,
                 target_dir,
             } => {
-                let mut cmd = Command::new(toolchain::cargo());
+                let mut cmd = Command::new(Tool::Cargo.path());
+                if let Some(sysroot_root) = &self.sysroot_root {
+                    cmd.env("RUSTUP_TOOLCHAIN", AsRef::<std::path::Path>::as_ref(sysroot_root));
+                }
                 cmd.arg(command);
                 cmd.current_dir(&self.root);
 
@@ -355,7 +384,7 @@ impl FlycheckActor {
                     cmd.arg("--target-dir").arg(target_dir);
                 }
                 cmd.envs(extra_env);
-                (cmd, extra_args)
+                (cmd, extra_args.clone())
             }
             FlycheckConfig::CustomCommand {
                 command,
@@ -384,12 +413,34 @@ impl FlycheckActor {
                     }
                 }
 
-                (cmd, args)
+                if args.contains(&SAVED_FILE_PLACEHOLDER.to_owned()) {
+                    // If the custom command has a $saved_file placeholder, and
+                    // we're saving a file, replace the placeholder in the arguments.
+                    if let Some(saved_file) = saved_file {
+                        let args = args
+                            .iter()
+                            .map(|arg| {
+                                if arg == SAVED_FILE_PLACEHOLDER {
+                                    saved_file.to_string()
+                                } else {
+                                    arg.clone()
+                                }
+                            })
+                            .collect();
+                        (cmd, args)
+                    } else {
+                        // The custom command has a $saved_file placeholder,
+                        // but we had an IDE event that wasn't a file save. Do nothing.
+                        return None;
+                    }
+                } else {
+                    (cmd, args.clone())
+                }
             }
         };
 
         cmd.args(args);
-        cmd
+        Some(cmd)
     }
 
     fn send(&self, check_task: Message) {
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/attr.rs b/src/tools/rust-analyzer/crates/hir-def/src/attr.rs
index c91a5497262..519706c65f2 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/attr.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/attr.rs
@@ -377,27 +377,39 @@ impl AttrsWithOwner {
             AttrDefId::GenericParamId(it) => match it {
                 GenericParamId::ConstParamId(it) => {
                     let src = it.parent().child_source(db);
-                    RawAttrs::from_attrs_owner(
-                        db.upcast(),
-                        src.with_value(&src.value[it.local_id()]),
-                        db.span_map(src.file_id).as_ref(),
-                    )
+                    // FIXME: We should be never getting `None` here.
+                    match src.value.get(it.local_id()) {
+                        Some(val) => RawAttrs::from_attrs_owner(
+                            db.upcast(),
+                            src.with_value(val),
+                            db.span_map(src.file_id).as_ref(),
+                        ),
+                        None => RawAttrs::EMPTY,
+                    }
                 }
                 GenericParamId::TypeParamId(it) => {
                     let src = it.parent().child_source(db);
-                    RawAttrs::from_attrs_owner(
-                        db.upcast(),
-                        src.with_value(&src.value[it.local_id()]),
-                        db.span_map(src.file_id).as_ref(),
-                    )
+                    // FIXME: We should be never getting `None` here.
+                    match src.value.get(it.local_id()) {
+                        Some(val) => RawAttrs::from_attrs_owner(
+                            db.upcast(),
+                            src.with_value(val),
+                            db.span_map(src.file_id).as_ref(),
+                        ),
+                        None => RawAttrs::EMPTY,
+                    }
                 }
                 GenericParamId::LifetimeParamId(it) => {
                     let src = it.parent.child_source(db);
-                    RawAttrs::from_attrs_owner(
-                        db.upcast(),
-                        src.with_value(&src.value[it.local_id]),
-                        db.span_map(src.file_id).as_ref(),
-                    )
+                    // FIXME: We should be never getting `None` here.
+                    match src.value.get(it.local_id) {
+                        Some(val) => RawAttrs::from_attrs_owner(
+                            db.upcast(),
+                            src.with_value(val),
+                            db.span_map(src.file_id).as_ref(),
+                        ),
+                        None => RawAttrs::EMPTY,
+                    }
                 }
             },
             AttrDefId::ExternBlockId(it) => attrs_from_item_tree_loc(db, it),
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/body/lower.rs b/src/tools/rust-analyzer/crates/hir-def/src/body/lower.rs
index 29ac666277d..5dc5fedd230 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/body/lower.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/body/lower.rs
@@ -416,6 +416,11 @@ impl ExprCollector<'_> {
                 let expr = e.expr().map(|e| self.collect_expr(e));
                 self.alloc_expr(Expr::Return { expr }, syntax_ptr)
             }
+            ast::Expr::BecomeExpr(e) => {
+                let expr =
+                    e.expr().map(|e| self.collect_expr(e)).unwrap_or_else(|| self.missing_expr());
+                self.alloc_expr(Expr::Become { expr }, syntax_ptr)
+            }
             ast::Expr::YieldExpr(e) => {
                 self.is_lowering_coroutine = true;
                 let expr = e.expr().map(|e| self.collect_expr(e));
@@ -1000,10 +1005,6 @@ impl ExprCollector<'_> {
                         krate: *krate,
                     });
                 }
-                Some(ExpandError::RecursionOverflowPoisoned) => {
-                    // Recursion limit has been reached in the macro expansion tree, but not in
-                    // this very macro call. Don't add diagnostics to avoid duplication.
-                }
                 Some(err) => {
                     self.source_map.diagnostics.push(BodyDiagnostic::MacroError {
                         node: InFile::new(outer_file, syntax_ptr),
@@ -1112,7 +1113,7 @@ impl ExprCollector<'_> {
                     statements.push(Statement::Expr { expr, has_semi });
                 }
             }
-            ast::Stmt::Item(_item) => (),
+            ast::Stmt::Item(_item) => statements.push(Statement::Item),
         }
     }
 
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/body/pretty.rs b/src/tools/rust-analyzer/crates/hir-def/src/body/pretty.rs
index 4afb4086517..8229b1ccf3d 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/body/pretty.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/body/pretty.rs
@@ -6,7 +6,7 @@ use itertools::Itertools;
 
 use crate::{
     hir::{
-        Array, BindingAnnotation, BindingId, CaptureBy, ClosureKind, Literal, LiteralOrConst,
+        Array, BindingAnnotation, CaptureBy, ClosureKind, Literal, LiteralOrConst,
         Movability, Statement,
     },
     pretty::{print_generic_args, print_path, print_type_ref},
@@ -261,6 +261,11 @@ impl Printer<'_> {
                     self.print_expr(*expr);
                 }
             }
+            Expr::Become { expr } => {
+                w!(self, "become");
+                self.whitespace();
+                self.print_expr(*expr);
+            }
             Expr::Yield { expr } => {
                 w!(self, "yield");
                 if let Some(expr) = expr {
@@ -623,6 +628,7 @@ impl Printer<'_> {
                 }
                 wln!(self);
             }
+            Statement::Item => (),
         }
     }
 
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/body/scope.rs b/src/tools/rust-analyzer/crates/hir-def/src/body/scope.rs
index ab623250d40..69b82ae871a 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/body/scope.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/body/scope.rs
@@ -197,6 +197,7 @@ fn compute_block_scopes(
             Statement::Expr { expr, .. } => {
                 compute_expr_scopes(*expr, body, scopes, scope);
             }
+            Statement::Item => (),
         }
     }
     if let Some(expr) = tail {
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/data.rs b/src/tools/rust-analyzer/crates/hir-def/src/data.rs
index 7ce05b64d02..f506864902c 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/data.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/data.rs
@@ -634,7 +634,6 @@ impl<'a> AssocItemCollector<'a> {
                     attr,
                 ) {
                     Ok(ResolvedAttr::Macro(call_id)) => {
-                        self.attr_calls.push((ast_id, call_id));
                         // If proc attribute macro expansion is disabled, skip expanding it here
                         if !self.db.expand_proc_attr_macros() {
                             continue 'attrs;
@@ -647,10 +646,21 @@ impl<'a> AssocItemCollector<'a> {
                             // disabled. This is analogous to the handling in
                             // `DefCollector::collect_macros`.
                             if exp.is_dummy() {
+                                self.diagnostics.push(DefDiagnostic::unresolved_proc_macro(
+                                    self.module_id.local_id,
+                                    loc.kind,
+                                    loc.def.krate,
+                                ));
+
+                                continue 'attrs;
+                            }
+                            if exp.is_disabled() {
                                 continue 'attrs;
                             }
                         }
 
+                        self.attr_calls.push((ast_id, call_id));
+
                         let res =
                             self.expander.enter_expand_id::<ast::MacroItems>(self.db, call_id);
                         self.collect_macro_items(res, &|| loc.kind.clone());
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/expander.rs b/src/tools/rust-analyzer/crates/hir-def/src/expander.rs
index b83feeedc34..b99df1ed593 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/expander.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/expander.rs
@@ -140,13 +140,11 @@ impl Expander {
             // The overflow error should have been reported when it occurred (see the next branch),
             // so don't return overflow error here to avoid diagnostics duplication.
             cov_mark::hit!(overflow_but_not_me);
-            return ExpandResult::only_err(ExpandError::RecursionOverflowPoisoned);
+            return ExpandResult::ok(None);
         } else if self.recursion_limit.check(self.recursion_depth as usize + 1).is_err() {
             self.recursion_depth = u32::MAX;
             cov_mark::hit!(your_stack_belongs_to_me);
-            return ExpandResult::only_err(ExpandError::other(
-                "reached recursion limit during macro expansion",
-            ));
+            return ExpandResult::only_err(ExpandError::RecursionOverflow);
         }
 
         let ExpandResult { value, err } = op(self);
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/find_path.rs b/src/tools/rust-analyzer/crates/hir-def/src/find_path.rs
index 2e137f67b4c..26247ba5b50 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/find_path.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/find_path.rs
@@ -447,18 +447,25 @@ fn select_best_path(
     }
     const STD_CRATES: [Name; 3] = [known::std, known::core, known::alloc];
 
-    let choose = |new_path: (ModPath, _), old_path: (ModPath, _)| {
-        let new_has_prelude = new_path.0.segments().iter().any(|seg| seg == &known::prelude);
-        let old_has_prelude = old_path.0.segments().iter().any(|seg| seg == &known::prelude);
+    let choose = |new: (ModPath, _), old: (ModPath, _)| {
+        let (new_path, _) = &new;
+        let (old_path, _) = &old;
+        let new_has_prelude = new_path.segments().iter().any(|seg| seg == &known::prelude);
+        let old_has_prelude = old_path.segments().iter().any(|seg| seg == &known::prelude);
         match (new_has_prelude, old_has_prelude, prefer_prelude) {
-            (true, false, true) | (false, true, false) => new_path,
-            (true, false, false) | (false, true, true) => old_path,
-            // no prelude difference in the paths, so pick the smaller one
+            (true, false, true) | (false, true, false) => new,
+            (true, false, false) | (false, true, true) => old,
+            // no prelude difference in the paths, so pick the shorter one
             (true, true, _) | (false, false, _) => {
-                if new_path.0.len() < old_path.0.len() {
-                    new_path
+                let new_path_is_shorter = new_path
+                    .len()
+                    .cmp(&old_path.len())
+                    .then_with(|| new_path.textual_len().cmp(&old_path.textual_len()))
+                    .is_lt();
+                if new_path_is_shorter {
+                    new
                 } else {
-                    old_path
+                    old
                 }
             }
         }
@@ -469,8 +476,8 @@ fn select_best_path(
             let rank = match prefer_no_std {
                 false => |name: &Name| match name {
                     name if name == &known::core => 0,
-                    name if name == &known::alloc => 0,
-                    name if name == &known::std => 1,
+                    name if name == &known::alloc => 1,
+                    name if name == &known::std => 2,
                     _ => unreachable!(),
                 },
                 true => |name: &Name| match name {
@@ -1539,4 +1546,38 @@ pub mod foo {
             "krate::prelude::Foo",
         );
     }
+
+    #[test]
+    fn respect_segment_length() {
+        check_found_path(
+            r#"
+//- /main.rs crate:main deps:petgraph
+$0
+//- /petgraph.rs crate:petgraph
+pub mod graph {
+    pub use crate::graph_impl::{
+        NodeIndex
+    };
+}
+
+mod graph_impl {
+    pub struct NodeIndex<Ix>(Ix);
+}
+
+pub mod stable_graph {
+    #[doc(no_inline)]
+    pub use crate::graph::{NodeIndex};
+}
+
+pub mod prelude {
+    #[doc(no_inline)]
+    pub use crate::graph::{NodeIndex};
+}
+"#,
+            "petgraph::graph::NodeIndex",
+            "petgraph::graph::NodeIndex",
+            "petgraph::graph::NodeIndex",
+            "petgraph::graph::NodeIndex",
+        );
+    }
 }
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/hir.rs b/src/tools/rust-analyzer/crates/hir-def/src/hir.rs
index ac44d379415..34b2910b4f5 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/hir.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/hir.rs
@@ -182,6 +182,7 @@ pub enum Expr {
         tail: Option<ExprId>,
     },
     Const(ConstBlockId),
+    // FIXME: Fold this into Block with an unsafe flag?
     Unsafe {
         id: Option<BlockId>,
         statements: Box<[Statement]>,
@@ -216,6 +217,9 @@ pub enum Expr {
     Return {
         expr: Option<ExprId>,
     },
+    Become {
+        expr: ExprId,
+    },
     Yield {
         expr: Option<ExprId>,
     },
@@ -349,6 +353,9 @@ pub enum Statement {
         expr: ExprId,
         has_semi: bool,
     },
+    // At the moment, we only use this to figure out if a return expression
+    // is really the last statement of a block. See #16566
+    Item,
 }
 
 impl Expr {
@@ -382,6 +389,7 @@ impl Expr {
                             }
                         }
                         Statement::Expr { expr: expression, .. } => f(*expression),
+                        Statement::Item => (),
                     }
                 }
                 if let &Some(expr) = tail {
@@ -410,6 +418,7 @@ impl Expr {
                     f(expr);
                 }
             }
+            Expr::Become { expr } => f(*expr),
             Expr::RecordLit { fields, spread, .. } => {
                 for field in fields.iter() {
                     f(field.expr);
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/import_map.rs b/src/tools/rust-analyzer/crates/hir-def/src/import_map.rs
index 98982c7db84..38cfcf0f281 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/import_map.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/import_map.rs
@@ -3,7 +3,7 @@
 use std::{fmt, hash::BuildHasherDefault};
 
 use base_db::CrateId;
-use fst::{self, raw::IndexedValue, Automaton, Streamer};
+use fst::{raw::IndexedValue, Automaton, Streamer};
 use hir_expand::name::Name;
 use indexmap::IndexMap;
 use itertools::Itertools;
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/item_tree/lower.rs b/src/tools/rust-analyzer/crates/hir-def/src/item_tree/lower.rs
index e0aa3ae6123..b51cb5de0f4 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/item_tree/lower.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/item_tree/lower.rs
@@ -2,12 +2,12 @@
 
 use std::collections::hash_map::Entry;
 
-use hir_expand::{ast_id_map::AstIdMap, span_map::SpanMapRef, HirFileId};
-use syntax::ast::{self, HasModuleItem, HasTypeBounds, IsString};
+use hir_expand::{ast_id_map::AstIdMap, span_map::SpanMapRef};
+use syntax::ast::{HasModuleItem, HasTypeBounds, IsString};
 
 use crate::{
-    generics::{GenericParams, GenericParamsCollector, TypeParamData, TypeParamProvenance},
-    type_ref::{LifetimeRef, TraitBoundModifier, TraitRef},
+    generics::{GenericParamsCollector, TypeParamData, TypeParamProvenance},
+    type_ref::{LifetimeRef, TraitBoundModifier},
     LocalLifetimeParamId, LocalTypeOrConstParamId,
 };
 
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/item_tree/pretty.rs b/src/tools/rust-analyzer/crates/hir-def/src/item_tree/pretty.rs
index 0086b7180b2..dae876f7ecb 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/item_tree/pretty.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/item_tree/pretty.rs
@@ -1,13 +1,12 @@
 //! `ItemTree` debug printer.
 
-use std::fmt::{self, Write};
+use std::fmt::Write;
 
 use span::ErasedFileAstId;
 
 use crate::{
-    generics::{TypeOrConstParamData, WherePredicate, WherePredicateTypeTarget},
+    generics::{WherePredicate, WherePredicateTypeTarget},
     pretty::{print_path, print_type_bounds, print_type_ref},
-    visibility::RawVisibility,
 };
 
 use super::*;
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/mbe/matching.rs b/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/mbe/matching.rs
index 0909d8c8354..63f211022c9 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/mbe/matching.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/mbe/matching.rs
@@ -33,7 +33,7 @@ m!(&k");
 "#,
         expect![[r#"
 macro_rules! m { ($i:literal) => {}; }
-/* error: invalid token tree */"#]],
+/* error: mismatched delimiters */"#]],
     );
 }
 
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/mbe/meta_syntax.rs b/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/mbe/meta_syntax.rs
index e875950e4e5..2d289b76833 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/mbe/meta_syntax.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/mbe/meta_syntax.rs
@@ -68,26 +68,26 @@ m2!();
 "#,
         expect![[r#"
 macro_rules! i1 { invalid }
-/* error: invalid macro definition: expected subtree */
+/* error: macro definition has parse errors */
 
 macro_rules! e1 { $i:ident => () }
-/* error: invalid macro definition: expected subtree */
+/* error: macro definition has parse errors */
 macro_rules! e2 { ($i:ident) () }
-/* error: invalid macro definition: expected `=` */
+/* error: macro definition has parse errors */
 macro_rules! e3 { ($(i:ident)_) => () }
-/* error: invalid macro definition: invalid repeat */
+/* error: macro definition has parse errors */
 
 macro_rules! f1 { ($i) => ($i) }
-/* error: invalid macro definition: missing fragment specifier */
+/* error: macro definition has parse errors */
 macro_rules! f2 { ($i:) => ($i) }
-/* error: invalid macro definition: missing fragment specifier */
+/* error: macro definition has parse errors */
 macro_rules! f3 { ($i:_) => () }
-/* error: invalid macro definition: missing fragment specifier */
+/* error: macro definition has parse errors */
 
 macro_rules! m1 { ($$i) => () }
-/* error: invalid macro definition: `$$` is not allowed on the pattern side */
+/* error: macro definition has parse errors */
 macro_rules! m2 { () => ( ${invalid()} ) }
-/* error: invalid macro definition: invalid metavariable expression */
+/* error: macro definition has parse errors */
 "#]],
     )
 }
@@ -137,18 +137,18 @@ macro_rules! m9 { ($($($($i:ident)?)*)+) => {}; }
 macro_rules! mA { ($($($($i:ident)+)?)*) => {}; }
 macro_rules! mB { ($($($($i:ident)+)*)?) => {}; }
 
-/* error: invalid macro definition: empty token tree in repetition */
-/* error: invalid macro definition: empty token tree in repetition */
-/* error: invalid macro definition: empty token tree in repetition */
-/* error: invalid macro definition: empty token tree in repetition */
-/* error: invalid macro definition: empty token tree in repetition */
-/* error: invalid macro definition: empty token tree in repetition */
-/* error: invalid macro definition: empty token tree in repetition */
-/* error: invalid macro definition: empty token tree in repetition */
-/* error: invalid macro definition: empty token tree in repetition */
-/* error: invalid macro definition: empty token tree in repetition */
-/* error: invalid macro definition: empty token tree in repetition */
-/* error: invalid macro definition: empty token tree in repetition */
+/* error: macro definition has parse errors */
+/* error: macro definition has parse errors */
+/* error: macro definition has parse errors */
+/* error: macro definition has parse errors */
+/* error: macro definition has parse errors */
+/* error: macro definition has parse errors */
+/* error: macro definition has parse errors */
+/* error: macro definition has parse errors */
+/* error: macro definition has parse errors */
+/* error: macro definition has parse errors */
+/* error: macro definition has parse errors */
+/* error: macro definition has parse errors */
     "#]],
     );
 }
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/mbe/metavar_expr.rs b/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/mbe/metavar_expr.rs
index 6560d0ec466..bf701198387 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/mbe/metavar_expr.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/mbe/metavar_expr.rs
@@ -275,9 +275,9 @@ macro_rules! depth_too_large {
 }
 
 fn test() {
-    /* error: invalid macro definition: invalid metavariable expression */;
-    /* error: invalid macro definition: invalid metavariable expression */;
-    /* error: invalid macro definition: invalid metavariable expression */;
+    /* error: macro definition has parse errors */;
+    /* error: macro definition has parse errors */;
+    /* error: macro definition has parse errors */;
 }
 "#]],
     );
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/mbe/regression.rs b/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/mbe/regression.rs
index 6717ee1aa5f..4aad53c3bd7 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/mbe/regression.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/mbe/regression.rs
@@ -1090,3 +1090,57 @@ fn main() {
 "#]],
     );
 }
+
+#[test]
+fn regression_16529() {
+    check(
+        r#"
+mod any {
+    #[macro_export]
+    macro_rules! nameable {
+        {
+            struct $name:ident[$a:lifetime]
+        } => {
+            $crate::any::nameable! {
+                struct $name[$a]
+                a
+            }
+        };
+        {
+            struct $name:ident[$a:lifetime]
+            a
+        } => {};
+    }
+    pub use nameable;
+
+    nameable! {
+        Name['a]
+    }
+}
+"#,
+        expect![[r#"
+mod any {
+    #[macro_export]
+    macro_rules! nameable {
+        {
+            struct $name:ident[$a:lifetime]
+        } => {
+            $crate::any::nameable! {
+                struct $name[$a]
+                a
+            }
+        };
+        {
+            struct $name:ident[$a:lifetime]
+            a
+        } => {};
+    }
+    pub use nameable;
+
+    /* error: unexpected token in input */$crate::any::nameable! {
+        struct $name[$a]a
+    }
+}
+"#]],
+    );
+}
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/mbe/tt_conversion.rs b/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/mbe/tt_conversion.rs
index ae56934f632..362c189f6a7 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/mbe/tt_conversion.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/mbe/tt_conversion.rs
@@ -97,8 +97,8 @@ m2!(x
 macro_rules! m1 { ($x:ident) => { ($x } }
 macro_rules! m2 { ($x:ident) => {} }
 
-/* error: invalid macro definition: expected subtree */
-/* error: invalid token tree */
+/* error: macro definition has parse errors */
+/* error: mismatched delimiters */
 "#]],
     )
 }
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/mod.rs b/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/mod.rs
index fc5a6e80a42..23b10cfd8e6 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/mod.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/mod.rs
@@ -58,6 +58,7 @@ pub fn identity_when_valid(_attr: TokenStream, item: TokenStream) -> TokenStream
             name: "identity_when_valid".into(),
             kind: ProcMacroKind::Attr,
             expander: sync::Arc::new(IdentityWhenValidProcMacroExpander),
+            disabled: false,
         },
     )];
     let db = TestDB::with_files_extra_proc_macros(ra_fixture, extra_proc_macros);
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/nameres.rs b/src/tools/rust-analyzer/crates/hir-def/src/nameres.rs
index 2a9390e7978..a2eca066438 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/nameres.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/nameres.rs
@@ -57,7 +57,7 @@ pub mod proc_macro;
 #[cfg(test)]
 mod tests;
 
-use std::{cmp::Ord, ops::Deref};
+use std::ops::Deref;
 
 use base_db::{CrateId, Edition, FileId};
 use hir_expand::{
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/nameres/collector.rs b/src/tools/rust-analyzer/crates/hir-def/src/nameres/collector.rs
index 21cc28f1b3d..88838f58fe7 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/nameres/collector.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/nameres/collector.rs
@@ -11,7 +11,7 @@ use either::Either;
 use hir_expand::{
     ast_id_map::FileAstId,
     attrs::{Attr, AttrId},
-    builtin_attr_macro::find_builtin_attr,
+    builtin_attr_macro::{find_builtin_attr, BuiltinAttrExpander},
     builtin_derive_macro::find_builtin_derive,
     builtin_fn_macro::find_builtin_macro,
     name::{name, AsName, Name},
@@ -98,9 +98,13 @@ pub(super) fn collect_defs(db: &dyn DefDatabase, def_map: DefMap, tree_id: TreeI
                         };
                         (
                             name.as_name(),
-                            CustomProcMacroExpander::new(hir_expand::proc_macro::ProcMacroId(
-                                idx as u32,
-                            )),
+                            if it.disabled {
+                                CustomProcMacroExpander::disabled()
+                            } else {
+                                CustomProcMacroExpander::new(
+                                    hir_expand::proc_macro::ProcMacroId::new(idx as u32),
+                                )
+                            },
                         )
                     })
                     .collect())
@@ -604,9 +608,6 @@ impl DefCollector<'_> {
         id: ItemTreeId<item_tree::Function>,
         fn_id: FunctionId,
     ) {
-        if self.def_map.block.is_some() {
-            return;
-        }
         let kind = def.kind.to_basedb_kind();
         let (expander, kind) =
             match self.proc_macros.as_ref().map(|it| it.iter().find(|(n, _)| n == &def.name)) {
@@ -1120,9 +1121,16 @@ impl DefCollector<'_> {
         let mut push_resolved = |directive: &MacroDirective, call_id| {
             resolved.push((directive.module_id, directive.depth, directive.container, call_id));
         };
+
+        #[derive(PartialEq, Eq)]
+        enum Resolved {
+            Yes,
+            No,
+        }
+
         let mut res = ReachedFixedPoint::Yes;
         // Retain unresolved macros after this round of resolution.
-        macros.retain(|directive| {
+        let mut retain = |directive: &MacroDirective| {
             let subns = match &directive.kind {
                 MacroDirectiveKind::FnLike { .. } => MacroSubNs::Bang,
                 MacroDirectiveKind::Attr { .. } | MacroDirectiveKind::Derive { .. } => {
@@ -1156,10 +1164,11 @@ impl DefCollector<'_> {
                         self.def_map.modules[directive.module_id]
                             .scope
                             .add_macro_invoc(ast_id.ast_id, call_id);
+
                         push_resolved(directive, call_id);
 
                         res = ReachedFixedPoint::No;
-                        return false;
+                        return Resolved::Yes;
                     }
                 }
                 MacroDirectiveKind::Derive { ast_id, derive_attr, derive_pos, call_site } => {
@@ -1198,7 +1207,7 @@ impl DefCollector<'_> {
 
                         push_resolved(directive, call_id);
                         res = ReachedFixedPoint::No;
-                        return false;
+                        return Resolved::Yes;
                     }
                 }
                 MacroDirectiveKind::Attr { ast_id: file_ast_id, mod_item, attr, tree } => {
@@ -1221,7 +1230,7 @@ impl DefCollector<'_> {
                         }
                         .collect(&[*mod_item], directive.container);
                         res = ReachedFixedPoint::No;
-                        false
+                        Resolved::Yes
                     };
 
                     if let Some(ident) = path.as_ident() {
@@ -1237,13 +1246,18 @@ impl DefCollector<'_> {
 
                     let def = match resolver_def_id(path.clone()) {
                         Some(def) if def.is_attribute() => def,
-                        _ => return true,
+                        _ => return Resolved::No,
                     };
-                    if matches!(
-                        def,
-                        MacroDefId { kind: MacroDefKind::BuiltInAttr(expander, _),.. }
-                        if expander.is_derive()
-                    ) {
+
+                    if let MacroDefId {
+                        kind:
+                            MacroDefKind::BuiltInAttr(
+                                BuiltinAttrExpander::Derive | BuiltinAttrExpander::DeriveConst,
+                                _,
+                            ),
+                        ..
+                    } = def
+                    {
                         // Resolved to `#[derive]`, we don't actually expand this attribute like
                         // normal (as that would just be an identity expansion with extra output)
                         // Instead we treat derive attributes special and apply them separately.
@@ -1316,16 +1330,6 @@ impl DefCollector<'_> {
                     let call_id =
                         attr_macro_as_call_id(self.db, file_ast_id, attr, self.def_map.krate, def);
 
-                    // If proc attribute macro expansion is disabled, skip expanding it here
-                    if !self.db.expand_proc_attr_macros() {
-                        self.def_map.diagnostics.push(DefDiagnostic::unresolved_proc_macro(
-                            directive.module_id,
-                            self.db.lookup_intern_macro_call(call_id).kind,
-                            def.krate,
-                        ));
-                        return recollect_without(self);
-                    }
-
                     // Skip #[test]/#[bench] expansion, which would merely result in more memory usage
                     // due to duplicating functions into macro expansions
                     if matches!(
@@ -1337,17 +1341,29 @@ impl DefCollector<'_> {
                     }
 
                     if let MacroDefKind::ProcMacro(exp, ..) = def.kind {
-                        if exp.is_dummy() {
-                            // If there's no expander for the proc macro (e.g.
-                            // because proc macros are disabled, or building the
-                            // proc macro crate failed), report this and skip
-                            // expansion like we would if it was disabled
+                        // If proc attribute macro expansion is disabled, skip expanding it here
+                        if !self.db.expand_proc_attr_macros() {
                             self.def_map.diagnostics.push(DefDiagnostic::unresolved_proc_macro(
                                 directive.module_id,
                                 self.db.lookup_intern_macro_call(call_id).kind,
                                 def.krate,
                             ));
+                            return recollect_without(self);
+                        }
 
+                        // If there's no expander for the proc macro (e.g.
+                        // because proc macros are disabled, or building the
+                        // proc macro crate failed), report this and skip
+                        // expansion like we would if it was disabled
+                        if exp.is_dummy() {
+                            self.def_map.diagnostics.push(DefDiagnostic::unresolved_proc_macro(
+                                directive.module_id,
+                                self.db.lookup_intern_macro_call(call_id).kind,
+                                def.krate,
+                            ));
+                            return recollect_without(self);
+                        }
+                        if exp.is_disabled() {
                             return recollect_without(self);
                         }
                     }
@@ -1358,12 +1374,13 @@ impl DefCollector<'_> {
 
                     push_resolved(directive, call_id);
                     res = ReachedFixedPoint::No;
-                    return false;
+                    return Resolved::Yes;
                 }
             }
 
-            true
-        });
+            Resolved::No
+        };
+        macros.retain(|it| retain(it) == Resolved::No);
         // Attribute resolution can add unresolved macro invocations, so concatenate the lists.
         macros.extend(mem::take(&mut self.unresolved_macros));
         self.unresolved_macros = macros;
@@ -1673,7 +1690,11 @@ impl ModCollector<'_, '_> {
                         FunctionLoc { container, id: ItemTreeId::new(self.tree_id, id) }.intern(db);
 
                     let vis = resolve_vis(def_map, &self.item_tree[it.visibility]);
-                    if self.def_collector.is_proc_macro && self.module_id == DefMap::ROOT {
+
+                    if self.def_collector.def_map.block.is_none()
+                        && self.def_collector.is_proc_macro
+                        && self.module_id == DefMap::ROOT
+                    {
                         if let Some(proc_macro) = attrs.parse_proc_macro_decl(&it.name) {
                             self.def_collector.export_proc_macro(
                                 proc_macro,
@@ -2333,7 +2354,7 @@ impl ModCollector<'_, '_> {
                 resolved_res.resolved_def.take_macros().map(|it| db.macro_def(it))
             },
         ) {
-            // FIXME: if there were errors, this mightve been in the eager expansion from an
+            // FIXME: if there were errors, this might've been in the eager expansion from an
             // unresolved macro, so we need to push this into late macro resolution. see fixme above
             if res.err.is_none() {
                 // Legacy macros need to be expanded immediately, so that any macros they produce
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/nameres/diagnostics.rs b/src/tools/rust-analyzer/crates/hir-def/src/nameres/diagnostics.rs
index 0a3f7bf7ec3..161b2c05990 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/nameres/diagnostics.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/nameres/diagnostics.rs
@@ -103,6 +103,9 @@ impl DefDiagnostic {
     }
 
     // FIXME: Whats the difference between this and unresolved_macro_call
+    // FIXME: This is used for a lot of things, unresolved proc macros, disabled proc macros, etc
+    // yet the diagnostic handler in ide-diagnostics has to figure out what happened because this
+    // struct loses all that information!
     pub(crate) fn unresolved_proc_macro(
         container: LocalModuleId,
         ast: MacroCallKind,
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 6d3de0e55d2..90cd3af7578 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
@@ -446,7 +446,7 @@ fn compile_error_expand(
 ) -> ExpandResult<tt::Subtree> {
     let err = match &*tt.token_trees {
         [tt::TokenTree::Leaf(tt::Leaf::Literal(it))] => match unquote_str(it) {
-            Some(unquoted) => ExpandError::other(unquoted),
+            Some(unquoted) => ExpandError::other(unquoted.into_boxed_str()),
             None => ExpandError::other("`compile_error!` argument must be a string"),
         },
         _ => ExpandError::other("`compile_error!` argument must be a string"),
diff --git a/src/tools/rust-analyzer/crates/hir-expand/src/change.rs b/src/tools/rust-analyzer/crates/hir-expand/src/change.rs
index 67b7df198e9..c6611438e64 100644
--- a/src/tools/rust-analyzer/crates/hir-expand/src/change.rs
+++ b/src/tools/rust-analyzer/crates/hir-expand/src/change.rs
@@ -1,6 +1,10 @@
 //! Defines a unit of change that can applied to the database to get the next
 //! state. Changes are transactional.
-use base_db::{salsa::Durability, CrateGraph, FileChange, SourceDatabaseExt, SourceRoot};
+use base_db::{
+    salsa::Durability, CrateGraph, CrateId, FileChange, SourceDatabaseExt, SourceRoot,
+    TargetLayoutLoadResult, Version,
+};
+use la_arena::RawIdx;
 use span::FileId;
 use triomphe::Arc;
 
@@ -10,6 +14,8 @@ use crate::{db::ExpandDatabase, proc_macro::ProcMacros};
 pub struct Change {
     pub source_change: FileChange,
     pub proc_macros: Option<ProcMacros>,
+    pub toolchains: Option<Vec<Option<Version>>>,
+    pub target_data_layouts: Option<Vec<TargetLayoutLoadResult>>,
 }
 
 impl Change {
@@ -22,6 +28,24 @@ impl Change {
         if let Some(proc_macros) = self.proc_macros {
             db.set_proc_macros_with_durability(Arc::new(proc_macros), Durability::HIGH);
         }
+        if let Some(target_data_layouts) = self.target_data_layouts {
+            for (id, val) in target_data_layouts.into_iter().enumerate() {
+                db.set_data_layout_with_durability(
+                    CrateId::from_raw(RawIdx::from(id as u32)),
+                    val,
+                    Durability::HIGH,
+                );
+            }
+        }
+        if let Some(toolchains) = self.toolchains {
+            for (id, val) in toolchains.into_iter().enumerate() {
+                db.set_toolchain_with_durability(
+                    CrateId::from_raw(RawIdx::from(id as u32)),
+                    val,
+                    Durability::HIGH,
+                );
+            }
+        }
     }
 
     pub fn change_file(&mut self, file_id: FileId, new_text: Option<Arc<str>>) {
@@ -36,6 +60,14 @@ impl Change {
         self.proc_macros = Some(proc_macros);
     }
 
+    pub fn set_toolchains(&mut self, toolchains: Vec<Option<Version>>) {
+        self.toolchains = Some(toolchains);
+    }
+
+    pub fn set_target_data_layouts(&mut self, target_data_layouts: Vec<TargetLayoutLoadResult>) {
+        self.target_data_layouts = Some(target_data_layouts);
+    }
+
     pub fn set_roots(&mut self, roots: Vec<SourceRoot>) {
         self.source_change.set_roots(roots)
     }
diff --git a/src/tools/rust-analyzer/crates/hir-expand/src/db.rs b/src/tools/rust-analyzer/crates/hir-expand/src/db.rs
index 6a288cf9197..7b62eaa0289 100644
--- a/src/tools/rust-analyzer/crates/hir-expand/src/db.rs
+++ b/src/tools/rust-analyzer/crates/hir-expand/src/db.rs
@@ -108,7 +108,7 @@ pub trait ExpandDatabase: SourceDatabase {
     fn macro_arg(
         &self,
         id: MacroCallId,
-    ) -> ValueResult<Option<(Arc<tt::Subtree>, SyntaxFixupUndoInfo)>, Arc<Box<[SyntaxError]>>>;
+    ) -> ValueResult<(Arc<tt::Subtree>, SyntaxFixupUndoInfo), Arc<Box<[SyntaxError]>>>;
     /// Fetches the expander for this macro.
     #[salsa::transparent]
     #[salsa::invoke(TokenExpander::macro_expander)]
@@ -326,58 +326,77 @@ fn macro_arg(
     db: &dyn ExpandDatabase,
     id: MacroCallId,
     // FIXME: consider the following by putting fixup info into eager call info args
-    // ) -> ValueResult<Option<Arc<(tt::Subtree, SyntaxFixupUndoInfo)>>, Arc<Box<[SyntaxError]>>> {
-) -> ValueResult<Option<(Arc<tt::Subtree>, SyntaxFixupUndoInfo)>, Arc<Box<[SyntaxError]>>> {
-    let mismatched_delimiters = |arg: &SyntaxNode| {
-        let first = arg.first_child_or_token().map_or(T![.], |it| it.kind());
-        let last = arg.last_child_or_token().map_or(T![.], |it| it.kind());
-        let well_formed_tt =
-            matches!((first, last), (T!['('], T![')']) | (T!['['], T![']']) | (T!['{'], T!['}']));
-        if !well_formed_tt {
-            // Don't expand malformed (unbalanced) macro invocations. This is
-            // less than ideal, but trying to expand unbalanced  macro calls
-            // sometimes produces pathological, deeply nested code which breaks
-            // all kinds of things.
-            //
-            // Some day, we'll have explicit recursion counters for all
-            // recursive things, at which point this code might be removed.
-            cov_mark::hit!(issue9358_bad_macro_stack_overflow);
-            Some(Arc::new(Box::new([SyntaxError::new(
-                "unbalanced token tree".to_owned(),
-                arg.text_range(),
-            )]) as Box<[_]>))
-        } else {
-            None
-        }
-    };
+    // ) -> ValueResult<Arc<(tt::Subtree, SyntaxFixupUndoInfo)>, Arc<Box<[SyntaxError]>>> {
+) -> ValueResult<(Arc<tt::Subtree>, SyntaxFixupUndoInfo), Arc<Box<[SyntaxError]>>> {
     let loc = db.lookup_intern_macro_call(id);
     if let Some(EagerCallInfo { arg, .. }) = matches!(loc.def.kind, MacroDefKind::BuiltInEager(..))
         .then(|| loc.eager.as_deref())
         .flatten()
     {
-        ValueResult::ok(Some((arg.clone(), SyntaxFixupUndoInfo::NONE)))
+        ValueResult::ok((arg.clone(), SyntaxFixupUndoInfo::NONE))
     } else {
         let (parse, map) = parse_with_map(db, loc.kind.file_id());
         let root = parse.syntax_node();
 
         let syntax = match loc.kind {
             MacroCallKind::FnLike { ast_id, .. } => {
+                let dummy_tt = |kind| {
+                    (
+                        Arc::new(tt::Subtree {
+                            delimiter: tt::Delimiter {
+                                open: loc.call_site,
+                                close: loc.call_site,
+                                kind,
+                            },
+                            token_trees: Box::default(),
+                        }),
+                        SyntaxFixupUndoInfo::default(),
+                    )
+                };
+
                 let node = &ast_id.to_ptr(db).to_node(&root);
                 let offset = node.syntax().text_range().start();
-                match node.token_tree() {
-                    Some(tt) => {
-                        let tt = tt.syntax();
-                        if let Some(e) = mismatched_delimiters(tt) {
-                            return ValueResult::only_err(e);
-                        }
-                        tt.clone()
-                    }
-                    None => {
-                        return ValueResult::only_err(Arc::new(Box::new([
-                            SyntaxError::new_at_offset("missing token tree".to_owned(), offset),
-                        ])));
-                    }
+                let Some(tt) = node.token_tree() else {
+                    return ValueResult::new(
+                        dummy_tt(tt::DelimiterKind::Invisible),
+                        Arc::new(Box::new([SyntaxError::new_at_offset(
+                            "missing token tree".to_owned(),
+                            offset,
+                        )])),
+                    );
+                };
+                let first = tt.left_delimiter_token().map(|it| it.kind()).unwrap_or(T!['(']);
+                let last = tt.right_delimiter_token().map(|it| it.kind()).unwrap_or(T![.]);
+
+                let mismatched_delimiters = !matches!(
+                    (first, last),
+                    (T!['('], T![')']) | (T!['['], T![']']) | (T!['{'], T!['}'])
+                );
+                if mismatched_delimiters {
+                    // Don't expand malformed (unbalanced) macro invocations. This is
+                    // less than ideal, but trying to expand unbalanced  macro calls
+                    // sometimes produces pathological, deeply nested code which breaks
+                    // all kinds of things.
+                    //
+                    // So instead, we'll return an empty subtree here
+                    cov_mark::hit!(issue9358_bad_macro_stack_overflow);
+
+                    let kind = match first {
+                        _ if loc.def.is_proc_macro() => tt::DelimiterKind::Invisible,
+                        T!['('] => tt::DelimiterKind::Parenthesis,
+                        T!['['] => tt::DelimiterKind::Bracket,
+                        T!['{'] => tt::DelimiterKind::Brace,
+                        _ => tt::DelimiterKind::Invisible,
+                    };
+                    return ValueResult::new(
+                        dummy_tt(kind),
+                        Arc::new(Box::new([SyntaxError::new_at_offset(
+                            "mismatched delimiters".to_owned(),
+                            offset,
+                        )])),
+                    );
                 }
+                tt.syntax().clone()
             }
             MacroCallKind::Derive { ast_id, .. } => {
                 ast_id.to_ptr(db).to_node(&root).syntax().clone()
@@ -427,15 +446,15 @@ fn macro_arg(
 
         if matches!(loc.def.kind, MacroDefKind::BuiltInEager(..)) {
             match parse.errors() {
-                [] => ValueResult::ok(Some((Arc::new(tt), undo_info))),
+                [] => ValueResult::ok((Arc::new(tt), undo_info)),
                 errors => ValueResult::new(
-                    Some((Arc::new(tt), undo_info)),
+                    (Arc::new(tt), undo_info),
                     // Box::<[_]>::from(res.errors()), not stable yet
                     Arc::new(errors.to_vec().into_boxed_slice()),
                 ),
             }
         } else {
-            ValueResult::ok(Some((Arc::new(tt), undo_info)))
+            ValueResult::ok((Arc::new(tt), undo_info))
         }
     }
 }
@@ -519,21 +538,20 @@ fn macro_expand(
             expander.expand(db, macro_call_id, &node, map.as_ref())
         }
         _ => {
-            let ValueResult { value, err } = db.macro_arg(macro_call_id);
-            let Some((macro_arg, undo_info)) = value else {
-                return ExpandResult {
-                    value: CowArc::Owned(tt::Subtree {
-                        delimiter: tt::Delimiter::invisible_spanned(loc.call_site),
-                        token_trees: Box::new([]),
-                    }),
-                    // FIXME: We should make sure to enforce an invariant that invalid macro
-                    // calls do not reach this call path!
-                    err: Some(ExpandError::other("invalid token tree")),
-                };
+            let ValueResult { value: (macro_arg, undo_info), err } = db.macro_arg(macro_call_id);
+            let format_parse_err = |err: Arc<Box<[SyntaxError]>>| {
+                let mut buf = String::new();
+                for err in &**err {
+                    use std::fmt::Write;
+                    _ = write!(buf, "{}, ", err);
+                }
+                buf.pop();
+                buf.pop();
+                ExpandError::other(buf)
             };
 
             let arg = &*macro_arg;
-            match loc.def.kind {
+            let res = match loc.def.kind {
                 MacroDefKind::Declarative(id) => {
                     db.decl_macro_expander(loc.def.krate, id).expand(db, arg.clone(), macro_call_id)
                 }
@@ -549,16 +567,7 @@ fn macro_expand(
                 MacroDefKind::BuiltInEager(..) if loc.eager.is_none() => {
                     return ExpandResult {
                         value: CowArc::Arc(macro_arg.clone()),
-                        err: err.map(|err| {
-                            let mut buf = String::new();
-                            for err in &**err {
-                                use std::fmt::Write;
-                                _ = write!(buf, "{}, ", err);
-                            }
-                            buf.pop();
-                            buf.pop();
-                            ExpandError::other(buf)
-                        }),
+                        err: err.map(format_parse_err),
                     };
                 }
                 MacroDefKind::BuiltInEager(it, _) => {
@@ -570,6 +579,11 @@ fn macro_expand(
                     res
                 }
                 _ => unreachable!(),
+            };
+            ExpandResult {
+                value: res.value,
+                // if the arg had parse errors, show them instead of the expansion errors
+                err: err.map(format_parse_err).or(res.err),
             }
         }
     };
@@ -597,17 +611,7 @@ fn macro_expand(
 
 fn expand_proc_macro(db: &dyn ExpandDatabase, id: MacroCallId) -> ExpandResult<Arc<tt::Subtree>> {
     let loc = db.lookup_intern_macro_call(id);
-    let Some((macro_arg, undo_info)) = db.macro_arg(id).value else {
-        return ExpandResult {
-            value: Arc::new(tt::Subtree {
-                delimiter: tt::Delimiter::invisible_spanned(loc.call_site),
-                token_trees: Box::new([]),
-            }),
-            // FIXME: We should make sure to enforce an invariant that invalid macro
-            // calls do not reach this call path!
-            err: Some(ExpandError::other("invalid token tree")),
-        };
-    };
+    let (macro_arg, undo_info) = db.macro_arg(id).value;
 
     let expander = match loc.def.kind {
         MacroDefKind::ProcMacro(expander, ..) => expander,
diff --git a/src/tools/rust-analyzer/crates/hir-expand/src/declarative.rs b/src/tools/rust-analyzer/crates/hir-expand/src/declarative.rs
index 37084ee8b93..6874336cd2d 100644
--- a/src/tools/rust-analyzer/crates/hir-expand/src/declarative.rs
+++ b/src/tools/rust-analyzer/crates/hir-expand/src/declarative.rs
@@ -31,7 +31,7 @@ impl DeclarativeMacroExpander {
         call_id: MacroCallId,
     ) -> ExpandResult<tt::Subtree> {
         let loc = db.lookup_intern_macro_call(call_id);
-        let toolchain = &db.crate_graph()[loc.def.krate].toolchain;
+        let toolchain = db.toolchain(loc.def.krate);
         let new_meta_vars = toolchain.as_ref().map_or(false, |version| {
             REQUIREMENT.get_or_init(|| VersionReq::parse(">=1.76").unwrap()).matches(
                 &base_db::Version {
@@ -44,9 +44,9 @@ impl DeclarativeMacroExpander {
             )
         });
         match self.mac.err() {
-            Some(e) => ExpandResult::new(
+            Some(_) => ExpandResult::new(
                 tt::Subtree::empty(tt::DelimSpan { open: loc.call_site, close: loc.call_site }),
-                ExpandError::other(format!("invalid macro definition: {e}")),
+                ExpandError::MacroDefinition,
             ),
             None => self
                 .mac
@@ -67,7 +67,7 @@ impl DeclarativeMacroExpander {
         krate: CrateId,
         call_site: Span,
     ) -> ExpandResult<tt::Subtree> {
-        let toolchain = &db.crate_graph()[krate].toolchain;
+        let toolchain = db.toolchain(krate);
         let new_meta_vars = toolchain.as_ref().map_or(false, |version| {
             REQUIREMENT.get_or_init(|| VersionReq::parse(">=1.76").unwrap()).matches(
                 &base_db::Version {
@@ -80,9 +80,9 @@ impl DeclarativeMacroExpander {
             )
         });
         match self.mac.err() {
-            Some(e) => ExpandResult::new(
+            Some(_) => ExpandResult::new(
                 tt::Subtree::empty(tt::DelimSpan { open: call_site, close: call_site }),
-                ExpandError::other(format!("invalid macro definition: {e}")),
+                ExpandError::MacroDefinition,
             ),
             None => self.mac.expand(&tt, |_| (), new_meta_vars, call_site).map_err(Into::into),
         }
@@ -119,7 +119,7 @@ impl DeclarativeMacroExpander {
                 _ => None,
             }
         };
-        let toolchain = crate_data.toolchain.as_ref();
+        let toolchain = db.toolchain(def_crate);
         let new_meta_vars = toolchain.as_ref().map_or(false, |version| {
             REQUIREMENT.get_or_init(|| VersionReq::parse(">=1.76").unwrap()).matches(
                 &base_db::Version {
diff --git a/src/tools/rust-analyzer/crates/hir-expand/src/lib.rs b/src/tools/rust-analyzer/crates/hir-expand/src/lib.rs
index fd028182faf..020ca75d80c 100644
--- a/src/tools/rust-analyzer/crates/hir-expand/src/lib.rs
+++ b/src/tools/rust-analyzer/crates/hir-expand/src/lib.rs
@@ -44,7 +44,6 @@ use crate::{
     builtin_derive_macro::BuiltinDeriveExpander,
     builtin_fn_macro::{BuiltinFnLikeExpander, EagerExpander},
     db::{ExpandDatabase, TokenExpander},
-    fixup::SyntaxFixupUndoInfo,
     hygiene::SyntaxContextData,
     mod_path::ModPath,
     proc_macro::{CustomProcMacroExpander, ProcMacroKind},
@@ -129,8 +128,11 @@ pub type ExpandResult<T> = ValueResult<T, ExpandError>;
 #[derive(Debug, PartialEq, Eq, Clone, Hash)]
 pub enum ExpandError {
     UnresolvedProcMacro(CrateId),
+    /// The macro expansion is disabled.
+    MacroDisabled,
+    MacroDefinition,
     Mbe(mbe::ExpandError),
-    RecursionOverflowPoisoned,
+    RecursionOverflow,
     Other(Box<Box<str>>),
     ProcMacroPanic(Box<Box<str>>),
 }
@@ -152,14 +154,14 @@ impl fmt::Display for ExpandError {
         match self {
             ExpandError::UnresolvedProcMacro(_) => f.write_str("unresolved proc-macro"),
             ExpandError::Mbe(it) => it.fmt(f),
-            ExpandError::RecursionOverflowPoisoned => {
-                f.write_str("overflow expanding the original macro")
-            }
+            ExpandError::RecursionOverflow => f.write_str("overflow expanding the original macro"),
             ExpandError::ProcMacroPanic(it) => {
                 f.write_str("proc-macro panicked: ")?;
                 f.write_str(it)
             }
             ExpandError::Other(it) => f.write_str(it),
+            ExpandError::MacroDisabled => f.write_str("macro disabled"),
+            ExpandError::MacroDefinition => f.write_str("macro definition has parse errors"),
         }
     }
 }
@@ -225,8 +227,8 @@ pub enum MacroCallKind {
     },
     Attr {
         ast_id: AstId<ast::Item>,
-        // FIXME: This is being interned, subtrees can vary quickly differ just slightly causing
-        // leakage problems here
+        // FIXME: This shouldn't be here, we can derive this from `invoc_attr_index`
+        // but we need to fix the `cfg_attr` handling first.
         attr_args: Option<Arc<tt::Subtree>>,
         /// Syntactical index of the invoking `#[attribute]`.
         ///
@@ -758,15 +760,7 @@ impl ExpansionInfo {
         let (parse, exp_map) = db.parse_macro_expansion(macro_file).value;
         let expanded = InMacroFile { file_id: macro_file, value: parse.syntax_node() };
 
-        let (macro_arg, _) = db.macro_arg(macro_file.macro_call_id).value.unwrap_or_else(|| {
-            (
-                Arc::new(tt::Subtree {
-                    delimiter: tt::Delimiter::invisible_spanned(loc.call_site),
-                    token_trees: Box::new([]),
-                }),
-                SyntaxFixupUndoInfo::NONE,
-            )
-        });
+        let (macro_arg, _) = db.macro_arg(macro_file.macro_call_id).value;
 
         let def = loc.def.ast_id().left().and_then(|id| {
             let def_tt = match id.to_node(db) {
diff --git a/src/tools/rust-analyzer/crates/hir-expand/src/mod_path.rs b/src/tools/rust-analyzer/crates/hir-expand/src/mod_path.rs
index b64c3549e42..136b0935be2 100644
--- a/src/tools/rust-analyzer/crates/hir-expand/src/mod_path.rs
+++ b/src/tools/rust-analyzer/crates/hir-expand/src/mod_path.rs
@@ -94,6 +94,21 @@ impl ModPath {
             }
     }
 
+    pub fn textual_len(&self) -> usize {
+        let base = match self.kind {
+            PathKind::Plain => 0,
+            PathKind::Super(0) => "self".len(),
+            PathKind::Super(i) => "super".len() * i as usize,
+            PathKind::Crate => "crate".len(),
+            PathKind::Abs => 0,
+            PathKind::DollarCrate(_) => "$crate".len(),
+        };
+        self.segments()
+            .iter()
+            .map(|segment| segment.as_str().map_or(0, str::len))
+            .fold(base, core::ops::Add::add)
+    }
+
     pub fn is_ident(&self) -> bool {
         self.as_ident().is_some()
     }
diff --git a/src/tools/rust-analyzer/crates/hir-expand/src/proc_macro.rs b/src/tools/rust-analyzer/crates/hir-expand/src/proc_macro.rs
index 70b47fc54b1..ca6fc0afe2d 100644
--- a/src/tools/rust-analyzer/crates/hir-expand/src/proc_macro.rs
+++ b/src/tools/rust-analyzer/crates/hir-expand/src/proc_macro.rs
@@ -12,7 +12,13 @@ use syntax::SmolStr;
 use crate::{db::ExpandDatabase, tt, ExpandError, ExpandResult};
 
 #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
-pub struct ProcMacroId(pub u32);
+pub struct ProcMacroId(u32);
+
+impl ProcMacroId {
+    pub fn new(u32: u32) -> Self {
+        ProcMacroId(u32)
+    }
+}
 
 #[derive(Copy, Clone, Eq, PartialEq, Debug, Hash)]
 pub enum ProcMacroKind {
@@ -49,6 +55,7 @@ pub struct ProcMacro {
     pub name: SmolStr,
     pub kind: ProcMacroKind,
     pub expander: sync::Arc<dyn ProcMacroExpander>,
+    pub disabled: bool,
 }
 
 #[derive(Debug, Clone, Copy, Eq, PartialEq, Hash)]
@@ -56,20 +63,35 @@ pub struct CustomProcMacroExpander {
     proc_macro_id: ProcMacroId,
 }
 
-const DUMMY_ID: u32 = !0;
-
 impl CustomProcMacroExpander {
+    const DUMMY_ID: u32 = !0;
+    const DISABLED_ID: u32 = !1;
+
     pub fn new(proc_macro_id: ProcMacroId) -> Self {
-        assert_ne!(proc_macro_id.0, DUMMY_ID);
+        assert_ne!(proc_macro_id.0, Self::DUMMY_ID);
+        assert_ne!(proc_macro_id.0, Self::DISABLED_ID);
         Self { proc_macro_id }
     }
 
-    pub fn dummy() -> Self {
-        Self { proc_macro_id: ProcMacroId(DUMMY_ID) }
+    /// A dummy expander that always errors. This is used for proc-macros that are missing, usually
+    /// due to them not being built yet.
+    pub const fn dummy() -> Self {
+        Self { proc_macro_id: ProcMacroId(Self::DUMMY_ID) }
+    }
+
+    /// The macro was not yet resolved.
+    pub const fn is_dummy(&self) -> bool {
+        self.proc_macro_id.0 == Self::DUMMY_ID
+    }
+
+    /// A dummy expander that always errors. This expander is used for macros that have been disabled.
+    pub const fn disabled() -> Self {
+        Self { proc_macro_id: ProcMacroId(Self::DISABLED_ID) }
     }
 
-    pub fn is_dummy(&self) -> bool {
-        self.proc_macro_id.0 == DUMMY_ID
+    /// The macro is explicitly disabled and cannot be expanded.
+    pub const fn is_disabled(&self) -> bool {
+        self.proc_macro_id.0 == Self::DISABLED_ID
     }
 
     pub fn expand(
@@ -84,10 +106,14 @@ impl CustomProcMacroExpander {
         mixed_site: Span,
     ) -> ExpandResult<tt::Subtree> {
         match self.proc_macro_id {
-            ProcMacroId(DUMMY_ID) => ExpandResult::new(
+            ProcMacroId(Self::DUMMY_ID) => ExpandResult::new(
                 tt::Subtree::empty(tt::DelimSpan { open: call_site, close: call_site }),
                 ExpandError::UnresolvedProcMacro(def_crate),
             ),
+            ProcMacroId(Self::DISABLED_ID) => ExpandResult::new(
+                tt::Subtree::empty(tt::DelimSpan { open: call_site, close: call_site }),
+                ExpandError::MacroDisabled,
+            ),
             ProcMacroId(id) => {
                 let proc_macros = db.proc_macros();
                 let proc_macros = match proc_macros.get(&def_crate) {
@@ -110,7 +136,7 @@ impl CustomProcMacroExpander {
                         );
                         return ExpandResult::new(
                             tt::Subtree::empty(tt::DelimSpan { open: call_site, close: call_site }),
-                            ExpandError::other("Internal error"),
+                            ExpandError::other("Internal error: proc-macro index out of bounds"),
                         );
                     }
                 };
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 7f8fb7f4b52..c4329a7b82b 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
@@ -169,9 +169,9 @@ impl ExprValidator {
             return;
         }
 
-        let pattern_arena = Arena::new();
-        let cx = MatchCheckCtx::new(self.owner.module(db.upcast()), self.owner, db, &pattern_arena);
+        let cx = MatchCheckCtx::new(self.owner.module(db.upcast()), self.owner, db);
 
+        let pattern_arena = Arena::new();
         let mut m_arms = Vec::with_capacity(arms.len());
         let mut has_lowering_errors = false;
         for arm in arms {
@@ -196,8 +196,9 @@ impl ExprValidator {
                     // If we had a NotUsefulMatchArm diagnostic, we could
                     // check the usefulness of each pattern as we added it
                     // to the matrix here.
+                    let pat = self.lower_pattern(&cx, arm.pat, db, &body, &mut has_lowering_errors);
                     let m_arm = pat_analysis::MatchArm {
-                        pat: self.lower_pattern(&cx, arm.pat, db, &body, &mut has_lowering_errors),
+                        pat: pattern_arena.alloc(pat),
                         has_guard: arm.guard.is_some(),
                         arm_data: (),
                     };
@@ -223,7 +224,7 @@ impl ExprValidator {
             ValidityConstraint::ValidOnly,
         ) {
             Ok(report) => report,
-            Err(void) => match void {},
+            Err(()) => return,
         };
 
         // FIXME Report unreachable arms
@@ -245,10 +246,10 @@ impl ExprValidator {
         db: &dyn HirDatabase,
         body: &Body,
         have_errors: &mut bool,
-    ) -> &'p DeconstructedPat<'p> {
+    ) -> DeconstructedPat<'p> {
         let mut patcx = match_check::PatCtxt::new(db, &self.infer, body);
         let pattern = patcx.lower_pattern(pat);
-        let pattern = cx.pattern_arena.alloc(cx.lower_pat(&pattern));
+        let pattern = cx.lower_pat(&pattern);
         if !patcx.errors.is_empty() {
             *have_errors = true;
         }
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 712842372b6..e98a946a870 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
@@ -1,6 +1,7 @@
 //! Interface with `rustc_pattern_analysis`.
 
 use std::fmt;
+use tracing::debug;
 
 use hir_def::{DefWithBodyId, EnumVariantId, HasModule, LocalFieldId, ModuleId, VariantId};
 use rustc_hash::FxHashMap;
@@ -11,7 +12,6 @@ use rustc_pattern_analysis::{
 };
 use smallvec::{smallvec, SmallVec};
 use stdx::never;
-use typed_arena::Arena;
 
 use crate::{
     db::HirDatabase,
@@ -26,7 +26,7 @@ use Constructor::*;
 
 // Re-export r-a-specific versions of all these types.
 pub(crate) type DeconstructedPat<'p> =
-    rustc_pattern_analysis::pat::DeconstructedPat<'p, MatchCheckCtx<'p>>;
+    rustc_pattern_analysis::pat::DeconstructedPat<MatchCheckCtx<'p>>;
 pub(crate) type MatchArm<'p> = rustc_pattern_analysis::MatchArm<'p, MatchCheckCtx<'p>>;
 pub(crate) type WitnessPat<'p> = rustc_pattern_analysis::pat::WitnessPat<MatchCheckCtx<'p>>;
 
@@ -40,7 +40,6 @@ pub(crate) struct MatchCheckCtx<'p> {
     module: ModuleId,
     body: DefWithBodyId,
     pub(crate) db: &'p dyn HirDatabase,
-    pub(crate) pattern_arena: &'p Arena<DeconstructedPat<'p>>,
     exhaustive_patterns: bool,
     min_exhaustive_patterns: bool,
 }
@@ -52,17 +51,12 @@ pub(crate) struct PatData<'p> {
 }
 
 impl<'p> MatchCheckCtx<'p> {
-    pub(crate) fn new(
-        module: ModuleId,
-        body: DefWithBodyId,
-        db: &'p dyn HirDatabase,
-        pattern_arena: &'p Arena<DeconstructedPat<'p>>,
-    ) -> Self {
+    pub(crate) fn new(module: ModuleId, body: DefWithBodyId, db: &'p dyn HirDatabase) -> Self {
         let def_map = db.crate_def_map(module.krate());
         let exhaustive_patterns = def_map.is_unstable_feature_enabled("exhaustive_patterns");
         let min_exhaustive_patterns =
             def_map.is_unstable_feature_enabled("min_exhaustive_patterns");
-        Self { module, body, db, pattern_arena, exhaustive_patterns, min_exhaustive_patterns }
+        Self { module, body, db, exhaustive_patterns, min_exhaustive_patterns }
     }
 
     fn is_uninhabited(&self, ty: &Ty) -> bool {
@@ -131,15 +125,15 @@ impl<'p> MatchCheckCtx<'p> {
     }
 
     pub(crate) fn lower_pat(&self, pat: &Pat) -> DeconstructedPat<'p> {
-        let singleton = |pat| std::slice::from_ref(self.pattern_arena.alloc(pat));
+        let singleton = |pat| vec![pat];
         let ctor;
-        let fields: &[_];
+        let fields: Vec<_>;
 
         match pat.kind.as_ref() {
             PatKind::Binding { subpattern: Some(subpat), .. } => return self.lower_pat(subpat),
             PatKind::Binding { subpattern: None, .. } | PatKind::Wild => {
                 ctor = Wildcard;
-                fields = &[];
+                fields = Vec::new();
             }
             PatKind::Deref { subpattern } => {
                 ctor = match pat.ty.kind(Interner) {
@@ -157,7 +151,7 @@ impl<'p> MatchCheckCtx<'p> {
                 match pat.ty.kind(Interner) {
                     TyKind::Tuple(_, substs) => {
                         ctor = Struct;
-                        let mut wilds: SmallVec<[_; 2]> = substs
+                        let mut wilds: Vec<_> = substs
                             .iter(Interner)
                             .map(|arg| arg.assert_ty_ref(Interner).clone())
                             .map(DeconstructedPat::wildcard)
@@ -166,7 +160,7 @@ impl<'p> MatchCheckCtx<'p> {
                             let idx: u32 = pat.field.into_raw().into();
                             wilds[idx as usize] = self.lower_pat(&pat.pattern);
                         }
-                        fields = self.pattern_arena.alloc_extend(wilds)
+                        fields = wilds
                     }
                     TyKind::Adt(adt, substs) if is_box(self.db, adt.0) => {
                         // The only legal patterns of type `Box` (outside `std`) are `_` and box
@@ -216,33 +210,29 @@ impl<'p> MatchCheckCtx<'p> {
                                 field_id_to_id[field_idx as usize] = Some(i);
                                 ty
                             });
-                        let mut wilds: SmallVec<[_; 2]> =
-                            tys.map(DeconstructedPat::wildcard).collect();
+                        let mut wilds: Vec<_> = tys.map(DeconstructedPat::wildcard).collect();
                         for pat in subpatterns {
                             let field_idx: u32 = pat.field.into_raw().into();
                             if let Some(i) = field_id_to_id[field_idx as usize] {
                                 wilds[i] = self.lower_pat(&pat.pattern);
                             }
                         }
-                        fields = self.pattern_arena.alloc_extend(wilds);
+                        fields = wilds;
                     }
                     _ => {
                         never!("pattern has unexpected type: pat: {:?}, ty: {:?}", pat, &pat.ty);
                         ctor = Wildcard;
-                        fields = &[];
+                        fields = Vec::new();
                     }
                 }
             }
             &PatKind::LiteralBool { value } => {
                 ctor = Bool(value);
-                fields = &[];
+                fields = Vec::new();
             }
             PatKind::Or { pats } => {
                 ctor = Or;
-                // Collect here because `Arena::alloc_extend` panics on reentrancy.
-                let subpats: SmallVec<[_; 2]> =
-                    pats.iter().map(|pat| self.lower_pat(pat)).collect();
-                fields = self.pattern_arena.alloc_extend(subpats);
+                fields = pats.iter().map(|pat| self.lower_pat(pat)).collect();
             }
         }
         let data = PatData { db: self.db };
@@ -307,7 +297,7 @@ impl<'p> MatchCheckCtx<'p> {
 }
 
 impl<'p> TypeCx for MatchCheckCtx<'p> {
-    type Error = Void;
+    type Error = ();
     type Ty = Ty;
     type VariantIdx = EnumVariantId;
     type StrLit = Void;
@@ -463,7 +453,7 @@ impl<'p> TypeCx for MatchCheckCtx<'p> {
 
     fn write_variant_name(
         f: &mut fmt::Formatter<'_>,
-        pat: &rustc_pattern_analysis::pat::DeconstructedPat<'_, Self>,
+        pat: &rustc_pattern_analysis::pat::DeconstructedPat<Self>,
     ) -> fmt::Result {
         let variant =
             pat.ty().as_adt().and_then(|(adt, _)| Self::variant_id_for_adt(pat.ctor(), adt));
@@ -485,8 +475,8 @@ impl<'p> TypeCx for MatchCheckCtx<'p> {
         Ok(())
     }
 
-    fn bug(&self, fmt: fmt::Arguments<'_>) -> ! {
-        panic!("{}", fmt)
+    fn bug(&self, fmt: fmt::Arguments<'_>) {
+        debug!("{}", fmt)
     }
 }
 
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/match_check/pat_util.rs b/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/match_check/pat_util.rs
index 217454499ef..c6a26cdd1d0 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/match_check/pat_util.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/match_check/pat_util.rs
@@ -2,7 +2,7 @@
 //!
 //! Originates from `rustc_hir::pat_util`
 
-use std::iter::{Enumerate, ExactSizeIterator};
+use std::iter::Enumerate;
 
 pub(crate) struct EnumerateAndAdjust<I> {
     enumerate: Enumerate<I>,
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 71c3f89716d..1977f00517c 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/infer.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/infer.rs
@@ -26,7 +26,7 @@ use std::{convert::identity, ops::Index};
 
 use chalk_ir::{
     cast::Cast, fold::TypeFoldable, interner::HasInterner, DebruijnIndex, Mutability, Safety,
-    Scalar, TyKind, TypeFlags,
+    Scalar, TyKind, TypeFlags, Variance,
 };
 use either::Either;
 use hir_def::{
@@ -58,8 +58,9 @@ use crate::{
     static_lifetime, to_assoc_type_id,
     traits::FnTrait,
     utils::{InTypeConstIdMetadata, UnevaluatedConstEvaluatorFolder},
-    AliasEq, AliasTy, ClosureId, DomainGoal, GenericArg, Goal, ImplTraitId, InEnvironment,
-    Interner, ProjectionTy, RpitId, Substitution, TraitEnvironment, TraitRef, Ty, TyBuilder, TyExt,
+    AliasEq, AliasTy, Binders, ClosureId, Const, DomainGoal, GenericArg, Goal, ImplTraitId,
+    InEnvironment, Interner, Lifetime, ProjectionTy, RpitId, Substitution, TraitEnvironment,
+    TraitRef, Ty, TyBuilder, TyExt,
 };
 
 // This lint has a false positive here. See the link below for details.
@@ -68,7 +69,7 @@ use crate::{
 #[allow(unreachable_pub)]
 pub use coerce::could_coerce;
 #[allow(unreachable_pub)]
-pub use unify::could_unify;
+pub use unify::{could_unify, could_unify_deeply};
 
 use cast::CastCheck;
 pub(crate) use closure::{CaptureKind, CapturedItem, CapturedItemWithoutTy};
@@ -688,10 +689,17 @@ impl<'a> InferenceContext<'a> {
         for ty in type_of_for_iterator.values_mut() {
             *ty = table.resolve_completely(ty.clone());
         }
-        for mismatch in type_mismatches.values_mut() {
+        type_mismatches.retain(|_, mismatch| {
             mismatch.expected = table.resolve_completely(mismatch.expected.clone());
             mismatch.actual = table.resolve_completely(mismatch.actual.clone());
-        }
+            chalk_ir::zip::Zip::zip_with(
+                &mut UnknownMismatch(self.db),
+                Variance::Invariant,
+                &mismatch.expected,
+                &mismatch.actual,
+            )
+            .is_ok()
+        });
         diagnostics.retain_mut(|diagnostic| {
             use InferenceDiagnostic::*;
             match diagnostic {
@@ -1502,3 +1510,116 @@ impl std::ops::BitOrAssign for Diverges {
         *self = *self | other;
     }
 }
+/// A zipper that checks for unequal `{unknown}` occurrences in the two types. Used to filter out
+/// mismatch diagnostics that only differ in `{unknown}`. These mismatches are usually not helpful.
+/// As the cause is usually an underlying name resolution problem.
+struct UnknownMismatch<'db>(&'db dyn HirDatabase);
+impl chalk_ir::zip::Zipper<Interner> for UnknownMismatch<'_> {
+    fn zip_tys(&mut self, variance: Variance, a: &Ty, b: &Ty) -> chalk_ir::Fallible<()> {
+        let zip_substs = |this: &mut Self,
+                          variances,
+                          sub_a: &Substitution,
+                          sub_b: &Substitution| {
+            this.zip_substs(variance, variances, sub_a.as_slice(Interner), sub_b.as_slice(Interner))
+        };
+        match (a.kind(Interner), b.kind(Interner)) {
+            (TyKind::Adt(id_a, sub_a), TyKind::Adt(id_b, sub_b)) if id_a == id_b => zip_substs(
+                self,
+                Some(self.unification_database().adt_variance(*id_a)),
+                sub_a,
+                sub_b,
+            )?,
+            (
+                TyKind::AssociatedType(assoc_ty_a, sub_a),
+                TyKind::AssociatedType(assoc_ty_b, sub_b),
+            ) if assoc_ty_a == assoc_ty_b => zip_substs(self, None, sub_a, sub_b)?,
+            (TyKind::Tuple(arity_a, sub_a), TyKind::Tuple(arity_b, sub_b))
+                if arity_a == arity_b =>
+            {
+                zip_substs(self, None, sub_a, sub_b)?
+            }
+            (TyKind::OpaqueType(opaque_ty_a, sub_a), TyKind::OpaqueType(opaque_ty_b, sub_b))
+                if opaque_ty_a == opaque_ty_b =>
+            {
+                zip_substs(self, None, sub_a, sub_b)?
+            }
+            (TyKind::Slice(ty_a), TyKind::Slice(ty_b)) => self.zip_tys(variance, ty_a, ty_b)?,
+            (TyKind::FnDef(fn_def_a, sub_a), TyKind::FnDef(fn_def_b, sub_b))
+                if fn_def_a == fn_def_b =>
+            {
+                zip_substs(
+                    self,
+                    Some(self.unification_database().fn_def_variance(*fn_def_a)),
+                    sub_a,
+                    sub_b,
+                )?
+            }
+            (TyKind::Ref(mutability_a, _, ty_a), TyKind::Ref(mutability_b, _, ty_b))
+                if mutability_a == mutability_b =>
+            {
+                self.zip_tys(variance, ty_a, ty_b)?
+            }
+            (TyKind::Raw(mutability_a, ty_a), TyKind::Raw(mutability_b, ty_b))
+                if mutability_a == mutability_b =>
+            {
+                self.zip_tys(variance, ty_a, ty_b)?
+            }
+            (TyKind::Array(ty_a, const_a), TyKind::Array(ty_b, const_b)) if const_a == const_b => {
+                self.zip_tys(variance, ty_a, ty_b)?
+            }
+            (TyKind::Closure(id_a, sub_a), TyKind::Closure(id_b, sub_b)) if id_a == id_b => {
+                zip_substs(self, None, sub_a, sub_b)?
+            }
+            (TyKind::Coroutine(coroutine_a, sub_a), TyKind::Coroutine(coroutine_b, sub_b))
+                if coroutine_a == coroutine_b =>
+            {
+                zip_substs(self, None, sub_a, sub_b)?
+            }
+            (
+                TyKind::CoroutineWitness(coroutine_a, sub_a),
+                TyKind::CoroutineWitness(coroutine_b, sub_b),
+            ) if coroutine_a == coroutine_b => zip_substs(self, None, sub_a, sub_b)?,
+            (TyKind::Function(fn_ptr_a), TyKind::Function(fn_ptr_b))
+                if fn_ptr_a.sig == fn_ptr_b.sig && fn_ptr_a.num_binders == fn_ptr_b.num_binders =>
+            {
+                zip_substs(self, None, &fn_ptr_a.substitution.0, &fn_ptr_b.substitution.0)?
+            }
+            (TyKind::Error, TyKind::Error) => (),
+            (TyKind::Error, _) | (_, TyKind::Error) => return Err(chalk_ir::NoSolution),
+            _ => (),
+        }
+
+        Ok(())
+    }
+
+    fn zip_lifetimes(&mut self, _: Variance, _: &Lifetime, _: &Lifetime) -> chalk_ir::Fallible<()> {
+        Ok(())
+    }
+
+    fn zip_consts(&mut self, _: Variance, _: &Const, _: &Const) -> chalk_ir::Fallible<()> {
+        Ok(())
+    }
+
+    fn zip_binders<T>(
+        &mut self,
+        variance: Variance,
+        a: &Binders<T>,
+        b: &Binders<T>,
+    ) -> chalk_ir::Fallible<()>
+    where
+        T: Clone
+            + HasInterner<Interner = Interner>
+            + chalk_ir::zip::Zip<Interner>
+            + TypeFoldable<Interner>,
+    {
+        chalk_ir::zip::Zip::zip_with(self, variance, a.skip_binders(), b.skip_binders())
+    }
+
+    fn interner(&self) -> Interner {
+        Interner
+    }
+
+    fn unification_database(&self) -> &dyn chalk_ir::UnificationDatabase<Interner> {
+        &self.0
+    }
+}
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 c3746f78706..22a70f951ea 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
@@ -485,6 +485,7 @@ impl InferenceContext<'_> {
                         Statement::Expr { expr, has_semi: _ } => {
                             self.consume_expr(*expr);
                         }
+                        Statement::Item => (),
                     }
                 }
                 if let Some(tail) = tail {
@@ -531,6 +532,9 @@ impl InferenceContext<'_> {
                     self.consume_expr(expr);
                 }
             }
+            &Expr::Become { expr } => {
+                self.consume_expr(expr);
+            }
             Expr::RecordLit { fields, spread, .. } => {
                 if let &Some(expr) = spread {
                     self.consume_expr(expr);
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 8b8e97b0081..428ed6748c6 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
@@ -502,6 +502,7 @@ impl InferenceContext<'_> {
                 self.result.standard_types.never.clone()
             }
             &Expr::Return { expr } => self.infer_expr_return(tgt_expr, expr),
+            &Expr::Become { expr } => self.infer_expr_become(expr),
             Expr::Yield { expr } => {
                 if let Some((resume_ty, yield_ty)) = self.resume_yield_tys.clone() {
                     if let Some(expr) = expr {
@@ -1084,6 +1085,27 @@ impl InferenceContext<'_> {
         self.result.standard_types.never.clone()
     }
 
+    fn infer_expr_become(&mut self, expr: ExprId) -> Ty {
+        match &self.return_coercion {
+            Some(return_coercion) => {
+                let ret_ty = return_coercion.expected_ty();
+
+                let call_expr_ty =
+                    self.infer_expr_inner(expr, &Expectation::HasType(ret_ty.clone()));
+
+                // NB: this should *not* coerce.
+                //     tail calls don't support any coercions except lifetimes ones (like `&'static u8 -> &'a u8`).
+                self.unify(&call_expr_ty, &ret_ty);
+            }
+            None => {
+                // FIXME: diagnose `become` outside of functions
+                self.infer_expr_no_expect(expr);
+            }
+        }
+
+        self.result.standard_types.never.clone()
+    }
+
     fn infer_expr_box(&mut self, inner_expr: ExprId, expected: &Expectation) -> Ty {
         if let Some(box_id) = self.resolve_boxed_box() {
             let table = &mut self.table;
@@ -1367,6 +1389,7 @@ impl InferenceContext<'_> {
                                 );
                             }
                         }
+                        Statement::Item => (),
                     }
                 }
 
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/infer/mutability.rs b/src/tools/rust-analyzer/crates/hir-ty/src/infer/mutability.rs
index 663ea853231..00e5eac229f 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/infer/mutability.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/infer/mutability.rs
@@ -65,6 +65,7 @@ impl InferenceContext<'_> {
                         Statement::Expr { expr, has_semi: _ } => {
                             self.infer_mut_expr(*expr, Mutability::Not);
                         }
+                        Statement::Item => (),
                     }
                 }
                 if let Some(tail) = tail {
@@ -93,6 +94,9 @@ impl InferenceContext<'_> {
                     self.infer_mut_expr(expr, Mutability::Not);
                 }
             }
+            Expr::Become { expr } => {
+                self.infer_mut_expr(*expr, Mutability::Not);
+            }
             Expr::RecordLit { path: _, fields, spread, ellipsis: _, is_assignee_expr: _ } => {
                 self.infer_mut_not_expr_iter(fields.iter().map(|it| it.expr).chain(*spread))
             }
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 de23ca34990..709760b64fd 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
@@ -74,6 +74,12 @@ impl<T: HasInterner<Interner = Interner>> Canonicalized<T> {
     }
 }
 
+/// Check if types unify.
+///
+/// Note that we consider placeholder types to unify with everything.
+/// This means that there may be some unresolved goals that actually set bounds for the placeholder
+/// type for the types to unify. For example `Option<T>` and `Option<U>` unify although there is
+/// unresolved goal `T = U`.
 pub fn could_unify(
     db: &dyn HirDatabase,
     env: Arc<TraitEnvironment>,
@@ -82,21 +88,35 @@ pub fn could_unify(
     unify(db, env, tys).is_some()
 }
 
+/// Check if types unify eagerly making sure there are no unresolved goals.
+///
+/// This means that placeholder types are not considered to unify if there are any bounds set on
+/// 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>,
+    tys: &Canonical<(Ty, Ty)>,
+) -> bool {
+    let mut table = InferenceTable::new(db, env);
+    let vars = make_substitutions(tys, &mut table);
+    let ty1_with_vars = vars.apply(tys.value.0.clone(), Interner);
+    let ty2_with_vars = vars.apply(tys.value.1.clone(), Interner);
+    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.resolve_obligations_as_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)
+}
+
 pub(crate) fn unify(
     db: &dyn HirDatabase,
     env: Arc<TraitEnvironment>,
     tys: &Canonical<(Ty, Ty)>,
 ) -> Option<Substitution> {
     let mut table = InferenceTable::new(db, env);
-    let vars = Substitution::from_iter(
-        Interner,
-        tys.binders.iter(Interner).map(|it| match &it.kind {
-            chalk_ir::VariableKind::Ty(_) => table.new_type_var().cast(Interner),
-            // FIXME: maybe wrong?
-            chalk_ir::VariableKind::Lifetime => table.new_type_var().cast(Interner),
-            chalk_ir::VariableKind::Const(ty) => table.new_const_var(ty.clone()).cast(Interner),
-        }),
-    );
+    let vars = make_substitutions(tys, &mut table);
     let ty1_with_vars = vars.apply(tys.value.0.clone(), Interner);
     let ty2_with_vars = vars.apply(tys.value.1.clone(), Interner);
     if !table.unify(&ty1_with_vars, &ty2_with_vars) {
@@ -125,6 +145,21 @@ pub(crate) fn unify(
     ))
 }
 
+fn make_substitutions(
+    tys: &chalk_ir::Canonical<(chalk_ir::Ty<Interner>, chalk_ir::Ty<Interner>)>,
+    table: &mut InferenceTable<'_>,
+) -> chalk_ir::Substitution<Interner> {
+    Substitution::from_iter(
+        Interner,
+        tys.binders.iter(Interner).map(|it| match &it.kind {
+            chalk_ir::VariableKind::Ty(_) => table.new_type_var().cast(Interner),
+            // FIXME: maybe wrong?
+            chalk_ir::VariableKind::Lifetime => table.new_type_var().cast(Interner),
+            chalk_ir::VariableKind::Const(ty) => table.new_const_var(ty.clone()).cast(Interner),
+        }),
+    )
+}
+
 bitflags::bitflags! {
     #[derive(Default, Clone, Copy)]
     pub(crate) struct TypeVariableFlags: u8 {
@@ -431,6 +466,18 @@ impl<'a> InferenceTable<'a> {
         true
     }
 
+    /// Unify two relatable values (e.g. `Ty`) and check whether trait goals which arise from that could be fulfilled
+    pub(crate) fn unify_deeply<T: ?Sized + Zip<Interner>>(&mut self, ty1: &T, ty2: &T) -> bool {
+        let result = match self.try_unify(ty1, ty2) {
+            Ok(r) => r,
+            Err(_) => return false,
+        };
+        result.goals.iter().all(|goal| {
+            let canonicalized = self.canonicalize(goal.clone());
+            self.try_resolve_obligation(&canonicalized).is_some()
+        })
+    }
+
     /// Unify two relatable values (e.g. `Ty`) and return new trait goals arising from it, so the
     /// caller needs to deal with them.
     pub(crate) fn try_unify<T: ?Sized + Zip<Interner>>(
@@ -501,7 +548,8 @@ impl<'a> InferenceTable<'a> {
 
     fn register_obligation_in_env(&mut self, goal: InEnvironment<Goal>) {
         let canonicalized = self.canonicalize(goal);
-        if !self.try_resolve_obligation(&canonicalized) {
+        let solution = self.try_resolve_obligation(&canonicalized);
+        if matches!(solution, Some(Solution::Ambig(_))) {
             self.pending_obligations.push(canonicalized);
         }
     }
@@ -627,38 +675,35 @@ impl<'a> InferenceTable<'a> {
     fn try_resolve_obligation(
         &mut self,
         canonicalized: &Canonicalized<InEnvironment<Goal>>,
-    ) -> bool {
+    ) -> Option<chalk_solve::Solution<Interner>> {
         let solution = self.db.trait_solve(
             self.trait_env.krate,
             self.trait_env.block,
             canonicalized.value.clone(),
         );
 
-        match solution {
+        match &solution {
             Some(Solution::Unique(canonical_subst)) => {
                 canonicalized.apply_solution(
                     self,
                     Canonical {
-                        binders: canonical_subst.binders,
+                        binders: canonical_subst.binders.clone(),
                         // FIXME: handle constraints
-                        value: canonical_subst.value.subst,
+                        value: canonical_subst.value.subst.clone(),
                     },
                 );
-                true
             }
             Some(Solution::Ambig(Guidance::Definite(substs))) => {
-                canonicalized.apply_solution(self, substs);
-                false
+                canonicalized.apply_solution(self, substs.clone());
             }
             Some(_) => {
                 // FIXME use this when trying to resolve everything at the end
-                false
             }
             None => {
                 // FIXME obligation cannot be fulfilled => diagnostic
-                true
             }
         }
+        solution
     }
 
     pub(crate) fn callable_sig(
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/layout/target.rs b/src/tools/rust-analyzer/crates/hir-ty/src/layout/target.rs
index 5bfe7bf010f..9b1424548c2 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/layout/target.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/layout/target.rs
@@ -11,10 +11,8 @@ pub fn target_data_layout_query(
     db: &dyn HirDatabase,
     krate: CrateId,
 ) -> Result<Arc<TargetDataLayout>, Arc<str>> {
-    let crate_graph = db.crate_graph();
-    let res = crate_graph[krate].target_layout.as_deref();
-    match res {
-        Ok(it) => match TargetDataLayout::parse_from_llvm_datalayout_string(it) {
+    match db.data_layout(krate) {
+        Ok(it) => match TargetDataLayout::parse_from_llvm_datalayout_string(&it) {
             Ok(it) => Ok(Arc::new(it)),
             Err(e) => {
                 Err(match e {
@@ -44,6 +42,6 @@ pub fn target_data_layout_query(
                 }.into())
             }
         },
-        Err(e) => Err(Arc::from(&**e)),
+        Err(e) => Err(e),
     }
 }
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 ba3dfe8100d..6c1eccb75e6 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,6 +1,7 @@
 use chalk_ir::{AdtId, TyKind};
 use either::Either;
 use hir_def::db::DefDatabase;
+use project_model::target_data_layout::RustcDataLayoutConfig;
 use rustc_hash::FxHashMap;
 use test_fixture::WithFixture;
 use triomphe::Arc;
@@ -15,13 +16,18 @@ use crate::{
 mod closure;
 
 fn current_machine_data_layout() -> String {
-    project_model::target_data_layout::get(None, None, &FxHashMap::default()).unwrap()
+    project_model::target_data_layout::get(
+        RustcDataLayoutConfig::Rustc(None),
+        None,
+        &FxHashMap::default(),
+    )
+    .unwrap()
 }
 
 fn eval_goal(ra_fixture: &str, minicore: &str) -> Result<Arc<Layout>, LayoutError> {
     let target_data_layout = current_machine_data_layout();
     let ra_fixture = format!(
-        "{minicore}//- /main.rs crate:test target_data_layout:{target_data_layout}\n{ra_fixture}",
+        "//- target_data_layout: {target_data_layout}\n{minicore}//- /main.rs crate:test\n{ra_fixture}",
     );
 
     let (db, file_ids) = TestDB::with_many_files(&ra_fixture);
@@ -70,7 +76,7 @@ fn eval_goal(ra_fixture: &str, minicore: &str) -> Result<Arc<Layout>, LayoutErro
 fn eval_expr(ra_fixture: &str, minicore: &str) -> Result<Arc<Layout>, LayoutError> {
     let target_data_layout = current_machine_data_layout();
     let ra_fixture = format!(
-        "{minicore}//- /main.rs crate:test target_data_layout:{target_data_layout}\nfn main(){{let goal = {{{ra_fixture}}};}}",
+        "//- target_data_layout: {target_data_layout}\n{minicore}//- /main.rs crate:test\nfn main(){{let goal = {{{ra_fixture}}};}}",
     );
 
     let (db, file_id) = TestDB::with_single_file(&ra_fixture);
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 70138633341..ec97bdc2c43 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/lib.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/lib.rs
@@ -79,8 +79,8 @@ pub use builder::{ParamKind, TyBuilder};
 pub use chalk_ext::*;
 pub use infer::{
     closure::{CaptureKind, CapturedItem},
-    could_coerce, could_unify, Adjust, Adjustment, AutoBorrow, BindingMode, InferenceDiagnostic,
-    InferenceResult, OverloadedDeref, PointerCast,
+    could_coerce, could_unify, could_unify_deeply, Adjust, Adjustment, AutoBorrow, BindingMode,
+    InferenceDiagnostic, InferenceResult, OverloadedDeref, PointerCast,
 };
 pub use interner::Interner;
 pub use lower::{
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/mir/borrowck.rs b/src/tools/rust-analyzer/crates/hir-ty/src/mir/borrowck.rs
index 9089c11c5d9..63fa87ad662 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/mir/borrowck.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/mir/borrowck.rs
@@ -7,6 +7,7 @@ use std::iter;
 
 use hir_def::{DefWithBodyId, HasModule};
 use la_arena::ArenaMap;
+use rustc_hash::FxHashMap;
 use stdx::never;
 use triomphe::Arc;
 
@@ -14,7 +15,7 @@ use crate::{
     db::{HirDatabase, InternedClosure},
     mir::Operand,
     utils::ClosureSubst,
-    ClosureId, Interner, Ty, TyExt, TypeFlags,
+    ClosureId, Interner, Substitution, Ty, TyExt, TypeFlags,
 };
 
 use super::{
@@ -37,10 +38,26 @@ pub struct MovedOutOfRef {
 }
 
 #[derive(Debug, Clone, PartialEq, Eq)]
+pub struct PartiallyMoved {
+    pub ty: Ty,
+    pub span: MirSpan,
+    pub local: LocalId,
+}
+
+#[derive(Debug, Clone, PartialEq, Eq)]
+pub struct BorrowRegion {
+    pub local: LocalId,
+    pub kind: BorrowKind,
+    pub places: Vec<MirSpan>,
+}
+
+#[derive(Debug, Clone, PartialEq, Eq)]
 pub struct BorrowckResult {
     pub mir_body: Arc<MirBody>,
     pub mutability_of_locals: ArenaMap<LocalId, MutabilityReason>,
     pub moved_out_of_ref: Vec<MovedOutOfRef>,
+    pub partially_moved: Vec<PartiallyMoved>,
+    pub borrow_regions: Vec<BorrowRegion>,
 }
 
 fn all_mir_bodies(
@@ -80,12 +97,26 @@ pub fn borrowck_query(
         res.push(BorrowckResult {
             mutability_of_locals: mutability_of_locals(db, &body),
             moved_out_of_ref: moved_out_of_ref(db, &body),
+            partially_moved: partially_moved(db, &body),
+            borrow_regions: borrow_regions(db, &body),
             mir_body: body,
         });
     })?;
     Ok(res.into())
 }
 
+fn make_fetch_closure_field(
+    db: &dyn HirDatabase,
+) -> impl FnOnce(ClosureId, &Substitution, usize) -> Ty + '_ {
+    |c: ClosureId, subst: &Substitution, f: usize| {
+        let InternedClosure(def, _) = db.lookup_intern_closure(c.into());
+        let infer = db.infer(def);
+        let (captures, _) = infer.closure_info(&c);
+        let parent_subst = ClosureSubst(subst).parent_subst();
+        captures.get(f).expect("broken closure field").ty.clone().substitute(Interner, parent_subst)
+    }
+}
+
 fn moved_out_of_ref(db: &dyn HirDatabase, body: &MirBody) -> Vec<MovedOutOfRef> {
     let mut result = vec![];
     let mut for_operand = |op: &Operand, span: MirSpan| match op {
@@ -99,18 +130,7 @@ fn moved_out_of_ref(db: &dyn HirDatabase, body: &MirBody) -> Vec<MovedOutOfRef>
                 ty = proj.projected_ty(
                     ty,
                     db,
-                    |c, subst, f| {
-                        let InternedClosure(def, _) = db.lookup_intern_closure(c.into());
-                        let infer = db.infer(def);
-                        let (captures, _) = infer.closure_info(&c);
-                        let parent_subst = ClosureSubst(subst).parent_subst();
-                        captures
-                            .get(f)
-                            .expect("broken closure field")
-                            .ty
-                            .clone()
-                            .substitute(Interner, parent_subst)
-                    },
+                    make_fetch_closure_field(db),
                     body.owner.module(db.upcast()).krate(),
                 );
             }
@@ -188,6 +208,132 @@ fn moved_out_of_ref(db: &dyn HirDatabase, body: &MirBody) -> Vec<MovedOutOfRef>
     result
 }
 
+fn partially_moved(db: &dyn HirDatabase, body: &MirBody) -> Vec<PartiallyMoved> {
+    let mut result = vec![];
+    let mut for_operand = |op: &Operand, span: MirSpan| match op {
+        Operand::Copy(p) | Operand::Move(p) => {
+            let mut ty: Ty = body.locals[p.local].ty.clone();
+            for proj in p.projection.lookup(&body.projection_store) {
+                ty = proj.projected_ty(
+                    ty,
+                    db,
+                    make_fetch_closure_field(db),
+                    body.owner.module(db.upcast()).krate(),
+                );
+            }
+            if !ty.clone().is_copy(db, body.owner)
+                && !ty.data(Interner).flags.intersects(TypeFlags::HAS_ERROR)
+            {
+                result.push(PartiallyMoved { span, ty, local: p.local });
+            }
+        }
+        Operand::Constant(_) | Operand::Static(_) => (),
+    };
+    for (_, block) in body.basic_blocks.iter() {
+        db.unwind_if_cancelled();
+        for statement in &block.statements {
+            match &statement.kind {
+                StatementKind::Assign(_, r) => match r {
+                    Rvalue::ShallowInitBoxWithAlloc(_) => (),
+                    Rvalue::ShallowInitBox(o, _)
+                    | Rvalue::UnaryOp(_, o)
+                    | Rvalue::Cast(_, o, _)
+                    | Rvalue::Repeat(o, _)
+                    | Rvalue::Use(o) => for_operand(o, statement.span),
+                    Rvalue::CopyForDeref(_)
+                    | Rvalue::Discriminant(_)
+                    | Rvalue::Len(_)
+                    | Rvalue::Ref(_, _) => (),
+                    Rvalue::CheckedBinaryOp(_, o1, o2) => {
+                        for_operand(o1, statement.span);
+                        for_operand(o2, statement.span);
+                    }
+                    Rvalue::Aggregate(_, ops) => {
+                        for op in ops.iter() {
+                            for_operand(op, statement.span);
+                        }
+                    }
+                },
+                StatementKind::FakeRead(_)
+                | StatementKind::Deinit(_)
+                | StatementKind::StorageLive(_)
+                | StatementKind::StorageDead(_)
+                | StatementKind::Nop => (),
+            }
+        }
+        match &block.terminator {
+            Some(terminator) => match &terminator.kind {
+                TerminatorKind::SwitchInt { discr, .. } => for_operand(discr, terminator.span),
+                TerminatorKind::FalseEdge { .. }
+                | TerminatorKind::FalseUnwind { .. }
+                | TerminatorKind::Goto { .. }
+                | TerminatorKind::UnwindResume
+                | TerminatorKind::CoroutineDrop
+                | TerminatorKind::Abort
+                | TerminatorKind::Return
+                | TerminatorKind::Unreachable
+                | TerminatorKind::Drop { .. } => (),
+                TerminatorKind::DropAndReplace { value, .. } => {
+                    for_operand(value, terminator.span);
+                }
+                TerminatorKind::Call { func, args, .. } => {
+                    for_operand(func, terminator.span);
+                    args.iter().for_each(|it| for_operand(it, terminator.span));
+                }
+                TerminatorKind::Assert { cond, .. } => {
+                    for_operand(cond, terminator.span);
+                }
+                TerminatorKind::Yield { value, .. } => {
+                    for_operand(value, terminator.span);
+                }
+            },
+            None => (),
+        }
+    }
+    result.shrink_to_fit();
+    result
+}
+
+fn borrow_regions(db: &dyn HirDatabase, body: &MirBody) -> Vec<BorrowRegion> {
+    let mut borrows = FxHashMap::default();
+    for (_, block) in body.basic_blocks.iter() {
+        db.unwind_if_cancelled();
+        for statement in &block.statements {
+            if let StatementKind::Assign(_, Rvalue::Ref(kind, p)) = &statement.kind {
+                borrows
+                    .entry(p.local)
+                    .and_modify(|it: &mut BorrowRegion| {
+                        it.places.push(statement.span);
+                    })
+                    .or_insert_with(|| BorrowRegion {
+                        local: p.local,
+                        kind: *kind,
+                        places: vec![statement.span],
+                    });
+            }
+        }
+        match &block.terminator {
+            Some(terminator) => match &terminator.kind {
+                TerminatorKind::FalseEdge { .. }
+                | TerminatorKind::FalseUnwind { .. }
+                | TerminatorKind::Goto { .. }
+                | TerminatorKind::UnwindResume
+                | TerminatorKind::CoroutineDrop
+                | TerminatorKind::Abort
+                | TerminatorKind::Return
+                | TerminatorKind::Unreachable
+                | TerminatorKind::Drop { .. } => (),
+                TerminatorKind::DropAndReplace { .. } => {}
+                TerminatorKind::Call { .. } => {}
+                _ => (),
+            },
+            None => (),
+        }
+    }
+
+    borrows.into_values().collect()
+}
+
 #[derive(Debug, Clone, Copy, PartialEq, Eq)]
 enum ProjectionCase {
     /// Projection is a local
@@ -217,18 +363,7 @@ fn place_case(db: &dyn HirDatabase, body: &MirBody, lvalue: &Place) -> Projectio
         ty = proj.projected_ty(
             ty,
             db,
-            |c, subst, f| {
-                let InternedClosure(def, _) = db.lookup_intern_closure(c.into());
-                let infer = db.infer(def);
-                let (captures, _) = infer.closure_info(&c);
-                let parent_subst = ClosureSubst(subst).parent_subst();
-                captures
-                    .get(f)
-                    .expect("broken closure field")
-                    .ty
-                    .clone()
-                    .substitute(Interner, parent_subst)
-            },
+            make_fetch_closure_field(db),
             body.owner.module(db.upcast()).krate(),
         );
     }
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 d68803fe280..fbe6a982d6f 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
@@ -4,11 +4,7 @@
 use std::cmp;
 
 use chalk_ir::TyKind;
-use hir_def::{
-    builtin_type::{BuiltinInt, BuiltinUint},
-    resolver::HasResolver,
-};
-use hir_expand::mod_path::ModPath;
+use hir_def::builtin_type::{BuiltinInt, BuiltinUint};
 
 use super::*;
 
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 1572a6d497c..9fe3d5b77ae 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
@@ -1,6 +1,6 @@
 //! This module generates a polymorphic MIR from a hir body
 
-use std::{fmt::Write, iter, mem};
+use std::{fmt::Write, mem};
 
 use base_db::{salsa::Cycle, FileId};
 use chalk_ir::{BoundVar, ConstData, DebruijnIndex, TyKind};
@@ -14,23 +14,19 @@ use hir_def::{
     lang_item::{LangItem, LangItemTarget},
     path::Path,
     resolver::{resolver_for_expr, HasResolver, ResolveValueResult, ValueNs},
-    AdtId, DefWithBodyId, EnumVariantId, GeneralConstId, HasModule, ItemContainerId, LocalFieldId,
+    AdtId, EnumVariantId, GeneralConstId, HasModule, ItemContainerId, LocalFieldId,
     Lookup, TraitId, TupleId, TypeOrConstParamId,
 };
 use hir_expand::name::Name;
-use la_arena::ArenaMap;
-use rustc_hash::FxHashMap;
 use syntax::TextRange;
 use triomphe::Arc;
 
 use crate::{
     consteval::ConstEvalError,
-    db::{HirDatabase, InternedClosure},
-    display::HirDisplay,
+    db::InternedClosure,
     infer::{CaptureKind, CapturedItem, TypeMismatch},
     inhabitedness::is_ty_uninhabited_from,
     layout::LayoutError,
-    mapping::ToChalk,
     static_lifetime,
     traits::FnTrait,
     utils::{generics, ClosureSubst},
@@ -775,6 +771,7 @@ impl<'ctx> MirLowerCtx<'ctx> {
                 self.set_terminator(current, TerminatorKind::Return, expr_id.into());
                 Ok(None)
             }
+            Expr::Become { .. } => not_supported!("tail-calls"),
             Expr::Yield { .. } => not_supported!("yield"),
             Expr::RecordLit { fields, path, spread, ellipsis: _, is_assignee_expr: _ } => {
                 let spread_place = match spread {
@@ -1246,7 +1243,7 @@ impl<'ctx> MirLowerCtx<'ctx> {
                 self.push_assignment(current, place, op.into(), expr_id.into());
                 Ok(Some(current))
             }
-            Expr::Underscore => not_supported!("underscore"),
+            Expr::Underscore => Ok(Some(current)),
         }
     }
 
@@ -1780,6 +1777,7 @@ impl<'ctx> MirLowerCtx<'ctx> {
                     self.push_fake_read(c, p, expr.into());
                     current = scope2.pop_and_drop(self, c, expr.into());
                 }
+                hir_def::hir::Statement::Item => (),
             }
         }
         if let Some(tail) = tail {
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/mir/lower/pattern_matching.rs b/src/tools/rust-analyzer/crates/hir-ty/src/mir/lower/pattern_matching.rs
index 8202bac532f..02b1494062f 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/mir/lower/pattern_matching.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/mir/lower/pattern_matching.rs
@@ -1,6 +1,6 @@
 //! MIR lowering for patterns
 
-use hir_def::{hir::LiteralOrConst, resolver::HasResolver, AssocItemId};
+use hir_def::AssocItemId;
 
 use crate::BindingMode;
 
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/tests/diagnostics.rs b/src/tools/rust-analyzer/crates/hir-ty/src/tests/diagnostics.rs
index 1876be303ad..80f92eaf435 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/tests/diagnostics.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/tests/diagnostics.rs
@@ -1,3 +1,5 @@
+use crate::tests::check_no_mismatches;
+
 use super::check;
 
 #[test]
@@ -94,3 +96,43 @@ fn test(x: bool) {
 "#,
     );
 }
+
+#[test]
+fn no_mismatches_on_atpit() {
+    check_no_mismatches(
+        r#"
+//- minicore: option, sized
+#![feature(impl_trait_in_assoc_type)]
+
+trait WrappedAssoc {
+    type Assoc;
+    fn do_thing(&self) -> Option<Self::Assoc>;
+}
+
+struct Foo;
+impl WrappedAssoc for Foo {
+    type Assoc = impl Sized;
+
+    fn do_thing(&self) -> Option<Self::Assoc> {
+        Some(())
+    }
+}
+"#,
+    );
+    check_no_mismatches(
+        r#"
+//- minicore: option, sized
+#![feature(impl_trait_in_assoc_type)]
+
+trait Trait {
+    type Assoc;
+    const DEFINE: Option<Self::Assoc>;
+}
+
+impl Trait for () {
+    type Assoc = impl Sized;
+    const DEFINE: Option<Self::Assoc> = Option::Some(());
+}
+"#,
+    );
+}
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/tests/simple.rs b/src/tools/rust-analyzer/crates/hir-ty/src/tests/simple.rs
index 84747822826..6c7dbe1db6f 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/tests/simple.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/tests/simple.rs
@@ -3376,11 +3376,8 @@ fn main() {
     [x,] = &[1,];
   //^^^^expected &[i32; 1], got [{unknown}; _]
 
-    // FIXME we only want the outermost error, but this matches the current
-    // behavior of slice patterns
     let x;
     [(x,),] = &[(1,),];
-  // ^^^^expected {unknown}, got ({unknown},)
   //^^^^^^^expected &[(i32,); 1], got [{unknown}; _]
 
     let x;
diff --git a/src/tools/rust-analyzer/crates/hir/src/lib.rs b/src/tools/rust-analyzer/crates/hir/src/lib.rs
index 32abbc80c6a..08f7bb14caa 100644
--- a/src/tools/rust-analyzer/crates/hir/src/lib.rs
+++ b/src/tools/rust-analyzer/crates/hir/src/lib.rs
@@ -31,6 +31,7 @@ mod has_source;
 pub mod db;
 pub mod diagnostics;
 pub mod symbols;
+pub mod term_search;
 
 mod display;
 
@@ -1084,6 +1085,27 @@ impl Field {
         Type::new(db, var_id, ty)
     }
 
+    // FIXME: Find better API to also handle const generics
+    pub fn ty_with_args(&self, db: &dyn HirDatabase, generics: impl Iterator<Item = Type>) -> Type {
+        let var_id = self.parent.into();
+        let def_id: AdtId = match self.parent {
+            VariantDef::Struct(it) => it.id.into(),
+            VariantDef::Union(it) => it.id.into(),
+            VariantDef::Variant(it) => it.parent_enum(db).id.into(),
+        };
+        let mut generics = generics.map(|it| it.ty.clone());
+        let substs = TyBuilder::subst_for_def(db, def_id, None)
+            .fill(|x| match x {
+                ParamKind::Type => {
+                    generics.next().unwrap_or_else(|| TyKind::Error.intern(Interner)).cast(Interner)
+                }
+                ParamKind::Const(ty) => unknown_const_as_generic(ty.clone()),
+            })
+            .build();
+        let ty = db.field_types(var_id)[self.id].clone().substitute(Interner, &substs);
+        Type::new(db, var_id, ty)
+    }
+
     pub fn layout(&self, db: &dyn HirDatabase) -> Result<Layout, LayoutError> {
         db.layout_of_ty(
             self.ty(db).ty,
@@ -1152,6 +1174,10 @@ impl Struct {
     fn variant_data(self, db: &dyn HirDatabase) -> Arc<VariantData> {
         db.struct_data(self.id).variant_data.clone()
     }
+
+    pub fn is_unstable(self, db: &dyn HirDatabase) -> bool {
+        db.attrs(self.id.into()).is_unstable()
+    }
 }
 
 impl HasVisibility for Struct {
@@ -1194,6 +1220,10 @@ impl Union {
     fn variant_data(self, db: &dyn HirDatabase) -> Arc<VariantData> {
         db.union_data(self.id).variant_data.clone()
     }
+
+    pub fn is_unstable(self, db: &dyn HirDatabase) -> bool {
+        db.attrs(self.id.into()).is_unstable()
+    }
 }
 
 impl HasVisibility for Union {
@@ -1269,6 +1299,10 @@ impl Enum {
     pub fn layout(self, db: &dyn HirDatabase) -> Result<Layout, LayoutError> {
         Adt::from(self).layout(db)
     }
+
+    pub fn is_unstable(self, db: &dyn HirDatabase) -> bool {
+        db.attrs(self.id.into()).is_unstable()
+    }
 }
 
 impl HasVisibility for Enum {
@@ -1344,6 +1378,10 @@ impl Variant {
             _ => parent_layout,
         })
     }
+
+    pub fn is_unstable(self, db: &dyn HirDatabase) -> bool {
+        db.attrs(self.id.into()).is_unstable()
+    }
 }
 
 /// Variants inherit visibility from the parent enum.
@@ -1394,9 +1432,9 @@ impl Adt {
 
     /// Turns this ADT into a type with the given type parameters. This isn't
     /// the greatest API, FIXME find a better one.
-    pub fn ty_with_args(self, db: &dyn HirDatabase, args: &[Type]) -> Type {
+    pub fn ty_with_args(self, db: &dyn HirDatabase, args: impl Iterator<Item = Type>) -> Type {
         let id = AdtId::from(self);
-        let mut it = args.iter().map(|t| t.ty.clone());
+        let mut it = args.map(|t| t.ty.clone());
         let ty = TyBuilder::def_ty(db, id.into(), None)
             .fill(|x| {
                 let r = it.next().unwrap_or_else(|| TyKind::Error.intern(Interner));
@@ -1789,6 +1827,35 @@ impl Function {
         Type::new_with_resolver_inner(db, &resolver, ty)
     }
 
+    // FIXME: Find better API to also handle const generics
+    pub fn ret_type_with_args(
+        self,
+        db: &dyn HirDatabase,
+        generics: impl Iterator<Item = Type>,
+    ) -> Type {
+        let resolver = self.id.resolver(db.upcast());
+        let parent_id: Option<GenericDefId> = match self.id.lookup(db.upcast()).container {
+            ItemContainerId::ImplId(it) => Some(it.into()),
+            ItemContainerId::TraitId(it) => Some(it.into()),
+            ItemContainerId::ModuleId(_) | ItemContainerId::ExternBlockId(_) => None,
+        };
+        let mut generics = generics.map(|it| it.ty.clone());
+        let mut filler = |x: &_| match x {
+            ParamKind::Type => {
+                generics.next().unwrap_or_else(|| TyKind::Error.intern(Interner)).cast(Interner)
+            }
+            ParamKind::Const(ty) => unknown_const_as_generic(ty.clone()),
+        };
+
+        let parent_substs =
+            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();
+        Type::new_with_resolver_inner(db, &resolver, ty)
+    }
+
     pub fn async_ret_type(self, db: &dyn HirDatabase) -> Option<Type> {
         if !self.is_async(db) {
             return None;
@@ -1855,6 +1922,51 @@ impl Function {
             .collect()
     }
 
+    // FIXME: Find better API to also handle const generics
+    pub fn params_without_self_with_args(
+        self,
+        db: &dyn HirDatabase,
+        generics: impl Iterator<Item = Type>,
+    ) -> Vec<Param> {
+        let environment = db.trait_environment(self.id.into());
+        let parent_id: Option<GenericDefId> = match self.id.lookup(db.upcast()).container {
+            ItemContainerId::ImplId(it) => Some(it.into()),
+            ItemContainerId::TraitId(it) => Some(it.into()),
+            ItemContainerId::ModuleId(_) | ItemContainerId::ExternBlockId(_) => None,
+        };
+        let mut generics = generics.map(|it| it.ty.clone());
+        let parent_substs = parent_id.map(|id| {
+            TyBuilder::subst_for_def(db, id, None)
+                .fill(|x| match x {
+                    ParamKind::Type => generics
+                        .next()
+                        .unwrap_or_else(|| TyKind::Error.intern(Interner))
+                        .cast(Interner),
+                    ParamKind::Const(ty) => unknown_const_as_generic(ty.clone()),
+                })
+                .build()
+        });
+
+        let substs = TyBuilder::subst_for_def(db, self.id, parent_substs)
+            .fill(|_| {
+                let ty = generics.next().unwrap_or_else(|| TyKind::Error.intern(Interner));
+                GenericArg::new(Interner, GenericArgData::Ty(ty))
+            })
+            .build();
+        let callable_sig = db.callable_item_signature(self.id.into()).substitute(Interner, &substs);
+        let skip = if db.function_data(self.id).has_self_param() { 1 } else { 0 };
+        callable_sig
+            .params()
+            .iter()
+            .enumerate()
+            .skip(skip)
+            .map(|(idx, ty)| {
+                let ty = Type { env: environment.clone(), ty: ty.clone() };
+                Param { func: self, ty, idx }
+            })
+            .collect()
+    }
+
     pub fn is_const(self, db: &dyn HirDatabase) -> bool {
         db.function_data(self.id).has_const_kw()
     }
@@ -1889,6 +2001,11 @@ impl Function {
         db.function_data(self.id).attrs.is_bench()
     }
 
+    /// Is this function marked as unstable with `#[feature]` attribute?
+    pub fn is_unstable(self, db: &dyn HirDatabase) -> bool {
+        db.function_data(self.id).attrs.is_unstable()
+    }
+
     pub fn is_unsafe_to_call(self, db: &dyn HirDatabase) -> bool {
         hir_ty::is_fn_unsafe_to_call(db, self.id)
     }
@@ -2052,6 +2169,34 @@ impl SelfParam {
         let ty = callable_sig.params()[0].clone();
         Type { env: environment, ty }
     }
+
+    // FIXME: Find better API to also handle const generics
+    pub fn ty_with_args(&self, db: &dyn HirDatabase, generics: impl Iterator<Item = Type>) -> Type {
+        let parent_id: GenericDefId = match self.func.lookup(db.upcast()).container {
+            ItemContainerId::ImplId(it) => it.into(),
+            ItemContainerId::TraitId(it) => it.into(),
+            ItemContainerId::ModuleId(_) | ItemContainerId::ExternBlockId(_) => {
+                panic!("Never get here")
+            }
+        };
+
+        let mut generics = generics.map(|it| it.ty.clone());
+        let mut filler = |x: &_| match x {
+            ParamKind::Type => {
+                generics.next().unwrap_or_else(|| TyKind::Error.intern(Interner)).cast(Interner)
+            }
+            ParamKind::Const(ty) => unknown_const_as_generic(ty.clone()),
+        };
+
+        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 environment = db.trait_environment(self.func.into());
+        let ty = callable_sig.params()[0].clone();
+        Type { env: environment, ty }
+    }
 }
 
 impl HasVisibility for Function {
@@ -2754,7 +2899,7 @@ impl GenericDef {
             .collect()
     }
 
-    pub fn type_params(self, db: &dyn HirDatabase) -> Vec<TypeOrConstParam> {
+    pub fn type_or_const_params(self, db: &dyn HirDatabase) -> Vec<TypeOrConstParam> {
         let generics = db.generic_params(self.into());
         generics
             .type_or_consts
@@ -3126,12 +3271,16 @@ impl TypeParam {
         let ty = generic_arg_from_param(db, self.id.into())?;
         let resolver = self.id.parent().resolver(db.upcast());
         match ty.data(Interner) {
-            GenericArgData::Ty(it) => {
+            GenericArgData::Ty(it) if *it.kind(Interner) != TyKind::Error => {
                 Some(Type::new_with_resolver_inner(db, &resolver, it.clone()))
             }
             _ => None,
         }
     }
+
+    pub fn is_unstable(self, db: &dyn HirDatabase) -> bool {
+        db.attrs(GenericParamId::from(self.id).into()).is_unstable()
+    }
 }
 
 #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
@@ -3241,6 +3390,26 @@ impl TypeOrConstParam {
             Either::Right(it) => it.ty(db),
         }
     }
+
+    pub fn as_type_param(self, db: &dyn HirDatabase) -> Option<TypeParam> {
+        let params = db.generic_params(self.id.parent);
+        match &params.type_or_consts[self.id.local_id] {
+            hir_def::generics::TypeOrConstParamData::TypeParamData(_) => {
+                Some(TypeParam { id: TypeParamId::from_unchecked(self.id) })
+            }
+            hir_def::generics::TypeOrConstParamData::ConstParamData(_) => None,
+        }
+    }
+
+    pub fn as_const_param(self, db: &dyn HirDatabase) -> Option<ConstParam> {
+        let params = db.generic_params(self.id.parent);
+        match &params.type_or_consts[self.id.local_id] {
+            hir_def::generics::TypeOrConstParamData::TypeParamData(_) => None,
+            hir_def::generics::TypeOrConstParamData::ConstParamData(_) => {
+                Some(ConstParam { id: ConstParamId::from_unchecked(self.id) })
+            }
+        }
+    }
 }
 
 #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
@@ -3285,12 +3454,11 @@ impl Impl {
                     .filter(filter),
             )
         });
+
         for id in def_crates
             .iter()
             .flat_map(|&id| Crate { id }.transitive_reverse_dependencies(db))
             .map(|Crate { id }| id)
-            .chain(def_crates.iter().copied())
-            .unique()
         {
             all.extend(
                 db.trait_impls_in_crate(id)
@@ -3520,7 +3688,7 @@ pub enum CaptureKind {
     Move,
 }
 
-#[derive(Clone, PartialEq, Eq, Debug)]
+#[derive(Clone, PartialEq, Eq, Debug, Hash)]
 pub struct Type {
     env: Arc<TraitEnvironment>,
     ty: Ty,
@@ -3620,6 +3788,50 @@ impl Type {
         matches!(self.ty.kind(Interner), TyKind::Ref(..))
     }
 
+    pub fn contains_reference(&self, db: &dyn HirDatabase) -> bool {
+        return go(db, self.env.krate, &self.ty);
+
+        fn go(db: &dyn HirDatabase, krate: CrateId, ty: &Ty) -> bool {
+            match ty.kind(Interner) {
+                // Reference itself
+                TyKind::Ref(_, _, _) => true,
+
+                // For non-phantom_data adts we check variants/fields as well as generic parameters
+                TyKind::Adt(adt_id, substitution)
+                    if !db.struct_datum(krate, *adt_id).flags.phantom_data =>
+                {
+                    let adt_datum = &db.struct_datum(krate, *adt_id);
+                    let adt_datum_bound =
+                        adt_datum.binders.clone().substitute(Interner, substitution);
+                    adt_datum_bound
+                        .variants
+                        .into_iter()
+                        .flat_map(|variant| variant.fields.into_iter())
+                        .any(|ty| go(db, krate, &ty))
+                        || substitution
+                            .iter(Interner)
+                            .filter_map(|x| x.ty(Interner))
+                            .any(|ty| go(db, krate, ty))
+                }
+                // And for `PhantomData<T>`, we check `T`.
+                TyKind::Adt(_, substitution)
+                | TyKind::Tuple(_, substitution)
+                | TyKind::OpaqueType(_, substitution)
+                | TyKind::AssociatedType(_, substitution)
+                | TyKind::FnDef(_, substitution) => substitution
+                    .iter(Interner)
+                    .filter_map(|x| x.ty(Interner))
+                    .any(|ty| go(db, krate, ty)),
+
+                // For `[T]` or `*T` we check `T`
+                TyKind::Array(ty, _) | TyKind::Slice(ty) | TyKind::Raw(_, ty) => go(db, krate, ty),
+
+                // Consider everything else as not reference
+                _ => false,
+            }
+        }
+    }
+
     pub fn as_reference(&self) -> Option<(Type, Mutability)> {
         let (ty, _lt, m) = self.ty.as_reference()?;
         let m = Mutability::from_mutable(matches!(m, hir_ty::Mutability::Mut));
@@ -3727,14 +3939,16 @@ impl Type {
         )
     }
 
+    // FIXME: Find better API that also handles const generics
     pub fn impls_trait(&self, db: &dyn HirDatabase, trait_: Trait, args: &[Type]) -> bool {
         let mut it = args.iter().map(|t| t.ty.clone());
         let trait_ref = TyBuilder::trait_ref(db, trait_.id)
             .push(self.ty.clone())
             .fill(|x| {
-                let r = it.next().unwrap();
                 match x {
-                    ParamKind::Type => r.cast(Interner),
+                    ParamKind::Type => {
+                        it.next().unwrap_or_else(|| TyKind::Error.intern(Interner)).cast(Interner)
+                    }
                     ParamKind::Const(ty) => {
                         // FIXME: this code is not covered in tests.
                         unknown_const_as_generic(ty.clone())
@@ -4368,12 +4582,24 @@ impl Type {
 
         walk_type(db, self, &mut cb);
     }
-
+    /// Check if type unifies with another type.
+    ///
+    /// Note that we consider placeholder types to unify with everything.
+    /// For example `Option<T>` and `Option<U>` unify although there is unresolved goal `T = U`.
     pub fn could_unify_with(&self, db: &dyn HirDatabase, other: &Type) -> bool {
         let tys = hir_ty::replace_errors_with_variables(&(self.ty.clone(), other.ty.clone()));
         hir_ty::could_unify(db, self.env.clone(), &tys)
     }
 
+    /// Check if type unifies with another type eagerly making sure there are no unresolved goals.
+    ///
+    /// This means that placeholder types are not considered to unify if there are any bounds set on
+    /// them. For example `Option<T>` and `Option<U>` do not unify as we cannot show that `T = U`
+    pub fn could_unify_with_deeply(&self, db: &dyn HirDatabase, other: &Type) -> bool {
+        let tys = hir_ty::replace_errors_with_variables(&(self.ty.clone(), other.ty.clone()));
+        hir_ty::could_unify_deeply(db, self.env.clone(), &tys)
+    }
+
     pub fn could_coerce_to(&self, db: &dyn HirDatabase, to: &Type) -> bool {
         let tys = hir_ty::replace_errors_with_variables(&(self.ty.clone(), to.ty.clone()));
         hir_ty::could_coerce(db, self.env.clone(), &tys)
diff --git a/src/tools/rust-analyzer/crates/hir/src/term_search.rs b/src/tools/rust-analyzer/crates/hir/src/term_search.rs
new file mode 100644
index 00000000000..72762007dc9
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/hir/src/term_search.rs
@@ -0,0 +1,298 @@
+//! Term search
+
+use hir_def::type_ref::Mutability;
+use hir_ty::db::HirDatabase;
+use itertools::Itertools;
+use rustc_hash::{FxHashMap, FxHashSet};
+
+use crate::{ModuleDef, ScopeDef, Semantics, SemanticsScope, Type};
+
+mod expr;
+pub use expr::Expr;
+
+mod tactics;
+
+/// Key for lookup table to query new types reached.
+#[derive(Debug, Hash, PartialEq, Eq)]
+enum NewTypesKey {
+    ImplMethod,
+    StructProjection,
+}
+
+/// Helper enum to squash big number of alternative trees into `Many` variant as there is too many
+/// to take into account.
+#[derive(Debug)]
+enum AlternativeExprs {
+    /// There are few trees, so we keep track of them all
+    Few(FxHashSet<Expr>),
+    /// There are too many trees to keep track of
+    Many,
+}
+
+impl AlternativeExprs {
+    /// Construct alternative trees
+    ///
+    /// # Arguments
+    /// `threshold` - threshold value for many trees (more than that is many)
+    /// `exprs` - expressions iterator
+    fn new(threshold: usize, exprs: impl Iterator<Item = Expr>) -> AlternativeExprs {
+        let mut it = AlternativeExprs::Few(Default::default());
+        it.extend_with_threshold(threshold, exprs);
+        it
+    }
+
+    /// Get type trees stored in alternative trees (or `Expr::Many` in case of many)
+    ///
+    /// # Arguments
+    /// `ty` - Type of expressions queried (this is used to give type to `Expr::Many`)
+    fn exprs(&self, ty: &Type) -> Vec<Expr> {
+        match self {
+            AlternativeExprs::Few(exprs) => exprs.iter().cloned().collect(),
+            AlternativeExprs::Many => vec![Expr::Many(ty.clone())],
+        }
+    }
+
+    /// Extend alternative expressions
+    ///
+    /// # Arguments
+    /// `threshold` - threshold value for many trees (more than that is many)
+    /// `exprs` - expressions iterator
+    fn extend_with_threshold(&mut self, threshold: usize, exprs: impl Iterator<Item = Expr>) {
+        match self {
+            AlternativeExprs::Few(tts) => {
+                for it in exprs {
+                    if tts.len() > threshold {
+                        *self = AlternativeExprs::Many;
+                        break;
+                    }
+
+                    tts.insert(it);
+                }
+            }
+            AlternativeExprs::Many => (),
+        }
+    }
+}
+
+/// # Lookup table for term search
+///
+/// Lookup table keeps all the state during term search.
+/// This means it knows what types and how are reachable.
+///
+/// The secondary functionality for lookup table is to keep track of new types reached since last
+/// iteration as well as keeping track of which `ScopeDef` items have been used.
+/// Both of them are to speed up the term search by leaving out types / ScopeDefs that likely do
+/// not produce any new results.
+#[derive(Default, Debug)]
+struct LookupTable {
+    /// All the `Expr`s in "value" produce the type of "key"
+    data: FxHashMap<Type, AlternativeExprs>,
+    /// New types reached since last query by the `NewTypesKey`
+    new_types: FxHashMap<NewTypesKey, Vec<Type>>,
+    /// ScopeDefs that are not interesting any more
+    exhausted_scopedefs: FxHashSet<ScopeDef>,
+    /// ScopeDefs that were used in current round
+    round_scopedef_hits: FxHashSet<ScopeDef>,
+    /// Amount of rounds since scopedef was first used.
+    rounds_since_sopedef_hit: FxHashMap<ScopeDef, u32>,
+    /// Types queried but not present
+    types_wishlist: FxHashSet<Type>,
+    /// Threshold to squash trees to `Many`
+    many_threshold: usize,
+}
+
+impl LookupTable {
+    /// Initialize lookup table
+    fn new(many_threshold: usize) -> Self {
+        let mut res = Self { many_threshold, ..Default::default() };
+        res.new_types.insert(NewTypesKey::ImplMethod, Vec::new());
+        res.new_types.insert(NewTypesKey::StructProjection, Vec::new());
+        res
+    }
+
+    /// Find all `Expr`s that unify with the `ty`
+    fn find(&self, db: &dyn HirDatabase, ty: &Type) -> Option<Vec<Expr>> {
+        self.data
+            .iter()
+            .find(|(t, _)| t.could_unify_with_deeply(db, ty))
+            .map(|(t, tts)| tts.exprs(t))
+    }
+
+    /// Same as find but automatically creates shared reference of types in the lookup
+    ///
+    /// For example if we have type `i32` in data and we query for `&i32` it map all the type
+    /// trees we have for `i32` with `Expr::Reference` and returns them.
+    fn find_autoref(&self, db: &dyn HirDatabase, ty: &Type) -> Option<Vec<Expr>> {
+        self.data
+            .iter()
+            .find(|(t, _)| t.could_unify_with_deeply(db, ty))
+            .map(|(t, it)| it.exprs(t))
+            .or_else(|| {
+                self.data
+                    .iter()
+                    .find(|(t, _)| {
+                        Type::reference(t, Mutability::Shared).could_unify_with_deeply(db, ty)
+                    })
+                    .map(|(t, it)| {
+                        it.exprs(t)
+                            .into_iter()
+                            .map(|expr| Expr::Reference(Box::new(expr)))
+                            .collect()
+                    })
+            })
+    }
+
+    /// Insert new type trees for type
+    ///
+    /// Note that the types have to be the same, unification is not enough as unification is not
+    /// transitive. For example Vec<i32> and FxHashSet<i32> both unify with Iterator<Item = i32>,
+    /// but they clearly do not unify themselves.
+    fn insert(&mut self, ty: Type, exprs: impl Iterator<Item = Expr>) {
+        match self.data.get_mut(&ty) {
+            Some(it) => it.extend_with_threshold(self.many_threshold, exprs),
+            None => {
+                self.data.insert(ty.clone(), AlternativeExprs::new(self.many_threshold, exprs));
+                for it in self.new_types.values_mut() {
+                    it.push(ty.clone());
+                }
+            }
+        }
+    }
+
+    /// Iterate all the reachable types
+    fn iter_types(&self) -> impl Iterator<Item = Type> + '_ {
+        self.data.keys().cloned()
+    }
+
+    /// Query new types reached since last query by key
+    ///
+    /// Create new key if you wish to query it to avoid conflicting with existing queries.
+    fn new_types(&mut self, key: NewTypesKey) -> Vec<Type> {
+        match self.new_types.get_mut(&key) {
+            Some(it) => std::mem::take(it),
+            None => Vec::new(),
+        }
+    }
+
+    /// Mark `ScopeDef` as exhausted meaning it is not interesting for us any more
+    fn mark_exhausted(&mut self, def: ScopeDef) {
+        self.exhausted_scopedefs.insert(def);
+    }
+
+    /// Mark `ScopeDef` as used meaning we managed to produce something useful from it
+    fn mark_fulfilled(&mut self, def: ScopeDef) {
+        self.round_scopedef_hits.insert(def);
+    }
+
+    /// Start new round (meant to be called at the beginning of iteration in `term_search`)
+    ///
+    /// This functions marks some `ScopeDef`s as exhausted if there have been
+    /// `MAX_ROUNDS_AFTER_HIT` rounds after first using a `ScopeDef`.
+    fn new_round(&mut self) {
+        for def in &self.round_scopedef_hits {
+            let hits =
+                self.rounds_since_sopedef_hit.entry(*def).and_modify(|n| *n += 1).or_insert(0);
+            const MAX_ROUNDS_AFTER_HIT: u32 = 2;
+            if *hits > MAX_ROUNDS_AFTER_HIT {
+                self.exhausted_scopedefs.insert(*def);
+            }
+        }
+        self.round_scopedef_hits.clear();
+    }
+
+    /// Get exhausted `ScopeDef`s
+    fn exhausted_scopedefs(&self) -> &FxHashSet<ScopeDef> {
+        &self.exhausted_scopedefs
+    }
+
+    /// Types queried but not found
+    fn take_types_wishlist(&mut self) -> FxHashSet<Type> {
+        std::mem::take(&mut self.types_wishlist)
+    }
+}
+
+/// Context for the `term_search` function
+#[derive(Debug)]
+pub struct TermSearchCtx<'a, DB: HirDatabase> {
+    /// Semantics for the program
+    pub sema: &'a Semantics<'a, DB>,
+    /// Semantic scope, captures context for the term search
+    pub scope: &'a SemanticsScope<'a>,
+    /// Target / expected output type
+    pub goal: Type,
+    /// Configuration for term search
+    pub config: TermSearchConfig,
+}
+
+/// Configuration options for the term search
+#[derive(Debug, Clone, Copy)]
+pub struct TermSearchConfig {
+    /// Enable borrow checking, this guarantees the outputs of the `term_search` to borrow-check
+    pub enable_borrowcheck: bool,
+    /// Indicate when to squash multiple trees to `Many` as there are too many to keep track
+    pub many_alternatives_threshold: usize,
+    /// Depth of the search eg. number of cycles to run
+    pub depth: usize,
+}
+
+impl Default for TermSearchConfig {
+    fn default() -> Self {
+        Self { enable_borrowcheck: true, many_alternatives_threshold: 1, depth: 6 }
+    }
+}
+
+/// # Term search
+///
+/// Search for terms (expressions) that unify with the `goal` type.
+///
+/// # Arguments
+/// * `ctx` - Context for term search
+///
+/// Internally this function uses Breadth First Search to find path to `goal` type.
+/// The general idea is following:
+/// 1. Populate lookup (frontier for BFS) from values (local variables, statics, constants, etc)
+///    as well as from well knows values (such as `true/false` and `()`)
+/// 2. Iteratively expand the frontier (or contents of the lookup) by trying different type
+///    transformation tactics. For example functions take as from set of types (arguments) to some
+///    type (return type). Other transformations include methods on type, type constructors and
+///    projections to struct fields (field access).
+/// 3. Once we manage to find path to type we are interested in we continue for single round to see
+///    if we can find more paths that take us to the `goal` type.
+/// 4. Return all the paths (type trees) that take us to the `goal` type.
+///
+/// Note that there are usually more ways we can get to the `goal` type but some are discarded to
+/// reduce the memory consumption. It is also unlikely anyone is willing ti browse through
+/// thousands of possible responses so we currently take first 10 from every tactic.
+pub fn term_search<DB: HirDatabase>(ctx: &TermSearchCtx<'_, DB>) -> Vec<Expr> {
+    let module = ctx.scope.module();
+    let mut defs = FxHashSet::default();
+    defs.insert(ScopeDef::ModuleDef(ModuleDef::Module(module)));
+
+    ctx.scope.process_all_names(&mut |_, def| {
+        defs.insert(def);
+    });
+
+    let mut lookup = LookupTable::new(ctx.config.many_alternatives_threshold);
+
+    // Try trivial tactic first, also populates lookup table
+    let mut solutions: Vec<Expr> = tactics::trivial(ctx, &defs, &mut lookup).collect();
+    // Use well known types tactic before iterations as it does not depend on other tactics
+    solutions.extend(tactics::famous_types(ctx, &defs, &mut lookup));
+
+    for _ in 0..ctx.config.depth {
+        lookup.new_round();
+
+        solutions.extend(tactics::type_constructor(ctx, &defs, &mut lookup));
+        solutions.extend(tactics::free_function(ctx, &defs, &mut lookup));
+        solutions.extend(tactics::impl_method(ctx, &defs, &mut lookup));
+        solutions.extend(tactics::struct_projection(ctx, &defs, &mut lookup));
+        solutions.extend(tactics::impl_static_method(ctx, &defs, &mut lookup));
+
+        // Discard not interesting `ScopeDef`s for speedup
+        for def in lookup.exhausted_scopedefs() {
+            defs.remove(def);
+        }
+    }
+
+    solutions.into_iter().filter(|it| !it.is_many()).unique().collect()
+}
diff --git a/src/tools/rust-analyzer/crates/hir/src/term_search/expr.rs b/src/tools/rust-analyzer/crates/hir/src/term_search/expr.rs
new file mode 100644
index 00000000000..254fbe7e2b5
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/hir/src/term_search/expr.rs
@@ -0,0 +1,468 @@
+//! Type tree for term search
+
+use hir_def::find_path::PrefixKind;
+use hir_expand::mod_path::ModPath;
+use hir_ty::{
+    db::HirDatabase,
+    display::{DisplaySourceCodeError, HirDisplay},
+};
+use itertools::Itertools;
+
+use crate::{
+    Adt, AsAssocItem, Const, ConstParam, Field, Function, GenericDef, Local, ModuleDef,
+    SemanticsScope, Static, Struct, StructKind, Trait, Type, Variant,
+};
+
+/// Helper function to get path to `ModuleDef`
+fn mod_item_path(
+    sema_scope: &SemanticsScope<'_>,
+    def: &ModuleDef,
+    prefer_no_std: bool,
+    prefer_prelude: bool,
+) -> Option<ModPath> {
+    let db = sema_scope.db;
+    // Account for locals shadowing items from module
+    let name_hit_count = def.name(db).map(|def_name| {
+        let mut name_hit_count = 0;
+        sema_scope.process_all_names(&mut |name, _| {
+            if name == def_name {
+                name_hit_count += 1;
+            }
+        });
+        name_hit_count
+    });
+
+    let m = sema_scope.module();
+    match name_hit_count {
+        Some(0..=1) | None => m.find_use_path(db.upcast(), *def, prefer_no_std, prefer_prelude),
+        Some(_) => m.find_use_path_prefixed(
+            db.upcast(),
+            *def,
+            PrefixKind::ByCrate,
+            prefer_no_std,
+            prefer_prelude,
+        ),
+    }
+}
+
+/// Helper function to get path to `ModuleDef` as string
+fn mod_item_path_str(
+    sema_scope: &SemanticsScope<'_>,
+    def: &ModuleDef,
+    prefer_no_std: bool,
+    prefer_prelude: bool,
+) -> Result<String, DisplaySourceCodeError> {
+    let path = mod_item_path(sema_scope, def, prefer_no_std, prefer_prelude);
+    path.map(|it| it.display(sema_scope.db.upcast()).to_string())
+        .ok_or(DisplaySourceCodeError::PathNotFound)
+}
+
+/// Helper function to get path to `Type`
+fn type_path(
+    sema_scope: &SemanticsScope<'_>,
+    ty: &Type,
+    prefer_no_std: bool,
+    prefer_prelude: bool,
+) -> Result<String, DisplaySourceCodeError> {
+    let db = sema_scope.db;
+    let m = sema_scope.module();
+
+    match ty.as_adt() {
+        Some(adt) => {
+            let ty_name = ty.display_source_code(db, m.id, true)?;
+
+            let mut path =
+                mod_item_path(sema_scope, &ModuleDef::Adt(adt), prefer_no_std, prefer_prelude)
+                    .unwrap();
+            path.pop_segment();
+            let path = path.display(db.upcast()).to_string();
+            let res = match path.is_empty() {
+                true => ty_name,
+                false => format!("{path}::{ty_name}"),
+            };
+            Ok(res)
+        }
+        None => ty.display_source_code(db, m.id, true),
+    }
+}
+
+/// Helper function to filter out generic parameters that are default
+fn non_default_generics(db: &dyn HirDatabase, def: GenericDef, generics: &[Type]) -> Vec<Type> {
+    def.type_or_const_params(db)
+        .into_iter()
+        .filter_map(|it| it.as_type_param(db))
+        .zip(generics)
+        .filter(|(tp, arg)| tp.default(db).as_ref() != Some(arg))
+        .map(|(_, arg)| arg.clone())
+        .collect()
+}
+
+/// Type tree shows how can we get from set of types to some type.
+///
+/// Consider the following code as an example
+/// ```
+/// fn foo(x: i32, y: bool) -> Option<i32> { None }
+/// fn bar() {
+///    let a = 1;
+///    let b = true;
+///    let c: Option<i32> = _;
+/// }
+/// ```
+/// If we generate type tree in the place of `_` we get
+/// ```txt
+///       Option<i32>
+///           |
+///     foo(i32, bool)
+///      /        \
+///  a: i32      b: bool
+/// ```
+/// So in short it pretty much gives us a way to get type `Option<i32>` using the items we have in
+/// scope.
+#[derive(Debug, Clone, Eq, Hash, PartialEq)]
+pub enum Expr {
+    /// Constant
+    Const(Const),
+    /// Static variable
+    Static(Static),
+    /// Local variable
+    Local(Local),
+    /// Constant generic parameter
+    ConstParam(ConstParam),
+    /// Well known type (such as `true` for bool)
+    FamousType { ty: Type, value: &'static str },
+    /// Function call (does not take self param)
+    Function { func: Function, generics: Vec<Type>, params: Vec<Expr> },
+    /// Method call (has self param)
+    Method { func: Function, generics: Vec<Type>, target: Box<Expr>, params: Vec<Expr> },
+    /// Enum variant construction
+    Variant { variant: Variant, generics: Vec<Type>, params: Vec<Expr> },
+    /// Struct construction
+    Struct { strukt: Struct, generics: Vec<Type>, params: Vec<Expr> },
+    /// Struct field access
+    Field { expr: Box<Expr>, field: Field },
+    /// Passing type as reference (with `&`)
+    Reference(Box<Expr>),
+    /// Indicates possibility of many different options that all evaluate to `ty`
+    Many(Type),
+}
+
+impl Expr {
+    /// Generate source code for type tree.
+    ///
+    /// Note that trait imports are not added to generated code.
+    /// To make sure that the code is valid, callee has to also ensure that all the traits listed
+    /// by `traits_used` method are also imported.
+    pub fn gen_source_code(
+        &self,
+        sema_scope: &SemanticsScope<'_>,
+        many_formatter: &mut dyn FnMut(&Type) -> String,
+        prefer_no_std: bool,
+        prefer_prelude: bool,
+    ) -> Result<String, DisplaySourceCodeError> {
+        let db = sema_scope.db;
+        let mod_item_path_str = |s, def| mod_item_path_str(s, def, prefer_no_std, prefer_prelude);
+        match self {
+            Expr::Const(it) => mod_item_path_str(sema_scope, &ModuleDef::Const(*it)),
+            Expr::Static(it) => mod_item_path_str(sema_scope, &ModuleDef::Static(*it)),
+            Expr::Local(it) => Ok(it.name(db).display(db.upcast()).to_string()),
+            Expr::ConstParam(it) => Ok(it.name(db).display(db.upcast()).to_string()),
+            Expr::FamousType { value, .. } => Ok(value.to_string()),
+            Expr::Function { func, params, .. } => {
+                let args = params
+                    .iter()
+                    .map(|f| {
+                        f.gen_source_code(sema_scope, many_formatter, prefer_no_std, prefer_prelude)
+                    })
+                    .collect::<Result<Vec<String>, DisplaySourceCodeError>>()?
+                    .into_iter()
+                    .join(", ");
+
+                match func.as_assoc_item(db).map(|it| it.container(db)) {
+                    Some(container) => {
+                        let container_name = match container {
+                            crate::AssocItemContainer::Trait(trait_) => {
+                                mod_item_path_str(sema_scope, &ModuleDef::Trait(trait_))?
+                            }
+                            crate::AssocItemContainer::Impl(imp) => {
+                                let self_ty = imp.self_ty(db);
+                                // Should it be guaranteed that `mod_item_path` always exists?
+                                match self_ty.as_adt().and_then(|adt| {
+                                    mod_item_path(
+                                        sema_scope,
+                                        &adt.into(),
+                                        prefer_no_std,
+                                        prefer_prelude,
+                                    )
+                                }) {
+                                    Some(path) => path.display(sema_scope.db.upcast()).to_string(),
+                                    None => self_ty.display(db).to_string(),
+                                }
+                            }
+                        };
+                        let fn_name = func.name(db).display(db.upcast()).to_string();
+                        Ok(format!("{container_name}::{fn_name}({args})"))
+                    }
+                    None => {
+                        let fn_name = mod_item_path_str(sema_scope, &ModuleDef::Function(*func))?;
+                        Ok(format!("{fn_name}({args})"))
+                    }
+                }
+            }
+            Expr::Method { func, target, params, .. } => {
+                if target.contains_many_in_illegal_pos() {
+                    return Ok(many_formatter(&target.ty(db)));
+                }
+
+                let func_name = func.name(db).display(db.upcast()).to_string();
+                let self_param = func.self_param(db).unwrap();
+                let target = target.gen_source_code(
+                    sema_scope,
+                    many_formatter,
+                    prefer_no_std,
+                    prefer_prelude,
+                )?;
+                let args = params
+                    .iter()
+                    .map(|f| {
+                        f.gen_source_code(sema_scope, many_formatter, prefer_no_std, prefer_prelude)
+                    })
+                    .collect::<Result<Vec<String>, DisplaySourceCodeError>>()?
+                    .into_iter()
+                    .join(", ");
+
+                match func.as_assoc_item(db).and_then(|it| it.container_or_implemented_trait(db)) {
+                    Some(trait_) => {
+                        let trait_name = mod_item_path_str(sema_scope, &ModuleDef::Trait(trait_))?;
+                        let target = match self_param.access(db) {
+                            crate::Access::Shared => format!("&{target}"),
+                            crate::Access::Exclusive => format!("&mut {target}"),
+                            crate::Access::Owned => target,
+                        };
+                        let res = match args.is_empty() {
+                            true => format!("{trait_name}::{func_name}({target})",),
+                            false => format!("{trait_name}::{func_name}({target}, {args})",),
+                        };
+                        Ok(res)
+                    }
+                    None => Ok(format!("{target}.{func_name}({args})")),
+                }
+            }
+            Expr::Variant { variant, generics, params } => {
+                let generics = non_default_generics(db, (*variant).into(), generics);
+                let generics_str = match generics.is_empty() {
+                    true => String::new(),
+                    false => {
+                        let generics = generics
+                            .iter()
+                            .map(|it| type_path(sema_scope, it, prefer_no_std, prefer_prelude))
+                            .collect::<Result<Vec<String>, DisplaySourceCodeError>>()?
+                            .into_iter()
+                            .join(", ");
+                        format!("::<{generics}>")
+                    }
+                };
+                let inner = match variant.kind(db) {
+                    StructKind::Tuple => {
+                        let args = params
+                            .iter()
+                            .map(|f| {
+                                f.gen_source_code(
+                                    sema_scope,
+                                    many_formatter,
+                                    prefer_no_std,
+                                    prefer_prelude,
+                                )
+                            })
+                            .collect::<Result<Vec<String>, DisplaySourceCodeError>>()?
+                            .into_iter()
+                            .join(", ");
+                        format!("{generics_str}({args})")
+                    }
+                    StructKind::Record => {
+                        let fields = variant.fields(db);
+                        let args = params
+                            .iter()
+                            .zip(fields.iter())
+                            .map(|(a, f)| {
+                                let tmp = format!(
+                                    "{}: {}",
+                                    f.name(db).display(db.upcast()),
+                                    a.gen_source_code(
+                                        sema_scope,
+                                        many_formatter,
+                                        prefer_no_std,
+                                        prefer_prelude
+                                    )?
+                                );
+                                Ok(tmp)
+                            })
+                            .collect::<Result<Vec<String>, DisplaySourceCodeError>>()?
+                            .into_iter()
+                            .join(", ");
+                        format!("{generics_str}{{ {args} }}")
+                    }
+                    StructKind::Unit => generics_str,
+                };
+
+                let prefix = mod_item_path_str(sema_scope, &ModuleDef::Variant(*variant))?;
+                Ok(format!("{prefix}{inner}"))
+            }
+            Expr::Struct { strukt, generics, params } => {
+                let generics = non_default_generics(db, (*strukt).into(), generics);
+                let inner = match strukt.kind(db) {
+                    StructKind::Tuple => {
+                        let args = params
+                            .iter()
+                            .map(|a| {
+                                a.gen_source_code(
+                                    sema_scope,
+                                    many_formatter,
+                                    prefer_no_std,
+                                    prefer_prelude,
+                                )
+                            })
+                            .collect::<Result<Vec<String>, DisplaySourceCodeError>>()?
+                            .into_iter()
+                            .join(", ");
+                        format!("({args})")
+                    }
+                    StructKind::Record => {
+                        let fields = strukt.fields(db);
+                        let args = params
+                            .iter()
+                            .zip(fields.iter())
+                            .map(|(a, f)| {
+                                let tmp = format!(
+                                    "{}: {}",
+                                    f.name(db).display(db.upcast()),
+                                    a.gen_source_code(
+                                        sema_scope,
+                                        many_formatter,
+                                        prefer_no_std,
+                                        prefer_prelude
+                                    )?
+                                );
+                                Ok(tmp)
+                            })
+                            .collect::<Result<Vec<String>, DisplaySourceCodeError>>()?
+                            .into_iter()
+                            .join(", ");
+                        format!(" {{ {args} }}")
+                    }
+                    StructKind::Unit => match generics.is_empty() {
+                        true => String::new(),
+                        false => {
+                            let generics = generics
+                                .iter()
+                                .map(|it| type_path(sema_scope, it, prefer_no_std, prefer_prelude))
+                                .collect::<Result<Vec<String>, DisplaySourceCodeError>>()?
+                                .into_iter()
+                                .join(", ");
+                            format!("::<{generics}>")
+                        }
+                    },
+                };
+
+                let prefix = mod_item_path_str(sema_scope, &ModuleDef::Adt(Adt::Struct(*strukt)))?;
+                Ok(format!("{prefix}{inner}"))
+            }
+            Expr::Field { expr, field } => {
+                if expr.contains_many_in_illegal_pos() {
+                    return Ok(many_formatter(&expr.ty(db)));
+                }
+
+                let strukt = expr.gen_source_code(
+                    sema_scope,
+                    many_formatter,
+                    prefer_no_std,
+                    prefer_prelude,
+                )?;
+                let field = field.name(db).display(db.upcast()).to_string();
+                Ok(format!("{strukt}.{field}"))
+            }
+            Expr::Reference(expr) => {
+                if expr.contains_many_in_illegal_pos() {
+                    return Ok(many_formatter(&expr.ty(db)));
+                }
+
+                let inner = expr.gen_source_code(
+                    sema_scope,
+                    many_formatter,
+                    prefer_no_std,
+                    prefer_prelude,
+                )?;
+                Ok(format!("&{inner}"))
+            }
+            Expr::Many(ty) => Ok(many_formatter(ty)),
+        }
+    }
+
+    /// Get type of the type tree.
+    ///
+    /// Same as getting the type of root node
+    pub fn ty(&self, db: &dyn HirDatabase) -> Type {
+        match self {
+            Expr::Const(it) => it.ty(db),
+            Expr::Static(it) => it.ty(db),
+            Expr::Local(it) => it.ty(db),
+            Expr::ConstParam(it) => it.ty(db),
+            Expr::FamousType { ty, .. } => ty.clone(),
+            Expr::Function { func, generics, .. } => {
+                func.ret_type_with_args(db, generics.iter().cloned())
+            }
+            Expr::Method { func, generics, target, .. } => func.ret_type_with_args(
+                db,
+                target.ty(db).type_arguments().chain(generics.iter().cloned()),
+            ),
+            Expr::Variant { variant, generics, .. } => {
+                Adt::from(variant.parent_enum(db)).ty_with_args(db, generics.iter().cloned())
+            }
+            Expr::Struct { strukt, generics, .. } => {
+                Adt::from(*strukt).ty_with_args(db, generics.iter().cloned())
+            }
+            Expr::Field { expr, field } => field.ty_with_args(db, expr.ty(db).type_arguments()),
+            Expr::Reference(it) => it.ty(db),
+            Expr::Many(ty) => ty.clone(),
+        }
+    }
+
+    /// List the traits used in type tree
+    pub fn traits_used(&self, db: &dyn HirDatabase) -> Vec<Trait> {
+        let mut res = Vec::new();
+
+        if let Expr::Method { func, params, .. } = self {
+            res.extend(params.iter().flat_map(|it| it.traits_used(db)));
+            if let Some(it) = func.as_assoc_item(db) {
+                if let Some(it) = it.container_or_implemented_trait(db) {
+                    res.push(it);
+                }
+            }
+        }
+
+        res
+    }
+
+    /// Check in the tree contains `Expr::Many` variant in illegal place to insert `todo`,
+    /// `unimplemented` or similar macro
+    ///
+    /// Some examples are following
+    /// ```no_compile
+    /// macro!().foo
+    /// macro!().bar()
+    /// &macro!()
+    /// ```
+    fn contains_many_in_illegal_pos(&self) -> bool {
+        match self {
+            Expr::Method { target, .. } => target.contains_many_in_illegal_pos(),
+            Expr::Field { expr, .. } => expr.contains_many_in_illegal_pos(),
+            Expr::Reference(target) => target.is_many(),
+            Expr::Many(_) => true,
+            _ => false,
+        }
+    }
+
+    /// Helper function to check if outermost type tree is `Expr::Many` variant
+    pub fn is_many(&self) -> bool {
+        matches!(self, Expr::Many(_))
+    }
+}
diff --git a/src/tools/rust-analyzer/crates/hir/src/term_search/tactics.rs b/src/tools/rust-analyzer/crates/hir/src/term_search/tactics.rs
new file mode 100644
index 00000000000..666d63ac155
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/hir/src/term_search/tactics.rs
@@ -0,0 +1,859 @@
+//! Tactics for term search
+//!
+//! All the tactics take following arguments
+//! * `ctx` - Context for the term search
+//! * `defs` - Set of items in scope at term search target location
+//! * `lookup` - Lookup table for types
+//! And they return iterator that yields type trees that unify with the `goal` type.
+
+use std::iter;
+
+use hir_ty::db::HirDatabase;
+use hir_ty::mir::BorrowKind;
+use hir_ty::TyBuilder;
+use itertools::Itertools;
+use rustc_hash::FxHashSet;
+
+use crate::{
+    Adt, AssocItem, Enum, GenericDef, GenericParam, HasVisibility, Impl, ModuleDef, ScopeDef, Type,
+    TypeParam, Variant,
+};
+
+use crate::term_search::{Expr, TermSearchConfig};
+
+use super::{LookupTable, NewTypesKey, TermSearchCtx};
+
+/// # Trivial tactic
+///
+/// Attempts to fulfill the goal by trying items in scope
+/// Also works as a starting point to move all items in scope to lookup table.
+///
+/// # Arguments
+/// * `ctx` - Context for the term search
+/// * `defs` - Set of items in scope at term search target location
+/// * `lookup` - Lookup table for types
+///
+/// Returns iterator that yields elements that unify with `goal`.
+///
+/// _Note that there is no use of calling this tactic in every iteration as the output does not
+/// depend on the current state of `lookup`_
+pub(super) fn trivial<'a, DB: HirDatabase>(
+    ctx: &'a TermSearchCtx<'a, DB>,
+    defs: &'a FxHashSet<ScopeDef>,
+    lookup: &'a mut LookupTable,
+) -> impl Iterator<Item = Expr> + 'a {
+    let db = ctx.sema.db;
+    defs.iter().filter_map(|def| {
+        let expr = match def {
+            ScopeDef::ModuleDef(ModuleDef::Const(it)) => Some(Expr::Const(*it)),
+            ScopeDef::ModuleDef(ModuleDef::Static(it)) => Some(Expr::Static(*it)),
+            ScopeDef::GenericParam(GenericParam::ConstParam(it)) => Some(Expr::ConstParam(*it)),
+            ScopeDef::Local(it) => {
+                if ctx.config.enable_borrowcheck {
+                    let borrowck = db.borrowck(it.parent).ok()?;
+
+                    let invalid = borrowck.iter().any(|b| {
+                        b.partially_moved.iter().any(|moved| {
+                            Some(&moved.local) == b.mir_body.binding_locals.get(it.binding_id)
+                        }) || b.borrow_regions.iter().any(|region| {
+                            // Shared borrows are fine
+                            Some(&region.local) == b.mir_body.binding_locals.get(it.binding_id)
+                                && region.kind != BorrowKind::Shared
+                        })
+                    });
+
+                    if invalid {
+                        return None;
+                    }
+                }
+
+                Some(Expr::Local(*it))
+            }
+            _ => None,
+        }?;
+
+        lookup.mark_exhausted(*def);
+
+        let ty = expr.ty(db);
+        lookup.insert(ty.clone(), std::iter::once(expr.clone()));
+
+        // Don't suggest local references as they are not valid for return
+        if matches!(expr, Expr::Local(_)) && ty.contains_reference(db) {
+            return None;
+        }
+
+        ty.could_unify_with_deeply(db, &ctx.goal).then_some(expr)
+    })
+}
+
+/// # Type constructor tactic
+///
+/// Attempts different type constructors for enums and structs in scope
+///
+/// Updates lookup by new types reached and returns iterator that yields
+/// elements that unify with `goal`.
+///
+/// # Arguments
+/// * `ctx` - Context for the term search
+/// * `defs` - Set of items in scope at term search target location
+/// * `lookup` - Lookup table for types
+pub(super) fn type_constructor<'a, DB: HirDatabase>(
+    ctx: &'a TermSearchCtx<'a, DB>,
+    defs: &'a FxHashSet<ScopeDef>,
+    lookup: &'a mut LookupTable,
+) -> impl Iterator<Item = Expr> + 'a {
+    let db = ctx.sema.db;
+    let module = ctx.scope.module();
+    fn variant_helper(
+        db: &dyn HirDatabase,
+        lookup: &mut LookupTable,
+        parent_enum: Enum,
+        variant: Variant,
+        goal: &Type,
+        config: &TermSearchConfig,
+    ) -> Vec<(Type, Vec<Expr>)> {
+        // Ignore unstable
+        if variant.is_unstable(db) {
+            return Vec::new();
+        }
+
+        let generics = GenericDef::from(variant.parent_enum(db));
+        let Some(type_params) = generics
+            .type_or_const_params(db)
+            .into_iter()
+            .map(|it| it.as_type_param(db))
+            .collect::<Option<Vec<TypeParam>>>()
+        else {
+            // Ignore enums with const generics
+            return Vec::new();
+        };
+
+        // We currently do not check lifetime bounds so ignore all types that have something to do
+        // with them
+        if !generics.lifetime_params(db).is_empty() {
+            return Vec::new();
+        }
+
+        // Only account for stable type parameters for now, unstable params can be default
+        // tho, for example in `Box<T, #[unstable] A: Allocator>`
+        if type_params.iter().any(|it| it.is_unstable(db) && it.default(db).is_none()) {
+            return Vec::new();
+        }
+
+        let non_default_type_params_len =
+            type_params.iter().filter(|it| it.default(db).is_none()).count();
+
+        let generic_params = lookup
+            .iter_types()
+            .collect::<Vec<_>>() // Force take ownership
+            .into_iter()
+            .permutations(non_default_type_params_len);
+
+        generic_params
+            .filter_map(move |generics| {
+                // Insert default type params
+                let mut g = generics.into_iter();
+                let generics: Vec<_> = type_params
+                    .iter()
+                    .map(|it| it.default(db).unwrap_or_else(|| g.next().expect("No generic")))
+                    .collect();
+
+                let enum_ty = Adt::from(parent_enum).ty_with_args(db, generics.iter().cloned());
+
+                // Allow types with generics only if they take us straight to goal for
+                // performance reasons
+                if !generics.is_empty() && !enum_ty.could_unify_with_deeply(db, goal) {
+                    return None;
+                }
+
+                // Ignore types that have something to do with lifetimes
+                if config.enable_borrowcheck && enum_ty.contains_reference(db) {
+                    return None;
+                }
+
+                // Early exit if some param cannot be filled from lookup
+                let param_exprs: Vec<Vec<Expr>> = variant
+                    .fields(db)
+                    .into_iter()
+                    .map(|field| lookup.find(db, &field.ty_with_args(db, generics.iter().cloned())))
+                    .collect::<Option<_>>()?;
+
+                // Note that we need special case for 0 param constructors because of multi cartesian
+                // product
+                let variant_exprs: Vec<Expr> = if param_exprs.is_empty() {
+                    vec![Expr::Variant { variant, generics: generics.clone(), params: Vec::new() }]
+                } else {
+                    param_exprs
+                        .into_iter()
+                        .multi_cartesian_product()
+                        .map(|params| Expr::Variant { variant, generics: generics.clone(), params })
+                        .collect()
+                };
+                lookup.insert(enum_ty.clone(), variant_exprs.iter().cloned());
+
+                Some((enum_ty, variant_exprs))
+            })
+            .collect()
+    }
+    defs.iter()
+        .filter_map(move |def| match def {
+            ScopeDef::ModuleDef(ModuleDef::Variant(it)) => {
+                let variant_exprs =
+                    variant_helper(db, lookup, it.parent_enum(db), *it, &ctx.goal, &ctx.config);
+                if variant_exprs.is_empty() {
+                    return None;
+                }
+                lookup.mark_fulfilled(ScopeDef::ModuleDef(ModuleDef::Variant(*it)));
+                Some(variant_exprs)
+            }
+            ScopeDef::ModuleDef(ModuleDef::Adt(Adt::Enum(enum_))) => {
+                let exprs: Vec<(Type, Vec<Expr>)> = enum_
+                    .variants(db)
+                    .into_iter()
+                    .flat_map(|it| variant_helper(db, lookup, *enum_, it, &ctx.goal, &ctx.config))
+                    .collect();
+
+                if !exprs.is_empty() {
+                    lookup.mark_fulfilled(ScopeDef::ModuleDef(ModuleDef::Adt(Adt::Enum(*enum_))));
+                }
+
+                Some(exprs)
+            }
+            ScopeDef::ModuleDef(ModuleDef::Adt(Adt::Struct(it))) => {
+                // Ignore unstable and not visible
+                if it.is_unstable(db) || !it.is_visible_from(db, module) {
+                    return None;
+                }
+
+                let generics = GenericDef::from(*it);
+
+                // Ignore const params for now
+                let type_params = generics
+                    .type_or_const_params(db)
+                    .into_iter()
+                    .map(|it| it.as_type_param(db))
+                    .collect::<Option<Vec<TypeParam>>>()?;
+
+                // We currently do not check lifetime bounds so ignore all types that have something to do
+                // with them
+                if !generics.lifetime_params(db).is_empty() {
+                    return None;
+                }
+
+                // Only account for stable type parameters for now, unstable params can be default
+                // tho, for example in `Box<T, #[unstable] A: Allocator>`
+                if type_params.iter().any(|it| it.is_unstable(db) && it.default(db).is_none()) {
+                    return None;
+                }
+
+                let non_default_type_params_len =
+                    type_params.iter().filter(|it| it.default(db).is_none()).count();
+
+                let generic_params = lookup
+                    .iter_types()
+                    .collect::<Vec<_>>() // Force take ownership
+                    .into_iter()
+                    .permutations(non_default_type_params_len);
+
+                let exprs = generic_params
+                    .filter_map(|generics| {
+                        // Insert default type params
+                        let mut g = generics.into_iter();
+                        let generics: Vec<_> = type_params
+                            .iter()
+                            .map(|it| {
+                                it.default(db)
+                                    .unwrap_or_else(|| g.next().expect("Missing type param"))
+                            })
+                            .collect();
+
+                        let struct_ty = Adt::from(*it).ty_with_args(db, generics.iter().cloned());
+
+                        // Allow types with generics only if they take us straight to goal for
+                        // performance reasons
+                        if non_default_type_params_len != 0
+                            && struct_ty.could_unify_with_deeply(db, &ctx.goal)
+                        {
+                            return None;
+                        }
+
+                        // Ignore types that have something to do with lifetimes
+                        if ctx.config.enable_borrowcheck && struct_ty.contains_reference(db) {
+                            return None;
+                        }
+                        let fileds = it.fields(db);
+                        // Check if all fields are visible, otherwise we cannot fill them
+                        if fileds.iter().any(|it| !it.is_visible_from(db, module)) {
+                            return None;
+                        }
+
+                        // Early exit if some param cannot be filled from lookup
+                        let param_exprs: Vec<Vec<Expr>> = fileds
+                            .into_iter()
+                            .map(|field| lookup.find(db, &field.ty(db)))
+                            .collect::<Option<_>>()?;
+
+                        // Note that we need special case for 0 param constructors because of multi cartesian
+                        // product
+                        let struct_exprs: Vec<Expr> = if param_exprs.is_empty() {
+                            vec![Expr::Struct { strukt: *it, generics, params: Vec::new() }]
+                        } else {
+                            param_exprs
+                                .into_iter()
+                                .multi_cartesian_product()
+                                .map(|params| Expr::Struct {
+                                    strukt: *it,
+                                    generics: generics.clone(),
+                                    params,
+                                })
+                                .collect()
+                        };
+
+                        lookup
+                            .mark_fulfilled(ScopeDef::ModuleDef(ModuleDef::Adt(Adt::Struct(*it))));
+                        lookup.insert(struct_ty.clone(), struct_exprs.iter().cloned());
+
+                        Some((struct_ty, struct_exprs))
+                    })
+                    .collect();
+                Some(exprs)
+            }
+            _ => None,
+        })
+        .flatten()
+        .filter_map(|(ty, exprs)| ty.could_unify_with_deeply(db, &ctx.goal).then_some(exprs))
+        .flatten()
+}
+
+/// # Free function tactic
+///
+/// Attempts to call different functions in scope with parameters from lookup table.
+/// Functions that include generics are not used for performance reasons.
+///
+/// Updates lookup by new types reached and returns iterator that yields
+/// elements that unify with `goal`.
+///
+/// # Arguments
+/// * `ctx` - Context for the term search
+/// * `defs` - Set of items in scope at term search target location
+/// * `lookup` - Lookup table for types
+pub(super) fn free_function<'a, DB: HirDatabase>(
+    ctx: &'a TermSearchCtx<'a, DB>,
+    defs: &'a FxHashSet<ScopeDef>,
+    lookup: &'a mut LookupTable,
+) -> impl Iterator<Item = Expr> + 'a {
+    let db = ctx.sema.db;
+    let module = ctx.scope.module();
+    defs.iter()
+        .filter_map(move |def| match def {
+            ScopeDef::ModuleDef(ModuleDef::Function(it)) => {
+                let generics = GenericDef::from(*it);
+
+                // Ignore const params for now
+                let type_params = generics
+                    .type_or_const_params(db)
+                    .into_iter()
+                    .map(|it| it.as_type_param(db))
+                    .collect::<Option<Vec<TypeParam>>>()?;
+
+                // Ignore lifetimes as we do not check them
+                if !generics.lifetime_params(db).is_empty() {
+                    return None;
+                }
+
+                // Only account for stable type parameters for now, unstable params can be default
+                // tho, for example in `Box<T, #[unstable] A: Allocator>`
+                if type_params.iter().any(|it| it.is_unstable(db) && it.default(db).is_none()) {
+                    return None;
+                }
+
+                let non_default_type_params_len =
+                    type_params.iter().filter(|it| it.default(db).is_none()).count();
+
+                // Ignore bigger number of generics for now as they kill the performance
+                if non_default_type_params_len > 0 {
+                    return None;
+                }
+
+                let generic_params = lookup
+                    .iter_types()
+                    .collect::<Vec<_>>() // Force take ownership
+                    .into_iter()
+                    .permutations(non_default_type_params_len);
+
+                let exprs: Vec<_> = generic_params
+                    .filter_map(|generics| {
+                        // Insert default type params
+                        let mut g = generics.into_iter();
+                        let generics: Vec<_> = type_params
+                            .iter()
+                            .map(|it| match it.default(db) {
+                                Some(ty) => Some(ty),
+                                None => {
+                                    let generic = g.next().expect("Missing type param");
+                                    // Filter out generics that do not unify due to trait bounds
+                                    it.ty(db).could_unify_with(db, &generic).then_some(generic)
+                                }
+                            })
+                            .collect::<Option<_>>()?;
+
+                        let ret_ty = it.ret_type_with_args(db, generics.iter().cloned());
+                        // Filter out private and unsafe functions
+                        if !it.is_visible_from(db, module)
+                            || it.is_unsafe_to_call(db)
+                            || it.is_unstable(db)
+                            || ctx.config.enable_borrowcheck && ret_ty.contains_reference(db)
+                            || ret_ty.is_raw_ptr()
+                        {
+                            return None;
+                        }
+
+                        // Early exit if some param cannot be filled from lookup
+                        let param_exprs: Vec<Vec<Expr>> = it
+                            .params_without_self_with_args(db, generics.iter().cloned())
+                            .into_iter()
+                            .map(|field| {
+                                let ty = field.ty();
+                                match ty.is_mutable_reference() {
+                                    true => None,
+                                    false => lookup.find_autoref(db, ty),
+                                }
+                            })
+                            .collect::<Option<_>>()?;
+
+                        // Note that we need special case for 0 param constructors because of multi cartesian
+                        // product
+                        let fn_exprs: Vec<Expr> = if param_exprs.is_empty() {
+                            vec![Expr::Function { func: *it, generics, params: Vec::new() }]
+                        } else {
+                            param_exprs
+                                .into_iter()
+                                .multi_cartesian_product()
+                                .map(|params| Expr::Function {
+                                    func: *it,
+                                    generics: generics.clone(),
+
+                                    params,
+                                })
+                                .collect()
+                        };
+
+                        lookup.mark_fulfilled(ScopeDef::ModuleDef(ModuleDef::Function(*it)));
+                        lookup.insert(ret_ty.clone(), fn_exprs.iter().cloned());
+                        Some((ret_ty, fn_exprs))
+                    })
+                    .collect();
+                Some(exprs)
+            }
+            _ => None,
+        })
+        .flatten()
+        .filter_map(|(ty, exprs)| ty.could_unify_with_deeply(db, &ctx.goal).then_some(exprs))
+        .flatten()
+}
+
+/// # Impl method tactic
+///
+/// Attempts to to call methods on types from lookup table.
+/// This includes both functions from direct impl blocks as well as functions from traits.
+/// Methods defined in impl blocks that are generic and methods that are themselves have
+/// generics are ignored for performance reasons.
+///
+/// Updates lookup by new types reached and returns iterator that yields
+/// elements that unify with `goal`.
+///
+/// # Arguments
+/// * `ctx` - Context for the term search
+/// * `defs` - Set of items in scope at term search target location
+/// * `lookup` - Lookup table for types
+pub(super) fn impl_method<'a, DB: HirDatabase>(
+    ctx: &'a TermSearchCtx<'a, DB>,
+    _defs: &'a FxHashSet<ScopeDef>,
+    lookup: &'a mut LookupTable,
+) -> impl Iterator<Item = Expr> + 'a {
+    let db = ctx.sema.db;
+    let module = ctx.scope.module();
+    lookup
+        .new_types(NewTypesKey::ImplMethod)
+        .into_iter()
+        .flat_map(|ty| {
+            Impl::all_for_type(db, ty.clone()).into_iter().map(move |imp| (ty.clone(), imp))
+        })
+        .flat_map(|(ty, imp)| imp.items(db).into_iter().map(move |item| (imp, ty.clone(), item)))
+        .filter_map(|(imp, ty, it)| match it {
+            AssocItem::Function(f) => Some((imp, ty, f)),
+            _ => None,
+        })
+        .filter_map(move |(imp, ty, it)| {
+            let fn_generics = GenericDef::from(it);
+            let imp_generics = GenericDef::from(imp);
+
+            // Ignore const params for now
+            let imp_type_params = imp_generics
+                .type_or_const_params(db)
+                .into_iter()
+                .map(|it| it.as_type_param(db))
+                .collect::<Option<Vec<TypeParam>>>()?;
+
+            // Ignore const params for now
+            let fn_type_params = fn_generics
+                .type_or_const_params(db)
+                .into_iter()
+                .map(|it| it.as_type_param(db))
+                .collect::<Option<Vec<TypeParam>>>()?;
+
+            // Ignore all functions that have something to do with lifetimes as we don't check them
+            if !fn_generics.lifetime_params(db).is_empty() {
+                return None;
+            }
+
+            // Ignore functions without self param
+            if !it.has_self_param(db) {
+                return None;
+            }
+
+            // Filter out private and unsafe functions
+            if !it.is_visible_from(db, module) || it.is_unsafe_to_call(db) || it.is_unstable(db) {
+                return None;
+            }
+
+            // Only account for stable type parameters for now, unstable params can be default
+            // tho, for example in `Box<T, #[unstable] A: Allocator>`
+            if imp_type_params.iter().any(|it| it.is_unstable(db) && it.default(db).is_none())
+                || fn_type_params.iter().any(|it| it.is_unstable(db) && it.default(db).is_none())
+            {
+                return None;
+            }
+
+            let non_default_type_params_len = imp_type_params
+                .iter()
+                .chain(fn_type_params.iter())
+                .filter(|it| it.default(db).is_none())
+                .count();
+
+            // Ignore bigger number of generics for now as they kill the performance
+            if non_default_type_params_len > 0 {
+                return None;
+            }
+
+            let generic_params = lookup
+                .iter_types()
+                .collect::<Vec<_>>() // Force take ownership
+                .into_iter()
+                .permutations(non_default_type_params_len);
+
+            let exprs: Vec<_> = generic_params
+                .filter_map(|generics| {
+                    // Insert default type params
+                    let mut g = generics.into_iter();
+                    let generics: Vec<_> = imp_type_params
+                        .iter()
+                        .chain(fn_type_params.iter())
+                        .map(|it| match it.default(db) {
+                            Some(ty) => Some(ty),
+                            None => {
+                                let generic = g.next().expect("Missing type param");
+                                // Filter out generics that do not unify due to trait bounds
+                                it.ty(db).could_unify_with(db, &generic).then_some(generic)
+                            }
+                        })
+                        .collect::<Option<_>>()?;
+
+                    let ret_ty = it.ret_type_with_args(
+                        db,
+                        ty.type_arguments().chain(generics.iter().cloned()),
+                    );
+                    // Filter out functions that return references
+                    if ctx.config.enable_borrowcheck && ret_ty.contains_reference(db)
+                        || ret_ty.is_raw_ptr()
+                    {
+                        return None;
+                    }
+
+                    // Ignore functions that do not change the type
+                    if ty.could_unify_with_deeply(db, &ret_ty) {
+                        return None;
+                    }
+
+                    let self_ty = it
+                        .self_param(db)
+                        .expect("No self param")
+                        .ty_with_args(db, ty.type_arguments().chain(generics.iter().cloned()));
+
+                    // Ignore functions that have different self type
+                    if !self_ty.autoderef(db).any(|s_ty| ty == s_ty) {
+                        return None;
+                    }
+
+                    let target_type_exprs = lookup.find(db, &ty).expect("Type not in lookup");
+
+                    // Early exit if some param cannot be filled from lookup
+                    let param_exprs: Vec<Vec<Expr>> = it
+                        .params_without_self_with_args(
+                            db,
+                            ty.type_arguments().chain(generics.iter().cloned()),
+                        )
+                        .into_iter()
+                        .map(|field| lookup.find_autoref(db, field.ty()))
+                        .collect::<Option<_>>()?;
+
+                    let fn_exprs: Vec<Expr> = std::iter::once(target_type_exprs)
+                        .chain(param_exprs)
+                        .multi_cartesian_product()
+                        .map(|params| {
+                            let mut params = params.into_iter();
+                            let target = Box::new(params.next().unwrap());
+                            Expr::Method {
+                                func: it,
+                                generics: generics.clone(),
+                                target,
+                                params: params.collect(),
+                            }
+                        })
+                        .collect();
+
+                    lookup.insert(ret_ty.clone(), fn_exprs.iter().cloned());
+                    Some((ret_ty, fn_exprs))
+                })
+                .collect();
+            Some(exprs)
+        })
+        .flatten()
+        .filter_map(|(ty, exprs)| ty.could_unify_with_deeply(db, &ctx.goal).then_some(exprs))
+        .flatten()
+}
+
+/// # Struct projection tactic
+///
+/// Attempts different struct fields (`foo.bar.baz`)
+///
+/// Updates lookup by new types reached and returns iterator that yields
+/// elements that unify with `goal`.
+///
+/// # Arguments
+/// * `ctx` - Context for the term search
+/// * `defs` - Set of items in scope at term search target location
+/// * `lookup` - Lookup table for types
+pub(super) fn struct_projection<'a, DB: HirDatabase>(
+    ctx: &'a TermSearchCtx<'a, DB>,
+    _defs: &'a FxHashSet<ScopeDef>,
+    lookup: &'a mut LookupTable,
+) -> impl Iterator<Item = Expr> + 'a {
+    let db = ctx.sema.db;
+    let module = ctx.scope.module();
+    lookup
+        .new_types(NewTypesKey::StructProjection)
+        .into_iter()
+        .map(|ty| (ty.clone(), lookup.find(db, &ty).expect("Expr not in lookup")))
+        .flat_map(move |(ty, targets)| {
+            ty.fields(db).into_iter().filter_map(move |(field, filed_ty)| {
+                if !field.is_visible_from(db, module) {
+                    return None;
+                }
+                let exprs = targets
+                    .clone()
+                    .into_iter()
+                    .map(move |target| Expr::Field { field, expr: Box::new(target) });
+                Some((filed_ty, exprs))
+            })
+        })
+        .filter_map(|(ty, exprs)| ty.could_unify_with_deeply(db, &ctx.goal).then_some(exprs))
+        .flatten()
+}
+
+/// # Famous types tactic
+///
+/// Attempts different values of well known types such as `true` or `false`.
+///
+/// Updates lookup by new types reached and returns iterator that yields
+/// elements that unify with `goal`.
+///
+/// _Note that there is no point of calling it iteratively as the output is always the same_
+///
+/// # Arguments
+/// * `ctx` - Context for the term search
+/// * `defs` - Set of items in scope at term search target location
+/// * `lookup` - Lookup table for types
+pub(super) fn famous_types<'a, DB: HirDatabase>(
+    ctx: &'a TermSearchCtx<'a, DB>,
+    _defs: &'a FxHashSet<ScopeDef>,
+    lookup: &'a mut LookupTable,
+) -> impl Iterator<Item = Expr> + 'a {
+    let db = ctx.sema.db;
+    let module = ctx.scope.module();
+    [
+        Expr::FamousType { ty: Type::new(db, module.id, TyBuilder::bool()), value: "true" },
+        Expr::FamousType { ty: Type::new(db, module.id, TyBuilder::bool()), value: "false" },
+        Expr::FamousType { ty: Type::new(db, module.id, TyBuilder::unit()), value: "()" },
+    ]
+    .into_iter()
+    .map(|exprs| {
+        lookup.insert(exprs.ty(db), std::iter::once(exprs.clone()));
+        exprs
+    })
+    .filter(|expr| expr.ty(db).could_unify_with_deeply(db, &ctx.goal))
+}
+
+/// # Impl static method (without self type) tactic
+///
+/// Attempts different functions from impl blocks that take no self parameter.
+///
+/// Updates lookup by new types reached and returns iterator that yields
+/// elements that unify with `goal`.
+///
+/// # Arguments
+/// * `ctx` - Context for the term search
+/// * `defs` - Set of items in scope at term search target location
+/// * `lookup` - Lookup table for types
+pub(super) fn impl_static_method<'a, DB: HirDatabase>(
+    ctx: &'a TermSearchCtx<'a, DB>,
+    _defs: &'a FxHashSet<ScopeDef>,
+    lookup: &'a mut LookupTable,
+) -> impl Iterator<Item = Expr> + 'a {
+    let db = ctx.sema.db;
+    let module = ctx.scope.module();
+    lookup
+        .take_types_wishlist()
+        .into_iter()
+        .chain(iter::once(ctx.goal.clone()))
+        .flat_map(|ty| {
+            Impl::all_for_type(db, ty.clone()).into_iter().map(move |imp| (ty.clone(), imp))
+        })
+        .filter(|(_, imp)| !imp.is_unsafe(db))
+        .flat_map(|(ty, imp)| imp.items(db).into_iter().map(move |item| (imp, ty.clone(), item)))
+        .filter_map(|(imp, ty, it)| match it {
+            AssocItem::Function(f) => Some((imp, ty, f)),
+            _ => None,
+        })
+        .filter_map(move |(imp, ty, it)| {
+            let fn_generics = GenericDef::from(it);
+            let imp_generics = GenericDef::from(imp);
+
+            // Ignore const params for now
+            let imp_type_params = imp_generics
+                .type_or_const_params(db)
+                .into_iter()
+                .map(|it| it.as_type_param(db))
+                .collect::<Option<Vec<TypeParam>>>()?;
+
+            // Ignore const params for now
+            let fn_type_params = fn_generics
+                .type_or_const_params(db)
+                .into_iter()
+                .map(|it| it.as_type_param(db))
+                .collect::<Option<Vec<TypeParam>>>()?;
+
+            // Ignore all functions that have something to do with lifetimes as we don't check them
+            if !fn_generics.lifetime_params(db).is_empty()
+                || !imp_generics.lifetime_params(db).is_empty()
+            {
+                return None;
+            }
+
+            // Ignore functions with self param
+            if it.has_self_param(db) {
+                return None;
+            }
+
+            // Filter out private and unsafe functions
+            if !it.is_visible_from(db, module) || it.is_unsafe_to_call(db) || it.is_unstable(db) {
+                return None;
+            }
+
+            // Only account for stable type parameters for now, unstable params can be default
+            // tho, for example in `Box<T, #[unstable] A: Allocator>`
+            if imp_type_params.iter().any(|it| it.is_unstable(db) && it.default(db).is_none())
+                || fn_type_params.iter().any(|it| it.is_unstable(db) && it.default(db).is_none())
+            {
+                return None;
+            }
+
+            let non_default_type_params_len = imp_type_params
+                .iter()
+                .chain(fn_type_params.iter())
+                .filter(|it| it.default(db).is_none())
+                .count();
+
+            // Ignore bigger number of generics for now as they kill the performance
+            if non_default_type_params_len > 1 {
+                return None;
+            }
+
+            let generic_params = lookup
+                .iter_types()
+                .collect::<Vec<_>>() // Force take ownership
+                .into_iter()
+                .permutations(non_default_type_params_len);
+
+            let exprs: Vec<_> = generic_params
+                .filter_map(|generics| {
+                    // Insert default type params
+                    let mut g = generics.into_iter();
+                    let generics: Vec<_> = imp_type_params
+                        .iter()
+                        .chain(fn_type_params.iter())
+                        .map(|it| match it.default(db) {
+                            Some(ty) => Some(ty),
+                            None => {
+                                let generic = g.next().expect("Missing type param");
+                                it.trait_bounds(db)
+                                    .into_iter()
+                                    .all(|bound| generic.impls_trait(db, bound, &[]));
+                                // Filter out generics that do not unify due to trait bounds
+                                it.ty(db).could_unify_with(db, &generic).then_some(generic)
+                            }
+                        })
+                        .collect::<Option<_>>()?;
+
+                    let ret_ty = it.ret_type_with_args(
+                        db,
+                        ty.type_arguments().chain(generics.iter().cloned()),
+                    );
+                    // Filter out functions that return references
+                    if ctx.config.enable_borrowcheck && ret_ty.contains_reference(db)
+                        || ret_ty.is_raw_ptr()
+                    {
+                        return None;
+                    }
+
+                    // Ignore functions that do not change the type
+                    // if ty.could_unify_with_deeply(db, &ret_ty) {
+                    //     return None;
+                    // }
+
+                    // Early exit if some param cannot be filled from lookup
+                    let param_exprs: Vec<Vec<Expr>> = it
+                        .params_without_self_with_args(
+                            db,
+                            ty.type_arguments().chain(generics.iter().cloned()),
+                        )
+                        .into_iter()
+                        .map(|field| lookup.find_autoref(db, field.ty()))
+                        .collect::<Option<_>>()?;
+
+                    // Note that we need special case for 0 param constructors because of multi cartesian
+                    // product
+                    let fn_exprs: Vec<Expr> = if param_exprs.is_empty() {
+                        vec![Expr::Function { func: it, generics, params: Vec::new() }]
+                    } else {
+                        param_exprs
+                            .into_iter()
+                            .multi_cartesian_product()
+                            .map(|params| Expr::Function {
+                                func: it,
+                                generics: generics.clone(),
+                                params,
+                            })
+                            .collect()
+                    };
+
+                    lookup.insert(ret_ty.clone(), fn_exprs.iter().cloned());
+                    Some((ret_ty, fn_exprs))
+                })
+                .collect();
+            Some(exprs)
+        })
+        .flatten()
+        .filter_map(|(ty, exprs)| ty.could_unify_with_deeply(db, &ctx.goal).then_some(exprs))
+        .flatten()
+}
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/fix_visibility.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/fix_visibility.rs
index 204e796fa2c..589591a6777 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/fix_visibility.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/fix_visibility.rs
@@ -79,7 +79,7 @@ fn add_vis_to_referenced_module_def(acc: &mut Assists, ctx: &AssistContext<'_>)
         edit.edit_file(target_file);
 
         let vis_owner = edit.make_mut(vis_owner);
-        vis_owner.set_visibility(missing_visibility.clone_for_update());
+        vis_owner.set_visibility(Some(missing_visibility.clone_for_update()));
 
         if let Some((cap, vis)) = ctx.config.snippet_cap.zip(vis_owner.visibility()) {
             edit.add_tabstop_before(cap, vis);
@@ -131,7 +131,7 @@ fn add_vis_to_referenced_record_field(acc: &mut Assists, ctx: &AssistContext<'_>
         edit.edit_file(target_file);
 
         let vis_owner = edit.make_mut(vis_owner);
-        vis_owner.set_visibility(missing_visibility.clone_for_update());
+        vis_owner.set_visibility(Some(missing_visibility.clone_for_update()));
 
         if let Some((cap, vis)) = ctx.config.snippet_cap.zip(vis_owner.visibility()) {
             edit.add_tabstop_before(cap, vis);
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_delegate_methods.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_delegate_methods.rs
index 4f2df5633c3..38f40b8d58b 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_delegate_methods.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_delegate_methods.rs
@@ -1,4 +1,4 @@
-use hir::{self, HasCrate, HasVisibility};
+use hir::{HasCrate, HasVisibility};
 use ide_db::{path_transform::PathTransform, FxHashSet};
 use syntax::{
     ast::{
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_trait_from_impl.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_trait_from_impl.rs
index 24094de22c8..5f7350bc281 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_trait_from_impl.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_trait_from_impl.rs
@@ -1,8 +1,13 @@
 use crate::assist_context::{AssistContext, Assists};
 use ide_db::assists::AssistId;
 use syntax::{
-    ast::{self, edit::IndentLevel, make, HasGenericParams, HasVisibility},
-    ted, AstNode, SyntaxKind,
+    ast::{
+        self,
+        edit_in_place::{HasVisibilityEdit, Indent},
+        make, HasGenericParams, HasName,
+    },
+    ted::{self, Position},
+    AstNode, SyntaxKind, T,
 };
 
 // NOTES :
@@ -44,7 +49,7 @@ use syntax::{
 //     };
 // }
 //
-// trait ${0:TraitName}<const N: usize> {
+// trait ${0:NewTrait}<const N: usize> {
 //     // Used as an associated constant.
 //     const CONST_ASSOC: usize = N * 4;
 //
@@ -53,7 +58,7 @@ use syntax::{
 //     const_maker! {i32, 7}
 // }
 //
-// impl<const N: usize> ${0:TraitName}<N> for Foo<N> {
+// impl<const N: usize> ${0:NewTrait}<N> for Foo<N> {
 //     // Used as an associated constant.
 //     const CONST_ASSOC: usize = N * 4;
 //
@@ -94,8 +99,10 @@ pub(crate) fn generate_trait_from_impl(acc: &mut Assists, ctx: &AssistContext<'_
         "Generate trait from impl",
         impl_ast.syntax().text_range(),
         |builder| {
+            let impl_ast = builder.make_mut(impl_ast);
             let trait_items = assoc_items.clone_for_update();
-            let impl_items = assoc_items.clone_for_update();
+            let impl_items = builder.make_mut(assoc_items);
+            let impl_name = builder.make_mut(impl_name);
 
             trait_items.assoc_items().for_each(|item| {
                 strip_body(&item);
@@ -112,46 +119,42 @@ pub(crate) fn generate_trait_from_impl(acc: &mut Assists, ctx: &AssistContext<'_
                 impl_ast.generic_param_list(),
                 impl_ast.where_clause(),
                 trait_items,
-            );
+            )
+            .clone_for_update();
+
+            let trait_name = trait_ast.name().expect("new trait should have a name");
+            let trait_name_ref = make::name_ref(&trait_name.to_string()).clone_for_update();
 
             // Change `impl Foo` to `impl NewTrait for Foo`
-            let arg_list = if let Some(genpars) = impl_ast.generic_param_list() {
-                genpars.to_generic_args().to_string()
-            } else {
-                "".to_owned()
-            };
-
-            if let Some(snippet_cap) = ctx.config.snippet_cap {
-                builder.replace_snippet(
-                    snippet_cap,
-                    impl_name.syntax().text_range(),
-                    format!("${{0:TraitName}}{} for {}", arg_list, impl_name),
-                );
+            let mut elements = vec![
+                trait_name_ref.syntax().clone().into(),
+                make::tokens::single_space().into(),
+                make::token(T![for]).into(),
+            ];
+
+            if let Some(params) = impl_ast.generic_param_list() {
+                let gen_args = &params.to_generic_args().clone_for_update();
+                elements.insert(1, gen_args.syntax().clone().into());
+            }
 
-                // Insert trait before TraitImpl
-                builder.insert_snippet(
-                    snippet_cap,
-                    impl_ast.syntax().text_range().start(),
-                    format!(
-                        "{}\n\n{}",
-                        trait_ast.to_string().replace("NewTrait", "${0:TraitName}"),
-                        IndentLevel::from_node(impl_ast.syntax())
-                    ),
-                );
-            } else {
-                builder.replace(
-                    impl_name.syntax().text_range(),
-                    format!("NewTrait{} for {}", arg_list, impl_name),
-                );
+            ted::insert_all(Position::before(impl_name.syntax()), elements);
+
+            // Insert trait before TraitImpl
+            ted::insert_all_raw(
+                Position::before(impl_ast.syntax()),
+                vec![
+                    trait_ast.syntax().clone().into(),
+                    make::tokens::whitespace(&format!("\n\n{}", impl_ast.indent_level())).into(),
+                ],
+            );
 
-                // Insert trait before TraitImpl
-                builder.insert(
-                    impl_ast.syntax().text_range().start(),
-                    format!("{}\n\n{}", trait_ast, IndentLevel::from_node(impl_ast.syntax())),
+            // Link the trait name & trait ref names together as a placeholder snippet group
+            if let Some(cap) = ctx.config.snippet_cap {
+                builder.add_placeholder_snippet_group(
+                    cap,
+                    vec![trait_name.syntax().clone(), trait_name_ref.syntax().clone()],
                 );
             }
-
-            builder.replace(assoc_items.syntax().text_range(), impl_items.to_string());
         },
     );
 
@@ -160,23 +163,8 @@ pub(crate) fn generate_trait_from_impl(acc: &mut Assists, ctx: &AssistContext<'_
 
 /// `E0449` Trait items always share the visibility of their trait
 fn remove_items_visibility(item: &ast::AssocItem) {
-    match item {
-        ast::AssocItem::Const(c) => {
-            if let Some(vis) = c.visibility() {
-                ted::remove(vis.syntax());
-            }
-        }
-        ast::AssocItem::Fn(f) => {
-            if let Some(vis) = f.visibility() {
-                ted::remove(vis.syntax());
-            }
-        }
-        ast::AssocItem::TypeAlias(t) => {
-            if let Some(vis) = t.visibility() {
-                ted::remove(vis.syntax());
-            }
-        }
-        _ => (),
+    if let Some(has_vis) = ast::AnyHasVisibility::cast(item.syntax().clone()) {
+        has_vis.set_visibility(None);
     }
 }
 
@@ -404,12 +392,12 @@ impl<const N: usize> F$0oo<N> {
             r#"
 struct Foo<const N: usize>([i32; N]);
 
-trait ${0:TraitName}<const N: usize> {
+trait ${0:NewTrait}<const N: usize> {
     // Used as an associated constant.
     const CONST: usize = N * 4;
 }
 
-impl<const N: usize> ${0:TraitName}<N> for Foo<N> {
+impl<const N: usize> ${0:NewTrait}<N> for Foo<N> {
     // Used as an associated constant.
     const CONST: usize = N * 4;
 }
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/term_search.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/term_search.rs
new file mode 100644
index 00000000000..51a1a406f31
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/term_search.rs
@@ -0,0 +1,253 @@
+//! Term search assist
+use hir::term_search::TermSearchCtx;
+use ide_db::{
+    assists::{AssistId, AssistKind, GroupLabel},
+    famous_defs::FamousDefs,
+};
+
+use itertools::Itertools;
+use syntax::{ast, AstNode};
+
+use crate::assist_context::{AssistContext, Assists};
+
+pub(crate) fn term_search(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<()> {
+    let unexpanded = ctx.find_node_at_offset::<ast::MacroCall>()?;
+    let syntax = unexpanded.syntax();
+    let goal_range = syntax.text_range();
+
+    let parent = syntax.parent()?;
+    let scope = ctx.sema.scope(&parent)?;
+
+    let macro_call = ctx.sema.resolve_macro_call(&unexpanded)?;
+
+    let famous_defs = FamousDefs(&ctx.sema, scope.krate());
+    let std_todo = famous_defs.core_macros_todo()?;
+    let std_unimplemented = famous_defs.core_macros_unimplemented()?;
+
+    if macro_call != std_todo && macro_call != std_unimplemented {
+        return None;
+    }
+
+    let target_ty = ctx.sema.type_of_expr(&ast::Expr::cast(parent.clone())?)?.adjusted();
+
+    let term_search_ctx = TermSearchCtx {
+        sema: &ctx.sema,
+        scope: &scope,
+        goal: target_ty,
+        config: Default::default(),
+    };
+    let paths = hir::term_search::term_search(&term_search_ctx);
+
+    if paths.is_empty() {
+        return None;
+    }
+
+    let mut formatter = |_: &hir::Type| String::from("todo!()");
+
+    let paths = paths
+        .into_iter()
+        .filter_map(|path| {
+            path.gen_source_code(
+                &scope,
+                &mut formatter,
+                ctx.config.prefer_no_std,
+                ctx.config.prefer_prelude,
+            )
+            .ok()
+        })
+        .unique();
+
+    for code in paths {
+        acc.add_group(
+            &GroupLabel(String::from("Term search")),
+            AssistId("term_search", AssistKind::Generate),
+            format!("Replace todo!() with {code}"),
+            goal_range,
+            |builder| {
+                builder.replace(goal_range, code);
+            },
+        );
+    }
+
+    Some(())
+}
+
+#[cfg(test)]
+mod tests {
+    use crate::tests::{check_assist, check_assist_not_applicable};
+
+    use super::*;
+
+    #[test]
+    fn test_complete_local() {
+        check_assist(
+            term_search,
+            r#"//- minicore: todo, unimplemented
+fn f() { let a: u128 = 1; let b: u128 = todo$0!() }"#,
+            r#"fn f() { let a: u128 = 1; let b: u128 = a }"#,
+        )
+    }
+
+    #[test]
+    fn test_complete_todo_with_msg() {
+        check_assist(
+            term_search,
+            r#"//- minicore: todo, unimplemented
+fn f() { let a: u128 = 1; let b: u128 = todo$0!("asd") }"#,
+            r#"fn f() { let a: u128 = 1; let b: u128 = a }"#,
+        )
+    }
+
+    #[test]
+    fn test_complete_unimplemented_with_msg() {
+        check_assist(
+            term_search,
+            r#"//- minicore: todo, unimplemented
+fn f() { let a: u128 = 1; let b: u128 = todo$0!("asd") }"#,
+            r#"fn f() { let a: u128 = 1; let b: u128 = a }"#,
+        )
+    }
+
+    #[test]
+    fn test_complete_unimplemented() {
+        check_assist(
+            term_search,
+            r#"//- minicore: todo, unimplemented
+fn f() { let a: u128 = 1; let b: u128 = todo$0!("asd") }"#,
+            r#"fn f() { let a: u128 = 1; let b: u128 = a }"#,
+        )
+    }
+
+    #[test]
+    fn test_complete_struct_field() {
+        check_assist(
+            term_search,
+            r#"//- minicore: todo, unimplemented
+struct A { pub x: i32, y: bool }
+fn f() { let a = A { x: 1, y: true }; let b: i32 = todo$0!(); }"#,
+            r#"struct A { pub x: i32, y: bool }
+fn f() { let a = A { x: 1, y: true }; let b: i32 = a.x; }"#,
+        )
+    }
+
+    #[test]
+    fn test_enum_with_generics() {
+        check_assist(
+            term_search,
+            r#"//- minicore: todo, unimplemented, option
+fn f() { let a: i32 = 1; let b: Option<i32> = todo$0!(); }"#,
+            r#"fn f() { let a: i32 = 1; let b: Option<i32> = None; }"#,
+        )
+    }
+
+    #[test]
+    fn test_enum_with_generics2() {
+        check_assist(
+            term_search,
+            r#"//- minicore: todo, unimplemented
+enum Option<T> { None, Some(T) }
+fn f() { let a: i32 = 1; let b: Option<i32> = todo$0!(); }"#,
+            r#"enum Option<T> { None, Some(T) }
+fn f() { let a: i32 = 1; let b: Option<i32> = Option::Some(a); }"#,
+        )
+    }
+
+    #[test]
+    fn test_enum_with_generics3() {
+        check_assist(
+            term_search,
+            r#"//- minicore: todo, unimplemented
+enum Option<T> { None, Some(T) }
+fn f() { let a: Option<i32> = Option::None; let b: Option<Option<i32>> = todo$0!(); }"#,
+            r#"enum Option<T> { None, Some(T) }
+fn f() { let a: Option<i32> = Option::None; let b: Option<Option<i32>> = Option::Some(a); }"#,
+        )
+    }
+
+    #[test]
+    fn test_enum_with_generics4() {
+        check_assist(
+            term_search,
+            r#"//- minicore: todo, unimplemented
+enum Foo<T = i32> { Foo(T) }
+fn f() { let a = 0; let b: Foo = todo$0!(); }"#,
+            r#"enum Foo<T = i32> { Foo(T) }
+fn f() { let a = 0; let b: Foo = Foo::Foo(a); }"#,
+        );
+
+        check_assist(
+            term_search,
+            r#"//- minicore: todo, unimplemented
+enum Foo<T = i32> { Foo(T) }
+fn f() { let a: Foo<u32> = Foo::Foo(0); let b: Foo<u32> = todo$0!(); }"#,
+            r#"enum Foo<T = i32> { Foo(T) }
+fn f() { let a: Foo<u32> = Foo::Foo(0); let b: Foo<u32> = a; }"#,
+        )
+    }
+
+    #[test]
+    fn test_newtype() {
+        check_assist(
+            term_search,
+            r#"//- minicore: todo, unimplemented
+struct Foo(i32);
+fn f() { let a: i32 = 1; let b: Foo = todo$0!(); }"#,
+            r#"struct Foo(i32);
+fn f() { let a: i32 = 1; let b: Foo = Foo(a); }"#,
+        )
+    }
+
+    #[test]
+    fn test_shadowing() {
+        check_assist(
+            term_search,
+            r#"//- minicore: todo, unimplemented
+fn f() { let a: i32 = 1; let b: i32 = 2; let a: u32 = 0; let c: i32 = todo$0!(); }"#,
+            r#"fn f() { let a: i32 = 1; let b: i32 = 2; let a: u32 = 0; let c: i32 = b; }"#,
+        )
+    }
+
+    #[test]
+    fn test_famous_bool() {
+        check_assist(
+            term_search,
+            r#"//- minicore: todo, unimplemented
+fn f() { let a: bool = todo$0!(); }"#,
+            r#"fn f() { let a: bool = false; }"#,
+        )
+    }
+
+    #[test]
+    fn test_fn_with_reference_types() {
+        check_assist(
+            term_search,
+            r#"//- minicore: todo, unimplemented
+fn f(a: &i32) -> f32 { a as f32 }
+fn g() { let a = 1; let b: f32 = todo$0!(); }"#,
+            r#"fn f(a: &i32) -> f32 { a as f32 }
+fn g() { let a = 1; let b: f32 = f(&a); }"#,
+        )
+    }
+
+    #[test]
+    fn test_fn_with_reference_types2() {
+        check_assist(
+            term_search,
+            r#"//- minicore: todo, unimplemented
+fn f(a: &i32) -> f32 { a as f32 }
+fn g() { let a = &1; let b: f32 = todo$0!(); }"#,
+            r#"fn f(a: &i32) -> f32 { a as f32 }
+fn g() { let a = &1; let b: f32 = f(a); }"#,
+        )
+    }
+
+    #[test]
+    fn test_fn_with_reference_types3() {
+        check_assist_not_applicable(
+            term_search,
+            r#"//- minicore: todo, unimplemented
+            fn f(a: &i32) -> f32 { a as f32 }
+            fn g() { let a = &mut 1; let b: f32 = todo$0!(); }"#,
+        )
+    }
+}
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/lib.rs b/src/tools/rust-analyzer/crates/ide-assists/src/lib.rs
index 2fec104323d..dcc89014b95 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/lib.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/lib.rs
@@ -60,11 +60,6 @@
 
 #![warn(rust_2018_idioms, unused_lifetimes)]
 
-#[allow(unused)]
-macro_rules! eprintln {
-    ($($tt:tt)*) => { stdx::eprintln!($($tt)*) };
-}
-
 mod assist_config;
 mod assist_context;
 #[cfg(test)]
@@ -210,6 +205,7 @@ mod handlers {
     mod replace_turbofish_with_explicit_type;
     mod sort_items;
     mod split_import;
+    mod term_search;
     mod toggle_ignore;
     mod unmerge_match_arm;
     mod unmerge_use;
@@ -332,6 +328,7 @@ mod handlers {
             replace_arith_op::replace_arith_with_saturating,
             sort_items::sort_items,
             split_import::split_import,
+            term_search::term_search,
             toggle_ignore::toggle_ignore,
             unmerge_match_arm::unmerge_match_arm,
             unmerge_use::unmerge_use,
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 8ad735d0ae8..268ba3225b6 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
@@ -1665,7 +1665,7 @@ macro_rules! const_maker {
     };
 }
 
-trait ${0:TraitName}<const N: usize> {
+trait ${0:NewTrait}<const N: usize> {
     // Used as an associated constant.
     const CONST_ASSOC: usize = N * 4;
 
@@ -1674,7 +1674,7 @@ trait ${0:TraitName}<const N: usize> {
     const_maker! {i32, 7}
 }
 
-impl<const N: usize> ${0:TraitName}<N> for Foo<N> {
+impl<const N: usize> ${0:NewTrait}<N> for Foo<N> {
     // Used as an associated constant.
     const CONST_ASSOC: usize = N * 4;
 
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 ba3c0cf3fd6..1ea7220960d 100644
--- a/src/tools/rust-analyzer/crates/ide-completion/src/completions.rs
+++ b/src/tools/rust-analyzer/crates/ide-completion/src/completions.rs
@@ -40,7 +40,8 @@ use crate::{
         literal::{render_struct_literal, render_variant_lit},
         macro_::render_macro,
         pattern::{render_struct_pat, render_variant_pat},
-        render_field, render_path_resolution, render_pattern_resolution, render_tuple_field,
+        render_expr, render_field, render_path_resolution, render_pattern_resolution,
+        render_tuple_field,
         type_alias::{render_type_alias, render_type_alias_with_eq},
         union_literal::render_union_literal,
         RenderContext,
@@ -157,6 +158,12 @@ impl Completions {
         item.add_to(self, ctx.db);
     }
 
+    pub(crate) fn add_expr(&mut self, ctx: &CompletionContext<'_>, expr: &hir::term_search::Expr) {
+        if let Some(item) = render_expr(ctx, expr) {
+            item.add_to(self, ctx.db)
+        }
+    }
+
     pub(crate) fn add_crate_roots(
         &mut self,
         ctx: &CompletionContext<'_>,
@@ -694,6 +701,7 @@ pub(super) fn complete_name_ref(
             match &path_ctx.kind {
                 PathKind::Expr { expr_ctx } => {
                     expr::complete_expr_path(acc, ctx, path_ctx, expr_ctx);
+                    expr::complete_expr(acc, ctx);
 
                     dot::complete_undotted_self(acc, ctx, path_ctx, expr_ctx);
                     item_list::complete_item_list_in_expr(acc, ctx, path_ctx, expr_ctx);
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 77fd5dd98b8..802e9bc3a80 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
@@ -328,3 +328,59 @@ pub(crate) fn complete_expr_path(
         }
     }
 }
+
+pub(crate) fn complete_expr(acc: &mut Completions, ctx: &CompletionContext<'_>) {
+    let _p = tracing::span!(tracing::Level::INFO, "complete_expr").entered();
+
+    if !ctx.config.enable_term_search {
+        return;
+    }
+
+    if !ctx.qualifier_ctx.none() {
+        return;
+    }
+
+    if let Some(ty) = &ctx.expected_type {
+        // Ignore unit types as they are not very interesting
+        if ty.is_unit() || ty.is_unknown() {
+            return;
+        }
+
+        let term_search_ctx = hir::term_search::TermSearchCtx {
+            sema: &ctx.sema,
+            scope: &ctx.scope,
+            goal: ty.clone(),
+            config: hir::term_search::TermSearchConfig {
+                enable_borrowcheck: false,
+                many_alternatives_threshold: 1,
+                depth: 6,
+            },
+        };
+        let exprs = hir::term_search::term_search(&term_search_ctx);
+        for expr in exprs {
+            // Expand method calls
+            match expr {
+                hir::term_search::Expr::Method { func, generics, target, params }
+                    if target.is_many() =>
+                {
+                    let target_ty = target.ty(ctx.db);
+                    let term_search_ctx =
+                        hir::term_search::TermSearchCtx { goal: target_ty, ..term_search_ctx };
+                    let target_exprs = hir::term_search::term_search(&term_search_ctx);
+
+                    for expr in target_exprs {
+                        let expanded_expr = hir::term_search::Expr::Method {
+                            func,
+                            generics: generics.clone(),
+                            target: Box::new(expr),
+                            params: params.clone(),
+                        };
+
+                        acc.add_expr(ctx, &expanded_expr)
+                    }
+                }
+                _ => acc.add_expr(ctx, &expr),
+            }
+        }
+    }
+}
diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/completions/flyimport.rs b/src/tools/rust-analyzer/crates/ide-completion/src/completions/flyimport.rs
index b9f91d34b2c..3bc329ecd74 100644
--- a/src/tools/rust-analyzer/crates/ide-completion/src/completions/flyimport.rs
+++ b/src/tools/rust-analyzer/crates/ide-completion/src/completions/flyimport.rs
@@ -238,6 +238,8 @@ fn import_on_the_fly(
             (PathKind::Type { location }, ItemInNs::Types(ty)) => {
                 if matches!(location, TypeLocation::TypeBound) {
                     matches!(ty, ModuleDef::Trait(_))
+                } else if matches!(location, TypeLocation::ImplTrait) {
+                    matches!(ty, ModuleDef::Trait(_) | ModuleDef::Module(_))
                 } else {
                     true
                 }
diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/completions/item_list/trait_impl.rs b/src/tools/rust-analyzer/crates/ide-completion/src/completions/item_list/trait_impl.rs
index 3c4b89ca742..7394d63be58 100644
--- a/src/tools/rust-analyzer/crates/ide-completion/src/completions/item_list/trait_impl.rs
+++ b/src/tools/rust-analyzer/crates/ide-completion/src/completions/item_list/trait_impl.rs
@@ -31,7 +31,7 @@
 //! }
 //! ```
 
-use hir::{self, HasAttrs};
+use hir::HasAttrs;
 use ide_db::{
     documentation::HasDocs, path_transform::PathTransform,
     syntax_helpers::insert_whitespace_into_node, traits::get_missing_assoc_items, SymbolKind,
diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/completions/type.rs b/src/tools/rust-analyzer/crates/ide-completion/src/completions/type.rs
index e6a4335c3fe..e4678089462 100644
--- a/src/tools/rust-analyzer/crates/ide-completion/src/completions/type.rs
+++ b/src/tools/rust-analyzer/crates/ide-completion/src/completions/type.rs
@@ -31,6 +31,11 @@ pub(crate) fn complete_type_path(
             ScopeDef::ImplSelfType(_) => location.complete_self_type(),
             // Don't suggest attribute macros and derives.
             ScopeDef::ModuleDef(Macro(mac)) => mac.is_fn_like(ctx.db),
+            ScopeDef::ModuleDef(Trait(_) | Module(_))
+                if matches!(location, TypeLocation::ImplTrait) =>
+            {
+                true
+            }
             // Type things are fine
             ScopeDef::ModuleDef(
                 BuiltinType(_) | Adt(_) | Module(_) | Trait(_) | TraitAlias(_) | TypeAlias(_),
@@ -184,6 +189,21 @@ pub(crate) fn complete_type_path(
                         }
                     }
                 }
+                TypeLocation::ImplTrait => {
+                    acc.add_nameref_keywords_with_colon(ctx);
+                    ctx.process_all_names(&mut |name, def, doc_aliases| {
+                        let is_trait_or_module = matches!(
+                            def,
+                            ScopeDef::ModuleDef(
+                                hir::ModuleDef::Module(_) | hir::ModuleDef::Trait(_)
+                            )
+                        );
+                        if is_trait_or_module {
+                            acc.add_path_resolution(ctx, path_ctx, name, def, doc_aliases);
+                        }
+                    });
+                    return;
+                }
                 _ => {}
             };
 
diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/config.rs b/src/tools/rust-analyzer/crates/ide-completion/src/config.rs
index ed5ddde8fbf..04563fb0f46 100644
--- a/src/tools/rust-analyzer/crates/ide-completion/src/config.rs
+++ b/src/tools/rust-analyzer/crates/ide-completion/src/config.rs
@@ -14,6 +14,7 @@ pub struct CompletionConfig {
     pub enable_imports_on_the_fly: bool,
     pub enable_self_on_the_fly: bool,
     pub enable_private_editable: bool,
+    pub enable_term_search: bool,
     pub full_function_signatures: bool,
     pub callable: Option<CallableSnippets>,
     pub snippet_cap: Option<SnippetCap>,
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 2a0004f60b8..aa22155feff 100644
--- a/src/tools/rust-analyzer/crates/ide-completion/src/context.rs
+++ b/src/tools/rust-analyzer/crates/ide-completion/src/context.rs
@@ -202,6 +202,7 @@ impl TypeLocation {
             }
             TypeLocation::AssocConstEq => false,
             TypeLocation::AssocTypeEq => true,
+            TypeLocation::ImplTrait => false,
             _ => true,
         }
     }
@@ -716,7 +717,7 @@ impl<'a> CompletionContext<'a> {
         let krate = scope.krate();
         let module = scope.module();
 
-        let toolchain = db.crate_graph()[krate.into()].channel();
+        let toolchain = db.toolchain_channel(krate.into());
         // `toolchain == None` means we're in some detached files. Since we have no information on
         // the toolchain being used, let's just allow unstable items to be listed.
         let is_nightly = matches!(toolchain, Some(base_db::ReleaseChannel::Nightly) | None);
diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/item.rs b/src/tools/rust-analyzer/crates/ide-completion/src/item.rs
index 8552a20392a..c2c0641961a 100644
--- a/src/tools/rust-analyzer/crates/ide-completion/src/item.rs
+++ b/src/tools/rust-analyzer/crates/ide-completion/src/item.rs
@@ -166,6 +166,8 @@ pub struct CompletionRelevance {
     pub postfix_match: Option<CompletionRelevancePostfixMatch>,
     /// This is set for type inference results
     pub is_definite: bool,
+    /// This is set for items that are function (associated or method)
+    pub function: Option<CompletionRelevanceFn>,
 }
 
 #[derive(Debug, Clone, Copy, Eq, PartialEq)]
@@ -207,6 +209,24 @@ pub enum CompletionRelevancePostfixMatch {
     Exact,
 }
 
+#[derive(Debug, Clone, Copy, Eq, PartialEq)]
+pub struct CompletionRelevanceFn {
+    pub has_params: bool,
+    pub has_self_param: bool,
+    pub return_type: CompletionRelevanceReturnType,
+}
+
+#[derive(Debug, Clone, Copy, Eq, PartialEq)]
+pub enum CompletionRelevanceReturnType {
+    Other,
+    /// Returns the Self type of the impl/trait
+    DirectConstructor,
+    /// Returns something that indirectly constructs the `Self` type of the impl/trait e.g. `Result<Self, ()>`, `Option<Self>`
+    Constructor,
+    /// Returns a possible builder for the type
+    Builder,
+}
+
 impl CompletionRelevance {
     /// Provides a relevance score. Higher values are more relevant.
     ///
@@ -231,6 +251,7 @@ impl CompletionRelevance {
             postfix_match,
             is_definite,
             is_item_from_notable_trait,
+            function,
         } = self;
 
         // lower rank private things
@@ -275,6 +296,33 @@ impl CompletionRelevance {
         if is_definite {
             score += 10;
         }
+
+        score += function
+            .map(|asf| {
+                let mut fn_score = match asf.return_type {
+                    CompletionRelevanceReturnType::DirectConstructor => 15,
+                    CompletionRelevanceReturnType::Builder => 10,
+                    CompletionRelevanceReturnType::Constructor => 5,
+                    CompletionRelevanceReturnType::Other => 0,
+                };
+
+                // When a fn is bumped due to return type:
+                // Bump Constructor or Builder methods with no arguments,
+                // over them tha with self arguments
+                if fn_score > 0 {
+                    if !asf.has_params {
+                        // bump associated functions
+                        fn_score += 1;
+                    } else if asf.has_self_param {
+                        // downgrade methods (below Constructor)
+                        fn_score = 1;
+                    }
+                }
+
+                fn_score
+            })
+            .unwrap_or_default();
+
         score
     }
 
@@ -297,6 +345,7 @@ pub enum CompletionItemKind {
     Method,
     Snippet,
     UnresolvedReference,
+    Expression,
 }
 
 impl_from!(SymbolKind for CompletionItemKind);
@@ -341,6 +390,7 @@ impl CompletionItemKind {
             CompletionItemKind::Method => "me",
             CompletionItemKind::Snippet => "sn",
             CompletionItemKind::UnresolvedReference => "??",
+            CompletionItemKind::Expression => "ex",
         }
     }
 }
diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/render.rs b/src/tools/rust-analyzer/crates/ide-completion/src/render.rs
index 2ed080a8347..3f374b307fb 100644
--- a/src/tools/rust-analyzer/crates/ide-completion/src/render.rs
+++ b/src/tools/rust-analyzer/crates/ide-completion/src/render.rs
@@ -17,7 +17,7 @@ use ide_db::{
     imports::import_assets::LocatedImport,
     RootDatabase, SnippetCap, SymbolKind,
 };
-use syntax::{format_smolstr, AstNode, SmolStr, SyntaxKind, TextRange};
+use syntax::{ast, format_smolstr, AstNode, SmolStr, SyntaxKind, TextRange};
 use text_edit::TextEdit;
 
 use crate::{
@@ -272,6 +272,82 @@ pub(crate) fn render_resolution_with_import_pat(
     Some(render_resolution_pat(ctx, pattern_ctx, local_name, Some(import_edit), resolution))
 }
 
+pub(crate) fn render_expr(
+    ctx: &CompletionContext<'_>,
+    expr: &hir::term_search::Expr,
+) -> Option<Builder> {
+    let mut i = 1;
+    let mut snippet_formatter = |ty: &hir::Type| {
+        let arg_name = ty
+            .as_adt()
+            .and_then(|adt| adt.name(ctx.db).as_text())
+            .map(|s| stdx::to_lower_snake_case(s.as_str()))
+            .unwrap_or_else(|| String::from("_"));
+        let res = format!("${{{i}:{arg_name}}}");
+        i += 1;
+        res
+    };
+
+    let mut label_formatter = |ty: &hir::Type| {
+        ty.as_adt()
+            .and_then(|adt| adt.name(ctx.db).as_text())
+            .map(|s| stdx::to_lower_snake_case(s.as_str()))
+            .unwrap_or_else(|| String::from("..."))
+    };
+
+    let label = expr
+        .gen_source_code(
+            &ctx.scope,
+            &mut label_formatter,
+            ctx.config.prefer_no_std,
+            ctx.config.prefer_prelude,
+        )
+        .ok()?;
+
+    let source_range = match ctx.original_token.parent() {
+        Some(node) => match node.ancestors().find_map(ast::Path::cast) {
+            Some(path) => path.syntax().text_range(),
+            None => node.text_range(),
+        },
+        None => ctx.source_range(),
+    };
+
+    let mut item = CompletionItem::new(CompletionItemKind::Expression, source_range, label.clone());
+
+    let snippet = format!(
+        "{}$0",
+        expr.gen_source_code(
+            &ctx.scope,
+            &mut snippet_formatter,
+            ctx.config.prefer_no_std,
+            ctx.config.prefer_prelude
+        )
+        .ok()?
+    );
+    let edit = TextEdit::replace(source_range, snippet);
+    item.snippet_edit(ctx.config.snippet_cap?, edit);
+    item.documentation(Documentation::new(String::from("Autogenerated expression by term search")));
+    item.set_relevance(crate::CompletionRelevance {
+        type_match: compute_type_match(ctx, &expr.ty(ctx.db)),
+        ..Default::default()
+    });
+    for trait_ in expr.traits_used(ctx.db) {
+        let trait_item = hir::ItemInNs::from(hir::ModuleDef::from(trait_));
+        let Some(path) = ctx.module.find_use_path(
+            ctx.db,
+            trait_item,
+            ctx.config.prefer_no_std,
+            ctx.config.prefer_prelude,
+        ) else {
+            continue;
+        };
+
+        item.add_import(LocatedImport::new(path, trait_item, trait_item));
+    }
+
+    Some(item)
+}
+
 fn scope_def_to_name(
     resolution: ScopeDef,
     ctx: &RenderContext<'_>,
@@ -600,6 +676,16 @@ mod tests {
     }
 
     #[track_caller]
+    fn check_function_relevance(ra_fixture: &str, expect: Expect) {
+        let actual: Vec<_> = do_completion(ra_fixture, CompletionItemKind::Method)
+            .into_iter()
+            .map(|item| (item.detail.unwrap_or_default(), item.relevance.function))
+            .collect();
+
+        expect.assert_debug_eq(&actual);
+    }
+
+    #[track_caller]
     fn check_relevance_for_kinds(ra_fixture: &str, kinds: &[CompletionItemKind], expect: Expect) {
         let mut actual = get_all_items(TEST_CONFIG, ra_fixture, None);
         actual.retain(|it| kinds.contains(&it.kind));
@@ -961,6 +1047,7 @@ fn func(input: Struct) { }
                 st Self [type]
                 sp Self [type]
                 st Struct [type]
+                ex Struct [type]
                 lc self [local]
                 fn func(…) []
                 me self.test() []
@@ -985,6 +1072,9 @@ fn main() {
 "#,
             expect![[r#"
                 lc input [type+name+local]
+                ex input [type]
+                ex true [type]
+                ex false [type]
                 lc inputbad [local]
                 fn main() []
                 fn test(…) []
@@ -1174,6 +1264,7 @@ fn main() { let _: m::Spam = S$0 }
                             is_private_editable: false,
                             postfix_match: None,
                             is_definite: false,
+                            function: None,
                         },
                         trigger_call_info: true,
                     },
@@ -1201,6 +1292,7 @@ fn main() { let _: m::Spam = S$0 }
                             is_private_editable: false,
                             postfix_match: None,
                             is_definite: false,
+                            function: None,
                         },
                         trigger_call_info: true,
                     },
@@ -1280,6 +1372,7 @@ fn foo() { A { the$0 } }
                             is_private_editable: false,
                             postfix_match: None,
                             is_definite: false,
+                            function: None,
                         },
                     },
                 ]
@@ -1313,6 +1406,26 @@ impl S {
                         documentation: Documentation(
                             "Method docs",
                         ),
+                        relevance: CompletionRelevance {
+                            exact_name_match: false,
+                            type_match: None,
+                            is_local: false,
+                            is_item_from_trait: false,
+                            is_item_from_notable_trait: false,
+                            is_name_already_imported: false,
+                            requires_import: false,
+                            is_op_method: false,
+                            is_private_editable: false,
+                            postfix_match: None,
+                            is_definite: false,
+                            function: Some(
+                                CompletionRelevanceFn {
+                                    has_params: true,
+                                    has_self_param: true,
+                                    return_type: Other,
+                                },
+                            ),
+                        },
                     },
                     CompletionItem {
                         label: "foo",
@@ -1418,6 +1531,26 @@ fn foo(s: S) { s.$0 }
                         kind: Method,
                         lookup: "the_method",
                         detail: "fn(&self)",
+                        relevance: CompletionRelevance {
+                            exact_name_match: false,
+                            type_match: None,
+                            is_local: false,
+                            is_item_from_trait: false,
+                            is_item_from_notable_trait: false,
+                            is_name_already_imported: false,
+                            requires_import: false,
+                            is_op_method: false,
+                            is_private_editable: false,
+                            postfix_match: None,
+                            is_definite: false,
+                            function: Some(
+                                CompletionRelevanceFn {
+                                    has_params: true,
+                                    has_self_param: true,
+                                    return_type: Other,
+                                },
+                            ),
+                        },
                     },
                 ]
             "#]],
@@ -1665,6 +1798,10 @@ fn f() { A { bar: b$0 }; }
             expect![[r#"
                 fn bar() [type+name]
                 fn baz() [type]
+                ex baz() [type]
+                ex bar() [type]
+                ex A { bar: baz() }.bar [type]
+                ex A { bar: bar() }.bar [type]
                 st A []
                 fn f() []
             "#]],
@@ -1749,6 +1886,8 @@ fn main() {
                 lc s [type+name+local]
                 st S [type]
                 st S [type]
+                ex s [type]
+                ex S [type]
                 fn foo(…) []
                 fn main() []
             "#]],
@@ -1766,6 +1905,8 @@ fn main() {
                 lc ssss [type+local]
                 st S [type]
                 st S [type]
+                ex ssss [type]
+                ex S [type]
                 fn foo(…) []
                 fn main() []
             "#]],
@@ -1798,6 +1939,8 @@ fn main() {
 }
             "#,
             expect![[r#"
+                ex core::ops::Deref::deref(&T(S)) (use core::ops::Deref) [type_could_unify]
+                ex core::ops::Deref::deref(&t) (use core::ops::Deref) [type_could_unify]
                 lc m [local]
                 lc t [local]
                 lc &t [type+local]
@@ -1846,6 +1989,8 @@ fn main() {
 }
             "#,
             expect![[r#"
+                ex core::ops::DerefMut::deref_mut(&mut T(S)) (use core::ops::DerefMut) [type_could_unify]
+                ex core::ops::DerefMut::deref_mut(&mut t) (use core::ops::DerefMut) [type_could_unify]
                 lc m [local]
                 lc t [local]
                 lc &mut t [type+local]
@@ -1894,6 +2039,8 @@ fn bar(t: Foo) {}
                 ev Foo::A [type]
                 ev Foo::B [type]
                 en Foo [type]
+                ex Foo::A [type]
+                ex Foo::B [type]
                 fn bar(…) []
                 fn foo() []
             "#]],
@@ -1947,6 +2094,8 @@ fn main() {
 }
 "#,
             expect![[r#"
+                ex core::ops::Deref::deref(&T(S)) (use core::ops::Deref) [type_could_unify]
+                ex core::ops::Deref::deref(&bar()) (use core::ops::Deref) [type_could_unify]
                 st S []
                 st &S [type]
                 st S []
@@ -2003,6 +2152,254 @@ fn main() {
     }
 
     #[test]
+    fn constructor_order_simple() {
+        check_relevance(
+            r#"
+struct Foo;
+struct Other;
+struct Option<T>(T);
+
+impl Foo {
+    fn fn_ctr() -> Foo { unimplemented!() }
+    fn fn_another(n: u32) -> Other { unimplemented!() }
+    fn fn_ctr_self() -> Option<Self> { unimplemented!() }
+}
+
+fn test() {
+    let a = Foo::$0;
+}
+"#,
+            expect![[r#"
+                fn fn_ctr() [type_could_unify]
+                fn fn_ctr_self() [type_could_unify]
+                fn fn_another(…) [type_could_unify]
+            "#]],
+        );
+    }
+
+    #[test]
+    fn constructor_order_kind() {
+        check_function_relevance(
+            r#"
+struct Foo;
+struct Bar;
+struct Option<T>(T);
+enum Result<T, E> { Ok(T), Err(E) };
+
+impl Foo {
+    fn fn_ctr(&self) -> Foo { unimplemented!() }
+    fn fn_ctr_with_args(&self, n: u32) -> Foo { unimplemented!() }
+    fn fn_another(&self, n: u32) -> Bar { unimplemented!() }
+    fn fn_ctr_wrapped(&self, ) -> Option<Self> { unimplemented!() }
+    fn fn_ctr_wrapped_2(&self, ) -> Result<Self, Bar> { unimplemented!() }
+    fn fn_ctr_wrapped_3(&self, ) -> Result<Bar, Self> { unimplemented!() } // Self is not the first type
+    fn fn_ctr_wrapped_with_args(&self, m: u32) -> Option<Self> { unimplemented!() }
+    fn fn_another_unit(&self) { unimplemented!() }
+}
+
+fn test() {
+    let a = self::Foo::$0;
+}
+"#,
+            expect![[r#"
+                [
+                    (
+                        "fn(&self, u32) -> Bar",
+                        Some(
+                            CompletionRelevanceFn {
+                                has_params: true,
+                                has_self_param: true,
+                                return_type: Other,
+                            },
+                        ),
+                    ),
+                    (
+                        "fn(&self)",
+                        Some(
+                            CompletionRelevanceFn {
+                                has_params: true,
+                                has_self_param: true,
+                                return_type: Other,
+                            },
+                        ),
+                    ),
+                    (
+                        "fn(&self) -> Foo",
+                        Some(
+                            CompletionRelevanceFn {
+                                has_params: true,
+                                has_self_param: true,
+                                return_type: DirectConstructor,
+                            },
+                        ),
+                    ),
+                    (
+                        "fn(&self, u32) -> Foo",
+                        Some(
+                            CompletionRelevanceFn {
+                                has_params: true,
+                                has_self_param: true,
+                                return_type: DirectConstructor,
+                            },
+                        ),
+                    ),
+                    (
+                        "fn(&self) -> Option<Foo>",
+                        Some(
+                            CompletionRelevanceFn {
+                                has_params: true,
+                                has_self_param: true,
+                                return_type: Constructor,
+                            },
+                        ),
+                    ),
+                    (
+                        "fn(&self) -> Result<Foo, Bar>",
+                        Some(
+                            CompletionRelevanceFn {
+                                has_params: true,
+                                has_self_param: true,
+                                return_type: Constructor,
+                            },
+                        ),
+                    ),
+                    (
+                        "fn(&self) -> Result<Bar, Foo>",
+                        Some(
+                            CompletionRelevanceFn {
+                                has_params: true,
+                                has_self_param: true,
+                                return_type: Constructor,
+                            },
+                        ),
+                    ),
+                    (
+                        "fn(&self, u32) -> Option<Foo>",
+                        Some(
+                            CompletionRelevanceFn {
+                                has_params: true,
+                                has_self_param: true,
+                                return_type: Constructor,
+                            },
+                        ),
+                    ),
+                ]
+            "#]],
+        );
+    }
+
+    #[test]
+    fn constructor_order_relevance() {
+        check_relevance(
+            r#"
+struct Foo;
+struct FooBuilder;
+struct Result<T>(T);
+
+impl Foo {
+    fn fn_no_ret(&self) {}
+    fn fn_ctr_with_args(input: u32) -> Foo { unimplemented!() }
+    fn fn_direct_ctr() -> Self { unimplemented!() }
+    fn fn_ctr() -> Result<Self> { unimplemented!() }
+    fn fn_other() -> Result<u32> { unimplemented!() }
+    fn fn_builder() -> FooBuilder { unimplemented!() }
+}
+
+fn test() {
+    let a = self::Foo::$0;
+}
+"#,
+            // preference:
+            // Direct Constructor
+            // Direct Constructor with args
+            // Builder
+            // Constructor
+            // Others
+            expect![[r#"
+                fn fn_direct_ctr() [type_could_unify]
+                fn fn_ctr_with_args(…) [type_could_unify]
+                fn fn_builder() [type_could_unify]
+                fn fn_ctr() [type_could_unify]
+                me fn_no_ret(…) [type_could_unify]
+                fn fn_other() [type_could_unify]
+            "#]],
+        );
+
+        //
+    }
+
+    #[test]
+    fn function_relevance_generic_1() {
+        check_relevance(
+            r#"
+struct Foo<T: Default>(T);
+struct FooBuilder;
+struct Option<T>(T);
+enum Result<T, E>{Ok(T), Err(E)};
+
+impl<T: Default> Foo<T> {
+    fn fn_returns_unit(&self) {}
+    fn fn_ctr_with_args(input: T) -> Foo<T> { unimplemented!() }
+    fn fn_direct_ctr() -> Self { unimplemented!() }
+    fn fn_ctr_wrapped() -> Option<Self> { unimplemented!() }
+    fn fn_ctr_wrapped_2() -> Result<Self, u32> { unimplemented!() }
+    fn fn_other() -> Option<u32> { unimplemented!() }
+    fn fn_builder() -> FooBuilder { unimplemented!() }
+}
+
+fn test() {
+    let a = self::Foo::<u32>::$0;
+}
+                "#,
+            expect![[r#"
+                        fn fn_direct_ctr() [type_could_unify]
+                        fn fn_ctr_with_args(…) [type_could_unify]
+                        fn fn_builder() [type_could_unify]
+                        fn fn_ctr_wrapped() [type_could_unify]
+                        fn fn_ctr_wrapped_2() [type_could_unify]
+                        me fn_returns_unit(…) [type_could_unify]
+                        fn fn_other() [type_could_unify]
+                    "#]],
+        );
+    }
+
+    #[test]
+    fn function_relevance_generic_2() {
+        // Generic 2
+        check_relevance(
+            r#"
+struct Foo<T: Default>(T);
+struct FooBuilder;
+struct Option<T>(T);
+enum Result<T, E>{Ok(T), Err(E)};
+
+impl<T: Default> Foo<T> {
+    fn fn_no_ret(&self) {}
+    fn fn_ctr_with_args(input: T) -> Foo<T> { unimplemented!() }
+    fn fn_direct_ctr() -> Self { unimplemented!() }
+    fn fn_ctr() -> Option<Self> { unimplemented!() }
+    fn fn_ctr2() -> Result<Self, u32> { unimplemented!() }
+    fn fn_other() -> Option<u32> { unimplemented!() }
+    fn fn_builder() -> FooBuilder { unimplemented!() }
+}
+
+fn test() {
+    let a : Res<Foo<u32>> = Foo::$0;
+}
+                "#,
+            expect![[r#"
+                fn fn_direct_ctr() [type_could_unify]
+                fn fn_ctr_with_args(…) [type_could_unify]
+                fn fn_builder() [type_could_unify]
+                fn fn_ctr() [type_could_unify]
+                fn fn_ctr2() [type_could_unify]
+                me fn_no_ret(…) [type_could_unify]
+                fn fn_other() [type_could_unify]
+            "#]],
+        );
+    }
+
+    #[test]
     fn struct_field_method_ref() {
         check_kinds(
             r#"
@@ -2022,6 +2419,26 @@ fn foo(f: Foo) { let _: &u32 = f.b$0 }
                         kind: Method,
                         lookup: "baz",
                         detail: "fn(&self) -> u32",
+                        relevance: CompletionRelevance {
+                            exact_name_match: false,
+                            type_match: None,
+                            is_local: false,
+                            is_item_from_trait: false,
+                            is_item_from_notable_trait: false,
+                            is_name_already_imported: false,
+                            requires_import: false,
+                            is_op_method: false,
+                            is_private_editable: false,
+                            postfix_match: None,
+                            is_definite: false,
+                            function: Some(
+                                CompletionRelevanceFn {
+                                    has_params: true,
+                                    has_self_param: true,
+                                    return_type: Other,
+                                },
+                            ),
+                        },
                         ref_match: "&@107",
                     },
                     CompletionItem {
@@ -2096,6 +2513,7 @@ fn foo() {
                             is_private_editable: false,
                             postfix_match: None,
                             is_definite: false,
+                            function: None,
                         },
                     },
                 ]
@@ -2133,6 +2551,26 @@ fn main() {
                         ),
                         lookup: "foo",
                         detail: "fn() -> S",
+                        relevance: CompletionRelevance {
+                            exact_name_match: false,
+                            type_match: None,
+                            is_local: false,
+                            is_item_from_trait: false,
+                            is_item_from_notable_trait: false,
+                            is_name_already_imported: false,
+                            requires_import: false,
+                            is_op_method: false,
+                            is_private_editable: false,
+                            postfix_match: None,
+                            is_definite: false,
+                            function: Some(
+                                CompletionRelevanceFn {
+                                    has_params: false,
+                                    has_self_param: false,
+                                    return_type: Other,
+                                },
+                            ),
+                        },
                         ref_match: "&@92",
                     },
                 ]
@@ -2160,6 +2598,7 @@ fn foo() {
 "#,
             expect![[r#"
                 lc foo [type+local]
+                ex foo [type]
                 ev Foo::A(…) [type_could_unify]
                 ev Foo::B [type_could_unify]
                 en Foo [type_could_unify]
@@ -2493,6 +2932,7 @@ fn main() {
                             is_private_editable: false,
                             postfix_match: None,
                             is_definite: false,
+                            function: None,
                         },
                     },
                     CompletionItem {
@@ -2515,6 +2955,7 @@ fn main() {
                             is_private_editable: false,
                             postfix_match: None,
                             is_definite: false,
+                            function: None,
                         },
                     },
                 ]
diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/render/function.rs b/src/tools/rust-analyzer/crates/ide-completion/src/render/function.rs
index 27186a2b7ff..cf9fe1ab307 100644
--- a/src/tools/rust-analyzer/crates/ide-completion/src/render/function.rs
+++ b/src/tools/rust-analyzer/crates/ide-completion/src/render/function.rs
@@ -8,8 +8,13 @@ use syntax::{format_smolstr, AstNode, SmolStr};
 
 use crate::{
     context::{CompletionContext, DotAccess, DotAccessKind, PathCompletionCtx, PathKind},
-    item::{Builder, CompletionItem, CompletionItemKind, CompletionRelevance},
-    render::{compute_exact_name_match, compute_ref_match, compute_type_match, RenderContext},
+    item::{
+        Builder, CompletionItem, CompletionItemKind, CompletionRelevance, CompletionRelevanceFn,
+        CompletionRelevanceReturnType,
+    },
+    render::{
+        compute_exact_name_match, compute_ref_match, compute_type_match, match_types, RenderContext,
+    },
     CallableSnippets,
 };
 
@@ -61,9 +66,9 @@ fn render(
         ),
         _ => (name.unescaped().to_smol_str(), name.to_smol_str()),
     };
-
+    let has_self_param = func.self_param(db).is_some();
     let mut item = CompletionItem::new(
-        if func.self_param(db).is_some() {
+        if has_self_param {
             CompletionItemKind::Method
         } else {
             CompletionItemKind::SymbolKind(SymbolKind::Function)
@@ -99,6 +104,15 @@ fn render(
         .filter(|_| !has_call_parens)
         .and_then(|cap| Some((cap, params(ctx.completion, func, &func_kind, has_dot_receiver)?)));
 
+    let function = assoc_item
+        .and_then(|assoc_item| assoc_item.implementing_ty(db))
+        .map(|self_type| compute_return_type_match(db, &ctx, self_type, &ret_type))
+        .map(|return_type| CompletionRelevanceFn {
+            has_params: has_self_param || func.num_params(db) > 0,
+            has_self_param,
+            return_type,
+        });
+
     item.set_relevance(CompletionRelevance {
         type_match: if has_call_parens || complete_call_parens.is_some() {
             compute_type_match(completion, &ret_type)
@@ -106,6 +120,7 @@ fn render(
             compute_type_match(completion, &func.ty(db))
         },
         exact_name_match: compute_exact_name_match(completion, &call),
+        function,
         is_op_method,
         is_item_from_notable_trait,
         ..ctx.completion_relevance()
@@ -156,6 +171,33 @@ fn render(
     item
 }
 
+fn compute_return_type_match(
+    db: &dyn HirDatabase,
+    ctx: &RenderContext<'_>,
+    self_type: hir::Type,
+    ret_type: &hir::Type,
+) -> CompletionRelevanceReturnType {
+    if match_types(ctx.completion, &self_type, ret_type).is_some() {
+        // fn([..]) -> Self
+        CompletionRelevanceReturnType::DirectConstructor
+    } else if ret_type
+        .type_arguments()
+        .any(|ret_type_arg| match_types(ctx.completion, &self_type, &ret_type_arg).is_some())
+    {
+        // fn([..]) -> Result<Self, E> OR Wrapped<Foo, Self>
+        CompletionRelevanceReturnType::Constructor
+    } else if ret_type
+        .as_adt()
+        .and_then(|adt| adt.name(db).as_str().map(|name| name.ends_with("Builder")))
+        .unwrap_or(false)
+    {
+        // fn([..]) -> [..]Builder
+        CompletionRelevanceReturnType::Builder
+    } else {
+        CompletionRelevanceReturnType::Other
+    }
+}
+
 pub(super) fn add_call_parens<'b>(
     builder: &'b mut Builder,
     ctx: &CompletionContext<'_>,
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 154b69875ae..1f032c7df48 100644
--- a/src/tools/rust-analyzer/crates/ide-completion/src/tests.rs
+++ b/src/tools/rust-analyzer/crates/ide-completion/src/tests.rs
@@ -65,6 +65,7 @@ pub(crate) const TEST_CONFIG: CompletionConfig = CompletionConfig {
     enable_imports_on_the_fly: true,
     enable_self_on_the_fly: true,
     enable_private_editable: false,
+    enable_term_search: true,
     full_function_signatures: false,
     callable: Some(CallableSnippets::FillArguments),
     snippet_cap: SnippetCap::new(true),
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 78907a2896c..7749fac40b9 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
@@ -97,6 +97,11 @@ fn func(param0 @ (param1, param2): (i32, i32)) {
             kw unsafe
             kw while
             kw while let
+            ex ifletlocal
+            ex letlocal
+            ex matcharm
+            ex param1
+            ex param2
         "#]],
     );
 }
@@ -241,6 +246,8 @@ fn complete_in_block() {
             sn macro_rules
             sn pd
             sn ppd
+            ex false
+            ex true
         "#]],
     )
 }
@@ -542,7 +549,26 @@ fn quux(x: i32) {
     m!(x$0
 }
 "#,
-        expect![[r#""#]],
+        expect![[r#"
+            fn quux(…)   fn(i32)
+            lc x         i32
+            lc y         i32
+            ma m!(…)     macro_rules! m
+            bt u32       u32
+            kw crate::
+            kw false
+            kw for
+            kw if
+            kw if let
+            kw loop
+            kw match
+            kw return
+            kw self::
+            kw true
+            kw unsafe
+            kw while
+            kw while let
+        "#]],
     );
 }
 
@@ -682,7 +708,9 @@ fn main() {
 }
 "#,
         expect![[r#"
-            fn test() fn() -> Zulu
+            fn test()       fn() -> Zulu
+            ex Zulu
+            ex Zulu::test()
         "#]],
     );
 }
diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/tests/flyimport.rs b/src/tools/rust-analyzer/crates/ide-completion/src/tests/flyimport.rs
index eaa1bebc03c..fff193ba4c9 100644
--- a/src/tools/rust-analyzer/crates/ide-completion/src/tests/flyimport.rs
+++ b/src/tools/rust-analyzer/crates/ide-completion/src/tests/flyimport.rs
@@ -1397,3 +1397,22 @@ pub use bridge2::server2::Span2;
         "#]],
     );
 }
+
+#[test]
+fn flyimport_only_traits_in_impl_trait_block() {
+    check(
+        r#"
+//- /main.rs crate:main deps:dep
+pub struct Bar;
+
+impl Foo$0 for Bar { }
+//- /lib.rs crate:dep
+pub trait FooTrait;
+
+pub struct FooStruct;
+"#,
+        expect![[r#"
+            tt FooTrait (use dep::FooTrait)
+        "#]],
+    );
+}
diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/tests/record.rs b/src/tools/rust-analyzer/crates/ide-completion/src/tests/record.rs
index 18afde1b7ce..e64ec74c610 100644
--- a/src/tools/rust-analyzer/crates/ide-completion/src/tests/record.rs
+++ b/src/tools/rust-analyzer/crates/ide-completion/src/tests/record.rs
@@ -192,6 +192,8 @@ fn main() {
             bt u32                  u32
             kw crate::
             kw self::
+            ex Foo::default()
+            ex foo
         "#]],
     );
     check(
diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/tests/special.rs b/src/tools/rust-analyzer/crates/ide-completion/src/tests/special.rs
index a87d16c789f..ff32eccfbff 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
@@ -225,10 +225,10 @@ impl S {
 fn foo() { let _ = lib::S::$0 }
 "#,
         expect![[r#"
-                ct PUBLIC_CONST    pub const PUBLIC_CONST: u32
-                fn public_method() fn()
-                ta PublicType      pub type PublicType = u32
-            "#]],
+            ct PUBLIC_CONST    pub const PUBLIC_CONST: u32
+            fn public_method() fn()
+            ta PublicType      pub type PublicType = u32
+        "#]],
     );
 }
 
@@ -242,8 +242,8 @@ impl U { fn m() { } }
 fn foo() { let _ = U::$0 }
 "#,
         expect![[r#"
-                fn m() fn()
-            "#]],
+            fn m() fn()
+        "#]],
     );
 }
 
@@ -256,8 +256,8 @@ trait Trait { fn m(); }
 fn foo() { let _ = Trait::$0 }
 "#,
         expect![[r#"
-                fn m() (as Trait) fn()
-            "#]],
+            fn m() (as Trait) fn()
+        "#]],
     );
 }
 
@@ -273,8 +273,8 @@ impl Trait for S {}
 fn foo() { let _ = S::$0 }
 "#,
         expect![[r#"
-                fn m() (as Trait) fn()
-            "#]],
+            fn m() (as Trait) fn()
+        "#]],
     );
 }
 
@@ -290,8 +290,8 @@ impl Trait for S {}
 fn foo() { let _ = <S as Trait>::$0 }
 "#,
         expect![[r#"
-                fn m() (as Trait) fn()
-            "#]],
+            fn m() (as Trait) fn()
+        "#]],
     );
 }
 
@@ -396,9 +396,9 @@ macro_rules! foo { () => {} }
 fn main() { let _ = crate::$0 }
 "#,
         expect![[r#"
-                fn main()  fn()
-                ma foo!(…) macro_rules! foo
-            "#]],
+            fn main()  fn()
+            ma foo!(…) macro_rules! foo
+        "#]],
     );
 }
 
@@ -694,8 +694,10 @@ fn bar() -> Bar {
 }
 "#,
         expect![[r#"
-                fn foo() (as Foo) fn() -> Self
-            "#]],
+            fn foo() (as Foo) fn() -> Self
+            ex Bar
+            ex bar()
+        "#]],
     );
 }
 
@@ -722,6 +724,8 @@ fn bar() -> Bar {
         expect![[r#"
             fn bar()          fn()
             fn foo() (as Foo) fn() -> Self
+            ex Bar
+            ex bar()
         "#]],
     );
 }
@@ -748,6 +752,8 @@ fn bar() -> Bar {
 "#,
         expect![[r#"
             fn foo() (as Foo) fn() -> Self
+            ex Bar
+            ex bar()
         "#]],
     );
 }
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 c7161f82ce7..db4ac9381ce 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
@@ -989,3 +989,43 @@ fn foo<'a>() { S::<'static, F$0, _, _>; }
         "#]],
     );
 }
+
+#[test]
+fn complete_traits_on_impl_trait_block() {
+    check(
+        r#"
+trait Foo {}
+
+struct Bar;
+
+impl $0 for Bar { }
+"#,
+        expect![[r#"
+            md module
+            tt Foo
+            tt Trait
+            kw crate::
+            kw self::
+        "#]],
+    );
+}
+
+#[test]
+fn complete_traits_with_path_on_impl_trait_block() {
+    check(
+        r#"
+mod outer {
+    pub trait Foo {}
+    pub struct Bar;
+    pub mod inner {
+    }
+}
+
+impl outer::$0 for Bar { }
+"#,
+        expect![[r#"
+            md inner
+            tt Foo
+        "#]],
+    );
+}
diff --git a/src/tools/rust-analyzer/crates/ide-db/src/famous_defs.rs b/src/tools/rust-analyzer/crates/ide-db/src/famous_defs.rs
index 4edfa37b329..3106772e63b 100644
--- a/src/tools/rust-analyzer/crates/ide-db/src/famous_defs.rs
+++ b/src/tools/rust-analyzer/crates/ide-db/src/famous_defs.rs
@@ -114,6 +114,14 @@ impl FamousDefs<'_, '_> {
         self.find_function("core:mem:drop")
     }
 
+    pub fn core_macros_todo(&self) -> Option<Macro> {
+        self.find_macro("core:todo")
+    }
+
+    pub fn core_macros_unimplemented(&self) -> Option<Macro> {
+        self.find_macro("core:unimplemented")
+    }
+
     pub fn builtin_crates(&self) -> impl Iterator<Item = Crate> {
         IntoIterator::into_iter([
             self.std(),
diff --git a/src/tools/rust-analyzer/crates/ide-db/src/path_transform.rs b/src/tools/rust-analyzer/crates/ide-db/src/path_transform.rs
index 3862acc2af4..7e1811b4cac 100644
--- a/src/tools/rust-analyzer/crates/ide-db/src/path_transform.rs
+++ b/src/tools/rust-analyzer/crates/ide-db/src/path_transform.rs
@@ -148,7 +148,7 @@ impl<'a> PathTransform<'a> {
         let mut defaulted_params: Vec<DefaultedParam> = Default::default();
         self.generic_def
             .into_iter()
-            .flat_map(|it| it.type_params(db))
+            .flat_map(|it| it.type_or_const_params(db))
             .skip(skip)
             // The actual list of trait type parameters may be longer than the one
             // used in the `impl` block due to trailing default type parameters.
diff --git a/src/tools/rust-analyzer/crates/ide-db/src/rename.rs b/src/tools/rust-analyzer/crates/ide-db/src/rename.rs
index 032b8338ab8..6a7042988a9 100644
--- a/src/tools/rust-analyzer/crates/ide-db/src/rename.rs
+++ b/src/tools/rust-analyzer/crates/ide-db/src/rename.rs
@@ -71,7 +71,6 @@ impl Definition {
         &self,
         sema: &Semantics<'_, RootDatabase>,
         new_name: &str,
-        rename_external: bool,
     ) -> Result<SourceChange> {
         // self.krate() returns None if
         // self is a built-in attr, built-in type or tool module.
@@ -80,8 +79,8 @@ impl Definition {
         if let Some(krate) = self.krate(sema.db) {
             // Can we not rename non-local items?
             // Then bail if non-local
-            if !rename_external && !krate.origin(sema.db).is_local() {
-                bail!("Cannot rename a non-local definition as the config for it is disabled")
+            if !krate.origin(sema.db).is_local() {
+                bail!("Cannot rename a non-local definition")
             }
         }
 
diff --git a/src/tools/rust-analyzer/crates/ide-db/src/source_change.rs b/src/tools/rust-analyzer/crates/ide-db/src/source_change.rs
index 73be6a4071e..f59d8d08c89 100644
--- a/src/tools/rust-analyzer/crates/ide-db/src/source_change.rs
+++ b/src/tools/rust-analyzer/crates/ide-db/src/source_change.rs
@@ -138,7 +138,7 @@ impl SnippetEdit {
             .into_iter()
             .zip(1..)
             .with_position()
-            .map(|pos| {
+            .flat_map(|pos| {
                 let (snippet, index) = match pos {
                     (itertools::Position::First, it) | (itertools::Position::Middle, it) => it,
                     // last/only snippet gets index 0
@@ -146,11 +146,13 @@ impl SnippetEdit {
                     | (itertools::Position::Only, (snippet, _)) => (snippet, 0),
                 };
 
-                let range = match snippet {
-                    Snippet::Tabstop(pos) => TextRange::empty(pos),
-                    Snippet::Placeholder(range) => range,
-                };
-                (index, range)
+                match snippet {
+                    Snippet::Tabstop(pos) => vec![(index, TextRange::empty(pos))],
+                    Snippet::Placeholder(range) => vec![(index, range)],
+                    Snippet::PlaceholderGroup(ranges) => {
+                        ranges.into_iter().map(|range| (index, range)).collect()
+                    }
+                }
             })
             .collect_vec();
 
@@ -248,7 +250,7 @@ impl SourceChangeBuilder {
     fn commit(&mut self) {
         let snippet_edit = self.snippet_builder.take().map(|builder| {
             SnippetEdit::new(
-                builder.places.into_iter().map(PlaceSnippet::finalize_position).collect_vec(),
+                builder.places.into_iter().flat_map(PlaceSnippet::finalize_position).collect(),
             )
         });
 
@@ -287,30 +289,10 @@ impl SourceChangeBuilder {
     pub fn insert(&mut self, offset: TextSize, text: impl Into<String>) {
         self.edit.insert(offset, text.into())
     }
-    /// Append specified `snippet` at the given `offset`
-    pub fn insert_snippet(
-        &mut self,
-        _cap: SnippetCap,
-        offset: TextSize,
-        snippet: impl Into<String>,
-    ) {
-        self.source_change.is_snippet = true;
-        self.insert(offset, snippet);
-    }
     /// Replaces specified `range` of text with a given string.
     pub fn replace(&mut self, range: TextRange, replace_with: impl Into<String>) {
         self.edit.replace(range, replace_with.into())
     }
-    /// Replaces specified `range` of text with a given `snippet`.
-    pub fn replace_snippet(
-        &mut self,
-        _cap: SnippetCap,
-        range: TextRange,
-        snippet: impl Into<String>,
-    ) {
-        self.source_change.is_snippet = true;
-        self.replace(range, snippet);
-    }
     pub fn replace_ast<N: AstNode>(&mut self, old: N, new: N) {
         algo::diff(old.syntax(), new.syntax()).into_text_edit(&mut self.edit)
     }
@@ -356,6 +338,17 @@ impl SourceChangeBuilder {
         self.add_snippet(PlaceSnippet::Over(node.syntax().clone().into()))
     }
 
+    /// Adds a snippet to move the cursor selected over `nodes`
+    ///
+    /// This allows for renaming newly generated items without having to go
+    /// through a separate rename step.
+    pub fn add_placeholder_snippet_group(&mut self, _cap: SnippetCap, nodes: Vec<SyntaxNode>) {
+        assert!(nodes.iter().all(|node| node.parent().is_some()));
+        self.add_snippet(PlaceSnippet::OverGroup(
+            nodes.into_iter().map(|node| node.into()).collect(),
+        ))
+    }
+
     fn add_snippet(&mut self, snippet: PlaceSnippet) {
         let snippet_builder = self.snippet_builder.get_or_insert(SnippetBuilder { places: vec![] });
         snippet_builder.places.push(snippet);
@@ -400,6 +393,13 @@ pub enum Snippet {
     Tabstop(TextSize),
     /// A placeholder snippet (e.g. `${0:placeholder}`).
     Placeholder(TextRange),
+    /// A group of placeholder snippets, e.g.
+    ///
+    /// ```no_run
+    /// let ${0:new_var} = 4;
+    /// fun(1, 2, 3, ${0:new_var});
+    /// ```
+    PlaceholderGroup(Vec<TextRange>),
 }
 
 enum PlaceSnippet {
@@ -409,14 +409,20 @@ enum PlaceSnippet {
     After(SyntaxElement),
     /// Place a placeholder snippet in place of the element
     Over(SyntaxElement),
+    /// Place a group of placeholder snippets which are linked together
+    /// in place of the elements
+    OverGroup(Vec<SyntaxElement>),
 }
 
 impl PlaceSnippet {
-    fn finalize_position(self) -> Snippet {
+    fn finalize_position(self) -> Vec<Snippet> {
         match self {
-            PlaceSnippet::Before(it) => Snippet::Tabstop(it.text_range().start()),
-            PlaceSnippet::After(it) => Snippet::Tabstop(it.text_range().end()),
-            PlaceSnippet::Over(it) => Snippet::Placeholder(it.text_range()),
+            PlaceSnippet::Before(it) => vec![Snippet::Tabstop(it.text_range().start())],
+            PlaceSnippet::After(it) => vec![Snippet::Tabstop(it.text_range().end())],
+            PlaceSnippet::Over(it) => vec![Snippet::Placeholder(it.text_range())],
+            PlaceSnippet::OverGroup(it) => {
+                vec![Snippet::PlaceholderGroup(it.into_iter().map(|it| it.text_range()).collect())]
+            }
         }
     }
 }
diff --git a/src/tools/rust-analyzer/crates/ide-db/src/symbol_index.rs b/src/tools/rust-analyzer/crates/ide-db/src/symbol_index.rs
index 92c09089e1f..722161282fe 100644
--- a/src/tools/rust-analyzer/crates/ide-db/src/symbol_index.rs
+++ b/src/tools/rust-analyzer/crates/ide-db/src/symbol_index.rs
@@ -31,7 +31,7 @@ use base_db::{
     salsa::{self, ParallelDatabase},
     SourceDatabaseExt, SourceRootId, Upcast,
 };
-use fst::{self, raw::IndexedValue, Automaton, Streamer};
+use fst::{raw::IndexedValue, Automaton, Streamer};
 use hir::{
     db::HirDatabase,
     import_map::{AssocSearchMode, SearchMode},
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 e4e735cecd8..4f706e26af2 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
@@ -329,6 +329,7 @@ pub fn for_each_tail_expr(expr: &ast::Expr, cb: &mut dyn FnMut(&ast::Expr)) {
         | ast::Expr::RecordExpr(_)
         | ast::Expr::RefExpr(_)
         | ast::Expr::ReturnExpr(_)
+        | ast::Expr::BecomeExpr(_)
         | ast::Expr::TryExpr(_)
         | ast::Expr::TupleExpr(_)
         | ast::Expr::LetExpr(_)
diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/incorrect_case.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/incorrect_case.rs
index dd64b93e454..5e2541795ca 100644
--- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/incorrect_case.rs
+++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/incorrect_case.rs
@@ -43,7 +43,7 @@ fn fixes(ctx: &DiagnosticsContext<'_>, d: &hir::IncorrectCase) -> Option<Vec<Ass
     let label = format!("Rename to {}", d.suggested_text);
     let mut res = unresolved_fix("change_case", &label, frange.range);
     if ctx.resolve.should_resolve(&res.id) {
-        let source_change = def.rename(&ctx.sema, &d.suggested_text, true);
+        let source_change = def.rename(&ctx.sema, &d.suggested_text);
         res.source_change = Some(source_change.ok().unwrap_or_default());
     }
 
diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/macro_error.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/macro_error.rs
index e4cb53f3a2f..6a957ac1c97 100644
--- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/macro_error.rs
+++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/macro_error.rs
@@ -242,7 +242,7 @@ macro_rules! foo {
 
 fn f() {
     foo!();
-  //^^^ error: invalid macro definition: expected subtree
+  //^^^ error: macro definition has parse errors
 
 }
 "#,
diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/missing_match_arms.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/missing_match_arms.rs
index 17dc679e055..7632fdf1d09 100644
--- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/missing_match_arms.rs
+++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/missing_match_arms.rs
@@ -311,6 +311,24 @@ fn main() {
     }
 
     #[test]
+    fn mismatched_types_issue_15883() {
+        // Check we don't panic.
+        check_diagnostics_no_bails(
+            r#"
+//- minicore: option
+fn main() {
+    match Some((true, false)) {
+        Some(true) | Some(false) => {}
+        //   ^^^^ error: expected (bool, bool), found bool
+        //                ^^^^^ error: expected (bool, bool), found bool
+        None => {}
+    }
+}
+            "#,
+        );
+    }
+
+    #[test]
     fn mismatched_types_in_or_patterns() {
         cov_mark::check_count!(validate_match_bailed_out, 2);
         check_diagnostics(
diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/remove_trailing_return.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/remove_trailing_return.rs
index a0d5d742d36..b7667dc318f 100644
--- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/remove_trailing_return.rs
+++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/remove_trailing_return.rs
@@ -183,6 +183,18 @@ fn foo() -> u8 {
     }
 
     #[test]
+    fn no_diagnostic_if_not_last_statement2() {
+        check_diagnostics(
+            r#"
+fn foo() -> u8 {
+    return 2;
+    fn bar() {}
+}
+"#,
+        );
+    }
+
+    #[test]
     fn replace_with_expr() {
         check_fix(
             r#"
diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/type_mismatch.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/type_mismatch.rs
index e93eea8ce29..8c97281b783 100644
--- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/type_mismatch.rs
+++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/type_mismatch.rs
@@ -112,7 +112,8 @@ fn add_missing_ok_or_some(
 
     let variant_name = if Some(expected_enum) == core_result { "Ok" } else { "Some" };
 
-    let wrapped_actual_ty = expected_adt.ty_with_args(ctx.sema.db, &[d.actual.clone()]);
+    let wrapped_actual_ty =
+        expected_adt.ty_with_args(ctx.sema.db, std::iter::once(d.actual.clone()));
 
     if !d.expected.could_unify_with(ctx.sema.db, &wrapped_actual_ty) {
         return None;
diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/typed_hole.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/typed_hole.rs
index 6441343ebac..56c8181e84c 100644
--- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/typed_hole.rs
+++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/typed_hole.rs
@@ -1,14 +1,20 @@
-use hir::{db::ExpandDatabase, ClosureStyle, HirDisplay, StructKind};
+use hir::{
+    db::ExpandDatabase,
+    term_search::{term_search, TermSearchCtx},
+    ClosureStyle, HirDisplay,
+};
 use ide_db::{
     assists::{Assist, AssistId, AssistKind, GroupLabel},
     label::Label,
     source_change::SourceChange,
 };
-use syntax::AstNode;
+use itertools::Itertools;
 use text_edit::TextEdit;
 
 use crate::{Diagnostic, DiagnosticCode, DiagnosticsContext};
 
+use syntax::AstNode;
+
 // Diagnostic: typed-hole
 //
 // This diagnostic is triggered when an underscore expression is used in an invalid position.
@@ -36,50 +42,54 @@ fn fixes(ctx: &DiagnosticsContext<'_>, d: &hir::TypedHole) -> Option<Vec<Assist>
     let (original_range, _) =
         d.expr.as_ref().map(|it| it.to_node(&root)).syntax().original_file_range_opt(db)?;
     let scope = ctx.sema.scope(d.expr.value.to_node(&root).syntax())?;
-    let mut assists = vec![];
-    scope.process_all_names(&mut |name, def| {
-        let ty = match def {
-            hir::ScopeDef::ModuleDef(it) => match it {
-                hir::ModuleDef::Function(it) => it.ty(db),
-                hir::ModuleDef::Adt(hir::Adt::Struct(it)) if it.kind(db) != StructKind::Record => {
-                    it.constructor_ty(db)
-                }
-                hir::ModuleDef::Variant(it) if it.kind(db) != StructKind::Record => {
-                    it.constructor_ty(db)
-                }
-                hir::ModuleDef::Const(it) => it.ty(db),
-                hir::ModuleDef::Static(it) => it.ty(db),
-                _ => return,
-            },
-            hir::ScopeDef::GenericParam(hir::GenericParam::ConstParam(it)) => it.ty(db),
-            hir::ScopeDef::Local(it) => it.ty(db),
-            _ => return,
-        };
-        // FIXME: should also check coercions if it is at a coercion site
-        if !ty.contains_unknown() && ty.could_unify_with(db, &d.expected) {
-            assists.push(Assist {
-                id: AssistId("typed-hole", AssistKind::QuickFix),
-                label: Label::new(format!("Replace `_` with `{}`", name.display(db))),
-                group: Some(GroupLabel("Replace `_` with a matching entity in scope".to_owned())),
-                target: original_range.range,
-                source_change: Some(SourceChange::from_text_edit(
-                    original_range.file_id,
-                    TextEdit::replace(original_range.range, name.display(db).to_string()),
-                )),
-                trigger_signature_help: false,
-            });
-        }
-    });
-    if assists.is_empty() {
-        None
-    } else {
+
+    let term_search_ctx = TermSearchCtx {
+        sema: &ctx.sema,
+        scope: &scope,
+        goal: d.expected.clone(),
+        config: Default::default(),
+    };
+    let paths = term_search(&term_search_ctx);
+
+    let mut formatter = |_: &hir::Type| String::from("_");
+
+    let assists: Vec<Assist> = paths
+        .into_iter()
+        .filter_map(|path| {
+            path.gen_source_code(
+                &scope,
+                &mut formatter,
+                ctx.config.prefer_no_std,
+                ctx.config.prefer_prelude,
+            )
+            .ok()
+        })
+        .unique()
+        .map(|code| Assist {
+            id: AssistId("typed-hole", AssistKind::QuickFix),
+            label: Label::new(format!("Replace `_` with `{}`", &code)),
+            group: Some(GroupLabel("Replace `_` with a term".to_owned())),
+            target: original_range.range,
+            source_change: Some(SourceChange::from_text_edit(
+                original_range.file_id,
+                TextEdit::replace(original_range.range, code),
+            )),
+            trigger_signature_help: false,
+        })
+        .collect();
+
+    if !assists.is_empty() {
         Some(assists)
+    } else {
+        None
     }
 }
 
 #[cfg(test)]
 mod tests {
-    use crate::tests::{check_diagnostics, check_fixes};
+    use crate::tests::{
+        check_diagnostics, check_fixes_unordered, check_has_fix, check_has_single_fix,
+    };
 
     #[test]
     fn unknown() {
@@ -99,7 +109,7 @@ fn main() {
             r#"
 fn main() {
     if _ {}
-     //^ error: invalid `_` expression, expected type `bool`
+     //^ 💡 error: invalid `_` expression, expected type `bool`
     let _: fn() -> i32 = _;
                        //^ error: invalid `_` expression, expected type `fn() -> i32`
     let _: fn() -> () = _; // FIXME: This should trigger an assist because `main` matches via *coercion*
@@ -129,7 +139,7 @@ fn main() {
 fn main() {
     let mut x = t();
     x = _;
-      //^ 💡 error: invalid `_` expression, expected type `&str`
+      //^ error: invalid `_` expression, expected type `&str`
     x = "";
 }
 fn t<T>() -> T { loop {} }
@@ -143,7 +153,8 @@ fn t<T>() -> T { loop {} }
             r#"
 fn main() {
     let _x = [(); _];
-    let _y: [(); 10] = [(); _];
+    // FIXME: This should trigger error
+    // let _y: [(); 10] = [(); _];
     _ = 0;
     (_,) = (1,);
 }
@@ -153,7 +164,7 @@ fn main() {
 
     #[test]
     fn check_quick_fix() {
-        check_fixes(
+        check_fixes_unordered(
             r#"
 enum Foo {
     Bar
@@ -175,7 +186,7 @@ use Foo::Bar;
 const C: Foo = Foo::Bar;
 fn main<const CP: Foo>(param: Foo) {
     let local = Foo::Bar;
-    let _: Foo = local;
+    let _: Foo = Bar;
                //^ error: invalid `_` expression, expected type `fn()`
 }
 "#,
@@ -187,7 +198,7 @@ use Foo::Bar;
 const C: Foo = Foo::Bar;
 fn main<const CP: Foo>(param: Foo) {
     let local = Foo::Bar;
-    let _: Foo = param;
+    let _: Foo = local;
                //^ error: invalid `_` expression, expected type `fn()`
 }
 "#,
@@ -199,7 +210,7 @@ use Foo::Bar;
 const C: Foo = Foo::Bar;
 fn main<const CP: Foo>(param: Foo) {
     let local = Foo::Bar;
-    let _: Foo = CP;
+    let _: Foo = param;
                //^ error: invalid `_` expression, expected type `fn()`
 }
 "#,
@@ -211,7 +222,7 @@ use Foo::Bar;
 const C: Foo = Foo::Bar;
 fn main<const CP: Foo>(param: Foo) {
     let local = Foo::Bar;
-    let _: Foo = Bar;
+    let _: Foo = CP;
                //^ error: invalid `_` expression, expected type `fn()`
 }
 "#,
@@ -230,4 +241,153 @@ fn main<const CP: Foo>(param: Foo) {
             ],
         );
     }
+
+    #[test]
+    fn local_item_use_trait() {
+        check_has_fix(
+            r#"
+struct Bar;
+struct Baz;
+trait Foo {
+    fn foo(self) -> Bar;
+}
+impl Foo for Baz {
+    fn foo(self) -> Bar {
+        unimplemented!()
+    }
+}
+fn asd() -> Bar {
+    let a = Baz;
+    _$0
+}
+"#,
+            r"
+struct Bar;
+struct Baz;
+trait Foo {
+    fn foo(self) -> Bar;
+}
+impl Foo for Baz {
+    fn foo(self) -> Bar {
+        unimplemented!()
+    }
+}
+fn asd() -> Bar {
+    let a = Baz;
+    Foo::foo(a)
+}
+",
+        );
+    }
+
+    #[test]
+    fn init_struct() {
+        check_has_fix(
+            r#"struct Abc {}
+struct Qwe { a: i32, b: Abc }
+fn main() {
+    let a: i32 = 1;
+    let c: Qwe = _$0;
+}"#,
+            r#"struct Abc {}
+struct Qwe { a: i32, b: Abc }
+fn main() {
+    let a: i32 = 1;
+    let c: Qwe = Qwe { a: a, b: Abc {  } };
+}"#,
+        );
+    }
+
+    #[test]
+    fn ignore_impl_func_with_incorrect_return() {
+        check_has_single_fix(
+            r#"
+struct Bar {}
+trait Foo {
+    type Res;
+    fn foo(&self) -> Self::Res;
+}
+impl Foo for i32 {
+    type Res = Self;
+    fn foo(&self) -> Self::Res { 1 }
+}
+fn main() {
+    let a: i32 = 1;
+    let c: Bar = _$0;
+}"#,
+            r#"
+struct Bar {}
+trait Foo {
+    type Res;
+    fn foo(&self) -> Self::Res;
+}
+impl Foo for i32 {
+    type Res = Self;
+    fn foo(&self) -> Self::Res { 1 }
+}
+fn main() {
+    let a: i32 = 1;
+    let c: Bar = Bar {  };
+}"#,
+        );
+    }
+
+    #[test]
+    fn use_impl_func_with_correct_return() {
+        check_has_fix(
+            r#"
+struct Bar {}
+struct A;
+trait Foo {
+    type Res;
+    fn foo(&self) -> Self::Res;
+}
+impl Foo for A {
+    type Res = Bar;
+    fn foo(&self) -> Self::Res { Bar { } }
+}
+fn main() {
+    let a = A;
+    let c: Bar = _$0;
+}"#,
+            r#"
+struct Bar {}
+struct A;
+trait Foo {
+    type Res;
+    fn foo(&self) -> Self::Res;
+}
+impl Foo for A {
+    type Res = Bar;
+    fn foo(&self) -> Self::Res { Bar { } }
+}
+fn main() {
+    let a = A;
+    let c: Bar = Foo::foo(&a);
+}"#,
+        );
+    }
+
+    #[test]
+    fn local_shadow_fn() {
+        check_fixes_unordered(
+            r#"
+fn f() {
+    let f: i32 = 0;
+    _$0
+}"#,
+            vec![
+                r#"
+fn f() {
+    let f: i32 = 0;
+    ()
+}"#,
+                r#"
+fn f() {
+    let f: i32 = 0;
+    crate::f()
+}"#,
+            ],
+        );
+    }
 }
diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/tests.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/tests.rs
index b62bb5affdd..4e4a851f67e 100644
--- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/tests.rs
+++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/tests.rs
@@ -91,6 +91,91 @@ fn check_nth_fix_with_config(
     assert_eq_text!(&after, &actual);
 }
 
+pub(crate) fn check_fixes_unordered(ra_fixture_before: &str, ra_fixtures_after: Vec<&str>) {
+    for ra_fixture_after in ra_fixtures_after.iter() {
+        check_has_fix(ra_fixture_before, ra_fixture_after)
+    }
+}
+
+#[track_caller]
+pub(crate) fn check_has_fix(ra_fixture_before: &str, ra_fixture_after: &str) {
+    let after = trim_indent(ra_fixture_after);
+
+    let (db, file_position) = RootDatabase::with_position(ra_fixture_before);
+    let mut conf = DiagnosticsConfig::test_sample();
+    conf.expr_fill_default = ExprFillDefaultMode::Default;
+    let fix = super::diagnostics(&db, &conf, &AssistResolveStrategy::All, file_position.file_id)
+        .into_iter()
+        .find(|d| {
+            d.fixes
+                .as_ref()
+                .and_then(|fixes| {
+                    fixes.iter().find(|fix| {
+                        if !fix.target.contains_inclusive(file_position.offset) {
+                            return false;
+                        }
+                        let actual = {
+                            let source_change = fix.source_change.as_ref().unwrap();
+                            let file_id = *source_change.source_file_edits.keys().next().unwrap();
+                            let mut actual = db.file_text(file_id).to_string();
+
+                            for (edit, snippet_edit) in source_change.source_file_edits.values() {
+                                edit.apply(&mut actual);
+                                if let Some(snippet_edit) = snippet_edit {
+                                    snippet_edit.apply(&mut actual);
+                                }
+                            }
+                            actual
+                        };
+                        after == actual
+                    })
+                })
+                .is_some()
+        });
+    assert!(fix.is_some(), "no diagnostic with desired fix");
+}
+
+#[track_caller]
+pub(crate) fn check_has_single_fix(ra_fixture_before: &str, ra_fixture_after: &str) {
+    let after = trim_indent(ra_fixture_after);
+
+    let (db, file_position) = RootDatabase::with_position(ra_fixture_before);
+    let mut conf = DiagnosticsConfig::test_sample();
+    conf.expr_fill_default = ExprFillDefaultMode::Default;
+    let mut n_fixes = 0;
+    let fix = super::diagnostics(&db, &conf, &AssistResolveStrategy::All, file_position.file_id)
+        .into_iter()
+        .find(|d| {
+            d.fixes
+                .as_ref()
+                .and_then(|fixes| {
+                    n_fixes += fixes.len();
+                    fixes.iter().find(|fix| {
+                        if !fix.target.contains_inclusive(file_position.offset) {
+                            return false;
+                        }
+                        let actual = {
+                            let source_change = fix.source_change.as_ref().unwrap();
+                            let file_id = *source_change.source_file_edits.keys().next().unwrap();
+                            let mut actual = db.file_text(file_id).to_string();
+
+                            for (edit, snippet_edit) in source_change.source_file_edits.values() {
+                                edit.apply(&mut actual);
+                                if let Some(snippet_edit) = snippet_edit {
+                                    snippet_edit.apply(&mut actual);
+                                }
+                            }
+                            actual
+                        };
+                        after == actual
+                    })
+                })
+                .is_some()
+        });
+    assert!(fix.is_some(), "no diagnostic with desired fix");
+    assert!(n_fixes == 1, "Too many fixes suggested");
+}
+
 /// Checks that there's a diagnostic *without* fix at `$0`.
 pub(crate) fn check_no_fix(ra_fixture: &str) {
     let (db, file_position) = RootDatabase::with_position(ra_fixture);
diff --git a/src/tools/rust-analyzer/crates/ide/src/doc_links.rs b/src/tools/rust-analyzer/crates/ide/src/doc_links.rs
index dbe6a5507cc..18821bd78bf 100644
--- a/src/tools/rust-analyzer/crates/ide/src/doc_links.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/doc_links.rs
@@ -501,7 +501,7 @@ fn get_doc_base_urls(
     let Some(krate) = def.krate(db) else { return Default::default() };
     let Some(display_name) = krate.display_name(db) else { return Default::default() };
     let crate_data = &db.crate_graph()[krate.into()];
-    let channel = crate_data.channel().unwrap_or(ReleaseChannel::Nightly).as_str();
+    let channel = db.toolchain_channel(krate.into()).unwrap_or(ReleaseChannel::Nightly).as_str();
 
     let (web_base, local_base) = match &crate_data.origin {
         // std and co do not specify `html_root_url` any longer so we gotta handwrite this ourself.
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 30bfe6ee9dc..69ddc1e45ef 100644
--- a/src/tools/rust-analyzer/crates/ide/src/hover/tests.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/hover/tests.rs
@@ -7263,8 +7263,8 @@ impl Iterator for S {
                                 file_id: FileId(
                                     1,
                                 ),
-                                full_range: 6157..6365,
-                                focus_range: 6222..6228,
+                                full_range: 6290..6498,
+                                focus_range: 6355..6361,
                                 name: "Future",
                                 kind: Trait,
                                 container_name: "future",
@@ -7277,8 +7277,8 @@ impl Iterator for S {
                                 file_id: FileId(
                                     1,
                                 ),
-                                full_range: 6995..7461,
-                                focus_range: 7039..7047,
+                                full_range: 7128..7594,
+                                focus_range: 7172..7180,
                                 name: "Iterator",
                                 kind: Trait,
                                 container_name: "iterator",
diff --git a/src/tools/rust-analyzer/crates/ide/src/lib.rs b/src/tools/rust-analyzer/crates/ide/src/lib.rs
index effdbf2c1f0..3238887257a 100644
--- a/src/tools/rust-analyzer/crates/ide/src/lib.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/lib.rs
@@ -12,11 +12,6 @@
 #![cfg_attr(feature = "in-rust-tree", feature(rustc_private))]
 #![recursion_limit = "128"]
 
-#[allow(unused)]
-macro_rules! eprintln {
-    ($($tt:tt)*) => { stdx::eprintln!($($tt)*) };
-}
-
 #[cfg(test)]
 mod fixture;
 
@@ -258,11 +253,11 @@ impl Analysis {
             Env::default(),
             false,
             CrateOrigin::Local { repo: None, name: None },
-            Err("Analysis::from_single_file has no target layout".into()),
-            None,
         );
         change.change_file(file_id, Some(Arc::from(text)));
         change.set_crate_graph(crate_graph);
+        change.set_target_data_layouts(vec![Err("fixture has no layout".into())]);
+        change.set_toolchains(vec![None]);
         host.apply_change(change);
         (host.analysis(), file_id)
     }
@@ -680,9 +675,8 @@ impl Analysis {
         &self,
         position: FilePosition,
         new_name: &str,
-        rename_external: bool,
     ) -> Cancellable<Result<SourceChange, RenameError>> {
-        self.with_db(|db| rename::rename(db, position, new_name, rename_external))
+        self.with_db(|db| rename::rename(db, position, new_name))
     }
 
     pub fn prepare_rename(
diff --git a/src/tools/rust-analyzer/crates/ide/src/parent_module.rs b/src/tools/rust-analyzer/crates/ide/src/parent_module.rs
index 413dbf9c5df..f67aea2d5b9 100644
--- a/src/tools/rust-analyzer/crates/ide/src/parent_module.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/parent_module.rs
@@ -54,7 +54,7 @@ pub(crate) fn parent_module(db: &RootDatabase, position: FilePosition) -> Vec<Na
     }
 }
 
-/// Returns `Vec` for the same reason as `parent_module`
+/// This returns `Vec` because a module may be included from several places.
 pub(crate) fn crates_for(db: &RootDatabase, file_id: FileId) -> Vec<CrateId> {
     db.relevant_crates(file_id)
         .iter()
diff --git a/src/tools/rust-analyzer/crates/ide/src/rename.rs b/src/tools/rust-analyzer/crates/ide/src/rename.rs
index 9fce4bb0f82..f2eedfa4316 100644
--- a/src/tools/rust-analyzer/crates/ide/src/rename.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/rename.rs
@@ -84,7 +84,6 @@ pub(crate) fn rename(
     db: &RootDatabase,
     position: FilePosition,
     new_name: &str,
-    rename_external: bool,
 ) -> RenameResult<SourceChange> {
     let sema = Semantics::new(db);
     let source_file = sema.parse(position.file_id);
@@ -104,7 +103,7 @@ pub(crate) fn rename(
                     return rename_to_self(&sema, local);
                 }
             }
-            def.rename(&sema, new_name, rename_external)
+            def.rename(&sema, new_name)
         })
         .collect();
 
@@ -123,9 +122,9 @@ pub(crate) fn will_rename_file(
     let module = sema.to_module_def(file_id)?;
     let def = Definition::Module(module);
     let mut change = if is_raw_identifier(new_name_stem) {
-        def.rename(&sema, &SmolStr::from_iter(["r#", new_name_stem]), true).ok()?
+        def.rename(&sema, &SmolStr::from_iter(["r#", new_name_stem])).ok()?
     } else {
-        def.rename(&sema, new_name_stem, true).ok()?
+        def.rename(&sema, new_name_stem).ok()?
     };
     change.file_system_edits.clear();
     Some(change)
@@ -377,16 +376,11 @@ mod tests {
     use super::{RangeInfo, RenameError};
 
     fn check(new_name: &str, ra_fixture_before: &str, ra_fixture_after: &str) {
-        check_with_rename_config(new_name, ra_fixture_before, ra_fixture_after, true);
+        check_with_rename_config(new_name, ra_fixture_before, ra_fixture_after);
     }
 
     #[track_caller]
-    fn check_with_rename_config(
-        new_name: &str,
-        ra_fixture_before: &str,
-        ra_fixture_after: &str,
-        rename_external: bool,
-    ) {
+    fn check_with_rename_config(new_name: &str, ra_fixture_before: &str, ra_fixture_after: &str) {
         let ra_fixture_after = &trim_indent(ra_fixture_after);
         let (analysis, position) = fixture::position(ra_fixture_before);
         if !ra_fixture_after.starts_with("error: ") {
@@ -395,7 +389,7 @@ mod tests {
             }
         }
         let rename_result = analysis
-            .rename(position, new_name, rename_external)
+            .rename(position, new_name)
             .unwrap_or_else(|err| panic!("Rename to '{new_name}' was cancelled: {err}"));
         match rename_result {
             Ok(source_change) => {
@@ -426,10 +420,8 @@ mod tests {
 
     fn check_expect(new_name: &str, ra_fixture: &str, expect: Expect) {
         let (analysis, position) = fixture::position(ra_fixture);
-        let source_change = analysis
-            .rename(position, new_name, true)
-            .unwrap()
-            .expect("Expect returned a RenameError");
+        let source_change =
+            analysis.rename(position, new_name).unwrap().expect("Expect returned a RenameError");
         expect.assert_eq(&filter_expect(source_change))
     }
 
@@ -2636,19 +2628,7 @@ pub struct S;
 //- /main.rs crate:main deps:lib new_source_root:local
 use lib::S$0;
 "#,
-            "error: Cannot rename a non-local definition as the config for it is disabled",
-            false,
-        );
-
-        check(
-            "Baz",
-            r#"
-//- /lib.rs crate:lib new_source_root:library
-pub struct S;
-//- /main.rs crate:main deps:lib new_source_root:local
-use lib::S$0;
-"#,
-            "use lib::Baz;\n",
+            "error: Cannot rename a non-local definition",
         );
     }
 
@@ -2663,8 +2643,7 @@ use core::hash::Hash;
 #[derive(H$0ash)]
 struct A;
             "#,
-            "error: Cannot rename a non-local definition as the config for it is disabled",
-            false,
+            "error: Cannot rename a non-local definition",
         );
     }
 
diff --git a/src/tools/rust-analyzer/crates/ide/src/shuffle_crate_graph.rs b/src/tools/rust-analyzer/crates/ide/src/shuffle_crate_graph.rs
index bf6ad47a495..453d1836e16 100644
--- a/src/tools/rust-analyzer/crates/ide/src/shuffle_crate_graph.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/shuffle_crate_graph.rs
@@ -39,8 +39,6 @@ pub(crate) fn shuffle_crate_graph(db: &mut RootDatabase) {
             data.env.clone(),
             data.is_proc_macro,
             data.origin.clone(),
-            data.target_layout.clone(),
-            data.toolchain.clone(),
         );
         new_proc_macros.insert(new_id, proc_macros[&old_id].clone());
         map.insert(old_id, new_id);
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 dee5afbf8d9..5feaf21aa97 100644
--- a/src/tools/rust-analyzer/crates/ide/src/static_index.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/static_index.rs
@@ -1,14 +1,16 @@
 //! This module provides `StaticIndex` which is used for powering
 //! read-only code browsers and emitting LSIF
 
-use hir::{db::HirDatabase, Crate, HirFileIdExt, Module};
+use hir::{db::HirDatabase, Crate, HirFileIdExt, Module, Semantics};
 use ide_db::{
     base_db::{FileId, FileRange, SourceDatabaseExt},
     defs::Definition,
+    documentation::Documentation,
+    famous_defs::FamousDefs,
     helpers::get_definition,
     FxHashMap, FxHashSet, RootDatabase,
 };
-use syntax::{AstNode, SyntaxKind::*, TextRange, T};
+use syntax::{AstNode, SyntaxKind::*, SyntaxNode, TextRange, T};
 
 use crate::inlay_hints::InlayFieldsToResolve;
 use crate::navigation_target::UpmappingResult;
@@ -22,7 +24,7 @@ use crate::{
 
 /// A static representation of fully analyzed source code.
 ///
-/// The intended use-case is powering read-only code browsers and emitting LSIF
+/// The intended use-case is powering read-only code browsers and emitting LSIF/SCIP.
 #[derive(Debug)]
 pub struct StaticIndex<'a> {
     pub files: Vec<StaticIndexedFile>,
@@ -40,6 +42,7 @@ pub struct ReferenceData {
 
 #[derive(Debug)]
 pub struct TokenStaticData {
+    pub documentation: Option<Documentation>,
     pub hover: Option<HoverResult>,
     pub definition: Option<FileRange>,
     pub references: Vec<ReferenceData>,
@@ -103,6 +106,19 @@ fn all_modules(db: &dyn HirDatabase) -> Vec<Module> {
     modules
 }
 
+fn documentation_for_definition(
+    sema: &Semantics<'_, RootDatabase>,
+    def: Definition,
+    scope_node: &SyntaxNode,
+) -> Option<Documentation> {
+    let famous_defs = match &def {
+        Definition::BuiltinType(_) => Some(FamousDefs(sema, sema.scope(scope_node)?.krate())),
+        _ => None,
+    };
+
+    def.docs(sema.db, famous_defs.as_ref())
+}
+
 impl StaticIndex<'_> {
     fn add_file(&mut self, file_id: FileId) {
         let current_crate = crates_for(self.db, file_id).pop().map(Into::into);
@@ -169,6 +185,7 @@ impl StaticIndex<'_> {
                 *it
             } else {
                 let it = self.tokens.insert(TokenStaticData {
+                    documentation: documentation_for_definition(&sema, def, &node),
                     hover: hover_for_definition(&sema, file_id, def, &node, &hover_config),
                     definition: def.try_to_nav(self.db).map(UpmappingResult::call_site).map(|it| {
                         FileRange { file_id: it.file_id, range: it.focus_or_full_range() }
diff --git a/src/tools/rust-analyzer/crates/ide/src/status.rs b/src/tools/rust-analyzer/crates/ide/src/status.rs
index 3321a0513b6..c3d85e38936 100644
--- a/src/tools/rust-analyzer/crates/ide/src/status.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/status.rs
@@ -72,8 +72,6 @@ pub(crate) fn status(db: &RootDatabase, file_id: Option<FileId>) -> String {
                 dependencies,
                 origin,
                 is_proc_macro,
-                target_layout,
-                toolchain,
             } = &crate_graph[crate_id];
             format_to!(
                 buf,
@@ -91,12 +89,6 @@ pub(crate) fn status(db: &RootDatabase, file_id: Option<FileId>) -> String {
             format_to!(buf, "    Env: {:?}\n", env);
             format_to!(buf, "    Origin: {:?}\n", origin);
             format_to!(buf, "    Is a proc macro crate: {}\n", is_proc_macro);
-            format_to!(buf, "    Workspace Target Layout: {:?}\n", target_layout);
-            format_to!(
-                buf,
-                "    Workspace Toolchain: {}\n",
-                toolchain.as_ref().map_or_else(|| "n/a".into(), |v| v.to_string())
-            );
             let deps = dependencies
                 .iter()
                 .map(|dep| format!("{}={}", dep.name, dep.crate_id.into_raw()))
diff --git a/src/tools/rust-analyzer/crates/load-cargo/src/lib.rs b/src/tools/rust-analyzer/crates/load-cargo/src/lib.rs
index c6dc071c394..8c5592da63e 100644
--- a/src/tools/rust-analyzer/crates/load-cargo/src/lib.rs
+++ b/src/tools/rust-analyzer/crates/load-cargo/src/lib.rs
@@ -2,7 +2,7 @@
 //! for incorporating changes.
 // Note, don't remove any public api from this. This API is consumed by external tools
 // to run rust-analyzer as a library.
-use std::{collections::hash_map::Entry, mem, path::Path, sync};
+use std::{collections::hash_map::Entry, iter, mem, path::Path, sync};
 
 use crossbeam_channel::{unbounded, Receiver};
 use hir_expand::proc_macro::{
@@ -18,7 +18,6 @@ use itertools::Itertools;
 use proc_macro_api::{MacroDylib, ProcMacroServer};
 use project_model::{CargoConfig, PackageRoot, ProjectManifest, ProjectWorkspace};
 use span::Span;
-use tt::DelimSpan;
 use vfs::{file_set::FileSetConfig, loader::Handle, AbsPath, AbsPathBuf, VfsPath};
 
 pub struct LoadCargoConfig {
@@ -68,9 +67,9 @@ pub fn load_workspace(
     let proc_macro_server = match &load_config.with_proc_macro_server {
         ProcMacroServerChoice::Sysroot => ws
             .find_sysroot_proc_macro_srv()
-            .and_then(|it| ProcMacroServer::spawn(it).map_err(Into::into)),
+            .and_then(|it| ProcMacroServer::spawn(it, extra_env).map_err(Into::into)),
         ProcMacroServerChoice::Explicit(path) => {
-            ProcMacroServer::spawn(path.clone()).map_err(Into::into)
+            ProcMacroServer::spawn(path.clone(), extra_env).map_err(Into::into)
         }
         ProcMacroServerChoice::None => Err(anyhow::format_err!("proc macro server disabled")),
     };
@@ -107,7 +106,7 @@ pub fn load_workspace(
             .collect()
     };
 
-    let project_folders = ProjectFolders::new(&[ws], &[]);
+    let project_folders = ProjectFolders::new(std::slice::from_ref(&ws), &[]);
     loader.set_config(vfs::loader::Config {
         load: project_folders.load,
         watch: vec![],
@@ -115,6 +114,7 @@ pub fn load_workspace(
     });
 
     let host = load_crate_graph(
+        &ws,
         crate_graph,
         proc_macros,
         project_folders.source_root_config,
@@ -273,7 +273,7 @@ impl SourceRootConfig {
 pub fn load_proc_macro(
     server: &ProcMacroServer,
     path: &AbsPath,
-    dummy_replace: &[Box<str>],
+    ignored_macros: &[Box<str>],
 ) -> ProcMacroLoadResult {
     let res: Result<Vec<_>, String> = (|| {
         let dylib = MacroDylib::new(path.to_path_buf());
@@ -283,7 +283,7 @@ pub fn load_proc_macro(
         }
         Ok(vec
             .into_iter()
-            .map(|expander| expander_to_proc_macro(expander, dummy_replace))
+            .map(|expander| expander_to_proc_macro(expander, ignored_macros))
             .collect())
     })();
     match res {
@@ -302,6 +302,7 @@ pub fn load_proc_macro(
 }
 
 fn load_crate_graph(
+    ws: &ProjectWorkspace,
     crate_graph: CrateGraph,
     proc_macros: ProcMacros,
     source_root_config: SourceRootConfig,
@@ -340,8 +341,17 @@ fn load_crate_graph(
     let source_roots = source_root_config.partition(vfs);
     analysis_change.set_roots(source_roots);
 
+    let num_crates = crate_graph.len();
     analysis_change.set_crate_graph(crate_graph);
     analysis_change.set_proc_macros(proc_macros);
+    if let ProjectWorkspace::Cargo { toolchain, target_layout, .. }
+    | ProjectWorkspace::Json { toolchain, target_layout, .. } = ws
+    {
+        analysis_change.set_target_data_layouts(
+            iter::repeat(target_layout.clone()).take(num_crates).collect(),
+        );
+        analysis_change.set_toolchains(iter::repeat(toolchain.clone()).take(num_crates).collect());
+    }
 
     host.apply_change(analysis_change);
     host
@@ -349,7 +359,7 @@ fn load_crate_graph(
 
 fn expander_to_proc_macro(
     expander: proc_macro_api::ProcMacro,
-    dummy_replace: &[Box<str>],
+    ignored_macros: &[Box<str>],
 ) -> ProcMacro {
     let name = From::from(expander.name());
     let kind = match expander.kind() {
@@ -357,16 +367,8 @@ fn expander_to_proc_macro(
         proc_macro_api::ProcMacroKind::FuncLike => ProcMacroKind::FuncLike,
         proc_macro_api::ProcMacroKind::Attr => ProcMacroKind::Attr,
     };
-    let expander: sync::Arc<dyn ProcMacroExpander> =
-        if dummy_replace.iter().any(|replace| **replace == name) {
-            match kind {
-                ProcMacroKind::Attr => sync::Arc::new(IdentityExpander),
-                _ => sync::Arc::new(EmptyExpander),
-            }
-        } else {
-            sync::Arc::new(Expander(expander))
-        };
-    ProcMacro { name, kind, expander }
+    let disabled = ignored_macros.iter().any(|replace| **replace == name);
+    ProcMacro { name, kind, expander: sync::Arc::new(Expander(expander)), disabled }
 }
 
 #[derive(Debug)]
@@ -391,42 +393,6 @@ impl ProcMacroExpander for Expander {
     }
 }
 
-/// Dummy identity expander, used for attribute proc-macros that are deliberately ignored by the user.
-#[derive(Debug)]
-struct IdentityExpander;
-
-impl ProcMacroExpander for IdentityExpander {
-    fn expand(
-        &self,
-        subtree: &tt::Subtree<Span>,
-        _: Option<&tt::Subtree<Span>>,
-        _: &Env,
-        _: Span,
-        _: Span,
-        _: Span,
-    ) -> Result<tt::Subtree<Span>, ProcMacroExpansionError> {
-        Ok(subtree.clone())
-    }
-}
-
-/// Empty expander, used for proc-macros that are deliberately ignored by the user.
-#[derive(Debug)]
-struct EmptyExpander;
-
-impl ProcMacroExpander for EmptyExpander {
-    fn expand(
-        &self,
-        _: &tt::Subtree<Span>,
-        _: Option<&tt::Subtree<Span>>,
-        _: &Env,
-        call_site: Span,
-        _: Span,
-        _: Span,
-    ) -> Result<tt::Subtree<Span>, ProcMacroExpansionError> {
-        Ok(tt::Subtree::empty(DelimSpan { open: call_site, close: call_site }))
-    }
-}
-
 #[cfg(test)]
 mod tests {
     use ide_db::base_db::SourceDatabase;
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 9291f799cca..6d3055da286 100644
--- a/src/tools/rust-analyzer/crates/mbe/src/expander/transcriber.rs
+++ b/src/tools/rust-analyzer/crates/mbe/src/expander/transcriber.rs
@@ -101,10 +101,20 @@ impl<S: Span> Bindings<S> {
                         })))
                     }
                     MetaVarKind::Lifetime => {
-                        Fragment::Tokens(tt::TokenTree::Leaf(tt::Leaf::Ident(tt::Ident {
-                            text: SmolStr::new_static("'missing"),
-                            span,
-                        })))
+                        Fragment::Tokens(tt::TokenTree::Subtree(tt::Subtree {
+                            delimiter: tt::Delimiter::invisible_spanned(span),
+                            token_trees: Box::new([
+                                tt::TokenTree::Leaf(tt::Leaf::Punct(tt::Punct {
+                                    char: '\'',
+                                    span,
+                                    spacing: tt::Spacing::Joint,
+                                })),
+                                tt::TokenTree::Leaf(tt::Leaf::Ident(tt::Ident {
+                                    text: SmolStr::new_static("missing"),
+                                    span,
+                                })),
+                            ]),
+                        }))
                     }
                     MetaVarKind::Literal => {
                         Fragment::Tokens(tt::TokenTree::Leaf(tt::Leaf::Ident(tt::Ident {
diff --git a/src/tools/rust-analyzer/crates/mbe/src/syntax_bridge.rs b/src/tools/rust-analyzer/crates/mbe/src/syntax_bridge.rs
index bfc5d197f68..3c270e30a9b 100644
--- a/src/tools/rust-analyzer/crates/mbe/src/syntax_bridge.rs
+++ b/src/tools/rust-analyzer/crates/mbe/src/syntax_bridge.rs
@@ -700,10 +700,12 @@ impl<S> SynToken<S> {
 }
 
 impl<SpanMap, S: std::fmt::Debug> SrcToken<Converter<SpanMap, S>, S> for SynToken<S> {
-    fn kind(&self, ctx: &Converter<SpanMap, S>) -> SyntaxKind {
+    fn kind(&self, _ctx: &Converter<SpanMap, S>) -> SyntaxKind {
         match self {
             SynToken::Ordinary(token) => token.kind(),
-            SynToken::Punct { .. } => SyntaxKind::from_char(self.to_char(ctx).unwrap()).unwrap(),
+            SynToken::Punct { token, offset: i } => {
+                SyntaxKind::from_char(token.text().chars().nth(*i).unwrap()).unwrap()
+            }
             SynToken::Leaf(_) => {
                 never!();
                 SyntaxKind::ERROR
diff --git a/src/tools/rust-analyzer/crates/parser/src/grammar/expressions.rs b/src/tools/rust-analyzer/crates/parser/src/grammar/expressions.rs
index f40c515fa07..6b660180f82 100644
--- a/src/tools/rust-analyzer/crates/parser/src/grammar/expressions.rs
+++ b/src/tools/rust-analyzer/crates/parser/src/grammar/expressions.rs
@@ -678,27 +678,38 @@ pub(crate) fn record_expr_field_list(p: &mut Parser<'_>) {
         attributes::outer_attrs(p);
 
         match p.current() {
-            IDENT | INT_NUMBER => {
+            IDENT | INT_NUMBER if p.nth_at(1, T![::]) => {
                 // test_err record_literal_missing_ellipsis_recovery
                 // fn main() {
                 //     S { S::default() }
                 // }
-                if p.nth_at(1, T![::]) {
-                    m.abandon(p);
-                    p.expect(T![..]);
-                    expr(p);
-                } else {
+                m.abandon(p);
+                p.expect(T![..]);
+                expr(p);
+            }
+            IDENT | INT_NUMBER => {
+                if p.nth_at(1, T![..]) {
                     // test_err record_literal_before_ellipsis_recovery
                     // fn main() {
                     //     S { field ..S::default() }
                     // }
-                    if p.nth_at(1, T![:]) || p.nth_at(1, T![..]) {
+                    name_ref_or_index(p);
+                    p.error("expected `:`");
+                } else {
+                    // test_err record_literal_field_eq_recovery
+                    // fn main() {
+                    //     S { field = foo }
+                    // }
+                    if p.nth_at(1, T![:]) {
+                        name_ref_or_index(p);
+                        p.bump(T![:]);
+                    } else if p.nth_at(1, T![=]) {
                         name_ref_or_index(p);
-                        p.expect(T![:]);
+                        p.err_and_bump("expected `:`");
                     }
                     expr(p);
-                    m.complete(p, RECORD_EXPR_FIELD);
                 }
+                m.complete(p, RECORD_EXPR_FIELD);
             }
             T![.] if p.at(T![..]) => {
                 m.abandon(p);
diff --git a/src/tools/rust-analyzer/crates/parser/src/grammar/expressions/atom.rs b/src/tools/rust-analyzer/crates/parser/src/grammar/expressions/atom.rs
index 4197f248e0a..48600641ad0 100644
--- a/src/tools/rust-analyzer/crates/parser/src/grammar/expressions/atom.rs
+++ b/src/tools/rust-analyzer/crates/parser/src/grammar/expressions/atom.rs
@@ -58,6 +58,7 @@ pub(super) const ATOM_EXPR_FIRST: TokenSet =
         T![match],
         T![move],
         T![return],
+        T![become],
         T![static],
         T![try],
         T![unsafe],
@@ -102,6 +103,7 @@ pub(super) fn atom_expr(
         T![try] => try_block_expr(p, None),
         T![match] => match_expr(p),
         T![return] => return_expr(p),
+        T![become] => become_expr(p),
         T![yield] => yield_expr(p),
         T![do] if p.nth_at_contextual_kw(1, T![yeet]) => yeet_expr(p),
         T![continue] => continue_expr(p),
@@ -621,6 +623,18 @@ fn return_expr(p: &mut Parser<'_>) -> CompletedMarker {
     m.complete(p, RETURN_EXPR)
 }
 
+// test become_expr
+// fn foo() {
+//     become foo();
+// }
+fn become_expr(p: &mut Parser<'_>) -> CompletedMarker {
+    assert!(p.at(T![become]));
+    let m = p.start();
+    p.bump(T![become]);
+    expr(p);
+    m.complete(p, BECOME_EXPR)
+}
+
 // test yield_expr
 // fn foo() {
 //     yield;
diff --git a/src/tools/rust-analyzer/crates/parser/src/grammar/generic_params.rs b/src/tools/rust-analyzer/crates/parser/src/grammar/generic_params.rs
index 3c577aa3cb4..4498daf21a3 100644
--- a/src/tools/rust-analyzer/crates/parser/src/grammar/generic_params.rs
+++ b/src/tools/rust-analyzer/crates/parser/src/grammar/generic_params.rs
@@ -157,6 +157,16 @@ fn type_bound(p: &mut Parser<'_>) -> bool {
                     p.bump_any();
                     p.expect(T![const]);
                 }
+                // test const_trait_bound
+                // const fn foo(_: impl const Trait) {}
+                T![const] => {
+                    p.bump_any();
+                }
+                // test async_trait_bound
+                // fn async_foo(_: impl async Fn(&i32)) {}
+                T![async] => {
+                    p.bump_any();
+                }
                 _ => (),
             }
             if paths::is_use_path_start(p) {
diff --git a/src/tools/rust-analyzer/crates/parser/src/grammar/patterns.rs b/src/tools/rust-analyzer/crates/parser/src/grammar/patterns.rs
index 39ded41bb24..50367423379 100644
--- a/src/tools/rust-analyzer/crates/parser/src/grammar/patterns.rs
+++ b/src/tools/rust-analyzer/crates/parser/src/grammar/patterns.rs
@@ -323,6 +323,15 @@ fn record_pat_field(p: &mut Parser<'_>) {
             p.bump(T![:]);
             pattern(p);
         }
+        // test_err record_pat_field_eq_recovery
+        // fn main() {
+        //     let S { field = foo };
+        // }
+        IDENT | INT_NUMBER if p.nth(1) == T![=] => {
+            name_ref_or_index(p);
+            p.err_and_bump("expected `:`");
+            pattern(p);
+        }
         T![box] => {
             // FIXME: not all box patterns should be allowed
             box_pat(p);
diff --git a/src/tools/rust-analyzer/crates/parser/src/syntax_kind/generated.rs b/src/tools/rust-analyzer/crates/parser/src/syntax_kind/generated.rs
index 4b589037672..6ecfdc9f466 100644
--- a/src/tools/rust-analyzer/crates/parser/src/syntax_kind/generated.rs
+++ b/src/tools/rust-analyzer/crates/parser/src/syntax_kind/generated.rs
@@ -90,6 +90,7 @@ pub enum SyntaxKind {
     PUB_KW,
     REF_KW,
     RETURN_KW,
+    BECOME_KW,
     SELF_KW,
     SELF_TYPE_KW,
     STATIC_KW,
@@ -195,6 +196,7 @@ pub enum SyntaxKind {
     BLOCK_EXPR,
     STMT_LIST,
     RETURN_EXPR,
+    BECOME_EXPR,
     YIELD_EXPR,
     YEET_EXPR,
     LET_EXPR,
@@ -307,6 +309,7 @@ impl SyntaxKind {
                 | PUB_KW
                 | REF_KW
                 | RETURN_KW
+                | BECOME_KW
                 | SELF_KW
                 | SELF_TYPE_KW
                 | STATIC_KW
@@ -425,6 +428,7 @@ impl SyntaxKind {
             "pub" => PUB_KW,
             "ref" => REF_KW,
             "return" => RETURN_KW,
+            "become" => BECOME_KW,
             "self" => SELF_KW,
             "Self" => SELF_TYPE_KW,
             "static" => STATIC_KW,
@@ -496,4 +500,4 @@ impl SyntaxKind {
     }
 }
 #[macro_export]
-macro_rules ! T { [;] => { $ crate :: SyntaxKind :: SEMICOLON } ; [,] => { $ crate :: SyntaxKind :: COMMA } ; ['('] => { $ crate :: SyntaxKind :: L_PAREN } ; [')'] => { $ crate :: SyntaxKind :: R_PAREN } ; ['{'] => { $ crate :: SyntaxKind :: L_CURLY } ; ['}'] => { $ crate :: SyntaxKind :: R_CURLY } ; ['['] => { $ crate :: SyntaxKind :: L_BRACK } ; [']'] => { $ crate :: SyntaxKind :: R_BRACK } ; [<] => { $ crate :: SyntaxKind :: L_ANGLE } ; [>] => { $ crate :: SyntaxKind :: R_ANGLE } ; [@] => { $ crate :: SyntaxKind :: AT } ; [#] => { $ crate :: SyntaxKind :: POUND } ; [~] => { $ crate :: SyntaxKind :: TILDE } ; [?] => { $ crate :: SyntaxKind :: QUESTION } ; [$] => { $ crate :: SyntaxKind :: DOLLAR } ; [&] => { $ crate :: SyntaxKind :: AMP } ; [|] => { $ crate :: SyntaxKind :: PIPE } ; [+] => { $ crate :: SyntaxKind :: PLUS } ; [*] => { $ crate :: SyntaxKind :: STAR } ; [/] => { $ crate :: SyntaxKind :: SLASH } ; [^] => { $ crate :: SyntaxKind :: CARET } ; [%] => { $ crate :: SyntaxKind :: PERCENT } ; [_] => { $ crate :: SyntaxKind :: UNDERSCORE } ; [.] => { $ crate :: SyntaxKind :: DOT } ; [..] => { $ crate :: SyntaxKind :: DOT2 } ; [...] => { $ crate :: SyntaxKind :: DOT3 } ; [..=] => { $ crate :: SyntaxKind :: DOT2EQ } ; [:] => { $ crate :: SyntaxKind :: COLON } ; [::] => { $ crate :: SyntaxKind :: COLON2 } ; [=] => { $ crate :: SyntaxKind :: EQ } ; [==] => { $ crate :: SyntaxKind :: EQ2 } ; [=>] => { $ crate :: SyntaxKind :: FAT_ARROW } ; [!] => { $ crate :: SyntaxKind :: BANG } ; [!=] => { $ crate :: SyntaxKind :: NEQ } ; [-] => { $ crate :: SyntaxKind :: MINUS } ; [->] => { $ crate :: SyntaxKind :: THIN_ARROW } ; [<=] => { $ crate :: SyntaxKind :: LTEQ } ; [>=] => { $ crate :: SyntaxKind :: GTEQ } ; [+=] => { $ crate :: SyntaxKind :: PLUSEQ } ; [-=] => { $ crate :: SyntaxKind :: MINUSEQ } ; [|=] => { $ crate :: SyntaxKind :: PIPEEQ } ; [&=] => { $ crate :: SyntaxKind :: AMPEQ } ; [^=] => { $ crate :: SyntaxKind :: CARETEQ } ; [/=] => { $ crate :: SyntaxKind :: SLASHEQ } ; [*=] => { $ crate :: SyntaxKind :: STAREQ } ; [%=] => { $ crate :: SyntaxKind :: PERCENTEQ } ; [&&] => { $ crate :: SyntaxKind :: AMP2 } ; [||] => { $ crate :: SyntaxKind :: PIPE2 } ; [<<] => { $ crate :: SyntaxKind :: SHL } ; [>>] => { $ crate :: SyntaxKind :: SHR } ; [<<=] => { $ crate :: SyntaxKind :: SHLEQ } ; [>>=] => { $ crate :: SyntaxKind :: SHREQ } ; [as] => { $ crate :: SyntaxKind :: AS_KW } ; [async] => { $ crate :: SyntaxKind :: ASYNC_KW } ; [await] => { $ crate :: SyntaxKind :: AWAIT_KW } ; [box] => { $ crate :: SyntaxKind :: BOX_KW } ; [break] => { $ crate :: SyntaxKind :: BREAK_KW } ; [const] => { $ crate :: SyntaxKind :: CONST_KW } ; [continue] => { $ crate :: SyntaxKind :: CONTINUE_KW } ; [crate] => { $ crate :: SyntaxKind :: CRATE_KW } ; [do] => { $ crate :: SyntaxKind :: DO_KW } ; [dyn] => { $ crate :: SyntaxKind :: DYN_KW } ; [else] => { $ crate :: SyntaxKind :: ELSE_KW } ; [enum] => { $ crate :: SyntaxKind :: ENUM_KW } ; [extern] => { $ crate :: SyntaxKind :: EXTERN_KW } ; [false] => { $ crate :: SyntaxKind :: FALSE_KW } ; [fn] => { $ crate :: SyntaxKind :: FN_KW } ; [for] => { $ crate :: SyntaxKind :: FOR_KW } ; [if] => { $ crate :: SyntaxKind :: IF_KW } ; [impl] => { $ crate :: SyntaxKind :: IMPL_KW } ; [in] => { $ crate :: SyntaxKind :: IN_KW } ; [let] => { $ crate :: SyntaxKind :: LET_KW } ; [loop] => { $ crate :: SyntaxKind :: LOOP_KW } ; [macro] => { $ crate :: SyntaxKind :: MACRO_KW } ; [match] => { $ crate :: SyntaxKind :: MATCH_KW } ; [mod] => { $ crate :: SyntaxKind :: MOD_KW } ; [move] => { $ crate :: SyntaxKind :: MOVE_KW } ; [mut] => { $ crate :: SyntaxKind :: MUT_KW } ; [pub] => { $ crate :: SyntaxKind :: PUB_KW } ; [ref] => { $ crate :: SyntaxKind :: REF_KW } ; [return] => { $ crate :: SyntaxKind :: RETURN_KW } ; [self] => { $ crate :: SyntaxKind :: SELF_KW } ; [Self] => { $ crate :: SyntaxKind :: SELF_TYPE_KW } ; [static] => { $ crate :: SyntaxKind :: STATIC_KW } ; [struct] => { $ crate :: SyntaxKind :: STRUCT_KW } ; [super] => { $ crate :: SyntaxKind :: SUPER_KW } ; [trait] => { $ crate :: SyntaxKind :: TRAIT_KW } ; [true] => { $ crate :: SyntaxKind :: TRUE_KW } ; [try] => { $ crate :: SyntaxKind :: TRY_KW } ; [type] => { $ crate :: SyntaxKind :: TYPE_KW } ; [unsafe] => { $ crate :: SyntaxKind :: UNSAFE_KW } ; [use] => { $ crate :: SyntaxKind :: USE_KW } ; [where] => { $ crate :: SyntaxKind :: WHERE_KW } ; [while] => { $ crate :: SyntaxKind :: WHILE_KW } ; [yield] => { $ crate :: SyntaxKind :: YIELD_KW } ; [auto] => { $ crate :: SyntaxKind :: AUTO_KW } ; [builtin] => { $ crate :: SyntaxKind :: BUILTIN_KW } ; [default] => { $ crate :: SyntaxKind :: DEFAULT_KW } ; [existential] => { $ crate :: SyntaxKind :: EXISTENTIAL_KW } ; [union] => { $ crate :: SyntaxKind :: UNION_KW } ; [raw] => { $ crate :: SyntaxKind :: RAW_KW } ; [macro_rules] => { $ crate :: SyntaxKind :: MACRO_RULES_KW } ; [yeet] => { $ crate :: SyntaxKind :: YEET_KW } ; [offset_of] => { $ crate :: SyntaxKind :: OFFSET_OF_KW } ; [asm] => { $ crate :: SyntaxKind :: ASM_KW } ; [format_args] => { $ crate :: SyntaxKind :: FORMAT_ARGS_KW } ; [lifetime_ident] => { $ crate :: SyntaxKind :: LIFETIME_IDENT } ; [ident] => { $ crate :: SyntaxKind :: IDENT } ; [shebang] => { $ crate :: SyntaxKind :: SHEBANG } ; }
+macro_rules ! T { [;] => { $ crate :: SyntaxKind :: SEMICOLON } ; [,] => { $ crate :: SyntaxKind :: COMMA } ; ['('] => { $ crate :: SyntaxKind :: L_PAREN } ; [')'] => { $ crate :: SyntaxKind :: R_PAREN } ; ['{'] => { $ crate :: SyntaxKind :: L_CURLY } ; ['}'] => { $ crate :: SyntaxKind :: R_CURLY } ; ['['] => { $ crate :: SyntaxKind :: L_BRACK } ; [']'] => { $ crate :: SyntaxKind :: R_BRACK } ; [<] => { $ crate :: SyntaxKind :: L_ANGLE } ; [>] => { $ crate :: SyntaxKind :: R_ANGLE } ; [@] => { $ crate :: SyntaxKind :: AT } ; [#] => { $ crate :: SyntaxKind :: POUND } ; [~] => { $ crate :: SyntaxKind :: TILDE } ; [?] => { $ crate :: SyntaxKind :: QUESTION } ; [$] => { $ crate :: SyntaxKind :: DOLLAR } ; [&] => { $ crate :: SyntaxKind :: AMP } ; [|] => { $ crate :: SyntaxKind :: PIPE } ; [+] => { $ crate :: SyntaxKind :: PLUS } ; [*] => { $ crate :: SyntaxKind :: STAR } ; [/] => { $ crate :: SyntaxKind :: SLASH } ; [^] => { $ crate :: SyntaxKind :: CARET } ; [%] => { $ crate :: SyntaxKind :: PERCENT } ; [_] => { $ crate :: SyntaxKind :: UNDERSCORE } ; [.] => { $ crate :: SyntaxKind :: DOT } ; [..] => { $ crate :: SyntaxKind :: DOT2 } ; [...] => { $ crate :: SyntaxKind :: DOT3 } ; [..=] => { $ crate :: SyntaxKind :: DOT2EQ } ; [:] => { $ crate :: SyntaxKind :: COLON } ; [::] => { $ crate :: SyntaxKind :: COLON2 } ; [=] => { $ crate :: SyntaxKind :: EQ } ; [==] => { $ crate :: SyntaxKind :: EQ2 } ; [=>] => { $ crate :: SyntaxKind :: FAT_ARROW } ; [!] => { $ crate :: SyntaxKind :: BANG } ; [!=] => { $ crate :: SyntaxKind :: NEQ } ; [-] => { $ crate :: SyntaxKind :: MINUS } ; [->] => { $ crate :: SyntaxKind :: THIN_ARROW } ; [<=] => { $ crate :: SyntaxKind :: LTEQ } ; [>=] => { $ crate :: SyntaxKind :: GTEQ } ; [+=] => { $ crate :: SyntaxKind :: PLUSEQ } ; [-=] => { $ crate :: SyntaxKind :: MINUSEQ } ; [|=] => { $ crate :: SyntaxKind :: PIPEEQ } ; [&=] => { $ crate :: SyntaxKind :: AMPEQ } ; [^=] => { $ crate :: SyntaxKind :: CARETEQ } ; [/=] => { $ crate :: SyntaxKind :: SLASHEQ } ; [*=] => { $ crate :: SyntaxKind :: STAREQ } ; [%=] => { $ crate :: SyntaxKind :: PERCENTEQ } ; [&&] => { $ crate :: SyntaxKind :: AMP2 } ; [||] => { $ crate :: SyntaxKind :: PIPE2 } ; [<<] => { $ crate :: SyntaxKind :: SHL } ; [>>] => { $ crate :: SyntaxKind :: SHR } ; [<<=] => { $ crate :: SyntaxKind :: SHLEQ } ; [>>=] => { $ crate :: SyntaxKind :: SHREQ } ; [as] => { $ crate :: SyntaxKind :: AS_KW } ; [async] => { $ crate :: SyntaxKind :: ASYNC_KW } ; [await] => { $ crate :: SyntaxKind :: AWAIT_KW } ; [box] => { $ crate :: SyntaxKind :: BOX_KW } ; [break] => { $ crate :: SyntaxKind :: BREAK_KW } ; [const] => { $ crate :: SyntaxKind :: CONST_KW } ; [continue] => { $ crate :: SyntaxKind :: CONTINUE_KW } ; [crate] => { $ crate :: SyntaxKind :: CRATE_KW } ; [do] => { $ crate :: SyntaxKind :: DO_KW } ; [dyn] => { $ crate :: SyntaxKind :: DYN_KW } ; [else] => { $ crate :: SyntaxKind :: ELSE_KW } ; [enum] => { $ crate :: SyntaxKind :: ENUM_KW } ; [extern] => { $ crate :: SyntaxKind :: EXTERN_KW } ; [false] => { $ crate :: SyntaxKind :: FALSE_KW } ; [fn] => { $ crate :: SyntaxKind :: FN_KW } ; [for] => { $ crate :: SyntaxKind :: FOR_KW } ; [if] => { $ crate :: SyntaxKind :: IF_KW } ; [impl] => { $ crate :: SyntaxKind :: IMPL_KW } ; [in] => { $ crate :: SyntaxKind :: IN_KW } ; [let] => { $ crate :: SyntaxKind :: LET_KW } ; [loop] => { $ crate :: SyntaxKind :: LOOP_KW } ; [macro] => { $ crate :: SyntaxKind :: MACRO_KW } ; [match] => { $ crate :: SyntaxKind :: MATCH_KW } ; [mod] => { $ crate :: SyntaxKind :: MOD_KW } ; [move] => { $ crate :: SyntaxKind :: MOVE_KW } ; [mut] => { $ crate :: SyntaxKind :: MUT_KW } ; [pub] => { $ crate :: SyntaxKind :: PUB_KW } ; [ref] => { $ crate :: SyntaxKind :: REF_KW } ; [return] => { $ crate :: SyntaxKind :: RETURN_KW } ; [become] => { $ crate :: SyntaxKind :: BECOME_KW } ; [self] => { $ crate :: SyntaxKind :: SELF_KW } ; [Self] => { $ crate :: SyntaxKind :: SELF_TYPE_KW } ; [static] => { $ crate :: SyntaxKind :: STATIC_KW } ; [struct] => { $ crate :: SyntaxKind :: STRUCT_KW } ; [super] => { $ crate :: SyntaxKind :: SUPER_KW } ; [trait] => { $ crate :: SyntaxKind :: TRAIT_KW } ; [true] => { $ crate :: SyntaxKind :: TRUE_KW } ; [try] => { $ crate :: SyntaxKind :: TRY_KW } ; [type] => { $ crate :: SyntaxKind :: TYPE_KW } ; [unsafe] => { $ crate :: SyntaxKind :: UNSAFE_KW } ; [use] => { $ crate :: SyntaxKind :: USE_KW } ; [where] => { $ crate :: SyntaxKind :: WHERE_KW } ; [while] => { $ crate :: SyntaxKind :: WHILE_KW } ; [yield] => { $ crate :: SyntaxKind :: YIELD_KW } ; [auto] => { $ crate :: SyntaxKind :: AUTO_KW } ; [builtin] => { $ crate :: SyntaxKind :: BUILTIN_KW } ; [default] => { $ crate :: SyntaxKind :: DEFAULT_KW } ; [existential] => { $ crate :: SyntaxKind :: EXISTENTIAL_KW } ; [union] => { $ crate :: SyntaxKind :: UNION_KW } ; [raw] => { $ crate :: SyntaxKind :: RAW_KW } ; [macro_rules] => { $ crate :: SyntaxKind :: MACRO_RULES_KW } ; [yeet] => { $ crate :: SyntaxKind :: YEET_KW } ; [offset_of] => { $ crate :: SyntaxKind :: OFFSET_OF_KW } ; [asm] => { $ crate :: SyntaxKind :: ASM_KW } ; [format_args] => { $ crate :: SyntaxKind :: FORMAT_ARGS_KW } ; [lifetime_ident] => { $ crate :: SyntaxKind :: LIFETIME_IDENT } ; [ident] => { $ crate :: SyntaxKind :: IDENT } ; [shebang] => { $ crate :: SyntaxKind :: SHEBANG } ; }
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/0014_record_literal_before_ellipsis_recovery.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/0014_record_literal_before_ellipsis_recovery.rast
index f511960040d..741b7845e7f 100644
--- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/0014_record_literal_before_ellipsis_recovery.rast
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/0014_record_literal_before_ellipsis_recovery.rast
@@ -24,26 +24,26 @@ SOURCE_FILE
             RECORD_EXPR_FIELD
               NAME_REF
                 IDENT "field"
-              WHITESPACE " "
-              RANGE_EXPR
-                DOT2 ".."
-                CALL_EXPR
-                  PATH_EXPR
-                    PATH
-                      PATH
-                        PATH_SEGMENT
-                          NAME_REF
-                            IDENT "S"
-                      COLON2 "::"
-                      PATH_SEGMENT
-                        NAME_REF
-                          IDENT "default"
-                  ARG_LIST
-                    L_PAREN "("
-                    R_PAREN ")"
+            WHITESPACE " "
+            DOT2 ".."
+            CALL_EXPR
+              PATH_EXPR
+                PATH
+                  PATH
+                    PATH_SEGMENT
+                      NAME_REF
+                        IDENT "S"
+                  COLON2 "::"
+                  PATH_SEGMENT
+                    NAME_REF
+                      IDENT "default"
+              ARG_LIST
+                L_PAREN "("
+                R_PAREN ")"
             WHITESPACE " "
             R_CURLY "}"
         WHITESPACE "\n"
         R_CURLY "}"
   WHITESPACE "\n"
-error 25: expected COLON
+error 25: expected `:`
+error 25: expected COMMA
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/0032_record_literal_field_eq_recovery.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/0032_record_literal_field_eq_recovery.rast
new file mode 100644
index 00000000000..ad4deeb0b67
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/0032_record_literal_field_eq_recovery.rast
@@ -0,0 +1,41 @@
+SOURCE_FILE
+  FN
+    FN_KW "fn"
+    WHITESPACE " "
+    NAME
+      IDENT "main"
+    PARAM_LIST
+      L_PAREN "("
+      R_PAREN ")"
+    WHITESPACE " "
+    BLOCK_EXPR
+      STMT_LIST
+        L_CURLY "{"
+        WHITESPACE "\n    "
+        RECORD_EXPR
+          PATH
+            PATH_SEGMENT
+              NAME_REF
+                IDENT "S"
+          WHITESPACE " "
+          RECORD_EXPR_FIELD_LIST
+            L_CURLY "{"
+            WHITESPACE " "
+            RECORD_EXPR_FIELD
+              NAME_REF
+                IDENT "field"
+              WHITESPACE " "
+              ERROR
+                EQ "="
+              WHITESPACE " "
+              PATH_EXPR
+                PATH
+                  PATH_SEGMENT
+                    NAME_REF
+                      IDENT "foo"
+            WHITESPACE " "
+            R_CURLY "}"
+        WHITESPACE "\n"
+        R_CURLY "}"
+  WHITESPACE "\n"
+error 26: expected `:`
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/0032_record_literal_field_eq_recovery.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/0032_record_literal_field_eq_recovery.rs
new file mode 100644
index 00000000000..1eb1aa9b926
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/0032_record_literal_field_eq_recovery.rs
@@ -0,0 +1,3 @@
+fn main() {
+    S { field = foo }
+}
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/0033_record_pat_field_eq_recovery.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/0033_record_pat_field_eq_recovery.rast
new file mode 100644
index 00000000000..6940a84b683
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/0033_record_pat_field_eq_recovery.rast
@@ -0,0 +1,43 @@
+SOURCE_FILE
+  FN
+    FN_KW "fn"
+    WHITESPACE " "
+    NAME
+      IDENT "main"
+    PARAM_LIST
+      L_PAREN "("
+      R_PAREN ")"
+    WHITESPACE " "
+    BLOCK_EXPR
+      STMT_LIST
+        L_CURLY "{"
+        WHITESPACE "\n    "
+        LET_STMT
+          LET_KW "let"
+          WHITESPACE " "
+          RECORD_PAT
+            PATH
+              PATH_SEGMENT
+                NAME_REF
+                  IDENT "S"
+            WHITESPACE " "
+            RECORD_PAT_FIELD_LIST
+              L_CURLY "{"
+              WHITESPACE " "
+              RECORD_PAT_FIELD
+                NAME_REF
+                  IDENT "field"
+                WHITESPACE " "
+                ERROR
+                  EQ "="
+                WHITESPACE " "
+                IDENT_PAT
+                  NAME
+                    IDENT "foo"
+              WHITESPACE " "
+              R_CURLY "}"
+          SEMICOLON ";"
+        WHITESPACE "\n"
+        R_CURLY "}"
+  WHITESPACE "\n"
+error 30: expected `:`
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/0033_record_pat_field_eq_recovery.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/0033_record_pat_field_eq_recovery.rs
new file mode 100644
index 00000000000..c4949d6e12e
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/0033_record_pat_field_eq_recovery.rs
@@ -0,0 +1,3 @@
+fn main() {
+    let S { field = foo };
+}
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0209_become_expr.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0209_become_expr.rast
new file mode 100644
index 00000000000..c544cf4e5e3
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0209_become_expr.rast
@@ -0,0 +1,31 @@
+SOURCE_FILE
+  FN
+    FN_KW "fn"
+    WHITESPACE " "
+    NAME
+      IDENT "foo"
+    PARAM_LIST
+      L_PAREN "("
+      R_PAREN ")"
+    WHITESPACE " "
+    BLOCK_EXPR
+      STMT_LIST
+        L_CURLY "{"
+        WHITESPACE "\n    "
+        EXPR_STMT
+          BECOME_EXPR
+            BECOME_KW "become"
+            WHITESPACE " "
+            CALL_EXPR
+              PATH_EXPR
+                PATH
+                  PATH_SEGMENT
+                    NAME_REF
+                      IDENT "foo"
+              ARG_LIST
+                L_PAREN "("
+                R_PAREN ")"
+          SEMICOLON ";"
+        WHITESPACE "\n"
+        R_CURLY "}"
+  WHITESPACE "\n"
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0209_become_expr.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0209_become_expr.rs
new file mode 100644
index 00000000000..918a83ca6e8
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0209_become_expr.rs
@@ -0,0 +1,3 @@
+fn foo() {
+    become foo();
+}
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0211_async_trait_bound.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0211_async_trait_bound.rast
new file mode 100644
index 00000000000..ebf758286a7
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0211_async_trait_bound.rast
@@ -0,0 +1,43 @@
+SOURCE_FILE
+  FN
+    FN_KW "fn"
+    WHITESPACE " "
+    NAME
+      IDENT "async_foo"
+    PARAM_LIST
+      L_PAREN "("
+      PARAM
+        WILDCARD_PAT
+          UNDERSCORE "_"
+        COLON ":"
+        WHITESPACE " "
+        IMPL_TRAIT_TYPE
+          IMPL_KW "impl"
+          WHITESPACE " "
+          TYPE_BOUND_LIST
+            TYPE_BOUND
+              ASYNC_KW "async"
+              WHITESPACE " "
+              PATH_TYPE
+                PATH
+                  PATH_SEGMENT
+                    NAME_REF
+                      IDENT "Fn"
+                    PARAM_LIST
+                      L_PAREN "("
+                      PARAM
+                        REF_TYPE
+                          AMP "&"
+                          PATH_TYPE
+                            PATH
+                              PATH_SEGMENT
+                                NAME_REF
+                                  IDENT "i32"
+                      R_PAREN ")"
+      R_PAREN ")"
+    WHITESPACE " "
+    BLOCK_EXPR
+      STMT_LIST
+        L_CURLY "{"
+        R_CURLY "}"
+  WHITESPACE "\n"
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0211_async_trait_bound.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0211_async_trait_bound.rs
new file mode 100644
index 00000000000..04d44175d77
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0211_async_trait_bound.rs
@@ -0,0 +1 @@
+fn async_foo(_: impl async Fn(&i32)) {}
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0212_const_trait_bound.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0212_const_trait_bound.rast
new file mode 100644
index 00000000000..646873881bc
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0212_const_trait_bound.rast
@@ -0,0 +1,34 @@
+SOURCE_FILE
+  FN
+    CONST_KW "const"
+    WHITESPACE " "
+    FN_KW "fn"
+    WHITESPACE " "
+    NAME
+      IDENT "foo"
+    PARAM_LIST
+      L_PAREN "("
+      PARAM
+        WILDCARD_PAT
+          UNDERSCORE "_"
+        COLON ":"
+        WHITESPACE " "
+        IMPL_TRAIT_TYPE
+          IMPL_KW "impl"
+          WHITESPACE " "
+          TYPE_BOUND_LIST
+            TYPE_BOUND
+              CONST_KW "const"
+              WHITESPACE " "
+              PATH_TYPE
+                PATH
+                  PATH_SEGMENT
+                    NAME_REF
+                      IDENT "Trait"
+      R_PAREN ")"
+    WHITESPACE " "
+    BLOCK_EXPR
+      STMT_LIST
+        L_CURLY "{"
+        R_CURLY "}"
+  WHITESPACE "\n"
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0212_const_trait_bound.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0212_const_trait_bound.rs
new file mode 100644
index 00000000000..8eb8f84c91f
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0212_const_trait_bound.rs
@@ -0,0 +1 @@
+const fn foo(_: impl const Trait) {}
diff --git a/src/tools/rust-analyzer/crates/proc-macro-api/src/lib.rs b/src/tools/rust-analyzer/crates/proc-macro-api/src/lib.rs
index 1dadfc40ac4..6b16711a8d8 100644
--- a/src/tools/rust-analyzer/crates/proc-macro-api/src/lib.rs
+++ b/src/tools/rust-analyzer/crates/proc-macro-api/src/lib.rs
@@ -13,6 +13,7 @@ mod version;
 
 use indexmap::IndexSet;
 use paths::AbsPathBuf;
+use rustc_hash::FxHashMap;
 use span::Span;
 use std::{
     fmt, io,
@@ -107,8 +108,11 @@ pub struct MacroPanic {
 
 impl ProcMacroServer {
     /// Spawns an external process as the proc macro server and returns a client connected to it.
-    pub fn spawn(process_path: AbsPathBuf) -> io::Result<ProcMacroServer> {
-        let process = ProcMacroProcessSrv::run(process_path)?;
+    pub fn spawn(
+        process_path: AbsPathBuf,
+        env: &FxHashMap<String, String>,
+    ) -> io::Result<ProcMacroServer> {
+        let process = ProcMacroProcessSrv::run(process_path, env)?;
         Ok(ProcMacroServer { process: Arc::new(Mutex::new(process)) })
     }
 
diff --git a/src/tools/rust-analyzer/crates/proc-macro-api/src/process.rs b/src/tools/rust-analyzer/crates/proc-macro-api/src/process.rs
index 96f97bf5e20..12eafcea442 100644
--- a/src/tools/rust-analyzer/crates/proc-macro-api/src/process.rs
+++ b/src/tools/rust-analyzer/crates/proc-macro-api/src/process.rs
@@ -7,6 +7,7 @@ use std::{
 };
 
 use paths::{AbsPath, AbsPathBuf};
+use rustc_hash::FxHashMap;
 use stdx::JodChild;
 
 use crate::{
@@ -26,9 +27,12 @@ pub(crate) struct ProcMacroProcessSrv {
 }
 
 impl ProcMacroProcessSrv {
-    pub(crate) fn run(process_path: AbsPathBuf) -> io::Result<ProcMacroProcessSrv> {
+    pub(crate) fn run(
+        process_path: AbsPathBuf,
+        env: &FxHashMap<String, String>,
+    ) -> io::Result<ProcMacroProcessSrv> {
         let create_srv = |null_stderr| {
-            let mut process = Process::run(process_path.clone(), null_stderr)?;
+            let mut process = Process::run(process_path.clone(), env, null_stderr)?;
             let (stdin, stdout) = process.stdio().expect("couldn't access child stdio");
 
             io::Result::Ok(ProcMacroProcessSrv {
@@ -147,8 +151,12 @@ struct Process {
 }
 
 impl Process {
-    fn run(path: AbsPathBuf, null_stderr: bool) -> io::Result<Process> {
-        let child = JodChild(mk_child(&path, null_stderr)?);
+    fn run(
+        path: AbsPathBuf,
+        env: &FxHashMap<String, String>,
+        null_stderr: bool,
+    ) -> io::Result<Process> {
+        let child = JodChild(mk_child(&path, env, null_stderr)?);
         Ok(Process { child })
     }
 
@@ -161,9 +169,14 @@ impl Process {
     }
 }
 
-fn mk_child(path: &AbsPath, null_stderr: bool) -> io::Result<Child> {
+fn mk_child(
+    path: &AbsPath,
+    env: &FxHashMap<String, String>,
+    null_stderr: bool,
+) -> io::Result<Child> {
     let mut cmd = Command::new(path.as_os_str());
-    cmd.env("RUST_ANALYZER_INTERNALS_DO_NOT_USE", "this is unstable")
+    cmd.envs(env)
+        .env("RUST_ANALYZER_INTERNALS_DO_NOT_USE", "this is unstable")
         .stdin(Stdio::piped())
         .stdout(Stdio::piped())
         .stderr(if null_stderr { Stdio::null() } else { Stdio::inherit() });
diff --git a/src/tools/rust-analyzer/crates/proc-macro-srv/Cargo.toml b/src/tools/rust-analyzer/crates/proc-macro-srv/Cargo.toml
index ba17ea6f7b4..bd7a3165458 100644
--- a/src/tools/rust-analyzer/crates/proc-macro-srv/Cargo.toml
+++ b/src/tools/rust-analyzer/crates/proc-macro-srv/Cargo.toml
@@ -29,6 +29,7 @@ paths.workspace = true
 base-db.workspace = true
 span.workspace = true
 proc-macro-api.workspace = true
+ra-ap-rustc_lexer.workspace = true
 
 [dev-dependencies]
 expect-test = "1.4.0"
diff --git a/src/tools/rust-analyzer/crates/proc-macro-srv/src/lib.rs b/src/tools/rust-analyzer/crates/proc-macro-srv/src/lib.rs
index 460a96c07f3..831632c64c0 100644
--- a/src/tools/rust-analyzer/crates/proc-macro-srv/src/lib.rs
+++ b/src/tools/rust-analyzer/crates/proc-macro-srv/src/lib.rs
@@ -20,6 +20,11 @@ extern crate proc_macro;
 #[cfg(feature = "in-rust-tree")]
 extern crate rustc_driver as _;
 
+#[cfg(not(feature = "in-rust-tree"))]
+extern crate ra_ap_rustc_lexer as rustc_lexer;
+#[cfg(feature = "in-rust-tree")]
+extern crate rustc_lexer;
+
 mod dylib;
 mod proc_macros;
 mod server;
diff --git a/src/tools/rust-analyzer/crates/proc-macro-srv/src/server/rust_analyzer_span.rs b/src/tools/rust-analyzer/crates/proc-macro-srv/src/server/rust_analyzer_span.rs
index 8a9d52a37a2..c6a0a666555 100644
--- a/src/tools/rust-analyzer/crates/proc-macro-srv/src/server/rust_analyzer_span.rs
+++ b/src/tools/rust-analyzer/crates/proc-macro-srv/src/server/rust_analyzer_span.rs
@@ -70,11 +70,58 @@ impl server::FreeFunctions for RaSpanServer {
         &mut self,
         s: &str,
     ) -> Result<bridge::Literal<Self::Span, Self::Symbol>, ()> {
-        // FIXME: keep track of LitKind and Suffix
+        use proc_macro::bridge::LitKind;
+        use rustc_lexer::{LiteralKind, Token, TokenKind};
+
+        let mut tokens = rustc_lexer::tokenize(s);
+        let minus_or_lit = tokens.next().unwrap_or(Token { kind: TokenKind::Eof, len: 0 });
+
+        let lit = if minus_or_lit.kind == TokenKind::Minus {
+            let lit = tokens.next().ok_or(())?;
+            if !matches!(
+                lit.kind,
+                TokenKind::Literal {
+                    kind: LiteralKind::Int { .. } | LiteralKind::Float { .. },
+                    ..
+                }
+            ) {
+                return Err(());
+            }
+            lit
+        } else {
+            minus_or_lit
+        };
+
+        if tokens.next().is_some() {
+            return Err(());
+        }
+
+        let TokenKind::Literal { kind, suffix_start } = lit.kind else { return Err(()) };
+        let kind = match kind {
+            LiteralKind::Int { .. } => LitKind::Integer,
+            LiteralKind::Float { .. } => LitKind::Float,
+            LiteralKind::Char { .. } => LitKind::Char,
+            LiteralKind::Byte { .. } => LitKind::Byte,
+            LiteralKind::Str { .. } => LitKind::Str,
+            LiteralKind::ByteStr { .. } => LitKind::ByteStr,
+            LiteralKind::CStr { .. } => LitKind::CStr,
+            LiteralKind::RawStr { n_hashes } => LitKind::StrRaw(n_hashes.unwrap_or_default()),
+            LiteralKind::RawByteStr { n_hashes } => {
+                LitKind::ByteStrRaw(n_hashes.unwrap_or_default())
+            }
+            LiteralKind::RawCStr { n_hashes } => LitKind::CStrRaw(n_hashes.unwrap_or_default()),
+        };
+
+        let (lit, suffix) = s.split_at(suffix_start as usize);
+        let suffix = match suffix {
+            "" | "_" => None,
+            suffix => Some(Symbol::intern(self.interner, suffix)),
+        };
+
         Ok(bridge::Literal {
-            kind: bridge::LitKind::Integer, // dummy
-            symbol: Symbol::intern(self.interner, s),
-            suffix: None,
+            kind,
+            symbol: Symbol::intern(self.interner, lit),
+            suffix,
             span: self.call_site,
         })
     }
diff --git a/src/tools/rust-analyzer/crates/proc-macro-srv/src/server/token_id.rs b/src/tools/rust-analyzer/crates/proc-macro-srv/src/server/token_id.rs
index 15a9e0deae4..7e9d8057ac9 100644
--- a/src/tools/rust-analyzer/crates/proc-macro-srv/src/server/token_id.rs
+++ b/src/tools/rust-analyzer/crates/proc-macro-srv/src/server/token_id.rs
@@ -62,11 +62,58 @@ impl server::FreeFunctions for TokenIdServer {
         &mut self,
         s: &str,
     ) -> Result<bridge::Literal<Self::Span, Self::Symbol>, ()> {
-        // FIXME: keep track of LitKind and Suffix
+        use proc_macro::bridge::LitKind;
+        use rustc_lexer::{LiteralKind, Token, TokenKind};
+
+        let mut tokens = rustc_lexer::tokenize(s);
+        let minus_or_lit = tokens.next().unwrap_or(Token { kind: TokenKind::Eof, len: 0 });
+
+        let lit = if minus_or_lit.kind == TokenKind::Minus {
+            let lit = tokens.next().ok_or(())?;
+            if !matches!(
+                lit.kind,
+                TokenKind::Literal {
+                    kind: LiteralKind::Int { .. } | LiteralKind::Float { .. },
+                    ..
+                }
+            ) {
+                return Err(());
+            }
+            lit
+        } else {
+            minus_or_lit
+        };
+
+        if tokens.next().is_some() {
+            return Err(());
+        }
+
+        let TokenKind::Literal { kind, suffix_start } = lit.kind else { return Err(()) };
+        let kind = match kind {
+            LiteralKind::Int { .. } => LitKind::Integer,
+            LiteralKind::Float { .. } => LitKind::Float,
+            LiteralKind::Char { .. } => LitKind::Char,
+            LiteralKind::Byte { .. } => LitKind::Byte,
+            LiteralKind::Str { .. } => LitKind::Str,
+            LiteralKind::ByteStr { .. } => LitKind::ByteStr,
+            LiteralKind::CStr { .. } => LitKind::CStr,
+            LiteralKind::RawStr { n_hashes } => LitKind::StrRaw(n_hashes.unwrap_or_default()),
+            LiteralKind::RawByteStr { n_hashes } => {
+                LitKind::ByteStrRaw(n_hashes.unwrap_or_default())
+            }
+            LiteralKind::RawCStr { n_hashes } => LitKind::CStrRaw(n_hashes.unwrap_or_default()),
+        };
+
+        let (lit, suffix) = s.split_at(suffix_start as usize);
+        let suffix = match suffix {
+            "" | "_" => None,
+            suffix => Some(Symbol::intern(self.interner, suffix)),
+        };
+
         Ok(bridge::Literal {
-            kind: bridge::LitKind::Integer, // dummy
-            symbol: Symbol::intern(self.interner, s),
-            suffix: None,
+            kind,
+            symbol: Symbol::intern(self.interner, lit),
+            suffix,
             span: self.call_site,
         })
     }
diff --git a/src/tools/rust-analyzer/crates/proc-macro-srv/src/tests/mod.rs b/src/tools/rust-analyzer/crates/proc-macro-srv/src/tests/mod.rs
index 87d832cc76f..e5bfe5ee92c 100644
--- a/src/tools/rust-analyzer/crates/proc-macro-srv/src/tests/mod.rs
+++ b/src/tools/rust-analyzer/crates/proc-macro-srv/src/tests/mod.rs
@@ -169,8 +169,8 @@ fn test_fn_like_mk_idents() {
 fn test_fn_like_macro_clone_literals() {
     assert_expand(
         "fn_like_clone_tokens",
-        r#"1u16, 2_u32, -4i64, 3.14f32, "hello bridge""#,
-        expect![[r#"
+        r###"1u16, 2_u32, -4i64, 3.14f32, "hello bridge", "suffixed"suffix, r##"raw"##"###,
+        expect![[r###"
             SUBTREE $$ 1 1
               LITERAL 1u16 1
               PUNCH   , [alone] 1
@@ -181,8 +181,12 @@ fn test_fn_like_macro_clone_literals() {
               PUNCH   , [alone] 1
               LITERAL 3.14f32 1
               PUNCH   , [alone] 1
-              LITERAL "hello bridge" 1"#]],
-        expect![[r#"
+              LITERAL ""hello bridge"" 1
+              PUNCH   , [alone] 1
+              LITERAL ""suffixed""suffix 1
+              PUNCH   , [alone] 1
+              LITERAL r##"r##"raw"##"## 1"###]],
+        expect![[r###"
             SUBTREE $$ SpanData { range: 0..100, anchor: SpanAnchor(FileId(42), 2), ctx: SyntaxContextId(0) } SpanData { range: 0..100, anchor: SpanAnchor(FileId(42), 2), ctx: SyntaxContextId(0) }
               LITERAL 1u16 SpanData { range: 0..4, anchor: SpanAnchor(FileId(42), 2), ctx: SyntaxContextId(0) }
               PUNCH   , [alone] SpanData { range: 4..5, anchor: SpanAnchor(FileId(42), 2), ctx: SyntaxContextId(0) }
@@ -193,7 +197,11 @@ fn test_fn_like_macro_clone_literals() {
               PUNCH   , [alone] SpanData { range: 18..19, anchor: SpanAnchor(FileId(42), 2), ctx: SyntaxContextId(0) }
               LITERAL 3.14f32 SpanData { range: 20..27, anchor: SpanAnchor(FileId(42), 2), ctx: SyntaxContextId(0) }
               PUNCH   , [alone] SpanData { range: 27..28, anchor: SpanAnchor(FileId(42), 2), ctx: SyntaxContextId(0) }
-              LITERAL "hello bridge" SpanData { range: 29..43, anchor: SpanAnchor(FileId(42), 2), ctx: SyntaxContextId(0) }"#]],
+              LITERAL ""hello bridge"" SpanData { range: 29..43, anchor: SpanAnchor(FileId(42), 2), ctx: SyntaxContextId(0) }
+              PUNCH   , [alone] SpanData { range: 43..44, anchor: SpanAnchor(FileId(42), 2), ctx: SyntaxContextId(0) }
+              LITERAL ""suffixed""suffix SpanData { range: 45..61, anchor: SpanAnchor(FileId(42), 2), ctx: SyntaxContextId(0) }
+              PUNCH   , [alone] SpanData { range: 61..62, anchor: SpanAnchor(FileId(42), 2), ctx: SyntaxContextId(0) }
+              LITERAL r##"r##"raw"##"## SpanData { range: 63..73, anchor: SpanAnchor(FileId(42), 2), ctx: SyntaxContextId(0) }"###]],
     );
 }
 
diff --git a/src/tools/rust-analyzer/crates/project-model/src/build_scripts.rs b/src/tools/rust-analyzer/crates/project-model/src/build_scripts.rs
index a2c9856a3f7..ab72f1fba09 100644
--- a/src/tools/rust-analyzer/crates/project-model/src/build_scripts.rs
+++ b/src/tools/rust-analyzer/crates/project-model/src/build_scripts.rs
@@ -20,10 +20,11 @@ use paths::{AbsPath, AbsPathBuf};
 use rustc_hash::{FxHashMap, FxHashSet};
 use semver::Version;
 use serde::Deserialize;
+use toolchain::Tool;
 
 use crate::{
     cfg_flag::CfgFlag, utf8_stdout, CargoConfig, CargoFeatures, CargoWorkspace, InvocationLocation,
-    InvocationStrategy, Package,
+    InvocationStrategy, Package, Sysroot, TargetKind,
 };
 
 #[derive(Debug, Default, Clone, PartialEq, Eq)]
@@ -61,6 +62,7 @@ impl WorkspaceBuildScripts {
         config: &CargoConfig,
         allowed_features: &FxHashSet<String>,
         workspace_root: &AbsPathBuf,
+        sysroot: Option<&Sysroot>,
     ) -> io::Result<Command> {
         let mut cmd = match config.run_build_script_command.as_deref() {
             Some([program, args @ ..]) => {
@@ -69,7 +71,8 @@ impl WorkspaceBuildScripts {
                 cmd
             }
             _ => {
-                let mut cmd = Command::new(toolchain::cargo());
+                let mut cmd = Command::new(Tool::Cargo.path());
+                Sysroot::set_rustup_toolchain_env(&mut cmd, sysroot);
 
                 cmd.args(["check", "--quiet", "--workspace", "--message-format=json"]);
                 cmd.args(&config.extra_args);
@@ -133,6 +136,7 @@ impl WorkspaceBuildScripts {
         workspace: &CargoWorkspace,
         progress: &dyn Fn(String),
         toolchain: &Option<Version>,
+        sysroot: Option<&Sysroot>,
     ) -> io::Result<WorkspaceBuildScripts> {
         const RUST_1_62: Version = Version::new(1, 62, 0);
 
@@ -151,6 +155,7 @@ impl WorkspaceBuildScripts {
                 config,
                 &allowed_features,
                 &workspace.workspace_root().to_path_buf(),
+                sysroot,
             )?,
             workspace,
             current_dir,
@@ -165,6 +170,7 @@ impl WorkspaceBuildScripts {
                     config,
                     &allowed_features,
                     &workspace.workspace_root().to_path_buf(),
+                    sysroot,
                 )?;
                 cmd.args(["-Z", "unstable-options", "--keep-going"]).env("RUSTC_BOOTSTRAP", "1");
                 let mut res = Self::run_per_ws(cmd, workspace, current_dir, progress)?;
@@ -194,7 +200,7 @@ impl WorkspaceBuildScripts {
                 ))
             }
         };
-        let cmd = Self::build_command(config, &Default::default(), workspace_root)?;
+        let cmd = Self::build_command(config, &Default::default(), workspace_root, None)?;
         // NB: Cargo.toml could have been modified between `cargo metadata` and
         // `cargo check`. We shouldn't assume that package ids we see here are
         // exactly those from `config`.
@@ -415,6 +421,7 @@ impl WorkspaceBuildScripts {
         rustc: &CargoWorkspace,
         current_dir: &AbsPath,
         extra_env: &FxHashMap<String, String>,
+        sysroot: Option<&Sysroot>,
     ) -> Self {
         let mut bs = WorkspaceBuildScripts::default();
         for p in rustc.packages() {
@@ -422,7 +429,8 @@ impl WorkspaceBuildScripts {
         }
         let res = (|| {
             let target_libdir = (|| {
-                let mut cargo_config = Command::new(toolchain::cargo());
+                let mut cargo_config = Command::new(Tool::Cargo.path());
+                Sysroot::set_rustup_toolchain_env(&mut cargo_config, sysroot);
                 cargo_config.envs(extra_env);
                 cargo_config
                     .current_dir(current_dir)
@@ -431,7 +439,8 @@ impl WorkspaceBuildScripts {
                 if let Ok(it) = utf8_stdout(cargo_config) {
                     return Ok(it);
                 }
-                let mut cmd = Command::new(toolchain::rustc());
+                let mut cmd = Command::new(Tool::Rustc.path());
+                Sysroot::set_rustup_toolchain_env(&mut cmd, sysroot);
                 cmd.envs(extra_env);
                 cmd.args(["--print", "target-libdir"]);
                 utf8_stdout(cmd)
@@ -458,7 +467,11 @@ impl WorkspaceBuildScripts {
                 .collect();
             for p in rustc.packages() {
                 let package = &rustc[p];
-                if package.targets.iter().any(|&it| rustc[it].is_proc_macro) {
+                if package
+                    .targets
+                    .iter()
+                    .any(|&it| matches!(rustc[it].kind, TargetKind::Lib { is_proc_macro: true }))
+                {
                     if let Some((_, path)) = proc_macro_dylibs
                         .iter()
                         .find(|(name, _)| *name.trim_start_matches("lib") == package.name)
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 a99ee6e664c..08d86fd7b0f 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
@@ -12,8 +12,9 @@ use paths::{AbsPath, AbsPathBuf};
 use rustc_hash::{FxHashMap, FxHashSet};
 use serde::Deserialize;
 use serde_json::from_value;
+use toolchain::Tool;
 
-use crate::{utf8_stdout, InvocationLocation, ManifestPath};
+use crate::{utf8_stdout, InvocationLocation, ManifestPath, Sysroot};
 use crate::{CfgOverrides, InvocationStrategy};
 
 /// [`CargoWorkspace`] represents the logical structure of, well, a Cargo
@@ -188,8 +189,6 @@ pub struct TargetData {
     pub root: AbsPathBuf,
     /// Kind of target
     pub kind: TargetKind,
-    /// Is this target a proc-macro
-    pub is_proc_macro: bool,
     /// Required features of the target without which it won't build
     pub required_features: Vec<String>,
 }
@@ -198,7 +197,10 @@ pub struct TargetData {
 pub enum TargetKind {
     Bin,
     /// Any kind of Cargo lib crate-type (dylib, rlib, proc-macro, ...).
-    Lib,
+    Lib {
+        /// Is this target a proc-macro
+        is_proc_macro: bool,
+    },
     Example,
     Test,
     Bench,
@@ -215,8 +217,8 @@ impl TargetKind {
                 "bench" => TargetKind::Bench,
                 "example" => TargetKind::Example,
                 "custom-build" => TargetKind::BuildScript,
-                "proc-macro" => TargetKind::Lib,
-                _ if kind.contains("lib") => TargetKind::Lib,
+                "proc-macro" => TargetKind::Lib { is_proc_macro: true },
+                _ if kind.contains("lib") => TargetKind::Lib { is_proc_macro: false },
                 _ => continue,
             };
         }
@@ -236,12 +238,13 @@ impl CargoWorkspace {
         cargo_toml: &ManifestPath,
         current_dir: &AbsPath,
         config: &CargoConfig,
+        sysroot: Option<&Sysroot>,
         progress: &dyn Fn(String),
     ) -> anyhow::Result<cargo_metadata::Metadata> {
-        let targets = find_list_of_build_targets(config, cargo_toml);
+        let targets = find_list_of_build_targets(config, cargo_toml, sysroot);
 
         let mut meta = MetadataCommand::new();
-        meta.cargo_path(toolchain::cargo());
+        meta.cargo_path(Tool::Cargo.path());
         meta.manifest_path(cargo_toml.to_path_buf());
         match &config.features {
             CargoFeatures::All => {
@@ -289,6 +292,7 @@ impl CargoWorkspace {
 
         (|| -> Result<cargo_metadata::Metadata, cargo_metadata::Error> {
             let mut command = meta.cargo_command();
+            Sysroot::set_rustup_toolchain_env(&mut command, sysroot);
             command.envs(&config.extra_env);
             let output = command.output()?;
             if !output.status.success() {
@@ -368,7 +372,6 @@ impl CargoWorkspace {
                     name,
                     root: AbsPathBuf::assert(src_path.into()),
                     kind: TargetKind::new(&kind),
-                    is_proc_macro: *kind == ["proc-macro"],
                     required_features,
                 });
                 pkg_data.targets.push(tgt);
@@ -476,24 +479,30 @@ impl CargoWorkspace {
     }
 }
 
-fn find_list_of_build_targets(config: &CargoConfig, cargo_toml: &ManifestPath) -> Vec<String> {
+fn find_list_of_build_targets(
+    config: &CargoConfig,
+    cargo_toml: &ManifestPath,
+    sysroot: Option<&Sysroot>,
+) -> Vec<String> {
     if let Some(target) = &config.target {
         return [target.into()].to_vec();
     }
 
-    let build_targets = cargo_config_build_target(cargo_toml, &config.extra_env);
+    let build_targets = cargo_config_build_target(cargo_toml, &config.extra_env, sysroot);
     if !build_targets.is_empty() {
         return build_targets;
     }
 
-    rustc_discover_host_triple(cargo_toml, &config.extra_env).into_iter().collect()
+    rustc_discover_host_triple(cargo_toml, &config.extra_env, sysroot).into_iter().collect()
 }
 
 fn rustc_discover_host_triple(
     cargo_toml: &ManifestPath,
     extra_env: &FxHashMap<String, String>,
+    sysroot: Option<&Sysroot>,
 ) -> Option<String> {
-    let mut rustc = Command::new(toolchain::rustc());
+    let mut rustc = Command::new(Tool::Rustc.path());
+    Sysroot::set_rustup_toolchain_env(&mut rustc, sysroot);
     rustc.envs(extra_env);
     rustc.current_dir(cargo_toml.parent()).arg("-vV");
     tracing::debug!("Discovering host platform by {:?}", rustc);
@@ -519,8 +528,10 @@ fn rustc_discover_host_triple(
 fn cargo_config_build_target(
     cargo_toml: &ManifestPath,
     extra_env: &FxHashMap<String, String>,
+    sysroot: Option<&Sysroot>,
 ) -> Vec<String> {
-    let mut cargo_config = Command::new(toolchain::cargo());
+    let mut cargo_config = Command::new(Tool::Cargo.path());
+    Sysroot::set_rustup_toolchain_env(&mut cargo_config, sysroot);
     cargo_config.envs(extra_env);
     cargo_config
         .current_dir(cargo_toml.parent())
diff --git a/src/tools/rust-analyzer/crates/project-model/src/project_json.rs b/src/tools/rust-analyzer/crates/project-model/src/project_json.rs
index cf3231498f3..fba0aaa8ce9 100644
--- a/src/tools/rust-analyzer/crates/project-model/src/project_json.rs
+++ b/src/tools/rust-analyzer/crates/project-model/src/project_json.rs
@@ -49,7 +49,7 @@
 //! user explores them belongs to that extension (it's totally valid to change
 //! rust-project.json over time via configuration request!)
 
-use base_db::{CrateDisplayName, CrateId, CrateName, Dependency, DependencyKind, Edition};
+use base_db::{CrateDisplayName, CrateId, CrateName, Dependency, Edition};
 use la_arena::RawIdx;
 use paths::{AbsPath, AbsPathBuf};
 use rustc_hash::FxHashMap;
@@ -135,7 +135,6 @@ impl ProjectJson {
                                 Dependency::new(
                                     dep_data.name,
                                     CrateId::from_raw(RawIdx::from(dep_data.krate as u32)),
-                                    DependencyKind::Normal,
                                 )
                             })
                             .collect::<Vec<_>>(),
diff --git a/src/tools/rust-analyzer/crates/project-model/src/rustc_cfg.rs b/src/tools/rust-analyzer/crates/project-model/src/rustc_cfg.rs
index 0aee002fbb3..1ad6e7255bf 100644
--- a/src/tools/rust-analyzer/crates/project-model/src/rustc_cfg.rs
+++ b/src/tools/rust-analyzer/crates/project-model/src/rustc_cfg.rs
@@ -8,17 +8,13 @@ use rustc_hash::FxHashMap;
 use crate::{cfg_flag::CfgFlag, utf8_stdout, ManifestPath, Sysroot};
 
 /// Determines how `rustc --print cfg` is discovered and invoked.
-///
-/// There options are supported:
-/// - [`RustcCfgConfig::Cargo`], which relies on `cargo rustc --print cfg`
-///   and `RUSTC_BOOTSTRAP`.
-/// - [`RustcCfgConfig::Explicit`], which uses an explicit path to the `rustc`
-///   binary in the sysroot.
-/// - [`RustcCfgConfig::Discover`], which uses [`toolchain::rustc`].
 pub(crate) enum RustcCfgConfig<'a> {
-    Cargo(&'a ManifestPath),
-    Explicit(&'a Sysroot),
-    Discover,
+    /// Use `rustc --print cfg`, either from with the binary from the sysroot or by discovering via
+    /// [`toolchain::rustc`].
+    Rustc(Option<&'a Sysroot>),
+    /// Use `cargo --print cfg`, either from with the binary from the sysroot or by discovering via
+    /// [`toolchain::cargo`].
+    Cargo(Option<&'a Sysroot>, &'a ManifestPath),
 }
 
 pub(crate) fn get(
@@ -71,9 +67,10 @@ fn get_rust_cfgs(
     extra_env: &FxHashMap<String, String>,
     config: RustcCfgConfig<'_>,
 ) -> anyhow::Result<String> {
-    let mut cmd = match config {
-        RustcCfgConfig::Cargo(cargo_toml) => {
-            let mut cmd = Command::new(toolchain::cargo());
+    let sysroot = match config {
+        RustcCfgConfig::Cargo(sysroot, cargo_toml) => {
+            let mut cmd = Command::new(toolchain::Tool::Cargo.path());
+            Sysroot::set_rustup_toolchain_env(&mut cmd, sysroot);
             cmd.envs(extra_env);
             cmd.current_dir(cargo_toml.parent())
                 .args(["rustc", "-Z", "unstable-options", "--print", "cfg"])
@@ -82,25 +79,24 @@ fn get_rust_cfgs(
                 cmd.args(["--target", target]);
             }
 
-            return utf8_stdout(cmd).context("Unable to run `cargo rustc`");
-        }
-        RustcCfgConfig::Explicit(sysroot) => {
-            let rustc: std::path::PathBuf = sysroot.discover_rustc()?.into();
-            tracing::debug!(?rustc, "using explicit rustc from sysroot");
-            Command::new(rustc)
-        }
-        RustcCfgConfig::Discover => {
-            let rustc = toolchain::rustc();
-            tracing::debug!(?rustc, "using rustc from env");
-            Command::new(rustc)
+            match utf8_stdout(cmd) {
+                Ok(it) => return Ok(it),
+                Err(e) => {
+                    tracing::warn!("failed to run `cargo rustc --print cfg`, falling back to invoking rustc directly: {e}");
+                    sysroot
+                }
+            }
         }
+        RustcCfgConfig::Rustc(sysroot) => sysroot,
     };
 
+    let mut cmd = Command::new(toolchain::Tool::Rustc.path());
+    Sysroot::set_rustup_toolchain_env(&mut cmd, sysroot);
     cmd.envs(extra_env);
     cmd.args(["--print", "cfg", "-O"]);
     if let Some(target) = target {
         cmd.args(["--target", target]);
     }
 
-    utf8_stdout(cmd).context("Unable to run `rustc`")
+    utf8_stdout(cmd).context("unable to fetch cfgs via `rustc --print cfg -O`")
 }
diff --git a/src/tools/rust-analyzer/crates/project-model/src/sysroot.rs b/src/tools/rust-analyzer/crates/project-model/src/sysroot.rs
index 9e19a525838..07cfaba2d2c 100644
--- a/src/tools/rust-analyzer/crates/project-model/src/sysroot.rs
+++ b/src/tools/rust-analyzer/crates/project-model/src/sysroot.rs
@@ -4,24 +4,38 @@
 //! but we can't process `.rlib` and need source code instead. The source code
 //! is typically installed with `rustup component add rust-src` command.
 
-use std::{env, fs, iter, ops, path::PathBuf, process::Command};
+use std::{env, fs, iter, ops, path::PathBuf, process::Command, sync::Arc};
 
-use anyhow::{format_err, Context, Result};
+use anyhow::{format_err, Result};
 use base_db::CrateName;
 use itertools::Itertools;
 use la_arena::{Arena, Idx};
 use paths::{AbsPath, AbsPathBuf};
 use rustc_hash::FxHashMap;
+use toolchain::probe_for_binary;
 
 use crate::{utf8_stdout, CargoConfig, CargoWorkspace, ManifestPath};
 
-#[derive(Debug, Clone, Eq, PartialEq)]
+#[derive(Debug, Clone)]
 pub struct Sysroot {
     root: AbsPathBuf,
-    src_root: AbsPathBuf,
+    src_root: Option<Result<AbsPathBuf, Arc<anyhow::Error>>>,
     mode: SysrootMode,
 }
 
+impl Eq for Sysroot {}
+impl PartialEq for Sysroot {
+    fn eq(&self, other: &Self) -> bool {
+        self.root == other.root
+            && self.mode == other.mode
+            && match (&self.src_root, &other.src_root) {
+                (Some(Ok(this)), Some(Ok(other))) => this == other,
+                (None, None) | (Some(Err(_)), Some(Err(_))) => true,
+                _ => false,
+            }
+    }
+}
+
 #[derive(Debug, Clone, Eq, PartialEq)]
 pub(crate) enum SysrootMode {
     Workspace(CargoWorkspace),
@@ -86,8 +100,8 @@ impl Sysroot {
 
     /// Returns the sysroot "source" directory, where stdlib sources are located, like:
     /// `$HOME/.rustup/toolchains/nightly-2022-07-23-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library`
-    pub fn src_root(&self) -> &AbsPath {
-        &self.src_root
+    pub fn src_root(&self) -> Option<&AbsPath> {
+        self.src_root.as_ref()?.as_deref().ok()
     }
 
     pub fn is_empty(&self) -> bool {
@@ -98,6 +112,11 @@ impl Sysroot {
     }
 
     pub fn loading_warning(&self) -> Option<String> {
+        let src_root = match &self.src_root {
+            None => return Some(format!("sysroot at `{}` has no library sources", self.root)),
+            Some(Ok(src_root)) => src_root,
+            Some(Err(e)) => return Some(e.to_string()),
+        };
         let has_core = match &self.mode {
             SysrootMode::Workspace(ws) => ws.packages().any(|p| ws[p].name == "core"),
             SysrootMode::Stitched(stitched) => stitched.by_name("core").is_some(),
@@ -108,10 +127,7 @@ impl Sysroot {
             } else {
                 " try running `rustup component add rust-src` to possible fix this"
             };
-            Some(format!(
-                "could not find libcore in loaded sysroot at `{}`{var_note}",
-                self.src_root.as_path(),
-            ))
+            Some(format!("could not find libcore in loaded sysroot at `{}`{var_note}", src_root,))
         } else {
             None
         }
@@ -140,8 +156,19 @@ impl Sysroot {
         tracing::debug!("discovering sysroot for {dir}");
         let sysroot_dir = discover_sysroot_dir(dir, extra_env)?;
         let sysroot_src_dir =
-            discover_sysroot_src_dir_or_add_component(&sysroot_dir, dir, extra_env)?;
-        Ok(Sysroot::load(sysroot_dir, sysroot_src_dir, metadata))
+            discover_sysroot_src_dir_or_add_component(&sysroot_dir, dir, extra_env);
+        Ok(Sysroot::load(sysroot_dir, Some(sysroot_src_dir), metadata))
+    }
+
+    pub fn discover_no_source(
+        dir: &AbsPath,
+        extra_env: &FxHashMap<String, String>,
+    ) -> Result<Sysroot> {
+        tracing::debug!("discovering sysroot for {dir}");
+        let sysroot_dir = discover_sysroot_dir(dir, extra_env)?;
+        let sysroot_src_dir =
+            discover_sysroot_src_dir_or_add_component(&sysroot_dir, dir, extra_env);
+        Ok(Sysroot::load(sysroot_dir, Some(sysroot_src_dir), false))
     }
 
     pub fn discover_with_src_override(
@@ -152,33 +179,59 @@ impl Sysroot {
     ) -> Result<Sysroot> {
         tracing::debug!("discovering sysroot for {current_dir}");
         let sysroot_dir = discover_sysroot_dir(current_dir, extra_env)?;
-        Ok(Sysroot::load(sysroot_dir, src, metadata))
+        Ok(Sysroot::load(sysroot_dir, Some(Ok(src)), metadata))
     }
 
     pub fn discover_rustc_src(&self) -> Option<ManifestPath> {
         get_rustc_src(&self.root)
     }
 
-    pub fn discover_rustc(&self) -> anyhow::Result<AbsPathBuf> {
-        let rustc = self.root.join("bin/rustc");
-        tracing::debug!(?rustc, "checking for rustc binary at location");
-        match fs::metadata(&rustc) {
-            Ok(_) => Ok(rustc),
-            Err(e) => Err(e).context(format!(
-                "failed to discover rustc in sysroot: {:?}",
-                AsRef::<std::path::Path>::as_ref(&self.root)
-            )),
-        }
-    }
-
     pub fn with_sysroot_dir(sysroot_dir: AbsPathBuf, metadata: bool) -> Result<Sysroot> {
         let sysroot_src_dir = discover_sysroot_src_dir(&sysroot_dir).ok_or_else(|| {
             format_err!("can't load standard library from sysroot path {sysroot_dir}")
-        })?;
-        Ok(Sysroot::load(sysroot_dir, sysroot_src_dir, metadata))
+        });
+        Ok(Sysroot::load(sysroot_dir, Some(sysroot_src_dir), metadata))
+    }
+
+    pub fn set_rustup_toolchain_env(cmd: &mut Command, sysroot: Option<&Self>) {
+        if let Some(sysroot) = sysroot {
+            cmd.env("RUSTUP_TOOLCHAIN", AsRef::<std::path::Path>::as_ref(&sysroot.root));
+        }
+    }
+
+    pub fn discover_proc_macro_srv(&self) -> anyhow::Result<AbsPathBuf> {
+        ["libexec", "lib"]
+            .into_iter()
+            .map(|segment| self.root().join(segment).join("rust-analyzer-proc-macro-srv"))
+            .find_map(|server_path| probe_for_binary(server_path.into()))
+            .map(AbsPathBuf::assert)
+            .ok_or_else(|| {
+                anyhow::format_err!("cannot find proc-macro server in sysroot `{}`", self.root())
+            })
     }
 
-    pub fn load(sysroot_dir: AbsPathBuf, sysroot_src_dir: AbsPathBuf, metadata: bool) -> Sysroot {
+    pub fn load(
+        sysroot_dir: AbsPathBuf,
+        sysroot_src_dir: Option<Result<AbsPathBuf, anyhow::Error>>,
+        metadata: bool,
+    ) -> Sysroot {
+        let sysroot_src_dir = match sysroot_src_dir {
+            Some(Ok(sysroot_src_dir)) => sysroot_src_dir,
+            Some(Err(e)) => {
+                return Sysroot {
+                    root: sysroot_dir,
+                    src_root: Some(Err(Arc::new(e))),
+                    mode: SysrootMode::Stitched(Stitched { crates: Arena::default() }),
+                }
+            }
+            None => {
+                return Sysroot {
+                    root: sysroot_dir,
+                    src_root: None,
+                    mode: SysrootMode::Stitched(Stitched { crates: Arena::default() }),
+                }
+            }
+        };
         if metadata {
             let sysroot: Option<_> = (|| {
                 let sysroot_cargo_toml = ManifestPath::try_from(
@@ -187,10 +240,19 @@ impl Sysroot {
                 .ok()?;
                 let current_dir =
                     AbsPathBuf::try_from(&*format!("{sysroot_src_dir}/sysroot")).ok()?;
+
+                let mut cargo_config = CargoConfig::default();
+                // the sysroot uses `public-dependency`, so we make cargo think it's a nightly
+                cargo_config.extra_env.insert(
+                    "__CARGO_TEST_CHANNEL_OVERRIDE_DO_NOT_USE_THIS".to_owned(),
+                    "nightly".to_owned(),
+                );
+
                 let res = CargoWorkspace::fetch_metadata(
                     &sysroot_cargo_toml,
                     &current_dir,
-                    &CargoConfig::default(),
+                    &cargo_config,
+                    None,
                     &|_| (),
                 )
                 .map_err(|e| {
@@ -274,7 +336,7 @@ impl Sysroot {
                 let cargo_workspace = CargoWorkspace::new(res);
                 Some(Sysroot {
                     root: sysroot_dir.clone(),
-                    src_root: sysroot_src_dir.clone(),
+                    src_root: Some(Ok(sysroot_src_dir.clone())),
                     mode: SysrootMode::Workspace(cargo_workspace),
                 })
             })();
@@ -326,7 +388,7 @@ impl Sysroot {
         }
         Sysroot {
             root: sysroot_dir,
-            src_root: sysroot_src_dir,
+            src_root: Some(Ok(sysroot_src_dir)),
             mode: SysrootMode::Stitched(stitched),
         }
     }
diff --git a/src/tools/rust-analyzer/crates/project-model/src/target_data_layout.rs b/src/tools/rust-analyzer/crates/project-model/src/target_data_layout.rs
index cb995857ec7..af635dda578 100644
--- a/src/tools/rust-analyzer/crates/project-model/src/target_data_layout.rs
+++ b/src/tools/rust-analyzer/crates/project-model/src/target_data_layout.rs
@@ -3,38 +3,58 @@ use std::process::Command;
 
 use rustc_hash::FxHashMap;
 
-use crate::{utf8_stdout, ManifestPath};
+use crate::{utf8_stdout, ManifestPath, Sysroot};
+
+/// Determines how `rustc --print target-spec-json` is discovered and invoked.
+pub enum RustcDataLayoutConfig<'a> {
+    /// Use `rustc --print target-spec-json`, either from with the binary from the sysroot or by discovering via
+    /// [`toolchain::rustc`].
+    Rustc(Option<&'a Sysroot>),
+    /// Use `cargo --print target-spec-json`, either from with the binary from the sysroot or by discovering via
+    /// [`toolchain::cargo`].
+    Cargo(Option<&'a Sysroot>, &'a ManifestPath),
+}
 
 pub fn get(
-    cargo_toml: Option<&ManifestPath>,
+    config: RustcDataLayoutConfig<'_>,
     target: Option<&str>,
     extra_env: &FxHashMap<String, String>,
 ) -> anyhow::Result<String> {
-    let output = (|| {
-        if let Some(cargo_toml) = cargo_toml {
-            let mut cmd = Command::new(toolchain::rustc());
+    let process = |output: String| {
+        (|| Some(output.split_once(r#""data-layout": ""#)?.1.split_once('"')?.0.to_owned()))()
+            .ok_or_else(|| {
+                anyhow::format_err!("could not fetch target-spec-json from command output")
+            })
+    };
+    let sysroot = match config {
+        RustcDataLayoutConfig::Cargo(sysroot, cargo_toml) => {
+            let mut cmd = Command::new(toolchain::Tool::Cargo.path());
+            Sysroot::set_rustup_toolchain_env(&mut cmd, sysroot);
             cmd.envs(extra_env);
             cmd.current_dir(cargo_toml.parent())
-                .args(["-Z", "unstable-options", "--print", "target-spec-json"])
+                .args(["rustc", "--", "-Z", "unstable-options", "--print", "target-spec-json"])
                 .env("RUSTC_BOOTSTRAP", "1");
             if let Some(target) = target {
                 cmd.args(["--target", target]);
             }
             match utf8_stdout(cmd) {
-                Ok(it) => return Ok(it),
-                Err(e) => tracing::debug!("{e:?}: falling back to querying rustc for cfgs"),
+                Ok(output) => return process(output),
+                Err(e) => {
+                    tracing::warn!("failed to run `cargo rustc --print target-spec-json`, falling back to invoking rustc directly: {e}");
+                    sysroot
+                }
             }
         }
-        // using unstable cargo features failed, fall back to using plain rustc
-        let mut cmd = Command::new(toolchain::rustc());
-        cmd.envs(extra_env)
-            .args(["-Z", "unstable-options", "--print", "target-spec-json"])
-            .env("RUSTC_BOOTSTRAP", "1");
-        if let Some(target) = target {
-            cmd.args(["--target", target]);
-        }
-        utf8_stdout(cmd)
-    })()?;
-    (|| Some(output.split_once(r#""data-layout": ""#)?.1.split_once('"')?.0.to_owned()))()
-        .ok_or_else(|| anyhow::format_err!("could not fetch target-spec-json from command output"))
+        RustcDataLayoutConfig::Rustc(sysroot) => sysroot,
+    };
+
+    let mut cmd = Command::new(toolchain::Tool::Rustc.path());
+    Sysroot::set_rustup_toolchain_env(&mut cmd, sysroot);
+    cmd.envs(extra_env)
+        .args(["-Z", "unstable-options", "--print", "target-spec-json"])
+        .env("RUSTC_BOOTSTRAP", "1");
+    if let Some(target) = target {
+        cmd.args(["--target", target]);
+    }
+    process(utf8_stdout(cmd)?)
 }
diff --git a/src/tools/rust-analyzer/crates/project-model/src/tests.rs b/src/tools/rust-analyzer/crates/project-model/src/tests.rs
index 74042e925ed..b9b1b701f6d 100644
--- a/src/tools/rust-analyzer/crates/project-model/src/tests.rs
+++ b/src/tools/rust-analyzer/crates/project-model/src/tests.rs
@@ -9,6 +9,7 @@ use expect_test::{expect_file, ExpectFile};
 use paths::{AbsPath, AbsPathBuf};
 use rustc_hash::FxHashMap;
 use serde::de::DeserializeOwned;
+use triomphe::Arc;
 
 use crate::{
     CargoWorkspace, CfgOverrides, ProjectJson, ProjectJsonData, ProjectWorkspace, Sysroot,
@@ -34,6 +35,7 @@ fn load_cargo_with_overrides(
         cfg_overrides,
         toolchain: None,
         target_layout: Err("target_data_layout not loaded".into()),
+        cargo_config_extra_env: Default::default(),
     };
     to_crate_graph(project_workspace)
 }
@@ -53,6 +55,7 @@ fn load_cargo_with_fake_sysroot(
         cfg_overrides: Default::default(),
         toolchain: None,
         target_layout: Err("target_data_layout not loaded".into()),
+        cargo_config_extra_env: Default::default(),
     };
     project_workspace.to_crate_graph(
         &mut {
@@ -69,8 +72,13 @@ fn load_rust_project(file: &str) -> (CrateGraph, ProcMacroPaths) {
     let data = get_test_json_file(file);
     let project = rooted_project_json(data);
     let sysroot = Ok(get_fake_sysroot());
-    let project_workspace =
-        ProjectWorkspace::Json { project, sysroot, rustc_cfg: Vec::new(), toolchain: None };
+    let project_workspace = ProjectWorkspace::Json {
+        project,
+        sysroot,
+        rustc_cfg: Vec::new(),
+        toolchain: None,
+        target_layout: Err(Arc::from("test has no data layout")),
+    };
     to_crate_graph(project_workspace)
 }
 
@@ -125,7 +133,7 @@ fn get_fake_sysroot() -> Sysroot {
     // fake sysroot, so we give them both the same path:
     let sysroot_dir = AbsPathBuf::assert(sysroot_path);
     let sysroot_src_dir = sysroot_dir.clone();
-    Sysroot::load(sysroot_dir, sysroot_src_dir, false)
+    Sysroot::load(sysroot_dir, Some(Ok(sysroot_src_dir)), false)
 }
 
 fn rooted_project_json(data: ProjectJsonData) -> ProjectJson {
@@ -230,7 +238,7 @@ fn crate_graph_dedup_identical() {
 
     let (d_crate_graph, mut d_proc_macros) = (crate_graph.clone(), proc_macros.clone());
 
-    crate_graph.extend(d_crate_graph.clone(), &mut d_proc_macros, |_| ());
+    crate_graph.extend(d_crate_graph.clone(), &mut d_proc_macros, |(_, a), (_, b)| a == b);
     assert!(crate_graph.iter().eq(d_crate_graph.iter()));
     assert_eq!(proc_macros, d_proc_macros);
 }
@@ -246,63 +254,11 @@ fn crate_graph_dedup() {
         load_cargo_with_fake_sysroot(path_map, "regex-metadata.json");
     assert_eq!(regex_crate_graph.iter().count(), 60);
 
-    crate_graph.extend(regex_crate_graph, &mut regex_proc_macros, |_| ());
+    crate_graph.extend(regex_crate_graph, &mut regex_proc_macros, |(_, a), (_, b)| a == b);
     assert_eq!(crate_graph.iter().count(), 118);
 }
 
 #[test]
-fn test_deduplicate_origin_dev() {
-    let path_map = &mut Default::default();
-    let (mut crate_graph, _proc_macros) =
-        load_cargo_with_fake_sysroot(path_map, "deduplication_crate_graph_A.json");
-    crate_graph.sort_deps();
-    let (crate_graph_1, mut _proc_macros_2) =
-        load_cargo_with_fake_sysroot(path_map, "deduplication_crate_graph_B.json");
-
-    crate_graph.extend(crate_graph_1, &mut _proc_macros_2, |_| ());
-
-    let mut crates_named_p2 = vec![];
-    for id in crate_graph.iter() {
-        let krate = &crate_graph[id];
-        if let Some(name) = krate.display_name.as_ref() {
-            if name.to_string() == "p2" {
-                crates_named_p2.push(krate);
-            }
-        }
-    }
-
-    assert!(crates_named_p2.len() == 1);
-    let p2 = crates_named_p2[0];
-    assert!(p2.origin.is_local());
-}
-
-#[test]
-fn test_deduplicate_origin_dev_rev() {
-    let path_map = &mut Default::default();
-    let (mut crate_graph, _proc_macros) =
-        load_cargo_with_fake_sysroot(path_map, "deduplication_crate_graph_B.json");
-    crate_graph.sort_deps();
-    let (crate_graph_1, mut _proc_macros_2) =
-        load_cargo_with_fake_sysroot(path_map, "deduplication_crate_graph_A.json");
-
-    crate_graph.extend(crate_graph_1, &mut _proc_macros_2, |_| ());
-
-    let mut crates_named_p2 = vec![];
-    for id in crate_graph.iter() {
-        let krate = &crate_graph[id];
-        if let Some(name) = krate.display_name.as_ref() {
-            if name.to_string() == "p2" {
-                crates_named_p2.push(krate);
-            }
-        }
-    }
-
-    assert!(crates_named_p2.len() == 1);
-    let p2 = crates_named_p2[0];
-    assert!(p2.origin.is_local());
-}
-
-#[test]
 fn smoke_test_real_sysroot_cargo() {
     if std::env::var("SYSROOT_CARGO_METADATA").is_err() {
         return;
@@ -327,6 +283,7 @@ fn smoke_test_real_sysroot_cargo() {
         cfg_overrides: Default::default(),
         toolchain: None,
         target_layout: Err("target_data_layout not loaded".into()),
+        cargo_config_extra_env: Default::default(),
     };
     project_workspace.to_crate_graph(
         &mut {
diff --git a/src/tools/rust-analyzer/crates/project-model/src/workspace.rs b/src/tools/rust-analyzer/crates/project-model/src/workspace.rs
index cda5ad2f110..b7ae76be8ce 100644
--- a/src/tools/rust-analyzer/crates/project-model/src/workspace.rs
+++ b/src/tools/rust-analyzer/crates/project-model/src/workspace.rs
@@ -6,14 +6,15 @@ use std::{collections::VecDeque, fmt, fs, iter, process::Command, str::FromStr,
 
 use anyhow::{format_err, Context};
 use base_db::{
-    CrateDisplayName, CrateGraph, CrateId, CrateName, CrateOrigin, Dependency, DependencyKind,
-    Edition, Env, FileId, LangCrateOrigin, ProcMacroPaths, TargetLayoutLoadResult,
+    CrateDisplayName, CrateGraph, CrateId, CrateName, CrateOrigin, Dependency, Edition, Env,
+    FileId, LangCrateOrigin, ProcMacroPaths, TargetLayoutLoadResult,
 };
 use cfg::{CfgAtom, CfgDiff, CfgOptions};
 use paths::{AbsPath, AbsPathBuf};
 use rustc_hash::{FxHashMap, FxHashSet};
 use semver::Version;
 use stdx::always;
+use toolchain::Tool;
 use triomphe::Arc;
 
 use crate::{
@@ -23,8 +24,9 @@ use crate::{
     project_json::Crate,
     rustc_cfg::{self, RustcCfgConfig},
     sysroot::{SysrootCrate, SysrootMode},
-    target_data_layout, utf8_stdout, CargoConfig, CargoWorkspace, InvocationStrategy, ManifestPath,
-    Package, ProjectJson, ProjectManifest, Sysroot, TargetData, TargetKind, WorkspaceBuildScripts,
+    target_data_layout::{self, RustcDataLayoutConfig},
+    utf8_stdout, CargoConfig, CargoWorkspace, InvocationStrategy, ManifestPath, Package,
+    ProjectJson, ProjectManifest, Sysroot, TargetData, TargetKind, WorkspaceBuildScripts,
 };
 
 /// A set of cfg-overrides per crate.
@@ -69,7 +71,8 @@ pub enum ProjectWorkspace {
         rustc_cfg: Vec<CfgFlag>,
         cfg_overrides: CfgOverrides,
         toolchain: Option<Version>,
-        target_layout: Result<String, String>,
+        target_layout: TargetLayoutLoadResult,
+        cargo_config_extra_env: FxHashMap<String, String>,
     },
     /// Project workspace was manually specified using a `rust-project.json` file.
     Json {
@@ -79,6 +82,7 @@ pub enum ProjectWorkspace {
         /// `rustc --print cfg`.
         rustc_cfg: Vec<CfgFlag>,
         toolchain: Option<Version>,
+        target_layout: TargetLayoutLoadResult,
     },
     // FIXME: The primary limitation of this approach is that the set of detached files needs to be fixed at the beginning.
     // That's not the end user experience we should strive for.
@@ -111,7 +115,8 @@ impl fmt::Debug for ProjectWorkspace {
                 rustc_cfg,
                 cfg_overrides,
                 toolchain,
-                target_layout: data_layout,
+                target_layout,
+                cargo_config_extra_env,
             } => f
                 .debug_struct("Cargo")
                 .field("root", &cargo.workspace_root().file_name())
@@ -124,16 +129,25 @@ impl fmt::Debug for ProjectWorkspace {
                 .field("n_rustc_cfg", &rustc_cfg.len())
                 .field("n_cfg_overrides", &cfg_overrides.len())
                 .field("toolchain", &toolchain)
-                .field("data_layout", &data_layout)
+                .field("data_layout", &target_layout)
+                .field("cargo_config_extra_env", &cargo_config_extra_env)
                 .finish(),
-            ProjectWorkspace::Json { project, sysroot, rustc_cfg, toolchain } => {
+            ProjectWorkspace::Json {
+                project,
+                sysroot,
+                rustc_cfg,
+                toolchain,
+                target_layout: data_layout,
+            } => {
                 let mut debug_struct = f.debug_struct("Json");
                 debug_struct.field("n_crates", &project.n_crates());
                 if let Ok(sysroot) = sysroot {
                     debug_struct.field("n_sysroot_crates", &sysroot.num_packages());
                 }
-                debug_struct.field("toolchain", &toolchain);
-                debug_struct.field("n_rustc_cfg", &rustc_cfg.len());
+                debug_struct
+                    .field("toolchain", &toolchain)
+                    .field("n_rustc_cfg", &rustc_cfg.len())
+                    .field("data_layout", &data_layout);
                 debug_struct.finish()
             }
             ProjectWorkspace::DetachedFiles { files, sysroot, rustc_cfg } => f
@@ -146,6 +160,28 @@ impl fmt::Debug for ProjectWorkspace {
     }
 }
 
+fn get_toolchain_version(
+    current_dir: &AbsPath,
+    sysroot: Option<&Sysroot>,
+    tool: Tool,
+    extra_env: &FxHashMap<String, String>,
+    prefix: &str,
+) -> Result<Option<Version>, anyhow::Error> {
+    let cargo_version = utf8_stdout({
+        let mut cmd = Command::new(tool.path());
+        Sysroot::set_rustup_toolchain_env(&mut cmd, sysroot);
+        cmd.envs(extra_env);
+        cmd.arg("--version").current_dir(current_dir);
+        cmd
+    })
+    .with_context(|| format!("Failed to query rust toolchain version at {current_dir}, is your toolchain setup correctly?"))?;
+    anyhow::Ok(
+        cargo_version
+            .get(prefix.len()..)
+            .and_then(|it| Version::parse(it.split_whitespace().next()?).ok()),
+    )
+}
+
 impl ProjectWorkspace {
     pub fn load(
         manifest: ProjectManifest,
@@ -161,20 +197,6 @@ impl ProjectWorkspace {
         config: &CargoConfig,
         progress: &dyn Fn(String),
     ) -> anyhow::Result<ProjectWorkspace> {
-        let version = |current_dir, cmd_path, prefix: &str| {
-            let cargo_version = utf8_stdout({
-                let mut cmd = Command::new(cmd_path);
-                cmd.envs(&config.extra_env);
-                cmd.arg("--version").current_dir(current_dir);
-                cmd
-            })
-            .with_context(|| format!("Failed to query rust toolchain version at {current_dir}, is your toolchain setup correctly?"))?;
-            anyhow::Ok(
-                cargo_version
-                    .get(prefix.len()..)
-                    .and_then(|it| Version::parse(it.split_whitespace().next()?).ok()),
-            )
-        };
         let res = match manifest {
             ProjectManifest::ProjectJson(project_json) => {
                 let file = fs::read_to_string(project_json)
@@ -182,30 +204,14 @@ impl ProjectWorkspace {
                 let data = serde_json::from_str(&file)
                     .with_context(|| format!("Failed to deserialize json file {project_json}"))?;
                 let project_location = project_json.parent().to_path_buf();
-                let toolchain = version(&*project_location, toolchain::rustc(), "rustc ")?;
-                let project_json = ProjectJson::new(&project_location, data);
+                let project_json: ProjectJson = ProjectJson::new(&project_location, data);
                 ProjectWorkspace::load_inline(
                     project_json,
                     config.target.as_deref(),
                     &config.extra_env,
-                    toolchain,
                 )
             }
             ProjectManifest::CargoToml(cargo_toml) => {
-                let toolchain = version(cargo_toml.parent(), toolchain::cargo(), "cargo ")?;
-                let meta = CargoWorkspace::fetch_metadata(
-                    cargo_toml,
-                    cargo_toml.parent(),
-                    config,
-                    progress,
-                )
-                .with_context(|| {
-                    format!(
-                        "Failed to read Cargo metadata from Cargo.toml file {cargo_toml}, {toolchain:?}",
-                    )
-                })?;
-                let cargo = CargoWorkspace::new(meta);
-
                 let sysroot = match (&config.sysroot, &config.sysroot_src) {
                     (Some(RustLibSource::Path(path)), None) => {
                         Sysroot::with_sysroot_dir(path.clone(), config.sysroot_query_metadata).map_err(|e| {
@@ -218,7 +224,7 @@ impl ProjectWorkspace {
                         })
                     }
                     (Some(RustLibSource::Path(sysroot)), Some(sysroot_src)) => {
-                        Ok(Sysroot::load(sysroot.clone(), sysroot_src.clone(), config.sysroot_query_metadata))
+                        Ok(Sysroot::load(sysroot.clone(), Some(Ok(sysroot_src.clone())), config.sysroot_query_metadata))
                     }
                     (Some(RustLibSource::Discover), Some(sysroot_src)) => {
                         Sysroot::discover_with_src_override(
@@ -231,18 +237,19 @@ impl ProjectWorkspace {
                     }
                     (None, _) => Err(None),
                 };
+                let sysroot_ref = sysroot.as_ref().ok();
 
                 if let Ok(sysroot) = &sysroot {
-                    tracing::info!(workspace = %cargo_toml, src_root = %sysroot.src_root(), root = %sysroot.root(), "Using sysroot");
+                    tracing::info!(workspace = %cargo_toml, src_root = ?sysroot.src_root(), root = %sysroot.root(), "Using sysroot");
                 }
 
                 let rustc_dir = match &config.rustc_source {
                     Some(RustLibSource::Path(path)) => ManifestPath::try_from(path.clone())
                         .map_err(|p| Some(format!("rustc source path is not absolute: {p}"))),
                     Some(RustLibSource::Discover) => {
-                        sysroot.as_ref().ok().and_then(Sysroot::discover_rustc_src).ok_or_else(
-                            || Some("Failed to discover rustc source for sysroot.".to_owned()),
-                        )
+                        sysroot_ref.and_then(Sysroot::discover_rustc_src).ok_or_else(|| {
+                            Some("Failed to discover rustc source for sysroot.".to_owned())
+                        })
                     }
                     None => Err(None),
                 };
@@ -256,6 +263,7 @@ impl ProjectWorkspace {
                             features: crate::CargoFeatures::default(),
                             ..config.clone()
                         },
+                        sysroot_ref,
                         progress,
                     ) {
                         Ok(meta) => {
@@ -264,6 +272,7 @@ impl ProjectWorkspace {
                                 &workspace,
                                 cargo_toml.parent(),
                                 &config.extra_env,
+                                sysroot_ref
                             );
                             Ok(Box::new((workspace, buildscripts)))
                         }
@@ -279,21 +288,45 @@ impl ProjectWorkspace {
                     }
                 });
 
+                let toolchain = get_toolchain_version(
+                    cargo_toml.parent(),
+                    sysroot_ref,
+                    toolchain::Tool::Cargo,
+                    &config.extra_env,
+                    "cargo ",
+                )?;
                 let rustc_cfg = rustc_cfg::get(
                     config.target.as_deref(),
                     &config.extra_env,
-                    RustcCfgConfig::Cargo(cargo_toml),
+                    RustcCfgConfig::Cargo(sysroot_ref, cargo_toml),
                 );
 
                 let cfg_overrides = config.cfg_overrides.clone();
                 let data_layout = target_data_layout::get(
-                    Some(cargo_toml),
+                    RustcDataLayoutConfig::Cargo(sysroot_ref, cargo_toml),
                     config.target.as_deref(),
                     &config.extra_env,
                 );
                 if let Err(e) = &data_layout {
                     tracing::error!(%e, "failed fetching data layout for {cargo_toml:?} workspace");
                 }
+
+                let meta = CargoWorkspace::fetch_metadata(
+                    cargo_toml,
+                    cargo_toml.parent(),
+                    config,
+                    sysroot_ref,
+                    progress,
+                )
+                .with_context(|| {
+                    format!(
+                        "Failed to read Cargo metadata from Cargo.toml file {cargo_toml}, {toolchain:?}",
+                    )
+                })?;
+                let cargo = CargoWorkspace::new(meta);
+
+                let cargo_config_extra_env =
+                    cargo_config_env(cargo_toml, &config.extra_env, sysroot_ref);
                 ProjectWorkspace::Cargo {
                     cargo,
                     build_scripts: WorkspaceBuildScripts::default(),
@@ -302,7 +335,10 @@ impl ProjectWorkspace {
                     rustc_cfg,
                     cfg_overrides,
                     toolchain,
-                    target_layout: data_layout.map_err(|it| it.to_string()),
+                    target_layout: data_layout
+                        .map(Arc::from)
+                        .map_err(|it| Arc::from(it.to_string())),
+                    cargo_config_extra_env,
                 }
             }
         };
@@ -314,15 +350,16 @@ impl ProjectWorkspace {
         project_json: ProjectJson,
         target: Option<&str>,
         extra_env: &FxHashMap<String, String>,
-        toolchain: Option<Version>,
     ) -> ProjectWorkspace {
         let sysroot = match (project_json.sysroot.clone(), project_json.sysroot_src.clone()) {
-            (Some(sysroot), Some(sysroot_src)) => Ok(Sysroot::load(sysroot, sysroot_src, false)),
+            (Some(sysroot), Some(sysroot_src)) => {
+                Ok(Sysroot::load(sysroot, Some(Ok(sysroot_src)), false))
+            }
             (Some(sysroot), None) => {
                 // assume sysroot is structured like rustup's and guess `sysroot_src`
                 let sysroot_src =
                     sysroot.join("lib").join("rustlib").join("src").join("rust").join("library");
-                Ok(Sysroot::load(sysroot, sysroot_src, false))
+                Ok(Sysroot::load(sysroot, Some(Ok(sysroot_src)), false))
             }
             (None, Some(sysroot_src)) => {
                 // assume sysroot is structured like rustup's and guess `sysroot`
@@ -330,23 +367,36 @@ impl ProjectWorkspace {
                 for _ in 0..5 {
                     sysroot.pop();
                 }
-                Ok(Sysroot::load(sysroot, sysroot_src, false))
+                Ok(Sysroot::load(sysroot, Some(Ok(sysroot_src)), false))
             }
             (None, None) => Err(None),
         };
-        let config = match &sysroot {
-            Ok(sysroot) => {
-                tracing::debug!(src_root = %sysroot.src_root(), root = %sysroot.root(), "Using sysroot");
-                RustcCfgConfig::Explicit(sysroot)
-            }
-            Err(_) => {
-                tracing::debug!("discovering sysroot");
-                RustcCfgConfig::Discover
+        let sysroot_ref = sysroot.as_ref().ok();
+        let cfg_config = RustcCfgConfig::Rustc(sysroot_ref);
+        let data_layout_config = RustcDataLayoutConfig::Rustc(sysroot_ref);
+        let toolchain = match get_toolchain_version(
+            project_json.path(),
+            sysroot_ref,
+            toolchain::Tool::Rustc,
+            extra_env,
+            "rustc ",
+        ) {
+            Ok(it) => it,
+            Err(e) => {
+                tracing::error!("{e}");
+                None
             }
         };
 
-        let rustc_cfg = rustc_cfg::get(target, extra_env, config);
-        ProjectWorkspace::Json { project: project_json, sysroot, rustc_cfg, toolchain }
+        let rustc_cfg = rustc_cfg::get(target, extra_env, cfg_config);
+        let data_layout = target_data_layout::get(data_layout_config, target, extra_env);
+        ProjectWorkspace::Json {
+            project: project_json,
+            sysroot,
+            rustc_cfg,
+            toolchain,
+            target_layout: data_layout.map(Arc::from).map_err(|it| Arc::from(it.to_string())),
+        }
     }
 
     pub fn load_detached_files(
@@ -373,18 +423,11 @@ impl ProjectWorkspace {
             }
             None => Err(None),
         };
-        let rustc_config = match &sysroot {
-            Ok(sysroot) => {
-                tracing::info!(src_root = %sysroot.src_root(), root = %sysroot.root(), "Using sysroot");
-                RustcCfgConfig::Explicit(sysroot)
-            }
-            Err(_) => {
-                tracing::info!("discovering sysroot");
-                RustcCfgConfig::Discover
-            }
-        };
-
-        let rustc_cfg = rustc_cfg::get(None, &FxHashMap::default(), rustc_config);
+        let rustc_cfg = rustc_cfg::get(
+            None,
+            &FxHashMap::default(),
+            RustcCfgConfig::Rustc(sysroot.as_ref().ok()),
+        );
         Ok(ProjectWorkspace::DetachedFiles { files: detached_files, sysroot, rustc_cfg })
     }
 
@@ -395,11 +438,17 @@ impl ProjectWorkspace {
         progress: &dyn Fn(String),
     ) -> anyhow::Result<WorkspaceBuildScripts> {
         match self {
-            ProjectWorkspace::Cargo { cargo, toolchain, .. } => {
-                WorkspaceBuildScripts::run_for_workspace(config, cargo, progress, toolchain)
-                    .with_context(|| {
-                        format!("Failed to run build scripts for {}", cargo.workspace_root())
-                    })
+            ProjectWorkspace::Cargo { cargo, toolchain, sysroot, .. } => {
+                WorkspaceBuildScripts::run_for_workspace(
+                    config,
+                    cargo,
+                    progress,
+                    toolchain,
+                    sysroot.as_ref().ok(),
+                )
+                .with_context(|| {
+                    format!("Failed to run build scripts for {}", cargo.workspace_root())
+                })
             }
             ProjectWorkspace::Json { .. } | ProjectWorkspace::DetachedFiles { .. } => {
                 Ok(WorkspaceBuildScripts::default())
@@ -472,18 +521,7 @@ impl ProjectWorkspace {
             ProjectWorkspace::Cargo { sysroot: Ok(sysroot), .. }
             | ProjectWorkspace::Json { sysroot: Ok(sysroot), .. }
             | ProjectWorkspace::DetachedFiles { sysroot: Ok(sysroot), .. } => {
-                let standalone_server_name =
-                    format!("rust-analyzer-proc-macro-srv{}", std::env::consts::EXE_SUFFIX);
-                ["libexec", "lib"]
-                    .into_iter()
-                    .map(|segment| sysroot.root().join(segment).join(&standalone_server_name))
-                    .find(|server_path| std::fs::metadata(server_path).is_ok())
-                    .ok_or_else(|| {
-                        anyhow::format_err!(
-                            "cannot find proc-macro server in sysroot `{}`",
-                            sysroot.root()
-                        )
-                    })
+                sysroot.discover_proc_macro_srv()
             }
             ProjectWorkspace::DetachedFiles { .. } => {
                 Err(anyhow::format_err!("cannot find proc-macro server, no sysroot was found"))
@@ -503,8 +541,7 @@ impl ProjectWorkspace {
     /// The return type contains the path and whether or not
     /// the root is a member of the current workspace
     pub fn to_roots(&self) -> Vec<PackageRoot> {
-        let mk_sysroot = |sysroot: Result<_, _>, project_root: Option<&AbsPath>| {
-            let project_root = project_root.map(ToOwned::to_owned);
+        let mk_sysroot = |sysroot: Result<_, _>| {
             sysroot.into_iter().flat_map(move |sysroot: &Sysroot| {
                 let mut r = match sysroot.mode() {
                     SysrootMode::Workspace(ws) => ws
@@ -532,18 +569,21 @@ impl ProjectWorkspace {
                 };
 
                 r.push(PackageRoot {
-                    // mark the sysroot as mutable if it is located inside of the project
-                    is_local: project_root
-                        .as_ref()
-                        .map_or(false, |project_root| sysroot.src_root().starts_with(project_root)),
-                    include: vec![sysroot.src_root().to_path_buf()],
+                    is_local: false,
+                    include: sysroot.src_root().map(|it| it.to_path_buf()).into_iter().collect(),
                     exclude: Vec::new(),
                 });
                 r
             })
         };
         match self {
-            ProjectWorkspace::Json { project, sysroot, rustc_cfg: _, toolchain: _ } => project
+            ProjectWorkspace::Json {
+                project,
+                sysroot,
+                rustc_cfg: _,
+                toolchain: _,
+                target_layout: _,
+            } => project
                 .crates()
                 .map(|(_, krate)| PackageRoot {
                     is_local: krate.is_workspace_member,
@@ -552,7 +592,7 @@ impl ProjectWorkspace {
                 })
                 .collect::<FxHashSet<_>>()
                 .into_iter()
-                .chain(mk_sysroot(sysroot.as_ref(), Some(project.path())))
+                .chain(mk_sysroot(sysroot.as_ref()))
                 .collect::<Vec<_>>(),
             ProjectWorkspace::Cargo {
                 cargo,
@@ -563,6 +603,7 @@ impl ProjectWorkspace {
                 build_scripts,
                 toolchain: _,
                 target_layout: _,
+                cargo_config_extra_env: _,
             } => {
                 cargo
                     .packages()
@@ -586,7 +627,7 @@ impl ProjectWorkspace {
                         let extra_targets = cargo[pkg]
                             .targets
                             .iter()
-                            .filter(|&&tgt| cargo[tgt].kind == TargetKind::Lib)
+                            .filter(|&&tgt| matches!(cargo[tgt].kind, TargetKind::Lib { .. }))
                             .filter_map(|&tgt| cargo[tgt].root.parent())
                             .map(|tgt| tgt.normalize().to_path_buf())
                             .filter(|path| !path.starts_with(&pkg_root));
@@ -602,7 +643,7 @@ impl ProjectWorkspace {
                         }
                         PackageRoot { is_local, include, exclude }
                     })
-                    .chain(mk_sysroot(sysroot.as_ref(), Some(cargo.workspace_root())))
+                    .chain(mk_sysroot(sysroot.as_ref()))
                     .chain(rustc.iter().map(|a| a.as_ref()).flat_map(|(rustc, _)| {
                         rustc.packages().map(move |krate| PackageRoot {
                             is_local: false,
@@ -619,7 +660,7 @@ impl ProjectWorkspace {
                     include: vec![detached_file.clone()],
                     exclude: Vec::new(),
                 })
-                .chain(mk_sysroot(sysroot.as_ref(), None))
+                .chain(mk_sysroot(sysroot.as_ref()))
                 .collect(),
         }
     }
@@ -651,17 +692,19 @@ impl ProjectWorkspace {
         let _p = tracing::span!(tracing::Level::INFO, "ProjectWorkspace::to_crate_graph").entered();
 
         let (mut crate_graph, proc_macros) = match self {
-            ProjectWorkspace::Json { project, sysroot, rustc_cfg, toolchain } => {
-                project_json_to_crate_graph(
-                    rustc_cfg.clone(),
-                    load,
-                    project,
-                    sysroot.as_ref().ok(),
-                    extra_env,
-                    Err("rust-project.json projects have no target layout set".into()),
-                    toolchain.clone(),
-                )
-            }
+            ProjectWorkspace::Json {
+                project,
+                sysroot,
+                rustc_cfg,
+                toolchain: _,
+                target_layout: _,
+            } => project_json_to_crate_graph(
+                rustc_cfg.clone(),
+                load,
+                project,
+                sysroot.as_ref().ok(),
+                extra_env,
+            ),
             ProjectWorkspace::Cargo {
                 cargo,
                 sysroot,
@@ -669,8 +712,9 @@ impl ProjectWorkspace {
                 rustc_cfg,
                 cfg_overrides,
                 build_scripts,
-                toolchain,
-                target_layout,
+                toolchain: _,
+                target_layout: _,
+                cargo_config_extra_env: _,
             } => cargo_to_crate_graph(
                 load,
                 rustc.as_ref().map(|a| a.as_ref()).ok(),
@@ -679,20 +723,9 @@ impl ProjectWorkspace {
                 rustc_cfg.clone(),
                 cfg_overrides,
                 build_scripts,
-                match target_layout.as_ref() {
-                    Ok(it) => Ok(Arc::from(it.as_str())),
-                    Err(it) => Err(Arc::from(it.as_str())),
-                },
-                toolchain.as_ref(),
             ),
             ProjectWorkspace::DetachedFiles { files, sysroot, rustc_cfg } => {
-                detached_files_to_crate_graph(
-                    rustc_cfg.clone(),
-                    load,
-                    files,
-                    sysroot.as_ref().ok(),
-                    Err("detached file projects have no target layout set".into()),
-                )
+                detached_files_to_crate_graph(rustc_cfg.clone(), load, files, sysroot.as_ref().ok())
             }
         };
         if crate_graph.patch_cfg_if() {
@@ -713,6 +746,7 @@ impl ProjectWorkspace {
                     rustc_cfg,
                     cfg_overrides,
                     toolchain,
+                    cargo_config_extra_env,
                     build_scripts: _,
                     target_layout: _,
                 },
@@ -723,6 +757,7 @@ impl ProjectWorkspace {
                     rustc_cfg: o_rustc_cfg,
                     cfg_overrides: o_cfg_overrides,
                     toolchain: o_toolchain,
+                    cargo_config_extra_env: o_cargo_config_extra_env,
                     build_scripts: _,
                     target_layout: _,
                 },
@@ -733,14 +768,16 @@ impl ProjectWorkspace {
                     && cfg_overrides == o_cfg_overrides
                     && toolchain == o_toolchain
                     && sysroot == o_sysroot
+                    && cargo_config_extra_env == o_cargo_config_extra_env
             }
             (
-                Self::Json { project, sysroot, rustc_cfg, toolchain },
+                Self::Json { project, sysroot, rustc_cfg, toolchain, target_layout: _ },
                 Self::Json {
                     project: o_project,
                     sysroot: o_sysroot,
                     rustc_cfg: o_rustc_cfg,
                     toolchain: o_toolchain,
+                    target_layout: _,
                 },
             ) => {
                 project == o_project
@@ -771,21 +808,12 @@ fn project_json_to_crate_graph(
     project: &ProjectJson,
     sysroot: Option<&Sysroot>,
     extra_env: &FxHashMap<String, String>,
-    target_layout: TargetLayoutLoadResult,
-    toolchain: Option<Version>,
 ) -> (CrateGraph, ProcMacroPaths) {
     let mut res = (CrateGraph::default(), ProcMacroPaths::default());
     let (crate_graph, proc_macros) = &mut res;
-    let sysroot_deps = sysroot.as_ref().map(|sysroot| {
-        sysroot_to_crate_graph(
-            crate_graph,
-            sysroot,
-            rustc_cfg.clone(),
-            target_layout.clone(),
-            load,
-            toolchain.as_ref(),
-        )
-    });
+    let sysroot_deps = sysroot
+        .as_ref()
+        .map(|sysroot| sysroot_to_crate_graph(crate_graph, sysroot, rustc_cfg.clone(), load));
 
     let r_a_cfg_flag = CfgFlag::Atom("rust_analyzer".to_owned());
     let mut cfg_cache: FxHashMap<&str, Vec<CfgFlag>> = FxHashMap::default();
@@ -813,12 +841,7 @@ fn project_json_to_crate_graph(
 
                 let target_cfgs = match target.as_deref() {
                     Some(target) => cfg_cache.entry(target).or_insert_with(|| {
-                        let rustc_cfg = match sysroot {
-                            Some(sysroot) => RustcCfgConfig::Explicit(sysroot),
-                            None => RustcCfgConfig::Discover,
-                        };
-
-                        rustc_cfg::get(Some(target), extra_env, rustc_cfg)
+                        rustc_cfg::get(Some(target), extra_env, RustcCfgConfig::Rustc(sysroot))
                     }),
                     None => &rustc_cfg,
                 };
@@ -845,8 +868,6 @@ fn project_json_to_crate_graph(
                     } else {
                         CrateOrigin::Local { repo: None, name: None }
                     },
-                    target_layout.clone(),
-                    toolchain.clone(),
                 );
                 if *is_proc_macro {
                     if let Some(path) = proc_macro_dylib_path.clone() {
@@ -873,7 +894,7 @@ fn project_json_to_crate_graph(
 
             for dep in &krate.deps {
                 if let Some(&to) = crates.get(&dep.crate_id) {
-                    add_dep(crate_graph, from, dep.name.clone(), to, dep.kind().to_owned())
+                    add_dep(crate_graph, from, dep.name.clone(), to)
                 }
             }
         }
@@ -889,22 +910,13 @@ fn cargo_to_crate_graph(
     rustc_cfg: Vec<CfgFlag>,
     override_cfg: &CfgOverrides,
     build_scripts: &WorkspaceBuildScripts,
-    target_layout: TargetLayoutLoadResult,
-    toolchain: Option<&Version>,
 ) -> (CrateGraph, ProcMacroPaths) {
     let _p = tracing::span!(tracing::Level::INFO, "cargo_to_crate_graph").entered();
     let mut res = (CrateGraph::default(), ProcMacroPaths::default());
     let crate_graph = &mut res.0;
     let proc_macros = &mut res.1;
     let (public_deps, libproc_macro) = match sysroot {
-        Some(sysroot) => sysroot_to_crate_graph(
-            crate_graph,
-            sysroot,
-            rustc_cfg.clone(),
-            target_layout.clone(),
-            load,
-            toolchain,
-        ),
+        Some(sysroot) => sysroot_to_crate_graph(crate_graph, sysroot, rustc_cfg.clone(), load),
         None => (SysrootPublicDeps::default(), None),
     };
 
@@ -926,8 +938,6 @@ fn cargo_to_crate_graph(
             // Add test cfg for local crates
             if cargo[pkg].is_local {
                 cfg_options.insert_atom("test".into());
-            }
-            if cargo[pkg].is_member {
                 cfg_options.insert_atom("rust_analyzer".into());
             }
 
@@ -949,7 +959,7 @@ fn cargo_to_crate_graph(
 
         let mut lib_tgt = None;
         for &tgt in cargo[pkg].targets.iter() {
-            if cargo[tgt].kind != TargetKind::Lib && !cargo[pkg].is_member {
+            if !matches!(cargo[tgt].kind, TargetKind::Lib { .. }) && !cargo[pkg].is_member {
                 // For non-workspace-members, Cargo does not resolve dev-dependencies, so we don't
                 // add any targets except the library target, since those will not work correctly if
                 // they use dev-dependencies.
@@ -957,46 +967,46 @@ fn cargo_to_crate_graph(
                 // https://github.com/rust-lang/rust-analyzer/issues/11300
                 continue;
             }
-            let &TargetData { ref name, kind, is_proc_macro, ref root, .. } = &cargo[tgt];
-
-            if kind == TargetKind::Lib
-                && sysroot.map_or(false, |sysroot| root.starts_with(sysroot.src_root()))
-            {
-                if let Some(&(_, crate_id, _)) =
-                    public_deps.deps.iter().find(|(dep_name, ..)| dep_name.as_smol_str() == name)
-                {
-                    pkg_crates.entry(pkg).or_insert_with(Vec::new).push((crate_id, kind));
-
-                    lib_tgt = Some((crate_id, name.clone()));
-                    pkg_to_lib_crate.insert(pkg, crate_id);
-                    // sysroot is inside the workspace, prevent the sysroot crates from being duplicated here
-                    continue;
-                }
-            }
+            let &TargetData { ref name, kind, ref root, .. } = &cargo[tgt];
 
             let Some(file_id) = load(root) else { continue };
 
+            let build_data = build_scripts.get_output(pkg);
+            let pkg_data = &cargo[pkg];
             let crate_id = add_target_crate_root(
                 crate_graph,
                 proc_macros,
-                &cargo[pkg],
-                build_scripts.get_output(pkg),
+                pkg_data,
+                build_data,
                 cfg_options.clone(),
                 file_id,
                 name,
-                is_proc_macro,
-                target_layout.clone(),
-                false,
-                toolchain.cloned(),
+                kind,
+                if pkg_data.is_local {
+                    CrateOrigin::Local {
+                        repo: pkg_data.repository.clone(),
+                        name: Some(pkg_data.name.clone()),
+                    }
+                } else {
+                    CrateOrigin::Library {
+                        repo: pkg_data.repository.clone(),
+                        name: pkg_data.name.clone(),
+                    }
+                },
             );
-            if kind == TargetKind::Lib {
+            if let TargetKind::Lib { .. } = kind {
                 lib_tgt = Some((crate_id, name.clone()));
                 pkg_to_lib_crate.insert(pkg, crate_id);
             }
             // Even crates that don't set proc-macro = true are allowed to depend on proc_macro
             // (just none of the APIs work when called outside of a proc macro).
             if let Some(proc_macro) = libproc_macro {
-                add_proc_macro_dep(crate_graph, crate_id, proc_macro, is_proc_macro);
+                add_proc_macro_dep(
+                    crate_graph,
+                    crate_id,
+                    proc_macro,
+                    matches!(kind, TargetKind::Lib { is_proc_macro: true }),
+                );
             }
 
             pkg_crates.entry(pkg).or_insert_with(Vec::new).push((crate_id, kind));
@@ -1016,7 +1026,7 @@ fn cargo_to_crate_graph(
                     // cargo metadata does not do any normalization,
                     // so we do it ourselves currently
                     let name = CrateName::normalize_dashes(&name);
-                    add_dep(crate_graph, from, name, to, DependencyKind::Normal);
+                    add_dep(crate_graph, from, name, to);
                 }
             }
         }
@@ -1036,17 +1046,7 @@ fn cargo_to_crate_graph(
                     continue;
                 }
 
-                add_dep(
-                    crate_graph,
-                    from,
-                    name.clone(),
-                    to,
-                    match dep.kind {
-                        DepKind::Normal => DependencyKind::Normal,
-                        DepKind::Dev => DependencyKind::Dev,
-                        DepKind::Build => DependencyKind::Build,
-                    },
-                )
+                add_dep(crate_graph, from, name.clone(), to)
             }
         }
     }
@@ -1074,8 +1074,6 @@ fn cargo_to_crate_graph(
                 } else {
                     rustc_build_scripts
                 },
-                target_layout,
-                toolchain,
             );
         }
     }
@@ -1087,19 +1085,11 @@ fn detached_files_to_crate_graph(
     load: &mut dyn FnMut(&AbsPath) -> Option<FileId>,
     detached_files: &[AbsPathBuf],
     sysroot: Option<&Sysroot>,
-    target_layout: TargetLayoutLoadResult,
 ) -> (CrateGraph, ProcMacroPaths) {
     let _p = tracing::span!(tracing::Level::INFO, "detached_files_to_crate_graph").entered();
     let mut crate_graph = CrateGraph::default();
     let (public_deps, _libproc_macro) = match sysroot {
-        Some(sysroot) => sysroot_to_crate_graph(
-            &mut crate_graph,
-            sysroot,
-            rustc_cfg.clone(),
-            target_layout.clone(),
-            load,
-            None,
-        ),
+        Some(sysroot) => sysroot_to_crate_graph(&mut crate_graph, sysroot, rustc_cfg.clone(), load),
         None => (SysrootPublicDeps::default(), None),
     };
 
@@ -1131,8 +1121,6 @@ fn detached_files_to_crate_graph(
                 repo: None,
                 name: display_name.map(|n| n.canonical_name().to_owned()),
             },
-            target_layout.clone(),
-            None,
         );
 
         public_deps.add_to_crate_graph(&mut crate_graph, detached_file_crate);
@@ -1153,8 +1141,6 @@ fn handle_rustc_crates(
     cfg_options: &CfgOptions,
     override_cfg: &CfgOverrides,
     build_scripts: &WorkspaceBuildScripts,
-    target_layout: TargetLayoutLoadResult,
-    toolchain: Option<&Version>,
 ) {
     let mut rustc_pkg_crates = FxHashMap::default();
     // The root package of the rustc-dev component is rustc_driver, so we match that
@@ -1194,9 +1180,9 @@ fn handle_rustc_crates(
             };
 
             for &tgt in rustc_workspace[pkg].targets.iter() {
-                if rustc_workspace[tgt].kind != TargetKind::Lib {
+                let kind @ TargetKind::Lib { is_proc_macro } = rustc_workspace[tgt].kind else {
                     continue;
-                }
+                };
                 if let Some(file_id) = load(&rustc_workspace[tgt].root) {
                     let crate_id = add_target_crate_root(
                         crate_graph,
@@ -1206,21 +1192,14 @@ fn handle_rustc_crates(
                         cfg_options.clone(),
                         file_id,
                         &rustc_workspace[tgt].name,
-                        rustc_workspace[tgt].is_proc_macro,
-                        target_layout.clone(),
-                        true,
-                        toolchain.cloned(),
+                        kind,
+                        CrateOrigin::Rustc { name: rustc_workspace[pkg].name.clone() },
                     );
                     pkg_to_lib_crate.insert(pkg, crate_id);
                     // Add dependencies on core / std / alloc for this crate
                     public_deps.add_to_crate_graph(crate_graph, crate_id);
                     if let Some(proc_macro) = libproc_macro {
-                        add_proc_macro_dep(
-                            crate_graph,
-                            crate_id,
-                            proc_macro,
-                            rustc_workspace[tgt].is_proc_macro,
-                        );
+                        add_proc_macro_dep(crate_graph, crate_id, proc_macro, is_proc_macro);
                     }
                     rustc_pkg_crates.entry(pkg).or_insert_with(Vec::new).push(crate_id);
                 }
@@ -1234,17 +1213,7 @@ fn handle_rustc_crates(
             let name = CrateName::new(&dep.name).unwrap();
             if let Some(&to) = pkg_to_lib_crate.get(&dep.pkg) {
                 for &from in rustc_pkg_crates.get(&pkg).into_iter().flatten() {
-                    add_dep(
-                        crate_graph,
-                        from,
-                        name.clone(),
-                        to,
-                        match dep.kind {
-                            DepKind::Normal => DependencyKind::Normal,
-                            DepKind::Dev => DependencyKind::Dev,
-                            DepKind::Build => DependencyKind::Build,
-                        },
-                    );
+                    add_dep(crate_graph, from, name.clone(), to);
                 }
             }
         }
@@ -1266,7 +1235,7 @@ fn handle_rustc_crates(
                     // `rust_analyzer` thinks that it should use the one from the `rustc_source`
                     // instead of the one from `crates.io`
                     if !crate_graph[*from].dependencies.iter().any(|d| d.name == name) {
-                        add_dep(crate_graph, *from, name.clone(), to, DependencyKind::Normal);
+                        add_dep(crate_graph, *from, name.clone(), to);
                     }
                 }
             }
@@ -1282,10 +1251,8 @@ fn add_target_crate_root(
     cfg_options: CfgOptions,
     file_id: FileId,
     cargo_name: &str,
-    is_proc_macro: bool,
-    target_layout: TargetLayoutLoadResult,
-    rustc_crate: bool,
-    toolchain: Option<Version>,
+    kind: TargetKind,
+    origin: CrateOrigin,
 ) -> CrateId {
     let edition = pkg.edition;
     let potential_cfg_options = if pkg.features.is_empty() {
@@ -1332,18 +1299,10 @@ fn add_target_crate_root(
         cfg_options,
         potential_cfg_options,
         env,
-        is_proc_macro,
-        if rustc_crate {
-            CrateOrigin::Rustc { name: pkg.name.clone() }
-        } else if pkg.is_member {
-            CrateOrigin::Local { repo: pkg.repository.clone(), name: Some(pkg.name.clone()) }
-        } else {
-            CrateOrigin::Library { repo: pkg.repository.clone(), name: pkg.name.clone() }
-        },
-        target_layout,
-        toolchain,
+        matches!(kind, TargetKind::Lib { is_proc_macro: true }),
+        origin,
     );
-    if is_proc_macro {
+    if let TargetKind::Lib { is_proc_macro: true } = kind {
         let proc_macro = match build_data.as_ref().map(|it| it.proc_macro_dylib_path.as_ref()) {
             Some(it) => it.cloned().map(|path| Ok((Some(cargo_name.to_owned()), path))),
             None => Some(Err("crate has not yet been built".to_owned())),
@@ -1365,14 +1324,7 @@ impl SysrootPublicDeps {
     /// Makes `from` depend on the public sysroot crates.
     fn add_to_crate_graph(&self, crate_graph: &mut CrateGraph, from: CrateId) {
         for (name, krate, prelude) in &self.deps {
-            add_dep_with_prelude(
-                crate_graph,
-                from,
-                name.clone(),
-                *krate,
-                *prelude,
-                DependencyKind::Normal,
-            );
+            add_dep_with_prelude(crate_graph, from, name.clone(), *krate, *prelude);
         }
     }
 }
@@ -1381,9 +1333,7 @@ fn sysroot_to_crate_graph(
     crate_graph: &mut CrateGraph,
     sysroot: &Sysroot,
     rustc_cfg: Vec<CfgFlag>,
-    target_layout: TargetLayoutLoadResult,
     load: &mut dyn FnMut(&AbsPath) -> Option<FileId>,
-    toolchain: Option<&Version>,
 ) -> (SysrootPublicDeps, Option<CrateId>) {
     let _p = tracing::span!(tracing::Level::INFO, "sysroot_to_crate_graph").entered();
     match sysroot.mode() {
@@ -1396,8 +1346,6 @@ fn sysroot_to_crate_graph(
                 rustc_cfg,
                 &CfgOverrides::default(),
                 &WorkspaceBuildScripts::default(),
-                target_layout,
-                toolchain,
             );
 
             let mut pub_deps = vec![];
@@ -1440,17 +1388,16 @@ fn sysroot_to_crate_graph(
 
             // Remove all crates except the ones we are interested in to keep the sysroot graph small.
             let removed_mapping = cg.remove_crates_except(&marker_set);
+            let mapping = crate_graph.extend(cg, &mut pm, |(_, a), (_, b)| a == b);
 
-            crate_graph.extend(cg, &mut pm, |mapping| {
-                // Map the id through the removal mapping first, then through the crate graph extension mapping.
-                pub_deps.iter_mut().for_each(|(_, cid, _)| {
-                    *cid = mapping[&removed_mapping[cid.into_raw().into_u32() as usize].unwrap()]
-                });
-                if let Some(libproc_macro) = &mut libproc_macro {
-                    *libproc_macro = mapping
-                        [&removed_mapping[libproc_macro.into_raw().into_u32() as usize].unwrap()];
-                }
+            // Map the id through the removal mapping first, then through the crate graph extension mapping.
+            pub_deps.iter_mut().for_each(|(_, cid, _)| {
+                *cid = mapping[&removed_mapping[cid.into_raw().into_u32() as usize].unwrap()]
             });
+            if let Some(libproc_macro) = &mut libproc_macro {
+                *libproc_macro = mapping
+                    [&removed_mapping[libproc_macro.into_raw().into_u32() as usize].unwrap()];
+            }
 
             (SysrootPublicDeps { deps: pub_deps }, libproc_macro)
         }
@@ -1474,8 +1421,6 @@ fn sysroot_to_crate_graph(
                         env,
                         false,
                         CrateOrigin::Lang(LangCrateOrigin::from(&*stitched[krate].name)),
-                        target_layout.clone(),
-                        toolchain.cloned(),
                     );
                     Some((krate, crate_id))
                 })
@@ -1487,7 +1432,7 @@ fn sysroot_to_crate_graph(
                     if let (Some(&from), Some(&to)) =
                         (sysroot_crates.get(&from), sysroot_crates.get(&to))
                     {
-                        add_dep(crate_graph, from, name, to, DependencyKind::Normal);
+                        add_dep(crate_graph, from, name, to);
                     }
                 }
             }
@@ -1508,14 +1453,8 @@ fn sysroot_to_crate_graph(
     }
 }
 
-fn add_dep(
-    graph: &mut CrateGraph,
-    from: CrateId,
-    name: CrateName,
-    to: CrateId,
-    kind: DependencyKind,
-) {
-    add_dep_inner(graph, from, Dependency::new(name, to, kind))
+fn add_dep(graph: &mut CrateGraph, from: CrateId, name: CrateName, to: CrateId) {
+    add_dep_inner(graph, from, Dependency::new(name, to))
 }
 
 fn add_dep_with_prelude(
@@ -1524,20 +1463,12 @@ fn add_dep_with_prelude(
     name: CrateName,
     to: CrateId,
     prelude: bool,
-    kind: DependencyKind,
 ) {
-    add_dep_inner(graph, from, Dependency::with_prelude(name, to, prelude, kind))
+    add_dep_inner(graph, from, Dependency::with_prelude(name, to, prelude))
 }
 
 fn add_proc_macro_dep(crate_graph: &mut CrateGraph, from: CrateId, to: CrateId, prelude: bool) {
-    add_dep_with_prelude(
-        crate_graph,
-        from,
-        CrateName::new("proc_macro").unwrap(),
-        to,
-        prelude,
-        DependencyKind::Normal,
-    );
+    add_dep_with_prelude(crate_graph, from, CrateName::new("proc_macro").unwrap(), to, prelude);
 }
 
 fn add_dep_inner(graph: &mut CrateGraph, from: CrateId, dep: Dependency) {
@@ -1588,3 +1519,29 @@ fn create_cfg_options(rustc_cfg: Vec<CfgFlag>) -> CfgOptions {
     cfg_options.insert_atom("debug_assertions".into());
     cfg_options
 }
+
+fn cargo_config_env(
+    cargo_toml: &ManifestPath,
+    extra_env: &FxHashMap<String, String>,
+    sysroot: Option<&Sysroot>,
+) -> FxHashMap<String, String> {
+    let mut cargo_config = Command::new(Tool::Cargo.path());
+    Sysroot::set_rustup_toolchain_env(&mut cargo_config, sysroot);
+    cargo_config.envs(extra_env);
+    cargo_config
+        .current_dir(cargo_toml.parent())
+        .args(["-Z", "unstable-options", "config", "get", "env"])
+        .env("RUSTC_BOOTSTRAP", "1");
+    // if successful we receive `env.key.value = "value" per entry
+    tracing::debug!("Discovering cargo config env by {:?}", cargo_config);
+    utf8_stdout(cargo_config).map(parse_output_cargo_config_env).unwrap_or_default()
+}
+
+fn parse_output_cargo_config_env(stdout: String) -> FxHashMap<String, String> {
+    stdout
+        .lines()
+        .filter_map(|l| l.strip_prefix("env."))
+        .filter_map(|l| l.split_once(".value = "))
+        .map(|(key, value)| (key.to_owned(), value.trim_matches('"').to_owned()))
+        .collect()
+}
diff --git a/src/tools/rust-analyzer/crates/project-model/test_data/output/cargo_hello_world_project_model.txt b/src/tools/rust-analyzer/crates/project-model/test_data/output/cargo_hello_world_project_model.txt
index d8d9e559e5c..0ad19ca9f75 100644
--- a/src/tools/rust-analyzer/crates/project-model/test_data/output/cargo_hello_world_project_model.txt
+++ b/src/tools/rust-analyzer/crates/project-model/test_data/output/cargo_hello_world_project_model.txt
@@ -48,7 +48,6 @@
                 name: CrateName(
                     "libc",
                 ),
-                kind: Normal,
                 prelude: true,
             },
         ],
@@ -59,10 +58,6 @@
             ),
         },
         is_proc_macro: false,
-        target_layout: Err(
-            "target_data_layout not loaded",
-        ),
-        toolchain: None,
     },
     1: CrateData {
         root_file_id: FileId(
@@ -113,7 +108,6 @@
                 name: CrateName(
                     "hello_world",
                 ),
-                kind: Normal,
                 prelude: true,
             },
             Dependency {
@@ -121,7 +115,6 @@
                 name: CrateName(
                     "libc",
                 ),
-                kind: Normal,
                 prelude: true,
             },
         ],
@@ -132,10 +125,6 @@
             ),
         },
         is_proc_macro: false,
-        target_layout: Err(
-            "target_data_layout not loaded",
-        ),
-        toolchain: None,
     },
     2: CrateData {
         root_file_id: FileId(
@@ -186,7 +175,6 @@
                 name: CrateName(
                     "hello_world",
                 ),
-                kind: Normal,
                 prelude: true,
             },
             Dependency {
@@ -194,7 +182,6 @@
                 name: CrateName(
                     "libc",
                 ),
-                kind: Normal,
                 prelude: true,
             },
         ],
@@ -205,10 +192,6 @@
             ),
         },
         is_proc_macro: false,
-        target_layout: Err(
-            "target_data_layout not loaded",
-        ),
-        toolchain: None,
     },
     3: CrateData {
         root_file_id: FileId(
@@ -259,7 +242,6 @@
                 name: CrateName(
                     "hello_world",
                 ),
-                kind: Normal,
                 prelude: true,
             },
             Dependency {
@@ -267,7 +249,6 @@
                 name: CrateName(
                     "libc",
                 ),
-                kind: Normal,
                 prelude: true,
             },
         ],
@@ -278,10 +259,6 @@
             ),
         },
         is_proc_macro: false,
-        target_layout: Err(
-            "target_data_layout not loaded",
-        ),
-        toolchain: None,
     },
     4: CrateData {
         root_file_id: FileId(
@@ -347,9 +324,5 @@
             name: "libc",
         },
         is_proc_macro: false,
-        target_layout: Err(
-            "target_data_layout not loaded",
-        ),
-        toolchain: None,
     },
 }
\ No newline at end of file
diff --git a/src/tools/rust-analyzer/crates/project-model/test_data/output/cargo_hello_world_project_model_with_selective_overrides.txt b/src/tools/rust-analyzer/crates/project-model/test_data/output/cargo_hello_world_project_model_with_selective_overrides.txt
index d8d9e559e5c..0ad19ca9f75 100644
--- a/src/tools/rust-analyzer/crates/project-model/test_data/output/cargo_hello_world_project_model_with_selective_overrides.txt
+++ b/src/tools/rust-analyzer/crates/project-model/test_data/output/cargo_hello_world_project_model_with_selective_overrides.txt
@@ -48,7 +48,6 @@
                 name: CrateName(
                     "libc",
                 ),
-                kind: Normal,
                 prelude: true,
             },
         ],
@@ -59,10 +58,6 @@
             ),
         },
         is_proc_macro: false,
-        target_layout: Err(
-            "target_data_layout not loaded",
-        ),
-        toolchain: None,
     },
     1: CrateData {
         root_file_id: FileId(
@@ -113,7 +108,6 @@
                 name: CrateName(
                     "hello_world",
                 ),
-                kind: Normal,
                 prelude: true,
             },
             Dependency {
@@ -121,7 +115,6 @@
                 name: CrateName(
                     "libc",
                 ),
-                kind: Normal,
                 prelude: true,
             },
         ],
@@ -132,10 +125,6 @@
             ),
         },
         is_proc_macro: false,
-        target_layout: Err(
-            "target_data_layout not loaded",
-        ),
-        toolchain: None,
     },
     2: CrateData {
         root_file_id: FileId(
@@ -186,7 +175,6 @@
                 name: CrateName(
                     "hello_world",
                 ),
-                kind: Normal,
                 prelude: true,
             },
             Dependency {
@@ -194,7 +182,6 @@
                 name: CrateName(
                     "libc",
                 ),
-                kind: Normal,
                 prelude: true,
             },
         ],
@@ -205,10 +192,6 @@
             ),
         },
         is_proc_macro: false,
-        target_layout: Err(
-            "target_data_layout not loaded",
-        ),
-        toolchain: None,
     },
     3: CrateData {
         root_file_id: FileId(
@@ -259,7 +242,6 @@
                 name: CrateName(
                     "hello_world",
                 ),
-                kind: Normal,
                 prelude: true,
             },
             Dependency {
@@ -267,7 +249,6 @@
                 name: CrateName(
                     "libc",
                 ),
-                kind: Normal,
                 prelude: true,
             },
         ],
@@ -278,10 +259,6 @@
             ),
         },
         is_proc_macro: false,
-        target_layout: Err(
-            "target_data_layout not loaded",
-        ),
-        toolchain: None,
     },
     4: CrateData {
         root_file_id: FileId(
@@ -347,9 +324,5 @@
             name: "libc",
         },
         is_proc_macro: false,
-        target_layout: Err(
-            "target_data_layout not loaded",
-        ),
-        toolchain: None,
     },
 }
\ No newline at end of file
diff --git a/src/tools/rust-analyzer/crates/project-model/test_data/output/cargo_hello_world_project_model_with_wildcard_overrides.txt b/src/tools/rust-analyzer/crates/project-model/test_data/output/cargo_hello_world_project_model_with_wildcard_overrides.txt
index e0ba5ed498f..e2334dca875 100644
--- a/src/tools/rust-analyzer/crates/project-model/test_data/output/cargo_hello_world_project_model_with_wildcard_overrides.txt
+++ b/src/tools/rust-analyzer/crates/project-model/test_data/output/cargo_hello_world_project_model_with_wildcard_overrides.txt
@@ -47,7 +47,6 @@
                 name: CrateName(
                     "libc",
                 ),
-                kind: Normal,
                 prelude: true,
             },
         ],
@@ -58,10 +57,6 @@
             ),
         },
         is_proc_macro: false,
-        target_layout: Err(
-            "target_data_layout not loaded",
-        ),
-        toolchain: None,
     },
     1: CrateData {
         root_file_id: FileId(
@@ -111,7 +106,6 @@
                 name: CrateName(
                     "hello_world",
                 ),
-                kind: Normal,
                 prelude: true,
             },
             Dependency {
@@ -119,7 +113,6 @@
                 name: CrateName(
                     "libc",
                 ),
-                kind: Normal,
                 prelude: true,
             },
         ],
@@ -130,10 +123,6 @@
             ),
         },
         is_proc_macro: false,
-        target_layout: Err(
-            "target_data_layout not loaded",
-        ),
-        toolchain: None,
     },
     2: CrateData {
         root_file_id: FileId(
@@ -183,7 +172,6 @@
                 name: CrateName(
                     "hello_world",
                 ),
-                kind: Normal,
                 prelude: true,
             },
             Dependency {
@@ -191,7 +179,6 @@
                 name: CrateName(
                     "libc",
                 ),
-                kind: Normal,
                 prelude: true,
             },
         ],
@@ -202,10 +189,6 @@
             ),
         },
         is_proc_macro: false,
-        target_layout: Err(
-            "target_data_layout not loaded",
-        ),
-        toolchain: None,
     },
     3: CrateData {
         root_file_id: FileId(
@@ -255,7 +238,6 @@
                 name: CrateName(
                     "hello_world",
                 ),
-                kind: Normal,
                 prelude: true,
             },
             Dependency {
@@ -263,7 +245,6 @@
                 name: CrateName(
                     "libc",
                 ),
-                kind: Normal,
                 prelude: true,
             },
         ],
@@ -274,10 +255,6 @@
             ),
         },
         is_proc_macro: false,
-        target_layout: Err(
-            "target_data_layout not loaded",
-        ),
-        toolchain: None,
     },
     4: CrateData {
         root_file_id: FileId(
@@ -343,9 +320,5 @@
             name: "libc",
         },
         is_proc_macro: false,
-        target_layout: Err(
-            "target_data_layout not loaded",
-        ),
-        toolchain: None,
     },
 }
\ No newline at end of file
diff --git a/src/tools/rust-analyzer/crates/project-model/test_data/output/rust_project_hello_world_project_model.txt b/src/tools/rust-analyzer/crates/project-model/test_data/output/rust_project_hello_world_project_model.txt
index 0df99534c5b..ccaba963ded 100644
--- a/src/tools/rust-analyzer/crates/project-model/test_data/output/rust_project_hello_world_project_model.txt
+++ b/src/tools/rust-analyzer/crates/project-model/test_data/output/rust_project_hello_world_project_model.txt
@@ -28,7 +28,6 @@
                 name: CrateName(
                     "core",
                 ),
-                kind: Normal,
                 prelude: true,
             },
         ],
@@ -36,10 +35,6 @@
             Alloc,
         ),
         is_proc_macro: false,
-        target_layout: Err(
-            "rust-project.json projects have no target layout set",
-        ),
-        toolchain: None,
     },
     1: CrateData {
         root_file_id: FileId(
@@ -69,10 +64,6 @@
             Core,
         ),
         is_proc_macro: false,
-        target_layout: Err(
-            "rust-project.json projects have no target layout set",
-        ),
-        toolchain: None,
     },
     2: CrateData {
         root_file_id: FileId(
@@ -102,10 +93,6 @@
             Other,
         ),
         is_proc_macro: false,
-        target_layout: Err(
-            "rust-project.json projects have no target layout set",
-        ),
-        toolchain: None,
     },
     3: CrateData {
         root_file_id: FileId(
@@ -135,10 +122,6 @@
             Other,
         ),
         is_proc_macro: false,
-        target_layout: Err(
-            "rust-project.json projects have no target layout set",
-        ),
-        toolchain: None,
     },
     4: CrateData {
         root_file_id: FileId(
@@ -169,7 +152,6 @@
                 name: CrateName(
                     "std",
                 ),
-                kind: Normal,
                 prelude: true,
             },
             Dependency {
@@ -177,7 +159,6 @@
                 name: CrateName(
                     "core",
                 ),
-                kind: Normal,
                 prelude: true,
             },
         ],
@@ -185,10 +166,6 @@
             ProcMacro,
         ),
         is_proc_macro: false,
-        target_layout: Err(
-            "rust-project.json projects have no target layout set",
-        ),
-        toolchain: None,
     },
     5: CrateData {
         root_file_id: FileId(
@@ -218,10 +195,6 @@
             Other,
         ),
         is_proc_macro: false,
-        target_layout: Err(
-            "rust-project.json projects have no target layout set",
-        ),
-        toolchain: None,
     },
     6: CrateData {
         root_file_id: FileId(
@@ -252,7 +225,6 @@
                 name: CrateName(
                     "alloc",
                 ),
-                kind: Normal,
                 prelude: true,
             },
             Dependency {
@@ -260,7 +232,6 @@
                 name: CrateName(
                     "panic_unwind",
                 ),
-                kind: Normal,
                 prelude: true,
             },
             Dependency {
@@ -268,7 +239,6 @@
                 name: CrateName(
                     "panic_abort",
                 ),
-                kind: Normal,
                 prelude: true,
             },
             Dependency {
@@ -276,7 +246,6 @@
                 name: CrateName(
                     "core",
                 ),
-                kind: Normal,
                 prelude: true,
             },
             Dependency {
@@ -284,7 +253,6 @@
                 name: CrateName(
                     "profiler_builtins",
                 ),
-                kind: Normal,
                 prelude: true,
             },
             Dependency {
@@ -292,7 +260,6 @@
                 name: CrateName(
                     "unwind",
                 ),
-                kind: Normal,
                 prelude: true,
             },
             Dependency {
@@ -300,7 +267,6 @@
                 name: CrateName(
                     "std_detect",
                 ),
-                kind: Normal,
                 prelude: true,
             },
             Dependency {
@@ -308,7 +274,6 @@
                 name: CrateName(
                     "test",
                 ),
-                kind: Normal,
                 prelude: true,
             },
         ],
@@ -316,10 +281,6 @@
             Std,
         ),
         is_proc_macro: false,
-        target_layout: Err(
-            "rust-project.json projects have no target layout set",
-        ),
-        toolchain: None,
     },
     7: CrateData {
         root_file_id: FileId(
@@ -349,10 +310,6 @@
             Other,
         ),
         is_proc_macro: false,
-        target_layout: Err(
-            "rust-project.json projects have no target layout set",
-        ),
-        toolchain: None,
     },
     8: CrateData {
         root_file_id: FileId(
@@ -382,10 +339,6 @@
             Test,
         ),
         is_proc_macro: false,
-        target_layout: Err(
-            "rust-project.json projects have no target layout set",
-        ),
-        toolchain: None,
     },
     9: CrateData {
         root_file_id: FileId(
@@ -415,10 +368,6 @@
             Other,
         ),
         is_proc_macro: false,
-        target_layout: Err(
-            "rust-project.json projects have no target layout set",
-        ),
-        toolchain: None,
     },
     10: CrateData {
         root_file_id: FileId(
@@ -449,7 +398,6 @@
                 name: CrateName(
                     "core",
                 ),
-                kind: Normal,
                 prelude: true,
             },
             Dependency {
@@ -457,7 +405,6 @@
                 name: CrateName(
                     "alloc",
                 ),
-                kind: Normal,
                 prelude: true,
             },
             Dependency {
@@ -465,7 +412,6 @@
                 name: CrateName(
                     "std",
                 ),
-                kind: Normal,
                 prelude: true,
             },
             Dependency {
@@ -473,7 +419,6 @@
                 name: CrateName(
                     "test",
                 ),
-                kind: Normal,
                 prelude: false,
             },
             Dependency {
@@ -481,7 +426,6 @@
                 name: CrateName(
                     "proc_macro",
                 ),
-                kind: Normal,
                 prelude: false,
             },
         ],
@@ -492,9 +436,5 @@
             ),
         },
         is_proc_macro: false,
-        target_layout: Err(
-            "rust-project.json projects have no target layout set",
-        ),
-        toolchain: None,
     },
 }
\ No newline at end of file
diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/bin/main.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/bin/main.rs
index 269dd3cfffe..07e04a83661 100644
--- a/src/tools/rust-analyzer/crates/rust-analyzer/src/bin/main.rs
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/bin/main.rs
@@ -11,7 +11,7 @@ extern crate rustc_driver as _;
 
 mod rustc_wrapper;
 
-use std::{env, fs, path::PathBuf, process, sync::Arc};
+use std::{env, fs, path::PathBuf, process::ExitCode, sync::Arc};
 
 use anyhow::Context;
 use lsp_server::Connection;
@@ -27,21 +27,15 @@ static ALLOC: mimalloc::MiMalloc = mimalloc::MiMalloc;
 #[global_allocator]
 static ALLOC: jemallocator::Jemalloc = jemallocator::Jemalloc;
 
-fn main() -> anyhow::Result<()> {
+fn main() -> anyhow::Result<ExitCode> {
     if std::env::var("RA_RUSTC_WRAPPER").is_ok() {
-        let mut args = std::env::args_os();
-        let _me = args.next().unwrap();
-        let rustc = args.next().unwrap();
-        let code = match rustc_wrapper::run_rustc_skipping_cargo_checking(rustc, args.collect()) {
-            Ok(rustc_wrapper::ExitCode(code)) => code.unwrap_or(102),
-            Err(err) => {
-                eprintln!("{err}");
-                101
-            }
-        };
-        process::exit(code);
+        rustc_wrapper::main().map_err(Into::into)
+    } else {
+        actual_main()
     }
+}
 
+fn actual_main() -> anyhow::Result<ExitCode> {
     let flags = flags::RustAnalyzer::from_env_or_exit();
 
     #[cfg(debug_assertions)]
@@ -58,14 +52,14 @@ fn main() -> anyhow::Result<()> {
     let verbosity = flags.verbosity();
 
     match flags.subcommand {
-        flags::RustAnalyzerCmd::LspServer(cmd) => {
+        flags::RustAnalyzerCmd::LspServer(cmd) => 'lsp_server: {
             if cmd.print_config_schema {
                 println!("{:#}", Config::json_schema());
-                return Ok(());
+                break 'lsp_server;
             }
             if cmd.version {
                 println!("rust-analyzer {}", rust_analyzer::version());
-                return Ok(());
+                break 'lsp_server;
             }
 
             // rust-analyzer’s “main thread” is actually
@@ -90,7 +84,7 @@ fn main() -> anyhow::Result<()> {
         flags::RustAnalyzerCmd::RunTests(cmd) => cmd.run()?,
         flags::RustAnalyzerCmd::RustcTests(cmd) => cmd.run()?,
     }
-    Ok(())
+    Ok(ExitCode::SUCCESS)
 }
 
 fn setup_logging(log_file_flag: Option<PathBuf>) -> anyhow::Result<()> {
diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/bin/rustc_wrapper.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/bin/rustc_wrapper.rs
index 38e9c7dd7e1..684b3f52afc 100644
--- a/src/tools/rust-analyzer/crates/rust-analyzer/src/bin/rustc_wrapper.rs
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/bin/rustc_wrapper.rs
@@ -7,13 +7,17 @@
 use std::{
     ffi::OsString,
     io,
-    process::{Command, Stdio},
+    process::{Command, ExitCode, Stdio},
 };
 
-/// ExitCode/ExitStatus are impossible to create :(.
-pub(crate) struct ExitCode(pub(crate) Option<i32>);
+pub(crate) fn main() -> io::Result<ExitCode> {
+    let mut args = std::env::args_os();
+    let _me = args.next().unwrap();
+    let rustc = args.next().unwrap();
+    run_rustc_skipping_cargo_checking(rustc, args.collect())
+}
 
-pub(crate) fn run_rustc_skipping_cargo_checking(
+fn run_rustc_skipping_cargo_checking(
     rustc_executable: OsString,
     args: Vec<OsString>,
 ) -> io::Result<ExitCode> {
@@ -35,9 +39,10 @@ pub(crate) fn run_rustc_skipping_cargo_checking(
         arg.starts_with("--emit=") && arg.contains("metadata") && !arg.contains("link")
     });
     if not_invoked_by_build_script && is_cargo_check {
-        return Ok(ExitCode(Some(0)));
+        Ok(ExitCode::from(0))
+    } else {
+        run_rustc(rustc_executable, args)
     }
-    run_rustc(rustc_executable, args)
 }
 
 fn run_rustc(rustc_executable: OsString, args: Vec<OsString>) -> io::Result<ExitCode> {
@@ -47,5 +52,5 @@ fn run_rustc(rustc_executable: OsString, args: Vec<OsString>) -> io::Result<Exit
         .stdout(Stdio::inherit())
         .stderr(Stdio::inherit())
         .spawn()?;
-    Ok(ExitCode(child.wait()?.code()))
+    Ok(ExitCode::from(child.wait()?.code().unwrap_or(102) as u8))
 }
diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/cargo_target_spec.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/cargo_target_spec.rs
index 0190ca3cab8..f9f26178259 100644
--- a/src/tools/rust-analyzer/crates/rust-analyzer/src/cargo_target_spec.rs
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/cargo_target_spec.rs
@@ -4,7 +4,7 @@ use std::mem;
 
 use cfg::{CfgAtom, CfgExpr};
 use ide::{Cancellable, CrateId, FileId, RunnableKind, TestId};
-use project_model::{self, CargoFeatures, ManifestPath, TargetKind};
+use project_model::{CargoFeatures, ManifestPath, TargetKind};
 use rustc_hash::FxHashSet;
 use vfs::AbsPathBuf;
 
@@ -174,7 +174,7 @@ impl CargoTargetSpec {
                 buf.push("--example".to_owned());
                 buf.push(self.target);
             }
-            TargetKind::Lib => {
+            TargetKind::Lib { is_proc_macro: _ } => {
                 buf.push("--lib".to_owned());
             }
             TargetKind::Other | TargetKind::BuildScript => (),
diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/analysis_stats.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/analysis_stats.rs
index 2741b452225..ce7e3b3cd6a 100644
--- a/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/analysis_stats.rs
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/analysis_stats.rs
@@ -32,7 +32,7 @@ use oorandom::Rand32;
 use profile::{Bytes, StopWatch};
 use project_model::{CargoConfig, ProjectManifest, ProjectWorkspace, RustLibSource};
 use rayon::prelude::*;
-use rustc_hash::FxHashSet;
+use rustc_hash::{FxHashMap, FxHashSet};
 use syntax::{AstNode, SyntaxNode};
 use vfs::{AbsPathBuf, FileId, Vfs, VfsPath};
 
@@ -91,7 +91,7 @@ impl flags::AnalysisStats {
         };
 
         let (host, vfs, _proc_macro) =
-            load_workspace(workspace, &cargo_config.extra_env, &load_cargo_config)?;
+            load_workspace(workspace.clone(), &cargo_config.extra_env, &load_cargo_config)?;
         let db = host.raw_database();
         eprint!("{:<20} {}", "Database loaded:", db_load_sw.elapsed());
         eprint!(" (metadata {metadata_time}");
@@ -232,7 +232,11 @@ impl flags::AnalysisStats {
         }
 
         if self.run_all_ide_things {
-            self.run_ide_things(host.analysis(), file_ids);
+            self.run_ide_things(host.analysis(), file_ids.clone());
+        }
+
+        if self.run_term_search {
+            self.run_term_search(&workspace, db, &vfs, file_ids, verbosity);
         }
 
         let total_span = analysis_sw.elapsed();
@@ -321,6 +325,212 @@ impl flags::AnalysisStats {
         report_metric("const eval time", const_eval_time.time.as_millis() as u64, "ms");
     }
 
+    fn run_term_search(
+        &self,
+        ws: &ProjectWorkspace,
+        db: &RootDatabase,
+        vfs: &Vfs,
+        mut file_ids: Vec<FileId>,
+        verbosity: Verbosity,
+    ) {
+        let cargo_config = CargoConfig {
+            sysroot: match self.no_sysroot {
+                true => None,
+                false => Some(RustLibSource::Discover),
+            },
+            ..Default::default()
+        };
+
+        let mut bar = match verbosity {
+            Verbosity::Quiet | Verbosity::Spammy => ProgressReport::hidden(),
+            _ if self.parallel || self.output.is_some() => ProgressReport::hidden(),
+            _ => ProgressReport::new(file_ids.len() as u64),
+        };
+
+        file_ids.sort();
+        file_ids.dedup();
+
+        #[derive(Debug, Default)]
+        struct Acc {
+            tail_expr_syntax_hits: u64,
+            tail_expr_no_term: u64,
+            total_tail_exprs: u64,
+            error_codes: FxHashMap<String, u32>,
+            syntax_errors: u32,
+        }
+
+        let mut acc: Acc = Default::default();
+        bar.tick();
+        let mut sw = self.stop_watch();
+
+        for &file_id in &file_ids {
+            let sema = hir::Semantics::new(db);
+            let _ = db.parse(file_id);
+
+            let parse = sema.parse(file_id);
+            let file_txt = db.file_text(file_id);
+            let path = vfs.file_path(file_id).as_path().unwrap().to_owned();
+
+            for node in parse.syntax().descendants() {
+                let expr = match syntax::ast::Expr::cast(node.clone()) {
+                    Some(it) => it,
+                    None => continue,
+                };
+                let block = match syntax::ast::BlockExpr::cast(expr.syntax().clone()) {
+                    Some(it) => it,
+                    None => continue,
+                };
+                let target_ty = match sema.type_of_expr(&expr) {
+                    Some(it) => it.adjusted(),
+                    None => continue, // Failed to infer type
+                };
+
+                let expected_tail = match block.tail_expr() {
+                    Some(it) => it,
+                    None => continue,
+                };
+
+                if expected_tail.is_block_like() {
+                    continue;
+                }
+
+                let range = sema.original_range(expected_tail.syntax()).range;
+                let original_text: String = db
+                    .file_text(file_id)
+                    .chars()
+                    .skip(usize::from(range.start()))
+                    .take(usize::from(range.end()) - usize::from(range.start()))
+                    .collect();
+
+                let scope = match sema.scope(expected_tail.syntax()) {
+                    Some(it) => it,
+                    None => continue,
+                };
+
+                let ctx = hir::term_search::TermSearchCtx {
+                    sema: &sema,
+                    scope: &scope,
+                    goal: target_ty,
+                    config: hir::term_search::TermSearchConfig {
+                        enable_borrowcheck: true,
+                        ..Default::default()
+                    },
+                };
+                let found_terms = hir::term_search::term_search(&ctx);
+
+                if found_terms.is_empty() {
+                    acc.tail_expr_no_term += 1;
+                    acc.total_tail_exprs += 1;
+                    // println!("\n{}\n", &original_text);
+                    continue;
+                };
+
+                fn trim(s: &str) -> String {
+                    s.chars().filter(|c| !c.is_whitespace()).collect()
+                }
+
+                let todo = syntax::ast::make::ext::expr_todo().to_string();
+                let mut formatter = |_: &hir::Type| todo.clone();
+                let mut syntax_hit_found = false;
+                for term in found_terms {
+                    let generated =
+                        term.gen_source_code(&scope, &mut formatter, false, true).unwrap();
+                    syntax_hit_found |= trim(&original_text) == trim(&generated);
+
+                    // Validate if type-checks
+                    let mut txt = file_txt.to_string();
+
+                    let edit = ide::TextEdit::replace(range, generated.clone());
+                    edit.apply(&mut txt);
+
+                    if self.validate_term_search {
+                        std::fs::write(&path, txt).unwrap();
+
+                        let res = ws.run_build_scripts(&cargo_config, &|_| ()).unwrap();
+                        if let Some(err) = res.error() {
+                            if err.contains("error: could not compile") {
+                                if let Some(mut err_idx) = err.find("error[E") {
+                                    err_idx += 7;
+                                    let err_code = &err[err_idx..err_idx + 4];
+                                    match err_code {
+                                        "0282" => continue,                              // Byproduct of testing method
+                                        "0277" if generated.contains(&todo) => continue, // See https://github.com/rust-lang/rust/issues/69882
+                                        _ => (),
+                                    }
+                                    bar.println(err);
+                                    bar.println(generated);
+                                    acc.error_codes
+                                        .entry(err_code.to_owned())
+                                        .and_modify(|n| *n += 1)
+                                        .or_insert(1);
+                                } else {
+                                    acc.syntax_errors += 1;
+                                    bar.println(format!("Syntax error: \n{}", err));
+                                }
+                            }
+                        }
+                    }
+                }
+
+                if syntax_hit_found {
+                    acc.tail_expr_syntax_hits += 1;
+                }
+                acc.total_tail_exprs += 1;
+
+                let msg = move || {
+                    format!(
+                        "processing: {:<50}",
+                        trim(&original_text).chars().take(50).collect::<String>()
+                    )
+                };
+                if verbosity.is_spammy() {
+                    bar.println(msg());
+                }
+                bar.set_message(msg);
+            }
+            // Revert file back to original state
+            if self.validate_term_search {
+                std::fs::write(&path, file_txt.to_string()).unwrap();
+            }
+
+            bar.inc(1);
+        }
+        let term_search_time = sw.elapsed();
+
+        bar.println(format!(
+            "Tail Expr syntactic hits: {}/{} ({}%)",
+            acc.tail_expr_syntax_hits,
+            acc.total_tail_exprs,
+            percentage(acc.tail_expr_syntax_hits, acc.total_tail_exprs)
+        ));
+        bar.println(format!(
+            "Tail Exprs found: {}/{} ({}%)",
+            acc.total_tail_exprs - acc.tail_expr_no_term,
+            acc.total_tail_exprs,
+            percentage(acc.total_tail_exprs - acc.tail_expr_no_term, acc.total_tail_exprs)
+        ));
+        if self.validate_term_search {
+            bar.println(format!(
+                "Tail Exprs total errors: {}, syntax errors: {}, error codes:",
+                acc.error_codes.values().sum::<u32>() + acc.syntax_errors,
+                acc.syntax_errors,
+            ));
+            for (err, count) in acc.error_codes {
+                bar.println(format!(
+                    "    E{err}: {count:>5}  (https://doc.rust-lang.org/error_codes/E{err}.html)"
+                ));
+            }
+        }
+        bar.println(format!(
+            "Term search avg time: {}ms",
+            term_search_time.time.as_millis() as u64 / acc.total_tail_exprs
+        ));
+        bar.println(format!("{:<20} {}", "Term search:", term_search_time));
+        report_metric("term search time", term_search_time.time.as_millis() as u64, "ms");
+
+        bar.finish_and_clear();
+    }
+
     fn run_mir_lowering(&self, db: &RootDatabase, bodies: &[DefWithBody], verbosity: Verbosity) {
         let mut sw = self.stop_watch();
         let mut all = 0;
diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/flags.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/flags.rs
index 252b1e1a485..493e614dce6 100644
--- a/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/flags.rs
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/flags.rs
@@ -93,6 +93,11 @@ xflags::xflags! {
             /// and annotations. This is useful for benchmarking the memory usage on a project that has
             /// been worked on for a bit in a longer running session.
             optional --run-all-ide-things
+            /// Run term search on all the tail expressions (of functions, block, if statements etc.)
+            optional --run-term-search
+            /// Validate term search by running `cargo check` on every response.
+            /// Note that this also temporarily modifies the files on disk, use with caution!
+            optional --validate-term-search
         }
 
         /// Run unit tests of the project using mir interpreter
@@ -218,6 +223,8 @@ pub struct AnalysisStats {
     pub skip_data_layout: bool,
     pub skip_const_eval: bool,
     pub run_all_ide_things: bool,
+    pub run_term_search: bool,
+    pub validate_term_search: bool,
 }
 
 #[derive(Debug)]
diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/lsif.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/lsif.rs
index 1424a775777..5e810463db6 100644
--- a/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/lsif.rs
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/lsif.rs
@@ -13,7 +13,7 @@ use ide_db::{
     LineIndexDatabase,
 };
 use load_cargo::{load_workspace, LoadCargoConfig, ProcMacroServerChoice};
-use lsp_types::{self, lsif};
+use lsp_types::lsif;
 use project_model::{CargoConfig, ProjectManifest, ProjectWorkspace, RustLibSource};
 use rustc_hash::FxHashMap;
 use vfs::{AbsPathBuf, Vfs};
diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/scip.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/scip.rs
index f4aec288348..2d56830c87f 100644
--- a/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/scip.rs
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/scip.rs
@@ -135,12 +135,11 @@ impl flags::Scip {
                     }
 
                     if symbols_emitted.insert(id) {
-                        let documentation = token
-                            .hover
-                            .as_ref()
-                            .map(|hover| hover.markup.as_str())
-                            .filter(|it| !it.is_empty())
-                            .map(|it| vec![it.to_owned()]);
+                        let documentation = match &token.documentation {
+                            Some(doc) => vec![doc.as_str().to_owned()],
+                            None => vec![],
+                        };
+
                         let position_encoding =
                             scip_types::PositionEncoding::UTF8CodeUnitOffsetFromLineStart.into();
                         let signature_documentation =
@@ -153,7 +152,7 @@ impl flags::Scip {
                             });
                         let symbol_info = scip_types::SymbolInformation {
                             symbol: symbol.clone(),
-                            documentation: documentation.unwrap_or_default(),
+                            documentation,
                             relationships: Vec::new(),
                             special_fields: Default::default(),
                             kind: symbol_kind(token.kind).into(),
@@ -599,4 +598,22 @@ pub mod example_mod {
             "rust-analyzer cargo main . MyTypeAlias#",
         );
     }
+
+    #[test]
+    fn documentation_matches_doc_comment() {
+        let s = "/// foo\nfn bar() {}";
+
+        let mut host = AnalysisHost::default();
+        let change_fixture = ChangeFixture::parse(s);
+        host.raw_database_mut().apply_change(change_fixture.change);
+
+        let analysis = host.analysis();
+        let si = StaticIndex::compute(&analysis);
+
+        let file = si.files.first().unwrap();
+        let (_, token_id) = file.tokens.first().unwrap();
+        let token = si.tokens.get(*token_id).unwrap();
+
+        assert_eq!(token.documentation.as_ref().map(|d| d.as_str()), Some("foo"));
+    }
 }
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 7bdd9ec866a..16e1a2f5449 100644
--- a/src/tools/rust-analyzer/crates/rust-analyzer/src/config.rs
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/config.rs
@@ -112,7 +112,7 @@ config_data! {
         cargo_buildScripts_overrideCommand: Option<Vec<String>> = "null",
         /// Rerun proc-macros building/build-scripts running when proc-macro
         /// or build-script sources change and are saved.
-        cargo_buildScripts_rebuildOnSave: bool = "false",
+        cargo_buildScripts_rebuildOnSave: bool = "true",
         /// Use `RUSTC_WRAPPER=rust-analyzer` when running build scripts to
         /// avoid checking unnecessary things.
         cargo_buildScripts_useRustcWrapper: bool = "true",
@@ -209,6 +209,11 @@ config_data! {
         /// by changing `#rust-analyzer.check.invocationStrategy#` and
         /// `#rust-analyzer.check.invocationLocation#`.
         ///
+        /// If `$saved_file` is part of the command, rust-analyzer will pass
+        /// the absolute path of the saved file to the provided command. This is
+        /// intended to be used with non-Cargo build systems.
+        /// Note that `$saved_file` is experimental and may be removed in the futureg.
+        ///
         /// An example command would be:
         ///
         /// ```bash
@@ -286,6 +291,8 @@ config_data! {
                 "scope": "expr"
             }
         }"#,
+        /// Whether to enable term search based snippets like `Some(foo.bar().baz())`.
+        completion_termSearch_enable: bool = "false",
 
         /// List of rust-analyzer diagnostics to disable.
         diagnostics_disabled: FxHashSet<String> = "[]",
@@ -504,9 +511,6 @@ config_data! {
         /// Exclude tests from find-all-references.
         references_excludeTests: bool = "false",
 
-        /// Allow renaming of items not belonging to the loaded workspaces.
-        rename_allowExternalItems: bool = "false",
-
 
         /// Command to be executed instead of 'cargo' for runnables.
         runnables_command: Option<String> = "null",
@@ -1202,7 +1206,7 @@ impl Config {
         Some(AbsPathBuf::try_from(path).unwrap_or_else(|path| self.root_path.join(path)))
     }
 
-    pub fn dummy_replacements(&self) -> &FxHashMap<Box<str>, Box<[Box<str>]>> {
+    pub fn ignored_proc_macros(&self) -> &FxHashMap<Box<str>, Box<[Box<str>]>> {
         &self.data.procMacro_ignored
     }
 
@@ -1535,6 +1539,7 @@ impl Config {
                 && completion_item_edit_resolve(&self.caps),
             enable_self_on_the_fly: self.data.completion_autoself_enable,
             enable_private_editable: self.data.completion_privateEditable_enable,
+            enable_term_search: self.data.completion_termSearch_enable,
             full_function_signatures: self.data.completion_fullFunctionSignatures_enable,
             callable: match self.data.completion_callable_snippets {
                 CallableCompletionDef::FillArguments => Some(CallableSnippets::FillArguments),
@@ -1766,10 +1771,6 @@ impl Config {
         self.data.typing_autoClosingAngleBrackets_enable
     }
 
-    pub fn rename(&self) -> bool {
-        self.data.rename_allowExternalItems
-    }
-
     // FIXME: VSCode seems to work wrong sometimes, see https://github.com/microsoft/vscode/issues/193124
     // hence, distinguish it for now.
     pub fn is_visual_studio_code(&self) -> bool {
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 da4422a60a8..293807a383b 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,7 +9,7 @@ use crossbeam_channel::{unbounded, Receiver, Sender};
 use flycheck::FlycheckHandle;
 use hir::Change;
 use ide::{Analysis, AnalysisHost, Cancellable, FileId};
-use ide_db::base_db::{CrateId, FileLoader, ProcMacroPaths, SourceDatabase};
+use ide_db::base_db::{CrateId, ProcMacroPaths};
 use load_cargo::SourceRootConfig;
 use lsp_types::{SemanticTokens, Url};
 use nohash_hasher::IntMap;
@@ -74,8 +74,8 @@ pub(crate) struct GlobalState {
     pub(crate) last_reported_status: Option<lsp_ext::ServerStatusParams>,
 
     // proc macros
-    pub(crate) proc_macro_changed: bool,
     pub(crate) proc_macro_clients: Arc<[anyhow::Result<ProcMacroServer>]>,
+    pub(crate) build_deps_changed: bool,
 
     // Flycheck
     pub(crate) flycheck: Arc<[FlycheckHandle]>,
@@ -203,9 +203,10 @@ impl GlobalState {
             source_root_config: SourceRootConfig::default(),
             config_errors: Default::default(),
 
-            proc_macro_changed: false,
             proc_macro_clients: Arc::from_iter([]),
 
+            build_deps_changed: false,
+
             flycheck: Arc::from_iter([]),
             flycheck_sender,
             flycheck_receiver,
@@ -300,12 +301,19 @@ impl GlobalState {
                 if let Some(path) = vfs_path.as_path() {
                     let path = path.to_path_buf();
                     if reload::should_refresh_for_change(&path, file.kind()) {
-                        workspace_structure_change = Some((path.clone(), false));
+                        workspace_structure_change = Some((
+                            path.clone(),
+                            false,
+                            AsRef::<std::path::Path>::as_ref(&path).ends_with("build.rs"),
+                        ));
                     }
                     if file.is_created_or_deleted() {
                         has_structure_changes = true;
-                        workspace_structure_change =
-                            Some((path, self.crate_graph_file_dependencies.contains(vfs_path)));
+                        workspace_structure_change = Some((
+                            path,
+                            self.crate_graph_file_dependencies.contains(vfs_path),
+                            false,
+                        ));
                     } else if path.extension() == Some("rs".as_ref()) {
                         modified_rust_files.push(file.file_id);
                     }
@@ -346,23 +354,28 @@ impl GlobalState {
         };
 
         self.analysis_host.apply_change(change);
+
         {
-            let raw_database = self.analysis_host.raw_database();
+            if !matches!(&workspace_structure_change, Some((.., true))) {
+                _ = self
+                    .deferred_task_queue
+                    .sender
+                    .send(crate::main_loop::QueuedTask::CheckProcMacroSources(modified_rust_files));
+            }
             // FIXME: ideally we should only trigger a workspace fetch for non-library changes
             // but something's going wrong with the source root business when we add a new local
             // crate see https://github.com/rust-lang/rust-analyzer/issues/13029
-            if let Some((path, force_crate_graph_reload)) = workspace_structure_change {
+            if let Some((path, force_crate_graph_reload, build_scripts_touched)) =
+                workspace_structure_change
+            {
                 self.fetch_workspaces_queue.request_op(
                     format!("workspace vfs file change: {path}"),
                     force_crate_graph_reload,
                 );
+                if build_scripts_touched {
+                    self.fetch_build_data_queue.request_op(format!("build.rs changed: {path}"), ());
+                }
             }
-            self.proc_macro_changed = modified_rust_files.into_iter().any(|file_id| {
-                let crates = raw_database.relevant_crates(file_id);
-                let crate_graph = raw_database.crate_graph();
-
-                crates.iter().any(|&krate| crate_graph[krate].is_proc_macro)
-            });
         }
 
         true
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 d3c2073f09d..b13c709dbfe 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
@@ -145,11 +145,11 @@ pub(crate) fn handle_did_save_text_document(
     state: &mut GlobalState,
     params: DidSaveTextDocumentParams,
 ) -> anyhow::Result<()> {
-    if state.config.script_rebuild_on_save() && state.proc_macro_changed {
-        // reset the flag
-        state.proc_macro_changed = false;
-        // rebuild the proc macros
-        state.fetch_build_data_queue.request_op("ScriptRebuildOnSave".to_owned(), ());
+    if state.config.script_rebuild_on_save() && state.build_deps_changed {
+        state.build_deps_changed = false;
+        state
+            .fetch_build_data_queue
+            .request_op("build_deps_changed - save notification".to_owned(), ());
     }
 
     if let Ok(vfs_path) = from_proto::vfs_path(&params.text_document.uri) {
@@ -158,7 +158,7 @@ pub(crate) fn handle_did_save_text_document(
             if reload::should_refresh_for_change(abs_path, ChangeKind::Modify) {
                 state
                     .fetch_workspaces_queue
-                    .request_op(format!("DidSaveTextDocument {abs_path}"), false);
+                    .request_op(format!("workspace vfs file change saved {abs_path}"), false);
             }
         }
 
@@ -168,7 +168,7 @@ pub(crate) fn handle_did_save_text_document(
     } else if state.config.check_on_save() {
         // No specific flycheck was triggered, so let's trigger all of them.
         for flycheck in state.flycheck.iter() {
-            flycheck.restart_workspace();
+            flycheck.restart_workspace(None);
         }
     }
     Ok(())
@@ -314,6 +314,8 @@ fn run_flycheck(state: &mut GlobalState, vfs_path: VfsPath) -> bool {
                 Some((idx, package))
             });
 
+            let saved_file = vfs_path.as_path().map(|p| p.to_owned());
+
             // Find and trigger corresponding flychecks
             for flycheck in world.flycheck.iter() {
                 for (id, package) in workspace_ids.clone() {
@@ -321,7 +323,7 @@ fn run_flycheck(state: &mut GlobalState, vfs_path: VfsPath) -> bool {
                         updated = true;
                         match package.filter(|_| !world.config.flycheck_workspace()) {
                             Some(package) => flycheck.restart_for_package(package),
-                            None => flycheck.restart_workspace(),
+                            None => flycheck.restart_workspace(saved_file.clone()),
                         }
                         continue;
                     }
@@ -330,7 +332,7 @@ fn run_flycheck(state: &mut GlobalState, vfs_path: VfsPath) -> bool {
             // No specific flycheck was triggered, so let's trigger all of them.
             if !updated {
                 for flycheck in world.flycheck.iter() {
-                    flycheck.restart_workspace();
+                    flycheck.restart_workspace(saved_file.clone());
                 }
             }
             Ok(())
@@ -372,7 +374,7 @@ pub(crate) fn handle_run_flycheck(
     }
     // No specific flycheck was triggered, so let's trigger all of them.
     for flycheck in state.flycheck.iter() {
-        flycheck.restart_workspace();
+        flycheck.restart_workspace(None);
     }
     Ok(())
 }
diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/handlers/request.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/handlers/request.rs
index 2a3633a48e9..eb9d4bf0f02 100644
--- a/src/tools/rust-analyzer/crates/rust-analyzer/src/handlers/request.rs
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/handlers/request.rs
@@ -52,7 +52,7 @@ use crate::{
 
 pub(crate) fn handle_workspace_reload(state: &mut GlobalState, _: ()) -> anyhow::Result<()> {
     state.proc_macro_clients = Arc::from_iter([]);
-    state.proc_macro_changed = false;
+    state.build_deps_changed = false;
 
     state.fetch_workspaces_queue.request_op("reload workspace request".to_owned(), false);
     Ok(())
@@ -60,7 +60,7 @@ pub(crate) fn handle_workspace_reload(state: &mut GlobalState, _: ()) -> anyhow:
 
 pub(crate) fn handle_proc_macros_rebuild(state: &mut GlobalState, _: ()) -> anyhow::Result<()> {
     state.proc_macro_clients = Arc::from_iter([]);
-    state.proc_macro_changed = false;
+    state.build_deps_changed = false;
 
     state.fetch_build_data_queue.request_op("rebuild proc macros request".to_owned(), ());
     Ok(())
@@ -1017,10 +1017,8 @@ pub(crate) fn handle_rename(
     let _p = tracing::span!(tracing::Level::INFO, "handle_rename").entered();
     let position = from_proto::file_position(&snap, params.text_document_position)?;
 
-    let mut change = snap
-        .analysis
-        .rename(position, &params.new_name, snap.config.rename())?
-        .map_err(to_proto::rename_error)?;
+    let mut change =
+        snap.analysis.rename(position, &params.new_name)?.map_err(to_proto::rename_error)?;
 
     // this is kind of a hack to prevent double edits from happening when moving files
     // When a module gets renamed by renaming the mod declaration this causes the file to move
@@ -1937,6 +1935,7 @@ fn run_rustfmt(
 
     let mut command = match snap.config.rustfmt() {
         RustfmtConfig::Rustfmt { extra_args, enable_range_formatting } => {
+            // FIXME: Set RUSTUP_TOOLCHAIN
             let mut cmd = process::Command::new(toolchain::rustfmt());
             cmd.envs(snap.config.extra_env());
             cmd.args(extra_args);
diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/integrated_benchmarks.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/integrated_benchmarks.rs
index acc02d6447c..f0eee77aff5 100644
--- a/src/tools/rust-analyzer/crates/rust-analyzer/src/integrated_benchmarks.rs
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/integrated_benchmarks.rs
@@ -132,6 +132,7 @@ fn integrated_completion_benchmark() {
             enable_imports_on_the_fly: true,
             enable_self_on_the_fly: true,
             enable_private_editable: true,
+            enable_term_search: true,
             full_function_signatures: false,
             callable: Some(CallableSnippets::FillArguments),
             snippet_cap: SnippetCap::new(true),
@@ -175,6 +176,7 @@ fn integrated_completion_benchmark() {
             enable_imports_on_the_fly: true,
             enable_self_on_the_fly: true,
             enable_private_editable: true,
+            enable_term_search: true,
             full_function_signatures: false,
             callable: Some(CallableSnippets::FillArguments),
             snippet_cap: SnippetCap::new(true),
@@ -216,6 +218,7 @@ fn integrated_completion_benchmark() {
             enable_imports_on_the_fly: true,
             enable_self_on_the_fly: true,
             enable_private_editable: true,
+            enable_term_search: true,
             full_function_signatures: false,
             callable: Some(CallableSnippets::FillArguments),
             snippet_cap: SnippetCap::new(true),
diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/lib.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/lib.rs
index b1809f58ae7..473ca991ad9 100644
--- a/src/tools/rust-analyzer/crates/rust-analyzer/src/lib.rs
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/lib.rs
@@ -47,7 +47,9 @@ mod integrated_benchmarks;
 
 use serde::de::DeserializeOwned;
 
-pub use crate::{caps::server_capabilities, main_loop::main_loop, version::version};
+pub use crate::{
+    caps::server_capabilities, main_loop::main_loop, reload::ws_to_crate_graph, version::version,
+};
 
 pub fn from_json<T: DeserializeOwned>(
     what: &'static str,
diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/lsp/to_proto.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/lsp/to_proto.rs
index 64f19f0b32d..727007bba08 100644
--- a/src/tools/rust-analyzer/crates/rust-analyzer/src/lsp/to_proto.rs
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/lsp/to_proto.rs
@@ -123,6 +123,7 @@ pub(crate) fn completion_item_kind(
         CompletionItemKind::Method => lsp_types::CompletionItemKind::METHOD,
         CompletionItemKind::Snippet => lsp_types::CompletionItemKind::SNIPPET,
         CompletionItemKind::UnresolvedReference => lsp_types::CompletionItemKind::REFERENCE,
+        CompletionItemKind::Expression => lsp_types::CompletionItemKind::SNIPPET,
         CompletionItemKind::SymbolKind(symbol) => match symbol {
             SymbolKind::Attribute => lsp_types::CompletionItemKind::FUNCTION,
             SymbolKind::Const => lsp_types::CompletionItemKind::CONSTANT,
@@ -929,6 +930,16 @@ fn merge_text_and_snippet_edits(
     let mut edits: Vec<SnippetTextEdit> = vec![];
     let mut snippets = snippet_edit.into_edit_ranges().into_iter().peekable();
     let text_edits = edit.into_iter();
+    // offset to go from the final source location to the original source location
+    let mut source_text_offset = 0i32;
+
+    let offset_range = |range: TextRange, offset: i32| -> TextRange {
+        // map the snippet range from the target location into the original source location
+        let start = u32::from(range.start()).checked_add_signed(offset).unwrap_or(0);
+        let end = u32::from(range.end()).checked_add_signed(offset).unwrap_or(0);
+
+        TextRange::new(start.into(), end.into())
+    };
 
     for current_indel in text_edits {
         let new_range = {
@@ -937,10 +948,17 @@ fn merge_text_and_snippet_edits(
             TextRange::at(current_indel.delete.start(), insert_len)
         };
 
+        // figure out how much this Indel will shift future ranges from the initial source
+        let offset_adjustment =
+            u32::from(current_indel.delete.len()) as i32 - u32::from(new_range.len()) as i32;
+
         // insert any snippets before the text edit
-        for (snippet_index, snippet_range) in
-            snippets.take_while_ref(|(_, range)| range.end() < new_range.start())
-        {
+        for (snippet_index, snippet_range) in snippets.peeking_take_while(|(_, range)| {
+            offset_range(*range, source_text_offset).end() < new_range.start()
+        }) {
+            // adjust the snippet range into the corresponding initial source location
+            let snippet_range = offset_range(snippet_range, source_text_offset);
+
             let snippet_range = if !stdx::always!(
                 snippet_range.is_empty(),
                 "placeholder range {:?} is before current text edit range {:?}",
@@ -953,22 +971,23 @@ fn merge_text_and_snippet_edits(
                 snippet_range
             };
 
-            let range = range(line_index, snippet_range);
-            let new_text = format!("${snippet_index}");
-
-            edits.push(SnippetTextEdit {
-                range,
-                new_text,
-                insert_text_format: Some(lsp_types::InsertTextFormat::SNIPPET),
-                annotation_id: None,
-            })
+            edits.push(snippet_text_edit(
+                line_index,
+                true,
+                Indel { insert: format!("${snippet_index}"), delete: snippet_range },
+            ))
         }
 
-        if snippets.peek().is_some_and(|(_, range)| new_range.intersect(*range).is_some()) {
+        if snippets.peek().is_some_and(|(_, range)| {
+            new_range.intersect(offset_range(*range, source_text_offset)).is_some()
+        }) {
             // at least one snippet edit intersects this text edit,
             // so gather all of the edits that intersect this text edit
             let mut all_snippets = snippets
-                .take_while_ref(|(_, range)| new_range.intersect(*range).is_some())
+                .peeking_take_while(|(_, range)| {
+                    new_range.intersect(offset_range(*range, source_text_offset)).is_some()
+                })
+                .map(|(tabstop, range)| (tabstop, offset_range(range, source_text_offset)))
                 .collect_vec();
 
             // ensure all of the ranges are wholly contained inside of the new range
@@ -979,40 +998,59 @@ fn merge_text_and_snippet_edits(
                     )
                 });
 
-            let mut text_edit = text_edit(line_index, current_indel);
+            let mut new_text = current_indel.insert;
 
-            // escape out snippet text
-            stdx::replace(&mut text_edit.new_text, '\\', r"\\");
-            stdx::replace(&mut text_edit.new_text, '$', r"\$");
+            // find which snippet bits need to be escaped
+            let escape_places = new_text
+                .rmatch_indices(['\\', '$', '{', '}'])
+                .map(|(insert, _)| insert)
+                .collect_vec();
+            let mut escape_places = escape_places.into_iter().peekable();
+            let mut escape_prior_bits = |new_text: &mut String, up_to: usize| {
+                for before in escape_places.peeking_take_while(|insert| *insert >= up_to) {
+                    new_text.insert(before, '\\');
+                }
+            };
 
-            // ...and apply!
+            // insert snippets, and escaping any needed bits along the way
             for (index, range) in all_snippets.iter().rev() {
-                let start = (range.start() - new_range.start()).into();
-                let end = (range.end() - new_range.start()).into();
+                let text_range = range - new_range.start();
+                let (start, end) = (text_range.start().into(), text_range.end().into());
 
                 if range.is_empty() {
-                    text_edit.new_text.insert_str(start, &format!("${index}"));
+                    escape_prior_bits(&mut new_text, start);
+                    new_text.insert_str(start, &format!("${index}"));
                 } else {
-                    text_edit.new_text.insert(end, '}');
-                    text_edit.new_text.insert_str(start, &format!("${{{index}:"));
+                    escape_prior_bits(&mut new_text, end);
+                    new_text.insert(end, '}');
+                    escape_prior_bits(&mut new_text, start);
+                    new_text.insert_str(start, &format!("${{{index}:"));
                 }
             }
 
-            edits.push(SnippetTextEdit {
-                range: text_edit.range,
-                new_text: text_edit.new_text,
-                insert_text_format: Some(lsp_types::InsertTextFormat::SNIPPET),
-                annotation_id: None,
-            })
+            // escape any remaining bits
+            escape_prior_bits(&mut new_text, 0);
+
+            edits.push(snippet_text_edit(
+                line_index,
+                true,
+                Indel { insert: new_text, delete: current_indel.delete },
+            ))
         } else {
             // snippet edit was beyond the current one
             // since it wasn't consumed, it's available for the next pass
             edits.push(snippet_text_edit(line_index, false, current_indel));
         }
+
+        // update the final source -> initial source mapping offset
+        source_text_offset += offset_adjustment;
     }
 
     // insert any remaining tabstops
     edits.extend(snippets.map(|(snippet_index, snippet_range)| {
+        // adjust the snippet range into the corresponding initial source location
+        let snippet_range = offset_range(snippet_range, source_text_offset);
+
         let snippet_range = if !stdx::always!(
             snippet_range.is_empty(),
             "found placeholder snippet {:?} without a text edit",
@@ -1023,15 +1061,11 @@ fn merge_text_and_snippet_edits(
             snippet_range
         };
 
-        let range = range(line_index, snippet_range);
-        let new_text = format!("${snippet_index}");
-
-        SnippetTextEdit {
-            range,
-            new_text,
-            insert_text_format: Some(lsp_types::InsertTextFormat::SNIPPET),
-            annotation_id: None,
-        }
+        snippet_text_edit(
+            line_index,
+            true,
+            Indel { insert: format!("${snippet_index}"), delete: snippet_range },
+        )
     }));
 
     edits
@@ -1658,15 +1692,44 @@ fn bar(_: usize) {}
         assert!(!docs.contains("use crate::bar"));
     }
 
+    #[track_caller]
     fn check_rendered_snippets(edit: TextEdit, snippets: SnippetEdit, expect: Expect) {
-        let text = r#"/* place to put all ranges in */"#;
+        check_rendered_snippets_in_source(
+            r"/* place to put all ranges in */",
+            edit,
+            snippets,
+            expect,
+        );
+    }
+
+    #[track_caller]
+    fn check_rendered_snippets_in_source(
+        ra_fixture: &str,
+        edit: TextEdit,
+        snippets: SnippetEdit,
+        expect: Expect,
+    ) {
+        let source = stdx::trim_indent(ra_fixture);
+        let endings = if source.contains('\r') { LineEndings::Dos } else { LineEndings::Unix };
         let line_index = LineIndex {
-            index: Arc::new(ide::LineIndex::new(text)),
-            endings: LineEndings::Unix,
+            index: Arc::new(ide::LineIndex::new(&source)),
+            endings,
             encoding: PositionEncoding::Utf8,
         };
 
         let res = merge_text_and_snippet_edits(&line_index, edit, snippets);
+
+        // Ensure that none of the ranges overlap
+        {
+            let mut sorted = res.clone();
+            sorted.sort_by_key(|edit| (edit.range.start, edit.range.end));
+            let disjoint_ranges = sorted
+                .iter()
+                .zip(sorted.iter().skip(1))
+                .all(|(l, r)| l.range.end <= r.range.start || l == r);
+            assert!(disjoint_ranges, "ranges overlap for {res:#?}");
+        }
+
         expect.assert_debug_eq(&res);
     }
 
@@ -1811,7 +1874,8 @@ fn bar(_: usize) {}
         let mut edit = TextEdit::builder();
         edit.insert(0.into(), "abc".to_owned());
         let edit = edit.finish();
-        let snippets = SnippetEdit::new(vec![Snippet::Tabstop(7.into())]);
+        // Note: tabstops are positioned in the source where all text edits have been applied
+        let snippets = SnippetEdit::new(vec![Snippet::Tabstop(10.into())]);
 
         check_rendered_snippets(
             edit,
@@ -1928,8 +1992,9 @@ fn bar(_: usize) {}
         edit.insert(0.into(), "abc".to_owned());
         edit.insert(7.into(), "abc".to_owned());
         let edit = edit.finish();
+        // Note: tabstops are positioned in the source where all text edits have been applied
         let snippets =
-            SnippetEdit::new(vec![Snippet::Tabstop(4.into()), Snippet::Tabstop(4.into())]);
+            SnippetEdit::new(vec![Snippet::Tabstop(7.into()), Snippet::Tabstop(7.into())]);
 
         check_rendered_snippets(
             edit,
@@ -2085,52 +2150,526 @@ fn bar(_: usize) {}
     fn snippet_rendering_escape_snippet_bits() {
         // only needed for snippet formats
         let mut edit = TextEdit::builder();
-        edit.insert(0.into(), r"abc\def$".to_owned());
-        edit.insert(8.into(), r"ghi\jkl$".to_owned());
+        edit.insert(0.into(), r"$ab{}$c\def".to_owned());
+        edit.insert(8.into(), r"ghi\jk<-check_insert_here$".to_owned());
+        edit.insert(10.into(), r"a\\b\\c{}$".to_owned());
         let edit = edit.finish();
-        let snippets =
-            SnippetEdit::new(vec![Snippet::Placeholder(TextRange::new(0.into(), 3.into()))]);
+        let snippets = SnippetEdit::new(vec![
+            Snippet::Placeholder(TextRange::new(1.into(), 9.into())),
+            Snippet::Tabstop(25.into()),
+        ]);
 
         check_rendered_snippets(
             edit,
             snippets,
             expect![[r#"
+                [
+                    SnippetTextEdit {
+                        range: Range {
+                            start: Position {
+                                line: 0,
+                                character: 0,
+                            },
+                            end: Position {
+                                line: 0,
+                                character: 0,
+                            },
+                        },
+                        new_text: "\\$${1:ab\\{\\}\\$c\\\\d}ef",
+                        insert_text_format: Some(
+                            Snippet,
+                        ),
+                        annotation_id: None,
+                    },
+                    SnippetTextEdit {
+                        range: Range {
+                            start: Position {
+                                line: 0,
+                                character: 8,
+                            },
+                            end: Position {
+                                line: 0,
+                                character: 8,
+                            },
+                        },
+                        new_text: "ghi\\\\jk$0<-check_insert_here\\$",
+                        insert_text_format: Some(
+                            Snippet,
+                        ),
+                        annotation_id: None,
+                    },
+                    SnippetTextEdit {
+                        range: Range {
+                            start: Position {
+                                line: 0,
+                                character: 10,
+                            },
+                            end: Position {
+                                line: 0,
+                                character: 10,
+                            },
+                        },
+                        new_text: "a\\\\b\\\\c{}$",
+                        insert_text_format: None,
+                        annotation_id: None,
+                    },
+                ]
+            "#]],
+        );
+    }
+
+    #[test]
+    fn snippet_rendering_tabstop_adjust_offset_deleted() {
+        // negative offset from inserting a smaller range
+        let mut edit = TextEdit::builder();
+        edit.replace(TextRange::new(47.into(), 56.into()), "let".to_owned());
+        edit.replace(
+            TextRange::new(57.into(), 89.into()),
+            "disabled = false;\n    ProcMacro {\n        disabled,\n    }".to_owned(),
+        );
+        let edit = edit.finish();
+        let snippets = SnippetEdit::new(vec![Snippet::Tabstop(51.into())]);
+
+        check_rendered_snippets_in_source(
+            r"
+fn expander_to_proc_macro() -> ProcMacro {
+    ProcMacro {
+        disabled: false,
+    }
+}
+
+struct ProcMacro {
+    disabled: bool,
+}",
+            edit,
+            snippets,
+            expect![[r#"
+                [
+                    SnippetTextEdit {
+                        range: Range {
+                            start: Position {
+                                line: 1,
+                                character: 4,
+                            },
+                            end: Position {
+                                line: 1,
+                                character: 13,
+                            },
+                        },
+                        new_text: "let",
+                        insert_text_format: None,
+                        annotation_id: None,
+                    },
+                    SnippetTextEdit {
+                        range: Range {
+                            start: Position {
+                                line: 1,
+                                character: 14,
+                            },
+                            end: Position {
+                                line: 3,
+                                character: 5,
+                            },
+                        },
+                        new_text: "$0disabled = false;\n    ProcMacro \\{\n        disabled,\n    \\}",
+                        insert_text_format: Some(
+                            Snippet,
+                        ),
+                        annotation_id: None,
+                    },
+                ]
+            "#]],
+        );
+    }
+
+    #[test]
+    fn snippet_rendering_tabstop_adjust_offset_added() {
+        // positive offset from inserting a larger range
+        let mut edit = TextEdit::builder();
+        edit.replace(TextRange::new(39.into(), 40.into()), "let".to_owned());
+        edit.replace(
+            TextRange::new(41.into(), 73.into()),
+            "disabled = false;\n    ProcMacro {\n        disabled,\n    }".to_owned(),
+        );
+        let edit = edit.finish();
+        let snippets = SnippetEdit::new(vec![Snippet::Tabstop(43.into())]);
+
+        check_rendered_snippets_in_source(
+            r"
+fn expander_to_proc_macro() -> P {
+    P {
+        disabled: false,
+    }
+}
+
+struct P {
+    disabled: bool,
+}",
+            edit,
+            snippets,
+            expect![[r#"
+                [
+                    SnippetTextEdit {
+                        range: Range {
+                            start: Position {
+                                line: 1,
+                                character: 4,
+                            },
+                            end: Position {
+                                line: 1,
+                                character: 5,
+                            },
+                        },
+                        new_text: "let",
+                        insert_text_format: None,
+                        annotation_id: None,
+                    },
+                    SnippetTextEdit {
+                        range: Range {
+                            start: Position {
+                                line: 1,
+                                character: 6,
+                            },
+                            end: Position {
+                                line: 3,
+                                character: 5,
+                            },
+                        },
+                        new_text: "$0disabled = false;\n    ProcMacro \\{\n        disabled,\n    \\}",
+                        insert_text_format: Some(
+                            Snippet,
+                        ),
+                        annotation_id: None,
+                    },
+                ]
+            "#]],
+        );
+    }
+
+    #[test]
+    fn snippet_rendering_placeholder_adjust_offset_deleted() {
+        // negative offset from inserting a smaller range
+        let mut edit = TextEdit::builder();
+        edit.replace(TextRange::new(47.into(), 56.into()), "let".to_owned());
+        edit.replace(
+            TextRange::new(57.into(), 89.into()),
+            "disabled = false;\n    ProcMacro {\n        disabled,\n    }".to_owned(),
+        );
+        let edit = edit.finish();
+        let snippets =
+            SnippetEdit::new(vec![Snippet::Placeholder(TextRange::new(51.into(), 59.into()))]);
+
+        check_rendered_snippets_in_source(
+            r"
+fn expander_to_proc_macro() -> ProcMacro {
+    ProcMacro {
+        disabled: false,
+    }
+}
+
+struct ProcMacro {
+    disabled: bool,
+}",
+            edit,
+            snippets,
+            expect![[r#"
+                [
+                    SnippetTextEdit {
+                        range: Range {
+                            start: Position {
+                                line: 1,
+                                character: 4,
+                            },
+                            end: Position {
+                                line: 1,
+                                character: 13,
+                            },
+                        },
+                        new_text: "let",
+                        insert_text_format: None,
+                        annotation_id: None,
+                    },
+                    SnippetTextEdit {
+                        range: Range {
+                            start: Position {
+                                line: 1,
+                                character: 14,
+                            },
+                            end: Position {
+                                line: 3,
+                                character: 5,
+                            },
+                        },
+                        new_text: "${0:disabled} = false;\n    ProcMacro \\{\n        disabled,\n    \\}",
+                        insert_text_format: Some(
+                            Snippet,
+                        ),
+                        annotation_id: None,
+                    },
+                ]
+            "#]],
+        );
+    }
+
+    #[test]
+    fn snippet_rendering_placeholder_adjust_offset_added() {
+        // positive offset from inserting a larger range
+        let mut edit = TextEdit::builder();
+        edit.replace(TextRange::new(39.into(), 40.into()), "let".to_owned());
+        edit.replace(
+            TextRange::new(41.into(), 73.into()),
+            "disabled = false;\n    ProcMacro {\n        disabled,\n    }".to_owned(),
+        );
+        let edit = edit.finish();
+        let snippets =
+            SnippetEdit::new(vec![Snippet::Placeholder(TextRange::new(43.into(), 51.into()))]);
+
+        check_rendered_snippets_in_source(
+            r"
+fn expander_to_proc_macro() -> P {
+    P {
+        disabled: false,
+    }
+}
+
+struct P {
+    disabled: bool,
+}",
+            edit,
+            snippets,
+            expect![[r#"
+                [
+                    SnippetTextEdit {
+                        range: Range {
+                            start: Position {
+                                line: 1,
+                                character: 4,
+                            },
+                            end: Position {
+                                line: 1,
+                                character: 5,
+                            },
+                        },
+                        new_text: "let",
+                        insert_text_format: None,
+                        annotation_id: None,
+                    },
+                    SnippetTextEdit {
+                        range: Range {
+                            start: Position {
+                                line: 1,
+                                character: 6,
+                            },
+                            end: Position {
+                                line: 3,
+                                character: 5,
+                            },
+                        },
+                        new_text: "${0:disabled} = false;\n    ProcMacro \\{\n        disabled,\n    \\}",
+                        insert_text_format: Some(
+                            Snippet,
+                        ),
+                        annotation_id: None,
+                    },
+                ]
+            "#]],
+        );
+    }
+
+    #[test]
+    fn snippet_rendering_tabstop_adjust_offset_between_text_edits() {
+        // inserting between edits, tabstop should be at (1, 14)
+        let mut edit = TextEdit::builder();
+        edit.replace(TextRange::new(47.into(), 56.into()), "let".to_owned());
+        edit.replace(
+            TextRange::new(58.into(), 90.into()),
+            "disabled = false;\n    ProcMacro {\n        disabled,\n    }".to_owned(),
+        );
+        let edit = edit.finish();
+        let snippets = SnippetEdit::new(vec![Snippet::Tabstop(51.into())]);
+
+        // add an extra space between `ProcMacro` and `{` to insert the tabstop at
+        check_rendered_snippets_in_source(
+            r"
+fn expander_to_proc_macro() -> ProcMacro {
+    ProcMacro  {
+        disabled: false,
+    }
+}
+
+struct ProcMacro {
+    disabled: bool,
+}",
+            edit,
+            snippets,
+            expect![[r#"
+    [
+        SnippetTextEdit {
+            range: Range {
+                start: Position {
+                    line: 1,
+                    character: 4,
+                },
+                end: Position {
+                    line: 1,
+                    character: 13,
+                },
+            },
+            new_text: "let",
+            insert_text_format: None,
+            annotation_id: None,
+        },
+        SnippetTextEdit {
+            range: Range {
+                start: Position {
+                    line: 1,
+                    character: 14,
+                },
+                end: Position {
+                    line: 1,
+                    character: 14,
+                },
+            },
+            new_text: "$0",
+            insert_text_format: Some(
+                Snippet,
+            ),
+            annotation_id: None,
+        },
+        SnippetTextEdit {
+            range: Range {
+                start: Position {
+                    line: 1,
+                    character: 15,
+                },
+                end: Position {
+                    line: 3,
+                    character: 5,
+                },
+            },
+            new_text: "disabled = false;\n    ProcMacro {\n        disabled,\n    }",
+            insert_text_format: None,
+            annotation_id: None,
+        },
+    ]
+"#]],
+        );
+    }
+
+    #[test]
+    fn snippet_rendering_tabstop_adjust_offset_after_text_edits() {
+        // inserting after edits, tabstop should be before the closing curly of the fn
+        let mut edit = TextEdit::builder();
+        edit.replace(TextRange::new(47.into(), 56.into()), "let".to_owned());
+        edit.replace(
+            TextRange::new(57.into(), 89.into()),
+            "disabled = false;\n    ProcMacro {\n        disabled,\n    }".to_owned(),
+        );
+        let edit = edit.finish();
+        let snippets = SnippetEdit::new(vec![Snippet::Tabstop(109.into())]);
+
+        check_rendered_snippets_in_source(
+            r"
+fn expander_to_proc_macro() -> ProcMacro {
+    ProcMacro {
+        disabled: false,
+    }
+}
+
+struct ProcMacro {
+    disabled: bool,
+}",
+            edit,
+            snippets,
+            expect![[r#"
+    [
+        SnippetTextEdit {
+            range: Range {
+                start: Position {
+                    line: 1,
+                    character: 4,
+                },
+                end: Position {
+                    line: 1,
+                    character: 13,
+                },
+            },
+            new_text: "let",
+            insert_text_format: None,
+            annotation_id: None,
+        },
+        SnippetTextEdit {
+            range: Range {
+                start: Position {
+                    line: 1,
+                    character: 14,
+                },
+                end: Position {
+                    line: 3,
+                    character: 5,
+                },
+            },
+            new_text: "disabled = false;\n    ProcMacro {\n        disabled,\n    }",
+            insert_text_format: None,
+            annotation_id: None,
+        },
+        SnippetTextEdit {
+            range: Range {
+                start: Position {
+                    line: 4,
+                    character: 0,
+                },
+                end: Position {
+                    line: 4,
+                    character: 0,
+                },
+            },
+            new_text: "$0",
+            insert_text_format: Some(
+                Snippet,
+            ),
+            annotation_id: None,
+        },
+    ]
+"#]],
+        );
+    }
+
+    #[test]
+    fn snippet_rendering_handle_dos_line_endings() {
+        // unix -> dos conversion should be handled after placing snippets
+        let mut edit = TextEdit::builder();
+        edit.insert(6.into(), "\n\n->".to_owned());
+
+        let edit = edit.finish();
+        let snippets = SnippetEdit::new(vec![Snippet::Tabstop(10.into())]);
+
+        check_rendered_snippets_in_source(
+            "yeah\r\n<-tabstop here",
+            edit,
+            snippets,
+            expect![[r#"
             [
                 SnippetTextEdit {
                     range: Range {
                         start: Position {
-                            line: 0,
+                            line: 1,
                             character: 0,
                         },
                         end: Position {
-                            line: 0,
+                            line: 1,
                             character: 0,
                         },
                     },
-                    new_text: "${0:abc}\\\\def\\$",
+                    new_text: "\r\n\r\n->$0",
                     insert_text_format: Some(
                         Snippet,
                     ),
                     annotation_id: None,
                 },
-                SnippetTextEdit {
-                    range: Range {
-                        start: Position {
-                            line: 0,
-                            character: 8,
-                        },
-                        end: Position {
-                            line: 0,
-                            character: 8,
-                        },
-                    },
-                    new_text: "ghi\\jkl$",
-                    insert_text_format: None,
-                    annotation_id: None,
-                },
             ]
         "#]],
-        );
+        )
     }
 
     // `Url` is not able to parse windows paths on unix machines.
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 88660db7e93..72f6d0fde5f 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
@@ -8,12 +8,10 @@ use std::{
 
 use always_assert::always;
 use crossbeam_channel::{select, Receiver};
-use flycheck::FlycheckHandle;
-use ide_db::base_db::{SourceDatabaseExt, VfsPath};
+use ide_db::base_db::{SourceDatabase, SourceDatabaseExt, VfsPath};
 use lsp_server::{Connection, Notification, Request};
 use lsp_types::notification::Notification as _;
 use stdx::thread::ThreadIntent;
-use triomphe::Arc;
 use vfs::FileId;
 
 use crate::{
@@ -77,6 +75,7 @@ impl fmt::Display for Event {
 #[derive(Debug)]
 pub(crate) enum QueuedTask {
     CheckIfIndexed(lsp_types::Url),
+    CheckProcMacroSources(Vec<FileId>),
 }
 
 #[derive(Debug)]
@@ -89,6 +88,7 @@ pub(crate) enum Task {
     FetchWorkspace(ProjectWorkspaceProgress),
     FetchBuildData(BuildDataProgress),
     LoadProcMacros(ProcMacroProgress),
+    BuildDepsHaveChanged,
 }
 
 #[derive(Debug)]
@@ -337,7 +337,7 @@ impl GlobalState {
             if became_quiescent {
                 if self.config.check_on_save() {
                     // Project has loaded properly, kick off initial flycheck
-                    self.flycheck.iter().for_each(FlycheckHandle::restart_workspace);
+                    self.flycheck.iter().for_each(|flycheck| flycheck.restart_workspace(None));
                 }
                 if self.config.prefill_caches() {
                     self.prime_caches_queue.request_op("became quiescent".to_owned(), ());
@@ -358,9 +358,7 @@ impl GlobalState {
                 }
 
                 // Refresh inlay hints if the client supports it.
-                if (self.send_hint_refresh_query || self.proc_macro_changed)
-                    && self.config.inlay_hints_refresh()
-                {
+                if self.send_hint_refresh_query && self.config.inlay_hints_refresh() {
                     self.send_request::<lsp_types::request::InlayHintRefreshRequest>((), |_, _| ());
                     self.send_hint_refresh_query = false;
                 }
@@ -555,16 +553,7 @@ impl GlobalState {
                         if let Err(e) = self.fetch_workspace_error() {
                             tracing::error!("FetchWorkspaceError:\n{e}");
                         }
-
-                        let old = Arc::clone(&self.workspaces);
                         self.switch_workspaces("fetched workspace".to_owned());
-                        let workspaces_updated = !Arc::ptr_eq(&old, &self.workspaces);
-
-                        if self.config.run_build_scripts() && workspaces_updated {
-                            self.fetch_build_data_queue
-                                .request_op("workspace updated".to_owned(), ());
-                        }
-
                         (Progress::End, None)
                     }
                 };
@@ -608,6 +597,7 @@ impl GlobalState {
                     self.report_progress("Loading", state, msg, None, None);
                 }
             }
+            Task::BuildDepsHaveChanged => self.build_deps_changed = true,
         }
     }
 
@@ -686,6 +676,25 @@ impl GlobalState {
                     }
                 });
             }
+            QueuedTask::CheckProcMacroSources(modified_rust_files) => {
+                let crate_graph = self.analysis_host.raw_database().crate_graph();
+                let snap = self.snapshot();
+                self.task_pool.handle.spawn_with_sender(stdx::thread::ThreadIntent::Worker, {
+                    move |sender| {
+                        if modified_rust_files.into_iter().any(|file_id| {
+                            // FIXME: Check whether these files could be build script related
+                            match snap.analysis.crates_for(file_id) {
+                                Ok(crates) => {
+                                    crates.iter().any(|&krate| crate_graph[krate].is_proc_macro)
+                                }
+                                _ => false,
+                            }
+                        }) {
+                            sender.send(Task::BuildDepsHaveChanged).unwrap();
+                        }
+                    }
+                });
+            }
         }
     }
 
diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/reload.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/reload.rs
index 7bd2877b00c..5895459d1fc 100644
--- a/src/tools/rust-analyzer/crates/rust-analyzer/src/reload.rs
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/reload.rs
@@ -17,8 +17,9 @@ use std::{iter, mem};
 
 use flycheck::{FlycheckConfig, FlycheckHandle};
 use hir::{db::DefDatabase, Change, ProcMacros};
+use ide::CrateId;
 use ide_db::{
-    base_db::{salsa::Durability, CrateGraph, ProcMacroPaths},
+    base_db::{salsa::Durability, CrateGraph, ProcMacroPaths, Version},
     FxHashMap,
 };
 use itertools::Itertools;
@@ -28,7 +29,7 @@ use project_model::{ProjectWorkspace, WorkspaceBuildScripts};
 use rustc_hash::FxHashSet;
 use stdx::{format_to, thread::ThreadIntent};
 use triomphe::Arc;
-use vfs::{AbsPath, ChangeKind};
+use vfs::{AbsPath, AbsPathBuf, ChangeKind};
 
 use crate::{
     config::{Config, FilesWatcher, LinkedProject},
@@ -83,7 +84,7 @@ impl GlobalState {
         }
         if self.config.linked_or_discovered_projects() != old_config.linked_or_discovered_projects()
         {
-            self.fetch_workspaces_queue.request_op("linked projects changed".to_owned(), false)
+            self.fetch_workspaces_queue.request_op("discovered projects changed".to_owned(), false)
         } else if self.config.flycheck() != old_config.flycheck() {
             self.reload_flycheck();
         }
@@ -106,9 +107,11 @@ impl GlobalState {
         };
         let mut message = String::new();
 
-        if self.proc_macro_changed {
+        if self.build_deps_changed {
             status.health = lsp_ext::Health::Warning;
-            message.push_str("Proc-macros have changed and need to be rebuilt.\n\n");
+            message.push_str(
+                "Proc-macros and/or build scripts have changed and need to be rebuilt.\n\n",
+            );
         }
         if self.fetch_build_data_error().is_err() {
             status.health = lsp_ext::Health::Warning;
@@ -234,7 +237,6 @@ impl GlobalState {
                                 it.clone(),
                                 cargo_config.target.as_deref(),
                                 &cargo_config.extra_env,
-                                None,
                             ))
                         }
                     })
@@ -300,13 +302,13 @@ impl GlobalState {
 
     pub(crate) fn fetch_proc_macros(&mut self, cause: Cause, paths: Vec<ProcMacroPaths>) {
         tracing::info!(%cause, "will load proc macros");
-        let dummy_replacements = self.config.dummy_replacements().clone();
+        let ignored_proc_macros = self.config.ignored_proc_macros().clone();
         let proc_macro_clients = self.proc_macro_clients.clone();
 
         self.task_pool.handle.spawn_with_sender(ThreadIntent::Worker, move |sender| {
             sender.send(Task::LoadProcMacros(ProcMacroProgress::Begin)).unwrap();
 
-            let dummy_replacements = &dummy_replacements;
+            let ignored_proc_macros = &ignored_proc_macros;
             let progress = {
                 let sender = sender.clone();
                 &move |msg| {
@@ -334,7 +336,12 @@ impl GlobalState {
                                         crate_name
                                             .as_deref()
                                             .and_then(|crate_name| {
-                                                dummy_replacements.get(crate_name).map(|v| &**v)
+                                                ignored_proc_macros.iter().find_map(
+                                                    |(name, macros)| {
+                                                        eq_ignore_underscore(name, crate_name)
+                                                            .then_some(&**macros)
+                                                    },
+                                                )
                                             })
                                             .unwrap_or_default(),
                                     )
@@ -404,6 +411,10 @@ impl GlobalState {
                 if *force_reload_crate_graph {
                     self.recreate_crate_graph(cause);
                 }
+                if self.build_deps_changed && self.config.run_build_scripts() {
+                    self.build_deps_changed = false;
+                    self.fetch_build_data_queue.request_op("build_deps_changed".to_owned(), ());
+                }
                 // Current build scripts do not match the version of the active
                 // workspace, so there's nothing for us to update.
                 return;
@@ -415,6 +426,11 @@ impl GlobalState {
             // we don't care about build-script results, they are stale.
             // FIXME: can we abort the build scripts here?
             self.workspaces = Arc::new(workspaces);
+
+            if self.config.run_build_scripts() {
+                self.build_deps_changed = false;
+                self.fetch_build_data_queue.request_op("workspace updated".to_owned(), ());
+            }
         }
 
         if let FilesWatcher::Client = self.config.files().watcher {
@@ -464,8 +480,23 @@ impl GlobalState {
                     None => ws.find_sysroot_proc_macro_srv()?,
                 };
 
+                let env =
+                    match ws {
+                        ProjectWorkspace::Cargo { cargo_config_extra_env, sysroot, .. } => {
+                            cargo_config_extra_env
+                                .iter()
+                                .chain(self.config.extra_env())
+                                .map(|(a, b)| (a.clone(), b.clone()))
+                                .chain(sysroot.as_ref().map(|it| {
+                                    ("RUSTUP_TOOLCHAIN".to_owned(), it.root().to_string())
+                                }))
+                                .collect()
+                        }
+                        _ => Default::default(),
+                    };
                 tracing::info!("Using proc-macro server at {path}");
-                ProcMacroServer::spawn(path.clone()).map_err(|err| {
+
+                ProcMacroServer::spawn(path.clone(), &env).map_err(|err| {
                     tracing::error!(
                         "Failed to run proc-macro server from path {path}, error: {err:?}",
                     );
@@ -494,15 +525,15 @@ impl GlobalState {
     }
 
     fn recreate_crate_graph(&mut self, cause: String) {
-        // Create crate graph from all the workspaces
-        let (crate_graph, proc_macro_paths, crate_graph_file_dependencies) = {
+        {
+            // Create crate graph from all the workspaces
             let vfs = &mut self.vfs.write().0;
             let loader = &mut self.loader;
             // crate graph construction relies on these paths, record them so when one of them gets
             // deleted or created we trigger a reconstruction of the crate graph
             let mut crate_graph_file_dependencies = FxHashSet::default();
 
-            let mut load = |path: &AbsPath| {
+            let load = |path: &AbsPath| {
                 let _p = tracing::span!(tracing::Level::DEBUG, "switch_workspaces::load").entered();
                 let vfs_path = vfs::VfsPath::from(path.to_path_buf());
                 crate_graph_file_dependencies.insert(vfs_path.clone());
@@ -517,32 +548,26 @@ impl GlobalState {
                 }
             };
 
-            let mut crate_graph = CrateGraph::default();
-            let mut proc_macros = Vec::default();
-            for ws in &**self.workspaces {
-                let (other, mut crate_proc_macros) =
-                    ws.to_crate_graph(&mut load, self.config.extra_env());
-                crate_graph.extend(other, &mut crate_proc_macros, |_| {});
-                proc_macros.push(crate_proc_macros);
-            }
-            (crate_graph, proc_macros, crate_graph_file_dependencies)
-        };
+            let (crate_graph, proc_macro_paths, layouts, toolchains) =
+                ws_to_crate_graph(&self.workspaces, self.config.extra_env(), load);
 
-        let mut change = Change::new();
-        if self.config.expand_proc_macros() {
-            change.set_proc_macros(
-                crate_graph
-                    .iter()
-                    .map(|id| (id, Err("Proc-macros have not been built yet".to_owned())))
-                    .collect(),
-            );
-            self.fetch_proc_macros_queue.request_op(cause, proc_macro_paths);
+            let mut change = Change::new();
+            if self.config.expand_proc_macros() {
+                change.set_proc_macros(
+                    crate_graph
+                        .iter()
+                        .map(|id| (id, Err("Proc-macros have not been built yet".to_owned())))
+                        .collect(),
+                );
+                self.fetch_proc_macros_queue.request_op(cause, proc_macro_paths);
+            }
+            change.set_crate_graph(crate_graph);
+            change.set_target_data_layouts(layouts);
+            change.set_toolchains(toolchains);
+            self.analysis_host.apply_change(change);
+            self.crate_graph_file_dependencies = crate_graph_file_dependencies;
         }
-        change.set_crate_graph(crate_graph);
-        self.analysis_host.apply_change(change);
-        self.crate_graph_file_dependencies = crate_graph_file_dependencies;
         self.process_changes();
-
         self.reload_flycheck();
     }
 
@@ -605,6 +630,7 @@ impl GlobalState {
                 0,
                 Box::new(move |msg| sender.send(msg).unwrap()),
                 config,
+                None,
                 self.config.root_path().clone(),
             )],
             flycheck::InvocationStrategy::PerWorkspace => {
@@ -612,23 +638,32 @@ impl GlobalState {
                     .iter()
                     .enumerate()
                     .filter_map(|(id, w)| match w {
-                        ProjectWorkspace::Cargo { cargo, .. } => Some((id, cargo.workspace_root())),
-                        ProjectWorkspace::Json { project, .. } => {
+                        ProjectWorkspace::Cargo { cargo, sysroot, .. } => Some((
+                            id,
+                            cargo.workspace_root(),
+                            sysroot.as_ref().ok().map(|sysroot| sysroot.root().to_owned()),
+                        )),
+                        ProjectWorkspace::Json { project, sysroot, .. } => {
                             // Enable flychecks for json projects if a custom flycheck command was supplied
                             // in the workspace configuration.
                             match config {
-                                FlycheckConfig::CustomCommand { .. } => Some((id, project.path())),
+                                FlycheckConfig::CustomCommand { .. } => Some((
+                                    id,
+                                    project.path(),
+                                    sysroot.as_ref().ok().map(|sysroot| sysroot.root().to_owned()),
+                                )),
                                 _ => None,
                             }
                         }
                         ProjectWorkspace::DetachedFiles { .. } => None,
                     })
-                    .map(|(id, root)| {
+                    .map(|(id, root, sysroot_root)| {
                         let sender = sender.clone();
                         FlycheckHandle::spawn(
                             id,
                             Box::new(move |msg| sender.send(msg).unwrap()),
                             config.clone(),
+                            sysroot_root,
                             root.to_path_buf(),
                         )
                     })
@@ -639,6 +674,69 @@ impl GlobalState {
     }
 }
 
+// FIXME: Move this into load-cargo?
+pub fn ws_to_crate_graph(
+    workspaces: &[ProjectWorkspace],
+    extra_env: &FxHashMap<String, String>,
+    mut load: impl FnMut(&AbsPath) -> Option<vfs::FileId>,
+) -> (
+    CrateGraph,
+    Vec<FxHashMap<CrateId, Result<(Option<String>, AbsPathBuf), String>>>,
+    Vec<Result<Arc<str>, Arc<str>>>,
+    Vec<Option<Version>>,
+) {
+    let mut crate_graph = CrateGraph::default();
+    let mut proc_macro_paths = Vec::default();
+    let mut layouts = Vec::default();
+    let mut toolchains = Vec::default();
+    let e = Err(Arc::from("missing layout"));
+    for ws in workspaces {
+        let (other, mut crate_proc_macros) = ws.to_crate_graph(&mut load, extra_env);
+        let num_layouts = layouts.len();
+        let num_toolchains = toolchains.len();
+        let (toolchain, layout) = match ws {
+            ProjectWorkspace::Cargo { toolchain, target_layout, .. }
+            | ProjectWorkspace::Json { toolchain, target_layout, .. } => {
+                (toolchain.clone(), target_layout.clone())
+            }
+            ProjectWorkspace::DetachedFiles { .. } => {
+                (None, Err("detached files have no layout".into()))
+            }
+        };
+
+        let mapping = crate_graph.extend(
+            other,
+            &mut crate_proc_macros,
+            |(cg_id, cg_data), (_o_id, o_data)| {
+                // if the newly created crate graph's layout is equal to the crate of the merged graph, then
+                // we can merge the crates.
+                let id = cg_id.into_raw().into_u32() as usize;
+                layouts[id] == layout && toolchains[id] == toolchain && cg_data == o_data
+            },
+        );
+        // Populate the side tables for the newly merged crates
+        mapping.values().for_each(|val| {
+            let idx = val.into_raw().into_u32() as usize;
+            // we only need to consider crates that were not merged and remapped, as the
+            // ones that were remapped already have the correct layout and toolchain
+            if idx >= num_layouts {
+                if layouts.len() <= idx {
+                    layouts.resize(idx + 1, e.clone());
+                }
+                layouts[idx] = layout.clone();
+            }
+            if idx >= num_toolchains {
+                if toolchains.len() <= idx {
+                    toolchains.resize(idx + 1, None);
+                }
+                toolchains[idx] = toolchain.clone();
+            }
+        });
+        proc_macro_paths.push(crate_proc_macros);
+    }
+    (crate_graph, proc_macro_paths, layouts, toolchains)
+}
+
 pub(crate) fn should_refresh_for_change(path: &AbsPath, change_kind: ChangeKind) -> bool {
     const IMPLICIT_TARGET_FILES: &[&str] = &["build.rs", "src/main.rs", "src/lib.rs"];
     const IMPLICIT_TARGET_DIRS: &[&str] = &["src/bin", "examples", "tests", "benches"];
@@ -683,3 +781,18 @@ pub(crate) fn should_refresh_for_change(path: &AbsPath, change_kind: ChangeKind)
     }
     false
 }
+
+/// Similar to [`str::eq_ignore_ascii_case`] but instead of ignoring
+/// case, we say that `-` and `_` are equal.
+fn eq_ignore_underscore(s1: &str, s2: &str) -> bool {
+    if s1.len() != s2.len() {
+        return false;
+    }
+
+    s1.as_bytes().iter().zip(s2.as_bytes()).all(|(c1, c2)| {
+        let c1_underscore = c1 == &b'_' || c1 == &b'-';
+        let c2_underscore = c2 == &b'_' || c2 == &b'-';
+
+        c1 == c2 || (c1_underscore && c2_underscore)
+    })
+}
diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/tests/crate_graph.rs b/src/tools/rust-analyzer/crates/rust-analyzer/tests/crate_graph.rs
new file mode 100644
index 00000000000..efd42fadf7e
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/tests/crate_graph.rs
@@ -0,0 +1,118 @@
+use std::path::PathBuf;
+
+use project_model::{CargoWorkspace, ProjectWorkspace, Sysroot, WorkspaceBuildScripts};
+use rust_analyzer::ws_to_crate_graph;
+use rustc_hash::FxHashMap;
+use serde::de::DeserializeOwned;
+use vfs::{AbsPathBuf, FileId};
+
+fn load_cargo_with_fake_sysroot(file: &str) -> ProjectWorkspace {
+    let meta = get_test_json_file(file);
+    let cargo_workspace = CargoWorkspace::new(meta);
+    ProjectWorkspace::Cargo {
+        cargo: cargo_workspace,
+        build_scripts: WorkspaceBuildScripts::default(),
+        sysroot: Ok(get_fake_sysroot()),
+        rustc: Err(None),
+        rustc_cfg: Vec::new(),
+        cfg_overrides: Default::default(),
+        toolchain: None,
+        target_layout: Err("target_data_layout not loaded".into()),
+        cargo_config_extra_env: Default::default(),
+    }
+}
+
+fn get_test_json_file<T: DeserializeOwned>(file: &str) -> T {
+    let base = PathBuf::from(env!("CARGO_MANIFEST_DIR"));
+    let file = base.join("tests/test_data").join(file);
+    let data = std::fs::read_to_string(file).unwrap();
+    let mut json = data.parse::<serde_json::Value>().unwrap();
+    fixup_paths(&mut json);
+    return serde_json::from_value(json).unwrap();
+
+    fn fixup_paths(val: &mut serde_json::Value) {
+        match val {
+            serde_json::Value::String(s) => replace_root(s, true),
+            serde_json::Value::Array(vals) => vals.iter_mut().for_each(fixup_paths),
+            serde_json::Value::Object(kvals) => kvals.values_mut().for_each(fixup_paths),
+            serde_json::Value::Null | serde_json::Value::Bool(_) | serde_json::Value::Number(_) => {
+            }
+        }
+    }
+}
+
+fn replace_root(s: &mut String, direction: bool) {
+    if direction {
+        let root = if cfg!(windows) { r#"C:\\ROOT\"# } else { "/ROOT/" };
+        *s = s.replace("$ROOT$", root)
+    } else {
+        let root = if cfg!(windows) { r#"C:\\\\ROOT\\"# } else { "/ROOT/" };
+        *s = s.replace(root, "$ROOT$")
+    }
+}
+
+fn get_fake_sysroot_path() -> PathBuf {
+    let base = PathBuf::from(env!("CARGO_MANIFEST_DIR"));
+    base.join("../project-model/test_data/fake-sysroot")
+}
+
+fn get_fake_sysroot() -> Sysroot {
+    let sysroot_path = get_fake_sysroot_path();
+    // there's no `libexec/` directory with a `proc-macro-srv` binary in that
+    // fake sysroot, so we give them both the same path:
+    let sysroot_dir = AbsPathBuf::assert(sysroot_path);
+    let sysroot_src_dir = sysroot_dir.clone();
+    Sysroot::load(sysroot_dir, Some(Ok(sysroot_src_dir)), false)
+}
+
+#[test]
+fn test_deduplicate_origin_dev() {
+    let path_map = &mut FxHashMap::default();
+    let ws = load_cargo_with_fake_sysroot("deduplication_crate_graph_A.json");
+    let ws2 = load_cargo_with_fake_sysroot("deduplication_crate_graph_B.json");
+
+    let (crate_graph, ..) = ws_to_crate_graph(&[ws, ws2], &Default::default(), |path| {
+        let len = path_map.len();
+        Some(*path_map.entry(path.to_path_buf()).or_insert(FileId::from_raw(len as u32)))
+    });
+
+    let mut crates_named_p2 = vec![];
+    for id in crate_graph.iter() {
+        let krate = &crate_graph[id];
+        if let Some(name) = krate.display_name.as_ref() {
+            if name.to_string() == "p2" {
+                crates_named_p2.push(krate);
+            }
+        }
+    }
+
+    assert!(crates_named_p2.len() == 1);
+    let p2 = crates_named_p2[0];
+    assert!(p2.origin.is_local());
+}
+
+#[test]
+fn test_deduplicate_origin_dev_rev() {
+    let path_map = &mut FxHashMap::default();
+    let ws = load_cargo_with_fake_sysroot("deduplication_crate_graph_B.json");
+    let ws2 = load_cargo_with_fake_sysroot("deduplication_crate_graph_A.json");
+
+    let (crate_graph, ..) = ws_to_crate_graph(&[ws, ws2], &Default::default(), |path| {
+        let len = path_map.len();
+        Some(*path_map.entry(path.to_path_buf()).or_insert(FileId::from_raw(len as u32)))
+    });
+
+    let mut crates_named_p2 = vec![];
+    for id in crate_graph.iter() {
+        let krate = &crate_graph[id];
+        if let Some(name) = krate.display_name.as_ref() {
+            if name.to_string() == "p2" {
+                crates_named_p2.push(krate);
+            }
+        }
+    }
+
+    assert!(crates_named_p2.len() == 1);
+    let p2 = crates_named_p2[0];
+    assert!(p2.origin.is_local());
+}
diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/tests/slow-tests/main.rs b/src/tools/rust-analyzer/crates/rust-analyzer/tests/slow-tests/main.rs
index 79ae0c30cfc..960f5b531d4 100644
--- a/src/tools/rust-analyzer/crates/rust-analyzer/tests/slow-tests/main.rs
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/tests/slow-tests/main.rs
@@ -911,20 +911,18 @@ fn root_contains_symlink_out_dirs_check() {
 #[cfg(any(feature = "sysroot-abi", rust_analyzer))]
 fn resolve_proc_macro() {
     use expect_test::expect;
+    use vfs::AbsPathBuf;
     if skip_slow_tests() {
         return;
     }
 
-    // skip using the sysroot config as to prevent us from loading the sysroot sources
-    let mut rustc = std::process::Command::new(toolchain::rustc());
-    rustc.args(["--print", "sysroot"]);
-    let output = rustc.output().unwrap();
-    let sysroot =
-        vfs::AbsPathBuf::try_from(std::str::from_utf8(&output.stdout).unwrap().trim()).unwrap();
+    let sysroot = project_model::Sysroot::discover_no_source(
+        &AbsPathBuf::assert(std::env::current_dir().unwrap()),
+        &Default::default(),
+    )
+    .unwrap();
 
-    let standalone_server_name =
-        format!("rust-analyzer-proc-macro-srv{}", std::env::consts::EXE_SUFFIX);
-    let proc_macro_server_path = sysroot.join("libexec").join(&standalone_server_name);
+    let proc_macro_server_path = sysroot.discover_proc_macro_srv().unwrap();
 
     let server = Project::with_fixture(
         r###"
diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/tests/slow-tests/support.rs b/src/tools/rust-analyzer/crates/rust-analyzer/tests/slow-tests/support.rs
index d02cb45b8e3..392a7170207 100644
--- a/src/tools/rust-analyzer/crates/rust-analyzer/tests/slow-tests/support.rs
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/tests/slow-tests/support.rs
@@ -101,8 +101,13 @@ impl Project<'_> {
             };
         });
 
-        let FixtureWithProjectMeta { fixture, mini_core, proc_macro_names, toolchain } =
-            FixtureWithProjectMeta::parse(self.fixture);
+        let FixtureWithProjectMeta {
+            fixture,
+            mini_core,
+            proc_macro_names,
+            toolchain,
+            target_data_layout: _,
+        } = FixtureWithProjectMeta::parse(self.fixture);
         assert!(proc_macro_names.is_empty());
         assert!(mini_core.is_none());
         assert!(toolchain.is_none());
diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/tests/slow-tests/tidy.rs b/src/tools/rust-analyzer/crates/rust-analyzer/tests/slow-tests/tidy.rs
index 3e38fc3ebcd..78da4487d4c 100644
--- a/src/tools/rust-analyzer/crates/rust-analyzer/tests/slow-tests/tidy.rs
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/tests/slow-tests/tidy.rs
@@ -9,27 +9,6 @@ use xshell::Shell;
 #[cfg(not(feature = "in-rust-tree"))]
 use xshell::cmd;
 
-#[cfg(not(feature = "in-rust-tree"))]
-#[test]
-fn check_code_formatting() {
-    let sh = &Shell::new().unwrap();
-    sh.change_dir(sourcegen::project_root());
-
-    let out = cmd!(sh, "rustup run stable rustfmt --version").read().unwrap();
-    if !out.contains("stable") {
-        panic!(
-            "Failed to run rustfmt from toolchain 'stable'. \
-                 Please run `rustup component add rustfmt --toolchain stable` to install it.",
-        )
-    }
-
-    let res = cmd!(sh, "rustup run stable cargo fmt -- --check").run();
-    if res.is_err() {
-        let _ = cmd!(sh, "rustup run stable cargo fmt").run();
-    }
-    res.unwrap()
-}
-
 #[test]
 fn check_lsp_extensions_docs() {
     let sh = &Shell::new().unwrap();
diff --git a/src/tools/rust-analyzer/crates/project-model/test_data/deduplication_crate_graph_A.json b/src/tools/rust-analyzer/crates/rust-analyzer/tests/test_data/deduplication_crate_graph_A.json
index b0fb5845cef..b0fb5845cef 100644
--- a/src/tools/rust-analyzer/crates/project-model/test_data/deduplication_crate_graph_A.json
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/tests/test_data/deduplication_crate_graph_A.json
diff --git a/src/tools/rust-analyzer/crates/project-model/test_data/deduplication_crate_graph_B.json b/src/tools/rust-analyzer/crates/rust-analyzer/tests/test_data/deduplication_crate_graph_B.json
index b5d1e16e62e..b5d1e16e62e 100644
--- a/src/tools/rust-analyzer/crates/project-model/test_data/deduplication_crate_graph_B.json
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/tests/test_data/deduplication_crate_graph_B.json
diff --git a/src/tools/rust-analyzer/crates/salsa/salsa-macros/src/query_group.rs b/src/tools/rust-analyzer/crates/salsa/salsa-macros/src/query_group.rs
index e535d7ed043..5d1678ef120 100644
--- a/src/tools/rust-analyzer/crates/salsa/salsa-macros/src/query_group.rs
+++ b/src/tools/rust-analyzer/crates/salsa/salsa-macros/src/query_group.rs
@@ -1,5 +1,4 @@
 //!
-use std::{convert::TryFrom, iter::FromIterator};
 
 use crate::parenthesized::Parenthesized;
 use heck::ToUpperCamelCase;
diff --git a/src/tools/rust-analyzer/crates/salsa/src/debug.rs b/src/tools/rust-analyzer/crates/salsa/src/debug.rs
index 0925ddb3d85..5f113541f04 100644
--- a/src/tools/rust-analyzer/crates/salsa/src/debug.rs
+++ b/src/tools/rust-analyzer/crates/salsa/src/debug.rs
@@ -5,7 +5,6 @@ use crate::durability::Durability;
 use crate::plumbing::QueryStorageOps;
 use crate::Query;
 use crate::QueryTable;
-use std::iter::FromIterator;
 
 /// Additional methods on queries that can be used to "peek into"
 /// their current state. These methods are meant for debugging and
diff --git a/src/tools/rust-analyzer/crates/salsa/src/derived.rs b/src/tools/rust-analyzer/crates/salsa/src/derived.rs
index c381e66e087..d6316710058 100644
--- a/src/tools/rust-analyzer/crates/salsa/src/derived.rs
+++ b/src/tools/rust-analyzer/crates/salsa/src/derived.rs
@@ -13,7 +13,6 @@ use crate::Runtime;
 use crate::{Database, DatabaseKeyIndex, QueryDb, Revision};
 use parking_lot::RwLock;
 use std::borrow::Borrow;
-use std::convert::TryFrom;
 use std::hash::Hash;
 use std::marker::PhantomData;
 use triomphe::Arc;
diff --git a/src/tools/rust-analyzer/crates/salsa/src/doctest.rs b/src/tools/rust-analyzer/crates/salsa/src/doctest.rs
deleted file mode 100644
index 29a80663567..00000000000
--- a/src/tools/rust-analyzer/crates/salsa/src/doctest.rs
+++ /dev/null
@@ -1,115 +0,0 @@
-//!
-#![allow(dead_code)]
-
-/// Test that a database with a key/value that is not `Send` will,
-/// indeed, not be `Send`.
-///
-/// ```compile_fail,E0277
-/// use std::rc::Rc;
-///
-/// #[salsa::query_group(NoSendSyncStorage)]
-/// trait NoSendSyncDatabase: salsa::Database {
-///     fn no_send_sync_value(&self, key: bool) -> Rc<bool>;
-///     fn no_send_sync_key(&self, key: Rc<bool>) -> bool;
-/// }
-///
-/// fn no_send_sync_value(_db: &dyn NoSendSyncDatabase, key: bool) -> Rc<bool> {
-///     Rc::new(key)
-/// }
-///
-/// fn no_send_sync_key(_db: &dyn NoSendSyncDatabase, key: Rc<bool>) -> bool {
-///     *key
-/// }
-///
-/// #[salsa::database(NoSendSyncStorage)]
-/// #[derive(Default)]
-/// struct DatabaseImpl {
-///     storage: salsa::Storage<Self>,
-/// }
-///
-/// impl salsa::Database for DatabaseImpl {
-/// }
-///
-/// fn is_send<T: Send>(_: T) { }
-///
-/// fn assert_send() {
-///    is_send(DatabaseImpl::default());
-/// }
-/// ```
-fn test_key_not_send_db_not_send() {}
-
-/// Test that a database with a key/value that is not `Sync` will not
-/// be `Send`.
-///
-/// ```compile_fail,E0277
-/// use std::rc::Rc;
-/// use std::cell::Cell;
-///
-/// #[salsa::query_group(NoSendSyncStorage)]
-/// trait NoSendSyncDatabase: salsa::Database {
-///     fn no_send_sync_value(&self, key: bool) -> Cell<bool>;
-///     fn no_send_sync_key(&self, key: Cell<bool>) -> bool;
-/// }
-///
-/// fn no_send_sync_value(_db: &dyn NoSendSyncDatabase, key: bool) -> Cell<bool> {
-///     Cell::new(key)
-/// }
-///
-/// fn no_send_sync_key(_db: &dyn NoSendSyncDatabase, key: Cell<bool>) -> bool {
-///     *key
-/// }
-///
-/// #[salsa::database(NoSendSyncStorage)]
-/// #[derive(Default)]
-/// struct DatabaseImpl {
-///     runtime: salsa::Storage<Self>,
-/// }
-///
-/// impl salsa::Database for DatabaseImpl {
-/// }
-///
-/// fn is_send<T: Send>(_: T) { }
-///
-/// fn assert_send() {
-///    is_send(DatabaseImpl::default());
-/// }
-/// ```
-fn test_key_not_sync_db_not_send() {}
-
-/// Test that a database with a key/value that is not `Sync` will
-/// not be `Sync`.
-///
-/// ```compile_fail,E0277
-/// use std::cell::Cell;
-/// use std::rc::Rc;
-///
-/// #[salsa::query_group(NoSendSyncStorage)]
-/// trait NoSendSyncDatabase: salsa::Database {
-///     fn no_send_sync_value(&self, key: bool) -> Cell<bool>;
-///     fn no_send_sync_key(&self, key: Cell<bool>) -> bool;
-/// }
-///
-/// fn no_send_sync_value(_db: &dyn NoSendSyncDatabase, key: bool) -> Cell<bool> {
-///     Cell::new(key)
-/// }
-///
-/// fn no_send_sync_key(_db: &dyn NoSendSyncDatabase, key: Cell<bool>) -> bool {
-///     *key
-/// }
-///
-/// #[salsa::database(NoSendSyncStorage)]
-/// #[derive(Default)]
-/// struct DatabaseImpl {
-///     runtime: salsa::Storage<Self>,
-/// }
-///
-/// impl salsa::Database for DatabaseImpl {
-/// }
-///
-/// fn is_sync<T: Sync>(_: T) { }
-///
-/// fn assert_send() {
-///    is_sync(DatabaseImpl::default());
-/// }
-/// ```
-fn test_key_not_sync_db_not_sync() {}
diff --git a/src/tools/rust-analyzer/crates/salsa/src/input.rs b/src/tools/rust-analyzer/crates/salsa/src/input.rs
index 4e8fca6149b..c2539570e0f 100644
--- a/src/tools/rust-analyzer/crates/salsa/src/input.rs
+++ b/src/tools/rust-analyzer/crates/salsa/src/input.rs
@@ -14,7 +14,6 @@ use crate::Runtime;
 use crate::{DatabaseKeyIndex, QueryDb};
 use indexmap::map::Entry;
 use parking_lot::RwLock;
-use std::convert::TryFrom;
 use std::iter;
 use tracing::debug;
 
diff --git a/src/tools/rust-analyzer/crates/salsa/src/interned.rs b/src/tools/rust-analyzer/crates/salsa/src/interned.rs
index 731839e9598..822219f5185 100644
--- a/src/tools/rust-analyzer/crates/salsa/src/interned.rs
+++ b/src/tools/rust-analyzer/crates/salsa/src/interned.rs
@@ -13,7 +13,6 @@ use crate::{Database, DatabaseKeyIndex, QueryDb};
 use parking_lot::RwLock;
 use rustc_hash::FxHashMap;
 use std::collections::hash_map::Entry;
-use std::convert::From;
 use std::fmt::Debug;
 use std::hash::Hash;
 use triomphe::Arc;
diff --git a/src/tools/rust-analyzer/crates/salsa/src/lib.rs b/src/tools/rust-analyzer/crates/salsa/src/lib.rs
index 2d58beafb2a..668dcfd925d 100644
--- a/src/tools/rust-analyzer/crates/salsa/src/lib.rs
+++ b/src/tools/rust-analyzer/crates/salsa/src/lib.rs
@@ -11,7 +11,6 @@
 //! from previous invocations as appropriate.
 
 mod derived;
-mod doctest;
 mod durability;
 mod hash;
 mod input;
diff --git a/src/tools/rust-analyzer/crates/syntax/rust.ungram b/src/tools/rust-analyzer/crates/syntax/rust.ungram
index c3010d090c6..c3d8e97c436 100644
--- a/src/tools/rust-analyzer/crates/syntax/rust.ungram
+++ b/src/tools/rust-analyzer/crates/syntax/rust.ungram
@@ -367,6 +367,7 @@ Expr =
 | RecordExpr
 | RefExpr
 | ReturnExpr
+| BecomeExpr
 | TryExpr
 | TupleExpr
 | WhileExpr
@@ -528,6 +529,9 @@ MatchGuard =
 ReturnExpr =
   Attr* 'return' Expr?
 
+BecomeExpr =
+  Attr* 'become' Expr
+
 YieldExpr =
   Attr* 'yield' Expr?
 
@@ -610,7 +614,7 @@ TypeBoundList =
 
 TypeBound =
   Lifetime
-| ('?' | '~' 'const')? Type
+| ('~' 'const' | 'const')? 'async'? '?'? Type
 
 //************************//
 //        Patterns        //
diff --git a/src/tools/rust-analyzer/crates/syntax/src/ast/edit_in_place.rs b/src/tools/rust-analyzer/crates/syntax/src/ast/edit_in_place.rs
index bc9c54d0b73..41d33c457ce 100644
--- a/src/tools/rust-analyzer/crates/syntax/src/ast/edit_in_place.rs
+++ b/src/tools/rust-analyzer/crates/syntax/src/ast/edit_in_place.rs
@@ -1007,20 +1007,24 @@ impl ast::IdentPat {
 }
 
 pub trait HasVisibilityEdit: ast::HasVisibility {
-    fn set_visibility(&self, visibility: ast::Visibility) {
-        match self.visibility() {
-            Some(current_visibility) => {
-                ted::replace(current_visibility.syntax(), visibility.syntax())
-            }
-            None => {
-                let vis_before = self
-                    .syntax()
-                    .children_with_tokens()
-                    .find(|it| !matches!(it.kind(), WHITESPACE | COMMENT | ATTR))
-                    .unwrap_or_else(|| self.syntax().first_child_or_token().unwrap());
-
-                ted::insert(ted::Position::before(vis_before), visibility.syntax());
+    fn set_visibility(&self, visibility: Option<ast::Visibility>) {
+        if let Some(visibility) = visibility {
+            match self.visibility() {
+                Some(current_visibility) => {
+                    ted::replace(current_visibility.syntax(), visibility.syntax())
+                }
+                None => {
+                    let vis_before = self
+                        .syntax()
+                        .children_with_tokens()
+                        .find(|it| !matches!(it.kind(), WHITESPACE | COMMENT | ATTR))
+                        .unwrap_or_else(|| self.syntax().first_child_or_token().unwrap());
+
+                    ted::insert(ted::Position::before(vis_before), visibility.syntax());
+                }
             }
+        } else if let Some(visibility) = self.visibility() {
+            ted::remove(visibility.syntax());
         }
     }
 }
diff --git a/src/tools/rust-analyzer/crates/syntax/src/ast/generated/nodes.rs b/src/tools/rust-analyzer/crates/syntax/src/ast/generated/nodes.rs
index 6c86e591044..75971861aa8 100644
--- a/src/tools/rust-analyzer/crates/syntax/src/ast/generated/nodes.rs
+++ b/src/tools/rust-analyzer/crates/syntax/src/ast/generated/nodes.rs
@@ -1096,6 +1096,16 @@ impl ReturnExpr {
 }
 
 #[derive(Debug, Clone, PartialEq, Eq, Hash)]
+pub struct BecomeExpr {
+    pub(crate) syntax: SyntaxNode,
+}
+impl ast::HasAttrs for BecomeExpr {}
+impl BecomeExpr {
+    pub fn become_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![become]) }
+    pub fn expr(&self) -> Option<Expr> { support::child(&self.syntax) }
+}
+
+#[derive(Debug, Clone, PartialEq, Eq, Hash)]
 pub struct TryExpr {
     pub(crate) syntax: SyntaxNode,
 }
@@ -1400,9 +1410,10 @@ pub struct TypeBound {
 }
 impl TypeBound {
     pub fn lifetime(&self) -> Option<Lifetime> { support::child(&self.syntax) }
-    pub fn question_mark_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![?]) }
     pub fn tilde_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![~]) }
     pub fn const_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![const]) }
+    pub fn async_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![async]) }
+    pub fn question_mark_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![?]) }
     pub fn ty(&self) -> Option<Type> { support::child(&self.syntax) }
 }
 
@@ -1633,6 +1644,7 @@ pub enum Expr {
     RecordExpr(RecordExpr),
     RefExpr(RefExpr),
     ReturnExpr(ReturnExpr),
+    BecomeExpr(BecomeExpr),
     TryExpr(TryExpr),
     TupleExpr(TupleExpr),
     WhileExpr(WhileExpr),
@@ -2792,6 +2804,17 @@ impl AstNode for ReturnExpr {
     }
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
 }
+impl AstNode for BecomeExpr {
+    fn can_cast(kind: SyntaxKind) -> bool { kind == BECOME_EXPR }
+    fn cast(syntax: SyntaxNode) -> Option<Self> {
+        if Self::can_cast(syntax.kind()) {
+            Some(Self { syntax })
+        } else {
+            None
+        }
+    }
+    fn syntax(&self) -> &SyntaxNode { &self.syntax }
+}
 impl AstNode for TryExpr {
     fn can_cast(kind: SyntaxKind) -> bool { kind == TRY_EXPR }
     fn cast(syntax: SyntaxNode) -> Option<Self> {
@@ -3540,6 +3563,9 @@ impl From<RefExpr> for Expr {
 impl From<ReturnExpr> for Expr {
     fn from(node: ReturnExpr) -> Expr { Expr::ReturnExpr(node) }
 }
+impl From<BecomeExpr> for Expr {
+    fn from(node: BecomeExpr) -> Expr { Expr::BecomeExpr(node) }
+}
 impl From<TryExpr> for Expr {
     fn from(node: TryExpr) -> Expr { Expr::TryExpr(node) }
 }
@@ -3593,6 +3619,7 @@ impl AstNode for Expr {
                 | RECORD_EXPR
                 | REF_EXPR
                 | RETURN_EXPR
+                | BECOME_EXPR
                 | TRY_EXPR
                 | TUPLE_EXPR
                 | WHILE_EXPR
@@ -3632,6 +3659,7 @@ impl AstNode for Expr {
             RECORD_EXPR => Expr::RecordExpr(RecordExpr { syntax }),
             REF_EXPR => Expr::RefExpr(RefExpr { syntax }),
             RETURN_EXPR => Expr::ReturnExpr(ReturnExpr { syntax }),
+            BECOME_EXPR => Expr::BecomeExpr(BecomeExpr { syntax }),
             TRY_EXPR => Expr::TryExpr(TryExpr { syntax }),
             TUPLE_EXPR => Expr::TupleExpr(TupleExpr { syntax }),
             WHILE_EXPR => Expr::WhileExpr(WhileExpr { syntax }),
@@ -3673,6 +3701,7 @@ impl AstNode for Expr {
             Expr::RecordExpr(it) => &it.syntax,
             Expr::RefExpr(it) => &it.syntax,
             Expr::ReturnExpr(it) => &it.syntax,
+            Expr::BecomeExpr(it) => &it.syntax,
             Expr::TryExpr(it) => &it.syntax,
             Expr::TupleExpr(it) => &it.syntax,
             Expr::WhileExpr(it) => &it.syntax,
@@ -4150,6 +4179,7 @@ impl AstNode for AnyHasAttrs {
                 | RANGE_EXPR
                 | REF_EXPR
                 | RETURN_EXPR
+                | BECOME_EXPR
                 | TRY_EXPR
                 | TUPLE_EXPR
                 | WHILE_EXPR
@@ -4851,6 +4881,11 @@ impl std::fmt::Display for ReturnExpr {
         std::fmt::Display::fmt(self.syntax(), f)
     }
 }
+impl std::fmt::Display for BecomeExpr {
+    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+        std::fmt::Display::fmt(self.syntax(), f)
+    }
+}
 impl std::fmt::Display for TryExpr {
     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
         std::fmt::Display::fmt(self.syntax(), f)
diff --git a/src/tools/rust-analyzer/crates/syntax/src/ast/make.rs b/src/tools/rust-analyzer/crates/syntax/src/ast/make.rs
index 120d801c8d1..02246fc3291 100644
--- a/src/tools/rust-analyzer/crates/syntax/src/ast/make.rs
+++ b/src/tools/rust-analyzer/crates/syntax/src/ast/make.rs
@@ -1147,7 +1147,7 @@ pub mod tokens {
 
     pub(super) static SOURCE_FILE: Lazy<Parse<SourceFile>> = Lazy::new(|| {
         SourceFile::parse(
-            "const C: <()>::Item = ( true && true , true || true , 1 != 1, 2 == 2, 3 < 3, 4 <= 4, 5 > 5, 6 >= 6, !true, *p, &p , &mut p, { let a @ [] })\n;\n\n",
+            "const C: <()>::Item = ( true && true , true || true , 1 != 1, 2 == 2, 3 < 3, 4 <= 4, 5 > 5, 6 >= 6, !true, *p, &p , &mut p, { let a @ [] })\n;\n\nimpl A for B where: {}",
         )
     });
 
diff --git a/src/tools/rust-analyzer/crates/syntax/src/ast/node_ext.rs b/src/tools/rust-analyzer/crates/syntax/src/ast/node_ext.rs
index 6e5e4127f4d..1bc1ef8434f 100644
--- a/src/tools/rust-analyzer/crates/syntax/src/ast/node_ext.rs
+++ b/src/tools/rust-analyzer/crates/syntax/src/ast/node_ext.rs
@@ -569,6 +569,26 @@ impl fmt::Display for NameOrNameRef {
     }
 }
 
+impl ast::AstNode for NameOrNameRef {
+    fn can_cast(kind: SyntaxKind) -> bool {
+        matches!(kind, SyntaxKind::NAME | SyntaxKind::NAME_REF)
+    }
+    fn cast(syntax: SyntaxNode) -> Option<Self> {
+        let res = match syntax.kind() {
+            SyntaxKind::NAME => NameOrNameRef::Name(ast::Name { syntax }),
+            SyntaxKind::NAME_REF => NameOrNameRef::NameRef(ast::NameRef { syntax }),
+            _ => return None,
+        };
+        Some(res)
+    }
+    fn syntax(&self) -> &SyntaxNode {
+        match self {
+            NameOrNameRef::NameRef(it) => it.syntax(),
+            NameOrNameRef::Name(it) => it.syntax(),
+        }
+    }
+}
+
 impl NameOrNameRef {
     pub fn text(&self) -> TokenText<'_> {
         match self {
diff --git a/src/tools/rust-analyzer/crates/syntax/src/ast/prec.rs b/src/tools/rust-analyzer/crates/syntax/src/ast/prec.rs
index 9ddf5a0a980..9131cd2f179 100644
--- a/src/tools/rust-analyzer/crates/syntax/src/ast/prec.rs
+++ b/src/tools/rust-analyzer/crates/syntax/src/ast/prec.rs
@@ -130,8 +130,8 @@ impl Expr {
             //
             ContinueExpr(_) => (0, 0),
 
-            ClosureExpr(_) | ReturnExpr(_) | YieldExpr(_) | YeetExpr(_) | BreakExpr(_)
-            | OffsetOfExpr(_) | FormatArgsExpr(_) | AsmExpr(_) => (0, 1),
+            ClosureExpr(_) | ReturnExpr(_) | BecomeExpr(_) | YieldExpr(_) | YeetExpr(_)
+            | BreakExpr(_) | OffsetOfExpr(_) | FormatArgsExpr(_) | AsmExpr(_) => (0, 1),
 
             RangeExpr(_) => (5, 5),
 
@@ -288,6 +288,7 @@ impl Expr {
                 PrefixExpr(e) => e.op_token(),
                 RefExpr(e) => e.amp_token(),
                 ReturnExpr(e) => e.return_token(),
+                BecomeExpr(e) => e.become_token(),
                 TryExpr(e) => e.question_mark_token(),
                 YieldExpr(e) => e.yield_token(),
                 YeetExpr(e) => e.do_token(),
@@ -316,7 +317,8 @@ impl Expr {
 
             // For BinExpr and RangeExpr this is technically wrong -- the child can be on the left...
             BinExpr(_) | RangeExpr(_) | BreakExpr(_) | ContinueExpr(_) | PrefixExpr(_)
-            | RefExpr(_) | ReturnExpr(_) | YieldExpr(_) | YeetExpr(_) | LetExpr(_) => self
+            | RefExpr(_) | ReturnExpr(_) | BecomeExpr(_) | YieldExpr(_) | YeetExpr(_)
+            | LetExpr(_) => self
                 .syntax()
                 .parent()
                 .and_then(Expr::cast)
diff --git a/src/tools/rust-analyzer/crates/syntax/src/lib.rs b/src/tools/rust-analyzer/crates/syntax/src/lib.rs
index 960889b7421..b755de86d32 100644
--- a/src/tools/rust-analyzer/crates/syntax/src/lib.rs
+++ b/src/tools/rust-analyzer/crates/syntax/src/lib.rs
@@ -27,11 +27,6 @@ extern crate ra_ap_rustc_lexer as rustc_lexer;
 #[cfg(feature = "in-rust-tree")]
 extern crate rustc_lexer;
 
-#[allow(unused)]
-macro_rules! eprintln {
-    ($($tt:tt)*) => { stdx::eprintln!($($tt)*) };
-}
-
 mod parsing;
 mod ptr;
 mod syntax_error;
diff --git a/src/tools/rust-analyzer/crates/syntax/src/tests/ast_src.rs b/src/tools/rust-analyzer/crates/syntax/src/tests/ast_src.rs
index 341bda892ba..8221c577892 100644
--- a/src/tools/rust-analyzer/crates/syntax/src/tests/ast_src.rs
+++ b/src/tools/rust-analyzer/crates/syntax/src/tests/ast_src.rs
@@ -67,8 +67,9 @@ pub(crate) const KINDS_SRC: KindsSrc<'_> = KindsSrc {
     keywords: &[
         "as", "async", "await", "box", "break", "const", "continue", "crate", "do", "dyn", "else",
         "enum", "extern", "false", "fn", "for", "if", "impl", "in", "let", "loop", "macro",
-        "match", "mod", "move", "mut", "pub", "ref", "return", "self", "Self", "static", "struct",
-        "super", "trait", "true", "try", "type", "unsafe", "use", "where", "while", "yield",
+        "match", "mod", "move", "mut", "pub", "ref", "return", "become", "self", "Self", "static",
+        "struct", "super", "trait", "true", "try", "type", "unsafe", "use", "where", "while",
+        "yield",
     ],
     contextual_keywords: &[
         "auto",
@@ -154,6 +155,7 @@ pub(crate) const KINDS_SRC: KindsSrc<'_> = KindsSrc {
         "BLOCK_EXPR",
         "STMT_LIST",
         "RETURN_EXPR",
+        "BECOME_EXPR",
         "YIELD_EXPR",
         "YEET_EXPR",
         "LET_EXPR",
diff --git a/src/tools/rust-analyzer/crates/test-fixture/src/lib.rs b/src/tools/rust-analyzer/crates/test-fixture/src/lib.rs
index 28e757e81bb..e118262b4ed 100644
--- a/src/tools/rust-analyzer/crates/test-fixture/src/lib.rs
+++ b/src/tools/rust-analyzer/crates/test-fixture/src/lib.rs
@@ -1,10 +1,9 @@
 //! A set of high-level utility fixture methods to use in tests.
-use std::{mem, ops::Not, str::FromStr, sync};
+use std::{iter, mem, ops::Not, str::FromStr, sync};
 
 use base_db::{
-    CrateDisplayName, CrateGraph, CrateId, CrateName, CrateOrigin, Dependency, DependencyKind,
-    Edition, Env, FileChange, FileSet, LangCrateOrigin, SourceDatabaseExt, SourceRoot, Version,
-    VfsPath,
+    CrateDisplayName, CrateGraph, CrateId, CrateName, CrateOrigin, Dependency, Edition, Env,
+    FileChange, FileSet, LangCrateOrigin, SourceDatabaseExt, SourceRoot, Version, VfsPath,
 };
 use cfg::CfgOptions;
 use hir_expand::{
@@ -118,8 +117,14 @@ impl ChangeFixture {
         ra_fixture: &str,
         mut proc_macro_defs: Vec<(String, ProcMacro)>,
     ) -> ChangeFixture {
-        let FixtureWithProjectMeta { fixture, mini_core, proc_macro_names, toolchain } =
-            FixtureWithProjectMeta::parse(ra_fixture);
+        let FixtureWithProjectMeta {
+            fixture,
+            mini_core,
+            proc_macro_names,
+            toolchain,
+            target_data_layout,
+        } = FixtureWithProjectMeta::parse(ra_fixture);
+        let target_data_layout = Ok(target_data_layout.into());
         let toolchain = Some({
             let channel = toolchain.as_deref().unwrap_or("stable");
             Version::parse(&format!("1.76.0-{channel}")).unwrap()
@@ -131,7 +136,6 @@ impl ChangeFixture {
         let mut crates = FxHashMap::default();
         let mut crate_deps = Vec::new();
         let mut default_crate_root: Option<FileId> = None;
-        let mut default_target_data_layout: Option<String> = None;
         let mut default_cfg = CfgOptions::default();
         let mut default_env = Env::new_for_test_fixture();
 
@@ -187,11 +191,6 @@ impl ChangeFixture {
                     meta.env,
                     false,
                     origin,
-                    meta.target_data_layout
-                        .as_deref()
-                        .map(From::from)
-                        .ok_or_else(|| "target_data_layout unset".into()),
-                    toolchain.clone(),
                 );
                 let prev = crates.insert(crate_name.clone(), crate_id);
                 assert!(prev.is_none(), "multiple crates with same name: {}", crate_name);
@@ -205,7 +204,6 @@ impl ChangeFixture {
                 default_crate_root = Some(file_id);
                 default_cfg.extend(meta.cfg.into_iter());
                 default_env.extend(meta.env.iter().map(|(x, y)| (x.to_owned(), y.to_owned())));
-                default_target_data_layout = meta.target_data_layout;
             }
 
             source_change.change_file(file_id, Some(text.into()));
@@ -228,10 +226,6 @@ impl ChangeFixture {
                 default_env,
                 false,
                 CrateOrigin::Local { repo: None, name: None },
-                default_target_data_layout
-                    .map(|it| it.into())
-                    .ok_or_else(|| "target_data_layout unset".into()),
-                toolchain.clone(),
             );
         } else {
             for (from, to, prelude) in crate_deps {
@@ -240,20 +234,11 @@ impl ChangeFixture {
                 crate_graph
                     .add_dep(
                         from_id,
-                        Dependency::with_prelude(
-                            CrateName::new(&to).unwrap(),
-                            to_id,
-                            prelude,
-                            DependencyKind::Normal,
-                        ),
+                        Dependency::with_prelude(CrateName::new(&to).unwrap(), to_id, prelude),
                     )
                     .unwrap();
             }
         }
-        let target_layout = crate_graph.iter().next().map_or_else(
-            || Err("target_data_layout unset".into()),
-            |it| crate_graph[it].target_layout.clone(),
-        );
 
         if let Some(mini_core) = mini_core {
             let core_file = file_id;
@@ -277,20 +262,11 @@ impl ChangeFixture {
                 Env::new_for_test_fixture(),
                 false,
                 CrateOrigin::Lang(LangCrateOrigin::Core),
-                target_layout.clone(),
-                toolchain.clone(),
             );
 
             for krate in all_crates {
                 crate_graph
-                    .add_dep(
-                        krate,
-                        Dependency::new(
-                            CrateName::new("core").unwrap(),
-                            core_crate,
-                            DependencyKind::Normal,
-                        ),
-                    )
+                    .add_dep(krate, Dependency::new(CrateName::new("core").unwrap(), core_crate))
                     .unwrap();
             }
         }
@@ -322,8 +298,6 @@ impl ChangeFixture {
                 Env::new_for_test_fixture(),
                 true,
                 CrateOrigin::Local { repo: None, name: None },
-                target_layout,
-                toolchain,
             );
             proc_macros.insert(proc_macros_crate, Ok(proc_macro));
 
@@ -331,11 +305,7 @@ impl ChangeFixture {
                 crate_graph
                     .add_dep(
                         krate,
-                        Dependency::new(
-                            CrateName::new("proc_macros").unwrap(),
-                            proc_macros_crate,
-                            DependencyKind::Normal,
-                        ),
+                        Dependency::new(CrateName::new("proc_macros").unwrap(), proc_macros_crate),
                     )
                     .unwrap();
             }
@@ -346,17 +316,20 @@ impl ChangeFixture {
             SourceRootKind::Library => SourceRoot::new_library(mem::take(&mut file_set)),
         };
         roots.push(root);
-        source_change.set_roots(roots);
-        source_change.set_crate_graph(crate_graph);
-
-        ChangeFixture {
-            file_position,
-            files,
-            change: Change {
-                source_change,
-                proc_macros: proc_macros.is_empty().not().then_some(proc_macros),
-            },
-        }
+
+        let mut change = Change {
+            source_change,
+            proc_macros: proc_macros.is_empty().not().then_some(proc_macros),
+            toolchains: Some(iter::repeat(toolchain).take(crate_graph.len()).collect()),
+            target_data_layouts: Some(
+                iter::repeat(target_data_layout).take(crate_graph.len()).collect(),
+            ),
+        };
+
+        change.source_change.set_roots(roots);
+        change.source_change.set_crate_graph(crate_graph);
+
+        ChangeFixture { file_position, files, change }
     }
 }
 
@@ -374,6 +347,7 @@ pub fn identity(_attr: TokenStream, item: TokenStream) -> TokenStream {
                 name: "identity".into(),
                 kind: ProcMacroKind::Attr,
                 expander: sync::Arc::new(IdentityProcMacroExpander),
+                disabled: false,
             },
         ),
         (
@@ -388,6 +362,7 @@ pub fn derive_identity(item: TokenStream) -> TokenStream {
                 name: "DeriveIdentity".into(),
                 kind: ProcMacroKind::CustomDerive,
                 expander: sync::Arc::new(IdentityProcMacroExpander),
+                disabled: false,
             },
         ),
         (
@@ -402,6 +377,7 @@ pub fn input_replace(attr: TokenStream, _item: TokenStream) -> TokenStream {
                 name: "input_replace".into(),
                 kind: ProcMacroKind::Attr,
                 expander: sync::Arc::new(AttributeInputReplaceProcMacroExpander),
+                disabled: false,
             },
         ),
         (
@@ -416,6 +392,7 @@ pub fn mirror(input: TokenStream) -> TokenStream {
                 name: "mirror".into(),
                 kind: ProcMacroKind::FuncLike,
                 expander: sync::Arc::new(MirrorProcMacroExpander),
+                disabled: false,
             },
         ),
         (
@@ -430,6 +407,7 @@ pub fn shorten(input: TokenStream) -> TokenStream {
                 name: "shorten".into(),
                 kind: ProcMacroKind::FuncLike,
                 expander: sync::Arc::new(ShortenProcMacroExpander),
+                disabled: false,
             },
         ),
     ]
@@ -470,7 +448,6 @@ struct FileMeta {
     edition: Edition,
     env: Env,
     introduce_new_source_root: Option<SourceRootKind>,
-    target_data_layout: Option<String>,
 }
 
 impl FileMeta {
@@ -502,7 +479,6 @@ impl FileMeta {
             edition: f.edition.map_or(Edition::CURRENT, |v| Edition::from_str(&v).unwrap()),
             env: f.env.into_iter().collect(),
             introduce_new_source_root,
-            target_data_layout: f.target_data_layout,
         }
     }
 }
diff --git a/src/tools/rust-analyzer/crates/test-utils/src/fixture.rs b/src/tools/rust-analyzer/crates/test-utils/src/fixture.rs
index 595281336d5..7e34c361899 100644
--- a/src/tools/rust-analyzer/crates/test-utils/src/fixture.rs
+++ b/src/tools/rust-analyzer/crates/test-utils/src/fixture.rs
@@ -126,11 +126,6 @@ pub struct Fixture {
     ///
     /// Syntax: `library`
     pub library: bool,
-    /// Specifies LLVM data layout to be used.
-    ///
-    /// You probably don't want to manually specify this. See LLVM manual for the
-    /// syntax, if you must: https://llvm.org/docs/LangRef.html#data-layout
-    pub target_data_layout: Option<String>,
     /// Actual file contents. All meta comments are stripped.
     pub text: String,
 }
@@ -145,6 +140,11 @@ pub struct FixtureWithProjectMeta {
     pub mini_core: Option<MiniCore>,
     pub proc_macro_names: Vec<String>,
     pub toolchain: Option<String>,
+    /// Specifies LLVM data layout to be used.
+    ///
+    /// You probably don't want to manually specify this. See LLVM manual for the
+    /// syntax, if you must: https://llvm.org/docs/LangRef.html#data-layout
+    pub target_data_layout: String,
 }
 
 impl FixtureWithProjectMeta {
@@ -172,6 +172,8 @@ impl FixtureWithProjectMeta {
         let fixture = trim_indent(ra_fixture);
         let mut fixture = fixture.as_str();
         let mut toolchain = None;
+        let mut target_data_layout =
+            "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128".to_owned();
         let mut mini_core = None;
         let mut res: Vec<Fixture> = Vec::new();
         let mut proc_macro_names = vec![];
@@ -182,6 +184,12 @@ impl FixtureWithProjectMeta {
             fixture = remain;
         }
 
+        if let Some(meta) = fixture.strip_prefix("//- target_data_layout:") {
+            let (meta, remain) = meta.split_once('\n').unwrap();
+            target_data_layout = meta.trim().to_owned();
+            fixture = remain;
+        }
+
         if let Some(meta) = fixture.strip_prefix("//- proc_macros:") {
             let (meta, remain) = meta.split_once('\n').unwrap();
             proc_macro_names = meta.split(',').map(|it| it.trim().to_owned()).collect();
@@ -225,7 +233,7 @@ impl FixtureWithProjectMeta {
             }
         }
 
-        Self { fixture: res, mini_core, proc_macro_names, toolchain }
+        Self { fixture: res, mini_core, proc_macro_names, toolchain, target_data_layout }
     }
 
     //- /lib.rs crate:foo deps:bar,baz cfg:foo=a,bar=b env:OUTDIR=path/to,OTHER=foo
@@ -245,9 +253,6 @@ impl FixtureWithProjectMeta {
         let mut env = FxHashMap::default();
         let mut introduce_new_source_root = None;
         let mut library = false;
-        let mut target_data_layout = Some(
-            "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128".to_owned(),
-        );
         for component in components {
             if component == "library" {
                 library = true;
@@ -284,7 +289,6 @@ impl FixtureWithProjectMeta {
                     }
                 }
                 "new_source_root" => introduce_new_source_root = Some(value.to_owned()),
-                "target_data_layout" => target_data_layout = Some(value.to_owned()),
                 _ => panic!("bad component: {component:?}"),
             }
         }
@@ -307,7 +311,6 @@ impl FixtureWithProjectMeta {
             env,
             introduce_new_source_root,
             library,
-            target_data_layout,
         }
     }
 }
@@ -476,16 +479,21 @@ fn parse_fixture_checks_further_indented_metadata() {
 
 #[test]
 fn parse_fixture_gets_full_meta() {
-    let FixtureWithProjectMeta { fixture: parsed, mini_core, proc_macro_names, toolchain } =
-        FixtureWithProjectMeta::parse(
-            r#"
+    let FixtureWithProjectMeta {
+        fixture: parsed,
+        mini_core,
+        proc_macro_names,
+        toolchain,
+        target_data_layout: _,
+    } = FixtureWithProjectMeta::parse(
+        r#"
 //- toolchain: nightly
 //- proc_macros: identity
 //- minicore: coerce_unsized
 //- /lib.rs crate:foo deps:bar,baz cfg:foo=a,bar=b,atom env:OUTDIR=path/to,OTHER=foo
 mod m;
 "#,
-        );
+    );
     assert_eq!(toolchain, Some("nightly".to_owned()));
     assert_eq!(proc_macro_names, vec!["identity".to_owned()]);
     assert_eq!(mini_core.unwrap().activated_flags, vec!["coerce_unsized".to_owned()]);
diff --git a/src/tools/rust-analyzer/crates/test-utils/src/minicore.rs b/src/tools/rust-analyzer/crates/test-utils/src/minicore.rs
index 23a3a7e0afa..f125792d125 100644
--- a/src/tools/rust-analyzer/crates/test-utils/src/minicore.rs
+++ b/src/tools/rust-analyzer/crates/test-utils/src/minicore.rs
@@ -60,6 +60,8 @@
 //!     try: infallible
 //!     unpin: sized
 //!     unsize: sized
+//!     todo: panic
+//!     unimplemented: panic
 
 #![rustc_coherence_is_core]
 
@@ -927,6 +929,10 @@ pub mod fmt {
                 use crate::mem::transmute;
                 unsafe { Argument { formatter: transmute(f), value: transmute(x) } }
             }
+
+            pub fn new_display<'b, T: Display>(x: &'b T) -> Argument<'_> {
+                Self::new(x, Display::fmt)
+            }
         }
 
         #[lang = "format_alignment"]
@@ -1438,6 +1444,33 @@ mod macros {
 
     // endregion:fmt
 
+    // region:todo
+    #[macro_export]
+    #[allow_internal_unstable(core_panic)]
+    macro_rules! todo {
+        () => {
+            $crate::panicking::panic("not yet implemented")
+        };
+        ($($arg:tt)+) => {
+            $crate::panic!("not yet implemented: {}", $crate::format_args!($($arg)+))
+        };
+    }
+    // endregion:todo
+
+    // region:unimplemented
+    #[macro_export]
+    #[allow_internal_unstable(core_panic)]
+    macro_rules! unimplemented {
+        () => {
+            $crate::panicking::panic("not implemented")
+        };
+        ($($arg:tt)+) => {
+            $crate::panic!("not implemented: {}", $crate::format_args!($($arg)+))
+        };
+    }
+    // endregion:unimplemented
+
+
     // region:derive
     pub(crate) mod builtin {
         #[rustc_builtin_macro]
diff --git a/src/tools/rust-analyzer/crates/toolchain/src/lib.rs b/src/tools/rust-analyzer/crates/toolchain/src/lib.rs
index 997f339edc4..ae71b6700c0 100644
--- a/src/tools/rust-analyzer/crates/toolchain/src/lib.rs
+++ b/src/tools/rust-analyzer/crates/toolchain/src/lib.rs
@@ -2,7 +2,41 @@
 
 #![warn(rust_2018_idioms, unused_lifetimes)]
 
-use std::{env, iter, path::PathBuf};
+use std::{
+    env, iter,
+    path::{Path, PathBuf},
+};
+
+#[derive(Copy, Clone)]
+pub enum Tool {
+    Cargo,
+    Rustc,
+    Rustup,
+    Rustfmt,
+}
+
+impl Tool {
+    pub fn path(self) -> PathBuf {
+        get_path_for_executable(self.name())
+    }
+
+    pub fn path_in(self, path: &Path) -> Option<PathBuf> {
+        probe_for_binary(path.join(self.name()))
+    }
+
+    pub fn path_in_or_discover(self, path: &Path) -> PathBuf {
+        probe_for_binary(path.join(self.name())).unwrap_or_else(|| self.path())
+    }
+
+    pub fn name(self) -> &'static str {
+        match self {
+            Tool::Cargo => "cargo",
+            Tool::Rustc => "rustc",
+            Tool::Rustup => "rustup",
+            Tool::Rustfmt => "rustfmt",
+        }
+    }
+}
 
 pub fn cargo() -> PathBuf {
     get_path_for_executable("cargo")
@@ -47,7 +81,7 @@ fn get_path_for_executable(executable_name: &'static str) -> PathBuf {
     if let Some(mut path) = get_cargo_home() {
         path.push("bin");
         path.push(executable_name);
-        if let Some(path) = probe(path) {
+        if let Some(path) = probe_for_binary(path) {
             return path;
         }
     }
@@ -57,7 +91,7 @@ fn get_path_for_executable(executable_name: &'static str) -> PathBuf {
 
 fn lookup_in_path(exec: &str) -> bool {
     let paths = env::var_os("PATH").unwrap_or_default();
-    env::split_paths(&paths).map(|path| path.join(exec)).find_map(probe).is_some()
+    env::split_paths(&paths).map(|path| path.join(exec)).find_map(probe_for_binary).is_some()
 }
 
 fn get_cargo_home() -> Option<PathBuf> {
@@ -73,7 +107,7 @@ fn get_cargo_home() -> Option<PathBuf> {
     None
 }
 
-fn probe(path: PathBuf) -> Option<PathBuf> {
+pub fn probe_for_binary(path: PathBuf) -> Option<PathBuf> {
     let with_extension = match env::consts::EXE_EXTENSION {
         "" => None,
         it => Some(path.with_extension(it)),
diff --git a/src/tools/rust-analyzer/crates/tt/src/lib.rs b/src/tools/rust-analyzer/crates/tt/src/lib.rs
index 9004bff53a8..eec88f80688 100644
--- a/src/tools/rust-analyzer/crates/tt/src/lib.rs
+++ b/src/tools/rust-analyzer/crates/tt/src/lib.rs
@@ -152,6 +152,7 @@ pub struct Punct<S> {
 #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
 pub enum Spacing {
     Alone,
+    /// Whether the following token is joint to the current one.
     Joint,
 }
 
diff --git a/src/tools/rust-analyzer/docs/user/generated_config.adoc b/src/tools/rust-analyzer/docs/user/generated_config.adoc
index a86ef709411..da7654b0f64 100644
--- a/src/tools/rust-analyzer/docs/user/generated_config.adoc
+++ b/src/tools/rust-analyzer/docs/user/generated_config.adoc
@@ -71,7 +71,7 @@ cargo check --quiet --workspace --message-format=json --all-targets
 ```
 .
 --
-[[rust-analyzer.cargo.buildScripts.rebuildOnSave]]rust-analyzer.cargo.buildScripts.rebuildOnSave (default: `false`)::
+[[rust-analyzer.cargo.buildScripts.rebuildOnSave]]rust-analyzer.cargo.buildScripts.rebuildOnSave (default: `true`)::
 +
 --
 Rerun proc-macros building/build-scripts running when proc-macro
@@ -234,6 +234,11 @@ each of them, with the working directory being the workspace root
 by changing `#rust-analyzer.check.invocationStrategy#` and
 `#rust-analyzer.check.invocationLocation#`.
 
+If `$saved_file` is part of the command, rust-analyzer will pass
+the absolute path of the saved file to the provided command. This is
+intended to be used with non-Cargo build systems.
+Note that `$saved_file` is experimental and may be removed in the futureg.
+
 An example command would be:
 
 ```bash
@@ -344,6 +349,11 @@ Default:
 Custom completion snippets.
 
 --
+[[rust-analyzer.completion.termSearch.enable]]rust-analyzer.completion.termSearch.enable (default: `false`)::
++
+--
+Whether to enable term search based snippets like `Some(foo.bar().baz())`.
+--
 [[rust-analyzer.diagnostics.disabled]]rust-analyzer.diagnostics.disabled (default: `[]`)::
 +
 --
@@ -793,11 +803,6 @@ Exclude imports from find-all-references.
 --
 Exclude tests from find-all-references.
 --
-[[rust-analyzer.rename.allowExternalItems]]rust-analyzer.rename.allowExternalItems (default: `false`)::
-+
---
-Allow renaming of items not belonging to the loaded workspaces.
---
 [[rust-analyzer.runnables.command]]rust-analyzer.runnables.command (default: `null`)::
 +
 --
diff --git a/src/tools/rust-analyzer/editors/code/.vscodeignore b/src/tools/rust-analyzer/editors/code/.vscodeignore
index 09dc27056b3..5c48205694f 100644
--- a/src/tools/rust-analyzer/editors/code/.vscodeignore
+++ b/src/tools/rust-analyzer/editors/code/.vscodeignore
@@ -12,3 +12,6 @@
 !ra_syntax_tree.tmGrammar.json
 !server
 !README.md
+!language-configuration-rustdoc.json
+!rustdoc-inject.json
+!rustdoc.json
diff --git a/src/tools/rust-analyzer/editors/code/language-configuration-rustdoc.json b/src/tools/rust-analyzer/editors/code/language-configuration-rustdoc.json
new file mode 100644
index 00000000000..c905d3b6067
--- /dev/null
+++ b/src/tools/rust-analyzer/editors/code/language-configuration-rustdoc.json
@@ -0,0 +1,37 @@
+{
+    "comments": {
+        "blockComment": ["<!--", "-->"]
+    },
+    "brackets": [
+        ["{", "}"],
+        ["[", "]"],
+        ["(", ")"]
+    ],
+    "colorizedBracketPairs": [],
+    "autoClosingPairs": [
+        { "open": "{", "close": "}" },
+        { "open": "[", "close": "]" },
+        { "open": "(", "close": ")" }
+    ],
+    "surroundingPairs": [
+        ["(", ")"],
+        ["[", "]"],
+        ["`", "`"],
+        ["_", "_"],
+        ["*", "*"],
+        ["{", "}"],
+        ["'", "'"],
+        ["\"", "\""]
+    ],
+    "folding": {
+        "offSide": true,
+        "markers": {
+            "start": "^\\s*<!--\\s*#?region\\b.*-->",
+            "end": "^\\s*<!--\\s*#?endregion\\b.*-->"
+        }
+    },
+    "wordPattern": {
+        "pattern": "(\\p{Alphabetic}|\\p{Number}|\\p{Nonspacing_Mark})(((\\p{Alphabetic}|\\p{Number}|\\p{Nonspacing_Mark})|[_])?(\\p{Alphabetic}|\\p{Number}|\\p{Nonspacing_Mark}))*",
+        "flags": "ug"
+    }
+}
diff --git a/src/tools/rust-analyzer/editors/code/package.json b/src/tools/rust-analyzer/editors/code/package.json
index b474471e5a4..3a1df5a2f90 100644
--- a/src/tools/rust-analyzer/editors/code/package.json
+++ b/src/tools/rust-analyzer/editors/code/package.json
@@ -68,7 +68,9 @@
         "typescript": "^5.1.6"
     },
     "activationEvents": [
+        "workspaceContains:Cargo.toml",
         "workspaceContains:*/Cargo.toml",
+        "workspaceContains:rust-project.json",
         "workspaceContains:*/rust-project.json"
     ],
     "main": "./out/main",
@@ -588,7 +590,7 @@
                 },
                 "rust-analyzer.cargo.buildScripts.rebuildOnSave": {
                     "markdownDescription": "Rerun proc-macros building/build-scripts running when proc-macro\nor build-script sources change and are saved.",
-                    "default": false,
+                    "default": true,
                     "type": "boolean"
                 },
                 "rust-analyzer.cargo.buildScripts.useRustcWrapper": {
@@ -775,7 +777,7 @@
                     ]
                 },
                 "rust-analyzer.check.overrideCommand": {
-                    "markdownDescription": "Override the command rust-analyzer uses instead of `cargo check` for\ndiagnostics on save. The command is required to output json and\nshould therefore include `--message-format=json` or a similar option\n(if your client supports the `colorDiagnosticOutput` experimental\ncapability, you can use `--message-format=json-diagnostic-rendered-ansi`).\n\nIf you're changing this because you're using some tool wrapping\nCargo, you might also want to change\n`#rust-analyzer.cargo.buildScripts.overrideCommand#`.\n\nIf there are multiple linked projects/workspaces, this command is invoked for\neach of them, with the working directory being the workspace root\n(i.e., the folder containing the `Cargo.toml`). This can be overwritten\nby changing `#rust-analyzer.check.invocationStrategy#` and\n`#rust-analyzer.check.invocationLocation#`.\n\nAn example command would be:\n\n```bash\ncargo check --workspace --message-format=json --all-targets\n```\n.",
+                    "markdownDescription": "Override the command rust-analyzer uses instead of `cargo check` for\ndiagnostics on save. The command is required to output json and\nshould therefore include `--message-format=json` or a similar option\n(if your client supports the `colorDiagnosticOutput` experimental\ncapability, you can use `--message-format=json-diagnostic-rendered-ansi`).\n\nIf you're changing this because you're using some tool wrapping\nCargo, you might also want to change\n`#rust-analyzer.cargo.buildScripts.overrideCommand#`.\n\nIf there are multiple linked projects/workspaces, this command is invoked for\neach of them, with the working directory being the workspace root\n(i.e., the folder containing the `Cargo.toml`). This can be overwritten\nby changing `#rust-analyzer.check.invocationStrategy#` and\n`#rust-analyzer.check.invocationLocation#`.\n\nIf `$saved_file` is part of the command, rust-analyzer will pass\nthe absolute path of the saved file to the provided command. This is\nintended to be used with non-Cargo build systems.\nNote that `$saved_file` is experimental and may be removed in the futureg.\n\nAn example command would be:\n\n```bash\ncargo check --workspace --message-format=json --all-targets\n```\n.",
                     "default": null,
                     "type": [
                         "null",
@@ -902,6 +904,11 @@
                     },
                     "type": "object"
                 },
+                "rust-analyzer.completion.termSearch.enable": {
+                    "markdownDescription": "Whether to enable term search based snippets like `Some(foo.bar().baz())`.",
+                    "default": false,
+                    "type": "boolean"
+                },
                 "rust-analyzer.diagnostics.disabled": {
                     "markdownDescription": "List of rust-analyzer diagnostics to disable.",
                     "default": [],
@@ -1520,11 +1527,6 @@
                     "default": false,
                     "type": "boolean"
                 },
-                "rust-analyzer.rename.allowExternalItems": {
-                    "markdownDescription": "Allow renaming of items not belonging to the loaded workspaces.",
-                    "default": false,
-                    "type": "boolean"
-                },
                 "rust-analyzer.runnables.command": {
                     "markdownDescription": "Command to be executed instead of 'cargo' for runnables.",
                     "default": null,
@@ -1756,6 +1758,13 @@
                     "rs"
                 ],
                 "configuration": "language-configuration.json"
+            },
+            {
+                "id": "rustdoc",
+                "extensions": [
+                    ".rustdoc"
+                ],
+                "configuration": "./language-configuration-rustdoc.json"
             }
         ],
         "grammars": [
@@ -1763,6 +1772,27 @@
                 "language": "ra_syntax_tree",
                 "scopeName": "source.ra_syntax_tree",
                 "path": "ra_syntax_tree.tmGrammar.json"
+            },
+            {
+                "language": "rustdoc",
+                "scopeName": "text.html.markdown.rustdoc",
+                "path": "rustdoc.json",
+                "embeddedLanguages": {
+                    "meta.embedded.block.html": "html",
+                    "meta.embedded.block.markdown": "markdown",
+                    "meta.embedded.block.rust": "rust"
+                }
+            },
+            {
+                "injectTo": [
+                    "source.rust"
+                ],
+                "scopeName": "comment.markdown-cell-inject.rustdoc",
+                "path": "rustdoc-inject.json",
+                "embeddedLanguages": {
+                    "meta.embedded.block.rustdoc": "rustdoc",
+                    "meta.embedded.block.rust": "rust"
+                }
             }
         ],
         "problemMatchers": [
diff --git a/src/tools/rust-analyzer/editors/code/rustdoc-inject.json b/src/tools/rust-analyzer/editors/code/rustdoc-inject.json
new file mode 100644
index 00000000000..7a4498fea9d
--- /dev/null
+++ b/src/tools/rust-analyzer/editors/code/rustdoc-inject.json
@@ -0,0 +1,93 @@
+{
+    "injectionSelector": "L:source.rust -string -comment -meta.embedded.block.rustdoc.md",
+    "patterns": [
+        {
+            "include": "#triple-slash"
+        },
+        {
+            "include": "#double-slash-exclamation"
+        },
+        {
+            "include": "#slash-start-exclamation"
+        },
+        {
+            "include": "#slash-double-start"
+        }
+    ],
+    "repository": {
+        "triple-slash": {
+            "begin": "(^|\\G)\\s*(///) ?",
+            "captures": {
+                "2": {
+                    "name": "comment.line.double-slash.rust"
+                }
+            },
+            "name": "comment.quote_code.triple-slash.rust",
+            "contentName": "meta.embedded.block.rustdoc",
+            "patterns": [
+                {
+                    "include": "text.html.markdown.rustdoc"
+                }
+            ],
+            "while": "(^|\\G)\\s*(///) ?"
+        },
+        "double-slash-exclamation": {
+            "begin": "(^|\\G)\\s*(//!) ?",
+            "captures": {
+                "2": {
+                    "name": "comment.line.double-slash.rust"
+                }
+            },
+            "name": "comment.quote_code.double-slash-exclamation.rust",
+            "contentName": "meta.embedded.block.rustdoc",
+            "patterns": [
+                {
+                    "include": "text.html.markdown.rustdoc"
+                }
+            ],
+            "while": "(^|\\G)\\s*(//!) ?"
+        },
+        "slash-start-exclamation": {
+            "begin": "(^)(/\\*!) ?$",
+            "captures": {
+                "2": {
+                    "name": "comment.block.rust"
+                }
+            },
+            "name": "comment.quote_code.slash-start-exclamation.rust",
+            "contentName": "meta.embedded.block.rustdoc",
+            "patterns": [
+                {
+                    "include": "text.html.markdown.rustdoc"
+                }
+            ],
+            "end": "( ?)(\\*/)"
+        },
+        "slash-double-start": {
+            "name": "comment.quote_code.slash-double-start-quote-star.rust",
+            "begin": "(?:^)\\s*/\\*\\* ?$",
+            "end": "\\*/",
+            "patterns": [
+                {
+                    "include": "#quote-star"
+                }
+            ]
+        },
+        "quote-star": {
+            "begin": "(^|\\G)\\s*(\\*(?!/)) ?",
+            "captures": {
+                "2": {
+                    "name": "comment.punctuation.definition.quote_code.slash-star.MR"
+                }
+            },
+            "contentName": "meta.embedded.block.rustdoc",
+            "patterns": [
+                {
+                    "include": "text.html.markdown.rustdoc"
+                }
+            ],
+            "while": "(^|\\G)\\s*(\\*(?!/)) ?"
+        }
+    },
+    "scopeName": "comment.markdown-cell-inject.rustdoc"
+}
diff --git a/src/tools/rust-analyzer/editors/code/rustdoc.json b/src/tools/rust-analyzer/editors/code/rustdoc.json
new file mode 100644
index 00000000000..cecfae9d753
--- /dev/null
+++ b/src/tools/rust-analyzer/editors/code/rustdoc.json
@@ -0,0 +1,82 @@
+{
+    "name": "rustdoc",
+    "patterns": [
+        {
+            "include": "#fenced_code_block"
+        },
+        {
+            "include": "#markdown"
+        }
+    ],
+    "scopeName": "text.html.markdown.rustdoc",
+    "repository": {
+        "markdown": {
+            "patterns": [
+                {
+                    "include": "text.html.markdown"
+                }
+            ]
+        },
+        "fenced_code_block": {
+            "patterns": [
+                {
+                    "include": "#fenced_code_block_rust"
+                },
+                {
+                    "include": "#fenced_code_block_unknown"
+                }
+            ]
+        },
+        "fenced_code_block_rust": {
+            "begin": "(^|\\G)(\\s*)(`{3,}|~{3,})\\s*(?i:(rust|not run|not_run)?((\\s+|:|,|\\{|\\?)[^`~]*)?$)",
+            "name": "markup.fenced_code.block.markdown",
+            "end": "(^|\\G)(\\2|\\s{0,3})(\\3)\\s*$",
+            "beginCaptures": {
+                "3": {
+                    "name": "punctuation.definition.markdown"
+                },
+                "4": {
+                    "name": "fenced_code.block.language.markdown"
+                },
+                "5": {
+                    "name": "fenced_code.block.language.attributes.markdown"
+                }
+            },
+            "endCaptures": {
+                "3": {
+                    "name": "punctuation.definition.markdown"
+                }
+            },
+            "patterns": [
+                {
+                    "begin": "(^|\\G)(\\s*)(.*)",
+                    "while": "(^|\\G)(?!\\s*([`~]{3,})\\s*$)",
+                    "contentName": "meta.embedded.block.rust",
+                    "patterns": [
+                        {
+                            "include": "source.rust"
+                        }
+                    ]
+                }
+            ]
+        },
+        "fenced_code_block_unknown": {
+            "begin": "(^|\\G)(\\s*)(`{3,}|~{3,})\\s*(?=([^`~]+)?$)",
+            "beginCaptures": {
+                "3": {
+                    "name": "punctuation.definition.markdown"
+                },
+                "4": {
+                    "name": "fenced_code.block.language"
+                }
+            },
+            "end": "(^|\\G)(\\2|\\s{0,3})(\\3)\\s*$",
+            "endCaptures": {
+                "3": {
+                    "name": "punctuation.definition.markdown"
+                }
+            },
+            "name": "markup.fenced_code.block.markdown"
+        }
+    }
+}
diff --git a/src/tools/rust-analyzer/editors/code/src/rust_project.ts b/src/tools/rust-analyzer/editors/code/src/rust_project.ts
index bf65ad43ba5..c983874fc00 100644
--- a/src/tools/rust-analyzer/editors/code/src/rust_project.ts
+++ b/src/tools/rust-analyzer/editors/code/src/rust_project.ts
@@ -1,7 +1,26 @@
 export interface JsonProject {
+    /// Path to the sysroot directory.
+    ///
+    /// The sysroot is where rustc looks for the
+    /// crates that are built-in to rust, such as
+    /// std.
+    ///
+    /// https://doc.rust-lang.org/rustc/command-line-arguments.html#--sysroot-override-the-system-root
+    ///
+    /// To see the current value of sysroot, you
+    /// can query rustc:
+    ///
+    /// ```
+    /// $ rustc --print sysroot
+    /// /Users/yourname/.rustup/toolchains/stable-x86_64-apple-darwin
+    /// ```
+    sysroot?: string;
     /// Path to the directory with *source code* of
     /// sysroot crates.
     ///
+    /// By default, this is `lib/rustlib/src/rust/library`
+    /// relative to the sysroot.
+    ///
     /// It should point to the directory where std,
     /// core, and friends can be found:
     ///
diff --git a/src/tools/rust-analyzer/lib/lsp-server/LICENSE-APACHE b/src/tools/rust-analyzer/lib/lsp-server/LICENSE-APACHE
new file mode 120000
index 00000000000..1cd601d0a3a
--- /dev/null
+++ b/src/tools/rust-analyzer/lib/lsp-server/LICENSE-APACHE
@@ -0,0 +1 @@
+../../LICENSE-APACHE
\ No newline at end of file
diff --git a/src/tools/rust-analyzer/lib/lsp-server/LICENSE-MIT b/src/tools/rust-analyzer/lib/lsp-server/LICENSE-MIT
new file mode 120000
index 00000000000..b2cfbdc7b0b
--- /dev/null
+++ b/src/tools/rust-analyzer/lib/lsp-server/LICENSE-MIT
@@ -0,0 +1 @@
+../../LICENSE-MIT
\ No newline at end of file
diff --git a/src/tools/rust-analyzer/xtask/src/metrics.rs b/src/tools/rust-analyzer/xtask/src/metrics.rs
index 9bd3a661c24..2efafa10a82 100644
--- a/src/tools/rust-analyzer/xtask/src/metrics.rs
+++ b/src/tools/rust-analyzer/xtask/src/metrics.rs
@@ -117,8 +117,6 @@ impl Metrics {
             sh,
             "./target/release/rust-analyzer -q analysis-stats {path} --query-sysroot-metadata"
         )
-        // the sysroot uses `public-dependency`, so we make cargo think it's a nightly
-        .env("__CARGO_TEST_CHANNEL_OVERRIDE_DO_NOT_USE_THIS", "nightly")
         .read()?;
         for (metric, value, unit) in parse_metrics(&output) {
             self.report(&format!("analysis-stats/{name}/{metric}"), value, unit.into());
diff --git a/src/tools/tidy/src/deps.rs b/src/tools/tidy/src/deps.rs
index d4642deb2c6..b36b6da308e 100644
--- a/src/tools/tidy/src/deps.rs
+++ b/src/tools/tidy/src/deps.rs
@@ -384,6 +384,7 @@ const PERMITTED_RUSTC_DEPENDENCIES: &[&str] = &[
     "winapi-util",
     "winapi-x86_64-pc-windows-gnu",
     "windows",
+    "windows-core",
     "windows-sys",
     "windows-targets",
     "windows_aarch64_gnullvm",
diff --git a/tests/coverage/no_spans.cov-map b/tests/coverage/no_spans.cov-map
index 9915fc52e6d..30171c3f319 100644
--- a/tests/coverage/no_spans.cov-map
+++ b/tests/coverage/no_spans.cov-map
@@ -1,3 +1,11 @@
+Function name: no_spans::affected_function
+Raw bytes (9): 0x[01, 01, 00, 01, 01, 1a, 1c, 00, 1d]
+Number of files: 1
+- file 0 => global file 1
+Number of expressions: 0
+Number of file 0 mappings: 1
+- Code(Counter(0)) at (prev + 26, 28) to (start + 0, 29)
+
 Function name: no_spans::affected_function::{closure#0}
 Raw bytes (9): 0x[01, 01, 00, 01, 01, 1b, 0c, 00, 0e]
 Number of files: 1
diff --git a/tests/coverage/no_spans.coverage b/tests/coverage/no_spans.coverage
index e55177698a2..b117c32ffd0 100644
--- a/tests/coverage/no_spans.coverage
+++ b/tests/coverage/no_spans.coverage
@@ -23,7 +23,7 @@
    LL|       |}
    LL|       |
    LL|       |macro_that_defines_a_function! {
-   LL|       |    fn affected_function() {
+   LL|      1|    fn affected_function() {
    LL|      1|        || ()
    LL|       |    }
    LL|       |}
diff --git a/tests/coverage/no_spans_if_not.cov-map b/tests/coverage/no_spans_if_not.cov-map
index 5277267ec1b..bc3e14eddd5 100644
--- a/tests/coverage/no_spans_if_not.cov-map
+++ b/tests/coverage/no_spans_if_not.cov-map
@@ -1,3 +1,15 @@
+Function name: no_spans_if_not::affected_function
+Raw bytes (21): 0x[01, 01, 01, 01, 00, 03, 01, 16, 1c, 01, 12, 02, 02, 0d, 00, 0f, 00, 02, 0d, 00, 0f]
+Number of files: 1
+- file 0 => global file 1
+Number of expressions: 1
+- expression 0 operands: lhs = Counter(0), rhs = Zero
+Number of file 0 mappings: 3
+- Code(Counter(0)) at (prev + 22, 28) to (start + 1, 18)
+- Code(Expression(0, Sub)) at (prev + 2, 13) to (start + 0, 15)
+    = (c0 - Zero)
+- Code(Zero) at (prev + 2, 13) to (start + 0, 15)
+
 Function name: no_spans_if_not::main
 Raw bytes (9): 0x[01, 01, 00, 01, 01, 0b, 01, 02, 02]
 Number of files: 1
diff --git a/tests/coverage/no_spans_if_not.coverage b/tests/coverage/no_spans_if_not.coverage
index 1b6bbc75a04..d235568db65 100644
--- a/tests/coverage/no_spans_if_not.coverage
+++ b/tests/coverage/no_spans_if_not.coverage
@@ -19,11 +19,11 @@
    LL|       |}
    LL|       |
    LL|       |macro_that_defines_a_function! {
-   LL|       |    fn affected_function() {
-   LL|       |        if !false {
-   LL|       |            ()
+   LL|      1|    fn affected_function() {
+   LL|      1|        if !false {
+   LL|      1|            ()
    LL|       |        } else {
-   LL|       |            ()
+   LL|      0|            ()
    LL|       |        }
    LL|       |    }
    LL|       |}
diff --git a/tests/rustdoc-gui/mobile-crate-name.goml b/tests/rustdoc-gui/mobile-crate-name.goml
new file mode 100644
index 00000000000..a0c96eec8a5
--- /dev/null
+++ b/tests/rustdoc-gui/mobile-crate-name.goml
@@ -0,0 +1,22 @@
+// Checks that if the crate name is too long on mobile, it will not grow and overflow its parent
+// (thanks to text overflow ellipsis).
+
+go-to: "file://" + |DOC_PATH| + "/test_docs/index.html"
+// First we change the title to make it big.
+set-window-size: (350, 800)
+// We ensure that the "format" of the title is the same as the one we'll use.
+assert-text: (".mobile-topbar .location a", "test_docs")
+// We store the height we know is correct.
+store-property: (".mobile-topbar .location", {"offsetHeight": height})
+// We change the crate name to something longer.
+set-text: (".mobile-topbar .location a", "cargo_packager_resource_resolver")
+// And we check that the size remained the same.
+assert-property: (".mobile-topbar .location", {"offsetHeight": |height|})
+
+// Now we check if it works for the non-crate pages as well.
+go-to: "file://" + |DOC_PATH| + "/test_docs/struct.Foo.html"
+// We store the height we know is correct.
+store-property: (".mobile-topbar .location", {"offsetHeight": height})
+set-text: (".mobile-topbar .location a", "Something_incredibly_long_because")
+// And we check that the size remained the same.
+assert-property: (".mobile-topbar .location", {"offsetHeight": |height|})
diff --git a/tests/rustdoc-gui/type-declation-overflow.goml b/tests/rustdoc-gui/type-declation-overflow.goml
index 5780f5c88f8..a97cc98897a 100644
--- a/tests/rustdoc-gui/type-declation-overflow.goml
+++ b/tests/rustdoc-gui/type-declation-overflow.goml
@@ -39,8 +39,8 @@ assert-property: ("pre.item-decl", {"scrollWidth": "950"})
 set-window-size: (600, 600)
 go-to: "file://" + |DOC_PATH| + "/lib2/too_long/struct.SuperIncrediblyLongLongLongLongLongLongLongGigaGigaGigaMegaLongLongLongStructName.html"
 // It shouldn't have an overflow in the topbar either.
-store-property: (".mobile-topbar h2", {"scrollWidth": scrollWidth})
-assert-property: (".mobile-topbar h2", {"clientWidth": |scrollWidth|})
+store-property: (".mobile-topbar", {"scrollWidth": scrollWidth})
+assert-property: (".mobile-topbar", {"clientWidth": |scrollWidth|})
 assert-css: (".mobile-topbar h2", {"overflow-x": "hidden"})
 
 // Check wrapping for top main-heading h1 and out-of-band.
diff --git a/tests/rustdoc/bounds-in-multiple-parts.rs b/tests/rustdoc/bounds.rs
index 279e3c14888..da09e3f2a52 100644
--- a/tests/rustdoc/bounds-in-multiple-parts.rs
+++ b/tests/rustdoc/bounds.rs
@@ -18,3 +18,15 @@ pub trait T2 {
     fn f<T: Eq>()
         where Self: Eq, Self: Eq2, T: Eq2;
 }
+
+// Checking that we support empty bounds (we used to crash on empty outlives-bounds).
+// Note that we don't want to hide them since they have a semantic effect.
+// For outlives-bounds, they force the lifetime param to be early-bound instead of late-bound.
+// For trait bounds, it can affect well-formedness (see `ClauseKind::WellFormed`).
+// @has 'foo/fn.empty.html'
+// @has - '//pre[@class="rust item-decl"]' "empty<'a, T>()where T:, 'a:,"
+pub fn empty<'a, T>()
+    where
+        T:,
+        'a:,
+{}
diff --git a/tests/rustdoc/const-generics/generic_const_exprs.rs b/tests/rustdoc/const-generics/generic_const_exprs.rs
index e23b3006da6..2d2d31d7231 100644
--- a/tests/rustdoc/const-generics/generic_const_exprs.rs
+++ b/tests/rustdoc/const-generics/generic_const_exprs.rs
@@ -3,5 +3,5 @@
 #![allow(incomplete_features)]
 // make sure that `ConstEvaluatable` predicates dont cause rustdoc to ICE #77647
 // @has foo/struct.Ice.html '//pre[@class="rust item-decl"]' \
-//      'pub struct Ice<const N: usize>;'
+//      'pub struct Ice<const N: usize> where [(); { _ }]:;'
 pub struct Ice<const N: usize> where [(); N + 1]:;
diff --git a/tests/rustdoc/inline_cross/auxiliary/issue-76736-1.rs b/tests/rustdoc/inline_cross/auxiliary/issue-76736-1.rs
new file mode 100644
index 00000000000..4ae9f79a532
--- /dev/null
+++ b/tests/rustdoc/inline_cross/auxiliary/issue-76736-1.rs
@@ -0,0 +1,6 @@
+#![feature(staged_api)]
+#![unstable(feature = "rustc_private", issue = "none")]
+
+pub trait MaybeResult<T> {}
+
+impl<T> MaybeResult<T> for T {}
diff --git a/tests/rustdoc/inline_cross/auxiliary/issue-76736-2.rs b/tests/rustdoc/inline_cross/auxiliary/issue-76736-2.rs
new file mode 100644
index 00000000000..b5fbac97082
--- /dev/null
+++ b/tests/rustdoc/inline_cross/auxiliary/issue-76736-2.rs
@@ -0,0 +1,5 @@
+#![feature(rustc_private)]
+
+extern crate issue_76736_1;
+
+pub struct Bar;
diff --git a/tests/rustdoc/inline_cross/issue-76736-1.rs b/tests/rustdoc/inline_cross/issue-76736-1.rs
new file mode 100644
index 00000000000..25feae2c8d6
--- /dev/null
+++ b/tests/rustdoc/inline_cross/issue-76736-1.rs
@@ -0,0 +1,15 @@
+// aux-build:issue-76736-1.rs
+// aux-build:issue-76736-2.rs
+
+#![crate_name = "foo"]
+
+extern crate issue_76736_1;
+extern crate issue_76736_2;
+
+// @has foo/struct.Foo.html
+// @!has - '//*[@class="impl"]//h3[@class="code-header"]' 'MaybeResult'
+pub struct Foo;
+
+// @has foo/struct.Bar.html
+// @!has - '//*[@class="impl"]//h3[@class="code-header"]' 'MaybeResult'
+pub use issue_76736_2::Bar;
diff --git a/tests/rustdoc/inline_cross/issue-76736-2.rs b/tests/rustdoc/inline_cross/issue-76736-2.rs
new file mode 100644
index 00000000000..e43c825d6e1
--- /dev/null
+++ b/tests/rustdoc/inline_cross/issue-76736-2.rs
@@ -0,0 +1,16 @@
+// aux-build:issue-76736-1.rs
+// aux-build:issue-76736-2.rs
+
+#![crate_name = "foo"]
+#![feature(rustc_private)]
+
+extern crate issue_76736_1;
+extern crate issue_76736_2;
+
+// @has foo/struct.Foo.html
+// @has - '//*[@class="impl"]//h3[@class="code-header"]' 'MaybeResult'
+pub struct Foo;
+
+// @has foo/struct.Bar.html
+// @has - '//*[@class="impl"]//h3[@class="code-header"]' 'MaybeResult'
+pub use issue_76736_2::Bar;
diff --git a/tests/rustdoc/inline_cross/issue-76736-3.rs b/tests/rustdoc/inline_cross/issue-76736-3.rs
new file mode 100644
index 00000000000..9542f3f3557
--- /dev/null
+++ b/tests/rustdoc/inline_cross/issue-76736-3.rs
@@ -0,0 +1,16 @@
+// compile-flags: -Zforce-unstable-if-unmarked
+// aux-build:issue-76736-1.rs
+// aux-build:issue-76736-2.rs
+
+#![crate_name = "foo"]
+
+extern crate issue_76736_1;
+extern crate issue_76736_2;
+
+// @has foo/struct.Foo.html
+// @has - '//*[@class="impl"]//h3[@class="code-header"]' 'MaybeResult'
+pub struct Foo;
+
+// @has foo/struct.Bar.html
+// @has - '//*[@class="impl"]//h3[@class="code-header"]' 'MaybeResult'
+pub use issue_76736_2::Bar;
diff --git a/tests/ui/abi/statics/static-mut-foreign.rs b/tests/ui/abi/statics/static-mut-foreign.rs
index fdd775da578..f32ce8cf085 100644
--- a/tests/ui/abi/statics/static-mut-foreign.rs
+++ b/tests/ui/abi/statics/static-mut-foreign.rs
@@ -33,9 +33,9 @@ unsafe fn run() {
     rust_dbg_static_mut = -3;
     assert_eq!(rust_dbg_static_mut, -3);
     static_bound(&rust_dbg_static_mut);
-    //~^ WARN shared reference of mutable static is discouraged [static_mut_ref]
+    //~^ WARN shared reference to mutable static is discouraged [static_mut_refs]
     static_bound_set(&mut rust_dbg_static_mut);
-    //~^ WARN mutable reference of mutable static is discouraged [static_mut_ref]
+    //~^ WARN mutable reference to mutable static is discouraged [static_mut_refs]
 }
 
 pub fn main() {
diff --git a/tests/ui/abi/statics/static-mut-foreign.stderr b/tests/ui/abi/statics/static-mut-foreign.stderr
index 144ac056f87..f393088ff9f 100644
--- a/tests/ui/abi/statics/static-mut-foreign.stderr
+++ b/tests/ui/abi/statics/static-mut-foreign.stderr
@@ -1,28 +1,28 @@
-warning: shared reference of mutable static is discouraged
+warning: creating a shared reference to mutable static is discouraged
   --> $DIR/static-mut-foreign.rs:35:18
    |
 LL |     static_bound(&rust_dbg_static_mut);
-   |                  ^^^^^^^^^^^^^^^^^^^^ shared reference of mutable static
+   |                  ^^^^^^^^^^^^^^^^^^^^ shared reference to mutable static
    |
    = note: for more information, see issue #114447 <https://github.com/rust-lang/rust/issues/114447>
-   = note: reference of mutable static is a hard error from 2024 edition
-   = note: mutable statics can be written to by multiple threads: aliasing violations or data races will cause undefined behavior
-   = note: `#[warn(static_mut_ref)]` on by default
-help: shared references are dangerous since if there's any kind of mutation of that static while the reference lives, that's UB; use `addr_of!` instead to create a raw pointer
+   = note: this will be a hard error in the 2024 edition
+   = note: this shared reference has lifetime `'static`, but if the static ever gets mutated, or a mutable reference is created, then any further use of this shared reference is Undefined Behavior
+   = note: `#[warn(static_mut_refs)]` on by default
+help: use `addr_of!` instead to create a raw pointer
    |
 LL |     static_bound(addr_of!(rust_dbg_static_mut));
    |                  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
-warning: mutable reference of mutable static is discouraged
+warning: creating a mutable reference to mutable static is discouraged
   --> $DIR/static-mut-foreign.rs:37:22
    |
 LL |     static_bound_set(&mut rust_dbg_static_mut);
-   |                      ^^^^^^^^^^^^^^^^^^^^^^^^ mutable reference of mutable static
+   |                      ^^^^^^^^^^^^^^^^^^^^^^^^ mutable reference to mutable static
    |
    = note: for more information, see issue #114447 <https://github.com/rust-lang/rust/issues/114447>
-   = note: reference of mutable static is a hard error from 2024 edition
-   = note: mutable statics can be written to by multiple threads: aliasing violations or data races will cause undefined behavior
-help: mutable references are dangerous since if there's any other pointer or reference used for that static while the reference lives, that's UB; use `addr_of_mut!` instead to create a raw pointer
+   = note: this will be a hard error in the 2024 edition
+   = note: this mutable reference has lifetime `'static`, but if the static gets accessed (read or written) by any other means, or any other reference is created, then any further use of this mutable reference is Undefined Behavior
+help: use `addr_of_mut!` instead to create a raw pointer
    |
 LL |     static_bound_set(addr_of_mut!(rust_dbg_static_mut));
    |                      ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
diff --git a/tests/ui/anon-params/anon-params-edition-hygiene.rs b/tests/ui/anon-params/anon-params-edition-hygiene.rs
index 607412f44c4..56e7336a7a5 100644
--- a/tests/ui/anon-params/anon-params-edition-hygiene.rs
+++ b/tests/ui/anon-params/anon-params-edition-hygiene.rs
@@ -1,3 +1,4 @@
+//@ check-pass
 //@ edition:2018
 //@ aux-build:anon-params-edition-hygiene.rs
 
@@ -8,7 +9,6 @@
 extern crate anon_params_edition_hygiene;
 
 generate_trait_2015_ident!(u8);
-// FIXME: Edition hygiene doesn't work correctly with `tt`s in this case.
-generate_trait_2015_tt!(u8); //~ ERROR expected one of `:`, `@`, or `|`, found `)`
+generate_trait_2015_tt!(u8);
 
 fn main() {}
diff --git a/tests/ui/anon-params/anon-params-edition-hygiene.stderr b/tests/ui/anon-params/anon-params-edition-hygiene.stderr
deleted file mode 100644
index 373d7c6aebb..00000000000
--- a/tests/ui/anon-params/anon-params-edition-hygiene.stderr
+++ /dev/null
@@ -1,23 +0,0 @@
-error: expected one of `:`, `@`, or `|`, found `)`
-  --> $DIR/anon-params-edition-hygiene.rs:12:1
-   |
-LL | generate_trait_2015_tt!(u8);
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected one of `:`, `@`, or `|`
-   |
-   = note: anonymous parameters are removed in the 2018 edition (see RFC 1685)
-   = note: this error originates in the macro `generate_trait_2015_tt` (in Nightly builds, run with -Z macro-backtrace for more info)
-help: if this is a `self` type, give it a parameter name
-   |
-LL | generate_trait_2015_tt!(self: u8);
-   |                         +++++
-help: if this is a parameter name, give it a type
-   |
-LL | generate_trait_2015_tt!(u8: TypeName);
-   |                           ++++++++++
-help: if this is a type, explicitly ignore the parameter name
-   |
-LL | generate_trait_2015_tt!(_: u8);
-   |                         ++
-
-error: aborting due to 1 previous error
-
diff --git a/tests/ui/async-await/issue-72442.stderr b/tests/ui/async-await/issue-72442.stderr
index 313f6079c7c..e68f7a29990 100644
--- a/tests/ui/async-await/issue-72442.stderr
+++ b/tests/ui/async-await/issue-72442.stderr
@@ -8,6 +8,11 @@ LL |             let mut f = File::open(path.to_str())?;
    |
 note: required by a bound in `File::open`
   --> $SRC_DIR/std/src/fs.rs:LL:COL
+help: consider removing this method call, as the receiver has type `&Path` and `&Path: AsRef<Path>` trivially holds
+   |
+LL -             let mut f = File::open(path.to_str())?;
+LL +             let mut f = File::open(path)?;
+   |
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/async-await/suggest-switching-edition-on-await-cargo.rs b/tests/ui/async-await/suggest-switching-edition-on-await-cargo.rs
index e5a3d54c5d0..e1fae0f0e93 100644
--- a/tests/ui/async-await/suggest-switching-edition-on-await-cargo.rs
+++ b/tests/ui/async-await/suggest-switching-edition-on-await-cargo.rs
@@ -1,4 +1,4 @@
-//@ rustc-env:CARGO=/usr/bin/cargo
+//@ rustc-env:CARGO_CRATE_NAME=foo
 
 use std::pin::Pin;
 use std::future::Future;
diff --git a/tests/ui/borrowck/borrowck-access-permissions.rs b/tests/ui/borrowck/borrowck-access-permissions.rs
index 1638644103b..be11286a523 100644
--- a/tests/ui/borrowck/borrowck-access-permissions.rs
+++ b/tests/ui/borrowck/borrowck-access-permissions.rs
@@ -16,7 +16,7 @@ fn main() {
         let _y1 = &mut static_x; //~ ERROR [E0596]
         unsafe {
             let _y2 = &mut static_x_mut;
-            //~^ WARN mutable reference of mutable static is discouraged [static_mut_ref]
+            //~^ WARN mutable reference to mutable static is discouraged [static_mut_refs]
         }
     }
 
diff --git a/tests/ui/borrowck/borrowck-access-permissions.stderr b/tests/ui/borrowck/borrowck-access-permissions.stderr
index 93d92295dd9..11e2b63bd6c 100644
--- a/tests/ui/borrowck/borrowck-access-permissions.stderr
+++ b/tests/ui/borrowck/borrowck-access-permissions.stderr
@@ -1,14 +1,14 @@
-warning: mutable reference of mutable static is discouraged
+warning: creating a mutable reference to mutable static is discouraged
   --> $DIR/borrowck-access-permissions.rs:18:23
    |
 LL |             let _y2 = &mut static_x_mut;
-   |                       ^^^^^^^^^^^^^^^^^ mutable reference of mutable static
+   |                       ^^^^^^^^^^^^^^^^^ mutable reference to mutable static
    |
    = note: for more information, see issue #114447 <https://github.com/rust-lang/rust/issues/114447>
-   = note: reference of mutable static is a hard error from 2024 edition
-   = note: mutable statics can be written to by multiple threads: aliasing violations or data races will cause undefined behavior
-   = note: `#[warn(static_mut_ref)]` on by default
-help: mutable references are dangerous since if there's any other pointer or reference used for that static while the reference lives, that's UB; use `addr_of_mut!` instead to create a raw pointer
+   = note: this will be a hard error in the 2024 edition
+   = note: this mutable reference has lifetime `'static`, but if the static gets accessed (read or written) by any other means, or any other reference is created, then any further use of this mutable reference is Undefined Behavior
+   = note: `#[warn(static_mut_refs)]` on by default
+help: use `addr_of_mut!` instead to create a raw pointer
    |
 LL |             let _y2 = addr_of_mut!(static_x_mut);
    |                       ~~~~~~~~~~~~~~~~~~~~~~~~~~
diff --git a/tests/ui/borrowck/borrowck-unsafe-static-mutable-borrows.rs b/tests/ui/borrowck/borrowck-unsafe-static-mutable-borrows.rs
index a89cad20f97..b09c96ada8a 100644
--- a/tests/ui/borrowck/borrowck-unsafe-static-mutable-borrows.rs
+++ b/tests/ui/borrowck/borrowck-unsafe-static-mutable-borrows.rs
@@ -17,7 +17,7 @@ impl Foo {
 fn main() {
     unsafe {
         let sfoo: *mut Foo = &mut SFOO;
-        //~^ WARN mutable reference of mutable static is discouraged [static_mut_ref]
+        //~^ WARN mutable reference to mutable static is discouraged [static_mut_refs]
         let x = (*sfoo).x();
         (*sfoo).x[1] += 1;
         *x += 1;
diff --git a/tests/ui/borrowck/borrowck-unsafe-static-mutable-borrows.stderr b/tests/ui/borrowck/borrowck-unsafe-static-mutable-borrows.stderr
index 7a3824f79a4..354d70eb1ad 100644
--- a/tests/ui/borrowck/borrowck-unsafe-static-mutable-borrows.stderr
+++ b/tests/ui/borrowck/borrowck-unsafe-static-mutable-borrows.stderr
@@ -1,14 +1,14 @@
-warning: mutable reference of mutable static is discouraged
+warning: creating a mutable reference to mutable static is discouraged
   --> $DIR/borrowck-unsafe-static-mutable-borrows.rs:19:30
    |
 LL |         let sfoo: *mut Foo = &mut SFOO;
-   |                              ^^^^^^^^^ mutable reference of mutable static
+   |                              ^^^^^^^^^ mutable reference to mutable static
    |
    = note: for more information, see issue #114447 <https://github.com/rust-lang/rust/issues/114447>
-   = note: reference of mutable static is a hard error from 2024 edition
-   = note: mutable statics can be written to by multiple threads: aliasing violations or data races will cause undefined behavior
-   = note: `#[warn(static_mut_ref)]` on by default
-help: mutable references are dangerous since if there's any other pointer or reference used for that static while the reference lives, that's UB; use `addr_of_mut!` instead to create a raw pointer
+   = note: this will be a hard error in the 2024 edition
+   = note: this mutable reference has lifetime `'static`, but if the static gets accessed (read or written) by any other means, or any other reference is created, then any further use of this mutable reference is Undefined Behavior
+   = note: `#[warn(static_mut_refs)]` on by default
+help: use `addr_of_mut!` instead to create a raw pointer
    |
 LL |         let sfoo: *mut Foo = addr_of_mut!(SFOO);
    |                              ~~~~~~~~~~~~~~~~~~
diff --git a/tests/ui/borrowck/issue-20801.rs b/tests/ui/borrowck/issue-20801.rs
index ec83af5d5df..7e3d3703dc7 100644
--- a/tests/ui/borrowck/issue-20801.rs
+++ b/tests/ui/borrowck/issue-20801.rs
@@ -12,7 +12,7 @@ fn imm_ref() -> &'static T {
 
 fn mut_ref() -> &'static mut T {
     unsafe { &mut GLOBAL_MUT_T }
-    //~^ WARN mutable reference of mutable static is discouraged [static_mut_ref]
+    //~^ WARN mutable reference to mutable static is discouraged [static_mut_refs]
 }
 
 fn mut_ptr() -> *mut T {
diff --git a/tests/ui/borrowck/issue-20801.stderr b/tests/ui/borrowck/issue-20801.stderr
index b2bee2d8803..97294afd3df 100644
--- a/tests/ui/borrowck/issue-20801.stderr
+++ b/tests/ui/borrowck/issue-20801.stderr
@@ -1,14 +1,14 @@
-warning: mutable reference of mutable static is discouraged
+warning: creating a mutable reference to mutable static is discouraged
   --> $DIR/issue-20801.rs:14:14
    |
 LL |     unsafe { &mut GLOBAL_MUT_T }
-   |              ^^^^^^^^^^^^^^^^^ mutable reference of mutable static
+   |              ^^^^^^^^^^^^^^^^^ mutable reference to mutable static
    |
    = note: for more information, see issue #114447 <https://github.com/rust-lang/rust/issues/114447>
-   = note: reference of mutable static is a hard error from 2024 edition
-   = note: mutable statics can be written to by multiple threads: aliasing violations or data races will cause undefined behavior
-   = note: `#[warn(static_mut_ref)]` on by default
-help: mutable references are dangerous since if there's any other pointer or reference used for that static while the reference lives, that's UB; use `addr_of_mut!` instead to create a raw pointer
+   = note: this will be a hard error in the 2024 edition
+   = note: this mutable reference has lifetime `'static`, but if the static gets accessed (read or written) by any other means, or any other reference is created, then any further use of this mutable reference is Undefined Behavior
+   = note: `#[warn(static_mut_refs)]` on by default
+help: use `addr_of_mut!` instead to create a raw pointer
    |
 LL |     unsafe { addr_of_mut!(GLOBAL_MUT_T) }
    |              ~~~~~~~~~~~~~~~~~~~~~~~~~~
diff --git a/tests/ui/borrowck/issue-55492-borrowck-migrate-scans-parents.rs b/tests/ui/borrowck/issue-55492-borrowck-migrate-scans-parents.rs
index 9b172b41319..c3909d05963 100644
--- a/tests/ui/borrowck/issue-55492-borrowck-migrate-scans-parents.rs
+++ b/tests/ui/borrowck/issue-55492-borrowck-migrate-scans-parents.rs
@@ -10,7 +10,7 @@ mod borrowck_closures_unique {
         //~^ ERROR is not declared as mutable
         unsafe {
             c1(&mut Y);
-            //~^ WARN mutable reference of mutable static is discouraged [static_mut_ref]
+            //~^ WARN mutable reference to mutable static is discouraged [static_mut_refs]
         }
     }
 }
@@ -25,7 +25,7 @@ mod borrowck_closures_unique_grandparent {
         };
         unsafe {
             c1(&mut Z);
-            //~^ WARN mutable reference of mutable static is discouraged [static_mut_ref]
+            //~^ WARN mutable reference to mutable static is discouraged [static_mut_refs]
         }
     }
 }
@@ -62,7 +62,7 @@ fn main() {
     static mut X: isize = 2;
     unsafe {
         borrowck_closures_unique::e(&mut X);
-        //~^ WARN mutable reference of mutable static is discouraged [static_mut_ref]
+        //~^ WARN mutable reference to mutable static is discouraged [static_mut_refs]
     }
 
     mutability_errors::capture_assign_whole((1000,));
diff --git a/tests/ui/borrowck/issue-55492-borrowck-migrate-scans-parents.stderr b/tests/ui/borrowck/issue-55492-borrowck-migrate-scans-parents.stderr
index e4e4947fce1..098a2964e9f 100644
--- a/tests/ui/borrowck/issue-55492-borrowck-migrate-scans-parents.stderr
+++ b/tests/ui/borrowck/issue-55492-borrowck-migrate-scans-parents.stderr
@@ -1,42 +1,42 @@
-warning: mutable reference of mutable static is discouraged
+warning: creating a mutable reference to mutable static is discouraged
   --> $DIR/issue-55492-borrowck-migrate-scans-parents.rs:12:16
    |
 LL |             c1(&mut Y);
-   |                ^^^^^^ mutable reference of mutable static
+   |                ^^^^^^ mutable reference to mutable static
    |
    = note: for more information, see issue #114447 <https://github.com/rust-lang/rust/issues/114447>
-   = note: reference of mutable static is a hard error from 2024 edition
-   = note: mutable statics can be written to by multiple threads: aliasing violations or data races will cause undefined behavior
-   = note: `#[warn(static_mut_ref)]` on by default
-help: mutable references are dangerous since if there's any other pointer or reference used for that static while the reference lives, that's UB; use `addr_of_mut!` instead to create a raw pointer
+   = note: this will be a hard error in the 2024 edition
+   = note: this mutable reference has lifetime `'static`, but if the static gets accessed (read or written) by any other means, or any other reference is created, then any further use of this mutable reference is Undefined Behavior
+   = note: `#[warn(static_mut_refs)]` on by default
+help: use `addr_of_mut!` instead to create a raw pointer
    |
 LL |             c1(addr_of_mut!(Y));
    |                ~~~~~~~~~~~~~~~
 
-warning: mutable reference of mutable static is discouraged
+warning: creating a mutable reference to mutable static is discouraged
   --> $DIR/issue-55492-borrowck-migrate-scans-parents.rs:27:16
    |
 LL |             c1(&mut Z);
-   |                ^^^^^^ mutable reference of mutable static
+   |                ^^^^^^ mutable reference to mutable static
    |
    = note: for more information, see issue #114447 <https://github.com/rust-lang/rust/issues/114447>
-   = note: reference of mutable static is a hard error from 2024 edition
-   = note: mutable statics can be written to by multiple threads: aliasing violations or data races will cause undefined behavior
-help: mutable references are dangerous since if there's any other pointer or reference used for that static while the reference lives, that's UB; use `addr_of_mut!` instead to create a raw pointer
+   = note: this will be a hard error in the 2024 edition
+   = note: this mutable reference has lifetime `'static`, but if the static gets accessed (read or written) by any other means, or any other reference is created, then any further use of this mutable reference is Undefined Behavior
+help: use `addr_of_mut!` instead to create a raw pointer
    |
 LL |             c1(addr_of_mut!(Z));
    |                ~~~~~~~~~~~~~~~
 
-warning: mutable reference of mutable static is discouraged
+warning: creating a mutable reference to mutable static is discouraged
   --> $DIR/issue-55492-borrowck-migrate-scans-parents.rs:64:37
    |
 LL |         borrowck_closures_unique::e(&mut X);
-   |                                     ^^^^^^ mutable reference of mutable static
+   |                                     ^^^^^^ mutable reference to mutable static
    |
    = note: for more information, see issue #114447 <https://github.com/rust-lang/rust/issues/114447>
-   = note: reference of mutable static is a hard error from 2024 edition
-   = note: mutable statics can be written to by multiple threads: aliasing violations or data races will cause undefined behavior
-help: mutable references are dangerous since if there's any other pointer or reference used for that static while the reference lives, that's UB; use `addr_of_mut!` instead to create a raw pointer
+   = note: this will be a hard error in the 2024 edition
+   = note: this mutable reference has lifetime `'static`, but if the static gets accessed (read or written) by any other means, or any other reference is created, then any further use of this mutable reference is Undefined Behavior
+help: use `addr_of_mut!` instead to create a raw pointer
    |
 LL |         borrowck_closures_unique::e(addr_of_mut!(X));
    |                                     ~~~~~~~~~~~~~~~
diff --git a/tests/ui/check-cfg/cargo-feature.rs b/tests/ui/check-cfg/cargo-feature.rs
index a91068ca05a..ba451921d79 100644
--- a/tests/ui/check-cfg/cargo-feature.rs
+++ b/tests/ui/check-cfg/cargo-feature.rs
@@ -4,7 +4,7 @@
 //
 //@ check-pass
 //@ revisions: some none
-//@ rustc-env:CARGO=/usr/bin/cargo
+//@ rustc-env:CARGO_CRATE_NAME=foo
 //@ compile-flags: -Z unstable-options
 //@ [none]compile-flags: --check-cfg=cfg(feature,values())
 //@ [some]compile-flags: --check-cfg=cfg(feature,values("bitcode"))
diff --git a/tests/ui/check-cfg/diagnotics.rs b/tests/ui/check-cfg/diagnotics.rs
index 54138d15890..134bfcf8ef4 100644
--- a/tests/ui/check-cfg/diagnotics.rs
+++ b/tests/ui/check-cfg/diagnotics.rs
@@ -1,7 +1,7 @@
 //@ check-pass
 //@ revisions: cargo rustc
-//@ [rustc]unset-rustc-env:CARGO
-//@ [cargo]rustc-env:CARGO=/usr/bin/cargo
+//@ [rustc]unset-rustc-env:CARGO_CRATE_NAME
+//@ [cargo]rustc-env:CARGO_CRATE_NAME=foo
 //@ compile-flags: --check-cfg=cfg(feature,values("foo")) --check-cfg=cfg(no_values) -Z unstable-options
 
 #[cfg(featur)]
diff --git a/tests/ui/consts/const_let_assign2.rs b/tests/ui/consts/const_let_assign2.rs
index f239507d245..e8ebba7b208 100644
--- a/tests/ui/consts/const_let_assign2.rs
+++ b/tests/ui/consts/const_let_assign2.rs
@@ -16,7 +16,7 @@ static mut BB: AA = AA::new();
 
 fn main() {
     let ptr = unsafe { &mut BB };
-    //~^ WARN mutable reference of mutable static is discouraged [static_mut_ref]
+    //~^ WARN mutable reference to mutable static is discouraged [static_mut_refs]
     for a in ptr.data.iter() {
         println!("{}", a);
     }
diff --git a/tests/ui/consts/const_let_assign2.stderr b/tests/ui/consts/const_let_assign2.stderr
index 2764153a8a5..5ae8fd353dd 100644
--- a/tests/ui/consts/const_let_assign2.stderr
+++ b/tests/ui/consts/const_let_assign2.stderr
@@ -1,14 +1,14 @@
-warning: mutable reference of mutable static is discouraged
+warning: creating a mutable reference to mutable static is discouraged
   --> $DIR/const_let_assign2.rs:18:24
    |
 LL |     let ptr = unsafe { &mut BB };
-   |                        ^^^^^^^ mutable reference of mutable static
+   |                        ^^^^^^^ mutable reference to mutable static
    |
    = note: for more information, see issue #114447 <https://github.com/rust-lang/rust/issues/114447>
-   = note: reference of mutable static is a hard error from 2024 edition
-   = note: mutable statics can be written to by multiple threads: aliasing violations or data races will cause undefined behavior
-   = note: `#[warn(static_mut_ref)]` on by default
-help: mutable references are dangerous since if there's any other pointer or reference used for that static while the reference lives, that's UB; use `addr_of_mut!` instead to create a raw pointer
+   = note: this will be a hard error in the 2024 edition
+   = note: this mutable reference has lifetime `'static`, but if the static gets accessed (read or written) by any other means, or any other reference is created, then any further use of this mutable reference is Undefined Behavior
+   = note: `#[warn(static_mut_refs)]` on by default
+help: use `addr_of_mut!` instead to create a raw pointer
    |
 LL |     let ptr = unsafe { addr_of_mut!(BB) };
    |                        ~~~~~~~~~~~~~~~~
diff --git a/tests/ui/consts/const_refs_to_static_fail_invalid.rs b/tests/ui/consts/const_refs_to_static_fail_invalid.rs
index 363a6da0901..be1574af588 100644
--- a/tests/ui/consts/const_refs_to_static_fail_invalid.rs
+++ b/tests/ui/consts/const_refs_to_static_fail_invalid.rs
@@ -1,7 +1,7 @@
 //@ normalize-stderr-test "(the raw bytes of the constant) \(size: [0-9]*, align: [0-9]*\)" -> "$1 (size: $$SIZE, align: $$ALIGN)"
 //@ normalize-stderr-test "([0-9a-f][0-9a-f] |╾─*ALLOC[0-9]+(\+[a-z0-9]+)?(<imm>)?─*╼ )+ *│.*" -> "HEX_DUMP"
 #![feature(const_refs_to_static)]
-#![allow(static_mut_ref)]
+#![allow(static_mut_refs)]
 
 fn invalid() {
     static S: i8 = 10;
@@ -43,8 +43,8 @@ fn mutable() {
     // This *must not build*, the constant we are matching against
     // could change its value!
     match &42 {
-        C => {}, //~ERROR: could not evaluate constant pattern
-        _ => {},
+        C => {} //~ERROR: could not evaluate constant pattern
+        _ => {}
     }
 }
 
diff --git a/tests/ui/consts/const_refs_to_static_fail_invalid.stderr b/tests/ui/consts/const_refs_to_static_fail_invalid.stderr
index 082f8532444..4ff15f0c28b 100644
--- a/tests/ui/consts/const_refs_to_static_fail_invalid.stderr
+++ b/tests/ui/consts/const_refs_to_static_fail_invalid.stderr
@@ -46,7 +46,7 @@ LL |     const C: &i32 = unsafe { &S_MUT };
 error: could not evaluate constant pattern
   --> $DIR/const_refs_to_static_fail_invalid.rs:46:9
    |
-LL |         C => {},
+LL |         C => {}
    |         ^
 
 error: aborting due to 6 previous errors
diff --git a/tests/ui/consts/issue-17718-const-bad-values.rs b/tests/ui/consts/issue-17718-const-bad-values.rs
index e112a346b65..33347d8df62 100644
--- a/tests/ui/consts/issue-17718-const-bad-values.rs
+++ b/tests/ui/consts/issue-17718-const-bad-values.rs
@@ -1,4 +1,4 @@
-#![allow(static_mut_ref)]
+#![allow(static_mut_refs)]
 
 const C1: &'static mut [usize] = &mut [];
 //~^ ERROR: mutable references are not allowed
diff --git a/tests/ui/consts/miri_unleashed/const_refers_to_static_cross_crate.rs b/tests/ui/consts/miri_unleashed/const_refers_to_static_cross_crate.rs
index 6ec44aab2c1..5e7845e4e82 100644
--- a/tests/ui/consts/miri_unleashed/const_refers_to_static_cross_crate.rs
+++ b/tests/ui/consts/miri_unleashed/const_refers_to_static_cross_crate.rs
@@ -3,7 +3,7 @@
 //@ normalize-stderr-test "(the raw bytes of the constant) \(size: [0-9]*, align: [0-9]*\)" -> "$1 (size: $$SIZE, align: $$ALIGN)"
 //@ normalize-stderr-test "([0-9a-f][0-9a-f] |╾─*ALLOC[0-9]+(\+[a-z0-9]+)?(<imm>)?─*╼ )+ *│.*" -> "HEX_DUMP"
 #![feature(exclusive_range_pattern, half_open_range_patterns_in_slices)]
-#![allow(static_mut_ref)]
+#![allow(static_mut_refs)]
 
 extern crate static_cross_crate;
 
diff --git a/tests/ui/consts/miri_unleashed/extern-static.rs b/tests/ui/consts/miri_unleashed/extern-static.rs
index 1a523cc8e31..c9d9397518e 100644
--- a/tests/ui/consts/miri_unleashed/extern-static.rs
+++ b/tests/ui/consts/miri_unleashed/extern-static.rs
@@ -1,6 +1,6 @@
 //@ compile-flags: -Zunleash-the-miri-inside-of-you
 #![feature(thread_local)]
-#![allow(static_mut_ref)]
+#![allow(static_mut_refs)]
 
 extern "C" {
     static mut DATA: u8;
diff --git a/tests/ui/consts/miri_unleashed/mutable_references_err.32bit.stderr b/tests/ui/consts/miri_unleashed/mutable_references_err.32bit.stderr
index 82739c08cf1..ea7573bf217 100644
--- a/tests/ui/consts/miri_unleashed/mutable_references_err.32bit.stderr
+++ b/tests/ui/consts/miri_unleashed/mutable_references_err.32bit.stderr
@@ -5,13 +5,13 @@ LL | const MUH: Meh = Meh {
    | ^^^^^^^^^^^^^^
 
 error: encountered mutable pointer in final value of constant
-  --> $DIR/mutable_references_err.rs:27:1
+  --> $DIR/mutable_references_err.rs:28:1
    |
 LL | const SNEAKY: &dyn Sync = &Synced { x: UnsafeCell::new(42) };
    | ^^^^^^^^^^^^^^^^^^^^^^^
 
 error[E0080]: it is undefined behavior to use this value
-  --> $DIR/mutable_references_err.rs:32:1
+  --> $DIR/mutable_references_err.rs:33:1
    |
 LL | const SUBTLE: &mut i32 = unsafe { &mut FOO };
    | ^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered mutable reference in a `const` or `static`
@@ -22,13 +22,13 @@ LL | const SUBTLE: &mut i32 = unsafe { &mut FOO };
            }
 
 error: encountered mutable pointer in final value of constant
-  --> $DIR/mutable_references_err.rs:35:1
+  --> $DIR/mutable_references_err.rs:36:1
    |
 LL | const BLUNT: &mut i32 = &mut 42;
    | ^^^^^^^^^^^^^^^^^^^^^
 
 error[E0080]: it is undefined behavior to use this value
-  --> $DIR/mutable_references_err.rs:40:1
+  --> $DIR/mutable_references_err.rs:41:1
    |
 LL | static mut MUT_TO_READONLY: &mut i32 = unsafe { &mut *(&READONLY as *const _ as *mut _) };
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered mutable reference or box pointing to read-only memory
@@ -39,7 +39,7 @@ LL | static mut MUT_TO_READONLY: &mut i32 = unsafe { &mut *(&READONLY as *const
            }
 
 error[E0080]: it is undefined behavior to use this value
-  --> $DIR/mutable_references_err.rs:47:1
+  --> $DIR/mutable_references_err.rs:48:1
    |
 LL | const POINTS_TO_MUTABLE1: &i32 = unsafe { &MUTABLE };
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered reference to mutable memory in `const`
@@ -50,49 +50,49 @@ LL | const POINTS_TO_MUTABLE1: &i32 = unsafe { &MUTABLE };
            }
 
 note: erroneous constant encountered
-  --> $DIR/mutable_references_err.rs:49:34
+  --> $DIR/mutable_references_err.rs:50:34
    |
 LL | const READS_FROM_MUTABLE: i32 = *POINTS_TO_MUTABLE1;
    |                                  ^^^^^^^^^^^^^^^^^^
 
 error[E0080]: evaluation of constant value failed
-  --> $DIR/mutable_references_err.rs:51:43
+  --> $DIR/mutable_references_err.rs:52:43
    |
 LL | const POINTS_TO_MUTABLE2: &i32 = unsafe { &*MUTABLE_REF };
    |                                           ^^^^^^^^^^^^^ constant accesses mutable global memory
 
 error: encountered mutable pointer in final value of constant
-  --> $DIR/mutable_references_err.rs:55:1
+  --> $DIR/mutable_references_err.rs:56:1
    |
 LL | const POINTS_TO_MUTABLE_INNER: *const i32 = &mut 42 as *mut _ as *const _;
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: encountered mutable pointer in final value of constant
-  --> $DIR/mutable_references_err.rs:57:1
+  --> $DIR/mutable_references_err.rs:58:1
    |
 LL | const POINTS_TO_MUTABLE_INNER2: *const i32 = &mut 42 as *const _;
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: encountered mutable pointer in final value of constant
-  --> $DIR/mutable_references_err.rs:59:1
+  --> $DIR/mutable_references_err.rs:60:1
    |
 LL | const INTERIOR_MUTABLE_BEHIND_RAW: *mut i32 = &UnsafeCell::new(42) as *const _ as *mut _;
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: encountered mutable pointer in final value of constant
-  --> $DIR/mutable_references_err.rs:69:1
+  --> $DIR/mutable_references_err.rs:72:1
    |
 LL | const RAW_SYNC: SyncPtr<AtomicI32> = SyncPtr { x: &AtomicI32::new(42) };
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: encountered mutable pointer in final value of constant
-  --> $DIR/mutable_references_err.rs:71:1
+  --> $DIR/mutable_references_err.rs:74:1
    |
-LL | const RAW_MUT_CAST: SyncPtr<i32> = SyncPtr { x : &mut 42 as *mut _ as *const _ };
+LL | const RAW_MUT_CAST: SyncPtr<i32> = SyncPtr { x: &mut 42 as *mut _ as *const _ };
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: encountered mutable pointer in final value of constant
-  --> $DIR/mutable_references_err.rs:73:1
+  --> $DIR/mutable_references_err.rs:76:1
    |
 LL | const RAW_MUT_COERCE: SyncPtr<i32> = SyncPtr { x: &mut 0 };
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -100,77 +100,77 @@ LL | const RAW_MUT_COERCE: SyncPtr<i32> = SyncPtr { x: &mut 0 };
 warning: skipping const checks
    |
 help: skipping check that does not even have a feature gate
-  --> $DIR/mutable_references_err.rs:18:8
+  --> $DIR/mutable_references_err.rs:19:8
    |
 LL |     x: &UnsafeCell::new(42),
    |        ^^^^^^^^^^^^^^^^^^^^
 help: skipping check that does not even have a feature gate
-  --> $DIR/mutable_references_err.rs:27:27
+  --> $DIR/mutable_references_err.rs:28:27
    |
 LL | const SNEAKY: &dyn Sync = &Synced { x: UnsafeCell::new(42) };
    |                           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 help: skipping check for `const_refs_to_static` feature
-  --> $DIR/mutable_references_err.rs:32:40
+  --> $DIR/mutable_references_err.rs:33:40
    |
 LL | const SUBTLE: &mut i32 = unsafe { &mut FOO };
    |                                        ^^^
 help: skipping check for `const_mut_refs` feature
-  --> $DIR/mutable_references_err.rs:32:35
+  --> $DIR/mutable_references_err.rs:33:35
    |
 LL | const SUBTLE: &mut i32 = unsafe { &mut FOO };
    |                                   ^^^^^^^^
 help: skipping check that does not even have a feature gate
-  --> $DIR/mutable_references_err.rs:35:25
+  --> $DIR/mutable_references_err.rs:36:25
    |
 LL | const BLUNT: &mut i32 = &mut 42;
    |                         ^^^^^^^
 help: skipping check for `const_mut_refs` feature
-  --> $DIR/mutable_references_err.rs:40:49
+  --> $DIR/mutable_references_err.rs:41:49
    |
 LL | static mut MUT_TO_READONLY: &mut i32 = unsafe { &mut *(&READONLY as *const _ as *mut _) };
    |                                                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 help: skipping check for `const_mut_refs` feature
-  --> $DIR/mutable_references_err.rs:40:49
+  --> $DIR/mutable_references_err.rs:41:49
    |
 LL | static mut MUT_TO_READONLY: &mut i32 = unsafe { &mut *(&READONLY as *const _ as *mut _) };
    |                                                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 help: skipping check for `const_refs_to_static` feature
-  --> $DIR/mutable_references_err.rs:47:44
+  --> $DIR/mutable_references_err.rs:48:44
    |
 LL | const POINTS_TO_MUTABLE1: &i32 = unsafe { &MUTABLE };
    |                                            ^^^^^^^
 help: skipping check for `const_refs_to_static` feature
-  --> $DIR/mutable_references_err.rs:51:45
+  --> $DIR/mutable_references_err.rs:52:45
    |
 LL | const POINTS_TO_MUTABLE2: &i32 = unsafe { &*MUTABLE_REF };
    |                                             ^^^^^^^^^^^
 help: skipping check that does not even have a feature gate
-  --> $DIR/mutable_references_err.rs:55:45
+  --> $DIR/mutable_references_err.rs:56:45
    |
 LL | const POINTS_TO_MUTABLE_INNER: *const i32 = &mut 42 as *mut _ as *const _;
    |                                             ^^^^^^^
 help: skipping check that does not even have a feature gate
-  --> $DIR/mutable_references_err.rs:57:46
+  --> $DIR/mutable_references_err.rs:58:46
    |
 LL | const POINTS_TO_MUTABLE_INNER2: *const i32 = &mut 42 as *const _;
    |                                              ^^^^^^^
 help: skipping check that does not even have a feature gate
-  --> $DIR/mutable_references_err.rs:59:47
+  --> $DIR/mutable_references_err.rs:60:47
    |
 LL | const INTERIOR_MUTABLE_BEHIND_RAW: *mut i32 = &UnsafeCell::new(42) as *const _ as *mut _;
    |                                               ^^^^^^^^^^^^^^^^^^^^
 help: skipping check that does not even have a feature gate
-  --> $DIR/mutable_references_err.rs:69:51
+  --> $DIR/mutable_references_err.rs:72:51
    |
 LL | const RAW_SYNC: SyncPtr<AtomicI32> = SyncPtr { x: &AtomicI32::new(42) };
    |                                                   ^^^^^^^^^^^^^^^^^^^
 help: skipping check that does not even have a feature gate
-  --> $DIR/mutable_references_err.rs:71:50
+  --> $DIR/mutable_references_err.rs:74:49
    |
-LL | const RAW_MUT_CAST: SyncPtr<i32> = SyncPtr { x : &mut 42 as *mut _ as *const _ };
-   |                                                  ^^^^^^^
+LL | const RAW_MUT_CAST: SyncPtr<i32> = SyncPtr { x: &mut 42 as *mut _ as *const _ };
+   |                                                 ^^^^^^^
 help: skipping check that does not even have a feature gate
-  --> $DIR/mutable_references_err.rs:73:51
+  --> $DIR/mutable_references_err.rs:76:51
    |
 LL | const RAW_MUT_COERCE: SyncPtr<i32> = SyncPtr { x: &mut 0 };
    |                                                   ^^^^^^
diff --git a/tests/ui/consts/miri_unleashed/mutable_references_err.64bit.stderr b/tests/ui/consts/miri_unleashed/mutable_references_err.64bit.stderr
index 844483d88e9..2b5e8643f3b 100644
--- a/tests/ui/consts/miri_unleashed/mutable_references_err.64bit.stderr
+++ b/tests/ui/consts/miri_unleashed/mutable_references_err.64bit.stderr
@@ -5,13 +5,13 @@ LL | const MUH: Meh = Meh {
    | ^^^^^^^^^^^^^^
 
 error: encountered mutable pointer in final value of constant
-  --> $DIR/mutable_references_err.rs:27:1
+  --> $DIR/mutable_references_err.rs:28:1
    |
 LL | const SNEAKY: &dyn Sync = &Synced { x: UnsafeCell::new(42) };
    | ^^^^^^^^^^^^^^^^^^^^^^^
 
 error[E0080]: it is undefined behavior to use this value
-  --> $DIR/mutable_references_err.rs:32:1
+  --> $DIR/mutable_references_err.rs:33:1
    |
 LL | const SUBTLE: &mut i32 = unsafe { &mut FOO };
    | ^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered mutable reference in a `const` or `static`
@@ -22,13 +22,13 @@ LL | const SUBTLE: &mut i32 = unsafe { &mut FOO };
            }
 
 error: encountered mutable pointer in final value of constant
-  --> $DIR/mutable_references_err.rs:35:1
+  --> $DIR/mutable_references_err.rs:36:1
    |
 LL | const BLUNT: &mut i32 = &mut 42;
    | ^^^^^^^^^^^^^^^^^^^^^
 
 error[E0080]: it is undefined behavior to use this value
-  --> $DIR/mutable_references_err.rs:40:1
+  --> $DIR/mutable_references_err.rs:41:1
    |
 LL | static mut MUT_TO_READONLY: &mut i32 = unsafe { &mut *(&READONLY as *const _ as *mut _) };
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered mutable reference or box pointing to read-only memory
@@ -39,7 +39,7 @@ LL | static mut MUT_TO_READONLY: &mut i32 = unsafe { &mut *(&READONLY as *const
            }
 
 error[E0080]: it is undefined behavior to use this value
-  --> $DIR/mutable_references_err.rs:47:1
+  --> $DIR/mutable_references_err.rs:48:1
    |
 LL | const POINTS_TO_MUTABLE1: &i32 = unsafe { &MUTABLE };
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered reference to mutable memory in `const`
@@ -50,49 +50,49 @@ LL | const POINTS_TO_MUTABLE1: &i32 = unsafe { &MUTABLE };
            }
 
 note: erroneous constant encountered
-  --> $DIR/mutable_references_err.rs:49:34
+  --> $DIR/mutable_references_err.rs:50:34
    |
 LL | const READS_FROM_MUTABLE: i32 = *POINTS_TO_MUTABLE1;
    |                                  ^^^^^^^^^^^^^^^^^^
 
 error[E0080]: evaluation of constant value failed
-  --> $DIR/mutable_references_err.rs:51:43
+  --> $DIR/mutable_references_err.rs:52:43
    |
 LL | const POINTS_TO_MUTABLE2: &i32 = unsafe { &*MUTABLE_REF };
    |                                           ^^^^^^^^^^^^^ constant accesses mutable global memory
 
 error: encountered mutable pointer in final value of constant
-  --> $DIR/mutable_references_err.rs:55:1
+  --> $DIR/mutable_references_err.rs:56:1
    |
 LL | const POINTS_TO_MUTABLE_INNER: *const i32 = &mut 42 as *mut _ as *const _;
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: encountered mutable pointer in final value of constant
-  --> $DIR/mutable_references_err.rs:57:1
+  --> $DIR/mutable_references_err.rs:58:1
    |
 LL | const POINTS_TO_MUTABLE_INNER2: *const i32 = &mut 42 as *const _;
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: encountered mutable pointer in final value of constant
-  --> $DIR/mutable_references_err.rs:59:1
+  --> $DIR/mutable_references_err.rs:60:1
    |
 LL | const INTERIOR_MUTABLE_BEHIND_RAW: *mut i32 = &UnsafeCell::new(42) as *const _ as *mut _;
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: encountered mutable pointer in final value of constant
-  --> $DIR/mutable_references_err.rs:69:1
+  --> $DIR/mutable_references_err.rs:72:1
    |
 LL | const RAW_SYNC: SyncPtr<AtomicI32> = SyncPtr { x: &AtomicI32::new(42) };
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: encountered mutable pointer in final value of constant
-  --> $DIR/mutable_references_err.rs:71:1
+  --> $DIR/mutable_references_err.rs:74:1
    |
-LL | const RAW_MUT_CAST: SyncPtr<i32> = SyncPtr { x : &mut 42 as *mut _ as *const _ };
+LL | const RAW_MUT_CAST: SyncPtr<i32> = SyncPtr { x: &mut 42 as *mut _ as *const _ };
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: encountered mutable pointer in final value of constant
-  --> $DIR/mutable_references_err.rs:73:1
+  --> $DIR/mutable_references_err.rs:76:1
    |
 LL | const RAW_MUT_COERCE: SyncPtr<i32> = SyncPtr { x: &mut 0 };
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -100,77 +100,77 @@ LL | const RAW_MUT_COERCE: SyncPtr<i32> = SyncPtr { x: &mut 0 };
 warning: skipping const checks
    |
 help: skipping check that does not even have a feature gate
-  --> $DIR/mutable_references_err.rs:18:8
+  --> $DIR/mutable_references_err.rs:19:8
    |
 LL |     x: &UnsafeCell::new(42),
    |        ^^^^^^^^^^^^^^^^^^^^
 help: skipping check that does not even have a feature gate
-  --> $DIR/mutable_references_err.rs:27:27
+  --> $DIR/mutable_references_err.rs:28:27
    |
 LL | const SNEAKY: &dyn Sync = &Synced { x: UnsafeCell::new(42) };
    |                           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 help: skipping check for `const_refs_to_static` feature
-  --> $DIR/mutable_references_err.rs:32:40
+  --> $DIR/mutable_references_err.rs:33:40
    |
 LL | const SUBTLE: &mut i32 = unsafe { &mut FOO };
    |                                        ^^^
 help: skipping check for `const_mut_refs` feature
-  --> $DIR/mutable_references_err.rs:32:35
+  --> $DIR/mutable_references_err.rs:33:35
    |
 LL | const SUBTLE: &mut i32 = unsafe { &mut FOO };
    |                                   ^^^^^^^^
 help: skipping check that does not even have a feature gate
-  --> $DIR/mutable_references_err.rs:35:25
+  --> $DIR/mutable_references_err.rs:36:25
    |
 LL | const BLUNT: &mut i32 = &mut 42;
    |                         ^^^^^^^
 help: skipping check for `const_mut_refs` feature
-  --> $DIR/mutable_references_err.rs:40:49
+  --> $DIR/mutable_references_err.rs:41:49
    |
 LL | static mut MUT_TO_READONLY: &mut i32 = unsafe { &mut *(&READONLY as *const _ as *mut _) };
    |                                                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 help: skipping check for `const_mut_refs` feature
-  --> $DIR/mutable_references_err.rs:40:49
+  --> $DIR/mutable_references_err.rs:41:49
    |
 LL | static mut MUT_TO_READONLY: &mut i32 = unsafe { &mut *(&READONLY as *const _ as *mut _) };
    |                                                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 help: skipping check for `const_refs_to_static` feature
-  --> $DIR/mutable_references_err.rs:47:44
+  --> $DIR/mutable_references_err.rs:48:44
    |
 LL | const POINTS_TO_MUTABLE1: &i32 = unsafe { &MUTABLE };
    |                                            ^^^^^^^
 help: skipping check for `const_refs_to_static` feature
-  --> $DIR/mutable_references_err.rs:51:45
+  --> $DIR/mutable_references_err.rs:52:45
    |
 LL | const POINTS_TO_MUTABLE2: &i32 = unsafe { &*MUTABLE_REF };
    |                                             ^^^^^^^^^^^
 help: skipping check that does not even have a feature gate
-  --> $DIR/mutable_references_err.rs:55:45
+  --> $DIR/mutable_references_err.rs:56:45
    |
 LL | const POINTS_TO_MUTABLE_INNER: *const i32 = &mut 42 as *mut _ as *const _;
    |                                             ^^^^^^^
 help: skipping check that does not even have a feature gate
-  --> $DIR/mutable_references_err.rs:57:46
+  --> $DIR/mutable_references_err.rs:58:46
    |
 LL | const POINTS_TO_MUTABLE_INNER2: *const i32 = &mut 42 as *const _;
    |                                              ^^^^^^^
 help: skipping check that does not even have a feature gate
-  --> $DIR/mutable_references_err.rs:59:47
+  --> $DIR/mutable_references_err.rs:60:47
    |
 LL | const INTERIOR_MUTABLE_BEHIND_RAW: *mut i32 = &UnsafeCell::new(42) as *const _ as *mut _;
    |                                               ^^^^^^^^^^^^^^^^^^^^
 help: skipping check that does not even have a feature gate
-  --> $DIR/mutable_references_err.rs:69:51
+  --> $DIR/mutable_references_err.rs:72:51
    |
 LL | const RAW_SYNC: SyncPtr<AtomicI32> = SyncPtr { x: &AtomicI32::new(42) };
    |                                                   ^^^^^^^^^^^^^^^^^^^
 help: skipping check that does not even have a feature gate
-  --> $DIR/mutable_references_err.rs:71:50
+  --> $DIR/mutable_references_err.rs:74:49
    |
-LL | const RAW_MUT_CAST: SyncPtr<i32> = SyncPtr { x : &mut 42 as *mut _ as *const _ };
-   |                                                  ^^^^^^^
+LL | const RAW_MUT_CAST: SyncPtr<i32> = SyncPtr { x: &mut 42 as *mut _ as *const _ };
+   |                                                 ^^^^^^^
 help: skipping check that does not even have a feature gate
-  --> $DIR/mutable_references_err.rs:73:51
+  --> $DIR/mutable_references_err.rs:76:51
    |
 LL | const RAW_MUT_COERCE: SyncPtr<i32> = SyncPtr { x: &mut 0 };
    |                                                   ^^^^^^
diff --git a/tests/ui/consts/miri_unleashed/mutable_references_err.rs b/tests/ui/consts/miri_unleashed/mutable_references_err.rs
index 2075adad6f7..feb2c825380 100644
--- a/tests/ui/consts/miri_unleashed/mutable_references_err.rs
+++ b/tests/ui/consts/miri_unleashed/mutable_references_err.rs
@@ -1,9 +1,9 @@
 //@ stderr-per-bitwidth
 //@ compile-flags: -Zunleash-the-miri-inside-of-you
-#![allow(invalid_reference_casting, static_mut_ref)]
+#![allow(invalid_reference_casting, static_mut_refs)]
 
-use std::sync::atomic::*;
 use std::cell::UnsafeCell;
+use std::sync::atomic::*;
 
 // this test ensures that our mutability story is sound
 
@@ -14,7 +14,8 @@ unsafe impl Sync for Meh {}
 
 // the following will never be ok! no interior mut behind consts, because
 // all allocs interned here will be marked immutable.
-const MUH: Meh = Meh { //~ ERROR: mutable pointer in final value
+const MUH: Meh = Meh {
+    //~^ ERROR encountered mutable pointer in final value of constant
     x: &UnsafeCell::new(42),
 };
 
@@ -59,7 +60,9 @@ const POINTS_TO_MUTABLE_INNER2: *const i32 = &mut 42 as *const _;
 const INTERIOR_MUTABLE_BEHIND_RAW: *mut i32 = &UnsafeCell::new(42) as *const _ as *mut _;
 //~^ ERROR: mutable pointer in final value
 
-struct SyncPtr<T> { x : *const T }
+struct SyncPtr<T> {
+    x: *const T,
+}
 unsafe impl<T> Sync for SyncPtr<T> {}
 
 // These pass the lifetime checks because of the "tail expression" / "outer scope" rule.
@@ -68,7 +71,7 @@ unsafe impl<T> Sync for SyncPtr<T> {}
 // (Also see `static-no-inner-mut` for similar tests on `static`.)
 const RAW_SYNC: SyncPtr<AtomicI32> = SyncPtr { x: &AtomicI32::new(42) };
 //~^ ERROR mutable pointer in final value
-const RAW_MUT_CAST: SyncPtr<i32> = SyncPtr { x : &mut 42 as *mut _ as *const _ };
+const RAW_MUT_CAST: SyncPtr<i32> = SyncPtr { x: &mut 42 as *mut _ as *const _ };
 //~^ ERROR mutable pointer in final value
 const RAW_MUT_COERCE: SyncPtr<i32> = SyncPtr { x: &mut 0 };
 //~^ ERROR mutable pointer in final value
diff --git a/tests/ui/consts/static-promoted-to-mutable-static.rs b/tests/ui/consts/static-promoted-to-mutable-static.rs
index 1cf72781e45..9eb9e1b8dfb 100644
--- a/tests/ui/consts/static-promoted-to-mutable-static.rs
+++ b/tests/ui/consts/static-promoted-to-mutable-static.rs
@@ -1,8 +1,9 @@
 //@ check-pass
-#![allow(non_camel_case_types, non_upper_case_globals, static_mut_ref)]
+
+#![allow(non_camel_case_types, non_upper_case_globals, static_mut_refs)]
 
 pub struct wl_interface {
-    pub version: i32
+    pub version: i32,
 }
 
 pub struct Interface {
@@ -10,20 +11,14 @@ pub struct Interface {
     pub c_ptr: Option<&'static wl_interface>,
 }
 
-pub static mut wl_callback_interface: wl_interface = wl_interface {
-    version: 0,
-};
+pub static mut wl_callback_interface: wl_interface = wl_interface { version: 0 };
 
-pub static WL_CALLBACK_INTERFACE: Interface = Interface {
-    other_interfaces: &[],
-    c_ptr: Some(unsafe { &wl_callback_interface }),
-};
+pub static WL_CALLBACK_INTERFACE: Interface =
+    Interface { other_interfaces: &[], c_ptr: Some(unsafe { &wl_callback_interface }) };
 
 // This static contains a promoted that points to a static that points to a mutable static.
-pub static WL_SURFACE_INTERFACE: Interface = Interface {
-    other_interfaces: &[&WL_CALLBACK_INTERFACE],
-    c_ptr: None,
-};
+pub static WL_SURFACE_INTERFACE: Interface =
+    Interface { other_interfaces: &[&WL_CALLBACK_INTERFACE], c_ptr: None };
 
 // And another variant of the same thing, this time with interior mutability.
 use std::sync::OnceLock;
diff --git a/tests/ui/consts/static_mut_containing_mut_ref.rs b/tests/ui/consts/static_mut_containing_mut_ref.rs
index 710328d6aa7..874a047d807 100644
--- a/tests/ui/consts/static_mut_containing_mut_ref.rs
+++ b/tests/ui/consts/static_mut_containing_mut_ref.rs
@@ -1,5 +1,5 @@
 //@ build-pass (FIXME(62277): could be check-pass?)
-#![allow(static_mut_ref)]
+#![allow(static_mut_refs)]
 
 static mut STDERR_BUFFER_SPACE: [u8; 42] = [0u8; 42];
 
diff --git a/tests/ui/consts/static_mut_containing_mut_ref2.rs b/tests/ui/consts/static_mut_containing_mut_ref2.rs
index b5110623606..547f6449f13 100644
--- a/tests/ui/consts/static_mut_containing_mut_ref2.rs
+++ b/tests/ui/consts/static_mut_containing_mut_ref2.rs
@@ -1,5 +1,5 @@
 //@ revisions: stock mut_refs
-#![allow(static_mut_ref)]
+#![allow(static_mut_refs)]
 #![cfg_attr(mut_refs, feature(const_mut_refs))]
 
 static mut STDERR_BUFFER_SPACE: u8 = 0;
diff --git a/tests/ui/crate-loading/missing-std.rs b/tests/ui/crate-loading/missing-std.rs
index ca9501cda3a..aed8b0c530a 100644
--- a/tests/ui/crate-loading/missing-std.rs
+++ b/tests/ui/crate-loading/missing-std.rs
@@ -1,6 +1,6 @@
 //@ compile-flags: --target x86_64-unknown-uefi
 //@ needs-llvm-components: x86
-//@ rustc-env:CARGO=/usr/bin/cargo
+//@ rustc-env:CARGO_CRATE_NAME=foo
 #![feature(no_core)]
 #![no_core]
 extern crate core;
diff --git a/tests/ui/drop/issue-23338-ensure-param-drop-order.rs b/tests/ui/drop/issue-23338-ensure-param-drop-order.rs
index f283b33f645..1fa68a2e738 100644
--- a/tests/ui/drop/issue-23338-ensure-param-drop-order.rs
+++ b/tests/ui/drop/issue-23338-ensure-param-drop-order.rs
@@ -91,7 +91,7 @@ pub mod d {
     pub fn max_width() -> u32 {
         unsafe {
             (mem::size_of_val(&trails) * 8) as u32
-            //~^ WARN shared reference of mutable static is discouraged [static_mut_ref]
+            //~^ WARN shared reference to mutable static is discouraged [static_mut_refs]
         }
     }
 
diff --git a/tests/ui/drop/issue-23338-ensure-param-drop-order.stderr b/tests/ui/drop/issue-23338-ensure-param-drop-order.stderr
index fd36ccbcbee..de1194e74b4 100644
--- a/tests/ui/drop/issue-23338-ensure-param-drop-order.stderr
+++ b/tests/ui/drop/issue-23338-ensure-param-drop-order.stderr
@@ -1,14 +1,14 @@
-warning: shared reference of mutable static is discouraged
+warning: creating a shared reference to mutable static is discouraged
   --> $DIR/issue-23338-ensure-param-drop-order.rs:93:31
    |
 LL |             (mem::size_of_val(&trails) * 8) as u32
-   |                               ^^^^^^^ shared reference of mutable static
+   |                               ^^^^^^^ shared reference to mutable static
    |
    = note: for more information, see issue #114447 <https://github.com/rust-lang/rust/issues/114447>
-   = note: reference of mutable static is a hard error from 2024 edition
-   = note: mutable statics can be written to by multiple threads: aliasing violations or data races will cause undefined behavior
-   = note: `#[warn(static_mut_ref)]` on by default
-help: shared references are dangerous since if there's any kind of mutation of that static while the reference lives, that's UB; use `addr_of!` instead to create a raw pointer
+   = note: this will be a hard error in the 2024 edition
+   = note: this shared reference has lifetime `'static`, but if the static ever gets mutated, or a mutable reference is created, then any further use of this shared reference is Undefined Behavior
+   = note: `#[warn(static_mut_refs)]` on by default
+help: use `addr_of!` instead to create a raw pointer
    |
 LL |             (mem::size_of_val(addr_of!(trails)) * 8) as u32
    |                               ~~~~~~~~~~~~~~~~
diff --git a/tests/ui/editions/edition-keywords-2018-2018-parsing.rs b/tests/ui/editions/edition-keywords-2018-2018-parsing.rs
index e3eed775a5f..4975246fa94 100644
--- a/tests/ui/editions/edition-keywords-2018-2018-parsing.rs
+++ b/tests/ui/editions/edition-keywords-2018-2018-parsing.rs
@@ -16,7 +16,7 @@ macro_rules! local_passes_ident {
     ($i: ident) => ($i) //~ ERROR macro expansion ends with an incomplete expression
 }
 macro_rules! local_passes_tt {
-    ($i: tt) => ($i) //~ ERROR macro expansion ends with an incomplete expression
+    ($i: tt) => ($i)
 }
 
 pub fn check_async() {
@@ -34,7 +34,7 @@ pub fn check_async() {
     if passes_tt!(r#async) == 1 {} // OK
     if local_passes_ident!(async) == 1 {} // Error reported above in the macro
     if local_passes_ident!(r#async) == 1 {} // OK
-    if local_passes_tt!(async) == 1 {} // Error reported above in the macro
+    if local_passes_tt!(async) == 1 {} //~ ERROR macro expansion ends with an incomplete expression
     if local_passes_tt!(r#async) == 1 {} // OK
     module::async(); //~ ERROR expected identifier, found keyword `async`
     module::r#async(); // OK
diff --git a/tests/ui/editions/edition-keywords-2018-2018-parsing.stderr b/tests/ui/editions/edition-keywords-2018-2018-parsing.stderr
index 6f08cff433b..4bbe1597233 100644
--- a/tests/ui/editions/edition-keywords-2018-2018-parsing.stderr
+++ b/tests/ui/editions/edition-keywords-2018-2018-parsing.stderr
@@ -68,10 +68,10 @@ LL |     ($i: ident) => ($i)
    |                       ^ expected one of `move`, `|`, or `||`
 
 error: macro expansion ends with an incomplete expression: expected one of `move`, `|`, or `||`
-  --> $DIR/edition-keywords-2018-2018-parsing.rs:19:20
+  --> $DIR/edition-keywords-2018-2018-parsing.rs:37:30
    |
-LL |     ($i: tt) => ($i)
-   |                    ^ expected one of `move`, `|`, or `||`
+LL |     if local_passes_tt!(async) == 1 {}
+   |                              ^ expected one of `move`, `|`, or `||`
 
 error[E0308]: mismatched types
   --> $DIR/edition-keywords-2018-2018-parsing.rs:42:33
diff --git a/tests/ui/error-codes/E0017.rs b/tests/ui/error-codes/E0017.rs
index c128c2779e2..144340b3512 100644
--- a/tests/ui/error-codes/E0017.rs
+++ b/tests/ui/error-codes/E0017.rs
@@ -13,6 +13,6 @@ static CONST_REF: &'static mut i32 = &mut C; //~ ERROR mutable references are no
 //~| WARN taking a mutable
 
 static STATIC_MUT_REF: &'static mut i32 = unsafe { &mut M };
-//~^ WARN mutable reference of mutable static is discouraged [static_mut_ref]
+//~^ WARN mutable reference to mutable static is discouraged [static_mut_refs]
 
 fn main() {}
diff --git a/tests/ui/error-codes/E0017.stderr b/tests/ui/error-codes/E0017.stderr
index eb626a7fe3a..982ce52764e 100644
--- a/tests/ui/error-codes/E0017.stderr
+++ b/tests/ui/error-codes/E0017.stderr
@@ -1,14 +1,14 @@
-warning: mutable reference of mutable static is discouraged
+warning: creating a mutable reference to mutable static is discouraged
   --> $DIR/E0017.rs:15:52
    |
 LL | static STATIC_MUT_REF: &'static mut i32 = unsafe { &mut M };
-   |                                                    ^^^^^^ mutable reference of mutable static
+   |                                                    ^^^^^^ mutable reference to mutable static
    |
    = note: for more information, see issue #114447 <https://github.com/rust-lang/rust/issues/114447>
-   = note: reference of mutable static is a hard error from 2024 edition
-   = note: mutable statics can be written to by multiple threads: aliasing violations or data races will cause undefined behavior
-   = note: `#[warn(static_mut_ref)]` on by default
-help: mutable references are dangerous since if there's any other pointer or reference used for that static while the reference lives, that's UB; use `addr_of_mut!` instead to create a raw pointer
+   = note: this will be a hard error in the 2024 edition
+   = note: this mutable reference has lifetime `'static`, but if the static gets accessed (read or written) by any other means, or any other reference is created, then any further use of this mutable reference is Undefined Behavior
+   = note: `#[warn(static_mut_refs)]` on by default
+help: use `addr_of_mut!` instead to create a raw pointer
    |
 LL | static STATIC_MUT_REF: &'static mut i32 = unsafe { addr_of_mut!(M) };
    |                                                    ~~~~~~~~~~~~~~~
diff --git a/tests/ui/error-codes/E0093.stderr b/tests/ui/error-codes/E0093.stderr
index 387e0c55d4d..51c367b343a 100644
--- a/tests/ui/error-codes/E0093.stderr
+++ b/tests/ui/error-codes/E0093.stderr
@@ -3,6 +3,8 @@ error[E0093]: unrecognized intrinsic function: `foo`
    |
 LL |     fn foo();
    |     ^^^^^^^^^ unrecognized intrinsic
+   |
+   = help: if you're adding an intrinsic, be sure to update `check_intrinsic_type`
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/error-should-say-copy-not-pod.stderr b/tests/ui/error-should-say-copy-not-pod.stderr
index 658584e2ff4..6aa129fa29b 100644
--- a/tests/ui/error-should-say-copy-not-pod.stderr
+++ b/tests/ui/error-should-say-copy-not-pod.stderr
@@ -11,6 +11,11 @@ note: required by a bound in `check_bound`
    |
 LL | fn check_bound<T:Copy>(_: T) {}
    |                  ^^^^ required by this bound in `check_bound`
+help: consider removing this method call, as the receiver has type `&'static str` and `&'static str: Copy` trivially holds
+   |
+LL -     check_bound("nocopy".to_string());
+LL +     check_bound("nocopy");
+   |
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/feature-gates/feature-gate-abi.stderr b/tests/ui/feature-gates/feature-gate-abi.stderr
index aa60434d9fe..3fd1e1189ab 100644
--- a/tests/ui/feature-gates/feature-gate-abi.stderr
+++ b/tests/ui/feature-gates/feature-gate-abi.stderr
@@ -187,12 +187,16 @@ error[E0093]: unrecognized intrinsic function: `f1`
    |
 LL | extern "rust-intrinsic" fn f1() {}
    |                            ^^ unrecognized intrinsic
+   |
+   = help: if you're adding an intrinsic, be sure to update `check_intrinsic_type`
 
 error[E0093]: unrecognized intrinsic function: `f2`
   --> $DIR/feature-gate-abi.rs:18:32
    |
 LL | extern "platform-intrinsic" fn f2() {}
    |                                ^^ unrecognized intrinsic
+   |
+   = help: if you're adding an intrinsic, be sure to update `check_intrinsic_type`
 
 error: intrinsic must be in `extern "rust-intrinsic" { ... }` block
   --> $DIR/feature-gate-abi.rs:25:32
diff --git a/tests/ui/feature-gates/feature-gate-intrinsics.stderr b/tests/ui/feature-gates/feature-gate-intrinsics.stderr
index 78c21843adb..583a4a1a84e 100644
--- a/tests/ui/feature-gates/feature-gate-intrinsics.stderr
+++ b/tests/ui/feature-gates/feature-gate-intrinsics.stderr
@@ -21,12 +21,16 @@ error[E0093]: unrecognized intrinsic function: `bar`
    |
 LL |     fn bar();
    |     ^^^^^^^^^ unrecognized intrinsic
+   |
+   = help: if you're adding an intrinsic, be sure to update `check_intrinsic_type`
 
 error[E0093]: unrecognized intrinsic function: `baz`
   --> $DIR/feature-gate-intrinsics.rs:5:28
    |
 LL | extern "rust-intrinsic" fn baz() {}
    |                            ^^^ unrecognized intrinsic
+   |
+   = help: if you're adding an intrinsic, be sure to update `check_intrinsic_type`
 
 error: intrinsic must be in `extern "rust-intrinsic" { ... }` block
   --> $DIR/feature-gate-intrinsics.rs:5:34
diff --git a/tests/ui/fmt/format-args-capture-first-literal-is-macro.rs b/tests/ui/fmt/format-args-capture-first-literal-is-macro.rs
index 5afd21a17e5..3a0b7ba4666 100644
--- a/tests/ui/fmt/format-args-capture-first-literal-is-macro.rs
+++ b/tests/ui/fmt/format-args-capture-first-literal-is-macro.rs
@@ -6,7 +6,6 @@ extern crate format_string_proc_macro;
 macro_rules! identity_mbe {
     ($tt:tt) => {
         $tt
-        //~^ ERROR there is no argument named `a`
     };
 }
 
@@ -16,6 +15,7 @@ fn main() {
     format!(identity_pm!("{a}"));
     //~^ ERROR there is no argument named `a`
     format!(identity_mbe!("{a}"));
+    //~^ ERROR there is no argument named `a`
     format!(concat!("{a}"));
     //~^ ERROR there is no argument named `a`
 }
diff --git a/tests/ui/fmt/format-args-capture-first-literal-is-macro.stderr b/tests/ui/fmt/format-args-capture-first-literal-is-macro.stderr
index 4cf3afad7b8..e399361579f 100644
--- a/tests/ui/fmt/format-args-capture-first-literal-is-macro.stderr
+++ b/tests/ui/fmt/format-args-capture-first-literal-is-macro.stderr
@@ -1,5 +1,5 @@
 error: there is no argument named `a`
-  --> $DIR/format-args-capture-first-literal-is-macro.rs:16:26
+  --> $DIR/format-args-capture-first-literal-is-macro.rs:15:26
    |
 LL |     format!(identity_pm!("{a}"));
    |                          ^^^^^
@@ -8,10 +8,10 @@ LL |     format!(identity_pm!("{a}"));
    = note: to avoid ambiguity, `format_args!` cannot capture variables when the format string is expanded from a macro
 
 error: there is no argument named `a`
-  --> $DIR/format-args-capture-first-literal-is-macro.rs:8:9
+  --> $DIR/format-args-capture-first-literal-is-macro.rs:17:27
    |
-LL |         $tt
-   |         ^^^
+LL |     format!(identity_mbe!("{a}"));
+   |                           ^^^^^
    |
    = note: did you intend to capture a variable `a` from the surrounding scope?
    = note: to avoid ambiguity, `format_args!` cannot capture variables when the format string is expanded from a macro
diff --git a/tests/ui/intrinsics-always-extern.stderr b/tests/ui/intrinsics-always-extern.stderr
index 32468f99197..1f7bb5a3b0d 100644
--- a/tests/ui/intrinsics-always-extern.stderr
+++ b/tests/ui/intrinsics-always-extern.stderr
@@ -9,6 +9,8 @@ error[E0093]: unrecognized intrinsic function: `hello`
    |
 LL | extern "rust-intrinsic" fn hello() {
    |                            ^^^^^ unrecognized intrinsic
+   |
+   = help: if you're adding an intrinsic, be sure to update `check_intrinsic_type`
 
 error: intrinsic must be in `extern "rust-intrinsic" { ... }` block
   --> $DIR/intrinsics-always-extern.rs:8:43
diff --git a/tests/ui/issues/issue-23611-enum-swap-in-drop.rs b/tests/ui/issues/issue-23611-enum-swap-in-drop.rs
index 980a2c01f23..1afaff0f735 100644
--- a/tests/ui/issues/issue-23611-enum-swap-in-drop.rs
+++ b/tests/ui/issues/issue-23611-enum-swap-in-drop.rs
@@ -187,7 +187,7 @@ pub mod d {
     pub fn max_width() -> u32 {
         unsafe {
             (mem::size_of_val(&trails) * 8) as u32
-            //~^ WARN shared reference of mutable static is discouraged [static_mut_ref]
+            //~^ WARN shared reference to mutable static is discouraged [static_mut_refs]
         }
     }
 
diff --git a/tests/ui/issues/issue-23611-enum-swap-in-drop.stderr b/tests/ui/issues/issue-23611-enum-swap-in-drop.stderr
index 14a986a3332..bdf46abea8a 100644
--- a/tests/ui/issues/issue-23611-enum-swap-in-drop.stderr
+++ b/tests/ui/issues/issue-23611-enum-swap-in-drop.stderr
@@ -1,14 +1,14 @@
-warning: shared reference of mutable static is discouraged
+warning: creating a shared reference to mutable static is discouraged
   --> $DIR/issue-23611-enum-swap-in-drop.rs:189:31
    |
 LL |             (mem::size_of_val(&trails) * 8) as u32
-   |                               ^^^^^^^ shared reference of mutable static
+   |                               ^^^^^^^ shared reference to mutable static
    |
    = note: for more information, see issue #114447 <https://github.com/rust-lang/rust/issues/114447>
-   = note: reference of mutable static is a hard error from 2024 edition
-   = note: mutable statics can be written to by multiple threads: aliasing violations or data races will cause undefined behavior
-   = note: `#[warn(static_mut_ref)]` on by default
-help: shared references are dangerous since if there's any kind of mutation of that static while the reference lives, that's UB; use `addr_of!` instead to create a raw pointer
+   = note: this will be a hard error in the 2024 edition
+   = note: this shared reference has lifetime `'static`, but if the static ever gets mutated, or a mutable reference is created, then any further use of this shared reference is Undefined Behavior
+   = note: `#[warn(static_mut_refs)]` on by default
+help: use `addr_of!` instead to create a raw pointer
    |
 LL |             (mem::size_of_val(addr_of!(trails)) * 8) as u32
    |                               ~~~~~~~~~~~~~~~~
diff --git a/tests/ui/issues/issue-54410.rs b/tests/ui/issues/issue-54410.rs
index 51eea3ad9ac..208be6f221c 100644
--- a/tests/ui/issues/issue-54410.rs
+++ b/tests/ui/issues/issue-54410.rs
@@ -5,5 +5,5 @@ extern "C" {
 
 fn main() {
     println!("{:p}", unsafe { &symbol });
-    //~^ WARN: shared reference of mutable static is discouraged
+    //~^ WARN creating a shared reference to mutable static is discouraged [static_mut_refs]
 }
diff --git a/tests/ui/issues/issue-54410.stderr b/tests/ui/issues/issue-54410.stderr
index 941c1be3eab..7cc67ab72c3 100644
--- a/tests/ui/issues/issue-54410.stderr
+++ b/tests/ui/issues/issue-54410.stderr
@@ -6,17 +6,17 @@ LL |     pub static mut symbol: [i8];
    |
    = help: the trait `Sized` is not implemented for `[i8]`
 
-warning: shared reference of mutable static is discouraged
+warning: creating a shared reference to mutable static is discouraged
   --> $DIR/issue-54410.rs:7:31
    |
 LL |     println!("{:p}", unsafe { &symbol });
-   |                               ^^^^^^^ shared reference of mutable static
+   |                               ^^^^^^^ shared reference to mutable static
    |
    = note: for more information, see issue #114447 <https://github.com/rust-lang/rust/issues/114447>
-   = note: reference of mutable static is a hard error from 2024 edition
-   = note: mutable statics can be written to by multiple threads: aliasing violations or data races will cause undefined behavior
-   = note: `#[warn(static_mut_ref)]` on by default
-help: shared references are dangerous since if there's any kind of mutation of that static while the reference lives, that's UB; use `addr_of!` instead to create a raw pointer
+   = note: this will be a hard error in the 2024 edition
+   = note: this shared reference has lifetime `'static`, but if the static ever gets mutated, or a mutable reference is created, then any further use of this shared reference is Undefined Behavior
+   = note: `#[warn(static_mut_refs)]` on by default
+help: use `addr_of!` instead to create a raw pointer
    |
 LL |     println!("{:p}", unsafe { addr_of!(symbol) });
    |                               ~~~~~~~~~~~~~~~~
diff --git a/tests/ui/lazy-type-alias/constrained-params.rs b/tests/ui/lazy-type-alias/constrained-params.rs
new file mode 100644
index 00000000000..59693dd5461
--- /dev/null
+++ b/tests/ui/lazy-type-alias/constrained-params.rs
@@ -0,0 +1,27 @@
+//@ check-pass
+
+#![feature(lazy_type_alias)]
+#![allow(incomplete_features)]
+
+type Injective<T> = Local<T>;
+struct Local<T>(T);
+
+impl<T> Injective<T> {
+    fn take(_: T) {}
+}
+
+trait Trait {
+    type Out;
+    fn produce() -> Self::Out;
+}
+
+impl<T: Default> Trait for Injective<T> {
+    type Out = T;
+    fn produce() -> Self::Out { T::default() }
+}
+
+fn main() {
+    Injective::take(0);
+    let _: String = Injective::produce();
+    let _: bool = Local::produce();
+}
diff --git a/tests/ui/lazy-type-alias/inherent-impls-conflicting.rs b/tests/ui/lazy-type-alias/inherent-impls-conflicting.rs
new file mode 100644
index 00000000000..2adb04839ae
--- /dev/null
+++ b/tests/ui/lazy-type-alias/inherent-impls-conflicting.rs
@@ -0,0 +1,10 @@
+#![feature(lazy_type_alias)]
+#![allow(incomplete_features)]
+
+type Alias = Local;
+struct Local;
+
+impl Alias { fn method() {} } //~ ERROR duplicate definitions with name `method`
+impl Local { fn method() {} }
+
+fn main() {}
diff --git a/tests/ui/lazy-type-alias/inherent-impls-conflicting.stderr b/tests/ui/lazy-type-alias/inherent-impls-conflicting.stderr
new file mode 100644
index 00000000000..3f8dcef857f
--- /dev/null
+++ b/tests/ui/lazy-type-alias/inherent-impls-conflicting.stderr
@@ -0,0 +1,11 @@
+error[E0592]: duplicate definitions with name `method`
+  --> $DIR/inherent-impls-conflicting.rs:7:14
+   |
+LL | impl Alias { fn method() {} }
+   |              ^^^^^^^^^^^ duplicate definitions for `method`
+LL | impl Local { fn method() {} }
+   |              ----------- other definition for `method`
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0592`.
diff --git a/tests/ui/lazy-type-alias/inherent-impls-not-nominal.rs b/tests/ui/lazy-type-alias/inherent-impls-not-nominal.rs
new file mode 100644
index 00000000000..0ec23bb7fb7
--- /dev/null
+++ b/tests/ui/lazy-type-alias/inherent-impls-not-nominal.rs
@@ -0,0 +1,12 @@
+#![feature(lazy_type_alias)]
+#![allow(incomplete_features)]
+
+type Alias = <() as Trait>::Out;
+
+trait Trait { type Out; }
+impl Trait for () { type Out = Local; }
+struct Local;
+
+impl Alias {} //~ ERROR no nominal type found for inherent implementation
+
+fn main() {}
diff --git a/tests/ui/lazy-type-alias/inherent-impls-not-nominal.stderr b/tests/ui/lazy-type-alias/inherent-impls-not-nominal.stderr
new file mode 100644
index 00000000000..2936e70f5b4
--- /dev/null
+++ b/tests/ui/lazy-type-alias/inherent-impls-not-nominal.stderr
@@ -0,0 +1,11 @@
+error[E0118]: no nominal type found for inherent implementation
+  --> $DIR/inherent-impls-not-nominal.rs:10:1
+   |
+LL | impl Alias {}
+   | ^^^^^^^^^^ impl requires a nominal type
+   |
+   = note: either implement a trait on it or create a newtype to wrap it instead
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0118`.
diff --git a/tests/ui/lazy-type-alias/inherent-impls-overflow.classic.stderr b/tests/ui/lazy-type-alias/inherent-impls-overflow.classic.stderr
new file mode 100644
index 00000000000..1cace470627
--- /dev/null
+++ b/tests/ui/lazy-type-alias/inherent-impls-overflow.classic.stderr
@@ -0,0 +1,43 @@
+error[E0275]: overflow evaluating the requirement `Loop`
+  --> $DIR/inherent-impls-overflow.rs:7:13
+   |
+LL | type Loop = Loop;
+   |             ^^^^
+   |
+   = note: in case this is a recursive type alias, consider using a struct, enum, or union instead
+
+error[E0275]: overflow evaluating the requirement `Loop`
+  --> $DIR/inherent-impls-overflow.rs:9:1
+   |
+LL | impl Loop {}
+   | ^^^^^^^^^^^^
+   |
+   = note: in case this is a recursive type alias, consider using a struct, enum, or union instead
+
+error[E0275]: overflow evaluating the requirement `Poly0<((((((...,),),),),),)>`
+  --> $DIR/inherent-impls-overflow.rs:11:17
+   |
+LL | type Poly0<T> = Poly1<(T,)>;
+   |                 ^^^^^^^^^^^
+   |
+   = note: in case this is a recursive type alias, consider using a struct, enum, or union instead
+
+error[E0275]: overflow evaluating the requirement `Poly1<((((((...,),),),),),)>`
+  --> $DIR/inherent-impls-overflow.rs:14:17
+   |
+LL | type Poly1<T> = Poly0<(T,)>;
+   |                 ^^^^^^^^^^^
+   |
+   = note: in case this is a recursive type alias, consider using a struct, enum, or union instead
+
+error[E0275]: overflow evaluating the requirement `Poly1<((((((...,),),),),),)>`
+  --> $DIR/inherent-impls-overflow.rs:18:1
+   |
+LL | impl Poly0<()> {}
+   | ^^^^^^^^^^^^^^^^^
+   |
+   = note: in case this is a recursive type alias, consider using a struct, enum, or union instead
+
+error: aborting due to 5 previous errors
+
+For more information about this error, try `rustc --explain E0275`.
diff --git a/tests/ui/lazy-type-alias/inherent-impls-overflow.next.stderr b/tests/ui/lazy-type-alias/inherent-impls-overflow.next.stderr
new file mode 100644
index 00000000000..1a6259b5cf9
--- /dev/null
+++ b/tests/ui/lazy-type-alias/inherent-impls-overflow.next.stderr
@@ -0,0 +1,38 @@
+error[E0275]: overflow evaluating the requirement `Loop == _`
+  --> $DIR/inherent-impls-overflow.rs:9:6
+   |
+LL | impl Loop {}
+   |      ^^^^
+   |
+   = help: consider increasing the recursion limit by adding a `#![recursion_limit = "256"]` attribute to your crate (`inherent_impls_overflow`)
+
+error[E0392]: type parameter `T` is never used
+  --> $DIR/inherent-impls-overflow.rs:11:12
+   |
+LL | type Poly0<T> = Poly1<(T,)>;
+   |            ^ unused type parameter
+   |
+   = help: consider removing `T` or referring to it in the body of the type alias
+   = help: if you intended `T` to be a const parameter, use `const T: /* Type */` instead
+
+error[E0392]: type parameter `T` is never used
+  --> $DIR/inherent-impls-overflow.rs:14:12
+   |
+LL | type Poly1<T> = Poly0<(T,)>;
+   |            ^ unused type parameter
+   |
+   = help: consider removing `T` or referring to it in the body of the type alias
+   = help: if you intended `T` to be a const parameter, use `const T: /* Type */` instead
+
+error[E0275]: overflow evaluating the requirement `Poly0<()> == _`
+  --> $DIR/inherent-impls-overflow.rs:18:6
+   |
+LL | impl Poly0<()> {}
+   |      ^^^^^^^^^
+   |
+   = help: consider increasing the recursion limit by adding a `#![recursion_limit = "256"]` attribute to your crate (`inherent_impls_overflow`)
+
+error: aborting due to 4 previous errors
+
+Some errors have detailed explanations: E0275, E0392.
+For more information about an error, try `rustc --explain E0275`.
diff --git a/tests/ui/lazy-type-alias/inherent-impls-overflow.rs b/tests/ui/lazy-type-alias/inherent-impls-overflow.rs
new file mode 100644
index 00000000000..b260dedeb07
--- /dev/null
+++ b/tests/ui/lazy-type-alias/inherent-impls-overflow.rs
@@ -0,0 +1,20 @@
+//@ revisions: classic next
+//@[next] compile-flags: -Znext-solver
+
+#![feature(lazy_type_alias)]
+#![allow(incomplete_features)]
+
+type Loop = Loop; //[classic]~ ERROR overflow evaluating the requirement
+
+impl Loop {} //~ ERROR overflow evaluating the requirement
+
+type Poly0<T> = Poly1<(T,)>;
+//[classic]~^ ERROR overflow evaluating the requirement
+//[next]~^^ ERROR type parameter `T` is never used
+type Poly1<T> = Poly0<(T,)>;
+//[classic]~^ ERROR overflow evaluating the requirement
+//[next]~^^ ERROR type parameter `T` is never used
+
+impl Poly0<()> {} //~ ERROR overflow evaluating the requirement
+
+fn main() {}
diff --git a/tests/ui/lazy-type-alias/inherent-impls.rs b/tests/ui/lazy-type-alias/inherent-impls.rs
new file mode 100644
index 00000000000..835b70bf67a
--- /dev/null
+++ b/tests/ui/lazy-type-alias/inherent-impls.rs
@@ -0,0 +1,18 @@
+//@ check-pass
+
+#![feature(lazy_type_alias)]
+#![allow(incomplete_features)]
+
+type Alias = Local;
+struct Local;
+
+impl Alias {
+    fn method(self) {}
+}
+
+fn main() {
+    let _ = Local.method();
+    let _ = Local::method;
+    let _ = Alias {}.method();
+    let _ = Alias::method;
+}
diff --git a/tests/ui/lazy-type-alias/unconstrained-param-due-to-overflow.rs b/tests/ui/lazy-type-alias/unconstrained-param-due-to-overflow.rs
new file mode 100644
index 00000000000..eceefa719ec
--- /dev/null
+++ b/tests/ui/lazy-type-alias/unconstrained-param-due-to-overflow.rs
@@ -0,0 +1,8 @@
+#![feature(lazy_type_alias)]
+#![allow(incomplete_features)]
+
+impl<T> Loop<T> {} //~ ERROR the type parameter `T` is not constrained
+
+type Loop<T> = Loop<T>;
+
+fn main() {}
diff --git a/tests/ui/lazy-type-alias/unconstrained-param-due-to-overflow.stderr b/tests/ui/lazy-type-alias/unconstrained-param-due-to-overflow.stderr
new file mode 100644
index 00000000000..9af6f5dda0b
--- /dev/null
+++ b/tests/ui/lazy-type-alias/unconstrained-param-due-to-overflow.stderr
@@ -0,0 +1,9 @@
+error[E0207]: the type parameter `T` is not constrained by the impl trait, self type, or predicates
+  --> $DIR/unconstrained-param-due-to-overflow.rs:4:6
+   |
+LL | impl<T> Loop<T> {}
+   |      ^ unconstrained type parameter
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0207`.
diff --git a/tests/ui/lazy-type-alias/unconstrained-params.rs b/tests/ui/lazy-type-alias/unconstrained-params.rs
new file mode 100644
index 00000000000..d58938b3070
--- /dev/null
+++ b/tests/ui/lazy-type-alias/unconstrained-params.rs
@@ -0,0 +1,12 @@
+#![feature(lazy_type_alias)]
+#![allow(incomplete_features)]
+
+impl<T> NotInjective<T> {} //~ ERROR the type parameter `T` is not constrained
+
+type NotInjective<T: ?Sized> = Local<<T as Discard>::Out>;
+struct Local<T>(T);
+
+trait Discard { type Out; }
+impl<T: ?Sized> Discard for T { type Out = (); }
+
+fn main() {}
diff --git a/tests/ui/lazy-type-alias/unconstrained-params.stderr b/tests/ui/lazy-type-alias/unconstrained-params.stderr
new file mode 100644
index 00000000000..3c52a06c319
--- /dev/null
+++ b/tests/ui/lazy-type-alias/unconstrained-params.stderr
@@ -0,0 +1,9 @@
+error[E0207]: the type parameter `T` is not constrained by the impl trait, self type, or predicates
+  --> $DIR/unconstrained-params.rs:4:6
+   |
+LL | impl<T> NotInjective<T> {}
+   |      ^ unconstrained type parameter
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0207`.
diff --git a/tests/ui/lint/unused/lint-unused-imports.rs b/tests/ui/lint/unused/lint-unused-imports.rs
index 4fa6511c97e..88f2baa5da9 100644
--- a/tests/ui/lint/unused/lint-unused-imports.rs
+++ b/tests/ui/lint/unused/lint-unused-imports.rs
@@ -66,7 +66,6 @@ pub mod bar {
 
 fn g() {
     use self::g; //~ ERROR unused import: `self::g`
-    //~^ ERROR the item `g` is imported redundantly
     fn f() {
         self::g();
     }
@@ -76,7 +75,6 @@ fn g() {
 #[allow(unused_variables)]
 fn h() {
     use test2::foo; //~ ERROR unused import: `test2::foo`
-    //~^ ERROR the item `foo` is imported redundantly
     let foo = 0;
 }
 
diff --git a/tests/ui/lint/unused/lint-unused-imports.stderr b/tests/ui/lint/unused/lint-unused-imports.stderr
index 0574ca4569f..07684a84a64 100644
--- a/tests/ui/lint/unused/lint-unused-imports.stderr
+++ b/tests/ui/lint/unused/lint-unused-imports.stderr
@@ -34,36 +34,14 @@ error: unused import: `foo::Square`
 LL |         use foo::Square;
    |             ^^^^^^^^^^^
 
-error: the item `g` is imported redundantly
-  --> $DIR/lint-unused-imports.rs:68:9
-   |
-LL | / fn g() {
-LL | |     use self::g;
-   | |         ^^^^^^^
-LL | |
-LL | |     fn f() {
-LL | |         self::g();
-LL | |     }
-LL | | }
-   | |_- the item `g` is already defined here
-
 error: unused import: `self::g`
   --> $DIR/lint-unused-imports.rs:68:9
    |
 LL |     use self::g;
    |         ^^^^^^^
 
-error: the item `foo` is imported redundantly
-  --> $DIR/lint-unused-imports.rs:78:9
-   |
-LL | use test2::{foo, bar};
-   |             --- the item `foo` is already imported here
-...
-LL |     use test2::foo;
-   |         ^^^^^^^^^^
-
 error: unused import: `test2::foo`
-  --> $DIR/lint-unused-imports.rs:78:9
+  --> $DIR/lint-unused-imports.rs:77:9
    |
 LL |     use test2::foo;
    |         ^^^^^^^^^^
@@ -74,5 +52,5 @@ error: unused import: `test::B2`
 LL | use test::B2;
    |     ^^^^^^^^
 
-error: aborting due to 10 previous errors
+error: aborting due to 8 previous errors
 
diff --git a/tests/ui/lint/use-redundant/use-redundant-prelude-rust-2015.rs b/tests/ui/lint/use-redundant/use-redundant-prelude-rust-2015.rs
new file mode 100644
index 00000000000..ae5118b2729
--- /dev/null
+++ b/tests/ui/lint/use-redundant/use-redundant-prelude-rust-2015.rs
@@ -0,0 +1,19 @@
+//@ check-pass
+#![warn(unused_imports)]
+
+
+use std::option::Option::Some;//~ WARNING the item `Some` is imported redundantly
+use std::option::Option::None; //~ WARNING the item `None` is imported redundantly
+
+use std::result::Result::Ok;//~ WARNING the item `Ok` is imported redundantly
+use std::result::Result::Err;//~ WARNING the item `Err` is imported redundantly
+use std::convert::{TryFrom, TryInto};
+
+fn main() {
+    let _a: Option<i32> = Some(1);
+    let _b: Option<i32>  = None;
+    let _c: Result<i32, String> = Ok(1);
+    let _d: Result<i32, &str> = Err("error");
+    let _e: Result<i32, _> = 8u8.try_into();
+    let _f: Result<i32, _> = i32::try_from(8u8);
+}
diff --git a/tests/ui/lint/use-redundant/use-redundant-prelude-rust-2015.stderr b/tests/ui/lint/use-redundant/use-redundant-prelude-rust-2015.stderr
new file mode 100644
index 00000000000..1b09df911eb
--- /dev/null
+++ b/tests/ui/lint/use-redundant/use-redundant-prelude-rust-2015.stderr
@@ -0,0 +1,44 @@
+warning: the item `Some` is imported redundantly
+  --> $DIR/use-redundant-prelude-rust-2015.rs:5:5
+   |
+LL | use std::option::Option::Some;
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
+  --> $SRC_DIR/std/src/prelude/mod.rs:LL:COL
+   |
+   = note: the item `Some` is already defined here
+   |
+note: the lint level is defined here
+  --> $DIR/use-redundant-prelude-rust-2015.rs:2:9
+   |
+LL | #![warn(unused_imports)]
+   |         ^^^^^^^^^^^^^^
+
+warning: the item `None` is imported redundantly
+  --> $DIR/use-redundant-prelude-rust-2015.rs:6:5
+   |
+LL | use std::option::Option::None;
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
+  --> $SRC_DIR/std/src/prelude/mod.rs:LL:COL
+   |
+   = note: the item `None` is already defined here
+
+warning: the item `Ok` is imported redundantly
+  --> $DIR/use-redundant-prelude-rust-2015.rs:8:5
+   |
+LL | use std::result::Result::Ok;
+   |     ^^^^^^^^^^^^^^^^^^^^^^^
+  --> $SRC_DIR/std/src/prelude/mod.rs:LL:COL
+   |
+   = note: the item `Ok` is already defined here
+
+warning: the item `Err` is imported redundantly
+  --> $DIR/use-redundant-prelude-rust-2015.rs:9:5
+   |
+LL | use std::result::Result::Err;
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^
+  --> $SRC_DIR/std/src/prelude/mod.rs:LL:COL
+   |
+   = note: the item `Err` is already defined here
+
+warning: 4 warnings emitted
+
diff --git a/tests/ui/lint/use-redundant/use-redundant-prelude-rust-2021.rs b/tests/ui/lint/use-redundant/use-redundant-prelude-rust-2021.rs
new file mode 100644
index 00000000000..cb4dcb6c0bd
--- /dev/null
+++ b/tests/ui/lint/use-redundant/use-redundant-prelude-rust-2021.rs
@@ -0,0 +1,11 @@
+//@ check-pass
+//@ edition:2021
+#![warn(unused_imports)]
+
+use std::convert::TryFrom;//~ WARNING the item `TryFrom` is imported redundantly
+use std::convert::TryInto;//~ WARNING the item `TryInto` is imported redundantly
+
+fn main() {
+    let _e: Result<i32, _> = 8u8.try_into();
+    let _f: Result<i32, _> = i32::try_from(8u8);
+}
diff --git a/tests/ui/lint/use-redundant/use-redundant-prelude-rust-2021.stderr b/tests/ui/lint/use-redundant/use-redundant-prelude-rust-2021.stderr
new file mode 100644
index 00000000000..542356dc996
--- /dev/null
+++ b/tests/ui/lint/use-redundant/use-redundant-prelude-rust-2021.stderr
@@ -0,0 +1,26 @@
+warning: the item `TryFrom` is imported redundantly
+  --> $DIR/use-redundant-prelude-rust-2021.rs:5:5
+   |
+LL | use std::convert::TryFrom;
+   |     ^^^^^^^^^^^^^^^^^^^^^
+  --> $SRC_DIR/std/src/prelude/mod.rs:LL:COL
+   |
+   = note: the item `TryFrom` is already defined here
+   |
+note: the lint level is defined here
+  --> $DIR/use-redundant-prelude-rust-2021.rs:3:9
+   |
+LL | #![warn(unused_imports)]
+   |         ^^^^^^^^^^^^^^
+
+warning: the item `TryInto` is imported redundantly
+  --> $DIR/use-redundant-prelude-rust-2021.rs:6:5
+   |
+LL | use std::convert::TryInto;
+   |     ^^^^^^^^^^^^^^^^^^^^^
+  --> $SRC_DIR/std/src/prelude/mod.rs:LL:COL
+   |
+   = note: the item `TryInto` is already defined here
+
+warning: 2 warnings emitted
+
diff --git a/tests/ui/lint/wide_pointer_comparisons.rs b/tests/ui/lint/wide_pointer_comparisons.rs
index 37807776d2f..31369001075 100644
--- a/tests/ui/lint/wide_pointer_comparisons.rs
+++ b/tests/ui/lint/wide_pointer_comparisons.rs
@@ -110,10 +110,12 @@ fn main() {
     {
         macro_rules! cmp {
             ($a:tt, $b:tt) => { $a == $b }
-            //~^ WARN ambiguous wide pointer comparison
         }
 
+        // FIXME: This lint uses some custom span combination logic.
+        // Rewrite it to adapt to the new metavariable span rules.
         cmp!(a, b);
+        //~^ WARN ambiguous wide pointer comparison
     }
 
     {
diff --git a/tests/ui/lint/wide_pointer_comparisons.stderr b/tests/ui/lint/wide_pointer_comparisons.stderr
index 349ff467d0f..6ef117c63c5 100644
--- a/tests/ui/lint/wide_pointer_comparisons.stderr
+++ b/tests/ui/lint/wide_pointer_comparisons.stderr
@@ -421,18 +421,18 @@ LL |         std::ptr::eq(*a, *b)
    |         ~~~~~~~~~~~~~  ~   +
 
 warning: ambiguous wide pointer comparison, the comparison includes metadata which may not be expected
-  --> $DIR/wide_pointer_comparisons.rs:112:33
+  --> $DIR/wide_pointer_comparisons.rs:117:14
    |
-LL |             ($a:tt, $b:tt) => { $a == $b }
-   |                                 ^^^^^^^^
+LL |         cmp!(a, b);
+   |              ^^^^
    |
 help: use `std::ptr::addr_eq` or untyped pointers to only compare their addresses
    |
-LL |             ($a:tt, $b:tt) => { std::ptr::addr_eq($a, $b) }
-   |                                 ++++++++++++++++++  ~   +
+LL |         cmp!(std::ptr::addr_eq(a, b));
+   |              ++++++++++++++++++ ~  +
 
 warning: ambiguous wide pointer comparison, the comparison includes metadata which may not be expected
-  --> $DIR/wide_pointer_comparisons.rs:121:39
+  --> $DIR/wide_pointer_comparisons.rs:123:39
    |
 LL |             ($a:ident, $b:ident) => { $a == $b }
    |                                       ^^^^^^^^
@@ -447,7 +447,7 @@ LL |             ($a:ident, $b:ident) => { std::ptr::addr_eq($a, $b) }
    |                                       ++++++++++++++++++  ~   +
 
 warning: ambiguous wide pointer comparison, the comparison includes metadata which may not be expected
-  --> $DIR/wide_pointer_comparisons.rs:131:37
+  --> $DIR/wide_pointer_comparisons.rs:133:37
    |
 LL |             ($a:expr, $b:expr) => { $a == $b }
    |                                     ^^
diff --git a/tests/ui/macros/invalid-fragment-specifier.rs b/tests/ui/macros/invalid-fragment-specifier.rs
new file mode 100644
index 00000000000..1daf0a95434
--- /dev/null
+++ b/tests/ui/macros/invalid-fragment-specifier.rs
@@ -0,0 +1,10 @@
+macro_rules! test {
+    ($wrong:id) => {};
+} //~^ ERROR: invalid fragment specifier `id`
+
+// guard against breaking raw identifier diagnostic
+macro_rules! test_raw_identifer {
+    ($wrong:r#if) => {};
+} //~^ ERROR: invalid fragment specifier `r#if`
+
+fn main() {}
diff --git a/tests/ui/macros/invalid-fragment-specifier.stderr b/tests/ui/macros/invalid-fragment-specifier.stderr
new file mode 100644
index 00000000000..7516dbc3a08
--- /dev/null
+++ b/tests/ui/macros/invalid-fragment-specifier.stderr
@@ -0,0 +1,18 @@
+error: invalid fragment specifier `id`
+  --> $DIR/invalid-fragment-specifier.rs:2:6
+   |
+LL |     ($wrong:id) => {};
+   |      ^^^^^^^^^
+   |
+   = help: valid fragment specifiers are `ident`, `block`, `stmt`, `expr`, `pat`, `ty`, `lifetime`, `literal`, `path`, `meta`, `tt`, `item` and `vis`
+
+error: invalid fragment specifier `r#if`
+  --> $DIR/invalid-fragment-specifier.rs:7:6
+   |
+LL |     ($wrong:r#if) => {};
+   |      ^^^^^^^^^^^
+   |
+   = help: valid fragment specifiers are `ident`, `block`, `stmt`, `expr`, `pat`, `ty`, `lifetime`, `literal`, `path`, `meta`, `tt`, `item` and `vis`
+
+error: aborting due to 2 previous errors
+
diff --git a/tests/ui/macros/issue-118786.rs b/tests/ui/macros/issue-118786.rs
index cc6c751813b..97454c9de07 100644
--- a/tests/ui/macros/issue-118786.rs
+++ b/tests/ui/macros/issue-118786.rs
@@ -5,8 +5,7 @@
 macro_rules! make_macro {
     ($macro_name:tt) => {
         macro_rules! $macro_name {
-        //~^ ERROR macros that expand to items must be delimited with braces or followed by a semicolon
-        //~| ERROR macro expansion ignores token `{` and any following
+        //~^ ERROR macro expansion ignores token `{` and any following
         //~| ERROR cannot find macro `macro_rules` in this scope
             () => {}
         }
@@ -14,3 +13,4 @@ macro_rules! make_macro {
 }
 
 make_macro!((meow));
+//~^ ERROR macros that expand to items must be delimited with braces or followed by a semicolon
diff --git a/tests/ui/macros/issue-118786.stderr b/tests/ui/macros/issue-118786.stderr
index 1a8ac9340da..03e65c94ba7 100644
--- a/tests/ui/macros/issue-118786.stderr
+++ b/tests/ui/macros/issue-118786.stderr
@@ -1,13 +1,13 @@
 error: macros that expand to items must be delimited with braces or followed by a semicolon
-  --> $DIR/issue-118786.rs:7:22
+  --> $DIR/issue-118786.rs:15:13
    |
-LL |         macro_rules! $macro_name {
-   |                      ^^^^^^^^^^^
+LL | make_macro!((meow));
+   |             ^^^^^^
    |
 help: change the delimiters to curly braces
    |
-LL |         macro_rules! {$macro_name} {
-   |                      +           +
+LL | make_macro!({meow});
+   |             ~    ~
 help: add a semicolon
    |
 LL |         macro_rules! $macro_name; {
diff --git a/tests/ui/macros/macro-invalid-fragment-spec.rs b/tests/ui/macros/macro-invalid-fragment-spec.rs
deleted file mode 100644
index dc4d75096af..00000000000
--- a/tests/ui/macros/macro-invalid-fragment-spec.rs
+++ /dev/null
@@ -1,8 +0,0 @@
-macro_rules! foo(
-    ($x:foo) => ()
-    //~^ ERROR invalid fragment specifier
-);
-
-fn main() {
-    foo!(foo);
-}
diff --git a/tests/ui/macros/macro-invalid-fragment-spec.stderr b/tests/ui/macros/macro-invalid-fragment-spec.stderr
deleted file mode 100644
index 919111ede51..00000000000
--- a/tests/ui/macros/macro-invalid-fragment-spec.stderr
+++ /dev/null
@@ -1,10 +0,0 @@
-error: invalid fragment specifier `foo`
-  --> $DIR/macro-invalid-fragment-spec.rs:2:6
-   |
-LL |     ($x:foo) => ()
-   |      ^^^^^^
-   |
-   = help: valid fragment specifiers are `ident`, `block`, `stmt`, `expr`, `pat`, `ty`, `lifetime`, `literal`, `path`, `meta`, `tt`, `item` and `vis`
-
-error: aborting due to 1 previous error
-
diff --git a/tests/ui/methods/method-on-ambiguous-numeric-type.stderr b/tests/ui/methods/method-on-ambiguous-numeric-type.stderr
index 060595e1d40..12427040272 100644
--- a/tests/ui/methods/method-on-ambiguous-numeric-type.stderr
+++ b/tests/ui/methods/method-on-ambiguous-numeric-type.stderr
@@ -47,8 +47,8 @@ LL |     local_bar_tt.pow(2);
    |
 help: you must specify a type for this binding, like `i32`
    |
-LL |     ($tt:tt) => { let $tt: i32 = 42; }
-   |                          +++++
+LL |     local_mac_tt!(local_bar_tt: i32);
+   |                               +++++
 
 error[E0689]: can't call method `pow` on ambiguous numeric type `{integer}`
   --> $DIR/method-on-ambiguous-numeric-type.rs:37:9
diff --git a/tests/ui/nll/borrowck-thread-local-static-mut-borrow-outlives-fn.rs b/tests/ui/nll/borrowck-thread-local-static-mut-borrow-outlives-fn.rs
index fd49b232265..be882085c5c 100644
--- a/tests/ui/nll/borrowck-thread-local-static-mut-borrow-outlives-fn.rs
+++ b/tests/ui/nll/borrowck-thread-local-static-mut-borrow-outlives-fn.rs
@@ -15,7 +15,7 @@ struct S1 {
 impl S1 {
     fn new(_x: u64) -> S1 {
         S1 { a: unsafe { &mut X1 } }
-        //~^ WARN mutable reference of mutable static is discouraged [static_mut_ref]
+        //~^ WARN mutable reference to mutable static is discouraged [static_mut_refs]
     }
 }
 
diff --git a/tests/ui/nll/borrowck-thread-local-static-mut-borrow-outlives-fn.stderr b/tests/ui/nll/borrowck-thread-local-static-mut-borrow-outlives-fn.stderr
index 17217cd5859..82065cc06ea 100644
--- a/tests/ui/nll/borrowck-thread-local-static-mut-borrow-outlives-fn.stderr
+++ b/tests/ui/nll/borrowck-thread-local-static-mut-borrow-outlives-fn.stderr
@@ -1,14 +1,14 @@
-warning: mutable reference of mutable static is discouraged
+warning: creating a mutable reference to mutable static is discouraged
   --> $DIR/borrowck-thread-local-static-mut-borrow-outlives-fn.rs:17:26
    |
 LL |         S1 { a: unsafe { &mut X1 } }
-   |                          ^^^^^^^ mutable reference of mutable static
+   |                          ^^^^^^^ mutable reference to mutable static
    |
    = note: for more information, see issue #114447 <https://github.com/rust-lang/rust/issues/114447>
-   = note: reference of mutable static is a hard error from 2024 edition
-   = note: mutable statics can be written to by multiple threads: aliasing violations or data races will cause undefined behavior
-   = note: `#[warn(static_mut_ref)]` on by default
-help: mutable references are dangerous since if there's any other pointer or reference used for that static while the reference lives, that's UB; use `addr_of_mut!` instead to create a raw pointer
+   = note: this will be a hard error in the 2024 edition
+   = note: this mutable reference has lifetime `'static`, but if the static gets accessed (read or written) by any other means, or any other reference is created, then any further use of this mutable reference is Undefined Behavior
+   = note: `#[warn(static_mut_refs)]` on by default
+help: use `addr_of_mut!` instead to create a raw pointer
    |
 LL |         S1 { a: unsafe { addr_of_mut!(X1) } }
    |                          ~~~~~~~~~~~~~~~~
diff --git a/tests/ui/parser/issues/issue-44406.stderr b/tests/ui/parser/issues/issue-44406.stderr
index d005f116e12..78cde9b6dca 100644
--- a/tests/ui/parser/issues/issue-44406.stderr
+++ b/tests/ui/parser/issues/issue-44406.stderr
@@ -15,7 +15,7 @@ LL |         bar { baz: $rest }
 help: if `bar` is a function, use the arguments directly
    |
 LL -         bar(baz: $rest)
-LL +         bar(: $rest)
+LL +         bar($rest)
    |
 
 error: aborting due to 1 previous error
diff --git a/tests/ui/parser/issues/issue-68091-unicode-ident-after-if.stderr b/tests/ui/parser/issues/issue-68091-unicode-ident-after-if.stderr
index 8e125864b8b..a68fae1a36e 100644
--- a/tests/ui/parser/issues/issue-68091-unicode-ident-after-if.stderr
+++ b/tests/ui/parser/issues/issue-68091-unicode-ident-after-if.stderr
@@ -5,6 +5,11 @@ LL |         $($c)ö* {}
    |             ^   - if this block is the condition of the `if` expression, then it must be followed by another block
    |             |
    |             expected condition here
+...
+LL |     x!(if);
+   |     ------ in this macro invocation
+   |
+   = note: this error originates in the macro `x` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/parser/issues/issue-68092-unicode-ident-after-incomplete-expr.rs b/tests/ui/parser/issues/issue-68092-unicode-ident-after-incomplete-expr.rs
index 1a90b4724d4..d489df85c44 100644
--- a/tests/ui/parser/issues/issue-68092-unicode-ident-after-incomplete-expr.rs
+++ b/tests/ui/parser/issues/issue-68092-unicode-ident-after-incomplete-expr.rs
@@ -1,9 +1,9 @@
 macro_rules! x {
     ($($c:tt)*) => {
-        $($c)ö* //~ ERROR macro expansion ends with an incomplete expression: expected expression
+        $($c)ö*
     };
 }
 
 fn main() {
-    x!(!);
+    x!(!); //~ ERROR macro expansion ends with an incomplete expression: expected expression
 }
diff --git a/tests/ui/parser/issues/issue-68092-unicode-ident-after-incomplete-expr.stderr b/tests/ui/parser/issues/issue-68092-unicode-ident-after-incomplete-expr.stderr
index 15aa62e0810..3a4b0cbf2a5 100644
--- a/tests/ui/parser/issues/issue-68092-unicode-ident-after-incomplete-expr.stderr
+++ b/tests/ui/parser/issues/issue-68092-unicode-ident-after-incomplete-expr.stderr
@@ -1,8 +1,8 @@
 error: macro expansion ends with an incomplete expression: expected expression
-  --> $DIR/issue-68092-unicode-ident-after-incomplete-expr.rs:3:13
+  --> $DIR/issue-68092-unicode-ident-after-incomplete-expr.rs:8:9
    |
-LL |         $($c)ö*
-   |             ^ expected expression
+LL |     x!(!);
+   |         ^ expected expression
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/proc-macro/capture-macro-rules-invoke.stdout b/tests/ui/proc-macro/capture-macro-rules-invoke.stdout
index bbab08bca49..71e34119ba7 100644
--- a/tests/ui/proc-macro/capture-macro-rules-invoke.stdout
+++ b/tests/ui/proc-macro/capture-macro-rules-invoke.stdout
@@ -271,7 +271,7 @@ PRINT-BANG INPUT (DEBUG): TokenStream [
                 span: $DIR/capture-macro-rules-invoke.rs:47:19: 47:20 (#0),
             },
         ],
-        span: $DIR/capture-macro-rules-invoke.rs:15:60: 15:63 (#0),
+        span: $DIR/capture-macro-rules-invoke.rs:47:13: 47:22 (#0),
     },
     Punct {
         ch: ',',
diff --git a/tests/ui/rust-2018/edition-lint-infer-outlives-macro.fixed b/tests/ui/rust-2018/edition-lint-infer-outlives-macro.fixed
index 38d8a36bcdf..435857224ac 100644
--- a/tests/ui/rust-2018/edition-lint-infer-outlives-macro.fixed
+++ b/tests/ui/rust-2018/edition-lint-infer-outlives-macro.fixed
@@ -111,10 +111,13 @@ mod everything_outside_with_tt_inner {
 mod everything_outside_with_tt_outer {
     macro_rules! m {
         ($b:lifetime $colon:tt $a:tt) => {
-            struct Foo<$a, $b >(&$a &$b ());
+            // FIXME: replacement span is corrupted due to a collision in metavar span table.
+            // struct Foo<$a, $b $colon $a>(&$a &$b ());
+            // ^ ERROR: outlives requirements can be inferred
+            struct Bar<$a, $b>(&$a &$b ()) ;
+            //~^ ERROR: outlives requirements can be inferred
+            struct Baz<$a, $b>(&$a &$b ()) where (): Sized, ;
             //~^ ERROR: outlives requirements can be inferred
-            struct Bar<$a, $b>(&$a &$b ()) where $b $colon $a;
-            struct Baz<$a, $b>(&$a &$b ()) where (): Sized, $b $colon $a;
         }
     }
     m!('b: 'a);
@@ -123,9 +126,10 @@ mod everything_outside_with_tt_outer {
 mod everything_outside_with_tt_both {
     macro_rules! m {
         ($b:tt $colon:tt $a:tt) => {
-            struct Foo<$a, $b >(&$a &$b ());
-            //~^ ERROR: outlives requirements can be inferred
-            struct Bar<$a, $b>(&$a &$b ()) where ;
+            // FIXME: replacement span is corrupted due to a collision in metavar span table.
+            // struct Foo<$a, $b $colon $a>(&$a &$b ());
+            // ^ ERROR: outlives requirements can be inferred
+            struct Bar<$a, $b>(&$a &$b ()) ;
             //~^ ERROR: outlives requirements can be inferred
             struct Baz<$a, $b>(&$a &$b ()) where (): Sized, ;
             //~^ ERROR: outlives requirements can be inferred
diff --git a/tests/ui/rust-2018/edition-lint-infer-outlives-macro.rs b/tests/ui/rust-2018/edition-lint-infer-outlives-macro.rs
index 60eedf7b069..6c879231a16 100644
--- a/tests/ui/rust-2018/edition-lint-infer-outlives-macro.rs
+++ b/tests/ui/rust-2018/edition-lint-infer-outlives-macro.rs
@@ -111,10 +111,13 @@ mod everything_outside_with_tt_inner {
 mod everything_outside_with_tt_outer {
     macro_rules! m {
         ($b:lifetime $colon:tt $a:tt) => {
-            struct Foo<$a, $b $colon $a>(&$a &$b ());
-            //~^ ERROR: outlives requirements can be inferred
+            // FIXME: replacement span is corrupted due to a collision in metavar span table.
+            // struct Foo<$a, $b $colon $a>(&$a &$b ());
+            // ^ ERROR: outlives requirements can be inferred
             struct Bar<$a, $b>(&$a &$b ()) where $b $colon $a;
+            //~^ ERROR: outlives requirements can be inferred
             struct Baz<$a, $b>(&$a &$b ()) where (): Sized, $b $colon $a;
+            //~^ ERROR: outlives requirements can be inferred
         }
     }
     m!('b: 'a);
@@ -123,8 +126,9 @@ mod everything_outside_with_tt_outer {
 mod everything_outside_with_tt_both {
     macro_rules! m {
         ($b:tt $colon:tt $a:tt) => {
-            struct Foo<$a, $b $colon $a>(&$a &$b ());
-            //~^ ERROR: outlives requirements can be inferred
+            // FIXME: replacement span is corrupted due to a collision in metavar span table.
+            // struct Foo<$a, $b $colon $a>(&$a &$b ());
+            // ^ ERROR: outlives requirements can be inferred
             struct Bar<$a, $b>(&$a &$b ()) where $b $colon $a;
             //~^ ERROR: outlives requirements can be inferred
             struct Baz<$a, $b>(&$a &$b ()) where (): Sized, $b $colon $a;
diff --git a/tests/ui/rust-2018/edition-lint-infer-outlives-macro.stderr b/tests/ui/rust-2018/edition-lint-infer-outlives-macro.stderr
index 734ae687978..d684911be39 100644
--- a/tests/ui/rust-2018/edition-lint-infer-outlives-macro.stderr
+++ b/tests/ui/rust-2018/edition-lint-infer-outlives-macro.stderr
@@ -83,25 +83,40 @@ LL |     m!('b: 'a);
    = note: this error originates in the macro `m` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error: outlives requirements can be inferred
-  --> $DIR/edition-lint-infer-outlives-macro.rs:114:31
+  --> $DIR/edition-lint-infer-outlives-macro.rs:117:44
    |
-LL |             struct Foo<$a, $b $colon $a>(&$a &$b ());
-   |                               ^^^^^^^^^ help: remove this bound
+LL |             struct Bar<$a, $b>(&$a &$b ()) where $b $colon $a;
+   |                                            ^^^^^^^^^^^^^^^^^^ help: remove this bound
+...
+LL |     m!('b: 'a);
+   |     ---------- in this macro invocation
+   |
+   = note: this error originates in the macro `m` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error: outlives requirements can be inferred
-  --> $DIR/edition-lint-infer-outlives-macro.rs:126:31
+  --> $DIR/edition-lint-infer-outlives-macro.rs:119:61
+   |
+LL |             struct Baz<$a, $b>(&$a &$b ()) where (): Sized, $b $colon $a;
+   |                                                             ^^^^^^^^^^^^ help: remove this bound
+...
+LL |     m!('b: 'a);
+   |     ---------- in this macro invocation
    |
-LL |             struct Foo<$a, $b $colon $a>(&$a &$b ());
-   |                               ^^^^^^^^^ help: remove this bound
+   = note: this error originates in the macro `m` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error: outlives requirements can be inferred
-  --> $DIR/edition-lint-infer-outlives-macro.rs:128:50
+  --> $DIR/edition-lint-infer-outlives-macro.rs:132:44
    |
 LL |             struct Bar<$a, $b>(&$a &$b ()) where $b $colon $a;
-   |                                                  ^^^^^^^^^^^^ help: remove this bound
+   |                                            ^^^^^^^^^^^^^^^^^^ help: remove this bound
+...
+LL |     m!('b: 'a);
+   |     ---------- in this macro invocation
+   |
+   = note: this error originates in the macro `m` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error: outlives requirements can be inferred
-  --> $DIR/edition-lint-infer-outlives-macro.rs:130:61
+  --> $DIR/edition-lint-infer-outlives-macro.rs:134:61
    |
 LL |             struct Baz<$a, $b>(&$a &$b ()) where (): Sized, $b $colon $a;
    |                                                             ^^^^^^^^^^^^ help: remove this bound
diff --git a/tests/ui/rust-2018/remove-extern-crate.fixed b/tests/ui/rust-2018/remove-extern-crate.fixed
index f025ccfeaeb..19b1dc6fb01 100644
--- a/tests/ui/rust-2018/remove-extern-crate.fixed
+++ b/tests/ui/rust-2018/remove-extern-crate.fixed
@@ -6,6 +6,7 @@
 
 #![warn(rust_2018_idioms)]
 #![allow(dropping_copy_types)]
+#![allow(unused_imports)]
 
  //~ WARNING unused extern crate
 // Shouldn't suggest changing to `use`, as `another_name`
diff --git a/tests/ui/rust-2018/remove-extern-crate.rs b/tests/ui/rust-2018/remove-extern-crate.rs
index 0312964d5f6..88ef858da14 100644
--- a/tests/ui/rust-2018/remove-extern-crate.rs
+++ b/tests/ui/rust-2018/remove-extern-crate.rs
@@ -6,6 +6,7 @@
 
 #![warn(rust_2018_idioms)]
 #![allow(dropping_copy_types)]
+#![allow(unused_imports)]
 
 extern crate core; //~ WARNING unused extern crate
 // Shouldn't suggest changing to `use`, as `another_name`
diff --git a/tests/ui/rust-2018/remove-extern-crate.stderr b/tests/ui/rust-2018/remove-extern-crate.stderr
index f752cac8ed6..020db9975c0 100644
--- a/tests/ui/rust-2018/remove-extern-crate.stderr
+++ b/tests/ui/rust-2018/remove-extern-crate.stderr
@@ -1,5 +1,5 @@
 warning: unused extern crate
-  --> $DIR/remove-extern-crate.rs:10:1
+  --> $DIR/remove-extern-crate.rs:11:1
    |
 LL | extern crate core;
    | ^^^^^^^^^^^^^^^^^^ help: remove it
@@ -12,7 +12,7 @@ LL | #![warn(rust_2018_idioms)]
    = note: `#[warn(unused_extern_crates)]` implied by `#[warn(rust_2018_idioms)]`
 
 warning: `extern crate` is not idiomatic in the new edition
-  --> $DIR/remove-extern-crate.rs:34:5
+  --> $DIR/remove-extern-crate.rs:35:5
    |
 LL |     extern crate core;
    |     ^^^^^^^^^^^^^^^^^^
@@ -23,7 +23,7 @@ LL |     use core;
    |     ~~~
 
 warning: `extern crate` is not idiomatic in the new edition
-  --> $DIR/remove-extern-crate.rs:44:5
+  --> $DIR/remove-extern-crate.rs:45:5
    |
 LL |     pub extern crate core;
    |     ^^^^^^^^^^^^^^^^^^^^^^
diff --git a/tests/ui/span/macro-span-replacement.rs b/tests/ui/span/macro-span-replacement.rs
index e6fcfa4c709..16f4018cf3e 100644
--- a/tests/ui/span/macro-span-replacement.rs
+++ b/tests/ui/span/macro-span-replacement.rs
@@ -4,10 +4,10 @@
 
 macro_rules! m {
     ($a:tt $b:tt) => {
-        $b $a; //~ WARN struct `S` is never constructed
+        $b $a;
     }
 }
 
 fn main() {
-    m!(S struct);
+    m!(S struct); //~ WARN struct `S` is never constructed
 }
diff --git a/tests/ui/span/macro-span-replacement.stderr b/tests/ui/span/macro-span-replacement.stderr
index 5dd56342889..6248db112f8 100644
--- a/tests/ui/span/macro-span-replacement.stderr
+++ b/tests/ui/span/macro-span-replacement.stderr
@@ -1,11 +1,8 @@
 warning: struct `S` is never constructed
-  --> $DIR/macro-span-replacement.rs:7:12
+  --> $DIR/macro-span-replacement.rs:12:8
    |
-LL |         $b $a;
-   |            ^^
-...
 LL |     m!(S struct);
-   |     ------------ in this macro invocation
+   |        ^
    |
 note: the lint level is defined here
   --> $DIR/macro-span-replacement.rs:3:9
diff --git a/tests/ui/static/reference-of-mut-static-safe.e2021.stderr b/tests/ui/static/reference-of-mut-static-safe.e2021.stderr
deleted file mode 100644
index 16f47ace3a9..00000000000
--- a/tests/ui/static/reference-of-mut-static-safe.e2021.stderr
+++ /dev/null
@@ -1,26 +0,0 @@
-warning: shared reference of mutable static is discouraged
-  --> $DIR/reference-of-mut-static-safe.rs:9:14
-   |
-LL |     let _x = &X;
-   |              ^^ shared reference of mutable static
-   |
-   = note: for more information, see issue #114447 <https://github.com/rust-lang/rust/issues/114447>
-   = note: reference of mutable static is a hard error from 2024 edition
-   = note: mutable statics can be written to by multiple threads: aliasing violations or data races will cause undefined behavior
-   = note: `#[warn(static_mut_ref)]` on by default
-help: shared references are dangerous since if there's any kind of mutation of that static while the reference lives, that's UB; use `addr_of!` instead to create a raw pointer
-   |
-LL |     let _x = addr_of!(X);
-   |              ~~~~~~~~~~~
-
-error[E0133]: use of mutable static is unsafe and requires unsafe function or block
-  --> $DIR/reference-of-mut-static-safe.rs:9:15
-   |
-LL |     let _x = &X;
-   |               ^ use of mutable static
-   |
-   = note: mutable statics can be mutated by multiple threads: aliasing violations or data races will cause undefined behavior
-
-error: aborting due to 1 previous error; 1 warning emitted
-
-For more information about this error, try `rustc --explain E0133`.
diff --git a/tests/ui/static/reference-of-mut-static-safe.e2024.stderr b/tests/ui/static/reference-of-mut-static-safe.e2024.stderr
deleted file mode 100644
index 53f81179de5..00000000000
--- a/tests/ui/static/reference-of-mut-static-safe.e2024.stderr
+++ /dev/null
@@ -1,15 +0,0 @@
-error[E0796]: reference of mutable static is disallowed
-  --> $DIR/reference-of-mut-static-safe.rs:9:14
-   |
-LL |     let _x = &X;
-   |              ^^ reference of mutable static
-   |
-   = note: mutable statics can be written to by multiple threads: aliasing violations or data races will cause undefined behavior
-help: shared references are dangerous since if there's any kind of mutation of that static while the reference lives, that's UB; use `addr_of!` instead to create a raw pointer
-   |
-LL |     let _x = addr_of!(X);
-   |              ~~~~~~~~~~~
-
-error: aborting due to 1 previous error
-
-For more information about this error, try `rustc --explain E0796`.
diff --git a/tests/ui/static/reference-of-mut-static-unsafe-fn.rs b/tests/ui/static/reference-of-mut-static-unsafe-fn.rs
index 8f3b3eb7745..5652703a271 100644
--- a/tests/ui/static/reference-of-mut-static-unsafe-fn.rs
+++ b/tests/ui/static/reference-of-mut-static-unsafe-fn.rs
@@ -7,17 +7,20 @@ unsafe fn _foo() {
     static mut Y: i32 = 1;
 
     let _y = &X;
-    //~^ ERROR reference of mutable static is disallowed
+    //~^ ERROR creating a shared reference to a mutable static [E0796]
 
     let ref _a = X;
-    //~^ ERROR reference of mutable static is disallowed
+    //~^ ERROR creating a shared reference to a mutable static [E0796]
 
-    let (_b, _c) = (&X, &Y);
-    //~^ ERROR reference of mutable static is disallowed
-    //~^^ ERROR reference of mutable static is disallowed
+    let ref mut _a = X;
+    //~^ ERROR creating a mutable reference to a mutable static [E0796]
+
+    let (_b, _c) = (&X, &mut Y);
+    //~^ ERROR creating a shared reference to a mutable static [E0796]
+    //~^^ ERROR creating a mutable reference to a mutable static [E0796]
 
     foo(&X);
-    //~^ ERROR reference of mutable static is disallowed
+    //~^ ERROR creating a shared reference to a mutable static [E0796]
 }
 
 fn foo<'a>(_x: &'a i32) {}
diff --git a/tests/ui/static/reference-of-mut-static-unsafe-fn.stderr b/tests/ui/static/reference-of-mut-static-unsafe-fn.stderr
index 5c6fdedfa96..5675d313e07 100644
--- a/tests/ui/static/reference-of-mut-static-unsafe-fn.stderr
+++ b/tests/ui/static/reference-of-mut-static-unsafe-fn.stderr
@@ -1,63 +1,75 @@
-error[E0796]: reference of mutable static is disallowed
+error[E0796]: creating a shared reference to a mutable static
   --> $DIR/reference-of-mut-static-unsafe-fn.rs:9:14
    |
 LL |     let _y = &X;
-   |              ^^ reference of mutable static
+   |              ^^ shared reference to mutable static
    |
-   = note: mutable statics can be written to by multiple threads: aliasing violations or data races will cause undefined behavior
-help: shared references are dangerous since if there's any kind of mutation of that static while the reference lives, that's UB; use `addr_of!` instead to create a raw pointer
+   = note: this shared reference has lifetime `'static`, but if the static ever gets mutated, or a mutable reference is created, then any further use of this shared reference is Undefined Behavior
+help: use `addr_of!` instead to create a raw pointer
    |
 LL |     let _y = addr_of!(X);
    |              ~~~~~~~~~~~
 
-error[E0796]: reference of mutable static is disallowed
+error[E0796]: creating a shared reference to a mutable static
   --> $DIR/reference-of-mut-static-unsafe-fn.rs:12:18
    |
 LL |     let ref _a = X;
-   |                  ^ reference of mutable static
+   |                  ^ shared reference to mutable static
    |
-   = note: mutable statics can be written to by multiple threads: aliasing violations or data races will cause undefined behavior
-help: shared references are dangerous since if there's any kind of mutation of that static while the reference lives, that's UB; use `addr_of!` instead to create a raw pointer
+   = note: this shared reference has lifetime `'static`, but if the static ever gets mutated, or a mutable reference is created, then any further use of this shared reference is Undefined Behavior
+help: use `addr_of!` instead to create a raw pointer
    |
 LL |     let ref _a = addr_of!(X);
    |                  ~~~~~~~~~~~
 
-error[E0796]: reference of mutable static is disallowed
-  --> $DIR/reference-of-mut-static-unsafe-fn.rs:15:21
+error[E0796]: creating a mutable reference to a mutable static
+  --> $DIR/reference-of-mut-static-unsafe-fn.rs:15:22
    |
-LL |     let (_b, _c) = (&X, &Y);
-   |                     ^^ reference of mutable static
+LL |     let ref mut _a = X;
+   |                      ^ mutable reference to mutable static
    |
-   = note: mutable statics can be written to by multiple threads: aliasing violations or data races will cause undefined behavior
-help: shared references are dangerous since if there's any kind of mutation of that static while the reference lives, that's UB; use `addr_of!` instead to create a raw pointer
+   = note: this mutable reference has lifetime `'static`, but if the static gets accessed (read or written) by any other means, or any other reference is created, then any further use of this mutable reference is Undefined Behavior
+help: use `addr_of_mut!` instead to create a raw pointer
    |
-LL |     let (_b, _c) = (addr_of!(X), &Y);
+LL |     let ref mut _a = addr_of_mut!(X);
+   |                      ~~~~~~~~~~~~~~~
+
+error[E0796]: creating a shared reference to a mutable static
+  --> $DIR/reference-of-mut-static-unsafe-fn.rs:18:21
+   |
+LL |     let (_b, _c) = (&X, &mut Y);
+   |                     ^^ shared reference to mutable static
+   |
+   = note: this shared reference has lifetime `'static`, but if the static ever gets mutated, or a mutable reference is created, then any further use of this shared reference is Undefined Behavior
+help: use `addr_of!` instead to create a raw pointer
+   |
+LL |     let (_b, _c) = (addr_of!(X), &mut Y);
    |                     ~~~~~~~~~~~
 
-error[E0796]: reference of mutable static is disallowed
-  --> $DIR/reference-of-mut-static-unsafe-fn.rs:15:25
+error[E0796]: creating a mutable reference to a mutable static
+  --> $DIR/reference-of-mut-static-unsafe-fn.rs:18:25
    |
-LL |     let (_b, _c) = (&X, &Y);
-   |                         ^^ reference of mutable static
+LL |     let (_b, _c) = (&X, &mut Y);
+   |                         ^^^^^^ mutable reference to mutable static
    |
-   = note: mutable statics can be written to by multiple threads: aliasing violations or data races will cause undefined behavior
-help: shared references are dangerous since if there's any kind of mutation of that static while the reference lives, that's UB; use `addr_of!` instead to create a raw pointer
+   = note: this mutable reference has lifetime `'static`, but if the static gets accessed (read or written) by any other means, or any other reference is created, then any further use of this mutable reference is Undefined Behavior
+help: use `addr_of_mut!` instead to create a raw pointer
    |
-LL |     let (_b, _c) = (&X, addr_of!(Y));
-   |                         ~~~~~~~~~~~
+LL |     let (_b, _c) = (&X, addr_of_mut!(Y));
+   |                         ~~~~~~~~~~~~~~~
 
-error[E0796]: reference of mutable static is disallowed
-  --> $DIR/reference-of-mut-static-unsafe-fn.rs:19:9
+error[E0796]: creating a shared reference to a mutable static
+  --> $DIR/reference-of-mut-static-unsafe-fn.rs:22:9
    |
 LL |     foo(&X);
-   |         ^^ reference of mutable static
+   |         ^^ shared reference to mutable static
    |
-   = note: mutable statics can be written to by multiple threads: aliasing violations or data races will cause undefined behavior
-help: shared references are dangerous since if there's any kind of mutation of that static while the reference lives, that's UB; use `addr_of!` instead to create a raw pointer
+   = note: this shared reference has lifetime `'static`, but if the static ever gets mutated, or a mutable reference is created, then any further use of this shared reference is Undefined Behavior
+help: use `addr_of!` instead to create a raw pointer
    |
 LL |     foo(addr_of!(X));
    |         ~~~~~~~~~~~
 
-error: aborting due to 5 previous errors
+error: aborting due to 6 previous errors
 
 For more information about this error, try `rustc --explain E0796`.
diff --git a/tests/ui/static/reference-of-mut-static.e2021.stderr b/tests/ui/static/reference-of-mut-static.e2021.stderr
index 77a6b3d304b..f7ad51b6157 100644
--- a/tests/ui/static/reference-of-mut-static.e2021.stderr
+++ b/tests/ui/static/reference-of-mut-static.e2021.stderr
@@ -1,88 +1,88 @@
-error: shared reference of mutable static is discouraged
+error: creating a shared reference to mutable static is discouraged
   --> $DIR/reference-of-mut-static.rs:16:18
    |
 LL |         let _y = &X;
-   |                  ^^ shared reference of mutable static
+   |                  ^^ shared reference to mutable static
    |
    = note: for more information, see issue #114447 <https://github.com/rust-lang/rust/issues/114447>
-   = note: reference of mutable static is a hard error from 2024 edition
-   = note: mutable statics can be written to by multiple threads: aliasing violations or data races will cause undefined behavior
+   = note: this will be a hard error in the 2024 edition
+   = note: this shared reference has lifetime `'static`, but if the static ever gets mutated, or a mutable reference is created, then any further use of this shared reference is Undefined Behavior
 note: the lint level is defined here
   --> $DIR/reference-of-mut-static.rs:6:9
    |
-LL | #![deny(static_mut_ref)]
-   |         ^^^^^^^^^^^^^^
-help: shared references are dangerous since if there's any kind of mutation of that static while the reference lives, that's UB; use `addr_of!` instead to create a raw pointer
+LL | #![deny(static_mut_refs)]
+   |         ^^^^^^^^^^^^^^^
+help: use `addr_of!` instead to create a raw pointer
    |
 LL |         let _y = addr_of!(X);
    |                  ~~~~~~~~~~~
 
-error: mutable reference of mutable static is discouraged
+error: creating a mutable reference to mutable static is discouraged
   --> $DIR/reference-of-mut-static.rs:20:18
    |
 LL |         let _y = &mut X;
-   |                  ^^^^^^ mutable reference of mutable static
+   |                  ^^^^^^ mutable reference to mutable static
    |
    = note: for more information, see issue #114447 <https://github.com/rust-lang/rust/issues/114447>
-   = note: reference of mutable static is a hard error from 2024 edition
-   = note: mutable statics can be written to by multiple threads: aliasing violations or data races will cause undefined behavior
-help: mutable references are dangerous since if there's any other pointer or reference used for that static while the reference lives, that's UB; use `addr_of_mut!` instead to create a raw pointer
+   = note: this will be a hard error in the 2024 edition
+   = note: this mutable reference has lifetime `'static`, but if the static gets accessed (read or written) by any other means, or any other reference is created, then any further use of this mutable reference is Undefined Behavior
+help: use `addr_of_mut!` instead to create a raw pointer
    |
 LL |         let _y = addr_of_mut!(X);
    |                  ~~~~~~~~~~~~~~~
 
-error: shared reference of mutable static is discouraged
+error: creating a shared reference to mutable static is discouraged
   --> $DIR/reference-of-mut-static.rs:28:22
    |
 LL |         let ref _a = X;
-   |                      ^ shared reference of mutable static
+   |                      ^ shared reference to mutable static
    |
    = note: for more information, see issue #114447 <https://github.com/rust-lang/rust/issues/114447>
-   = note: reference of mutable static is a hard error from 2024 edition
-   = note: mutable statics can be written to by multiple threads: aliasing violations or data races will cause undefined behavior
-help: shared references are dangerous since if there's any kind of mutation of that static while the reference lives, that's UB; use `addr_of!` instead to create a raw pointer
+   = note: this will be a hard error in the 2024 edition
+   = note: this shared reference has lifetime `'static`, but if the static ever gets mutated, or a mutable reference is created, then any further use of this shared reference is Undefined Behavior
+help: use `addr_of!` instead to create a raw pointer
    |
 LL |         let ref _a = addr_of!(X);
    |                      ~~~~~~~~~~~
 
-error: shared reference of mutable static is discouraged
+error: creating a shared reference to mutable static is discouraged
   --> $DIR/reference-of-mut-static.rs:32:25
    |
 LL |         let (_b, _c) = (&X, &Y);
-   |                         ^^ shared reference of mutable static
+   |                         ^^ shared reference to mutable static
    |
    = note: for more information, see issue #114447 <https://github.com/rust-lang/rust/issues/114447>
-   = note: reference of mutable static is a hard error from 2024 edition
-   = note: mutable statics can be written to by multiple threads: aliasing violations or data races will cause undefined behavior
-help: shared references are dangerous since if there's any kind of mutation of that static while the reference lives, that's UB; use `addr_of!` instead to create a raw pointer
+   = note: this will be a hard error in the 2024 edition
+   = note: this shared reference has lifetime `'static`, but if the static ever gets mutated, or a mutable reference is created, then any further use of this shared reference is Undefined Behavior
+help: use `addr_of!` instead to create a raw pointer
    |
 LL |         let (_b, _c) = (addr_of!(X), &Y);
    |                         ~~~~~~~~~~~
 
-error: shared reference of mutable static is discouraged
+error: creating a shared reference to mutable static is discouraged
   --> $DIR/reference-of-mut-static.rs:32:29
    |
 LL |         let (_b, _c) = (&X, &Y);
-   |                             ^^ shared reference of mutable static
+   |                             ^^ shared reference to mutable static
    |
    = note: for more information, see issue #114447 <https://github.com/rust-lang/rust/issues/114447>
-   = note: reference of mutable static is a hard error from 2024 edition
-   = note: mutable statics can be written to by multiple threads: aliasing violations or data races will cause undefined behavior
-help: shared references are dangerous since if there's any kind of mutation of that static while the reference lives, that's UB; use `addr_of!` instead to create a raw pointer
+   = note: this will be a hard error in the 2024 edition
+   = note: this shared reference has lifetime `'static`, but if the static ever gets mutated, or a mutable reference is created, then any further use of this shared reference is Undefined Behavior
+help: use `addr_of!` instead to create a raw pointer
    |
 LL |         let (_b, _c) = (&X, addr_of!(Y));
    |                             ~~~~~~~~~~~
 
-error: shared reference of mutable static is discouraged
+error: creating a shared reference to mutable static is discouraged
   --> $DIR/reference-of-mut-static.rs:38:13
    |
 LL |         foo(&X);
-   |             ^^ shared reference of mutable static
+   |             ^^ shared reference to mutable static
    |
    = note: for more information, see issue #114447 <https://github.com/rust-lang/rust/issues/114447>
-   = note: reference of mutable static is a hard error from 2024 edition
-   = note: mutable statics can be written to by multiple threads: aliasing violations or data races will cause undefined behavior
-help: shared references are dangerous since if there's any kind of mutation of that static while the reference lives, that's UB; use `addr_of!` instead to create a raw pointer
+   = note: this will be a hard error in the 2024 edition
+   = note: this shared reference has lifetime `'static`, but if the static ever gets mutated, or a mutable reference is created, then any further use of this shared reference is Undefined Behavior
+help: use `addr_of!` instead to create a raw pointer
    |
 LL |         foo(addr_of!(X));
    |             ~~~~~~~~~~~
diff --git a/tests/ui/static/reference-of-mut-static.e2024.stderr b/tests/ui/static/reference-of-mut-static.e2024.stderr
index f445ec65a5d..6205c10ac41 100644
--- a/tests/ui/static/reference-of-mut-static.e2024.stderr
+++ b/tests/ui/static/reference-of-mut-static.e2024.stderr
@@ -1,71 +1,71 @@
-error[E0796]: reference of mutable static is disallowed
+error[E0796]: creating a shared reference to a mutable static
   --> $DIR/reference-of-mut-static.rs:16:18
    |
 LL |         let _y = &X;
-   |                  ^^ reference of mutable static
+   |                  ^^ shared reference to mutable static
    |
-   = note: mutable statics can be written to by multiple threads: aliasing violations or data races will cause undefined behavior
-help: shared references are dangerous since if there's any kind of mutation of that static while the reference lives, that's UB; use `addr_of!` instead to create a raw pointer
+   = note: this shared reference has lifetime `'static`, but if the static ever gets mutated, or a mutable reference is created, then any further use of this shared reference is Undefined Behavior
+help: use `addr_of!` instead to create a raw pointer
    |
 LL |         let _y = addr_of!(X);
    |                  ~~~~~~~~~~~
 
-error[E0796]: reference of mutable static is disallowed
+error[E0796]: creating a mutable reference to a mutable static
   --> $DIR/reference-of-mut-static.rs:20:18
    |
 LL |         let _y = &mut X;
-   |                  ^^^^^^ reference of mutable static
+   |                  ^^^^^^ mutable reference to mutable static
    |
-   = note: mutable statics can be written to by multiple threads: aliasing violations or data races will cause undefined behavior
-help: mutable references are dangerous since if there's any other pointer or reference used for that static while the reference lives, that's UB; use `addr_of_mut!` instead to create a raw pointer
+   = note: this mutable reference has lifetime `'static`, but if the static gets accessed (read or written) by any other means, or any other reference is created, then any further use of this mutable reference is Undefined Behavior
+help: use `addr_of_mut!` instead to create a raw pointer
    |
 LL |         let _y = addr_of_mut!(X);
    |                  ~~~~~~~~~~~~~~~
 
-error[E0796]: reference of mutable static is disallowed
+error[E0796]: creating a shared reference to a mutable static
   --> $DIR/reference-of-mut-static.rs:28:22
    |
 LL |         let ref _a = X;
-   |                      ^ reference of mutable static
+   |                      ^ shared reference to mutable static
    |
-   = note: mutable statics can be written to by multiple threads: aliasing violations or data races will cause undefined behavior
-help: shared references are dangerous since if there's any kind of mutation of that static while the reference lives, that's UB; use `addr_of!` instead to create a raw pointer
+   = note: this shared reference has lifetime `'static`, but if the static ever gets mutated, or a mutable reference is created, then any further use of this shared reference is Undefined Behavior
+help: use `addr_of!` instead to create a raw pointer
    |
 LL |         let ref _a = addr_of!(X);
    |                      ~~~~~~~~~~~
 
-error[E0796]: reference of mutable static is disallowed
+error[E0796]: creating a shared reference to a mutable static
   --> $DIR/reference-of-mut-static.rs:32:25
    |
 LL |         let (_b, _c) = (&X, &Y);
-   |                         ^^ reference of mutable static
+   |                         ^^ shared reference to mutable static
    |
-   = note: mutable statics can be written to by multiple threads: aliasing violations or data races will cause undefined behavior
-help: shared references are dangerous since if there's any kind of mutation of that static while the reference lives, that's UB; use `addr_of!` instead to create a raw pointer
+   = note: this shared reference has lifetime `'static`, but if the static ever gets mutated, or a mutable reference is created, then any further use of this shared reference is Undefined Behavior
+help: use `addr_of!` instead to create a raw pointer
    |
 LL |         let (_b, _c) = (addr_of!(X), &Y);
    |                         ~~~~~~~~~~~
 
-error[E0796]: reference of mutable static is disallowed
+error[E0796]: creating a shared reference to a mutable static
   --> $DIR/reference-of-mut-static.rs:32:29
    |
 LL |         let (_b, _c) = (&X, &Y);
-   |                             ^^ reference of mutable static
+   |                             ^^ shared reference to mutable static
    |
-   = note: mutable statics can be written to by multiple threads: aliasing violations or data races will cause undefined behavior
-help: shared references are dangerous since if there's any kind of mutation of that static while the reference lives, that's UB; use `addr_of!` instead to create a raw pointer
+   = note: this shared reference has lifetime `'static`, but if the static ever gets mutated, or a mutable reference is created, then any further use of this shared reference is Undefined Behavior
+help: use `addr_of!` instead to create a raw pointer
    |
 LL |         let (_b, _c) = (&X, addr_of!(Y));
    |                             ~~~~~~~~~~~
 
-error[E0796]: reference of mutable static is disallowed
+error[E0796]: creating a shared reference to a mutable static
   --> $DIR/reference-of-mut-static.rs:38:13
    |
 LL |         foo(&X);
-   |             ^^ reference of mutable static
+   |             ^^ shared reference to mutable static
    |
-   = note: mutable statics can be written to by multiple threads: aliasing violations or data races will cause undefined behavior
-help: shared references are dangerous since if there's any kind of mutation of that static while the reference lives, that's UB; use `addr_of!` instead to create a raw pointer
+   = note: this shared reference has lifetime `'static`, but if the static ever gets mutated, or a mutable reference is created, then any further use of this shared reference is Undefined Behavior
+help: use `addr_of!` instead to create a raw pointer
    |
 LL |         foo(addr_of!(X));
    |             ~~~~~~~~~~~
diff --git a/tests/ui/static/reference-of-mut-static.rs b/tests/ui/static/reference-of-mut-static.rs
index 166303f0257..af2cab7dd87 100644
--- a/tests/ui/static/reference-of-mut-static.rs
+++ b/tests/ui/static/reference-of-mut-static.rs
@@ -3,7 +3,7 @@
 //@ [e2021] edition:2021
 //@ [e2024] compile-flags: --edition 2024 -Z unstable-options
 
-#![deny(static_mut_ref)]
+#![deny(static_mut_refs)]
 
 use std::ptr::{addr_of, addr_of_mut};
 
@@ -14,30 +14,30 @@ fn main() {
 
     unsafe {
         let _y = &X;
-        //[e2024]~^ ERROR reference of mutable static is disallowed
-        //[e2021]~^^ ERROR shared reference of mutable static is discouraged [static_mut_ref]
+        //[e2024]~^ ERROR creating a shared reference to a mutable static [E0796]
+        //[e2021]~^^ ERROR shared reference to mutable static is discouraged [static_mut_refs]
 
         let _y = &mut X;
-        //[e2024]~^ ERROR reference of mutable static is disallowed
-        //[e2021]~^^ ERROR mutable reference of mutable static is discouraged [static_mut_ref]
+        //[e2024]~^ ERROR creating a mutable reference to a mutable static [E0796]
+        //[e2021]~^^ ERROR mutable reference to mutable static is discouraged [static_mut_refs]
 
         let _z = addr_of_mut!(X);
 
         let _p = addr_of!(X);
 
         let ref _a = X;
-        //[e2024]~^ ERROR reference of mutable static is disallowed
-        //[e2021]~^^ ERROR shared reference of mutable static is discouraged [static_mut_ref]
+        //[e2024]~^ ERROR creating a shared reference to a mutable static [E0796]
+        //[e2021]~^^ ERROR shared reference to mutable static is discouraged [static_mut_refs]
 
         let (_b, _c) = (&X, &Y);
-        //[e2024]~^ ERROR reference of mutable static is disallowed
-        //[e2021]~^^ ERROR shared reference of mutable static is discouraged [static_mut_ref]
-        //[e2024]~^^^ ERROR reference of mutable static is disallowed
-        //[e2021]~^^^^ ERROR shared reference of mutable static is discouraged [static_mut_ref]
+        //[e2024]~^ ERROR creating a shared reference to a mutable static [E0796]
+        //[e2021]~^^ ERROR shared reference to mutable static is discouraged [static_mut_refs]
+        //[e2024]~^^^ ERROR creating a shared reference to a mutable static [E0796]
+        //[e2021]~^^^^ ERROR shared reference to mutable static is discouraged [static_mut_refs]
 
         foo(&X);
-        //[e2024]~^ ERROR reference of mutable static is disallowed
-        //[e2021]~^^ ERROR shared reference of mutable static is discouraged [static_mut_ref]
+        //[e2024]~^ ERROR creating a shared reference to a mutable static [E0796]
+        //[e2021]~^^ ERROR shared reference to mutable static is discouraged [static_mut_refs]
 
         static mut Z: &[i32; 3] = &[0, 1, 2];
 
diff --git a/tests/ui/static/reference-to-mut-static-safe.e2021.stderr b/tests/ui/static/reference-to-mut-static-safe.e2021.stderr
new file mode 100644
index 00000000000..9ea34290e36
--- /dev/null
+++ b/tests/ui/static/reference-to-mut-static-safe.e2021.stderr
@@ -0,0 +1,26 @@
+warning: creating a shared reference to mutable static is discouraged
+  --> $DIR/reference-to-mut-static-safe.rs:9:14
+   |
+LL |     let _x = &X;
+   |              ^^ shared reference to mutable static
+   |
+   = note: for more information, see issue #114447 <https://github.com/rust-lang/rust/issues/114447>
+   = note: this will be a hard error in the 2024 edition
+   = note: this shared reference has lifetime `'static`, but if the static ever gets mutated, or a mutable reference is created, then any further use of this shared reference is Undefined Behavior
+   = note: `#[warn(static_mut_refs)]` on by default
+help: use `addr_of!` instead to create a raw pointer
+   |
+LL |     let _x = addr_of!(X);
+   |              ~~~~~~~~~~~
+
+error[E0133]: use of mutable static is unsafe and requires unsafe function or block
+  --> $DIR/reference-to-mut-static-safe.rs:9:15
+   |
+LL |     let _x = &X;
+   |               ^ use of mutable static
+   |
+   = note: mutable statics can be mutated by multiple threads: aliasing violations or data races will cause undefined behavior
+
+error: aborting due to 1 previous error; 1 warning emitted
+
+For more information about this error, try `rustc --explain E0133`.
diff --git a/tests/ui/static/reference-to-mut-static-safe.e2024.stderr b/tests/ui/static/reference-to-mut-static-safe.e2024.stderr
new file mode 100644
index 00000000000..607c1bba135
--- /dev/null
+++ b/tests/ui/static/reference-to-mut-static-safe.e2024.stderr
@@ -0,0 +1,15 @@
+error[E0796]: creating a shared reference to a mutable static
+  --> $DIR/reference-to-mut-static-safe.rs:9:14
+   |
+LL |     let _x = &X;
+   |              ^^ shared reference to mutable static
+   |
+   = note: this shared reference has lifetime `'static`, but if the static ever gets mutated, or a mutable reference is created, then any further use of this shared reference is Undefined Behavior
+help: use `addr_of!` instead to create a raw pointer
+   |
+LL |     let _x = addr_of!(X);
+   |              ~~~~~~~~~~~
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0796`.
diff --git a/tests/ui/static/reference-of-mut-static-safe.rs b/tests/ui/static/reference-to-mut-static-safe.rs
index d113d0ee48d..de4f4be8f76 100644
--- a/tests/ui/static/reference-of-mut-static-safe.rs
+++ b/tests/ui/static/reference-to-mut-static-safe.rs
@@ -7,7 +7,7 @@ fn main() {
     static mut X: i32 = 1;
 
     let _x = &X;
-    //[e2024]~^ reference of mutable static is disallowed [E0796]
+    //[e2024]~^ creating a shared reference to a mutable static [E0796]
     //[e2021]~^^ use of mutable static is unsafe and requires unsafe function or block [E0133]
-    //[e2021]~^^^ shared reference of mutable static is discouraged [static_mut_ref]
+    //[e2021]~^^^ shared reference to mutable static is discouraged [static_mut_refs]
 }
diff --git a/tests/ui/static/reference-to-mut-static-unsafe-fn.rs b/tests/ui/static/reference-to-mut-static-unsafe-fn.rs
new file mode 100644
index 00000000000..5652703a271
--- /dev/null
+++ b/tests/ui/static/reference-to-mut-static-unsafe-fn.rs
@@ -0,0 +1,26 @@
+//@ compile-flags: --edition 2024 -Z unstable-options
+
+fn main() {}
+
+unsafe fn _foo() {
+    static mut X: i32 = 1;
+    static mut Y: i32 = 1;
+
+    let _y = &X;
+    //~^ ERROR creating a shared reference to a mutable static [E0796]
+
+    let ref _a = X;
+    //~^ ERROR creating a shared reference to a mutable static [E0796]
+
+    let ref mut _a = X;
+    //~^ ERROR creating a mutable reference to a mutable static [E0796]
+
+    let (_b, _c) = (&X, &mut Y);
+    //~^ ERROR creating a shared reference to a mutable static [E0796]
+    //~^^ ERROR creating a mutable reference to a mutable static [E0796]
+
+    foo(&X);
+    //~^ ERROR creating a shared reference to a mutable static [E0796]
+}
+
+fn foo<'a>(_x: &'a i32) {}
diff --git a/tests/ui/static/reference-to-mut-static-unsafe-fn.stderr b/tests/ui/static/reference-to-mut-static-unsafe-fn.stderr
new file mode 100644
index 00000000000..77d2aa5d1ae
--- /dev/null
+++ b/tests/ui/static/reference-to-mut-static-unsafe-fn.stderr
@@ -0,0 +1,75 @@
+error[E0796]: creating a shared reference to a mutable static
+  --> $DIR/reference-to-mut-static-unsafe-fn.rs:9:14
+   |
+LL |     let _y = &X;
+   |              ^^ shared reference to mutable static
+   |
+   = note: this shared reference has lifetime `'static`, but if the static ever gets mutated, or a mutable reference is created, then any further use of this shared reference is Undefined Behavior
+help: use `addr_of!` instead to create a raw pointer
+   |
+LL |     let _y = addr_of!(X);
+   |              ~~~~~~~~~~~
+
+error[E0796]: creating a shared reference to a mutable static
+  --> $DIR/reference-to-mut-static-unsafe-fn.rs:12:18
+   |
+LL |     let ref _a = X;
+   |                  ^ shared reference to mutable static
+   |
+   = note: this shared reference has lifetime `'static`, but if the static ever gets mutated, or a mutable reference is created, then any further use of this shared reference is Undefined Behavior
+help: use `addr_of!` instead to create a raw pointer
+   |
+LL |     let ref _a = addr_of!(X);
+   |                  ~~~~~~~~~~~
+
+error[E0796]: creating a mutable reference to a mutable static
+  --> $DIR/reference-to-mut-static-unsafe-fn.rs:15:22
+   |
+LL |     let ref mut _a = X;
+   |                      ^ mutable reference to mutable static
+   |
+   = note: this mutable reference has lifetime `'static`, but if the static gets accessed (read or written) by any other means, or any other reference is created, then any further use of this mutable reference is Undefined Behavior
+help: use `addr_of_mut!` instead to create a raw pointer
+   |
+LL |     let ref mut _a = addr_of_mut!(X);
+   |                      ~~~~~~~~~~~~~~~
+
+error[E0796]: creating a shared reference to a mutable static
+  --> $DIR/reference-to-mut-static-unsafe-fn.rs:18:21
+   |
+LL |     let (_b, _c) = (&X, &mut Y);
+   |                     ^^ shared reference to mutable static
+   |
+   = note: this shared reference has lifetime `'static`, but if the static ever gets mutated, or a mutable reference is created, then any further use of this shared reference is Undefined Behavior
+help: use `addr_of!` instead to create a raw pointer
+   |
+LL |     let (_b, _c) = (addr_of!(X), &mut Y);
+   |                     ~~~~~~~~~~~
+
+error[E0796]: creating a mutable reference to a mutable static
+  --> $DIR/reference-to-mut-static-unsafe-fn.rs:18:25
+   |
+LL |     let (_b, _c) = (&X, &mut Y);
+   |                         ^^^^^^ mutable reference to mutable static
+   |
+   = note: this mutable reference has lifetime `'static`, but if the static gets accessed (read or written) by any other means, or any other reference is created, then any further use of this mutable reference is Undefined Behavior
+help: use `addr_of_mut!` instead to create a raw pointer
+   |
+LL |     let (_b, _c) = (&X, addr_of_mut!(Y));
+   |                         ~~~~~~~~~~~~~~~
+
+error[E0796]: creating a shared reference to a mutable static
+  --> $DIR/reference-to-mut-static-unsafe-fn.rs:22:9
+   |
+LL |     foo(&X);
+   |         ^^ shared reference to mutable static
+   |
+   = note: this shared reference has lifetime `'static`, but if the static ever gets mutated, or a mutable reference is created, then any further use of this shared reference is Undefined Behavior
+help: use `addr_of!` instead to create a raw pointer
+   |
+LL |     foo(addr_of!(X));
+   |         ~~~~~~~~~~~
+
+error: aborting due to 6 previous errors
+
+For more information about this error, try `rustc --explain E0796`.
diff --git a/tests/ui/static/reference-to-mut-static.e2021.stderr b/tests/ui/static/reference-to-mut-static.e2021.stderr
new file mode 100644
index 00000000000..f477e5ac6c5
--- /dev/null
+++ b/tests/ui/static/reference-to-mut-static.e2021.stderr
@@ -0,0 +1,91 @@
+error: creating a shared reference to mutable static is discouraged
+  --> $DIR/reference-to-mut-static.rs:16:18
+   |
+LL |         let _y = &X;
+   |                  ^^ shared reference to mutable static
+   |
+   = note: for more information, see issue #114447 <https://github.com/rust-lang/rust/issues/114447>
+   = note: this will be a hard error in the 2024 edition
+   = note: this shared reference has lifetime `'static`, but if the static ever gets mutated, or a mutable reference is created, then any further use of this shared reference is Undefined Behavior
+note: the lint level is defined here
+  --> $DIR/reference-to-mut-static.rs:6:9
+   |
+LL | #![deny(static_mut_refs)]
+   |         ^^^^^^^^^^^^^^^
+help: use `addr_of!` instead to create a raw pointer
+   |
+LL |         let _y = addr_of!(X);
+   |                  ~~~~~~~~~~~
+
+error: creating a mutable reference to mutable static is discouraged
+  --> $DIR/reference-to-mut-static.rs:20:18
+   |
+LL |         let _y = &mut X;
+   |                  ^^^^^^ mutable reference to mutable static
+   |
+   = note: for more information, see issue #114447 <https://github.com/rust-lang/rust/issues/114447>
+   = note: this will be a hard error in the 2024 edition
+   = note: this mutable reference has lifetime `'static`, but if the static gets accessed (read or written) by any other means, or any other reference is created, then any further use of this mutable reference is Undefined Behavior
+help: use `addr_of_mut!` instead to create a raw pointer
+   |
+LL |         let _y = addr_of_mut!(X);
+   |                  ~~~~~~~~~~~~~~~
+
+error: creating a shared reference to mutable static is discouraged
+  --> $DIR/reference-to-mut-static.rs:28:22
+   |
+LL |         let ref _a = X;
+   |                      ^ shared reference to mutable static
+   |
+   = note: for more information, see issue #114447 <https://github.com/rust-lang/rust/issues/114447>
+   = note: this will be a hard error in the 2024 edition
+   = note: this shared reference has lifetime `'static`, but if the static ever gets mutated, or a mutable reference is created, then any further use of this shared reference is Undefined Behavior
+help: use `addr_of!` instead to create a raw pointer
+   |
+LL |         let ref _a = addr_of!(X);
+   |                      ~~~~~~~~~~~
+
+error: creating a shared reference to mutable static is discouraged
+  --> $DIR/reference-to-mut-static.rs:32:25
+   |
+LL |         let (_b, _c) = (&X, &Y);
+   |                         ^^ shared reference to mutable static
+   |
+   = note: for more information, see issue #114447 <https://github.com/rust-lang/rust/issues/114447>
+   = note: this will be a hard error in the 2024 edition
+   = note: this shared reference has lifetime `'static`, but if the static ever gets mutated, or a mutable reference is created, then any further use of this shared reference is Undefined Behavior
+help: use `addr_of!` instead to create a raw pointer
+   |
+LL |         let (_b, _c) = (addr_of!(X), &Y);
+   |                         ~~~~~~~~~~~
+
+error: creating a shared reference to mutable static is discouraged
+  --> $DIR/reference-to-mut-static.rs:32:29
+   |
+LL |         let (_b, _c) = (&X, &Y);
+   |                             ^^ shared reference to mutable static
+   |
+   = note: for more information, see issue #114447 <https://github.com/rust-lang/rust/issues/114447>
+   = note: this will be a hard error in the 2024 edition
+   = note: this shared reference has lifetime `'static`, but if the static ever gets mutated, or a mutable reference is created, then any further use of this shared reference is Undefined Behavior
+help: use `addr_of!` instead to create a raw pointer
+   |
+LL |         let (_b, _c) = (&X, addr_of!(Y));
+   |                             ~~~~~~~~~~~
+
+error: creating a shared reference to mutable static is discouraged
+  --> $DIR/reference-to-mut-static.rs:38:13
+   |
+LL |         foo(&X);
+   |             ^^ shared reference to mutable static
+   |
+   = note: for more information, see issue #114447 <https://github.com/rust-lang/rust/issues/114447>
+   = note: this will be a hard error in the 2024 edition
+   = note: this shared reference has lifetime `'static`, but if the static ever gets mutated, or a mutable reference is created, then any further use of this shared reference is Undefined Behavior
+help: use `addr_of!` instead to create a raw pointer
+   |
+LL |         foo(addr_of!(X));
+   |             ~~~~~~~~~~~
+
+error: aborting due to 6 previous errors
+
diff --git a/tests/ui/static/reference-to-mut-static.e2024.stderr b/tests/ui/static/reference-to-mut-static.e2024.stderr
new file mode 100644
index 00000000000..b18e214e84f
--- /dev/null
+++ b/tests/ui/static/reference-to-mut-static.e2024.stderr
@@ -0,0 +1,75 @@
+error[E0796]: creating a shared reference to a mutable static
+  --> $DIR/reference-to-mut-static.rs:16:18
+   |
+LL |         let _y = &X;
+   |                  ^^ shared reference to mutable static
+   |
+   = note: this shared reference has lifetime `'static`, but if the static ever gets mutated, or a mutable reference is created, then any further use of this shared reference is Undefined Behavior
+help: use `addr_of!` instead to create a raw pointer
+   |
+LL |         let _y = addr_of!(X);
+   |                  ~~~~~~~~~~~
+
+error[E0796]: creating a mutable reference to a mutable static
+  --> $DIR/reference-to-mut-static.rs:20:18
+   |
+LL |         let _y = &mut X;
+   |                  ^^^^^^ mutable reference to mutable static
+   |
+   = note: this mutable reference has lifetime `'static`, but if the static gets accessed (read or written) by any other means, or any other reference is created, then any further use of this mutable reference is Undefined Behavior
+help: use `addr_of_mut!` instead to create a raw pointer
+   |
+LL |         let _y = addr_of_mut!(X);
+   |                  ~~~~~~~~~~~~~~~
+
+error[E0796]: creating a shared reference to a mutable static
+  --> $DIR/reference-to-mut-static.rs:28:22
+   |
+LL |         let ref _a = X;
+   |                      ^ shared reference to mutable static
+   |
+   = note: this shared reference has lifetime `'static`, but if the static ever gets mutated, or a mutable reference is created, then any further use of this shared reference is Undefined Behavior
+help: use `addr_of!` instead to create a raw pointer
+   |
+LL |         let ref _a = addr_of!(X);
+   |                      ~~~~~~~~~~~
+
+error[E0796]: creating a shared reference to a mutable static
+  --> $DIR/reference-to-mut-static.rs:32:25
+   |
+LL |         let (_b, _c) = (&X, &Y);
+   |                         ^^ shared reference to mutable static
+   |
+   = note: this shared reference has lifetime `'static`, but if the static ever gets mutated, or a mutable reference is created, then any further use of this shared reference is Undefined Behavior
+help: use `addr_of!` instead to create a raw pointer
+   |
+LL |         let (_b, _c) = (addr_of!(X), &Y);
+   |                         ~~~~~~~~~~~
+
+error[E0796]: creating a shared reference to a mutable static
+  --> $DIR/reference-to-mut-static.rs:32:29
+   |
+LL |         let (_b, _c) = (&X, &Y);
+   |                             ^^ shared reference to mutable static
+   |
+   = note: this shared reference has lifetime `'static`, but if the static ever gets mutated, or a mutable reference is created, then any further use of this shared reference is Undefined Behavior
+help: use `addr_of!` instead to create a raw pointer
+   |
+LL |         let (_b, _c) = (&X, addr_of!(Y));
+   |                             ~~~~~~~~~~~
+
+error[E0796]: creating a shared reference to a mutable static
+  --> $DIR/reference-to-mut-static.rs:38:13
+   |
+LL |         foo(&X);
+   |             ^^ shared reference to mutable static
+   |
+   = note: this shared reference has lifetime `'static`, but if the static ever gets mutated, or a mutable reference is created, then any further use of this shared reference is Undefined Behavior
+help: use `addr_of!` instead to create a raw pointer
+   |
+LL |         foo(addr_of!(X));
+   |             ~~~~~~~~~~~
+
+error: aborting due to 6 previous errors
+
+For more information about this error, try `rustc --explain E0796`.
diff --git a/tests/ui/static/reference-to-mut-static.rs b/tests/ui/static/reference-to-mut-static.rs
new file mode 100644
index 00000000000..af2cab7dd87
--- /dev/null
+++ b/tests/ui/static/reference-to-mut-static.rs
@@ -0,0 +1,50 @@
+//@ revisions: e2021 e2024
+
+//@ [e2021] edition:2021
+//@ [e2024] compile-flags: --edition 2024 -Z unstable-options
+
+#![deny(static_mut_refs)]
+
+use std::ptr::{addr_of, addr_of_mut};
+
+fn main() {
+    static mut X: i32 = 1;
+
+    static mut Y: i32 = 1;
+
+    unsafe {
+        let _y = &X;
+        //[e2024]~^ ERROR creating a shared reference to a mutable static [E0796]
+        //[e2021]~^^ ERROR shared reference to mutable static is discouraged [static_mut_refs]
+
+        let _y = &mut X;
+        //[e2024]~^ ERROR creating a mutable reference to a mutable static [E0796]
+        //[e2021]~^^ ERROR mutable reference to mutable static is discouraged [static_mut_refs]
+
+        let _z = addr_of_mut!(X);
+
+        let _p = addr_of!(X);
+
+        let ref _a = X;
+        //[e2024]~^ ERROR creating a shared reference to a mutable static [E0796]
+        //[e2021]~^^ ERROR shared reference to mutable static is discouraged [static_mut_refs]
+
+        let (_b, _c) = (&X, &Y);
+        //[e2024]~^ ERROR creating a shared reference to a mutable static [E0796]
+        //[e2021]~^^ ERROR shared reference to mutable static is discouraged [static_mut_refs]
+        //[e2024]~^^^ ERROR creating a shared reference to a mutable static [E0796]
+        //[e2021]~^^^^ ERROR shared reference to mutable static is discouraged [static_mut_refs]
+
+        foo(&X);
+        //[e2024]~^ ERROR creating a shared reference to a mutable static [E0796]
+        //[e2021]~^^ ERROR shared reference to mutable static is discouraged [static_mut_refs]
+
+        static mut Z: &[i32; 3] = &[0, 1, 2];
+
+        let _ = Z.len();
+        let _ = Z[0];
+        let _ = format!("{:?}", Z);
+    }
+}
+
+fn foo<'a>(_x: &'a i32) {}
diff --git a/tests/ui/static/safe-extern-statics-mut.rs b/tests/ui/static/safe-extern-statics-mut.rs
index 8aa0b47a311..05a1bee8891 100644
--- a/tests/ui/static/safe-extern-statics-mut.rs
+++ b/tests/ui/static/safe-extern-statics-mut.rs
@@ -10,8 +10,8 @@ extern "C" {
 fn main() {
     let b = B; //~ ERROR use of mutable static is unsafe
     let rb = &B; //~ ERROR use of mutable static is unsafe
-    //~^ WARN shared reference of mutable static is discouraged [static_mut_ref]
+    //~^ WARN shared reference to mutable static is discouraged [static_mut_refs]
     let xb = XB; //~ ERROR use of mutable static is unsafe
     let xrb = &XB; //~ ERROR use of mutable static is unsafe
-    //~^ WARN shared reference of mutable static is discouraged [static_mut_ref]
+    //~^ WARN shared reference to mutable static is discouraged [static_mut_refs]
 }
diff --git a/tests/ui/static/safe-extern-statics-mut.stderr b/tests/ui/static/safe-extern-statics-mut.stderr
index eda353ce673..9a4b651405f 100644
--- a/tests/ui/static/safe-extern-statics-mut.stderr
+++ b/tests/ui/static/safe-extern-statics-mut.stderr
@@ -1,28 +1,28 @@
-warning: shared reference of mutable static is discouraged
+warning: creating a shared reference to mutable static is discouraged
   --> $DIR/safe-extern-statics-mut.rs:12:14
    |
 LL |     let rb = &B;
-   |              ^^ shared reference of mutable static
+   |              ^^ shared reference to mutable static
    |
    = note: for more information, see issue #114447 <https://github.com/rust-lang/rust/issues/114447>
-   = note: reference of mutable static is a hard error from 2024 edition
-   = note: mutable statics can be written to by multiple threads: aliasing violations or data races will cause undefined behavior
-   = note: `#[warn(static_mut_ref)]` on by default
-help: shared references are dangerous since if there's any kind of mutation of that static while the reference lives, that's UB; use `addr_of!` instead to create a raw pointer
+   = note: this will be a hard error in the 2024 edition
+   = note: this shared reference has lifetime `'static`, but if the static ever gets mutated, or a mutable reference is created, then any further use of this shared reference is Undefined Behavior
+   = note: `#[warn(static_mut_refs)]` on by default
+help: use `addr_of!` instead to create a raw pointer
    |
 LL |     let rb = addr_of!(B);
    |              ~~~~~~~~~~~
 
-warning: shared reference of mutable static is discouraged
+warning: creating a shared reference to mutable static is discouraged
   --> $DIR/safe-extern-statics-mut.rs:15:15
    |
 LL |     let xrb = &XB;
-   |               ^^^ shared reference of mutable static
+   |               ^^^ shared reference to mutable static
    |
    = note: for more information, see issue #114447 <https://github.com/rust-lang/rust/issues/114447>
-   = note: reference of mutable static is a hard error from 2024 edition
-   = note: mutable statics can be written to by multiple threads: aliasing violations or data races will cause undefined behavior
-help: shared references are dangerous since if there's any kind of mutation of that static while the reference lives, that's UB; use `addr_of!` instead to create a raw pointer
+   = note: this will be a hard error in the 2024 edition
+   = note: this shared reference has lifetime `'static`, but if the static ever gets mutated, or a mutable reference is created, then any further use of this shared reference is Undefined Behavior
+help: use `addr_of!` instead to create a raw pointer
    |
 LL |     let xrb = addr_of!(XB);
    |               ~~~~~~~~~~~~
diff --git a/tests/ui/statics/issue-15261.rs b/tests/ui/statics/issue-15261.rs
index 71eeb2a6d26..e168abce078 100644
--- a/tests/ui/statics/issue-15261.rs
+++ b/tests/ui/statics/issue-15261.rs
@@ -7,6 +7,6 @@
 static mut n_mut: usize = 0;
 
 static n: &'static usize = unsafe { &n_mut };
-//~^ WARN shared reference of mutable static is discouraged [static_mut_ref]
+//~^ WARN shared reference to mutable static is discouraged [static_mut_refs]
 
 fn main() {}
diff --git a/tests/ui/statics/issue-15261.stderr b/tests/ui/statics/issue-15261.stderr
index 72d88ce1b38..c31793f3d8f 100644
--- a/tests/ui/statics/issue-15261.stderr
+++ b/tests/ui/statics/issue-15261.stderr
@@ -1,14 +1,14 @@
-warning: shared reference of mutable static is discouraged
+warning: creating a shared reference to mutable static is discouraged
   --> $DIR/issue-15261.rs:9:37
    |
 LL | static n: &'static usize = unsafe { &n_mut };
-   |                                     ^^^^^^ shared reference of mutable static
+   |                                     ^^^^^^ shared reference to mutable static
    |
    = note: for more information, see issue #114447 <https://github.com/rust-lang/rust/issues/114447>
-   = note: reference of mutable static is a hard error from 2024 edition
-   = note: mutable statics can be written to by multiple threads: aliasing violations or data races will cause undefined behavior
-   = note: `#[warn(static_mut_ref)]` on by default
-help: shared references are dangerous since if there's any kind of mutation of that static while the reference lives, that's UB; use `addr_of!` instead to create a raw pointer
+   = note: this will be a hard error in the 2024 edition
+   = note: this shared reference has lifetime `'static`, but if the static ever gets mutated, or a mutable reference is created, then any further use of this shared reference is Undefined Behavior
+   = note: `#[warn(static_mut_refs)]` on by default
+help: use `addr_of!` instead to create a raw pointer
    |
 LL | static n: &'static usize = unsafe { addr_of!(n_mut) };
    |                                     ~~~~~~~~~~~~~~~
diff --git a/tests/ui/statics/static-mut-xc.rs b/tests/ui/statics/static-mut-xc.rs
index 75a4faed83d..a772d4151f7 100644
--- a/tests/ui/statics/static-mut-xc.rs
+++ b/tests/ui/statics/static-mut-xc.rs
@@ -26,9 +26,9 @@ unsafe fn run() {
     static_mut_xc::a = -3;
     assert_eq!(static_mut_xc::a, -3);
     static_bound(&static_mut_xc::a);
-    //~^ WARN shared reference of mutable static is discouraged [static_mut_ref]
+    //~^ WARN shared reference to mutable static is discouraged [static_mut_refs]
     static_bound_set(&mut static_mut_xc::a);
-    //~^ WARN mutable reference of mutable static is discouraged [static_mut_ref]
+    //~^ WARN mutable reference to mutable static is discouraged [static_mut_refs]
 }
 
 pub fn main() {
diff --git a/tests/ui/statics/static-mut-xc.stderr b/tests/ui/statics/static-mut-xc.stderr
index 37aa336bc50..d381328c071 100644
--- a/tests/ui/statics/static-mut-xc.stderr
+++ b/tests/ui/statics/static-mut-xc.stderr
@@ -1,28 +1,28 @@
-warning: shared reference of mutable static is discouraged
+warning: creating a shared reference to mutable static is discouraged
   --> $DIR/static-mut-xc.rs:28:18
    |
 LL |     static_bound(&static_mut_xc::a);
-   |                  ^^^^^^^^^^^^^^^^^ shared reference of mutable static
+   |                  ^^^^^^^^^^^^^^^^^ shared reference to mutable static
    |
    = note: for more information, see issue #114447 <https://github.com/rust-lang/rust/issues/114447>
-   = note: reference of mutable static is a hard error from 2024 edition
-   = note: mutable statics can be written to by multiple threads: aliasing violations or data races will cause undefined behavior
-   = note: `#[warn(static_mut_ref)]` on by default
-help: shared references are dangerous since if there's any kind of mutation of that static while the reference lives, that's UB; use `addr_of!` instead to create a raw pointer
+   = note: this will be a hard error in the 2024 edition
+   = note: this shared reference has lifetime `'static`, but if the static ever gets mutated, or a mutable reference is created, then any further use of this shared reference is Undefined Behavior
+   = note: `#[warn(static_mut_refs)]` on by default
+help: use `addr_of!` instead to create a raw pointer
    |
 LL |     static_bound(addr_of!(static_mut_xc::a));
    |                  ~~~~~~~~~~~~~~~~~~~~~~~~~~
 
-warning: mutable reference of mutable static is discouraged
+warning: creating a mutable reference to mutable static is discouraged
   --> $DIR/static-mut-xc.rs:30:22
    |
 LL |     static_bound_set(&mut static_mut_xc::a);
-   |                      ^^^^^^^^^^^^^^^^^^^^^ mutable reference of mutable static
+   |                      ^^^^^^^^^^^^^^^^^^^^^ mutable reference to mutable static
    |
    = note: for more information, see issue #114447 <https://github.com/rust-lang/rust/issues/114447>
-   = note: reference of mutable static is a hard error from 2024 edition
-   = note: mutable statics can be written to by multiple threads: aliasing violations or data races will cause undefined behavior
-help: mutable references are dangerous since if there's any other pointer or reference used for that static while the reference lives, that's UB; use `addr_of_mut!` instead to create a raw pointer
+   = note: this will be a hard error in the 2024 edition
+   = note: this mutable reference has lifetime `'static`, but if the static gets accessed (read or written) by any other means, or any other reference is created, then any further use of this mutable reference is Undefined Behavior
+help: use `addr_of_mut!` instead to create a raw pointer
    |
 LL |     static_bound_set(addr_of_mut!(static_mut_xc::a));
    |                      ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
diff --git a/tests/ui/statics/static-recursive.rs b/tests/ui/statics/static-recursive.rs
index f504e2a79f0..29b80818b7d 100644
--- a/tests/ui/statics/static-recursive.rs
+++ b/tests/ui/statics/static-recursive.rs
@@ -1,7 +1,7 @@
 //@ run-pass
 
 static mut S: *const u8 = unsafe { &S as *const *const u8 as *const u8 };
-//~^ WARN shared reference of mutable static is discouraged [static_mut_ref]
+//~^ WARN shared reference to mutable static is discouraged [static_mut_refs]
 
 struct StaticDoubleLinked {
     prev: &'static StaticDoubleLinked,
diff --git a/tests/ui/statics/static-recursive.stderr b/tests/ui/statics/static-recursive.stderr
index 15888e5c68d..cd285c6c2a4 100644
--- a/tests/ui/statics/static-recursive.stderr
+++ b/tests/ui/statics/static-recursive.stderr
@@ -1,14 +1,14 @@
-warning: shared reference of mutable static is discouraged
+warning: creating a shared reference to mutable static is discouraged
   --> $DIR/static-recursive.rs:3:36
    |
 LL | static mut S: *const u8 = unsafe { &S as *const *const u8 as *const u8 };
-   |                                    ^^ shared reference of mutable static
+   |                                    ^^ shared reference to mutable static
    |
    = note: for more information, see issue #114447 <https://github.com/rust-lang/rust/issues/114447>
-   = note: reference of mutable static is a hard error from 2024 edition
-   = note: mutable statics can be written to by multiple threads: aliasing violations or data races will cause undefined behavior
-   = note: `#[warn(static_mut_ref)]` on by default
-help: shared references are dangerous since if there's any kind of mutation of that static while the reference lives, that's UB; use `addr_of!` instead to create a raw pointer
+   = note: this will be a hard error in the 2024 edition
+   = note: this shared reference has lifetime `'static`, but if the static ever gets mutated, or a mutable reference is created, then any further use of this shared reference is Undefined Behavior
+   = note: `#[warn(static_mut_refs)]` on by default
+help: use `addr_of!` instead to create a raw pointer
    |
 LL | static mut S: *const u8 = unsafe { addr_of!(S) as *const *const u8 as *const u8 };
    |                                    ~~~~~~~~~~~
diff --git a/tests/ui/suggestions/issue-84973-blacklist.stderr b/tests/ui/suggestions/issue-84973-blacklist.stderr
index 8e980997089..33338228328 100644
--- a/tests/ui/suggestions/issue-84973-blacklist.stderr
+++ b/tests/ui/suggestions/issue-84973-blacklist.stderr
@@ -11,6 +11,11 @@ note: required by a bound in `f_copy`
    |
 LL | fn f_copy<T: Copy>(t: T) {}
    |              ^^^^ required by this bound in `f_copy`
+help: consider removing this method call, as the receiver has type `&'static str` and `&'static str: Copy` trivially holds
+   |
+LL -     f_copy("".to_string());
+LL +     f_copy("");
+   |
 
 error[E0277]: the trait bound `S: Clone` is not satisfied
   --> $DIR/issue-84973-blacklist.rs:16:13
diff --git a/tests/ui/thread-local/thread-local-static.rs b/tests/ui/thread-local/thread-local-static.rs
index a1b72323f71..05df0471b14 100644
--- a/tests/ui/thread-local/thread-local-static.rs
+++ b/tests/ui/thread-local/thread-local-static.rs
@@ -2,7 +2,7 @@
 
 #![feature(thread_local)]
 #![feature(const_swap)]
-#![allow(static_mut_ref)]
+#![allow(static_mut_refs)]
 
 #[thread_local]
 static mut STATIC_VAR_2: [u32; 8] = [4; 8];
diff --git a/tests/ui/trait-bounds/argument-with-unnecessary-method-call.rs b/tests/ui/trait-bounds/argument-with-unnecessary-method-call.rs
new file mode 100644
index 00000000000..d8fd1d44a98
--- /dev/null
+++ b/tests/ui/trait-bounds/argument-with-unnecessary-method-call.rs
@@ -0,0 +1,11 @@
+struct Foo;
+struct Bar;
+impl From<Bar> for Foo {
+    fn from(_: Bar) -> Self { Foo }
+}
+fn qux(_: impl From<Bar>) {}
+fn main() {
+    qux(Bar.into()); //~ ERROR type annotations needed
+    //~| HELP try using a fully qualified path to specify the expected types
+    //~| HELP consider removing this method call, as the receiver has type `Bar` and `Bar: From<Bar>` trivially holds
+}
diff --git a/tests/ui/trait-bounds/argument-with-unnecessary-method-call.stderr b/tests/ui/trait-bounds/argument-with-unnecessary-method-call.stderr
new file mode 100644
index 00000000000..49230c98a12
--- /dev/null
+++ b/tests/ui/trait-bounds/argument-with-unnecessary-method-call.stderr
@@ -0,0 +1,27 @@
+error[E0283]: type annotations needed
+  --> $DIR/argument-with-unnecessary-method-call.rs:8:13
+   |
+LL |     qux(Bar.into());
+   |     ---     ^^^^
+   |     |
+   |     required by a bound introduced by this call
+   |
+   = note: cannot satisfy `_: From<Bar>`
+note: required by a bound in `qux`
+  --> $DIR/argument-with-unnecessary-method-call.rs:6:16
+   |
+LL | fn qux(_: impl From<Bar>) {}
+   |                ^^^^^^^^^ required by this bound in `qux`
+help: try using a fully qualified path to specify the expected types
+   |
+LL |     qux(<Bar as Into<T>>::into(Bar));
+   |         +++++++++++++++++++++++   ~
+help: consider removing this method call, as the receiver has type `Bar` and `Bar: From<Bar>` trivially holds
+   |
+LL -     qux(Bar.into());
+LL +     qux(Bar);
+   |
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0283`.
diff --git a/tests/ui/type/type-check/issue-88577-check-fn-with-more-than-65535-arguments.stderr b/tests/ui/type/type-check/issue-88577-check-fn-with-more-than-65535-arguments.stderr
index 1ef02321e15..1a3848bbcf5 100644
--- a/tests/ui/type/type-check/issue-88577-check-fn-with-more-than-65535-arguments.stderr
+++ b/tests/ui/type/type-check/issue-88577-check-fn-with-more-than-65535-arguments.stderr
@@ -1,8 +1,8 @@
 error: function can not have more than 65535 arguments
-  --> $DIR/issue-88577-check-fn-with-more-than-65535-arguments.rs:6:22
+  --> $DIR/issue-88577-check-fn-with-more-than-65535-arguments.rs:6:17
    |
 LL |         fn _f($($t: ()),*) {}
-   |                      ^
+   |                 ^^^^^^
 ...
 LL | many_args!{[_]########## ######}
    | -------------------------------- in this macro invocation
diff --git a/tests/ui/typeck/issue-116473-ice-wrong-span-variant-args.rs b/tests/ui/typeck/issue-116473-ice-wrong-span-variant-args.rs
index c319c63eda2..cc66b5fd6f2 100644
--- a/tests/ui/typeck/issue-116473-ice-wrong-span-variant-args.rs
+++ b/tests/ui/typeck/issue-116473-ice-wrong-span-variant-args.rs
@@ -58,12 +58,12 @@ macro_rules! nested2_ident {
 // instead of the enum variant
 macro_rules! nested1_tt_args_in_first_macro {
     () => (nested2_tt_args_in_first_macro!(i32, u32));
+    //~^ ERROR type arguments are not allowed on this type
 }
 
 macro_rules! nested2_tt_args_in_first_macro {
     ($arg1:tt, $arg2:tt) => (if let EnumUnit::VariantB::<$arg1, $arg2> {}
-    //~^ ERROR type arguments are not allowed on this type
-    //~| ERROR mismatched types
+    //~^ ERROR mismatched types
             = 5 { true } else { false });
 }
 
diff --git a/tests/ui/typeck/issue-116473-ice-wrong-span-variant-args.stderr b/tests/ui/typeck/issue-116473-ice-wrong-span-variant-args.stderr
index b17936ee3d3..cb7666657ef 100644
--- a/tests/ui/typeck/issue-116473-ice-wrong-span-variant-args.stderr
+++ b/tests/ui/typeck/issue-116473-ice-wrong-span-variant-args.stderr
@@ -1,10 +1,10 @@
 error[E0109]: type arguments are not allowed on this type
   --> $DIR/issue-116473-ice-wrong-span-variant-args.rs:15:51
    |
+LL |     () => (recursive_tt!(VariantB));
+   |                          -------- not allowed on this type
 LL |     ($variant:tt) => (if let EnumUnit::$variant::<i32, u32> {} = 5 { true } else { false });
-   |                                        --------   ^^^  ^^^ type argument not allowed
-   |                                        |
-   |                                        not allowed on this type
+   |                                                   ^^^  ^^^ type argument not allowed
 ...
 LL |     recursive_tt!();
    |     --------------- in this macro invocation
@@ -69,10 +69,11 @@ LL |     recursive_ident!();
 error[E0109]: type arguments are not allowed on this type
   --> $DIR/issue-116473-ice-wrong-span-variant-args.rs:38:51
    |
+LL |     () => (nested2_tt!(VariantB));
+   |                        -------- not allowed on this type
+...
 LL |     ($variant:tt) => (if let EnumUnit::$variant::<i32, u32> {} = 5 { true } else { false });
-   |                                        --------   ^^^  ^^^ type argument not allowed
-   |                                        |
-   |                                        not allowed on this type
+   |                                                   ^^^  ^^^ type argument not allowed
 ...
 LL |     nested1_tt!();
    |     ------------- in this macro invocation
@@ -136,12 +137,13 @@ LL |     nested1_ident!();
    = note: this error originates in the macro `nested2_ident` which comes from the expansion of the macro `nested1_ident` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error[E0109]: type arguments are not allowed on this type
-  --> $DIR/issue-116473-ice-wrong-span-variant-args.rs:64:58
+  --> $DIR/issue-116473-ice-wrong-span-variant-args.rs:60:44
    |
+LL |     () => (nested2_tt_args_in_first_macro!(i32, u32));
+   |                                            ^^^  ^^^ type argument not allowed
+...
 LL |     ($arg1:tt, $arg2:tt) => (if let EnumUnit::VariantB::<$arg1, $arg2> {}
-   |                                               --------   ^^^^^  ^^^^^ type argument not allowed
-   |                                               |
-   |                                               not allowed on this type
+   |                                               -------- not allowed on this type
 ...
 LL |     nested1_tt_args_in_first_macro!();
    |     --------------------------------- in this macro invocation
@@ -155,11 +157,11 @@ LL +     ($arg1:tt, $arg2:tt) => (if let EnumUnit::<$arg1, $arg2>::VariantB {}
    |
 
 error[E0308]: mismatched types
-  --> $DIR/issue-116473-ice-wrong-span-variant-args.rs:64:37
+  --> $DIR/issue-116473-ice-wrong-span-variant-args.rs:65:37
    |
 LL |     ($arg1:tt, $arg2:tt) => (if let EnumUnit::VariantB::<$arg1, $arg2> {}
    |                                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected integer, found `Enum<(), ()>`
-...
+LL |
 LL |             = 5 { true } else { false });
    |               - this expression has type `{integer}`
 ...
diff --git a/tests/ui/union/unnamed-fields/auxiliary/dep.rs b/tests/ui/union/unnamed-fields/auxiliary/dep.rs
new file mode 100644
index 00000000000..a11f3e18f52
--- /dev/null
+++ b/tests/ui/union/unnamed-fields/auxiliary/dep.rs
@@ -0,0 +1,18 @@
+#[repr(C)]
+pub struct GoodStruct(());
+
+pub struct BadStruct(());
+
+pub enum BadEnum {
+    A,
+    B,
+}
+
+#[repr(C)]
+pub enum BadEnum2 {
+    A,
+    B,
+}
+
+pub type GoodAlias = GoodStruct;
+pub type BadAlias = i32;
diff --git a/tests/ui/union/unnamed-fields/restrict_type_hir.rs b/tests/ui/union/unnamed-fields/restrict_type_hir.rs
new file mode 100644
index 00000000000..80e4608be82
--- /dev/null
+++ b/tests/ui/union/unnamed-fields/restrict_type_hir.rs
@@ -0,0 +1,44 @@
+//@ aux-build:dep.rs
+
+// test for #121151
+
+#![allow(incomplete_features)]
+#![feature(unnamed_fields)]
+
+extern crate dep;
+
+#[repr(C)]
+struct A {
+    a: u8,
+}
+
+enum BadEnum {
+    A,
+    B,
+}
+
+#[repr(C)]
+enum BadEnum2 {
+    A,
+    B,
+}
+
+type MyStruct = A;
+type MyI32 = i32;
+
+#[repr(C)]
+struct L {
+    _: i32, //~ ERROR unnamed fields can only have struct or union types
+    _: MyI32, //~ ERROR unnamed fields can only have struct or union types
+    _: BadEnum, //~ ERROR unnamed fields can only have struct or union types
+    _: BadEnum2, //~ ERROR unnamed fields can only have struct or union types
+    _: MyStruct,
+    _: dep::BadStruct, //~ ERROR named type of unnamed field must have `#[repr(C)]` representation
+    _: dep::BadEnum, //~ ERROR unnamed fields can only have struct or union types
+    _: dep::BadEnum2, //~ ERROR unnamed fields can only have struct or union types
+    _: dep::BadAlias, //~ ERROR unnamed fields can only have struct or union types
+    _: dep::GoodAlias,
+    _: dep::GoodStruct,
+}
+
+fn main() {}
diff --git a/tests/ui/union/unnamed-fields/restrict_type_hir.stderr b/tests/ui/union/unnamed-fields/restrict_type_hir.stderr
new file mode 100644
index 00000000000..3e80d7fbf5c
--- /dev/null
+++ b/tests/ui/union/unnamed-fields/restrict_type_hir.stderr
@@ -0,0 +1,62 @@
+error: unnamed fields can only have struct or union types
+  --> $DIR/restrict_type_hir.rs:31:5
+   |
+LL |     _: i32,
+   |     ^^^^^^
+
+error: unnamed fields can only have struct or union types
+  --> $DIR/restrict_type_hir.rs:32:5
+   |
+LL |     _: MyI32,
+   |     ^^^^^^^^
+
+error: unnamed fields can only have struct or union types
+  --> $DIR/restrict_type_hir.rs:33:5
+   |
+LL |     _: BadEnum,
+   |     ^^^^^^^^^^
+
+error: unnamed fields can only have struct or union types
+  --> $DIR/restrict_type_hir.rs:34:5
+   |
+LL |     _: BadEnum2,
+   |     ^^^^^^^^^^^
+
+error: named type of unnamed field must have `#[repr(C)]` representation
+  --> $DIR/restrict_type_hir.rs:36:5
+   |
+LL |     _: dep::BadStruct,
+   |     ^^^^^^^^^^^^^^^^^ unnamed field defined here
+   |
+  ::: $DIR/auxiliary/dep.rs:4:1
+   |
+LL | pub struct BadStruct(());
+   | -------------------- `BadStruct` defined here
+   |
+help: add `#[repr(C)]` to this struct
+  --> $DIR/auxiliary/dep.rs:4:1
+   |
+LL + #[repr(C)]
+LL | pub struct BadStruct(());
+   |
+
+error: unnamed fields can only have struct or union types
+  --> $DIR/restrict_type_hir.rs:37:5
+   |
+LL |     _: dep::BadEnum,
+   |     ^^^^^^^^^^^^^^^
+
+error: unnamed fields can only have struct or union types
+  --> $DIR/restrict_type_hir.rs:38:5
+   |
+LL |     _: dep::BadEnum2,
+   |     ^^^^^^^^^^^^^^^^
+
+error: unnamed fields can only have struct or union types
+  --> $DIR/restrict_type_hir.rs:39:5
+   |
+LL |     _: dep::BadAlias,
+   |     ^^^^^^^^^^^^^^^^
+
+error: aborting due to 8 previous errors
+