about summary refs log tree commit diff
path: root/src/tools
diff options
context:
space:
mode:
authorThe Miri Cronjob Bot <miri@cron.bot>2025-06-28 05:02:19 +0000
committerThe Miri Cronjob Bot <miri@cron.bot>2025-06-28 05:02:19 +0000
commit3d8d4d4545996f6b43c47d1f0b867dacf20a5b48 (patch)
tree99983ba704aaaa6d8743ead87e86f08293946e94 /src/tools
parent34949e30d30e1751a070606f87cb0cc8bd478625 (diff)
parentd41e12f1f4e4884c356f319b881921aa37040de5 (diff)
downloadrust-3d8d4d4545996f6b43c47d1f0b867dacf20a5b48.tar.gz
rust-3d8d4d4545996f6b43c47d1f0b867dacf20a5b48.zip
Merge from rustc
Diffstat (limited to 'src/tools')
m---------src/tools/cargo0
-rw-r--r--src/tools/clippy/.github/ISSUE_TEMPLATE/new_lint.yml4
-rw-r--r--src/tools/clippy/.github/PULL_REQUEST_TEMPLATE.md4
-rw-r--r--src/tools/clippy/.github/workflows/feature_freeze.yml25
-rw-r--r--src/tools/clippy/CHANGELOG.md91
-rw-r--r--src/tools/clippy/Cargo.toml4
-rw-r--r--src/tools/clippy/book/src/README.md4
-rw-r--r--src/tools/clippy/book/src/SUMMARY.md1
-rw-r--r--src/tools/clippy/book/src/development/adding_lints.md3
-rw-r--r--src/tools/clippy/book/src/development/feature_freeze.md55
-rw-r--r--src/tools/clippy/book/src/lint_configuration.md24
-rw-r--r--src/tools/clippy/clippy_config/Cargo.toml2
-rw-r--r--src/tools/clippy/clippy_config/src/conf.rs25
-rw-r--r--src/tools/clippy/clippy_dev/src/lint.rs4
-rw-r--r--src/tools/clippy/clippy_dev/src/release.rs1
-rw-r--r--src/tools/clippy/clippy_dev/src/serve.rs2
-rw-r--r--src/tools/clippy/clippy_dev/src/update_lints.rs290
-rw-r--r--src/tools/clippy/clippy_dev/src/utils.rs15
-rw-r--r--src/tools/clippy/clippy_lints/Cargo.toml3
-rw-r--r--src/tools/clippy/clippy_lints/src/attrs/inline_always.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/attrs/mod.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/attrs/utils.rs12
-rw-r--r--src/tools/clippy/clippy_lints/src/bool_assert_comparison.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/borrow_deref_ref.rs15
-rw-r--r--src/tools/clippy/clippy_lints/src/casts/cast_sign_loss.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/casts/manual_dangling_ptr.rs5
-rw-r--r--src/tools/clippy/clippy_lints/src/collapsible_if.rs127
-rw-r--r--src/tools/clippy/clippy_lints/src/copies.rs18
-rw-r--r--src/tools/clippy/clippy_lints/src/declare_clippy_lint.rs168
-rw-r--r--src/tools/clippy/clippy_lints/src/declared_lints.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/disallowed_macros.rs3
-rw-r--r--src/tools/clippy/clippy_lints/src/disallowed_methods.rs3
-rw-r--r--src/tools/clippy/clippy_lints/src/disallowed_types.rs3
-rw-r--r--src/tools/clippy/clippy_lints/src/doc/broken_link.rs83
-rw-r--r--src/tools/clippy/clippy_lints/src/doc/doc_suspicious_footnotes.rs9
-rw-r--r--src/tools/clippy/clippy_lints/src/doc/mod.rs54
-rw-r--r--src/tools/clippy/clippy_lints/src/doc/needless_doctest_main.rs32
-rw-r--r--src/tools/clippy/clippy_lints/src/empty_line_after.rs64
-rw-r--r--src/tools/clippy/clippy_lints/src/eta_reduction.rs97
-rw-r--r--src/tools/clippy/clippy_lints/src/exhaustive_items.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/floating_point_arithmetic.rs3
-rw-r--r--src/tools/clippy/clippy_lints/src/functions/must_use.rs68
-rw-r--r--src/tools/clippy/clippy_lints/src/if_not_else.rs11
-rw-r--r--src/tools/clippy/clippy_lints/src/inline_fn_without_body.rs10
-rw-r--r--src/tools/clippy/clippy_lints/src/lib.rs126
-rw-r--r--src/tools/clippy/clippy_lints/src/loops/same_item_push.rs15
-rw-r--r--src/tools/clippy/clippy_lints/src/manual_let_else.rs1
-rw-r--r--src/tools/clippy/clippy_lints/src/manual_option_as_slice.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/matches/manual_ok_err.rs20
-rw-r--r--src/tools/clippy/clippy_lints/src/matches/match_wild_enum.rs14
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/io_other_error.rs9
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/mod.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/or_fun_call.rs11
-rw-r--r--src/tools/clippy/clippy_lints/src/missing_inline.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/needless_borrows_for_generic_args.rs12
-rw-r--r--src/tools/clippy/clippy_lints/src/needless_parens_on_range_literals.rs1
-rw-r--r--src/tools/clippy/clippy_lints/src/needless_pass_by_value.rs6
-rw-r--r--src/tools/clippy/clippy_lints/src/no_mangle_with_rust_abi.rs8
-rw-r--r--src/tools/clippy/clippy_lints/src/non_copy_const.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/operators/identity_op.rs76
-rw-r--r--src/tools/clippy/clippy_lints/src/operators/manual_is_multiple_of.rs66
-rw-r--r--src/tools/clippy/clippy_lints/src/operators/mod.rs33
-rw-r--r--src/tools/clippy/clippy_lints/src/pass_by_ref_or_value.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/question_mark.rs1
-rw-r--r--src/tools/clippy/clippy_lints/src/question_mark_used.rs1
-rw-r--r--src/tools/clippy/clippy_lints/src/read_zero_byte_vec.rs3
-rw-r--r--src/tools/clippy/clippy_lints/src/return_self_not_must_use.rs8
-rw-r--r--src/tools/clippy/clippy_lints/src/single_component_path_imports.rs29
-rw-r--r--src/tools/clippy/clippy_lints/src/single_range_in_vec_init.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/to_digit_is_some.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/undocumented_unsafe_blocks.rs45
-rw-r--r--src/tools/clippy/clippy_lints/src/useless_concat.rs5
-rw-r--r--src/tools/clippy/clippy_utils/Cargo.toml2
-rw-r--r--src/tools/clippy/clippy_utils/README.md2
-rw-r--r--src/tools/clippy/clippy_utils/src/consts.rs15
-rw-r--r--src/tools/clippy/clippy_utils/src/diagnostics.rs6
-rw-r--r--src/tools/clippy/clippy_utils/src/lib.rs19
-rw-r--r--src/tools/clippy/clippy_utils/src/msrvs.rs3
-rw-r--r--src/tools/clippy/clippy_utils/src/paths.rs9
-rw-r--r--src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs17
-rw-r--r--src/tools/clippy/clippy_utils/src/sugg.rs22
-rw-r--r--src/tools/clippy/clippy_utils/src/sym.rs5
-rw-r--r--src/tools/clippy/clippy_utils/src/ty/mod.rs16
-rw-r--r--src/tools/clippy/declare_clippy_lint/Cargo.toml10
-rw-r--r--src/tools/clippy/declare_clippy_lint/src/lib.rs280
-rw-r--r--src/tools/clippy/lintcheck/src/main.rs2
-rw-r--r--src/tools/clippy/rust-toolchain.toml2
-rw-r--r--src/tools/clippy/src/driver.rs43
-rw-r--r--src/tools/clippy/src/main.rs2
-rw-r--r--src/tools/clippy/tests/compile-test.rs6
-rw-r--r--src/tools/clippy/tests/dogfood.rs1
-rw-r--r--src/tools/clippy/tests/ui-toml/collapsible_if/collapsible_else_if.fixed50
-rw-r--r--src/tools/clippy/tests/ui-toml/collapsible_if/collapsible_else_if.rs55
-rw-r--r--src/tools/clippy/tests/ui-toml/collapsible_if/collapsible_else_if.stderr105
-rw-r--r--src/tools/clippy/tests/ui/assign_ops.fixed2
-rw-r--r--src/tools/clippy/tests/ui/assign_ops.rs2
-rw-r--r--src/tools/clippy/tests/ui/borrow_deref_ref.fixed47
-rw-r--r--src/tools/clippy/tests/ui/borrow_deref_ref.rs47
-rw-r--r--src/tools/clippy/tests/ui/borrow_deref_ref.stderr32
-rw-r--r--src/tools/clippy/tests/ui/borrow_interior_mutable_const.rs16
-rw-r--r--src/tools/clippy/tests/ui/box_default.fixed2
-rw-r--r--src/tools/clippy/tests/ui/box_default.rs2
-rw-r--r--src/tools/clippy/tests/ui/branches_sharing_code/shared_at_bottom.rs24
-rw-r--r--src/tools/clippy/tests/ui/branches_sharing_code/shared_at_bottom.stderr32
-rw-r--r--src/tools/clippy/tests/ui/collapsible_else_if.fixed18
-rw-r--r--src/tools/clippy/tests/ui/collapsible_else_if.rs18
-rw-r--r--src/tools/clippy/tests/ui/collapsible_if.fixed9
-rw-r--r--src/tools/clippy/tests/ui/collapsible_if.rs9
-rw-r--r--src/tools/clippy/tests/ui/doc/needless_doctest_main.rs112
-rw-r--r--src/tools/clippy/tests/ui/doc/needless_doctest_main.stderr36
-rw-r--r--src/tools/clippy/tests/ui/doc_broken_link.rs72
-rw-r--r--src/tools/clippy/tests/ui/doc_broken_link.stderr29
-rw-r--r--src/tools/clippy/tests/ui/empty_line_after/outer_attribute.1.fixed9
-rw-r--r--src/tools/clippy/tests/ui/empty_line_after/outer_attribute.2.fixed9
-rw-r--r--src/tools/clippy/tests/ui/empty_line_after/outer_attribute.rs10
-rw-r--r--src/tools/clippy/tests/ui/empty_line_after/outer_attribute.stderr13
-rw-r--r--src/tools/clippy/tests/ui/eta.fixed18
-rw-r--r--src/tools/clippy/tests/ui/eta.rs18
-rw-r--r--src/tools/clippy/tests/ui/exhaustive_items.fixed7
-rw-r--r--src/tools/clippy/tests/ui/exhaustive_items.rs7
-rw-r--r--src/tools/clippy/tests/ui/exhaustive_items.stderr10
-rw-r--r--src/tools/clippy/tests/ui/identity_op.fixed46
-rw-r--r--src/tools/clippy/tests/ui/identity_op.rs46
-rw-r--r--src/tools/clippy/tests/ui/identity_op.stderr44
-rw-r--r--src/tools/clippy/tests/ui/infinite_iter.rs2
-rw-r--r--src/tools/clippy/tests/ui/infinite_iter.stderr4
-rw-r--r--src/tools/clippy/tests/ui/iter_kv_map.fixed20
-rw-r--r--src/tools/clippy/tests/ui/iter_kv_map.rs20
-rw-r--r--src/tools/clippy/tests/ui/iter_kv_map.stderr64
-rw-r--r--src/tools/clippy/tests/ui/let_unit.fixed2
-rw-r--r--src/tools/clippy/tests/ui/let_unit.rs2
-rw-r--r--src/tools/clippy/tests/ui/let_unit.stderr2
-rw-r--r--src/tools/clippy/tests/ui/manual_contains.fixed2
-rw-r--r--src/tools/clippy/tests/ui/manual_contains.rs2
-rw-r--r--src/tools/clippy/tests/ui/manual_find_fixable.fixed4
-rw-r--r--src/tools/clippy/tests/ui/manual_find_fixable.rs4
-rw-r--r--src/tools/clippy/tests/ui/manual_find_fixable.stderr4
-rw-r--r--src/tools/clippy/tests/ui/manual_is_multiple_of.fixed25
-rw-r--r--src/tools/clippy/tests/ui/manual_is_multiple_of.rs25
-rw-r--r--src/tools/clippy/tests/ui/manual_is_multiple_of.stderr41
-rw-r--r--src/tools/clippy/tests/ui/manual_is_variant_and.fixed8
-rw-r--r--src/tools/clippy/tests/ui/manual_is_variant_and.rs8
-rw-r--r--src/tools/clippy/tests/ui/manual_is_variant_and.stderr12
-rw-r--r--src/tools/clippy/tests/ui/manual_ok_err.fixed24
-rw-r--r--src/tools/clippy/tests/ui/manual_ok_err.rs36
-rw-r--r--src/tools/clippy/tests/ui/manual_ok_err.stderr32
-rw-r--r--src/tools/clippy/tests/ui/missing_const_for_fn/const_trait.fixed2
-rw-r--r--src/tools/clippy/tests/ui/missing_const_for_fn/const_trait.rs2
-rw-r--r--src/tools/clippy/tests/ui/missing_const_for_fn/could_be_const.fixed57
-rw-r--r--src/tools/clippy/tests/ui/missing_const_for_fn/could_be_const.rs57
-rw-r--r--src/tools/clippy/tests/ui/missing_const_for_fn/could_be_const.stderr72
-rw-r--r--src/tools/clippy/tests/ui/nonminimal_bool.stderr4
-rw-r--r--src/tools/clippy/tests/ui/or_fun_call.fixed30
-rw-r--r--src/tools/clippy/tests/ui/or_fun_call.rs30
-rw-r--r--src/tools/clippy/tests/ui/or_fun_call.stderr96
-rw-r--r--src/tools/clippy/tests/ui/question_mark.fixed12
-rw-r--r--src/tools/clippy/tests/ui/question_mark.rs12
-rw-r--r--src/tools/clippy/tests/ui/trait_duplication_in_bounds.fixed4
-rw-r--r--src/tools/clippy/tests/ui/trait_duplication_in_bounds.rs4
-rw-r--r--src/tools/clippy/tests/ui/trait_duplication_in_bounds.stderr4
-rw-r--r--src/tools/clippy/tests/ui/unnecessary_os_str_debug_formatting.rs13
-rw-r--r--src/tools/clippy/tests/ui/unnecessary_os_str_debug_formatting.stderr11
-rw-r--r--src/tools/clippy/tests/ui/wildcard_enum_match_arm.fixed29
-rw-r--r--src/tools/clippy/tests/ui/wildcard_enum_match_arm.rs29
-rw-r--r--src/tools/clippy/tests/ui/wildcard_enum_match_arm.stderr14
-rw-r--r--src/tools/clippy/tests/versioncheck.rs1
-rw-r--r--src/tools/clippy/triagebot.toml3
-rwxr-xr-xsrc/tools/clippy/util/versions.py6
-rw-r--r--src/tools/compiletest/src/errors.rs46
-rw-r--r--src/tools/compiletest/src/executor.rs6
-rw-r--r--src/tools/compiletest/src/header.rs2
-rw-r--r--src/tools/compiletest/src/json.rs40
-rw-r--r--src/tools/compiletest/src/runtest.rs147
-rw-r--r--src/tools/compiletest/src/runtest/run_make.rs4
m---------src/tools/enzyme0
-rw-r--r--src/tools/jsondoclint/src/validator.rs13
-rwxr-xr-xsrc/tools/linkchecker/linkcheck.sh1
-rw-r--r--src/tools/lint-docs/Cargo.toml2
-rw-r--r--src/tools/lint-docs/src/lib.rs4
-rw-r--r--src/tools/miri/cargo-miri/src/setup.rs2
-rw-r--r--src/tools/miri/src/bin/miri.rs1
-rw-r--r--src/tools/miri/src/borrow_tracker/stacked_borrows/mod.rs2
-rw-r--r--src/tools/miri/src/borrow_tracker/tree_borrows/mod.rs2
-rw-r--r--src/tools/miri/src/eval.rs2
-rw-r--r--src/tools/miri/src/helpers.rs4
-rw-r--r--src/tools/miri/src/intrinsics/simd.rs1
-rw-r--r--src/tools/miri/src/shims/backtrace.rs1
-rw-r--r--src/tools/miri/src/shims/os_str.rs1
-rw-r--r--src/tools/miri/src/shims/unix/env.rs1
-rw-r--r--src/tools/miri/src/shims/unix/foreign_items.rs1
-rw-r--r--src/tools/miri/src/shims/windows/thread.rs1
-rw-r--r--src/tools/miri/src/shims/x86/aesni.rs1
-rw-r--r--src/tools/miri/src/shims/x86/avx.rs1
-rw-r--r--src/tools/miri/src/shims/x86/avx2.rs1
-rw-r--r--src/tools/miri/src/shims/x86/mod.rs1
-rw-r--r--src/tools/miri/src/shims/x86/sse42.rs1
-rw-r--r--src/tools/run-make-support/src/lib.rs2
-rw-r--r--src/tools/run-make-support/src/run.rs25
-rw-r--r--src/tools/run-make-support/src/targets.rs6
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/db.rs17
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/expr_store/lower.rs227
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/expr_store/tests/body.rs138
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/expr_store/tests/body/block.rs4
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/lib.rs21
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/infer/closure.rs6
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/layout.rs2
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/tests/closure_captures.rs19
-rw-r--r--src/tools/rust-analyzer/crates/hir/src/attrs.rs12
-rw-r--r--src/tools/rust-analyzer/crates/hir/src/diagnostics.rs80
-rw-r--r--src/tools/rust-analyzer/crates/hir/src/display.rs4
-rw-r--r--src/tools/rust-analyzer/crates/hir/src/has_source.rs2
-rw-r--r--src/tools/rust-analyzer/crates/hir/src/lib.rs448
-rw-r--r--src/tools/rust-analyzer/crates/hir/src/semantics.rs67
-rw-r--r--src/tools/rust-analyzer/crates/hir/src/source_analyzer.rs41
-rw-r--r--src/tools/rust-analyzer/crates/hir/src/term_search.rs48
-rw-r--r--src/tools/rust-analyzer/crates/hir/src/term_search/expr.rs33
-rw-r--r--src/tools/rust-analyzer/crates/hir/src/term_search/tactics.rs98
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/assist_config.rs1
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/assist_context.rs2
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/handlers/add_missing_impl_members.rs2
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/handlers/add_missing_match_arms.rs207
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/handlers/auto_import.rs10
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_function.rs149
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_function.rs2
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/handlers/inline_call.rs8
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/handlers/inline_const_as_literal.rs2
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/handlers/merge_match_arms.rs16
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/handlers/qualify_path.rs4
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/handlers/remove_unused_imports.rs2
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/handlers/term_search.rs14
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/tests.rs21
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/utils.rs37
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/utils/gen_trait_fn_body.rs6
-rw-r--r--src/tools/rust-analyzer/crates/ide-completion/src/completions.rs38
-rw-r--r--src/tools/rust-analyzer/crates/ide-completion/src/completions/attribute.rs2
-rw-r--r--src/tools/rust-analyzer/crates/ide-completion/src/completions/attribute/derive.rs2
-rw-r--r--src/tools/rust-analyzer/crates/ide-completion/src/completions/dot.rs14
-rw-r--r--src/tools/rust-analyzer/crates/ide-completion/src/completions/expr.rs18
-rw-r--r--src/tools/rust-analyzer/crates/ide-completion/src/completions/field.rs2
-rw-r--r--src/tools/rust-analyzer/crates/ide-completion/src/completions/flyimport.rs20
-rw-r--r--src/tools/rust-analyzer/crates/ide-completion/src/completions/item_list.rs6
-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/pattern.rs2
-rw-r--r--src/tools/rust-analyzer/crates/ide-completion/src/completions/postfix.rs326
-rw-r--r--src/tools/rust-analyzer/crates/ide-completion/src/completions/record.rs4
-rw-r--r--src/tools/rust-analyzer/crates/ide-completion/src/completions/snippet.rs6
-rw-r--r--src/tools/rust-analyzer/crates/ide-completion/src/completions/type.rs4
-rw-r--r--src/tools/rust-analyzer/crates/ide-completion/src/completions/use_.rs2
-rw-r--r--src/tools/rust-analyzer/crates/ide-completion/src/completions/vis.rs2
-rw-r--r--src/tools/rust-analyzer/crates/ide-completion/src/context.rs50
-rw-r--r--src/tools/rust-analyzer/crates/ide-completion/src/context/analysis.rs33
-rw-r--r--src/tools/rust-analyzer/crates/ide-completion/src/item.rs2
-rw-r--r--src/tools/rust-analyzer/crates/ide-completion/src/render.rs112
-rw-r--r--src/tools/rust-analyzer/crates/ide-completion/src/render/function.rs24
-rw-r--r--src/tools/rust-analyzer/crates/ide-completion/src/render/literal.rs8
-rw-r--r--src/tools/rust-analyzer/crates/ide-completion/src/render/macro_.rs2
-rw-r--r--src/tools/rust-analyzer/crates/ide-completion/src/render/pattern.rs4
-rw-r--r--src/tools/rust-analyzer/crates/ide-completion/src/tests/expression.rs4
-rw-r--r--src/tools/rust-analyzer/crates/ide-completion/src/tests/visibility.rs89
-rw-r--r--src/tools/rust-analyzer/crates/ide-db/src/active_parameter.rs32
-rw-r--r--src/tools/rust-analyzer/crates/ide-db/src/defs.rs59
-rw-r--r--src/tools/rust-analyzer/crates/ide-db/src/imports/import_assets.rs60
-rw-r--r--src/tools/rust-analyzer/crates/ide-db/src/search.rs8
-rw-r--r--src/tools/rust-analyzer/crates/ide-db/src/syntax_helpers/suggest_name.rs18
-rw-r--r--src/tools/rust-analyzer/crates/ide-db/src/ty_filter.rs4
-rw-r--r--src/tools/rust-analyzer/crates/ide-db/src/use_trivial_constructor.rs2
-rw-r--r--src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/expected_function.rs2
-rw-r--r--src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/invalid_cast.rs7
-rw-r--r--src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/missing_fields.rs6
-rw-r--r--src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/missing_unsafe.rs25
-rw-r--r--src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/moved_out_of_ref.rs24
-rw-r--r--src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/no_such_field.rs33
-rw-r--r--src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/private_field.rs124
-rw-r--r--src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/type_mismatch.rs22
-rw-r--r--src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/typed_hole.rs6
-rw-r--r--src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unresolved_field.rs6
-rw-r--r--src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unresolved_method.rs13
-rw-r--r--src/tools/rust-analyzer/crates/ide-ssr/src/lib.rs2
-rw-r--r--src/tools/rust-analyzer/crates/ide-ssr/src/matching.rs22
-rw-r--r--src/tools/rust-analyzer/crates/ide-ssr/src/replacing.rs28
-rw-r--r--src/tools/rust-analyzer/crates/ide-ssr/src/resolving.rs26
-rw-r--r--src/tools/rust-analyzer/crates/ide-ssr/src/search.rs16
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/goto_implementation.rs2
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/goto_type_definition.rs2
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/hover.rs16
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/hover/render.rs10
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/inlay_hints.rs16
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/inlay_hints/param_name.rs6
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/lib.rs4
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/signature_help.rs14
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/typing.rs88
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/view_memory_layout.rs2
-rw-r--r--src/tools/rust-analyzer/crates/intern/src/symbol/symbols.rs1
-rw-r--r--src/tools/rust-analyzer/crates/load-cargo/src/lib.rs2
-rw-r--r--src/tools/rust-analyzer/crates/project-model/src/build_dependencies.rs26
-rw-r--r--src/tools/rust-analyzer/crates/project-model/src/cargo_workspace.rs90
-rw-r--r--src/tools/rust-analyzer/crates/project-model/src/manifest_path.rs8
-rw-r--r--src/tools/rust-analyzer/crates/project-model/src/sysroot.rs58
-rw-r--r--src/tools/rust-analyzer/crates/project-model/src/tests.rs13
-rw-r--r--src/tools/rust-analyzer/crates/project-model/src/workspace.rs150
-rw-r--r--src/tools/rust-analyzer/crates/query-group-macro/src/queries.rs8
-rw-r--r--src/tools/rust-analyzer/crates/rust-analyzer/src/cli/analysis_stats.rs2
-rw-r--r--src/tools/rust-analyzer/crates/rust-analyzer/src/cli/rustc_tests.rs10
-rw-r--r--src/tools/rust-analyzer/crates/rust-analyzer/src/config.rs9
-rw-r--r--src/tools/rust-analyzer/crates/rust-analyzer/src/handlers/notification.rs2
-rw-r--r--src/tools/rust-analyzer/crates/rust-analyzer/src/lsp/capabilities.rs2
-rw-r--r--src/tools/rust-analyzer/crates/rust-analyzer/src/reload.rs10
-rw-r--r--src/tools/rust-analyzer/crates/rust-analyzer/src/test_runner.rs1
-rw-r--r--src/tools/rust-analyzer/crates/stdx/src/lib.rs1
-rw-r--r--src/tools/rust-analyzer/crates/stdx/src/variance.rs270
-rw-r--r--src/tools/rust-analyzer/crates/syntax/src/ast/make.rs7
-rw-r--r--src/tools/rust-analyzer/crates/test-utils/src/fixture.rs40
-rw-r--r--src/tools/rust-analyzer/crates/test-utils/src/minicore.rs15
-rw-r--r--src/tools/rust-analyzer/docs/book/src/configuration_generated.md13
-rw-r--r--src/tools/rust-analyzer/editors/code/package.json12
-rw-r--r--src/tools/rust-analyzer/editors/code/src/config.ts14
-rw-r--r--src/tools/rust-analyzer/rust-version2
-rw-r--r--src/tools/rust-installer/install-template.sh8
-rw-r--r--src/tools/rustfmt/src/expr.rs2
-rw-r--r--src/tools/rustfmt/src/imports.rs2
-rw-r--r--src/tools/rustfmt/src/parse/session.rs56
-rw-r--r--src/tools/rustfmt/tests/source/pin_sugar.rs10
-rw-r--r--src/tools/rustfmt/tests/source/type.rs12
-rw-r--r--src/tools/rustfmt/tests/target/pin_sugar.rs7
-rw-r--r--src/tools/rustfmt/tests/target/type.rs12
-rw-r--r--src/tools/tidy/src/alphabetical.rs59
-rw-r--r--src/tools/tidy/src/alphabetical/tests.rs147
-rw-r--r--src/tools/tidy/src/deps.rs6
-rw-r--r--src/tools/tidy/src/error_codes.rs32
-rw-r--r--src/tools/tidy/src/issues.txt3
-rw-r--r--src/tools/tidy/src/lib.rs62
-rw-r--r--src/tools/tidy/src/main.rs7
-rw-r--r--src/tools/tidy/src/rustdoc_js.rs3
-rw-r--r--src/tools/tidy/src/rustdoc_json.rs90
-rw-r--r--src/tools/tidy/src/ui_tests.rs2
-rw-r--r--src/tools/wasm-component-ld/Cargo.toml2
336 files changed, 6674 insertions, 2292 deletions
diff --git a/src/tools/cargo b/src/tools/cargo
-Subproject 2251525ae503fa196f6d7f9ce6d32eccb2d5f04
+Subproject 409fed7dc1553d49cb9a8c0637d12d65571346c
diff --git a/src/tools/clippy/.github/ISSUE_TEMPLATE/new_lint.yml b/src/tools/clippy/.github/ISSUE_TEMPLATE/new_lint.yml
index b49493edce1..464740640e0 100644
--- a/src/tools/clippy/.github/ISSUE_TEMPLATE/new_lint.yml
+++ b/src/tools/clippy/.github/ISSUE_TEMPLATE/new_lint.yml
@@ -1,5 +1,7 @@
 name: New lint suggestion
-description: Suggest a new Clippy lint.
+description: |
+  Suggest a new Clippy lint (currently not accepting new lints)
+  Check out the Clippy book for more information about the feature freeze.
 labels: ["A-lint"]
 body:
   - type: markdown
diff --git a/src/tools/clippy/.github/PULL_REQUEST_TEMPLATE.md b/src/tools/clippy/.github/PULL_REQUEST_TEMPLATE.md
index 9e49f60892d..83bfd8e9c68 100644
--- a/src/tools/clippy/.github/PULL_REQUEST_TEMPLATE.md
+++ b/src/tools/clippy/.github/PULL_REQUEST_TEMPLATE.md
@@ -32,6 +32,10 @@ order to get feedback.
 
 Delete this line and everything above before opening your PR.
 
+Note that we are currently not taking in new PRs that add new lints. We are in a
+feature freeze. Check out the book for more information. If you open a
+feature-adding pull request, its review will be delayed.
+
 ---
 
 *Please write a short comment explaining your change (or "none" for internal only changes)*
diff --git a/src/tools/clippy/.github/workflows/feature_freeze.yml b/src/tools/clippy/.github/workflows/feature_freeze.yml
new file mode 100644
index 00000000000..a5f8d4bc145
--- /dev/null
+++ b/src/tools/clippy/.github/workflows/feature_freeze.yml
@@ -0,0 +1,25 @@
+name: Feature freeze check
+
+on:
+  pull_request:
+    paths:
+      - 'clippy_lints/src/declared_lints.rs'
+
+jobs:
+  auto-comment:
+    runs-on: ubuntu-latest
+
+    steps:
+    - name: Check PR Changes
+      id: pr-changes
+      run: echo "::set-output name=changes::${{ toJson(github.event.pull_request.changed_files) }}"
+
+    - name: Create Comment
+      if: steps.pr-changes.outputs.changes != '[]'
+      run: |
+        # Use GitHub API to create a comment on the PR
+        PR_NUMBER=${{ github.event.pull_request.number }}
+        COMMENT="**Seems that you are trying to add a new lint!**\nWe are currently in a [feature freeze](https://doc.rust-lang.org/nightly/clippy/development/feature_freeze.html), so we are delaying all lint-adding PRs to August 1st and focusing on bugfixes.\nThanks a lot for your contribution, and sorry for the inconvenience.\nWith ❤ from the Clippy team"
+        GITHUB_TOKEN=${{ secrets.GITHUB_TOKEN }}
+        COMMENT_URL="https://api.github.com/repos/${{ github.repository }}/issues/${PR_NUMBER}/comments"
+        curl -s -H "Authorization: token ${GITHUB_TOKEN}" -X POST $COMMENT_URL -d "{\"body\":\"$COMMENT\"}"
diff --git a/src/tools/clippy/CHANGELOG.md b/src/tools/clippy/CHANGELOG.md
index 0cfe89ad378..a92fbdc767b 100644
--- a/src/tools/clippy/CHANGELOG.md
+++ b/src/tools/clippy/CHANGELOG.md
@@ -6,7 +6,94 @@ document.
 
 ## Unreleased / Beta / In Rust Nightly
 
-[1e5237f4...master](https://github.com/rust-lang/rust-clippy/compare/1e5237f4...master)
+[03a5b6b9...master](https://github.com/rust-lang/rust-clippy/compare/03a5b6b9...master)
+
+## Rust 1.88
+
+Current stable, released 2025-06-26
+
+[View all 126 merged pull requests](https://github.com/rust-lang/rust-clippy/pulls?q=merged%3A2025-03-21T10%3A30%3A57Z..2025-05-01T08%3A03%3A26Z+base%3Amaster)
+
+### New Lints
+
+* Added [`swap_with_temporary`] to `complexity` [#14046](https://github.com/rust-lang/rust-clippy/pull/14046)
+* Added [`redundant_test_prefix`] to `restriction` [#13710](https://github.com/rust-lang/rust-clippy/pull/13710)
+* Added [`manual_dangling_ptr`] to `style` [#14107](https://github.com/rust-lang/rust-clippy/pull/14107)
+* Added [`char_indices_as_byte_indices`] to `correctness` [#13435](https://github.com/rust-lang/rust-clippy/pull/13435)
+* Added [`manual_abs_diff`] to `complexity` [#14482](https://github.com/rust-lang/rust-clippy/pull/14482)
+* Added [`ignore_without_reason`] to `pedantic` [#13931](https://github.com/rust-lang/rust-clippy/pull/13931)
+
+### Moves and Deprecations
+
+* Moved [`uninlined_format_args`] to `style` (from `pedantic`)
+  [#14160](https://github.com/rust-lang/rust-clippy/pull/14160)
+* [`match_on_vec_items`] deprecated in favor of [`indexing_slicing`]
+  [#14217](https://github.com/rust-lang/rust-clippy/pull/14217)
+* Removed superseded lints: `transmute_float_to_int`, `transmute_int_to_char`,
+  `transmute_int_to_float`, `transmute_num_to_bytes` (now in rustc)
+  [#14703](https://github.com/rust-lang/rust-clippy/pull/14703)
+
+### Enhancements
+
+* Configuration renamed from `lint-inconsistent-struct-field-initializers`
+  to `check-inconsistent-struct-field-initializers`
+  [#14280](https://github.com/rust-lang/rust-clippy/pull/14280)
+* Paths in `disallowed_*` configurations are now validated
+  [#14397](https://github.com/rust-lang/rust-clippy/pull/14397)
+* [`borrow_as_ptr`] now lints implicit casts as well
+  [#14408](https://github.com/rust-lang/rust-clippy/pull/14408)
+* [`iter_kv_map`] now recognizes references on maps
+  [#14596](https://github.com/rust-lang/rust-clippy/pull/14596)
+* [`empty_enum_variants_with_brackets`] no longer lints reachable enums or enums used 
+  as functions within same crate [#12971](https://github.com/rust-lang/rust-clippy/pull/12971)
+* [`needless_lifetimes`] now checks for lifetime uses in closures
+  [#14608](https://github.com/rust-lang/rust-clippy/pull/14608)
+* [`wildcard_imports`] now lints on `pub use` when `warn_on_all_wildcard_imports` is enabled
+  [#14182](https://github.com/rust-lang/rust-clippy/pull/14182)
+* [`collapsible_if`] now recognizes the `let_chains` feature
+  [#14481](https://github.com/rust-lang/rust-clippy/pull/14481)
+* [`match_single_binding`] now allows macros in scrutinee and patterns
+  [#14635](https://github.com/rust-lang/rust-clippy/pull/14635)
+* [`needless_borrow`] does not contradict the compiler's
+  `dangerous_implicit_autorefs` lint even though the references
+  are not mandatory
+  [#14810](https://github.com/rust-lang/rust-clippy/pull/14810)
+
+### False Positive Fixes
+
+* [`double_ended_iterator_last`] and [`needless_collect`] fixed FP when iter has side effects
+  [#14490](https://github.com/rust-lang/rust-clippy/pull/14490)
+* [`mut_from_ref`] fixed FP where lifetimes nested in types were not considered
+  [#14471](https://github.com/rust-lang/rust-clippy/pull/14471)
+* [`redundant_clone`] fixed FP in overlapping lifetime
+  [#14237](https://github.com/rust-lang/rust-clippy/pull/14237)
+* [`map_entry`] fixed FP where lint would trigger without insert calls present
+  [#14568](https://github.com/rust-lang/rust-clippy/pull/14568)
+* [`iter_cloned_collect`] fixed FP with custom `From`/`IntoIterator` impl
+  [#14473](https://github.com/rust-lang/rust-clippy/pull/14473)
+* [`shadow_unrelated`] fixed FP in destructuring assignments
+  [#14381](https://github.com/rust-lang/rust-clippy/pull/14381)
+* [`redundant_clone`] fixed FP on enum cast
+  [#14395](https://github.com/rust-lang/rust-clippy/pull/14395)
+* [`collapsible_if`] fixed FP on block stmt before expr
+  [#14730](https://github.com/rust-lang/rust-clippy/pull/14730)
+
+### ICE Fixes
+
+* [`missing_const_for_fn`] fix ICE with `-Z validate-mir` compilation option
+  [#14776](https://github.com/rust-lang/rust-clippy/pull/14776)
+
+### Documentation Improvements
+
+* [`missing_asserts_for_indexing`] improved documentation and examples
+  [#14108](https://github.com/rust-lang/rust-clippy/pull/14108)
+
+### Others
+
+* We're testing with edition 2024 now
+  [#14602](https://github.com/rust-lang/rust-clippy/pull/14602)
+* Don't warn about unloaded crates in `clippy.toml` disallowed paths
+  [#14733](https://github.com/rust-lang/rust-clippy/pull/14733)
 
 ## Rust 1.87
 
@@ -5729,6 +5816,7 @@ Released 2018-09-13
 [`disallowed_type`]: https://rust-lang.github.io/rust-clippy/master/index.html#disallowed_type
 [`disallowed_types`]: https://rust-lang.github.io/rust-clippy/master/index.html#disallowed_types
 [`diverging_sub_expression`]: https://rust-lang.github.io/rust-clippy/master/index.html#diverging_sub_expression
+[`doc_broken_link`]: https://rust-lang.github.io/rust-clippy/master/index.html#doc_broken_link
 [`doc_comment_double_space_linebreaks`]: https://rust-lang.github.io/rust-clippy/master/index.html#doc_comment_double_space_linebreaks
 [`doc_include_without_cfg`]: https://rust-lang.github.io/rust-clippy/master/index.html#doc_include_without_cfg
 [`doc_lazy_continuation`]: https://rust-lang.github.io/rust-clippy/master/index.html#doc_lazy_continuation
@@ -5967,6 +6055,7 @@ Released 2018-09-13
 [`manual_is_ascii_check`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_is_ascii_check
 [`manual_is_finite`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_is_finite
 [`manual_is_infinite`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_is_infinite
+[`manual_is_multiple_of`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_is_multiple_of
 [`manual_is_power_of_two`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_is_power_of_two
 [`manual_is_variant_and`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_is_variant_and
 [`manual_let_else`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_let_else
diff --git a/src/tools/clippy/Cargo.toml b/src/tools/clippy/Cargo.toml
index 3a76c61489e..1278427b5a7 100644
--- a/src/tools/clippy/Cargo.toml
+++ b/src/tools/clippy/Cargo.toml
@@ -1,6 +1,6 @@
 [package]
 name = "clippy"
-version = "0.1.89"
+version = "0.1.90"
 description = "A bunch of helpful lints to avoid common pitfalls in Rust"
 repository = "https://github.com/rust-lang/rust-clippy"
 readme = "README.md"
@@ -24,6 +24,7 @@ path = "src/driver.rs"
 clippy_config = { path = "clippy_config" }
 clippy_lints = { path = "clippy_lints" }
 clippy_utils = { path = "clippy_utils" }
+declare_clippy_lint = { path = "declare_clippy_lint" }
 rustc_tools_util = { path = "rustc_tools_util", version = "0.4.2" }
 clippy_lints_internal = { path = "clippy_lints_internal", optional = true }
 tempfile = { version = "3.20", optional = true }
@@ -58,6 +59,7 @@ rustc_tools_util = { path = "rustc_tools_util", version = "0.4.2" }
 [features]
 integration = ["dep:tempfile"]
 internal = ["dep:clippy_lints_internal", "dep:tempfile"]
+jemalloc = []
 
 [package.metadata.rust-analyzer]
 # This package uses #[feature(rustc_private)]
diff --git a/src/tools/clippy/book/src/README.md b/src/tools/clippy/book/src/README.md
index 5d2c3972b06..db73b49ecc2 100644
--- a/src/tools/clippy/book/src/README.md
+++ b/src/tools/clippy/book/src/README.md
@@ -1,5 +1,9 @@
 # Clippy
 
+[### IMPORTANT NOTE FOR CONTRIBUTORS ================](development/feature_freeze.md)
+
+----
+
 [![License: MIT OR Apache-2.0](https://img.shields.io/crates/l/clippy.svg)](https://github.com/rust-lang/rust-clippy#license)
 
 A collection of lints to catch common mistakes and improve your
diff --git a/src/tools/clippy/book/src/SUMMARY.md b/src/tools/clippy/book/src/SUMMARY.md
index 39fe7358ed8..b66c3481e49 100644
--- a/src/tools/clippy/book/src/SUMMARY.md
+++ b/src/tools/clippy/book/src/SUMMARY.md
@@ -13,6 +13,7 @@
     - [GitLab CI](continuous_integration/gitlab.md)
     - [Travis CI](continuous_integration/travis.md)
 - [Development](development/README.md)
+    - [IMPORTANT: FEATURE FREEZE](development/feature_freeze.md)
     - [Basics](development/basics.md)
     - [Adding Lints](development/adding_lints.md)
     - [Defining Lints](development/defining_lints.md)
diff --git a/src/tools/clippy/book/src/development/adding_lints.md b/src/tools/clippy/book/src/development/adding_lints.md
index 2b89e94cf8f..a42a2983744 100644
--- a/src/tools/clippy/book/src/development/adding_lints.md
+++ b/src/tools/clippy/book/src/development/adding_lints.md
@@ -1,5 +1,8 @@
 # Adding a new lint
 
+[### IMPORTANT NOTE FOR CONTRIBUTORS ================](feature_freeze.md)
+
+
 You are probably here because you want to add a new lint to Clippy. If this is
 the first time you're contributing to Clippy, this document guides you through
 creating an example lint from scratch.
diff --git a/src/tools/clippy/book/src/development/feature_freeze.md b/src/tools/clippy/book/src/development/feature_freeze.md
new file mode 100644
index 00000000000..260cb136cc0
--- /dev/null
+++ b/src/tools/clippy/book/src/development/feature_freeze.md
@@ -0,0 +1,55 @@
+# IMPORTANT: FEATURE FREEZE
+
+This is a temporary notice.
+
+From the 26th of June until the 18th of September we will perform a feature freeze. Only bugfix PRs will be reviewed
+except already open ones. Every feature-adding PR opened in between those dates will be moved into a
+milestone to be reviewed separately at another time.
+
+We do this because of the long backlog of bugs that need to be addressed
+in order to continue being the state-of-the-art linter that Clippy has become known for being.
+
+## For contributors
+
+If you are a contributor or are planning to become one, **please do not open a lint-adding PR**, we have lots of open
+bugs of all levels of difficulty that you can address instead!
+
+We currently have about 800 lints, each one posing a maintainability challenge that needs to account to every possible
+use case of the whole ecosystem. Bugs are natural in every software, but the Clippy team considers that Clippy needs a
+refinement period.
+
+If you open a PR at this time, we will not review it but push it into a milestone until the refinement period ends,
+adding additional load into our reviewing schedules.
+
+## I want to help, what can I do
+
+Thanks a lot to everyone who wants to help Clippy become better software in this feature freeze period!
+If you'd like to help, making a bugfix, making sure that it works, and opening a PR is a great step!
+
+To find things to fix, go to the [tracking issue][tracking_issue], find an issue that you like, go there and claim that
+issue with `@rustbot claim`.
+
+As a general metric and always taking into account your skill and knowledge level, you can use this guide:
+
+- 🟥 [ICEs][search_ice], these are compiler errors that causes Clippy to panic and crash. Usually involves high-level
+debugging, sometimes interacting directly with the upstream compiler. Difficult to fix but a great challenge that
+improves a lot developer workflows!
+
+- 🟧 [Suggestion causes bug][sugg_causes_bug], Clippy suggested code that changed logic in some silent way.
+Unacceptable, as this may have disastrous consequences. Easier to fix than ICEs
+
+- 🟨 [Suggestion causes error][sugg_causes_error], Clippy suggested code snippet that caused a compiler error
+when applied. We need to make sure that Clippy doesn't suggest using a variable twice at the same time or similar
+easy-to-happen occurrences.
+
+- 🟩 [False positives][false_positive], a lint should not have fired, the easiest of them all, as this is "just"
+identifying the root of a false positive and making an exception for those cases.
+
+Note that false negatives do not have priority unless the case is very clear, as they are a feature-request in a
+trench coat.
+
+[search_ice]: https://github.com/rust-lang/rust-clippy/issues?q=sort%3Aupdated-desc+state%3Aopen+label%3A%22I-ICE%22
+[sugg_causes_bug]: https://github.com/rust-lang/rust-clippy/issues?q=sort%3Aupdated-desc%20state%3Aopen%20label%3AI-suggestion-causes-bug
+[sugg_causes_error]: https://github.com/rust-lang/rust-clippy/issues?q=sort%3Aupdated-desc%20state%3Aopen%20label%3AI-suggestion-causes-error%20
+[false_positive]: https://github.com/rust-lang/rust-clippy/issues?q=sort%3Aupdated-desc%20state%3Aopen%20label%3AI-false-positive
+[tracking_issue]: https://github.com/rust-lang/rust-clippy/issues/15086
diff --git a/src/tools/clippy/book/src/lint_configuration.md b/src/tools/clippy/book/src/lint_configuration.md
index 7c850b4b023..e9b7f42a183 100644
--- a/src/tools/clippy/book/src/lint_configuration.md
+++ b/src/tools/clippy/book/src/lint_configuration.md
@@ -488,6 +488,13 @@ The maximum cognitive complexity a function can have
 ## `disallowed-macros`
 The list of disallowed macros, written as fully qualified paths.
 
+**Fields:**
+- `path` (required): the fully qualified path to the macro that should be disallowed
+- `reason` (optional): explanation why this macro is disallowed
+- `replacement` (optional): suggested alternative macro
+- `allow-invalid` (optional, `false` by default): when set to `true`, it will ignore this entry
+  if the path doesn't exist, instead of emitting an error
+
 **Default Value:** `[]`
 
 ---
@@ -498,6 +505,13 @@ The list of disallowed macros, written as fully qualified paths.
 ## `disallowed-methods`
 The list of disallowed methods, written as fully qualified paths.
 
+**Fields:**
+- `path` (required): the fully qualified path to the method that should be disallowed
+- `reason` (optional): explanation why this method is disallowed
+- `replacement` (optional): suggested alternative method
+- `allow-invalid` (optional, `false` by default): when set to `true`, it will ignore this entry
+  if the path doesn't exist, instead of emitting an error
+
 **Default Value:** `[]`
 
 ---
@@ -520,6 +534,13 @@ default configuration of Clippy. By default, any configuration will replace the
 ## `disallowed-types`
 The list of disallowed types, written as fully qualified paths.
 
+**Fields:**
+- `path` (required): the fully qualified path to the type that should be disallowed
+- `reason` (optional): explanation why this type is disallowed
+- `replacement` (optional): suggested alternative type
+- `allow-invalid` (optional, `false` by default): when set to `true`, it will ignore this entry
+  if the path doesn't exist, instead of emitting an error
+
 **Default Value:** `[]`
 
 ---
@@ -651,13 +672,14 @@ The maximum size of the `Err`-variant in a `Result` returned from a function
 
 
 ## `lint-commented-code`
-Whether collapsible `if` chains are linted if they contain comments inside the parts
+Whether collapsible `if` and `else if` chains are linted if they contain comments inside the parts
 that would be collapsed.
 
 **Default Value:** `false`
 
 ---
 **Affected lints:**
+* [`collapsible_else_if`](https://rust-lang.github.io/rust-clippy/master/index.html#collapsible_else_if)
 * [`collapsible_if`](https://rust-lang.github.io/rust-clippy/master/index.html#collapsible_if)
 
 
diff --git a/src/tools/clippy/clippy_config/Cargo.toml b/src/tools/clippy/clippy_config/Cargo.toml
index 0606245f990..858366c8a5c 100644
--- a/src/tools/clippy/clippy_config/Cargo.toml
+++ b/src/tools/clippy/clippy_config/Cargo.toml
@@ -1,6 +1,6 @@
 [package]
 name = "clippy_config"
-version = "0.1.89"
+version = "0.1.90"
 edition = "2024"
 publish = false
 
diff --git a/src/tools/clippy/clippy_config/src/conf.rs b/src/tools/clippy/clippy_config/src/conf.rs
index 87158cec42b..841facdca06 100644
--- a/src/tools/clippy/clippy_config/src/conf.rs
+++ b/src/tools/clippy/clippy_config/src/conf.rs
@@ -575,10 +575,24 @@ define_Conf! {
     #[conf_deprecated("Please use `cognitive-complexity-threshold` instead", cognitive_complexity_threshold)]
     cyclomatic_complexity_threshold: u64 = 25,
     /// The list of disallowed macros, written as fully qualified paths.
+    ///
+    /// **Fields:**
+    /// - `path` (required): the fully qualified path to the macro that should be disallowed
+    /// - `reason` (optional): explanation why this macro is disallowed
+    /// - `replacement` (optional): suggested alternative macro
+    /// - `allow-invalid` (optional, `false` by default): when set to `true`, it will ignore this entry
+    ///   if the path doesn't exist, instead of emitting an error
     #[disallowed_paths_allow_replacements = true]
     #[lints(disallowed_macros)]
     disallowed_macros: Vec<DisallowedPath> = Vec::new(),
     /// The list of disallowed methods, written as fully qualified paths.
+    ///
+    /// **Fields:**
+    /// - `path` (required): the fully qualified path to the method that should be disallowed
+    /// - `reason` (optional): explanation why this method is disallowed
+    /// - `replacement` (optional): suggested alternative method
+    /// - `allow-invalid` (optional, `false` by default): when set to `true`, it will ignore this entry
+    ///   if the path doesn't exist, instead of emitting an error
     #[disallowed_paths_allow_replacements = true]
     #[lints(disallowed_methods)]
     disallowed_methods: Vec<DisallowedPath> = Vec::new(),
@@ -588,6 +602,13 @@ define_Conf! {
     #[lints(disallowed_names)]
     disallowed_names: Vec<String> = DEFAULT_DISALLOWED_NAMES.iter().map(ToString::to_string).collect(),
     /// The list of disallowed types, written as fully qualified paths.
+    ///
+    /// **Fields:**
+    /// - `path` (required): the fully qualified path to the type that should be disallowed
+    /// - `reason` (optional): explanation why this type is disallowed
+    /// - `replacement` (optional): suggested alternative type
+    /// - `allow-invalid` (optional, `false` by default): when set to `true`, it will ignore this entry
+    ///   if the path doesn't exist, instead of emitting an error
     #[disallowed_paths_allow_replacements = true]
     #[lints(disallowed_types)]
     disallowed_types: Vec<DisallowedPath> = Vec::new(),
@@ -641,9 +662,9 @@ define_Conf! {
     /// The maximum size of the `Err`-variant in a `Result` returned from a function
     #[lints(result_large_err)]
     large_error_threshold: u64 = 128,
-    /// Whether collapsible `if` chains are linted if they contain comments inside the parts
+    /// Whether collapsible `if` and `else if` chains are linted if they contain comments inside the parts
     /// that would be collapsed.
-    #[lints(collapsible_if)]
+    #[lints(collapsible_else_if, collapsible_if)]
     lint_commented_code: bool = false,
     /// Whether to suggest reordering constructor fields when initializers are present.
     /// DEPRECATED CONFIGURATION: lint-inconsistent-struct-field-initializers
diff --git a/src/tools/clippy/clippy_dev/src/lint.rs b/src/tools/clippy/clippy_dev/src/lint.rs
index e0e036757d5..0d66f167a38 100644
--- a/src/tools/clippy/clippy_dev/src/lint.rs
+++ b/src/tools/clippy/clippy_dev/src/lint.rs
@@ -13,7 +13,7 @@ pub fn run<'a>(path: &str, edition: &str, args: impl Iterator<Item = &'a String>
 
     if is_file {
         exit_if_err(
-            Command::new(env::var("CARGO").unwrap_or("cargo".into()))
+            Command::new(env::var("CARGO").unwrap_or_else(|_| "cargo".into()))
                 .args(["run", "--bin", "clippy-driver", "--"])
                 .args(["-L", "./target/debug"])
                 .args(["-Z", "no-codegen"])
@@ -26,7 +26,7 @@ pub fn run<'a>(path: &str, edition: &str, args: impl Iterator<Item = &'a String>
         );
     } else {
         exit_if_err(
-            Command::new(env::var("CARGO").unwrap_or("cargo".into()))
+            Command::new(env::var("CARGO").unwrap_or_else(|_| "cargo".into()))
                 .arg("build")
                 .status(),
         );
diff --git a/src/tools/clippy/clippy_dev/src/release.rs b/src/tools/clippy/clippy_dev/src/release.rs
index 62c1bee8185..15392dd1d29 100644
--- a/src/tools/clippy/clippy_dev/src/release.rs
+++ b/src/tools/clippy/clippy_dev/src/release.rs
@@ -5,6 +5,7 @@ static CARGO_TOML_FILES: &[&str] = &[
     "clippy_config/Cargo.toml",
     "clippy_lints/Cargo.toml",
     "clippy_utils/Cargo.toml",
+    "declare_clippy_lint/Cargo.toml",
     "Cargo.toml",
 ];
 
diff --git a/src/tools/clippy/clippy_dev/src/serve.rs b/src/tools/clippy/clippy_dev/src/serve.rs
index a2d1236629f..498ffeba9d6 100644
--- a/src/tools/clippy/clippy_dev/src/serve.rs
+++ b/src/tools/clippy/clippy_dev/src/serve.rs
@@ -28,7 +28,7 @@ pub fn run(port: u16, lint: Option<String>) -> ! {
         .map(mtime);
 
         if times.iter().any(|&time| index_time < time) {
-            Command::new(env::var("CARGO").unwrap_or("cargo".into()))
+            Command::new(env::var("CARGO").unwrap_or_else(|_| "cargo".into()))
                 .arg("collect-metadata")
                 .spawn()
                 .unwrap()
diff --git a/src/tools/clippy/clippy_dev/src/update_lints.rs b/src/tools/clippy/clippy_dev/src/update_lints.rs
index 08592f2521f..5f6e874ffe2 100644
--- a/src/tools/clippy/clippy_dev/src/update_lints.rs
+++ b/src/tools/clippy/clippy_dev/src/update_lints.rs
@@ -4,8 +4,9 @@ use crate::utils::{
 use itertools::Itertools;
 use std::collections::HashSet;
 use std::fmt::Write;
+use std::fs;
 use std::ops::Range;
-use std::path::{Path, PathBuf};
+use std::path::{self, Path, PathBuf};
 use walkdir::{DirEntry, WalkDir};
 
 const GENERATED_FILE_COMMENT: &str = "// This file was generated by `cargo dev update_lints`.\n\
@@ -36,123 +37,164 @@ pub fn generate_lint_files(
     deprecated: &[DeprecatedLint],
     renamed: &[RenamedLint],
 ) {
-    FileUpdater::default().update_files_checked(
+    let mut updater = FileUpdater::default();
+    updater.update_file_checked(
         "cargo dev update_lints",
         update_mode,
-        &mut [
-            (
-                "README.md",
-                &mut update_text_region_fn("[There are over ", " lints included in this crate!]", |dst| {
-                    write!(dst, "{}", round_to_fifty(lints.len())).unwrap();
-                }),
-            ),
-            (
-                "book/src/README.md",
-                &mut update_text_region_fn("[There are over ", " lints included in this crate!]", |dst| {
-                    write!(dst, "{}", round_to_fifty(lints.len())).unwrap();
-                }),
-            ),
-            (
-                "CHANGELOG.md",
-                &mut update_text_region_fn(
-                    "<!-- begin autogenerated links to lint list -->\n",
-                    "<!-- end autogenerated links to lint list -->",
-                    |dst| {
-                        for lint in lints
-                            .iter()
-                            .map(|l| &*l.name)
-                            .chain(deprecated.iter().filter_map(|l| l.name.strip_prefix("clippy::")))
-                            .chain(renamed.iter().filter_map(|l| l.old_name.strip_prefix("clippy::")))
-                            .sorted()
-                        {
-                            writeln!(dst, "[`{lint}`]: {DOCS_LINK}#{lint}").unwrap();
-                        }
-                    },
-                ),
-            ),
-            (
-                "clippy_lints/src/lib.rs",
-                &mut update_text_region_fn(
-                    "// begin lints modules, do not remove this comment, it's used in `update_lints`\n",
-                    "// end lints modules, do not remove this comment, it's used in `update_lints`",
-                    |dst| {
-                        for lint_mod in lints.iter().map(|l| &l.module).sorted().dedup() {
-                            writeln!(dst, "mod {lint_mod};").unwrap();
-                        }
-                    },
-                ),
-            ),
-            ("clippy_lints/src/declared_lints.rs", &mut |_, src, dst| {
-                dst.push_str(GENERATED_FILE_COMMENT);
-                dst.push_str("pub static LINTS: &[&crate::LintInfo] = &[\n");
-                for (module_name, lint_name) in lints.iter().map(|l| (&l.module, l.name.to_uppercase())).sorted() {
-                    writeln!(dst, "    crate::{module_name}::{lint_name}_INFO,").unwrap();
-                }
-                dst.push_str("];\n");
-                UpdateStatus::from_changed(src != dst)
-            }),
-            ("clippy_lints/src/deprecated_lints.rs", &mut |_, src, dst| {
-                let mut searcher = RustSearcher::new(src);
-                assert!(
-                    searcher.find_token(Token::Ident("declare_with_version"))
-                        && searcher.find_token(Token::Ident("declare_with_version")),
-                    "error reading deprecated lints"
-                );
-                dst.push_str(&src[..searcher.pos() as usize]);
-                dst.push_str("! { DEPRECATED(DEPRECATED_VERSION) = [\n");
-                for lint in deprecated {
-                    write!(
-                        dst,
-                        "    #[clippy::version = \"{}\"]\n    (\"{}\", \"{}\"),\n",
-                        lint.version, lint.name, lint.reason,
-                    )
-                    .unwrap();
+        "README.md",
+        &mut update_text_region_fn("[There are over ", " lints included in this crate!]", |dst| {
+            write!(dst, "{}", round_to_fifty(lints.len())).unwrap();
+        }),
+    );
+    updater.update_file_checked(
+        "cargo dev update_lints",
+        update_mode,
+        "book/src/README.md",
+        &mut update_text_region_fn("[There are over ", " lints included in this crate!]", |dst| {
+            write!(dst, "{}", round_to_fifty(lints.len())).unwrap();
+        }),
+    );
+    updater.update_file_checked(
+        "cargo dev update_lints",
+        update_mode,
+        "CHANGELOG.md",
+        &mut update_text_region_fn(
+            "<!-- begin autogenerated links to lint list -->\n",
+            "<!-- end autogenerated links to lint list -->",
+            |dst| {
+                for lint in lints
+                    .iter()
+                    .map(|l| &*l.name)
+                    .chain(deprecated.iter().filter_map(|l| l.name.strip_prefix("clippy::")))
+                    .chain(renamed.iter().filter_map(|l| l.old_name.strip_prefix("clippy::")))
+                    .sorted()
+                {
+                    writeln!(dst, "[`{lint}`]: {DOCS_LINK}#{lint}").unwrap();
                 }
-                dst.push_str(
-                    "]}\n\n\
+            },
+        ),
+    );
+    updater.update_file_checked(
+        "cargo dev update_lints",
+        update_mode,
+        "clippy_lints/src/deprecated_lints.rs",
+        &mut |_, src, dst| {
+            let mut searcher = RustSearcher::new(src);
+            assert!(
+                searcher.find_token(Token::Ident("declare_with_version"))
+                    && searcher.find_token(Token::Ident("declare_with_version")),
+                "error reading deprecated lints"
+            );
+            dst.push_str(&src[..searcher.pos() as usize]);
+            dst.push_str("! { DEPRECATED(DEPRECATED_VERSION) = [\n");
+            for lint in deprecated {
+                write!(
+                    dst,
+                    "    #[clippy::version = \"{}\"]\n    (\"{}\", \"{}\"),\n",
+                    lint.version, lint.name, lint.reason,
+                )
+                .unwrap();
+            }
+            dst.push_str(
+                "]}\n\n\
                     #[rustfmt::skip]\n\
                     declare_with_version! { RENAMED(RENAMED_VERSION) = [\n\
                 ",
-                );
-                for lint in renamed {
-                    write!(
-                        dst,
-                        "    #[clippy::version = \"{}\"]\n    (\"{}\", \"{}\"),\n",
-                        lint.version, lint.old_name, lint.new_name,
-                    )
-                    .unwrap();
+            );
+            for lint in renamed {
+                write!(
+                    dst,
+                    "    #[clippy::version = \"{}\"]\n    (\"{}\", \"{}\"),\n",
+                    lint.version, lint.old_name, lint.new_name,
+                )
+                .unwrap();
+            }
+            dst.push_str("]}\n");
+            UpdateStatus::from_changed(src != dst)
+        },
+    );
+    updater.update_file_checked(
+        "cargo dev update_lints",
+        update_mode,
+        "tests/ui/deprecated.rs",
+        &mut |_, src, dst| {
+            dst.push_str(GENERATED_FILE_COMMENT);
+            for lint in deprecated {
+                writeln!(dst, "#![warn({})] //~ ERROR: lint `{}`", lint.name, lint.name).unwrap();
+            }
+            dst.push_str("\nfn main() {}\n");
+            UpdateStatus::from_changed(src != dst)
+        },
+    );
+    updater.update_file_checked(
+        "cargo dev update_lints",
+        update_mode,
+        "tests/ui/rename.rs",
+        &mut move |_, src, dst| {
+            let mut seen_lints = HashSet::new();
+            dst.push_str(GENERATED_FILE_COMMENT);
+            dst.push_str("#![allow(clippy::duplicated_attributes)]\n");
+            for lint in renamed {
+                if seen_lints.insert(&lint.new_name) {
+                    writeln!(dst, "#![allow({})]", lint.new_name).unwrap();
                 }
-                dst.push_str("]}\n");
-                UpdateStatus::from_changed(src != dst)
-            }),
-            ("tests/ui/deprecated.rs", &mut |_, src, dst| {
-                dst.push_str(GENERATED_FILE_COMMENT);
-                for lint in deprecated {
-                    writeln!(dst, "#![warn({})] //~ ERROR: lint `{}`", lint.name, lint.name).unwrap();
+            }
+            seen_lints.clear();
+            for lint in renamed {
+                if seen_lints.insert(&lint.old_name) {
+                    writeln!(dst, "#![warn({})] //~ ERROR: lint `{}`", lint.old_name, lint.old_name).unwrap();
                 }
-                dst.push_str("\nfn main() {}\n");
-                UpdateStatus::from_changed(src != dst)
-            }),
-            ("tests/ui/rename.rs", &mut move |_, src, dst| {
-                let mut seen_lints = HashSet::new();
-                dst.push_str(GENERATED_FILE_COMMENT);
-                dst.push_str("#![allow(clippy::duplicated_attributes)]\n");
-                for lint in renamed {
-                    if seen_lints.insert(&lint.new_name) {
-                        writeln!(dst, "#![allow({})]", lint.new_name).unwrap();
+            }
+            dst.push_str("\nfn main() {}\n");
+            UpdateStatus::from_changed(src != dst)
+        },
+    );
+    for (crate_name, lints) in lints.iter().into_group_map_by(|&l| {
+        let Some(path::Component::Normal(name)) = l.path.components().next() else {
+            // All paths should start with `{crate_name}/src` when parsed from `find_lint_decls`
+            panic!("internal error: can't read crate name from path `{}`", l.path.display());
+        };
+        name
+    }) {
+        updater.update_file_checked(
+            "cargo dev update_lints",
+            update_mode,
+            Path::new(crate_name).join("src/lib.rs"),
+            &mut update_text_region_fn(
+                "// begin lints modules, do not remove this comment, it's used in `update_lints`\n",
+                "// end lints modules, do not remove this comment, it's used in `update_lints`",
+                |dst| {
+                    for lint_mod in lints
+                        .iter()
+                        .filter(|l| !l.module.is_empty())
+                        .map(|l| l.module.split_once("::").map_or(&*l.module, |x| x.0))
+                        .sorted()
+                        .dedup()
+                    {
+                        writeln!(dst, "mod {lint_mod};").unwrap();
                     }
-                }
-                seen_lints.clear();
-                for lint in renamed {
-                    if seen_lints.insert(&lint.old_name) {
-                        writeln!(dst, "#![warn({})] //~ ERROR: lint `{}`", lint.old_name, lint.old_name).unwrap();
+                },
+            ),
+        );
+        updater.update_file_checked(
+            "cargo dev update_lints",
+            update_mode,
+            Path::new(crate_name).join("src/declared_lints.rs"),
+            &mut |_, src, dst| {
+                dst.push_str(GENERATED_FILE_COMMENT);
+                dst.push_str("pub static LINTS: &[&::declare_clippy_lint::LintInfo] = &[\n");
+                for (module_path, lint_name) in lints.iter().map(|l| (&l.module, l.name.to_uppercase())).sorted() {
+                    if module_path.is_empty() {
+                        writeln!(dst, "    crate::{lint_name}_INFO,").unwrap();
+                    } else {
+                        writeln!(dst, "    crate::{module_path}::{lint_name}_INFO,").unwrap();
                     }
                 }
-                dst.push_str("\nfn main() {}\n");
+                dst.push_str("];\n");
                 UpdateStatus::from_changed(src != dst)
-            }),
-        ],
-    );
+            },
+        );
+    }
 }
 
 fn round_to_fifty(count: usize) -> usize {
@@ -186,13 +228,25 @@ pub struct RenamedLint {
 pub fn find_lint_decls() -> Vec<Lint> {
     let mut lints = Vec::with_capacity(1000);
     let mut contents = String::new();
-    for (file, module) in read_src_with_module("clippy_lints/src".as_ref()) {
-        parse_clippy_lint_decls(
-            file.path(),
-            File::open_read_to_cleared_string(file.path(), &mut contents),
-            &module,
-            &mut lints,
-        );
+    for e in expect_action(fs::read_dir("."), ErrAction::Read, ".") {
+        let e = expect_action(e, ErrAction::Read, ".");
+        if !expect_action(e.file_type(), ErrAction::Read, ".").is_dir() {
+            continue;
+        }
+        let Ok(mut name) = e.file_name().into_string() else {
+            continue;
+        };
+        if name.starts_with("clippy_lints") && name != "clippy_lints_internal" {
+            name.push_str("/src");
+            for (file, module) in read_src_with_module(name.as_ref()) {
+                parse_clippy_lint_decls(
+                    file.path(),
+                    File::open_read_to_cleared_string(file.path(), &mut contents),
+                    &module,
+                    &mut lints,
+                );
+            }
+        }
     }
     lints.sort_by(|lhs, rhs| lhs.name.cmp(&rhs.name));
     lints
@@ -204,7 +258,7 @@ fn read_src_with_module(src_root: &Path) -> impl use<'_> + Iterator<Item = (DirE
         let e = expect_action(e, ErrAction::Read, src_root);
         let path = e.path().as_os_str().as_encoded_bytes();
         if let Some(path) = path.strip_suffix(b".rs")
-            && let Some(path) = path.get("clippy_lints/src/".len()..)
+            && let Some(path) = path.get(src_root.as_os_str().len() + 1..)
         {
             if path == b"lib" {
                 Some((e, String::new()))
@@ -332,17 +386,13 @@ pub fn read_deprecated_lints() -> (Vec<DeprecatedLint>, Vec<RenamedLint>) {
 
 /// Removes the line splices and surrounding quotes from a string literal
 fn parse_str_lit(s: &str) -> String {
-    let (s, mode) = if let Some(s) = s.strip_prefix("r") {
-        (s.trim_matches('#'), rustc_literal_escaper::Mode::RawStr)
-    } else {
-        (s, rustc_literal_escaper::Mode::Str)
-    };
+    let s = s.strip_prefix("r").unwrap_or(s).trim_matches('#');
     let s = s
         .strip_prefix('"')
         .and_then(|s| s.strip_suffix('"'))
         .unwrap_or_else(|| panic!("expected quoted string, found `{s}`"));
     let mut res = String::with_capacity(s.len());
-    rustc_literal_escaper::unescape_unicode(s, mode, &mut |_, ch| {
+    rustc_literal_escaper::unescape_str(s, &mut |_, ch| {
         if let Ok(ch) = ch {
             res.push(ch);
         }
diff --git a/src/tools/clippy/clippy_dev/src/utils.rs b/src/tools/clippy/clippy_dev/src/utils.rs
index c4808b7048b..89962a11034 100644
--- a/src/tools/clippy/clippy_dev/src/utils.rs
+++ b/src/tools/clippy/clippy_dev/src/utils.rs
@@ -383,21 +383,6 @@ impl FileUpdater {
         self.update_file_checked_inner(tool, mode, path.as_ref(), update);
     }
 
-    #[expect(clippy::type_complexity)]
-    pub fn update_files_checked(
-        &mut self,
-        tool: &str,
-        mode: UpdateMode,
-        files: &mut [(
-            impl AsRef<Path>,
-            &mut dyn FnMut(&Path, &str, &mut String) -> UpdateStatus,
-        )],
-    ) {
-        for (path, update) in files {
-            self.update_file_checked_inner(tool, mode, path.as_ref(), update);
-        }
-    }
-
     pub fn update_file(
         &mut self,
         path: impl AsRef<Path>,
diff --git a/src/tools/clippy/clippy_lints/Cargo.toml b/src/tools/clippy/clippy_lints/Cargo.toml
index 39e4e2e365e..c03cc99b581 100644
--- a/src/tools/clippy/clippy_lints/Cargo.toml
+++ b/src/tools/clippy/clippy_lints/Cargo.toml
@@ -1,6 +1,6 @@
 [package]
 name = "clippy_lints"
-version = "0.1.89"
+version = "0.1.90"
 description = "A bunch of helpful lints to avoid common pitfalls in Rust"
 repository = "https://github.com/rust-lang/rust-clippy"
 readme = "README.md"
@@ -13,6 +13,7 @@ arrayvec = { version = "0.7", default-features = false }
 cargo_metadata = "0.18"
 clippy_config = { path = "../clippy_config" }
 clippy_utils = { path = "../clippy_utils" }
+declare_clippy_lint = { path = "../declare_clippy_lint" }
 itertools = "0.12"
 quine-mc_cluskey = "0.2"
 regex-syntax = "0.8"
diff --git a/src/tools/clippy/clippy_lints/src/attrs/inline_always.rs b/src/tools/clippy/clippy_lints/src/attrs/inline_always.rs
index 58e51128a0d..b8f93ee5e2c 100644
--- a/src/tools/clippy/clippy_lints/src/attrs/inline_always.rs
+++ b/src/tools/clippy/clippy_lints/src/attrs/inline_always.rs
@@ -1,10 +1,10 @@
 use super::INLINE_ALWAYS;
 use clippy_utils::diagnostics::span_lint;
-use rustc_attr_data_structures::{find_attr, AttributeKind, InlineAttr};
+use rustc_attr_data_structures::{AttributeKind, InlineAttr, find_attr};
 use rustc_hir::Attribute;
 use rustc_lint::LateContext;
-use rustc_span::symbol::Symbol;
 use rustc_span::Span;
+use rustc_span::symbol::Symbol;
 
 pub(super) fn check(cx: &LateContext<'_>, span: Span, name: Symbol, attrs: &[Attribute]) {
     if span.from_expansion() {
diff --git a/src/tools/clippy/clippy_lints/src/attrs/mod.rs b/src/tools/clippy/clippy_lints/src/attrs/mod.rs
index 9a124298041..91c2dc7f3dc 100644
--- a/src/tools/clippy/clippy_lints/src/attrs/mod.rs
+++ b/src/tools/clippy/clippy_lints/src/attrs/mod.rs
@@ -207,7 +207,7 @@ declare_clippy_lint! {
 declare_clippy_lint! {
     /// ### What it does
     /// Checks for usage of the `#[allow]` attribute and suggests replacing it with
-    /// the `#[expect]` (See [RFC 2383](https://rust-lang.github.io/rfcs/2383-lint-reasons.html))
+    /// the `#[expect]` attribute (See [RFC 2383](https://rust-lang.github.io/rfcs/2383-lint-reasons.html))
     ///
     /// This lint only warns outer attributes (`#[allow]`), as inner attributes
     /// (`#![allow]`) are usually used to enable or disable lints on a global scale.
diff --git a/src/tools/clippy/clippy_lints/src/attrs/utils.rs b/src/tools/clippy/clippy_lints/src/attrs/utils.rs
index a5ce2137bff..7b66f91f6c0 100644
--- a/src/tools/clippy/clippy_lints/src/attrs/utils.rs
+++ b/src/tools/clippy/clippy_lints/src/attrs/utils.rs
@@ -46,11 +46,13 @@ pub(super) fn is_relevant_trait(cx: &LateContext<'_>, item: &TraitItem<'_>) -> b
 }
 
 fn is_relevant_block(cx: &LateContext<'_>, typeck_results: &ty::TypeckResults<'_>, block: &Block<'_>) -> bool {
-    block.stmts.first().map_or(
-        block
-            .expr
-            .as_ref()
-            .is_some_and(|e| is_relevant_expr(cx, typeck_results, e)),
+    block.stmts.first().map_or_else(
+        || {
+            block
+                .expr
+                .as_ref()
+                .is_some_and(|e| is_relevant_expr(cx, typeck_results, e))
+        },
         |stmt| match &stmt.kind {
             StmtKind::Let(_) => true,
             StmtKind::Expr(expr) | StmtKind::Semi(expr) => is_relevant_expr(cx, typeck_results, expr),
diff --git a/src/tools/clippy/clippy_lints/src/bool_assert_comparison.rs b/src/tools/clippy/clippy_lints/src/bool_assert_comparison.rs
index ae36bb76117..8f95e44bf85 100644
--- a/src/tools/clippy/clippy_lints/src/bool_assert_comparison.rs
+++ b/src/tools/clippy/clippy_lints/src/bool_assert_comparison.rs
@@ -56,7 +56,7 @@ fn is_impl_not_trait_with_bool_out<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -
         .and_then(|trait_id| {
             cx.tcx.associated_items(trait_id).find_by_ident_and_kind(
                 cx.tcx,
-                Ident::from_str("Output"),
+                Ident::with_dummy_span(sym::Output),
                 ty::AssocTag::Type,
                 trait_id,
             )
diff --git a/src/tools/clippy/clippy_lints/src/borrow_deref_ref.rs b/src/tools/clippy/clippy_lints/src/borrow_deref_ref.rs
index 7cde007a9b6..70c9c45a60c 100644
--- a/src/tools/clippy/clippy_lints/src/borrow_deref_ref.rs
+++ b/src/tools/clippy/clippy_lints/src/borrow_deref_ref.rs
@@ -2,9 +2,9 @@ use crate::reference::DEREF_ADDROF;
 use clippy_utils::diagnostics::span_lint_and_then;
 use clippy_utils::source::SpanRangeExt;
 use clippy_utils::ty::implements_trait;
-use clippy_utils::{get_parent_expr, is_from_proc_macro, is_lint_allowed, is_mutable};
+use clippy_utils::{get_parent_expr, is_expr_temporary_value, is_from_proc_macro, is_lint_allowed, is_mutable};
 use rustc_errors::Applicability;
-use rustc_hir::{BorrowKind, ExprKind, UnOp};
+use rustc_hir::{BorrowKind, Expr, ExprKind, Node, UnOp};
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_middle::mir::Mutability;
 use rustc_middle::ty;
@@ -48,7 +48,7 @@ declare_clippy_lint! {
 declare_lint_pass!(BorrowDerefRef => [BORROW_DEREF_REF]);
 
 impl<'tcx> LateLintPass<'tcx> for BorrowDerefRef {
-    fn check_expr(&mut self, cx: &LateContext<'tcx>, e: &rustc_hir::Expr<'tcx>) {
+    fn check_expr(&mut self, cx: &LateContext<'tcx>, e: &'tcx Expr<'tcx>) {
         if let ExprKind::AddrOf(BorrowKind::Ref, Mutability::Not, addrof_target) = e.kind
             && let ExprKind::Unary(UnOp::Deref, deref_target) = addrof_target.kind
             && !matches!(deref_target.kind, ExprKind::Unary(UnOp::Deref, ..))
@@ -76,6 +76,9 @@ impl<'tcx> LateLintPass<'tcx> for BorrowDerefRef {
             && let e_ty = cx.typeck_results().expr_ty_adjusted(e)
             // check if the reference is coercing to a mutable reference
             && (!matches!(e_ty.kind(), ty::Ref(_, _, Mutability::Mut)) || is_mutable(cx, deref_target))
+            // If the new borrow might be itself borrowed mutably and the original reference is not a temporary
+            // value, do not propose to use it directly.
+            && (is_expr_temporary_value(cx, deref_target) || !potentially_bound_to_mutable_ref(cx, e))
             && let Some(deref_text) = deref_target.span.get_source_text(cx)
         {
             span_lint_and_then(
@@ -110,3 +113,9 @@ impl<'tcx> LateLintPass<'tcx> for BorrowDerefRef {
         }
     }
 }
+
+/// Checks if `expr` is used as part of a `let` statement containing a `ref mut` binding.
+fn potentially_bound_to_mutable_ref<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) -> bool {
+    matches!(cx.tcx.parent_hir_node(expr.hir_id), Node::LetStmt(let_stmt)
+             if let_stmt.pat.contains_explicit_ref_binding() == Some(Mutability::Mut))
+}
diff --git a/src/tools/clippy/clippy_lints/src/casts/cast_sign_loss.rs b/src/tools/clippy/clippy_lints/src/casts/cast_sign_loss.rs
index 9a1ad8a7473..a70bd886191 100644
--- a/src/tools/clippy/clippy_lints/src/casts/cast_sign_loss.rs
+++ b/src/tools/clippy/clippy_lints/src/casts/cast_sign_loss.rs
@@ -168,7 +168,7 @@ fn pow_call_result_sign(cx: &LateContext<'_>, base: &Expr<'_>, exponent: &Expr<'
 
     // Rust's integer pow() functions take an unsigned exponent.
     let exponent_val = get_const_unsigned_int_eval(cx, exponent, None);
-    let exponent_is_even = exponent_val.map(|val| val % 2 == 0);
+    let exponent_is_even = exponent_val.map(|val| val.is_multiple_of(2));
 
     match (base_sign, exponent_is_even) {
         // Non-negative bases always return non-negative results, ignoring overflow.
diff --git a/src/tools/clippy/clippy_lints/src/casts/manual_dangling_ptr.rs b/src/tools/clippy/clippy_lints/src/casts/manual_dangling_ptr.rs
index 61dfc0fc042..d9e88d6a401 100644
--- a/src/tools/clippy/clippy_lints/src/casts/manual_dangling_ptr.rs
+++ b/src/tools/clippy/clippy_lints/src/casts/manual_dangling_ptr.rs
@@ -1,6 +1,6 @@
 use clippy_utils::diagnostics::span_lint_and_sugg;
 use clippy_utils::source::SpanRangeExt;
-use clippy_utils::{expr_or_init, path_def_id, paths, std_or_core};
+use clippy_utils::{expr_or_init, is_path_diagnostic_item, std_or_core, sym};
 use rustc_ast::LitKind;
 use rustc_errors::Applicability;
 use rustc_hir::{Expr, ExprKind, GenericArg, Mutability, QPath, Ty, TyKind};
@@ -53,8 +53,7 @@ fn is_expr_const_aligned(cx: &LateContext<'_>, expr: &Expr<'_>, to: &Ty<'_>) ->
 
 fn is_align_of_call(cx: &LateContext<'_>, fun: &Expr<'_>, to: &Ty<'_>) -> bool {
     if let ExprKind::Path(QPath::Resolved(_, path)) = fun.kind
-        && let Some(fun_id) = path_def_id(cx, fun)
-        && paths::ALIGN_OF.matches(cx, fun_id)
+        && is_path_diagnostic_item(cx, fun, sym::mem_align_of)
         && let Some(args) = path.segments.last().and_then(|seg| seg.args)
         && let [GenericArg::Type(generic_ty)] = args.args
     {
diff --git a/src/tools/clippy/clippy_lints/src/collapsible_if.rs b/src/tools/clippy/clippy_lints/src/collapsible_if.rs
index 7f6ecea99fb..1854d86c53b 100644
--- a/src/tools/clippy/clippy_lints/src/collapsible_if.rs
+++ b/src/tools/clippy/clippy_lints/src/collapsible_if.rs
@@ -1,13 +1,16 @@
 use clippy_config::Conf;
-use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_and_then};
+use clippy_utils::diagnostics::span_lint_and_then;
 use clippy_utils::msrvs::{self, Msrv};
-use clippy_utils::source::{IntoSpan as _, SpanRangeExt, snippet, snippet_block, snippet_block_with_applicability};
+use clippy_utils::source::{IntoSpan as _, SpanRangeExt, snippet, snippet_block_with_applicability};
+use clippy_utils::{span_contains_non_whitespace, tokenize_with_text};
 use rustc_ast::BinOpKind;
 use rustc_errors::Applicability;
 use rustc_hir::{Block, Expr, ExprKind, Stmt, StmtKind};
+use rustc_lexer::TokenKind;
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_session::impl_lint_pass;
-use rustc_span::Span;
+use rustc_span::source_map::SourceMap;
+use rustc_span::{BytePos, Span};
 
 declare_clippy_lint! {
     /// ### What it does
@@ -90,35 +93,74 @@ impl CollapsibleIf {
         }
     }
 
-    fn check_collapsible_else_if(cx: &LateContext<'_>, then_span: Span, else_block: &Block<'_>) {
-        if !block_starts_with_comment(cx, else_block)
-            && let Some(else_) = expr_block(else_block)
+    fn check_collapsible_else_if(&self, cx: &LateContext<'_>, then_span: Span, else_block: &Block<'_>) {
+        if let Some(else_) = expr_block(else_block)
             && cx.tcx.hir_attrs(else_.hir_id).is_empty()
             && !else_.span.from_expansion()
-            && let ExprKind::If(..) = else_.kind
+            && let ExprKind::If(else_if_cond, ..) = else_.kind
+            && !block_starts_with_significant_tokens(cx, else_block, else_, self.lint_commented_code)
         {
-            // Prevent "elseif"
-            // Check that the "else" is followed by whitespace
-            let up_to_else = then_span.between(else_block.span);
-            let requires_space = if let Some(c) = snippet(cx, up_to_else, "..").chars().last() {
-                !c.is_whitespace()
-            } else {
-                false
-            };
-
-            let mut applicability = Applicability::MachineApplicable;
-            span_lint_and_sugg(
+            span_lint_and_then(
                 cx,
                 COLLAPSIBLE_ELSE_IF,
                 else_block.span,
                 "this `else { if .. }` block can be collapsed",
-                "collapse nested if block",
-                format!(
-                    "{}{}",
-                    if requires_space { " " } else { "" },
-                    snippet_block_with_applicability(cx, else_.span, "..", Some(else_block.span), &mut applicability)
-                ),
-                applicability,
+                |diag| {
+                    let up_to_else = then_span.between(else_block.span);
+                    let else_before_if = else_.span.shrink_to_lo().with_hi(else_if_cond.span.lo() - BytePos(1));
+                    if self.lint_commented_code
+                        && let Some(else_keyword_span) =
+                            span_extract_keyword(cx.tcx.sess.source_map(), up_to_else, "else")
+                        && let Some(else_if_keyword_span) =
+                            span_extract_keyword(cx.tcx.sess.source_map(), else_before_if, "if")
+                    {
+                        let else_keyword_span = else_keyword_span.with_leading_whitespace(cx).into_span();
+                        let else_open_bracket = else_block.span.split_at(1).0.with_leading_whitespace(cx).into_span();
+                        let else_closing_bracket = {
+                            let end = else_block.span.shrink_to_hi();
+                            end.with_lo(end.lo() - BytePos(1))
+                                .with_leading_whitespace(cx)
+                                .into_span()
+                        };
+                        let sugg = vec![
+                            // Remove the outer else block `else`
+                            (else_keyword_span, String::new()),
+                            // Replace the inner `if` by `else if`
+                            (else_if_keyword_span, String::from("else if")),
+                            // Remove the outer else block `{`
+                            (else_open_bracket, String::new()),
+                            // Remove the outer else block '}'
+                            (else_closing_bracket, String::new()),
+                        ];
+                        diag.multipart_suggestion("collapse nested if block", sugg, Applicability::MachineApplicable);
+                        return;
+                    }
+
+                    // Prevent "elseif"
+                    // Check that the "else" is followed by whitespace
+                    let requires_space = if let Some(c) = snippet(cx, up_to_else, "..").chars().last() {
+                        !c.is_whitespace()
+                    } else {
+                        false
+                    };
+                    let mut applicability = Applicability::MachineApplicable;
+                    diag.span_suggestion(
+                        else_block.span,
+                        "collapse nested if block",
+                        format!(
+                            "{}{}",
+                            if requires_space { " " } else { "" },
+                            snippet_block_with_applicability(
+                                cx,
+                                else_.span,
+                                "..",
+                                Some(else_block.span),
+                                &mut applicability
+                            )
+                        ),
+                        applicability,
+                    );
+                },
             );
         }
     }
@@ -130,7 +172,7 @@ impl CollapsibleIf {
             && self.eligible_condition(cx, check_inner)
             && let ctxt = expr.span.ctxt()
             && inner.span.ctxt() == ctxt
-            && (self.lint_commented_code || !block_starts_with_comment(cx, then))
+            && !block_starts_with_significant_tokens(cx, then, inner, self.lint_commented_code)
         {
             span_lint_and_then(
                 cx,
@@ -141,7 +183,7 @@ impl CollapsibleIf {
                     let then_open_bracket = then.span.split_at(1).0.with_leading_whitespace(cx).into_span();
                     let then_closing_bracket = {
                         let end = then.span.shrink_to_hi();
-                        end.with_lo(end.lo() - rustc_span::BytePos(1))
+                        end.with_lo(end.lo() - BytePos(1))
                             .with_leading_whitespace(cx)
                             .into_span()
                     };
@@ -179,7 +221,7 @@ impl LateLintPass<'_> for CollapsibleIf {
             if let Some(else_) = else_
                 && let ExprKind::Block(else_, None) = else_.kind
             {
-                Self::check_collapsible_else_if(cx, then.span, else_);
+                self.check_collapsible_else_if(cx, then.span, else_);
             } else if else_.is_none()
                 && self.eligible_condition(cx, cond)
                 && let ExprKind::Block(then, None) = then.kind
@@ -190,12 +232,16 @@ impl LateLintPass<'_> for CollapsibleIf {
     }
 }
 
-fn block_starts_with_comment(cx: &LateContext<'_>, block: &Block<'_>) -> bool {
-    // We trim all opening braces and whitespaces and then check if the next string is a comment.
-    let trimmed_block_text = snippet_block(cx, block.span, "..", None)
-        .trim_start_matches(|c: char| c.is_whitespace() || c == '{')
-        .to_owned();
-    trimmed_block_text.starts_with("//") || trimmed_block_text.starts_with("/*")
+// Check that nothing significant can be found but whitespaces between the initial `{` of `block`
+// and the beginning of `stop_at`.
+fn block_starts_with_significant_tokens(
+    cx: &LateContext<'_>,
+    block: &Block<'_>,
+    stop_at: &Expr<'_>,
+    lint_commented_code: bool,
+) -> bool {
+    let span = block.span.split_at(1).1.until(stop_at.span);
+    span_contains_non_whitespace(cx, span, lint_commented_code)
 }
 
 /// If `block` is a block with either one expression or a statement containing an expression,
@@ -226,3 +272,16 @@ fn parens_around(expr: &Expr<'_>) -> Vec<(Span, String)> {
         vec![]
     }
 }
+
+fn span_extract_keyword(sm: &SourceMap, span: Span, keyword: &str) -> Option<Span> {
+    let snippet = sm.span_to_snippet(span).ok()?;
+    tokenize_with_text(&snippet)
+        .filter(|(t, s, _)| matches!(t, TokenKind::Ident if *s == keyword))
+        .map(|(_, _, inner)| {
+            span.split_at(u32::try_from(inner.start).unwrap())
+                .1
+                .split_at(u32::try_from(inner.end - inner.start).unwrap())
+                .0
+        })
+        .next()
+}
diff --git a/src/tools/clippy/clippy_lints/src/copies.rs b/src/tools/clippy/clippy_lints/src/copies.rs
index 5ef726638a5..27918698cd6 100644
--- a/src/tools/clippy/clippy_lints/src/copies.rs
+++ b/src/tools/clippy/clippy_lints/src/copies.rs
@@ -11,7 +11,7 @@ use clippy_utils::{
 use core::iter;
 use core::ops::ControlFlow;
 use rustc_errors::Applicability;
-use rustc_hir::{BinOpKind, Block, Expr, ExprKind, HirId, HirIdSet, Stmt, StmtKind, intravisit};
+use rustc_hir::{BinOpKind, Block, Expr, ExprKind, HirId, HirIdSet, LetStmt, Node, Stmt, StmtKind, intravisit};
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_middle::ty::TyCtxt;
 use rustc_session::impl_lint_pass;
@@ -295,7 +295,7 @@ fn lint_branches_sharing_code<'tcx>(
                 sugg,
                 Applicability::Unspecified,
             );
-            if !cx.typeck_results().expr_ty(expr).is_unit() {
+            if is_expr_parent_assignment(cx, expr) || !cx.typeck_results().expr_ty(expr).is_unit() {
                 diag.note("the end suggestion probably needs some adjustments to use the expression result correctly");
             }
         }
@@ -660,3 +660,17 @@ fn lint_same_fns_in_if_cond(cx: &LateContext<'_>, conds: &[&Expr<'_>]) {
         );
     }
 }
+
+fn is_expr_parent_assignment(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
+    let parent = cx.tcx.parent_hir_node(expr.hir_id);
+    if let Node::LetStmt(LetStmt { init: Some(e), .. })
+    | Node::Expr(Expr {
+        kind: ExprKind::Assign(_, e, _),
+        ..
+    }) = parent
+    {
+        return e.hir_id == expr.hir_id;
+    }
+
+    false
+}
diff --git a/src/tools/clippy/clippy_lints/src/declare_clippy_lint.rs b/src/tools/clippy/clippy_lints/src/declare_clippy_lint.rs
deleted file mode 100644
index 9f82f876727..00000000000
--- a/src/tools/clippy/clippy_lints/src/declare_clippy_lint.rs
+++ /dev/null
@@ -1,168 +0,0 @@
-#[macro_export]
-#[allow(clippy::crate_in_macro_def)]
-macro_rules! declare_clippy_lint {
-    (@
-        $(#[doc = $lit:literal])*
-        pub $lint_name:ident,
-        $level:ident,
-        $lintcategory:expr,
-        $desc:literal,
-        $version_expr:expr,
-        $version_lit:literal
-        $(, $eval_always: literal)?
-    ) => {
-        rustc_session::declare_tool_lint! {
-            $(#[doc = $lit])*
-            #[clippy::version = $version_lit]
-            pub clippy::$lint_name,
-            $level,
-            $desc,
-            report_in_external_macro:true
-            $(, @eval_always = $eval_always)?
-        }
-
-        pub(crate) static ${concat($lint_name, _INFO)}: &'static crate::LintInfo = &crate::LintInfo {
-            lint: &$lint_name,
-            category:  $lintcategory,
-            explanation: concat!($($lit,"\n",)*),
-            location: concat!(file!(), "#L", line!()),
-            version: $version_expr
-        };
-    };
-    (
-        $(#[doc = $lit:literal])*
-        #[clippy::version = $version:literal]
-        pub $lint_name:ident,
-        restriction,
-        $desc:literal
-        $(, @eval_always = $eval_always: literal)?
-    ) => {
-        declare_clippy_lint! {@
-            $(#[doc = $lit])*
-            pub $lint_name, Allow, crate::LintCategory::Restriction, $desc,
-            Some($version), $version
-            $(, $eval_always)?
-        }
-    };
-    (
-        $(#[doc = $lit:literal])*
-        #[clippy::version = $version:literal]
-        pub $lint_name:ident,
-        style,
-        $desc:literal
-        $(, @eval_always = $eval_always: literal)?
-    ) => {
-        declare_clippy_lint! {@
-            $(#[doc = $lit])*
-            pub $lint_name, Warn, crate::LintCategory::Style, $desc,
-            Some($version), $version
-            $(, $eval_always)?
-        }
-    };
-    (
-        $(#[doc = $lit:literal])*
-        #[clippy::version = $version:literal]
-        pub $lint_name:ident,
-        correctness,
-        $desc:literal
-        $(, @eval_always = $eval_always: literal)?
-    ) => {
-        declare_clippy_lint! {@
-            $(#[doc = $lit])*
-            pub $lint_name, Deny, crate::LintCategory::Correctness, $desc,
-            Some($version), $version
-            $(, $eval_always)?
-
-        }
-    };
-    (
-        $(#[doc = $lit:literal])*
-        #[clippy::version = $version:literal]
-        pub $lint_name:ident,
-        perf,
-        $desc:literal
-        $(, @eval_always = $eval_always: literal)?
-    ) => {
-        declare_clippy_lint! {@
-            $(#[doc = $lit])*
-            pub $lint_name, Warn, crate::LintCategory::Perf, $desc,
-            Some($version), $version
-            $(, $eval_always)?
-        }
-    };
-    (
-        $(#[doc = $lit:literal])*
-        #[clippy::version = $version:literal]
-        pub $lint_name:ident,
-        complexity,
-        $desc:literal
-        $(, @eval_always = $eval_always: literal)?
-    ) => {
-        declare_clippy_lint! {@
-            $(#[doc = $lit])*
-            pub $lint_name, Warn, crate::LintCategory::Complexity, $desc,
-            Some($version), $version
-            $(, $eval_always)?
-        }
-    };
-    (
-        $(#[doc = $lit:literal])*
-        #[clippy::version = $version:literal]
-        pub $lint_name:ident,
-        suspicious,
-        $desc:literal
-        $(, @eval_always = $eval_always: literal)?
-    ) => {
-        declare_clippy_lint! {@
-            $(#[doc = $lit])*
-            pub $lint_name, Warn, crate::LintCategory::Suspicious, $desc,
-            Some($version), $version
-            $(, $eval_always)?
-        }
-    };
-    (
-        $(#[doc = $lit:literal])*
-        #[clippy::version = $version:literal]
-        pub $lint_name:ident,
-        nursery,
-        $desc:literal
-        $(, @eval_always = $eval_always: literal)?
-    ) => {
-        declare_clippy_lint! {@
-            $(#[doc = $lit])*
-            pub $lint_name, Allow, crate::LintCategory::Nursery, $desc,
-            Some($version), $version
-            $(, $eval_always)?
-        }
-    };
-    (
-        $(#[doc = $lit:literal])*
-        #[clippy::version = $version:literal]
-        pub $lint_name:ident,
-        pedantic,
-        $desc:literal
-        $(, @eval_always = $eval_always: literal)?
-    ) => {
-        declare_clippy_lint! {@
-            $(#[doc = $lit])*
-            pub $lint_name, Allow, crate::LintCategory::Pedantic, $desc,
-            Some($version), $version
-            $(, $eval_always)?
-        }
-    };
-    (
-        $(#[doc = $lit:literal])*
-        #[clippy::version = $version:literal]
-        pub $lint_name:ident,
-        cargo,
-        $desc:literal
-        $(, @eval_always = $eval_always: literal)?
-    ) => {
-        declare_clippy_lint! {@
-            $(#[doc = $lit])*
-            pub $lint_name, Allow, crate::LintCategory::Cargo, $desc,
-            Some($version), $version
-            $(, $eval_always)?
-        }
-    };
-}
diff --git a/src/tools/clippy/clippy_lints/src/declared_lints.rs b/src/tools/clippy/clippy_lints/src/declared_lints.rs
index 1e3907d9ede..c3f8e02b4c0 100644
--- a/src/tools/clippy/clippy_lints/src/declared_lints.rs
+++ b/src/tools/clippy/clippy_lints/src/declared_lints.rs
@@ -2,7 +2,7 @@
 // Use that command to update this file and do not edit by hand.
 // Manual edits will be overwritten.
 
-pub static LINTS: &[&crate::LintInfo] = &[
+pub static LINTS: &[&::declare_clippy_lint::LintInfo] = &[
     crate::absolute_paths::ABSOLUTE_PATHS_INFO,
     crate::almost_complete_range::ALMOST_COMPLETE_RANGE_INFO,
     crate::approx_const::APPROX_CONSTANT_INFO,
@@ -112,6 +112,7 @@ pub static LINTS: &[&crate::LintInfo] = &[
     crate::disallowed_names::DISALLOWED_NAMES_INFO,
     crate::disallowed_script_idents::DISALLOWED_SCRIPT_IDENTS_INFO,
     crate::disallowed_types::DISALLOWED_TYPES_INFO,
+    crate::doc::DOC_BROKEN_LINK_INFO,
     crate::doc::DOC_COMMENT_DOUBLE_SPACE_LINEBREAKS_INFO,
     crate::doc::DOC_INCLUDE_WITHOUT_CFG_INFO,
     crate::doc::DOC_LAZY_CONTINUATION_INFO,
@@ -590,6 +591,7 @@ pub static LINTS: &[&crate::LintInfo] = &[
     crate::operators::IMPOSSIBLE_COMPARISONS_INFO,
     crate::operators::INEFFECTIVE_BIT_MASK_INFO,
     crate::operators::INTEGER_DIVISION_INFO,
+    crate::operators::MANUAL_IS_MULTIPLE_OF_INFO,
     crate::operators::MANUAL_MIDPOINT_INFO,
     crate::operators::MISREFACTORED_ASSIGN_OP_INFO,
     crate::operators::MODULO_ARITHMETIC_INFO,
diff --git a/src/tools/clippy/clippy_lints/src/disallowed_macros.rs b/src/tools/clippy/clippy_lints/src/disallowed_macros.rs
index 9814d4fa84f..d55aeae98ed 100644
--- a/src/tools/clippy/clippy_lints/src/disallowed_macros.rs
+++ b/src/tools/clippy/clippy_lints/src/disallowed_macros.rs
@@ -40,6 +40,9 @@ declare_clippy_lint! {
     ///     # When using an inline table, can add a `reason` for why the macro
     ///     # is disallowed.
     ///     { path = "serde::Serialize", reason = "no serializing" },
+    ///     # This would normally error if the path is incorrect, but with `allow-invalid` = `true`,
+    ///     # it will be silently ignored
+    ///     { path = "std::invalid_macro", reason = "use alternative instead", allow-invalid = true }
     /// ]
     /// ```
     /// ```no_run
diff --git a/src/tools/clippy/clippy_lints/src/disallowed_methods.rs b/src/tools/clippy/clippy_lints/src/disallowed_methods.rs
index fb970e17f38..8c067432cb4 100644
--- a/src/tools/clippy/clippy_lints/src/disallowed_methods.rs
+++ b/src/tools/clippy/clippy_lints/src/disallowed_methods.rs
@@ -34,6 +34,9 @@ declare_clippy_lint! {
     ///     { path = "std::vec::Vec::leak", reason = "no leaking memory" },
     ///     # Can also add a `replacement` that will be offered as a suggestion.
     ///     { path = "std::sync::Mutex::new", reason = "prefer faster & simpler non-poisonable mutex", replacement = "parking_lot::Mutex::new" },
+    ///     # This would normally error if the path is incorrect, but with `allow-invalid` = `true`,
+    ///     # it will be silently ignored
+    ///     { path = "std::fs::InvalidPath", reason = "use alternative instead", allow-invalid = true },
     /// ]
     /// ```
     ///
diff --git a/src/tools/clippy/clippy_lints/src/disallowed_types.rs b/src/tools/clippy/clippy_lints/src/disallowed_types.rs
index 7875cdd77e8..9a82327a0d7 100644
--- a/src/tools/clippy/clippy_lints/src/disallowed_types.rs
+++ b/src/tools/clippy/clippy_lints/src/disallowed_types.rs
@@ -35,6 +35,9 @@ declare_clippy_lint! {
     ///     { path = "std::net::Ipv4Addr", reason = "no IPv4 allowed" },
     ///     # Can also add a `replacement` that will be offered as a suggestion.
     ///     { path = "std::sync::Mutex", reason = "prefer faster & simpler non-poisonable mutex", replacement = "parking_lot::Mutex" },
+    ///     # This would normally error if the path is incorrect, but with `allow-invalid` = `true`,
+    ///     # it will be silently ignored
+    ///     { path = "std::invalid::Type", reason = "use alternative instead", allow-invalid = true }
     /// ]
     /// ```
     ///
diff --git a/src/tools/clippy/clippy_lints/src/doc/broken_link.rs b/src/tools/clippy/clippy_lints/src/doc/broken_link.rs
new file mode 100644
index 00000000000..4af10510023
--- /dev/null
+++ b/src/tools/clippy/clippy_lints/src/doc/broken_link.rs
@@ -0,0 +1,83 @@
+use clippy_utils::diagnostics::span_lint;
+use pulldown_cmark::BrokenLink as PullDownBrokenLink;
+use rustc_lint::LateContext;
+use rustc_resolve::rustdoc::{DocFragment, source_span_for_markdown_range};
+use rustc_span::{BytePos, Pos, Span};
+
+use super::DOC_BROKEN_LINK;
+
+/// Scan and report broken link on documents.
+/// It ignores false positives detected by `pulldown_cmark`, and only
+/// warns users when the broken link is consider a URL.
+// NOTE: We don't check these other cases because
+// rustdoc itself will check and warn about it:
+// - When a link url is broken across multiple lines in the URL path part
+// - When a link tag is missing the close parenthesis character at the end.
+// - When a link has whitespace within the url link.
+pub fn check(cx: &LateContext<'_>, bl: &PullDownBrokenLink<'_>, doc: &str, fragments: &[DocFragment]) {
+    warn_if_broken_link(cx, bl, doc, fragments);
+}
+
+fn warn_if_broken_link(cx: &LateContext<'_>, bl: &PullDownBrokenLink<'_>, doc: &str, fragments: &[DocFragment]) {
+    if let Some((span, _)) = source_span_for_markdown_range(cx.tcx, doc, &bl.span, fragments) {
+        let mut len = 0;
+
+        // grab raw link data
+        let (_, raw_link) = doc.split_at(bl.span.start);
+
+        // strip off link text part
+        let raw_link = match raw_link.split_once(']') {
+            None => return,
+            Some((prefix, suffix)) => {
+                len += prefix.len() + 1;
+                suffix
+            },
+        };
+
+        let raw_link = match raw_link.split_once('(') {
+            None => return,
+            Some((prefix, suffix)) => {
+                if !prefix.is_empty() {
+                    // there is text between ']' and '(' chars, so it is not a valid link
+                    return;
+                }
+                len += prefix.len() + 1;
+                suffix
+            },
+        };
+
+        if raw_link.starts_with("(http") {
+            // reduce chances of false positive reports
+            // by limiting this checking only to http/https links.
+            return;
+        }
+
+        for c in raw_link.chars() {
+            if c == ')' {
+                // it is a valid link
+                return;
+            }
+
+            if c == '\n' {
+                report_broken_link(cx, span, len);
+                break;
+            }
+
+            len += 1;
+        }
+    }
+}
+
+fn report_broken_link(cx: &LateContext<'_>, frag_span: Span, offset: usize) {
+    let start = frag_span.lo();
+    let end = start + BytePos::from_usize(offset);
+
+    let span = Span::new(start, end, frag_span.ctxt(), frag_span.parent());
+
+    span_lint(
+        cx,
+        DOC_BROKEN_LINK,
+        span,
+        "possible broken doc link: broken across multiple lines",
+    );
+}
diff --git a/src/tools/clippy/clippy_lints/src/doc/doc_suspicious_footnotes.rs b/src/tools/clippy/clippy_lints/src/doc/doc_suspicious_footnotes.rs
index 289b6b915d4..3330cc5defd 100644
--- a/src/tools/clippy/clippy_lints/src/doc/doc_suspicious_footnotes.rs
+++ b/src/tools/clippy/clippy_lints/src/doc/doc_suspicious_footnotes.rs
@@ -1,4 +1,5 @@
 use clippy_utils::diagnostics::span_lint_and_then;
+use rustc_ast::attr::AttributeExt as _;
 use rustc_ast::token::CommentKind;
 use rustc_errors::Applicability;
 use rustc_hir::{AttrStyle, Attribute};
@@ -43,13 +44,15 @@ pub fn check(cx: &LateContext<'_>, doc: &str, range: Range<usize>, fragments: &F
                 "looks like a footnote ref, but has no matching footnote",
                 |diag| {
                     if this_fragment.kind == DocFragmentKind::SugaredDoc {
-                        let (doc_attr, (_, doc_attr_comment_kind)) = attrs
+                        let (doc_attr, (_, doc_attr_comment_kind), attr_style) = attrs
                             .iter()
                             .filter(|attr| attr.span().overlaps(this_fragment.span))
                             .rev()
-                            .find_map(|attr| Some((attr, attr.doc_str_and_comment_kind()?)))
+                            .find_map(|attr| {
+                                Some((attr, attr.doc_str_and_comment_kind()?, attr.doc_resolution_scope()?))
+                            })
                             .unwrap();
-                        let (to_add, terminator) = match (doc_attr_comment_kind, doc_attr.style()) {
+                        let (to_add, terminator) = match (doc_attr_comment_kind, attr_style) {
                             (CommentKind::Line, AttrStyle::Outer) => ("\n///\n/// ", ""),
                             (CommentKind::Line, AttrStyle::Inner) => ("\n//!\n//! ", ""),
                             (CommentKind::Block, AttrStyle::Outer) => ("\n/** ", " */"),
diff --git a/src/tools/clippy/clippy_lints/src/doc/mod.rs b/src/tools/clippy/clippy_lints/src/doc/mod.rs
index e0fc2fd9347..5ea55e102df 100644
--- a/src/tools/clippy/clippy_lints/src/doc/mod.rs
+++ b/src/tools/clippy/clippy_lints/src/doc/mod.rs
@@ -24,6 +24,7 @@ use rustc_span::edition::Edition;
 use std::ops::Range;
 use url::Url;
 
+mod broken_link;
 mod doc_comment_double_space_linebreaks;
 mod doc_suspicious_footnotes;
 mod include_in_doc_without_cfg;
@@ -294,6 +295,34 @@ declare_clippy_lint! {
 
 declare_clippy_lint! {
     /// ### What it does
+    /// Checks the doc comments have unbroken links, mostly caused
+    /// by bad formatted links such as broken across multiple lines.
+    ///
+    /// ### Why is this bad?
+    /// Because documentation generated by rustdoc will be broken
+    /// since expected links won't be links and just text.
+    ///
+    /// ### Examples
+    /// This link is broken:
+    /// ```no_run
+    /// /// [example of a bad link](https://
+    /// /// github.com/rust-lang/rust-clippy/)
+    /// pub fn do_something() {}
+    /// ```
+    ///
+    /// It shouldn't be broken across multiple lines to work:
+    /// ```no_run
+    /// /// [example of a good link](https://github.com/rust-lang/rust-clippy/)
+    /// pub fn do_something() {}
+    /// ```
+    #[clippy::version = "1.84.0"]
+    pub DOC_BROKEN_LINK,
+    pedantic,
+    "broken document link"
+}
+
+declare_clippy_lint! {
+    /// ### What it does
     /// Checks for the doc comments of publicly visible
     /// safe functions and traits and warns if there is a `# Safety` section.
     ///
@@ -656,6 +685,7 @@ impl Documentation {
 impl_lint_pass!(Documentation => [
     DOC_LINK_CODE,
     DOC_LINK_WITH_QUOTES,
+    DOC_BROKEN_LINK,
     DOC_MARKDOWN,
     DOC_NESTED_REFDEFS,
     MISSING_SAFETY_DOC,
@@ -765,8 +795,8 @@ impl Fragments<'_> {
     /// get the span for the markdown range. Note that this function is not cheap, use it with
     /// caution.
     #[must_use]
-    fn span(&self, cx: &LateContext<'_>, range: Range<usize>) -> Option<Span> {
-        source_span_for_markdown_range(cx.tcx, self.doc, &range, self.fragments)
+    fn span(self, cx: &LateContext<'_>, range: Range<usize>) -> Option<Span> {
+        source_span_for_markdown_range(cx.tcx, self.doc, &range, self.fragments).map(|(sp, _)| sp)
     }
 }
 
@@ -786,9 +816,9 @@ struct DocHeaders {
 /// back in the various late lint pass methods if they need the final doc headers, like "Safety" or
 /// "Panics" sections.
 fn check_attrs(cx: &LateContext<'_>, valid_idents: &FxHashSet<String>, attrs: &[Attribute]) -> Option<DocHeaders> {
-    /// We don't want the parser to choke on intra doc links. Since we don't
-    /// actually care about rendering them, just pretend that all broken links
-    /// point to a fake address.
+    // We don't want the parser to choke on intra doc links. Since we don't
+    // actually care about rendering them, just pretend that all broken links
+    // point to a fake address.
     #[expect(clippy::unnecessary_wraps)] // we're following a type signature
     fn fake_broken_link_callback<'a>(_: BrokenLink<'_>) -> Option<(CowStr<'a>, CowStr<'a>)> {
         Some(("fake".into(), "fake".into()))
@@ -828,14 +858,12 @@ fn check_attrs(cx: &LateContext<'_>, valid_idents: &FxHashSet<String>, attrs: &[
         return Some(DocHeaders::default());
     }
 
-    let mut cb = fake_broken_link_callback;
-
     check_for_code_clusters(
         cx,
         pulldown_cmark::Parser::new_with_broken_link_callback(
             &doc,
             main_body_opts() - Options::ENABLE_SMART_PUNCTUATION,
-            Some(&mut cb),
+            Some(&mut fake_broken_link_callback),
         )
         .into_offset_iter(),
         &doc,
@@ -845,9 +873,17 @@ fn check_attrs(cx: &LateContext<'_>, valid_idents: &FxHashSet<String>, attrs: &[
         },
     );
 
+    // NOTE: check_doc uses it own cb function,
+    // to avoid causing duplicated diagnostics for the broken link checker.
+    let mut full_fake_broken_link_callback = |bl: BrokenLink<'_>| -> Option<(CowStr<'_>, CowStr<'_>)> {
+        broken_link::check(cx, &bl, &doc, &fragments);
+        Some(("fake".into(), "fake".into()))
+    };
+
     // disable smart punctuation to pick up ['link'] more easily
     let opts = main_body_opts() - Options::ENABLE_SMART_PUNCTUATION;
-    let parser = pulldown_cmark::Parser::new_with_broken_link_callback(&doc, opts, Some(&mut cb));
+    let parser =
+        pulldown_cmark::Parser::new_with_broken_link_callback(&doc, opts, Some(&mut full_fake_broken_link_callback));
 
     Some(check_doc(
         cx,
diff --git a/src/tools/clippy/clippy_lints/src/doc/needless_doctest_main.rs b/src/tools/clippy/clippy_lints/src/doc/needless_doctest_main.rs
index ec4538039a9..74283d7ba86 100644
--- a/src/tools/clippy/clippy_lints/src/doc/needless_doctest_main.rs
+++ b/src/tools/clippy/clippy_lints/src/doc/needless_doctest_main.rs
@@ -42,9 +42,8 @@ pub fn check(
                 let mut test_attr_spans = vec![];
                 let filename = FileName::anon_source_code(&code);
 
-                let fallback_bundle =
-                    rustc_errors::fallback_fluent_bundle(rustc_driver::DEFAULT_LOCALE_RESOURCES.to_vec(), false);
-                let emitter = HumanEmitter::new(Box::new(io::sink()), fallback_bundle);
+                let translator = rustc_driver::default_translator();
+                let emitter = HumanEmitter::new(Box::new(io::sink()), translator);
                 let dcx = DiagCtxt::new(Box::new(emitter)).disable_warnings();
                 #[expect(clippy::arc_with_non_send_sync)] // `Arc` is expected by with_dcx
                 let sm = Arc::new(SourceMap::new(FilePathMapping::empty()));
@@ -72,6 +71,7 @@ pub fn check(
                                 if !ignore {
                                     get_test_spans(&item, *ident, &mut test_attr_spans);
                                 }
+
                                 let is_async = matches!(sig.header.coroutine_kind, Some(CoroutineKind::Async { .. }));
                                 let returns_nothing = match &sig.decl.output {
                                     FnRetTy::Default(..) => true,
@@ -90,9 +90,14 @@ pub fn check(
                             // Another function was found; this case is ignored for needless_doctest_main
                             ItemKind::Fn(fn_) => {
                                 eligible = false;
-                                if !ignore {
-                                    get_test_spans(&item, fn_.ident, &mut test_attr_spans);
+                                if ignore {
+                                    // If ignore is active invalidating one lint,
+                                    // and we already found another function thus
+                                    // invalidating the other one, we have no
+                                    // business continuing.
+                                    return (false, test_attr_spans);
                                 }
+                                get_test_spans(&item, fn_.ident, &mut test_attr_spans);
                             },
                             // Tests with one of these items are ignored
                             ItemKind::Static(..)
@@ -105,7 +110,10 @@ pub fn check(
                         },
                         Ok(None) => break,
                         Err(e) => {
-                            e.cancel();
+                            // See issue #15041. When calling `.cancel()` on the `Diag`, Clippy will unexpectedly panic
+                            // when the `Diag` is unwinded. Meanwhile, we can just call `.emit()`, since the `DiagCtxt`
+                            // is just a sink, nothing will be printed.
+                            e.emit();
                             return (false, test_attr_spans);
                         },
                     }
@@ -120,6 +128,18 @@ pub fn check(
 
     let trailing_whitespace = text.len() - text.trim_end().len();
 
+    // We currently only test for "fn main". Checking for the real
+    // entrypoint (with tcx.entry_fn(())) in each block would be unnecessarily
+    // expensive, as those are probably intended and relevant. Same goes for
+    // macros and other weird ways of declaring a main function.
+    //
+    // Also, as we only check for attribute names and don't do macro expansion,
+    // we can check only for #[test]
+
+    if !((text.contains("main") && text.contains("fn")) || text.contains("#[test]")) {
+        return;
+    }
+
     // Because of the global session, we need to create a new session in a different thread with
     // the edition we need.
     let text = text.to_owned();
diff --git a/src/tools/clippy/clippy_lints/src/empty_line_after.rs b/src/tools/clippy/clippy_lints/src/empty_line_after.rs
index 0c5f8bbf4ca..3bd74856165 100644
--- a/src/tools/clippy/clippy_lints/src/empty_line_after.rs
+++ b/src/tools/clippy/clippy_lints/src/empty_line_after.rs
@@ -10,7 +10,7 @@ use rustc_errors::{Applicability, Diag, SuggestionStyle};
 use rustc_lexer::TokenKind;
 use rustc_lint::{EarlyContext, EarlyLintPass, LintContext};
 use rustc_session::impl_lint_pass;
-use rustc_span::{BytePos, ExpnKind, Ident, InnerSpan, Span, SpanData, Symbol, kw};
+use rustc_span::{BytePos, ExpnKind, Ident, InnerSpan, Span, SpanData, Symbol, kw, sym};
 
 declare_clippy_lint! {
     /// ### What it does
@@ -129,10 +129,55 @@ struct Stop {
     kind: StopKind,
     first: usize,
     last: usize,
+    name: Option<Symbol>,
 }
 
 impl Stop {
-    fn convert_to_inner(&self) -> (Span, String) {
+    fn is_outer_attr_only(&self) -> bool {
+        let Some(name) = self.name else {
+            return false;
+        };
+        // Check if the attribute only has effect when as an outer attribute
+        // The below attributes are collected from the builtin attributes of The Rust Reference
+        // https://doc.rust-lang.org/reference/attributes.html#r-attributes.builtin
+        // And the comments below are from compiler errors and warnings
+        matches!(
+            name,
+            // Cannot be used at crate level
+            sym::repr | sym::test | sym::derive | sym::automatically_derived | sym::path | sym::global_allocator |
+            // Only has an effect on macro definitions
+            sym::macro_export |
+            // Only be applied to trait definitions
+            sym::on_unimplemented |
+            // Only be placed on trait implementations
+            sym::do_not_recommend |
+            // Only has an effect on items
+            sym::ignore | sym::should_panic | sym::proc_macro | sym::proc_macro_derive | sym::proc_macro_attribute |
+            // Has no effect when applied to a module
+            sym::must_use |
+            // Should be applied to a foreign function or static
+            sym::link_name | sym::link_ordinal | sym::link_section |
+            // Should be applied to an `extern crate` item
+            sym::no_link |
+            // Should be applied to a free function, impl method or static
+            sym::export_name | sym::no_mangle |
+            // Should be applied to a `static` variable
+            sym::used |
+            // Should be applied to function or closure
+            sym::inline |
+            // Should be applied to a function definition
+            sym::cold | sym::target_feature | sym::track_caller | sym::instruction_set |
+            // Should be applied to a struct or enum
+            sym::non_exhaustive |
+            // Note: No any warning when it as an inner attribute, but it has no effect
+            sym::panic_handler
+        )
+    }
+
+    fn convert_to_inner(&self) -> Option<(Span, String)> {
+        if self.is_outer_attr_only() {
+            return None;
+        }
         let inner = match self.kind {
             // #![...]
             StopKind::Attr => InnerSpan::new(1, 1),
@@ -140,7 +185,7 @@ impl Stop {
             //   ^      ^
             StopKind::Doc(_) => InnerSpan::new(2, 3),
         };
-        (self.span.from_inner(inner), "!".into())
+        Some((self.span.from_inner(inner), "!".into()))
     }
 
     fn comment_out(&self, cx: &EarlyContext<'_>, suggestions: &mut Vec<(Span, String)>) {
@@ -177,6 +222,7 @@ impl Stop {
             },
             first: file.lookup_line(file.relative_position(lo))?,
             last: file.lookup_line(file.relative_position(hi))?,
+            name: attr.name(),
         })
     }
 }
@@ -356,6 +402,12 @@ impl EmptyLineAfter {
         if let Some(parent) = self.items.iter().rev().nth(1)
             && (parent.kind == "module" || parent.kind == "crate")
             && parent.mod_items == Some(id)
+            && let suggestions = gaps
+                .iter()
+                .flat_map(|gap| gap.prev_chunk)
+                .filter_map(Stop::convert_to_inner)
+                .collect::<Vec<_>>()
+            && !suggestions.is_empty()
         {
             let desc = if parent.kind == "module" {
                 "parent module"
@@ -367,10 +419,7 @@ impl EmptyLineAfter {
                     StopKind::Attr => format!("if the attribute should apply to the {desc} use an inner attribute"),
                     StopKind::Doc(_) => format!("if the comment should document the {desc} use an inner doc comment"),
                 },
-                gaps.iter()
-                    .flat_map(|gap| gap.prev_chunk)
-                    .map(Stop::convert_to_inner)
-                    .collect(),
+                suggestions,
                 Applicability::MaybeIncorrect,
             );
         }
@@ -425,6 +474,7 @@ impl EmptyLineAfter {
                 first: line.line,
                 // last doesn't need to be accurate here, we don't compare it with anything
                 last: line.line,
+                name: None,
             });
         }
 
diff --git a/src/tools/clippy/clippy_lints/src/eta_reduction.rs b/src/tools/clippy/clippy_lints/src/eta_reduction.rs
index 6ed7c87915b..0288747d6f3 100644
--- a/src/tools/clippy/clippy_lints/src/eta_reduction.rs
+++ b/src/tools/clippy/clippy_lints/src/eta_reduction.rs
@@ -1,4 +1,4 @@
-use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_and_then};
+use clippy_utils::diagnostics::span_lint_hir_and_then;
 use clippy_utils::higher::VecArgs;
 use clippy_utils::source::{snippet_opt, snippet_with_applicability};
 use clippy_utils::ty::get_type_diagnostic_name;
@@ -7,6 +7,7 @@ use clippy_utils::{
     get_path_from_caller_to_method_type, is_adjusted, is_no_std_crate, path_to_local, path_to_local_id,
 };
 use rustc_abi::ExternAbi;
+use rustc_attr_data_structures::{AttributeKind, find_attr};
 use rustc_errors::Applicability;
 use rustc_hir::{BindingMode, Expr, ExprKind, FnRetTy, GenericArgs, Param, PatKind, QPath, Safety, TyKind};
 use rustc_infer::infer::TyCtxtInferExt;
@@ -108,14 +109,20 @@ fn check_closure<'tcx>(cx: &LateContext<'tcx>, outer_receiver: Option<&Expr<'tcx
         {
             let vec_crate = if is_no_std_crate(cx) { "alloc" } else { "std" };
             // replace `|| vec![]` with `Vec::new`
-            span_lint_and_sugg(
+            span_lint_hir_and_then(
                 cx,
                 REDUNDANT_CLOSURE,
+                expr.hir_id,
                 expr.span,
                 "redundant closure",
-                "replace the closure with `Vec::new`",
-                format!("{vec_crate}::vec::Vec::new"),
-                Applicability::MachineApplicable,
+                |diag| {
+                    diag.span_suggestion(
+                        expr.span,
+                        "replace the closure with `Vec::new`",
+                        format!("{vec_crate}::vec::Vec::new"),
+                        Applicability::MachineApplicable,
+                    );
+                },
             );
         }
         // skip `foo(|| macro!())`
@@ -155,7 +162,7 @@ fn check_closure<'tcx>(cx: &LateContext<'tcx>, outer_receiver: Option<&Expr<'tcx
             let sig = match callee_ty_adjusted.kind() {
                 ty::FnDef(def, _) => {
                     // Rewriting `x(|| f())` to `x(f)` where f is marked `#[track_caller]` moves the `Location`
-                    if cx.tcx.has_attr(*def, sym::track_caller) {
+                    if find_attr!(cx.tcx.get_all_attrs(*def), AttributeKind::TrackCaller(..)) {
                         return;
                     }
 
@@ -197,46 +204,53 @@ fn check_closure<'tcx>(cx: &LateContext<'tcx>, outer_receiver: Option<&Expr<'tcx
                 // For now ignore all callee types which reference a type parameter.
                 && !generic_args.types().any(|t| matches!(t.kind(), ty::Param(_)))
             {
-                span_lint_and_then(cx, REDUNDANT_CLOSURE, expr.span, "redundant closure", |diag| {
-                    if let Some(mut snippet) = snippet_opt(cx, callee.span) {
-                        if path_to_local(callee).is_some_and(|l| {
-                            // FIXME: Do we really need this `local_used_in` check?
-                            // Isn't it checking something like... `callee(callee)`?
-                            // If somehow this check is needed, add some test for it,
-                            // 'cuz currently nothing changes after deleting this check.
-                            local_used_in(cx, l, args) || local_used_after_expr(cx, l, expr)
-                        }) {
-                            match cx
-                                .tcx
-                                .infer_ctxt()
-                                .build(cx.typing_mode())
-                                .err_ctxt()
-                                .type_implements_fn_trait(
-                                    cx.param_env,
-                                    Binder::bind_with_vars(callee_ty_adjusted, List::empty()),
-                                    ty::PredicatePolarity::Positive,
-                                ) {
-                                // Mutable closure is used after current expr; we cannot consume it.
-                                Ok((ClosureKind::FnMut, _)) => snippet = format!("&mut {snippet}"),
-                                Ok((ClosureKind::Fn, _)) if !callee_ty_raw.is_ref() => {
-                                    snippet = format!("&{snippet}");
-                                },
-                                _ => (),
+                span_lint_hir_and_then(
+                    cx,
+                    REDUNDANT_CLOSURE,
+                    expr.hir_id,
+                    expr.span,
+                    "redundant closure",
+                    |diag| {
+                        if let Some(mut snippet) = snippet_opt(cx, callee.span) {
+                            if path_to_local(callee).is_some_and(|l| {
+                                // FIXME: Do we really need this `local_used_in` check?
+                                // Isn't it checking something like... `callee(callee)`?
+                                // If somehow this check is needed, add some test for it,
+                                // 'cuz currently nothing changes after deleting this check.
+                                local_used_in(cx, l, args) || local_used_after_expr(cx, l, expr)
+                            }) {
+                                match cx
+                                    .tcx
+                                    .infer_ctxt()
+                                    .build(cx.typing_mode())
+                                    .err_ctxt()
+                                    .type_implements_fn_trait(
+                                        cx.param_env,
+                                        Binder::bind_with_vars(callee_ty_adjusted, List::empty()),
+                                        ty::PredicatePolarity::Positive,
+                                    ) {
+                                    // Mutable closure is used after current expr; we cannot consume it.
+                                    Ok((ClosureKind::FnMut, _)) => snippet = format!("&mut {snippet}"),
+                                    Ok((ClosureKind::Fn, _)) if !callee_ty_raw.is_ref() => {
+                                        snippet = format!("&{snippet}");
+                                    },
+                                    _ => (),
+                                }
                             }
+                            diag.span_suggestion(
+                                expr.span,
+                                "replace the closure with the function itself",
+                                snippet,
+                                Applicability::MachineApplicable,
+                            );
                         }
-                        diag.span_suggestion(
-                            expr.span,
-                            "replace the closure with the function itself",
-                            snippet,
-                            Applicability::MachineApplicable,
-                        );
-                    }
-                });
+                    },
+                );
             }
         },
         ExprKind::MethodCall(path, self_, args, _) if check_inputs(typeck, body.params, Some(self_), args) => {
             if let Some(method_def_id) = typeck.type_dependent_def_id(body.value.hir_id)
-                && !cx.tcx.has_attr(method_def_id, sym::track_caller)
+                && !find_attr!(cx.tcx.get_all_attrs(method_def_id), AttributeKind::TrackCaller(..))
                 && check_sig(closure_sig, cx.tcx.fn_sig(method_def_id).skip_binder().skip_binder())
             {
                 let mut app = Applicability::MachineApplicable;
@@ -244,9 +258,10 @@ fn check_closure<'tcx>(cx: &LateContext<'tcx>, outer_receiver: Option<&Expr<'tcx
                     Some(span) => format!("::{}", snippet_with_applicability(cx, span, "<..>", &mut app)),
                     None => String::new(),
                 };
-                span_lint_and_then(
+                span_lint_hir_and_then(
                     cx,
                     REDUNDANT_CLOSURE_FOR_METHOD_CALLS,
+                    expr.hir_id,
                     expr.span,
                     "redundant closure",
                     |diag| {
diff --git a/src/tools/clippy/clippy_lints/src/exhaustive_items.rs b/src/tools/clippy/clippy_lints/src/exhaustive_items.rs
index 1fb0e4d24d0..86d9038ec45 100644
--- a/src/tools/clippy/clippy_lints/src/exhaustive_items.rs
+++ b/src/tools/clippy/clippy_lints/src/exhaustive_items.rs
@@ -76,7 +76,7 @@ impl LateLintPass<'_> for ExhaustiveItems {
                 "exported enums should not be exhaustive",
                 [].as_slice(),
             ),
-            ItemKind::Struct(_, _, v) => (
+            ItemKind::Struct(_, _, v) if v.fields().iter().all(|f| f.default.is_none()) => (
                 EXHAUSTIVE_STRUCTS,
                 "exported structs should not be exhaustive",
                 v.fields(),
diff --git a/src/tools/clippy/clippy_lints/src/floating_point_arithmetic.rs b/src/tools/clippy/clippy_lints/src/floating_point_arithmetic.rs
index 3c7e83b0697..b3c9e860758 100644
--- a/src/tools/clippy/clippy_lints/src/floating_point_arithmetic.rs
+++ b/src/tools/clippy/clippy_lints/src/floating_point_arithmetic.rs
@@ -5,14 +5,13 @@ use clippy_utils::{
     eq_expr_value, get_parent_expr, higher, is_in_const_context, is_inherent_method_call, is_no_std_crate,
     numeric_literal, peel_blocks, sugg, sym,
 };
+use rustc_ast::ast;
 use rustc_errors::Applicability;
 use rustc_hir::{BinOpKind, Expr, ExprKind, PathSegment, UnOp};
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_middle::ty;
 use rustc_session::declare_lint_pass;
 use rustc_span::source_map::Spanned;
-
-use rustc_ast::ast;
 use std::f32::consts as f32_consts;
 use std::f64::consts as f64_consts;
 use sugg::Sugg;
diff --git a/src/tools/clippy/clippy_lints/src/functions/must_use.rs b/src/tools/clippy/clippy_lints/src/functions/must_use.rs
index 70655838b6a..d959981a83c 100644
--- a/src/tools/clippy/clippy_lints/src/functions/must_use.rs
+++ b/src/tools/clippy/clippy_lints/src/functions/must_use.rs
@@ -14,6 +14,8 @@ use clippy_utils::source::SpanRangeExt;
 use clippy_utils::ty::is_must_use_ty;
 use clippy_utils::visitors::for_each_expr_without_closures;
 use clippy_utils::{return_ty, trait_ref_of_method};
+use rustc_attr_data_structures::{AttributeKind, find_attr};
+use rustc_span::Symbol;
 use rustc_trait_selection::error_reporting::InferCtxtErrorExt;
 
 use core::ops::ControlFlow;
@@ -22,7 +24,7 @@ use super::{DOUBLE_MUST_USE, MUST_USE_CANDIDATE, MUST_USE_UNIT};
 
 pub(super) fn check_item<'tcx>(cx: &LateContext<'tcx>, item: &'tcx hir::Item<'_>) {
     let attrs = cx.tcx.hir_attrs(item.hir_id());
-    let attr = cx.tcx.get_attr(item.owner_id, sym::must_use);
+    let attr = find_attr!(cx.tcx.hir_attrs(item.hir_id()), AttributeKind::MustUse { span, reason } => (span, reason));
     if let hir::ItemKind::Fn {
         ref sig,
         body: ref body_id,
@@ -31,9 +33,19 @@ pub(super) fn check_item<'tcx>(cx: &LateContext<'tcx>, item: &'tcx hir::Item<'_>
     {
         let is_public = cx.effective_visibilities.is_exported(item.owner_id.def_id);
         let fn_header_span = item.span.with_hi(sig.decl.output.span().hi());
-        if let Some(attr) = attr {
-            check_needless_must_use(cx, sig.decl, item.owner_id, item.span, fn_header_span, attr, attrs, sig);
-        } else if is_public && !is_proc_macro(attrs) && !attrs.iter().any(|a| a.has_name(sym::no_mangle)) {
+        if let Some((attr_span, reason)) = attr {
+            check_needless_must_use(
+                cx,
+                sig.decl,
+                item.owner_id,
+                item.span,
+                fn_header_span,
+                *attr_span,
+                *reason,
+                attrs,
+                sig,
+            );
+        } else if is_public && !is_proc_macro(attrs) && !find_attr!(attrs, AttributeKind::NoMangle(..)) {
             check_must_use_candidate(
                 cx,
                 sig.decl,
@@ -52,9 +64,20 @@ pub(super) fn check_impl_item<'tcx>(cx: &LateContext<'tcx>, item: &'tcx hir::Imp
         let is_public = cx.effective_visibilities.is_exported(item.owner_id.def_id);
         let fn_header_span = item.span.with_hi(sig.decl.output.span().hi());
         let attrs = cx.tcx.hir_attrs(item.hir_id());
-        let attr = cx.tcx.get_attr(item.owner_id, sym::must_use);
-        if let Some(attr) = attr {
-            check_needless_must_use(cx, sig.decl, item.owner_id, item.span, fn_header_span, attr, attrs, sig);
+        let attr =
+            find_attr!(cx.tcx.hir_attrs(item.hir_id()), AttributeKind::MustUse { span, reason } => (span, reason));
+        if let Some((attr_span, reason)) = attr {
+            check_needless_must_use(
+                cx,
+                sig.decl,
+                item.owner_id,
+                item.span,
+                fn_header_span,
+                *attr_span,
+                *reason,
+                attrs,
+                sig,
+            );
         } else if is_public && !is_proc_macro(attrs) && trait_ref_of_method(cx, item.owner_id).is_none() {
             check_must_use_candidate(
                 cx,
@@ -75,9 +98,20 @@ pub(super) fn check_trait_item<'tcx>(cx: &LateContext<'tcx>, item: &'tcx hir::Tr
         let fn_header_span = item.span.with_hi(sig.decl.output.span().hi());
 
         let attrs = cx.tcx.hir_attrs(item.hir_id());
-        let attr = cx.tcx.get_attr(item.owner_id, sym::must_use);
-        if let Some(attr) = attr {
-            check_needless_must_use(cx, sig.decl, item.owner_id, item.span, fn_header_span, attr, attrs, sig);
+        let attr =
+            find_attr!(cx.tcx.hir_attrs(item.hir_id()), AttributeKind::MustUse { span, reason } => (span, reason));
+        if let Some((attr_span, reason)) = attr {
+            check_needless_must_use(
+                cx,
+                sig.decl,
+                item.owner_id,
+                item.span,
+                fn_header_span,
+                *attr_span,
+                *reason,
+                attrs,
+                sig,
+            );
         } else if let hir::TraitFn::Provided(eid) = *eid {
             let body = cx.tcx.hir_body(eid);
             if attr.is_none() && is_public && !is_proc_macro(attrs) {
@@ -103,7 +137,8 @@ fn check_needless_must_use(
     item_id: hir::OwnerId,
     item_span: Span,
     fn_header_span: Span,
-    attr: &Attribute,
+    attr_span: Span,
+    reason: Option<Symbol>,
     attrs: &[Attribute],
     sig: &FnSig<'_>,
 ) {
@@ -118,12 +153,7 @@ fn check_needless_must_use(
                 fn_header_span,
                 "this unit-returning function has a `#[must_use]` attribute",
                 |diag| {
-                    diag.span_suggestion(
-                        attr.span(),
-                        "remove the attribute",
-                        "",
-                        Applicability::MachineApplicable,
-                    );
+                    diag.span_suggestion(attr_span, "remove the attribute", "", Applicability::MachineApplicable);
                 },
             );
         } else {
@@ -137,11 +167,11 @@ fn check_needless_must_use(
                 MUST_USE_UNIT,
                 fn_header_span,
                 "this unit-returning function has a `#[must_use]` attribute",
-                Some(attr.span()),
+                Some(attr_span),
                 "remove `must_use`",
             );
         }
-    } else if attr.value_str().is_none() && is_must_use_ty(cx, return_ty(cx, item_id)) {
+    } else if reason.is_none() && is_must_use_ty(cx, return_ty(cx, item_id)) {
         // Ignore async functions unless Future::Output type is a must_use type
         if sig.header.is_async() {
             let infcx = cx.tcx.infer_ctxt().build(cx.typing_mode());
diff --git a/src/tools/clippy/clippy_lints/src/if_not_else.rs b/src/tools/clippy/clippy_lints/src/if_not_else.rs
index 45f9aa0a53e..ab7a965b367 100644
--- a/src/tools/clippy/clippy_lints/src/if_not_else.rs
+++ b/src/tools/clippy/clippy_lints/src/if_not_else.rs
@@ -1,4 +1,4 @@
-use clippy_utils::consts::{ConstEvalCtxt, Constant};
+use clippy_utils::consts::is_zero_integer_const;
 use clippy_utils::diagnostics::{span_lint_and_help, span_lint_and_sugg};
 use clippy_utils::is_else_clause;
 use clippy_utils::source::{HasSession, indent_of, reindent_multiline, snippet};
@@ -48,13 +48,6 @@ declare_clippy_lint! {
 
 declare_lint_pass!(IfNotElse => [IF_NOT_ELSE]);
 
-fn is_zero_const(expr: &Expr<'_>, cx: &LateContext<'_>) -> bool {
-    if let Some(value) = ConstEvalCtxt::new(cx).eval_simple(expr) {
-        return Constant::Int(0) == value;
-    }
-    false
-}
-
 impl LateLintPass<'_> for IfNotElse {
     fn check_expr(&mut self, cx: &LateContext<'_>, e: &Expr<'_>) {
         if let ExprKind::If(cond, cond_inner, Some(els)) = e.kind
@@ -68,7 +61,7 @@ impl LateLintPass<'_> for IfNotElse {
                 ),
                 // Don't lint on `… != 0`, as these are likely to be bit tests.
                 // For example, `if foo & 0x0F00 != 0 { … } else { … }` is already in the "proper" order.
-                ExprKind::Binary(op, _, rhs) if op.node == BinOpKind::Ne && !is_zero_const(rhs, cx) => (
+                ExprKind::Binary(op, _, rhs) if op.node == BinOpKind::Ne && !is_zero_integer_const(cx, rhs) => (
                     "unnecessary `!=` operation",
                     "change to `==` and swap the blocks of the `if`/`else`",
                 ),
diff --git a/src/tools/clippy/clippy_lints/src/inline_fn_without_body.rs b/src/tools/clippy/clippy_lints/src/inline_fn_without_body.rs
index 617c006795b..ffe6ad14f63 100644
--- a/src/tools/clippy/clippy_lints/src/inline_fn_without_body.rs
+++ b/src/tools/clippy/clippy_lints/src/inline_fn_without_body.rs
@@ -1,6 +1,6 @@
 use clippy_utils::diagnostics::span_lint_and_then;
 use clippy_utils::sugg::DiagExt;
-use rustc_attr_data_structures::{find_attr, AttributeKind};
+use rustc_attr_data_structures::{AttributeKind, find_attr};
 use rustc_errors::Applicability;
 use rustc_hir::{TraitFn, TraitItem, TraitItemKind};
 use rustc_lint::{LateContext, LateLintPass};
@@ -33,10 +33,10 @@ impl<'tcx> LateLintPass<'tcx> for InlineFnWithoutBody {
     fn check_trait_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx TraitItem<'_>) {
         if let TraitItemKind::Fn(_, TraitFn::Required(_)) = item.kind
             && let Some(attr_span) = find_attr!(cx
-                .tcx
-                .hir_attrs(item.hir_id()),
-                AttributeKind::Inline(_, span) => *span
-        )
+                    .tcx
+                    .hir_attrs(item.hir_id()),
+                    AttributeKind::Inline(_, span) => *span
+            )
         {
             span_lint_and_then(
                 cx,
diff --git a/src/tools/clippy/clippy_lints/src/lib.rs b/src/tools/clippy/clippy_lints/src/lib.rs
index be9142b17fe..96a6dee5885 100644
--- a/src/tools/clippy/clippy_lints/src/lib.rs
+++ b/src/tools/clippy/clippy_lints/src/lib.rs
@@ -59,10 +59,10 @@ extern crate smallvec;
 extern crate thin_vec;
 
 #[macro_use]
-mod declare_clippy_lint;
+extern crate clippy_utils;
 
 #[macro_use]
-extern crate clippy_utils;
+extern crate declare_clippy_lint;
 
 mod utils;
 
@@ -411,108 +411,9 @@ mod zombie_processes;
 use clippy_config::{Conf, get_configuration_metadata, sanitize_explanation};
 use clippy_utils::macros::FormatArgsStorage;
 use rustc_data_structures::fx::FxHashSet;
-use rustc_lint::{Lint, LintId};
+use rustc_lint::Lint;
 use utils::attr_collector::{AttrCollector, AttrStorage};
 
-#[derive(Default)]
-struct RegistrationGroups {
-    all: Vec<LintId>,
-    cargo: Vec<LintId>,
-    complexity: Vec<LintId>,
-    correctness: Vec<LintId>,
-    nursery: Vec<LintId>,
-    pedantic: Vec<LintId>,
-    perf: Vec<LintId>,
-    restriction: Vec<LintId>,
-    style: Vec<LintId>,
-    suspicious: Vec<LintId>,
-}
-
-impl RegistrationGroups {
-    #[rustfmt::skip]
-    fn register(self, store: &mut rustc_lint::LintStore) {
-        store.register_group(true, "clippy::all", Some("clippy_all"), self.all);
-        store.register_group(true, "clippy::cargo", Some("clippy_cargo"), self.cargo);
-        store.register_group(true, "clippy::complexity", Some("clippy_complexity"), self.complexity);
-        store.register_group(true, "clippy::correctness", Some("clippy_correctness"), self.correctness);
-        store.register_group(true, "clippy::nursery", Some("clippy_nursery"), self.nursery);
-        store.register_group(true, "clippy::pedantic", Some("clippy_pedantic"), self.pedantic);
-        store.register_group(true, "clippy::perf", Some("clippy_perf"), self.perf);
-        store.register_group(true, "clippy::restriction", Some("clippy_restriction"), self.restriction);
-        store.register_group(true, "clippy::style", Some("clippy_style"), self.style);
-        store.register_group(true, "clippy::suspicious", Some("clippy_suspicious"), self.suspicious);
-    }
-}
-
-#[derive(Copy, Clone, Debug)]
-pub(crate) enum LintCategory {
-    Cargo,
-    Complexity,
-    Correctness,
-    Nursery,
-    Pedantic,
-    Perf,
-    Restriction,
-    Style,
-    Suspicious,
-}
-
-#[allow(clippy::enum_glob_use)]
-use LintCategory::*;
-
-impl LintCategory {
-    fn is_all(self) -> bool {
-        matches!(self, Correctness | Suspicious | Style | Complexity | Perf)
-    }
-
-    fn group(self, groups: &mut RegistrationGroups) -> &mut Vec<LintId> {
-        match self {
-            Cargo => &mut groups.cargo,
-            Complexity => &mut groups.complexity,
-            Correctness => &mut groups.correctness,
-            Nursery => &mut groups.nursery,
-            Pedantic => &mut groups.pedantic,
-            Perf => &mut groups.perf,
-            Restriction => &mut groups.restriction,
-            Style => &mut groups.style,
-            Suspicious => &mut groups.suspicious,
-        }
-    }
-}
-
-pub struct LintInfo {
-    /// Double reference to maintain pointer equality
-    pub lint: &'static &'static Lint,
-    category: LintCategory,
-    pub explanation: &'static str,
-    /// e.g. `clippy_lints/src/absolute_paths.rs#43`
-    pub location: &'static str,
-    pub version: Option<&'static str>,
-}
-
-impl LintInfo {
-    /// Returns the lint name in lowercase without the `clippy::` prefix
-    #[allow(clippy::missing_panics_doc)]
-    pub fn name_lower(&self) -> String {
-        self.lint.name.strip_prefix("clippy::").unwrap().to_ascii_lowercase()
-    }
-
-    /// Returns the name of the lint's category in lowercase (`style`, `pedantic`)
-    pub fn category_str(&self) -> &'static str {
-        match self.category {
-            Cargo => "cargo",
-            Complexity => "complexity",
-            Correctness => "correctness",
-            Nursery => "nursery",
-            Pedantic => "pedantic",
-            Perf => "perf",
-            Restriction => "restriction",
-            Style => "style",
-            Suspicious => "suspicious",
-        }
-    }
-}
-
 pub fn explain(name: &str) -> i32 {
     let target = format!("clippy::{}", name.to_ascii_uppercase());
 
@@ -535,30 +436,11 @@ pub fn explain(name: &str) -> i32 {
     }
 }
 
-fn register_categories(store: &mut rustc_lint::LintStore) {
-    let mut groups = RegistrationGroups::default();
-
-    for LintInfo { lint, category, .. } in declared_lints::LINTS {
-        if category.is_all() {
-            groups.all.push(LintId::of(lint));
-        }
-
-        category.group(&mut groups).push(LintId::of(lint));
-    }
-
-    let lints: Vec<&'static Lint> = declared_lints::LINTS.iter().map(|info| *info.lint).collect();
-
-    store.register_lints(&lints);
-    groups.register(store);
-}
-
 /// Register all lints and lint groups with the rustc lint store
 ///
 /// Used in `./src/driver.rs`.
 #[expect(clippy::too_many_lines)]
-pub fn register_lints(store: &mut rustc_lint::LintStore, conf: &'static Conf) {
-    register_categories(store);
-
+pub fn register_lint_passes(store: &mut rustc_lint::LintStore, conf: &'static Conf) {
     for (old_name, new_name) in deprecated_lints::RENAMED {
         store.register_renamed(old_name, new_name);
     }
diff --git a/src/tools/clippy/clippy_lints/src/loops/same_item_push.rs b/src/tools/clippy/clippy_lints/src/loops/same_item_push.rs
index 388034c39f5..e792edbe23e 100644
--- a/src/tools/clippy/clippy_lints/src/loops/same_item_push.rs
+++ b/src/tools/clippy/clippy_lints/src/loops/same_item_push.rs
@@ -163,15 +163,14 @@ impl<'tcx> Visitor<'tcx> for SameItemPushVisitor<'_, 'tcx> {
                 StmtKind::Expr(expr) | StmtKind::Semi(expr) => self.visit_expr(expr),
                 _ => {},
             }
+        }
+        // Current statement is a push ...check whether another
+        // push had been previously done
+        else if self.vec_push.is_none() {
+            self.vec_push = vec_push_option;
         } else {
-            // Current statement is a push ...check whether another
-            // push had been previously done
-            if self.vec_push.is_none() {
-                self.vec_push = vec_push_option;
-            } else {
-                // There are multiple pushes ... don't lint
-                self.multiple_pushes = true;
-            }
+            // There are multiple pushes ... don't lint
+            self.multiple_pushes = true;
         }
     }
 }
diff --git a/src/tools/clippy/clippy_lints/src/manual_let_else.rs b/src/tools/clippy/clippy_lints/src/manual_let_else.rs
index 0b3bec714c0..9ff82cdcb66 100644
--- a/src/tools/clippy/clippy_lints/src/manual_let_else.rs
+++ b/src/tools/clippy/clippy_lints/src/manual_let_else.rs
@@ -13,7 +13,6 @@ use rustc_errors::Applicability;
 use rustc_hir::def::{CtorOf, DefKind, Res};
 use rustc_hir::{Arm, Expr, ExprKind, HirId, MatchSource, Pat, PatExpr, PatExprKind, PatKind, QPath, Stmt, StmtKind};
 use rustc_lint::{LateContext, LintContext};
-
 use rustc_span::Span;
 use rustc_span::symbol::{Symbol, sym};
 use std::slice;
diff --git a/src/tools/clippy/clippy_lints/src/manual_option_as_slice.rs b/src/tools/clippy/clippy_lints/src/manual_option_as_slice.rs
index b55c11f2d5b..922db174e3d 100644
--- a/src/tools/clippy/clippy_lints/src/manual_option_as_slice.rs
+++ b/src/tools/clippy/clippy_lints/src/manual_option_as_slice.rs
@@ -1,7 +1,7 @@
 use clippy_config::Conf;
 use clippy_utils::diagnostics::{span_lint, span_lint_and_sugg};
 use clippy_utils::msrvs::Msrv;
-use clippy_utils::{is_none_arm, msrvs, paths, peel_hir_expr_refs, sym};
+use clippy_utils::{is_none_arm, msrvs, peel_hir_expr_refs, sym};
 use rustc_errors::Applicability;
 use rustc_hir::def::{DefKind, Res};
 use rustc_hir::{Arm, Expr, ExprKind, LangItem, Pat, PatKind, QPath, is_range_literal};
@@ -220,5 +220,5 @@ fn is_empty_slice(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
 }
 
 fn is_slice_from_ref(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
-    paths::SLICE_FROM_REF.matches_path(cx, expr)
+    clippy_utils::is_path_diagnostic_item(cx, expr, sym::slice_from_ref)
 }
diff --git a/src/tools/clippy/clippy_lints/src/matches/manual_ok_err.rs b/src/tools/clippy/clippy_lints/src/matches/manual_ok_err.rs
index 4959908dad6..edbb556fd97 100644
--- a/src/tools/clippy/clippy_lints/src/matches/manual_ok_err.rs
+++ b/src/tools/clippy/clippy_lints/src/matches/manual_ok_err.rs
@@ -1,9 +1,9 @@
 use clippy_utils::diagnostics::span_lint_and_sugg;
 use clippy_utils::source::{indent_of, reindent_multiline};
 use clippy_utils::sugg::Sugg;
-use clippy_utils::ty::option_arg_ty;
+use clippy_utils::ty::{option_arg_ty, peel_mid_ty_refs_is_mutable};
 use clippy_utils::{get_parent_expr, is_res_lang_ctor, path_res, peel_blocks, span_contains_comment};
-use rustc_ast::BindingMode;
+use rustc_ast::{BindingMode, Mutability};
 use rustc_errors::Applicability;
 use rustc_hir::LangItem::{OptionNone, OptionSome, ResultErr};
 use rustc_hir::def::{DefKind, Res};
@@ -133,7 +133,21 @@ fn apply_lint(cx: &LateContext<'_>, expr: &Expr<'_>, scrutinee: &Expr<'_>, is_ok
         Applicability::MachineApplicable
     };
     let scrut = Sugg::hir_with_applicability(cx, scrutinee, "..", &mut app).maybe_paren();
-    let sugg = format!("{scrut}.{method}()");
+
+    let scrutinee_ty = cx.typeck_results().expr_ty(scrutinee);
+    let (_, n_ref, mutability) = peel_mid_ty_refs_is_mutable(scrutinee_ty);
+    let prefix = if n_ref > 0 {
+        if mutability == Mutability::Mut {
+            ".as_mut()"
+        } else {
+            ".as_ref()"
+        }
+    } else {
+        ""
+    };
+
+    let sugg = format!("{scrut}{prefix}.{method}()");
+
     // If the expression being expanded is the `if …` part of an `else if …`, it must be blockified.
     let sugg = if let Some(parent_expr) = get_parent_expr(cx, expr)
         && let ExprKind::If(_, _, Some(else_part)) = parent_expr.kind
diff --git a/src/tools/clippy/clippy_lints/src/matches/match_wild_enum.rs b/src/tools/clippy/clippy_lints/src/matches/match_wild_enum.rs
index 24b4a675800..70a03ff9376 100644
--- a/src/tools/clippy/clippy_lints/src/matches/match_wild_enum.rs
+++ b/src/tools/clippy/clippy_lints/src/matches/match_wild_enum.rs
@@ -1,4 +1,5 @@
 use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_and_then};
+use clippy_utils::source::SpanRangeExt;
 use clippy_utils::ty::is_type_diagnostic_item;
 use clippy_utils::{is_refutable, peel_hir_pat_refs, recurse_or_patterns};
 use rustc_errors::Applicability;
@@ -116,11 +117,12 @@ pub(crate) fn check(cx: &LateContext<'_>, ex: &Expr<'_>, arms: &[Arm<'_>]) {
     let format_suggestion = |variant: &VariantDef| {
         format!(
             "{}{}{}{}",
-            if let Some(ident) = wildcard_ident {
-                format!("{} @ ", ident.name)
-            } else {
-                String::new()
-            },
+            wildcard_ident.map_or(String::new(), |ident| {
+                ident
+                    .span
+                    .get_source_text(cx)
+                    .map_or_else(|| format!("{} @ ", ident.name), |s| format!("{s} @ "))
+            }),
             if let CommonPrefixSearcher::Path(path_prefix) = path_prefix {
                 let mut s = String::new();
                 for seg in path_prefix {
@@ -138,7 +140,7 @@ pub(crate) fn check(cx: &LateContext<'_>, ex: &Expr<'_>, arms: &[Arm<'_>]) {
                 Some(CtorKind::Fn) if variant.fields.len() == 1 => "(_)",
                 Some(CtorKind::Fn) => "(..)",
                 Some(CtorKind::Const) => "",
-                None => "{ .. }",
+                None => " { .. }",
             }
         )
     };
diff --git a/src/tools/clippy/clippy_lints/src/methods/io_other_error.rs b/src/tools/clippy/clippy_lints/src/methods/io_other_error.rs
index ec4b9c7ae2e..9276261606e 100644
--- a/src/tools/clippy/clippy_lints/src/methods/io_other_error.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/io_other_error.rs
@@ -1,6 +1,6 @@
 use clippy_utils::diagnostics::span_lint_and_then;
 use clippy_utils::msrvs::{self, Msrv};
-use clippy_utils::{expr_or_init, paths};
+use clippy_utils::{expr_or_init, is_path_diagnostic_item, sym};
 use rustc_errors::Applicability;
 use rustc_hir::{Expr, ExprKind, QPath};
 use rustc_lint::LateContext;
@@ -10,8 +10,11 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, path: &Expr<'_>, args
         && !expr.span.from_expansion()
         && !error_kind.span.from_expansion()
         && let ExprKind::Path(QPath::TypeRelative(_, new_segment)) = path.kind
-        && paths::IO_ERROR_NEW.matches_path(cx, path)
-        && paths::IO_ERRORKIND_OTHER_CTOR.matches_path(cx, expr_or_init(cx, error_kind))
+        && is_path_diagnostic_item(cx, path, sym::io_error_new)
+        && let ExprKind::Path(QPath::Resolved(_, init_path)) = &expr_or_init(cx, error_kind).kind
+        && let [.., error_kind_ty, error_kind_variant] = init_path.segments
+        && cx.tcx.is_diagnostic_item(sym::io_errorkind, error_kind_ty.res.def_id())
+        && error_kind_variant.ident.name == sym::Other
         && msrv.meets(cx, msrvs::IO_ERROR_OTHER)
     {
         span_lint_and_then(
diff --git a/src/tools/clippy/clippy_lints/src/methods/mod.rs b/src/tools/clippy/clippy_lints/src/methods/mod.rs
index 347960e0003..f2dabdd3438 100644
--- a/src/tools/clippy/clippy_lints/src/methods/mod.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/mod.rs
@@ -4426,7 +4426,7 @@ declare_clippy_lint! {
     /// ```no_run
     /// use std::io::{BufReader, Read};
     /// use std::fs::File;
-    /// let file = BufReader::new(std::fs::File::open("./bytes.txt").unwrap());
+    /// let file = BufReader::new(File::open("./bytes.txt").unwrap());
     /// file.bytes();
     /// ```
     #[clippy::version = "1.87.0"]
diff --git a/src/tools/clippy/clippy_lints/src/methods/or_fun_call.rs b/src/tools/clippy/clippy_lints/src/methods/or_fun_call.rs
index 7bdd999bbba..2139466ce74 100644
--- a/src/tools/clippy/clippy_lints/src/methods/or_fun_call.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/or_fun_call.rs
@@ -136,7 +136,7 @@ pub(super) fn check<'tcx>(
         fun_span: Option<Span>,
     ) -> bool {
         // (path, fn_has_argument, methods, suffix)
-        const KNOW_TYPES: [(Symbol, bool, &[Symbol], &str); 4] = [
+        const KNOW_TYPES: [(Symbol, bool, &[Symbol], &str); 5] = [
             (sym::BTreeEntry, false, &[sym::or_insert], "with"),
             (sym::HashMapEntry, false, &[sym::or_insert], "with"),
             (
@@ -145,16 +145,17 @@ pub(super) fn check<'tcx>(
                 &[sym::map_or, sym::ok_or, sym::or, sym::unwrap_or],
                 "else",
             ),
-            (sym::Result, true, &[sym::or, sym::unwrap_or], "else"),
+            (sym::Option, false, &[sym::get_or_insert], "with"),
+            (sym::Result, true, &[sym::map_or, sym::or, sym::unwrap_or], "else"),
         ];
 
         if KNOW_TYPES.iter().any(|k| k.2.contains(&name))
             && switch_to_lazy_eval(cx, arg)
             && !contains_return(arg)
             && let self_ty = cx.typeck_results().expr_ty(self_expr)
-            && let Some(&(_, fn_has_arguments, poss, suffix)) =
-                KNOW_TYPES.iter().find(|&&i| is_type_diagnostic_item(cx, self_ty, i.0))
-            && poss.contains(&name)
+            && let Some(&(_, fn_has_arguments, _, suffix)) = KNOW_TYPES
+                .iter()
+                .find(|&&i| is_type_diagnostic_item(cx, self_ty, i.0) && i.2.contains(&name))
         {
             let ctxt = span.ctxt();
             let mut app = Applicability::HasPlaceholders;
diff --git a/src/tools/clippy/clippy_lints/src/missing_inline.rs b/src/tools/clippy/clippy_lints/src/missing_inline.rs
index f835bbb7c56..25c95d23436 100644
--- a/src/tools/clippy/clippy_lints/src/missing_inline.rs
+++ b/src/tools/clippy/clippy_lints/src/missing_inline.rs
@@ -1,5 +1,5 @@
 use clippy_utils::diagnostics::span_lint;
-use rustc_attr_data_structures::{find_attr, AttributeKind};
+use rustc_attr_data_structures::{AttributeKind, find_attr};
 use rustc_hir as hir;
 use rustc_hir::Attribute;
 use rustc_lint::{LateContext, LateLintPass, LintContext};
diff --git a/src/tools/clippy/clippy_lints/src/needless_borrows_for_generic_args.rs b/src/tools/clippy/clippy_lints/src/needless_borrows_for_generic_args.rs
index 8d2f8029112..17d251a7bbb 100644
--- a/src/tools/clippy/clippy_lints/src/needless_borrows_for_generic_args.rs
+++ b/src/tools/clippy/clippy_lints/src/needless_borrows_for_generic_args.rs
@@ -161,7 +161,7 @@ fn path_has_args(p: &QPath<'_>) -> bool {
 ///   - `Copy` itself, or
 ///   - the only use of a mutable reference, or
 ///   - not a variable (created by a function call)
-#[expect(clippy::too_many_arguments)]
+#[expect(clippy::too_many_arguments, clippy::too_many_lines)]
 fn needless_borrow_count<'tcx>(
     cx: &LateContext<'tcx>,
     possible_borrowers: &mut Vec<(LocalDefId, PossibleBorrowerMap<'tcx, 'tcx>)>,
@@ -232,11 +232,11 @@ fn needless_borrow_count<'tcx>(
     let mut args_with_referent_ty = callee_args.to_vec();
 
     let mut check_reference_and_referent = |reference: &Expr<'tcx>, referent: &Expr<'tcx>| {
-        if let ExprKind::Field(base, _) = &referent.kind {
-            let base_ty = cx.typeck_results().expr_ty(base);
-            if drop_trait_def_id.is_some_and(|id| implements_trait(cx, base_ty, id, &[])) {
-                return false;
-            }
+        if let ExprKind::Field(base, _) = &referent.kind
+            && let base_ty = cx.typeck_results().expr_ty(base)
+            && drop_trait_def_id.is_some_and(|id| implements_trait(cx, base_ty, id, &[]))
+        {
+            return false;
         }
 
         let referent_ty = cx.typeck_results().expr_ty(referent);
diff --git a/src/tools/clippy/clippy_lints/src/needless_parens_on_range_literals.rs b/src/tools/clippy/clippy_lints/src/needless_parens_on_range_literals.rs
index 8a62106377c..021a11593f3 100644
--- a/src/tools/clippy/clippy_lints/src/needless_parens_on_range_literals.rs
+++ b/src/tools/clippy/clippy_lints/src/needless_parens_on_range_literals.rs
@@ -5,7 +5,6 @@ use clippy_utils::source::{snippet, snippet_with_applicability};
 use rustc_ast::ast;
 use rustc_errors::Applicability;
 use rustc_hir::{Expr, ExprKind};
-
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_session::declare_lint_pass;
 
diff --git a/src/tools/clippy/clippy_lints/src/needless_pass_by_value.rs b/src/tools/clippy/clippy_lints/src/needless_pass_by_value.rs
index 9aede1dec93..c97ecce75b4 100644
--- a/src/tools/clippy/clippy_lints/src/needless_pass_by_value.rs
+++ b/src/tools/clippy/clippy_lints/src/needless_pass_by_value.rs
@@ -124,8 +124,10 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessPassByValue {
                 // Note that we do not want to deal with qualified predicates here.
                 match pred.kind().no_bound_vars() {
                     Some(ty::ClauseKind::Trait(pred))
-                        if pred.def_id() != sized_trait && pred.def_id() != meta_sized_trait
-                            => Some(pred),
+                        if pred.def_id() != sized_trait && pred.def_id() != meta_sized_trait =>
+                    {
+                        Some(pred)
+                    },
                     _ => None,
                 }
             })
diff --git a/src/tools/clippy/clippy_lints/src/no_mangle_with_rust_abi.rs b/src/tools/clippy/clippy_lints/src/no_mangle_with_rust_abi.rs
index b71dde90691..dee8efeb291 100644
--- a/src/tools/clippy/clippy_lints/src/no_mangle_with_rust_abi.rs
+++ b/src/tools/clippy/clippy_lints/src/no_mangle_with_rust_abi.rs
@@ -1,8 +1,9 @@
 use clippy_utils::diagnostics::span_lint_and_then;
 use clippy_utils::source::{snippet, snippet_with_applicability};
 use rustc_abi::ExternAbi;
+use rustc_attr_data_structures::AttributeKind;
 use rustc_errors::Applicability;
-use rustc_hir::{Item, ItemKind};
+use rustc_hir::{Attribute, Item, ItemKind};
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_session::declare_lint_pass;
 use rustc_span::{BytePos, Pos};
@@ -44,8 +45,7 @@ impl<'tcx> LateLintPass<'tcx> for NoMangleWithRustAbi {
             let mut app = Applicability::MaybeIncorrect;
             let fn_snippet = snippet_with_applicability(cx, fn_sig.span.with_hi(ident.span.lo()), "..", &mut app);
             for attr in attrs {
-                if let Some(ident) = attr.ident()
-                    && ident.name == rustc_span::sym::no_mangle
+                if let Attribute::Parsed(AttributeKind::NoMangle(attr_span)) = attr
                     && fn_sig.header.abi == ExternAbi::Rust
                     && let Some((fn_attrs, _)) = fn_snippet.rsplit_once("fn")
                     && !fn_attrs.contains("extern")
@@ -54,7 +54,7 @@ impl<'tcx> LateLintPass<'tcx> for NoMangleWithRustAbi {
                         .span
                         .with_lo(fn_sig.span.lo() + BytePos::from_usize(fn_attrs.len()))
                         .shrink_to_lo();
-                    let attr_snippet = snippet(cx, attr.span(), "..");
+                    let attr_snippet = snippet(cx, *attr_span, "..");
 
                     span_lint_and_then(
                         cx,
diff --git a/src/tools/clippy/clippy_lints/src/non_copy_const.rs b/src/tools/clippy/clippy_lints/src/non_copy_const.rs
index a27c6aa75e3..5f10e1968f1 100644
--- a/src/tools/clippy/clippy_lints/src/non_copy_const.rs
+++ b/src/tools/clippy/clippy_lints/src/non_copy_const.rs
@@ -617,7 +617,7 @@ impl<'tcx> NonCopyConst<'tcx> {
 
             // Then a type check. Note we only check the type here as the result
             // gets cached.
-            let ty = EarlyBinder::bind(typeck.expr_ty(src_expr)).instantiate(tcx, init_args);
+            let ty = typeck.expr_ty(src_expr);
             // Normalized as we need to check if this is an array later.
             let ty = tcx.try_normalize_erasing_regions(typing_env, ty).unwrap_or(ty);
             if self.is_ty_freeze(tcx, typing_env, ty).is_freeze() {
diff --git a/src/tools/clippy/clippy_lints/src/operators/identity_op.rs b/src/tools/clippy/clippy_lints/src/operators/identity_op.rs
index e1fd09549a4..3efbb896358 100644
--- a/src/tools/clippy/clippy_lints/src/operators/identity_op.rs
+++ b/src/tools/clippy/clippy_lints/src/operators/identity_op.rs
@@ -1,12 +1,13 @@
-use clippy_utils::consts::{ConstEvalCtxt, Constant, FullInt};
+use clippy_utils::consts::{ConstEvalCtxt, Constant, FullInt, integer_const, is_zero_integer_const};
 use clippy_utils::diagnostics::span_lint_and_sugg;
 use clippy_utils::source::snippet_with_applicability;
-use clippy_utils::{clip, peel_hir_expr_refs, unsext};
+use clippy_utils::{ExprUseNode, clip, expr_use_ctxt, peel_hir_expr_refs, unsext};
 use rustc_errors::Applicability;
-use rustc_hir::{BinOpKind, Expr, ExprKind, Node};
+use rustc_hir::def::{DefKind, Res};
+use rustc_hir::{BinOpKind, Expr, ExprKind, Node, Path, QPath};
 use rustc_lint::LateContext;
 use rustc_middle::ty;
-use rustc_span::Span;
+use rustc_span::{Span, kw};
 
 use super::IDENTITY_OP;
 
@@ -17,7 +18,7 @@ pub(crate) fn check<'tcx>(
     left: &'tcx Expr<'_>,
     right: &'tcx Expr<'_>,
 ) {
-    if !is_allowed(cx, op, left, right) {
+    if !is_allowed(cx, expr, op, left, right) {
         return;
     }
 
@@ -165,14 +166,27 @@ fn needs_parenthesis(cx: &LateContext<'_>, binary: &Expr<'_>, child: &Expr<'_>)
     Parens::Needed
 }
 
-fn is_allowed(cx: &LateContext<'_>, cmp: BinOpKind, left: &Expr<'_>, right: &Expr<'_>) -> bool {
+fn is_allowed<'tcx>(
+    cx: &LateContext<'tcx>,
+    expr: &'tcx Expr<'tcx>,
+    cmp: BinOpKind,
+    left: &Expr<'tcx>,
+    right: &Expr<'tcx>,
+) -> bool {
+    // Exclude case where the left or right side is associated function call returns a type which is
+    // `Self` that is not given explicitly, and the expression is not a let binding's init
+    // expression and the let binding has a type annotation, or a function's return value.
+    if (is_assoc_fn_without_type_instance(cx, left) || is_assoc_fn_without_type_instance(cx, right))
+        && !is_expr_used_with_type_annotation(cx, expr)
+    {
+        return false;
+    }
+
     // This lint applies to integers and their references
     cx.typeck_results().expr_ty(left).peel_refs().is_integral()
         && cx.typeck_results().expr_ty(right).peel_refs().is_integral()
         // `1 << 0` is a common pattern in bit manipulation code
-        && !(cmp == BinOpKind::Shl
-            && ConstEvalCtxt::new(cx).eval_simple(right) == Some(Constant::Int(0))
-            && ConstEvalCtxt::new(cx).eval_simple(left) == Some(Constant::Int(1)))
+        && !(cmp == BinOpKind::Shl && is_zero_integer_const(cx, right) && integer_const(cx, left) == Some(1))
 }
 
 fn check_remainder(cx: &LateContext<'_>, left: &Expr<'_>, right: &Expr<'_>, span: Span, arg: Span) {
@@ -234,3 +248,47 @@ fn span_ineffective_operation(
         applicability,
     );
 }
+
+fn is_expr_used_with_type_annotation<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) -> bool {
+    match expr_use_ctxt(cx, expr).use_node(cx) {
+        ExprUseNode::LetStmt(letstmt) => letstmt.ty.is_some(),
+        ExprUseNode::Return(_) => true,
+        _ => false,
+    }
+}
+
+/// Check if the expression is an associated function without a type instance.
+/// Example:
+/// ```
+/// trait Def {
+///     fn def() -> Self;
+/// }
+/// impl Def for usize {
+///     fn def() -> Self {
+///         0
+///     }
+/// }
+/// fn test() {
+///     let _ = 0usize + &Default::default();
+///     let _ = 0usize + &Def::def();
+/// }
+/// ```
+fn is_assoc_fn_without_type_instance<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'tcx>) -> bool {
+    if let ExprKind::Call(func, _) = peel_hir_expr_refs(expr).0.kind
+        && let ExprKind::Path(QPath::Resolved(
+            // If it's not None, don't need to go further.
+            None,
+            Path {
+                res: Res::Def(DefKind::AssocFn, def_id),
+                ..
+            },
+        )) = func.kind
+        && let output_ty = cx.tcx.fn_sig(def_id).instantiate_identity().skip_binder().output()
+        && let ty::Param(ty::ParamTy {
+            name: kw::SelfUpper, ..
+        }) = output_ty.kind()
+    {
+        return true;
+    }
+    false
+}
diff --git a/src/tools/clippy/clippy_lints/src/operators/manual_is_multiple_of.rs b/src/tools/clippy/clippy_lints/src/operators/manual_is_multiple_of.rs
new file mode 100644
index 00000000000..821178a4315
--- /dev/null
+++ b/src/tools/clippy/clippy_lints/src/operators/manual_is_multiple_of.rs
@@ -0,0 +1,66 @@
+use clippy_utils::consts::is_zero_integer_const;
+use clippy_utils::diagnostics::span_lint_and_sugg;
+use clippy_utils::msrvs::{self, Msrv};
+use clippy_utils::sugg::Sugg;
+use rustc_ast::BinOpKind;
+use rustc_errors::Applicability;
+use rustc_hir::{Expr, ExprKind};
+use rustc_lint::LateContext;
+use rustc_middle::ty;
+
+use super::MANUAL_IS_MULTIPLE_OF;
+
+pub(super) fn check<'tcx>(
+    cx: &LateContext<'tcx>,
+    expr: &Expr<'_>,
+    op: BinOpKind,
+    lhs: &'tcx Expr<'tcx>,
+    rhs: &'tcx Expr<'tcx>,
+    msrv: Msrv,
+) {
+    if msrv.meets(cx, msrvs::UNSIGNED_IS_MULTIPLE_OF)
+        && let Some(operand) = uint_compare_to_zero(cx, op, lhs, rhs)
+        && let ExprKind::Binary(operand_op, operand_left, operand_right) = operand.kind
+        && operand_op.node == BinOpKind::Rem
+    {
+        let mut app = Applicability::MachineApplicable;
+        let divisor = Sugg::hir_with_applicability(cx, operand_right, "_", &mut app);
+        span_lint_and_sugg(
+            cx,
+            MANUAL_IS_MULTIPLE_OF,
+            expr.span,
+            "manual implementation of `.is_multiple_of()`",
+            "replace with",
+            format!(
+                "{}{}.is_multiple_of({divisor})",
+                if op == BinOpKind::Eq { "" } else { "!" },
+                Sugg::hir_with_applicability(cx, operand_left, "_", &mut app).maybe_paren()
+            ),
+            app,
+        );
+    }
+}
+
+// If we have a `x == 0`, `x != 0` or `x > 0` (or the reverted ones), return the non-zero operand
+fn uint_compare_to_zero<'tcx>(
+    cx: &LateContext<'tcx>,
+    op: BinOpKind,
+    lhs: &'tcx Expr<'tcx>,
+    rhs: &'tcx Expr<'tcx>,
+) -> Option<&'tcx Expr<'tcx>> {
+    let operand = if matches!(lhs.kind, ExprKind::Binary(..))
+        && matches!(op, BinOpKind::Eq | BinOpKind::Ne | BinOpKind::Gt)
+        && is_zero_integer_const(cx, rhs)
+    {
+        lhs
+    } else if matches!(rhs.kind, ExprKind::Binary(..))
+        && matches!(op, BinOpKind::Eq | BinOpKind::Ne | BinOpKind::Lt)
+        && is_zero_integer_const(cx, lhs)
+    {
+        rhs
+    } else {
+        return None;
+    };
+
+    matches!(cx.typeck_results().expr_ty_adjusted(operand).kind(), ty::Uint(_)).then_some(operand)
+}
diff --git a/src/tools/clippy/clippy_lints/src/operators/mod.rs b/src/tools/clippy/clippy_lints/src/operators/mod.rs
index 2f4e8e99588..bdbbb3475cd 100644
--- a/src/tools/clippy/clippy_lints/src/operators/mod.rs
+++ b/src/tools/clippy/clippy_lints/src/operators/mod.rs
@@ -11,6 +11,7 @@ mod float_cmp;
 mod float_equality_without_abs;
 mod identity_op;
 mod integer_division;
+mod manual_is_multiple_of;
 mod manual_midpoint;
 mod misrefactored_assign_op;
 mod modulo_arithmetic;
@@ -830,12 +831,42 @@ declare_clippy_lint! {
     "manual implementation of `midpoint` which can overflow"
 }
 
+declare_clippy_lint! {
+    /// ### What it does
+    /// Checks for manual implementation of `.is_multiple_of()` on
+    /// unsigned integer types.
+    ///
+    /// ### Why is this bad?
+    /// `a.is_multiple_of(b)` is a clearer way to check for divisibility
+    /// of `a` by `b`. This expression can never panic.
+    ///
+    /// ### Example
+    /// ```no_run
+    /// # let (a, b) = (3u64, 4u64);
+    /// if a % b == 0 {
+    ///     println!("{a} is divisible by {b}");
+    /// }
+    /// ```
+    /// Use instead:
+    /// ```no_run
+    /// # let (a, b) = (3u64, 4u64);
+    /// if a.is_multiple_of(b) {
+    ///     println!("{a} is divisible by {b}");
+    /// }
+    /// ```
+    #[clippy::version = "1.89.0"]
+    pub MANUAL_IS_MULTIPLE_OF,
+    complexity,
+    "manual implementation of `.is_multiple_of()`"
+}
+
 pub struct Operators {
     arithmetic_context: numeric_arithmetic::Context,
     verbose_bit_mask_threshold: u64,
     modulo_arithmetic_allow_comparison_to_zero: bool,
     msrv: Msrv,
 }
+
 impl Operators {
     pub fn new(conf: &'static Conf) -> Self {
         Self {
@@ -874,6 +905,7 @@ impl_lint_pass!(Operators => [
     NEEDLESS_BITWISE_BOOL,
     SELF_ASSIGNMENT,
     MANUAL_MIDPOINT,
+    MANUAL_IS_MULTIPLE_OF,
 ]);
 
 impl<'tcx> LateLintPass<'tcx> for Operators {
@@ -891,6 +923,7 @@ impl<'tcx> LateLintPass<'tcx> for Operators {
                     identity_op::check(cx, e, op.node, lhs, rhs);
                     needless_bitwise_bool::check(cx, e, op.node, lhs, rhs);
                     manual_midpoint::check(cx, e, op.node, lhs, rhs, self.msrv);
+                    manual_is_multiple_of::check(cx, e, op.node, lhs, rhs, self.msrv);
                 }
                 self.arithmetic_context.check_binary(cx, e, op.node, lhs, rhs);
                 bit_mask::check(cx, e, op.node, lhs, rhs);
diff --git a/src/tools/clippy/clippy_lints/src/pass_by_ref_or_value.rs b/src/tools/clippy/clippy_lints/src/pass_by_ref_or_value.rs
index e18bdfb34ac..b8005dfd6f8 100644
--- a/src/tools/clippy/clippy_lints/src/pass_by_ref_or_value.rs
+++ b/src/tools/clippy/clippy_lints/src/pass_by_ref_or_value.rs
@@ -3,10 +3,10 @@ use clippy_utils::diagnostics::span_lint_and_sugg;
 use clippy_utils::source::snippet;
 use clippy_utils::ty::{for_each_top_level_late_bound_region, is_copy};
 use clippy_utils::{is_self, is_self_ty};
-use rustc_attr_data_structures::{find_attr, AttributeKind, InlineAttr};
-use rustc_data_structures::fx::FxHashSet;
 use core::ops::ControlFlow;
 use rustc_abi::ExternAbi;
+use rustc_attr_data_structures::{AttributeKind, InlineAttr, find_attr};
+use rustc_data_structures::fx::FxHashSet;
 use rustc_errors::Applicability;
 use rustc_hir as hir;
 use rustc_hir::intravisit::FnKind;
diff --git a/src/tools/clippy/clippy_lints/src/question_mark.rs b/src/tools/clippy/clippy_lints/src/question_mark.rs
index c02e5e0621c..de12a25b03d 100644
--- a/src/tools/clippy/clippy_lints/src/question_mark.rs
+++ b/src/tools/clippy/clippy_lints/src/question_mark.rs
@@ -142,6 +142,7 @@ fn check_let_some_else_return_none(cx: &LateContext<'_>, stmt: &Stmt<'_>) {
         && let Some(ret) = find_let_else_ret_expression(els)
         && let Some(inner_pat) = pat_and_expr_can_be_question_mark(cx, pat, ret)
         && !span_contains_comment(cx.tcx.sess.source_map(), els.span)
+        && !span_contains_cfg(cx, els.span)
     {
         let mut applicability = Applicability::MaybeIncorrect;
         let init_expr_str = Sugg::hir_with_applicability(cx, init_expr, "..", &mut applicability).maybe_paren();
diff --git a/src/tools/clippy/clippy_lints/src/question_mark_used.rs b/src/tools/clippy/clippy_lints/src/question_mark_used.rs
index 96ea485d769..7bbbd0d25ac 100644
--- a/src/tools/clippy/clippy_lints/src/question_mark_used.rs
+++ b/src/tools/clippy/clippy_lints/src/question_mark_used.rs
@@ -1,5 +1,4 @@
 use clippy_utils::diagnostics::span_lint_and_then;
-
 use clippy_utils::macros::span_is_local;
 use rustc_hir::{Expr, ExprKind, MatchSource};
 use rustc_lint::{LateContext, LateLintPass};
diff --git a/src/tools/clippy/clippy_lints/src/read_zero_byte_vec.rs b/src/tools/clippy/clippy_lints/src/read_zero_byte_vec.rs
index 6b1dc864fb7..acd840401c6 100644
--- a/src/tools/clippy/clippy_lints/src/read_zero_byte_vec.rs
+++ b/src/tools/clippy/clippy_lints/src/read_zero_byte_vec.rs
@@ -3,11 +3,10 @@ use clippy_utils::higher::{VecInitKind, get_vec_init_kind};
 use clippy_utils::source::snippet;
 use clippy_utils::{get_enclosing_block, sym};
 
-use hir::{Expr, ExprKind, HirId, LetStmt, PatKind, PathSegment, QPath, StmtKind};
 use rustc_errors::Applicability;
-use rustc_hir as hir;
 use rustc_hir::def::Res;
 use rustc_hir::intravisit::{Visitor, walk_expr};
+use rustc_hir::{self as hir, Expr, ExprKind, HirId, LetStmt, PatKind, PathSegment, QPath, StmtKind};
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_session::declare_lint_pass;
 
diff --git a/src/tools/clippy/clippy_lints/src/return_self_not_must_use.rs b/src/tools/clippy/clippy_lints/src/return_self_not_must_use.rs
index 07ae92fa984..25929b853af 100644
--- a/src/tools/clippy/clippy_lints/src/return_self_not_must_use.rs
+++ b/src/tools/clippy/clippy_lints/src/return_self_not_must_use.rs
@@ -1,12 +1,13 @@
 use clippy_utils::diagnostics::span_lint_and_help;
 use clippy_utils::ty::is_must_use_ty;
 use clippy_utils::{nth_arg, return_ty};
+use rustc_attr_data_structures::{AttributeKind, find_attr};
 use rustc_hir::def_id::LocalDefId;
 use rustc_hir::intravisit::FnKind;
 use rustc_hir::{Body, FnDecl, OwnerId, TraitItem, TraitItemKind};
 use rustc_lint::{LateContext, LateLintPass, LintContext};
 use rustc_session::declare_lint_pass;
-use rustc_span::{Span, sym};
+use rustc_span::Span;
 
 declare_clippy_lint! {
     /// ### What it does
@@ -74,7 +75,10 @@ fn check_method(cx: &LateContext<'_>, decl: &FnDecl<'_>, fn_def: LocalDefId, spa
         // We only show this warning for public exported methods.
         && cx.effective_visibilities.is_exported(fn_def)
         // We don't want to emit this lint if the `#[must_use]` attribute is already there.
-        && !cx.tcx.hir_attrs(owner_id.into()).iter().any(|attr| attr.has_name(sym::must_use))
+        && !find_attr!(
+            cx.tcx.hir_attrs(owner_id.into()),
+            AttributeKind::MustUse { .. }
+        )
         && cx.tcx.visibility(fn_def.to_def_id()).is_public()
         && let ret_ty = return_ty(cx, owner_id)
         && let self_arg = nth_arg(cx, owner_id, 0)
diff --git a/src/tools/clippy/clippy_lints/src/single_component_path_imports.rs b/src/tools/clippy/clippy_lints/src/single_component_path_imports.rs
index 62939912304..38cf7e3822a 100644
--- a/src/tools/clippy/clippy_lints/src/single_component_path_imports.rs
+++ b/src/tools/clippy/clippy_lints/src/single_component_path_imports.rs
@@ -219,22 +219,21 @@ impl SingleComponentPathImports {
                             }
                         }
                     }
-                } else {
-                    // keep track of `use self::some_module` usages
-                    if segments[0].ident.name == kw::SelfLower {
-                        // simple case such as `use self::module::SomeStruct`
-                        if segments.len() > 1 {
-                            imports_reused_with_self.push(segments[1].ident.name);
-                            return;
-                        }
+                }
+                // keep track of `use self::some_module` usages
+                else if segments[0].ident.name == kw::SelfLower {
+                    // simple case such as `use self::module::SomeStruct`
+                    if segments.len() > 1 {
+                        imports_reused_with_self.push(segments[1].ident.name);
+                        return;
+                    }
 
-                        // nested case such as `use self::{module1::Struct1, module2::Struct2}`
-                        if let UseTreeKind::Nested { items, .. } = &use_tree.kind {
-                            for tree in items {
-                                let segments = &tree.0.prefix.segments;
-                                if !segments.is_empty() {
-                                    imports_reused_with_self.push(segments[0].ident.name);
-                                }
+                    // nested case such as `use self::{module1::Struct1, module2::Struct2}`
+                    if let UseTreeKind::Nested { items, .. } = &use_tree.kind {
+                        for tree in items {
+                            let segments = &tree.0.prefix.segments;
+                            if !segments.is_empty() {
+                                imports_reused_with_self.push(segments[0].ident.name);
                             }
                         }
                     }
diff --git a/src/tools/clippy/clippy_lints/src/single_range_in_vec_init.rs b/src/tools/clippy/clippy_lints/src/single_range_in_vec_init.rs
index 54d09ff9ee4..dda2f8cc1d0 100644
--- a/src/tools/clippy/clippy_lints/src/single_range_in_vec_init.rs
+++ b/src/tools/clippy/clippy_lints/src/single_range_in_vec_init.rs
@@ -3,7 +3,7 @@ use clippy_utils::higher::VecArgs;
 use clippy_utils::macros::root_macro_call_first_node;
 use clippy_utils::source::SpanRangeExt;
 use clippy_utils::ty::implements_trait;
-use clippy_utils::{is_no_std_crate, paths};
+use clippy_utils::{is_no_std_crate, sym};
 use rustc_ast::{LitIntType, LitKind, UintTy};
 use rustc_errors::Applicability;
 use rustc_hir::{Expr, ExprKind, LangItem, QPath, StructTailExpr};
@@ -100,7 +100,7 @@ impl LateLintPass<'_> for SingleRangeInVecInit {
             && let Some(start_snippet) = start.span.get_source_text(cx)
             && let Some(end_snippet) = end.span.get_source_text(cx)
         {
-            let should_emit_every_value = if let Some(step_def_id) = paths::ITER_STEP.only(cx)
+            let should_emit_every_value = if let Some(step_def_id) = cx.tcx.get_diagnostic_item(sym::range_step)
                 && implements_trait(cx, ty, step_def_id, &[])
             {
                 true
diff --git a/src/tools/clippy/clippy_lints/src/to_digit_is_some.rs b/src/tools/clippy/clippy_lints/src/to_digit_is_some.rs
index 7d7d74f27b3..3e847543e1c 100644
--- a/src/tools/clippy/clippy_lints/src/to_digit_is_some.rs
+++ b/src/tools/clippy/clippy_lints/src/to_digit_is_some.rs
@@ -2,7 +2,7 @@ use clippy_config::Conf;
 use clippy_utils::diagnostics::span_lint_and_sugg;
 use clippy_utils::msrvs::{self, Msrv};
 use clippy_utils::source::snippet_with_applicability;
-use clippy_utils::{is_in_const_context, paths, sym};
+use clippy_utils::{is_in_const_context, is_path_diagnostic_item, sym};
 use rustc_errors::Applicability;
 use rustc_hir as hir;
 use rustc_lint::{LateContext, LateLintPass};
@@ -62,7 +62,7 @@ impl<'tcx> LateLintPass<'tcx> for ToDigitIsSome {
                     }
                 },
                 hir::ExprKind::Call(to_digits_call, [char_arg, radix_arg]) => {
-                    if paths::CHAR_TO_DIGIT.matches_path(cx, to_digits_call) {
+                    if is_path_diagnostic_item(cx, to_digits_call, sym::char_to_digit) {
                         Some((false, char_arg, radix_arg))
                     } else {
                         None
diff --git a/src/tools/clippy/clippy_lints/src/undocumented_unsafe_blocks.rs b/src/tools/clippy/clippy_lints/src/undocumented_unsafe_blocks.rs
index a2938c86c76..92427473a8e 100644
--- a/src/tools/clippy/clippy_lints/src/undocumented_unsafe_blocks.rs
+++ b/src/tools/clippy/clippy_lints/src/undocumented_unsafe_blocks.rs
@@ -606,32 +606,31 @@ fn span_from_macro_expansion_has_safety_comment(cx: &LateContext<'_>, span: Span
     let ctxt = span.ctxt();
     if ctxt == SyntaxContext::root() {
         HasSafetyComment::Maybe
-    } else {
-        // From a macro expansion. Get the text from the start of the macro declaration to start of the
-        // unsafe block.
-        //     macro_rules! foo { () => { stuff }; (x) => { unsafe { stuff } }; }
-        //     ^--------------------------------------------^
-        if let Ok(unsafe_line) = source_map.lookup_line(span.lo())
-            && let Ok(macro_line) = source_map.lookup_line(ctxt.outer_expn_data().def_site.lo())
-            && Arc::ptr_eq(&unsafe_line.sf, &macro_line.sf)
-            && let Some(src) = unsafe_line.sf.src.as_deref()
-        {
-            if macro_line.line < unsafe_line.line {
-                match text_has_safety_comment(
-                    src,
-                    &unsafe_line.sf.lines()[macro_line.line + 1..=unsafe_line.line],
-                    unsafe_line.sf.start_pos,
-                ) {
-                    Some(b) => HasSafetyComment::Yes(b),
-                    None => HasSafetyComment::No,
-                }
-            } else {
-                HasSafetyComment::No
+    }
+    // From a macro expansion. Get the text from the start of the macro declaration to start of the
+    // unsafe block.
+    //     macro_rules! foo { () => { stuff }; (x) => { unsafe { stuff } }; }
+    //     ^--------------------------------------------^
+    else if let Ok(unsafe_line) = source_map.lookup_line(span.lo())
+        && let Ok(macro_line) = source_map.lookup_line(ctxt.outer_expn_data().def_site.lo())
+        && Arc::ptr_eq(&unsafe_line.sf, &macro_line.sf)
+        && let Some(src) = unsafe_line.sf.src.as_deref()
+    {
+        if macro_line.line < unsafe_line.line {
+            match text_has_safety_comment(
+                src,
+                &unsafe_line.sf.lines()[macro_line.line + 1..=unsafe_line.line],
+                unsafe_line.sf.start_pos,
+            ) {
+                Some(b) => HasSafetyComment::Yes(b),
+                None => HasSafetyComment::No,
             }
         } else {
-            // Problem getting source text. Pretend a comment was found.
-            HasSafetyComment::Maybe
+            HasSafetyComment::No
         }
+    } else {
+        // Problem getting source text. Pretend a comment was found.
+        HasSafetyComment::Maybe
     }
 }
 
diff --git a/src/tools/clippy/clippy_lints/src/useless_concat.rs b/src/tools/clippy/clippy_lints/src/useless_concat.rs
index 1ed1fbb3b9c..96845adb04a 100644
--- a/src/tools/clippy/clippy_lints/src/useless_concat.rs
+++ b/src/tools/clippy/clippy_lints/src/useless_concat.rs
@@ -1,8 +1,7 @@
 use clippy_utils::diagnostics::span_lint_and_sugg;
 use clippy_utils::macros::macro_backtrace;
-use clippy_utils::paths::CONCAT;
 use clippy_utils::source::snippet_opt;
-use clippy_utils::tokenize_with_text;
+use clippy_utils::{sym, tokenize_with_text};
 use rustc_ast::LitKind;
 use rustc_errors::Applicability;
 use rustc_hir::{Expr, ExprKind};
@@ -43,7 +42,7 @@ impl LateLintPass<'_> for UselessConcat {
             // Get the direct parent of the expression.
             && let Some(macro_call) = macro_backtrace(expr.span).next()
             // Check if the `concat` macro from the `core` library.
-            && CONCAT.matches(cx, macro_call.def_id)
+            && cx.tcx.is_diagnostic_item(sym::macro_concat, macro_call.def_id)
             // We get the original code to parse it.
             && let Some(original_code) = snippet_opt(cx, macro_call.span)
             // This check allows us to ensure that the code snippet:
diff --git a/src/tools/clippy/clippy_utils/Cargo.toml b/src/tools/clippy/clippy_utils/Cargo.toml
index 615c0995e8b..73291aa8cdf 100644
--- a/src/tools/clippy/clippy_utils/Cargo.toml
+++ b/src/tools/clippy/clippy_utils/Cargo.toml
@@ -1,6 +1,6 @@
 [package]
 name = "clippy_utils"
-version = "0.1.89"
+version = "0.1.90"
 edition = "2024"
 description = "Helpful tools for writing lints, provided as they are used in Clippy"
 repository = "https://github.com/rust-lang/rust-clippy"
diff --git a/src/tools/clippy/clippy_utils/README.md b/src/tools/clippy/clippy_utils/README.md
index 1aa16e3943c..649748d1534 100644
--- a/src/tools/clippy/clippy_utils/README.md
+++ b/src/tools/clippy/clippy_utils/README.md
@@ -8,7 +8,7 @@ This crate is only guaranteed to build with this `nightly` toolchain:
 
 <!-- begin autogenerated nightly -->
 ```
-nightly-2025-06-12
+nightly-2025-06-26
 ```
 <!-- end autogenerated nightly -->
 
diff --git a/src/tools/clippy/clippy_utils/src/consts.rs b/src/tools/clippy/clippy_utils/src/consts.rs
index 1ec5d11384f..aaa071fd5c9 100644
--- a/src/tools/clippy/clippy_utils/src/consts.rs
+++ b/src/tools/clippy/clippy_utils/src/consts.rs
@@ -958,3 +958,18 @@ fn field_of_struct<'tcx>(
         None
     }
 }
+
+/// If `expr` evaluates to an integer constant, return its value.
+pub fn integer_const(cx: &LateContext<'_>, expr: &Expr<'_>) -> Option<u128> {
+    if let Some(Constant::Int(value)) = ConstEvalCtxt::new(cx).eval_simple(expr) {
+        Some(value)
+    } else {
+        None
+    }
+}
+
+/// Check if `expr` evaluates to an integer constant of 0.
+#[inline]
+pub fn is_zero_integer_const(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
+    integer_const(cx, expr) == Some(0)
+}
diff --git a/src/tools/clippy/clippy_utils/src/diagnostics.rs b/src/tools/clippy/clippy_utils/src/diagnostics.rs
index cd2098a8989..dc240dd067b 100644
--- a/src/tools/clippy/clippy_utils/src/diagnostics.rs
+++ b/src/tools/clippy/clippy_utils/src/diagnostics.rs
@@ -109,7 +109,7 @@ pub fn span_lint<T: LintContext>(cx: &T, lint: &'static Lint, sp: impl Into<Mult
     });
 }
 
-/// Same as `span_lint` but with an extra `help` message.
+/// Same as [`span_lint`] but with an extra `help` message.
 ///
 /// Use this if you want to provide some general help but
 /// can't provide a specific machine applicable suggestion.
@@ -166,7 +166,7 @@ pub fn span_lint_and_help<T: LintContext>(
     });
 }
 
-/// Like `span_lint` but with a `note` section instead of a `help` message.
+/// Like [`span_lint`] but with a `note` section instead of a `help` message.
 ///
 /// The `note` message is presented separately from the main lint message
 /// and is attached to a specific span:
@@ -226,7 +226,7 @@ pub fn span_lint_and_note<T: LintContext>(
     });
 }
 
-/// Like `span_lint` but allows to add notes, help and suggestions using a closure.
+/// Like [`span_lint`] but allows to add notes, help and suggestions using a closure.
 ///
 /// If you need to customize your lint output a lot, use this function.
 /// If you change the signature, remember to update the internal lint `CollapsibleCalls`
diff --git a/src/tools/clippy/clippy_utils/src/lib.rs b/src/tools/clippy/clippy_utils/src/lib.rs
index c7a2375c8df..a8b33418c8c 100644
--- a/src/tools/clippy/clippy_utils/src/lib.rs
+++ b/src/tools/clippy/clippy_utils/src/lib.rs
@@ -122,7 +122,7 @@ use rustc_span::hygiene::{ExpnKind, MacroKind};
 use rustc_span::source_map::SourceMap;
 use rustc_span::symbol::{Ident, Symbol, kw};
 use rustc_span::{InnerSpan, Span};
-use source::walk_span_to_context;
+use source::{SpanRangeExt, walk_span_to_context};
 use visitors::{Visitable, for_each_unconsumed_temporary};
 
 use crate::consts::{ConstEvalCtxt, Constant, mir_to_const};
@@ -1886,7 +1886,7 @@ pub fn is_must_use_func_call(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
         _ => None,
     };
 
-    did.is_some_and(|did| cx.tcx.has_attr(did, sym::must_use))
+    did.is_some_and(|did| find_attr!(cx.tcx.get_all_attrs(did), AttributeKind::MustUse { .. }))
 }
 
 /// Checks if a function's body represents the identity function. Looks for bodies of the form:
@@ -2710,7 +2710,7 @@ impl<'tcx> ExprUseNode<'tcx> {
 }
 
 /// Gets the context an expression's value is used in.
-pub fn expr_use_ctxt<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'tcx>) -> ExprUseCtxt<'tcx> {
+pub fn expr_use_ctxt<'tcx>(cx: &LateContext<'tcx>, e: &Expr<'tcx>) -> ExprUseCtxt<'tcx> {
     let mut adjustments = [].as_slice();
     let mut is_ty_unified = false;
     let mut moved_before_use = false;
@@ -2787,6 +2787,19 @@ pub fn span_contains_comment(sm: &SourceMap, span: Span) -> bool {
     });
 }
 
+/// Checks whether a given span has any significant token. A significant token is a non-whitespace
+/// token, including comments unless `skip_comments` is set.
+/// This is useful to determine if there are any actual code tokens in the span that are omitted in
+/// the late pass, such as platform-specific code.
+pub fn span_contains_non_whitespace(cx: &impl source::HasSession, span: Span, skip_comments: bool) -> bool {
+    matches!(span.get_source_text(cx), Some(snippet) if tokenize_with_text(&snippet).any(|(token, _, _)|
+        match token {
+            TokenKind::Whitespace => false,
+            TokenKind::BlockComment { .. } | TokenKind::LineComment { .. } => !skip_comments,
+            _ => true,
+        }
+    ))
+}
 /// Returns all the comments a given span contains
 ///
 /// Comments are returned wrapped with their relevant delimiters
diff --git a/src/tools/clippy/clippy_utils/src/msrvs.rs b/src/tools/clippy/clippy_utils/src/msrvs.rs
index a5e66ad463b..7a0bef1a9bb 100644
--- a/src/tools/clippy/clippy_utils/src/msrvs.rs
+++ b/src/tools/clippy/clippy_utils/src/msrvs.rs
@@ -24,7 +24,7 @@ macro_rules! msrv_aliases {
 // names may refer to stabilized feature flags or library items
 msrv_aliases! {
     1,88,0 { LET_CHAINS }
-    1,87,0 { OS_STR_DISPLAY, INT_MIDPOINT, CONST_CHAR_IS_DIGIT }
+    1,87,0 { OS_STR_DISPLAY, INT_MIDPOINT, CONST_CHAR_IS_DIGIT, UNSIGNED_IS_MULTIPLE_OF }
     1,85,0 { UINT_FLOAT_MIDPOINT, CONST_SIZE_OF_VAL }
     1,84,0 { CONST_OPTION_AS_SLICE, MANUAL_DANGLING_PTR }
     1,83,0 { CONST_EXTERN_FN, CONST_FLOAT_BITS_CONV, CONST_FLOAT_CLASSIFY, CONST_MUT_REFS, CONST_UNWRAP }
@@ -42,6 +42,7 @@ msrv_aliases! {
     1,65,0 { LET_ELSE, POINTER_CAST_CONSTNESS }
     1,63,0 { CLONE_INTO, CONST_SLICE_FROM_REF }
     1,62,0 { BOOL_THEN_SOME, DEFAULT_ENUM_ATTRIBUTE, CONST_EXTERN_C_FN }
+    1,61,0 { CONST_FN_TRAIT_BOUND }
     1,60,0 { ABS_DIFF }
     1,59,0 { THREAD_LOCAL_CONST_INIT }
     1,58,0 { FORMAT_ARGS_CAPTURE, PATTERN_TRAIT_CHAR_ARRAY, CONST_RAW_PTR_DEREF }
diff --git a/src/tools/clippy/clippy_utils/src/paths.rs b/src/tools/clippy/clippy_utils/src/paths.rs
index f37a609497e..8bbcb220210 100644
--- a/src/tools/clippy/clippy_utils/src/paths.rs
+++ b/src/tools/clippy/clippy_utils/src/paths.rs
@@ -126,15 +126,6 @@ path_macros! {
     macro_path: PathNS::Macro,
 }
 
-// Paths in `core`/`alloc`/`std`. This should be avoided and cleaned up by adding diagnostic items.
-pub static ALIGN_OF: PathLookup = value_path!(core::mem::align_of);
-pub static CHAR_TO_DIGIT: PathLookup = value_path!(char::to_digit);
-pub static CONCAT: PathLookup = macro_path!(core::concat);
-pub static IO_ERROR_NEW: PathLookup = value_path!(std::io::Error::new);
-pub static IO_ERRORKIND_OTHER_CTOR: PathLookup = value_path!(std::io::ErrorKind::Other);
-pub static ITER_STEP: PathLookup = type_path!(core::iter::Step);
-pub static SLICE_FROM_REF: PathLookup = value_path!(core::slice::from_ref);
-
 // Paths in external crates
 pub static FUTURES_IO_ASYNCREADEXT: PathLookup = type_path!(futures_util::AsyncReadExt);
 pub static FUTURES_IO_ASYNCWRITEEXT: PathLookup = type_path!(futures_util::AsyncWriteExt);
diff --git a/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs b/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs
index e629012b187..8f1ebb8ada6 100644
--- a/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs
+++ b/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs
@@ -32,6 +32,21 @@ pub fn is_min_const_fn<'tcx>(cx: &LateContext<'tcx>, body: &Body<'tcx>, msrv: Ms
     for local in &body.local_decls {
         check_ty(cx, local.ty, local.source_info.span, msrv)?;
     }
+    if !msrv.meets(cx, msrvs::CONST_FN_TRAIT_BOUND)
+        && let Some(sized_did) = cx.tcx.lang_items().sized_trait()
+        && let Some(meta_sized_did) = cx.tcx.lang_items().meta_sized_trait()
+        && cx.tcx.param_env(def_id).caller_bounds().iter().any(|bound| {
+            bound.as_trait_clause().is_some_and(|clause| {
+                let did = clause.def_id();
+                did != sized_did && did != meta_sized_did
+            })
+        })
+    {
+        return Err((
+            body.span,
+            "non-`Sized` trait clause before `const_fn_trait_bound` is stabilized".into(),
+        ));
+    }
     // impl trait is gone in MIR, so check the return type manually
     check_ty(
         cx,
@@ -436,7 +451,7 @@ fn is_ty_const_destruct<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>, body: &Body<'tcx>
     // FIXME(const_trait_impl, fee1-dead) revert to const destruct once it works again
     #[expect(unused)]
     fn is_ty_const_destruct_unused<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>, body: &Body<'tcx>) -> bool {
-        // If this doesn't need drop at all, then don't select `~const Destruct`.
+        // If this doesn't need drop at all, then don't select `[const] Destruct`.
         if !ty.needs_drop(tcx, body.typing_env(tcx)) {
             return false;
         }
diff --git a/src/tools/clippy/clippy_utils/src/sugg.rs b/src/tools/clippy/clippy_utils/src/sugg.rs
index 6974e6512e2..7a24d07fa1d 100644
--- a/src/tools/clippy/clippy_utils/src/sugg.rs
+++ b/src/tools/clippy/clippy_utils/src/sugg.rs
@@ -494,7 +494,17 @@ impl<T: Display> Display for ParenHelper<T> {
 /// operators have the same
 /// precedence.
 pub fn make_unop(op: &str, expr: Sugg<'_>) -> Sugg<'static> {
-    Sugg::MaybeParen(format!("{op}{}", expr.maybe_paren()).into())
+    // If the `expr` starts with `op` already, do not add wrap it in
+    // parentheses.
+    let expr = if let Sugg::MaybeParen(ref sugg) = expr
+        && !has_enclosing_paren(sugg)
+        && sugg.starts_with(op)
+    {
+        expr
+    } else {
+        expr.maybe_paren()
+    };
+    Sugg::MaybeParen(format!("{op}{expr}").into())
 }
 
 /// Builds the string for `<lhs> <op> <rhs>` adding parenthesis when necessary.
@@ -1016,6 +1026,16 @@ mod test {
         let sugg = Sugg::BinOp(AssocOp::Binary(ast::BinOpKind::Add), "(1 + 1)".into(), "(1 + 1)".into());
         assert_eq!("((1 + 1) + (1 + 1))", sugg.maybe_paren().to_string());
     }
+
+    #[test]
+    fn unop_parenthesize() {
+        let sugg = Sugg::NonParen("x".into()).mut_addr();
+        assert_eq!("&mut x", sugg.to_string());
+        let sugg = sugg.mut_addr();
+        assert_eq!("&mut &mut x", sugg.to_string());
+        assert_eq!("(&mut &mut x)", sugg.maybe_paren().to_string());
+    }
+
     #[test]
     fn not_op() {
         use ast::BinOpKind::{Add, And, Eq, Ge, Gt, Le, Lt, Ne, Or};
diff --git a/src/tools/clippy/clippy_utils/src/sym.rs b/src/tools/clippy/clippy_utils/src/sym.rs
index 3b58dba5628..8a8218c6976 100644
--- a/src/tools/clippy/clippy_utils/src/sym.rs
+++ b/src/tools/clippy/clippy_utils/src/sym.rs
@@ -46,7 +46,6 @@ generate! {
     DOUBLE_QUOTE: "\"",
     Deserialize,
     EarlyLintPass,
-    ErrorKind,
     IntoIter,
     Itertools,
     LF: "\n",
@@ -65,7 +64,6 @@ generate! {
     RegexBuilder,
     RegexSet,
     Start,
-    Step,
     Symbol,
     SyntaxContext,
     TBD,
@@ -158,7 +156,6 @@ generate! {
     from_ne_bytes,
     from_ptr,
     from_raw,
-    from_ref,
     from_str,
     from_str_radix,
     fs,
@@ -166,6 +163,7 @@ generate! {
     futures_util,
     get,
     get_mut,
+    get_or_insert,
     get_or_insert_with,
     get_unchecked,
     get_unchecked_mut,
@@ -216,7 +214,6 @@ generate! {
     max_by_key,
     max_value,
     maximum,
-    mem,
     min,
     min_by,
     min_by_key,
diff --git a/src/tools/clippy/clippy_utils/src/ty/mod.rs b/src/tools/clippy/clippy_utils/src/ty/mod.rs
index 32a992ccc2d..bffbcf073ab 100644
--- a/src/tools/clippy/clippy_utils/src/ty/mod.rs
+++ b/src/tools/clippy/clippy_utils/src/ty/mod.rs
@@ -6,6 +6,7 @@ use core::ops::ControlFlow;
 use itertools::Itertools;
 use rustc_abi::VariantIdx;
 use rustc_ast::ast::Mutability;
+use rustc_attr_data_structures::{AttributeKind, find_attr};
 use rustc_data_structures::fx::{FxHashMap, FxHashSet};
 use rustc_hir as hir;
 use rustc_hir::def::{CtorKind, CtorOf, DefKind, Res};
@@ -20,8 +21,8 @@ use rustc_middle::traits::EvaluationResult;
 use rustc_middle::ty::layout::ValidityRequirement;
 use rustc_middle::ty::{
     self, AdtDef, AliasTy, AssocItem, AssocTag, Binder, BoundRegion, FnSig, GenericArg, GenericArgKind, GenericArgsRef,
-    GenericParamDefKind, IntTy, Region, RegionKind, TraitRef, Ty, TyCtxt, TypeSuperVisitable,
-    TypeVisitable, TypeVisitableExt, TypeVisitor, UintTy, Upcast, VariantDef, VariantDiscr,
+    GenericParamDefKind, IntTy, Region, RegionKind, TraitRef, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable,
+    TypeVisitableExt, TypeVisitor, UintTy, Upcast, VariantDef, VariantDiscr,
 };
 use rustc_span::symbol::Ident;
 use rustc_span::{DUMMY_SP, Span, Symbol, sym};
@@ -326,8 +327,8 @@ pub fn has_drop<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool {
 // Returns whether the type has #[must_use] attribute
 pub fn is_must_use_ty<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool {
     match ty.kind() {
-        ty::Adt(adt, _) => cx.tcx.has_attr(adt.did(), sym::must_use),
-        ty::Foreign(did) => cx.tcx.has_attr(*did, sym::must_use),
+        ty::Adt(adt, _) => find_attr!(cx.tcx.get_all_attrs(adt.did()), AttributeKind::MustUse { .. }),
+        ty::Foreign(did) => find_attr!(cx.tcx.get_all_attrs(*did), AttributeKind::MustUse { .. }),
         ty::Slice(ty) | ty::Array(ty, _) | ty::RawPtr(ty, _) | ty::Ref(_, ty, _) => {
             // for the Array case we don't need to care for the len == 0 case
             // because we don't want to lint functions returning empty arrays
@@ -337,7 +338,10 @@ pub fn is_must_use_ty<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool {
         ty::Alias(ty::Opaque, AliasTy { def_id, .. }) => {
             for (predicate, _) in cx.tcx.explicit_item_self_bounds(def_id).skip_binder() {
                 if let ty::ClauseKind::Trait(trait_predicate) = predicate.kind().skip_binder()
-                    && cx.tcx.has_attr(trait_predicate.trait_ref.def_id, sym::must_use)
+                    && find_attr!(
+                        cx.tcx.get_all_attrs(trait_predicate.trait_ref.def_id),
+                        AttributeKind::MustUse { .. }
+                    )
                 {
                     return true;
                 }
@@ -347,7 +351,7 @@ pub fn is_must_use_ty<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool {
         ty::Dynamic(binder, _, _) => {
             for predicate in *binder {
                 if let ty::ExistentialPredicate::Trait(ref trait_ref) = predicate.skip_binder()
-                    && cx.tcx.has_attr(trait_ref.def_id, sym::must_use)
+                    && find_attr!(cx.tcx.get_all_attrs(trait_ref.def_id), AttributeKind::MustUse { .. })
                 {
                     return true;
                 }
diff --git a/src/tools/clippy/declare_clippy_lint/Cargo.toml b/src/tools/clippy/declare_clippy_lint/Cargo.toml
new file mode 100644
index 00000000000..bd6b4dfdee4
--- /dev/null
+++ b/src/tools/clippy/declare_clippy_lint/Cargo.toml
@@ -0,0 +1,10 @@
+[package]
+name = "declare_clippy_lint"
+version = "0.1.90"
+edition = "2024"
+repository = "https://github.com/rust-lang/rust-clippy"
+license = "MIT OR Apache-2.0"
+
+[package.metadata.rust-analyzer]
+# This crate uses #[feature(rustc_private)]
+rustc_private = true
diff --git a/src/tools/clippy/declare_clippy_lint/src/lib.rs b/src/tools/clippy/declare_clippy_lint/src/lib.rs
new file mode 100644
index 00000000000..f7d9c64bfbd
--- /dev/null
+++ b/src/tools/clippy/declare_clippy_lint/src/lib.rs
@@ -0,0 +1,280 @@
+#![feature(macro_metavar_expr_concat, rustc_private)]
+
+extern crate rustc_lint;
+
+use rustc_lint::{Lint, LintId, LintStore};
+
+// Needed by `declare_clippy_lint!`.
+pub extern crate rustc_session;
+
+#[derive(Default)]
+pub struct LintListBuilder {
+    lints: Vec<&'static Lint>,
+    all: Vec<LintId>,
+    cargo: Vec<LintId>,
+    complexity: Vec<LintId>,
+    correctness: Vec<LintId>,
+    nursery: Vec<LintId>,
+    pedantic: Vec<LintId>,
+    perf: Vec<LintId>,
+    restriction: Vec<LintId>,
+    style: Vec<LintId>,
+    suspicious: Vec<LintId>,
+}
+impl LintListBuilder {
+    pub fn insert(&mut self, lints: &[&LintInfo]) {
+        #[allow(clippy::enum_glob_use)]
+        use LintCategory::*;
+
+        self.lints.extend(lints.iter().map(|&x| x.lint));
+        for &&LintInfo { lint, category, .. } in lints {
+            let (all, cat) = match category {
+                Complexity => (Some(&mut self.all), &mut self.complexity),
+                Correctness => (Some(&mut self.all), &mut self.correctness),
+                Perf => (Some(&mut self.all), &mut self.perf),
+                Style => (Some(&mut self.all), &mut self.style),
+                Suspicious => (Some(&mut self.all), &mut self.suspicious),
+                Cargo => (None, &mut self.cargo),
+                Nursery => (None, &mut self.nursery),
+                Pedantic => (None, &mut self.pedantic),
+                Restriction => (None, &mut self.restriction),
+            };
+            if let Some(all) = all {
+                all.push(LintId::of(lint));
+            }
+            cat.push(LintId::of(lint));
+        }
+    }
+
+    pub fn register(self, store: &mut LintStore) {
+        store.register_lints(&self.lints);
+        store.register_group(true, "clippy::all", Some("clippy_all"), self.all);
+        store.register_group(true, "clippy::cargo", Some("clippy_cargo"), self.cargo);
+        store.register_group(true, "clippy::complexity", Some("clippy_complexity"), self.complexity);
+        store.register_group(
+            true,
+            "clippy::correctness",
+            Some("clippy_correctness"),
+            self.correctness,
+        );
+        store.register_group(true, "clippy::nursery", Some("clippy_nursery"), self.nursery);
+        store.register_group(true, "clippy::pedantic", Some("clippy_pedantic"), self.pedantic);
+        store.register_group(true, "clippy::perf", Some("clippy_perf"), self.perf);
+        store.register_group(
+            true,
+            "clippy::restriction",
+            Some("clippy_restriction"),
+            self.restriction,
+        );
+        store.register_group(true, "clippy::style", Some("clippy_style"), self.style);
+        store.register_group(true, "clippy::suspicious", Some("clippy_suspicious"), self.suspicious);
+    }
+}
+
+#[derive(Copy, Clone, Debug)]
+pub enum LintCategory {
+    Cargo,
+    Complexity,
+    Correctness,
+    Nursery,
+    Pedantic,
+    Perf,
+    Restriction,
+    Style,
+    Suspicious,
+}
+impl LintCategory {
+    #[must_use]
+    pub fn name(self) -> &'static str {
+        match self {
+            Self::Cargo => "cargo",
+            Self::Complexity => "complexity",
+            Self::Correctness => "correctness",
+            Self::Nursery => "nursery",
+            Self::Pedantic => "pedantic",
+            Self::Perf => "perf",
+            Self::Restriction => "restriction",
+            Self::Style => "style",
+            Self::Suspicious => "suspicious",
+        }
+    }
+}
+
+pub struct LintInfo {
+    pub lint: &'static Lint,
+    pub category: LintCategory,
+    pub explanation: &'static str,
+    /// e.g. `clippy_lints/src/absolute_paths.rs#43`
+    pub location: &'static str,
+    pub version: &'static str,
+}
+
+impl LintInfo {
+    /// Returns the lint name in lowercase without the `clippy::` prefix
+    #[must_use]
+    #[expect(clippy::missing_panics_doc)]
+    pub fn name_lower(&self) -> String {
+        self.lint.name.strip_prefix("clippy::").unwrap().to_ascii_lowercase()
+    }
+}
+
+#[macro_export]
+macro_rules! declare_clippy_lint_inner {
+    (
+        $(#[doc = $docs:literal])*
+        #[clippy::version = $version:literal]
+        $vis:vis $lint_name:ident,
+        $level:ident,
+        $category:ident,
+        $desc:literal
+        $(, @eval_always = $eval_always:literal)?
+    ) => {
+        $crate::rustc_session::declare_tool_lint! {
+            $(#[doc = $docs])*
+            #[clippy::version = $version]
+            $vis clippy::$lint_name,
+            $level,
+            $desc,
+            report_in_external_macro:true
+            $(, @eval_always = $eval_always)?
+        }
+
+        pub(crate) static ${concat($lint_name, _INFO)}: &'static $crate::LintInfo = &$crate::LintInfo {
+            lint: $lint_name,
+            category: $crate::LintCategory::$category,
+            explanation: concat!($($docs,"\n",)*),
+            location: concat!(file!(), "#L", line!()),
+            version: $version,
+        };
+    };
+}
+
+#[macro_export]
+macro_rules! declare_clippy_lint {
+    (
+        $(#[$($meta:tt)*])*
+        $vis:vis $lint_name:ident,
+        correctness,
+        $($rest:tt)*
+    ) => {
+        $crate::declare_clippy_lint_inner! {
+            $(#[$($meta)*])*
+            $vis $lint_name,
+            Deny,
+            Correctness,
+            $($rest)*
+        }
+    };
+    (
+        $(#[$($meta:tt)*])*
+        $vis:vis $lint_name:ident,
+        complexity,
+        $($rest:tt)*
+    ) => {
+        $crate::declare_clippy_lint_inner! {
+            $(#[$($meta)*])*
+            $vis $lint_name,
+            Warn,
+            Complexity,
+            $($rest)*
+        }
+    };
+    (
+        $(#[$($meta:tt)*])*
+        $vis:vis $lint_name:ident,
+        perf,
+        $($rest:tt)*
+    ) => {
+        $crate::declare_clippy_lint_inner! {
+            $(#[$($meta)*])*
+            $vis $lint_name,
+            Warn,
+            Perf,
+            $($rest)*
+        }
+    };
+    (
+        $(#[$($meta:tt)*])*
+        $vis:vis $lint_name:ident,
+        style,
+        $($rest:tt)*
+    ) => {
+        $crate::declare_clippy_lint_inner! {
+            $(#[$($meta)*])*
+            $vis $lint_name,
+            Warn,
+            Style,
+            $($rest)*
+        }
+    };
+    (
+        $(#[$($meta:tt)*])*
+        $vis:vis $lint_name:ident,
+        suspicious,
+        $($rest:tt)*
+    ) => {
+        $crate::declare_clippy_lint_inner! {
+            $(#[$($meta)*])*
+            $vis $lint_name,
+            Warn,
+            Suspicious,
+            $($rest)*
+        }
+    };
+    (
+        $(#[$($meta:tt)*])*
+        $vis:vis $lint_name:ident,
+        cargo,
+        $($rest:tt)*
+    ) => {
+        $crate::declare_clippy_lint_inner! {
+            $(#[$($meta)*])*
+            $vis $lint_name,
+            Allow,
+            Cargo,
+            $($rest)*
+        }
+    };
+    (
+        $(#[$($meta:tt)*])*
+        $vis:vis $lint_name:ident,
+        nursery,
+        $($rest:tt)*
+    ) => {
+        $crate::declare_clippy_lint_inner! {
+            $(#[$($meta)*])*
+            $vis $lint_name,
+            Allow,
+            Nursery,
+            $($rest)*
+        }
+    };
+    (
+        $(#[$($meta:tt)*])*
+        $vis:vis $lint_name:ident,
+        pedantic,
+        $($rest:tt)*
+    ) => {
+        $crate::declare_clippy_lint_inner! {
+            $(#[$($meta)*])*
+            $vis $lint_name,
+            Allow,
+            Pedantic,
+            $($rest)*
+        }
+    };
+    (
+        $(#[$($meta:tt)*])*
+        $vis:vis $lint_name:ident,
+        restriction,
+        $($rest:tt)*
+    ) => {
+        $crate::declare_clippy_lint_inner! {
+            $(#[$($meta)*])*
+            $vis $lint_name,
+            Allow,
+            Restriction,
+            $($rest)*
+        }
+    };
+}
diff --git a/src/tools/clippy/lintcheck/src/main.rs b/src/tools/clippy/lintcheck/src/main.rs
index 84183831432..eb390eecbcc 100644
--- a/src/tools/clippy/lintcheck/src/main.rs
+++ b/src/tools/clippy/lintcheck/src/main.rs
@@ -45,7 +45,7 @@ use rayon::prelude::*;
 
 #[must_use]
 pub fn target_dir() -> String {
-    env::var("CARGO_TARGET_DIR").unwrap_or("target".to_owned())
+    env::var("CARGO_TARGET_DIR").unwrap_or_else(|_| "target".to_owned())
 }
 
 fn lintcheck_sources() -> String {
diff --git a/src/tools/clippy/rust-toolchain.toml b/src/tools/clippy/rust-toolchain.toml
index 3fc5a1224a8..124756a3600 100644
--- a/src/tools/clippy/rust-toolchain.toml
+++ b/src/tools/clippy/rust-toolchain.toml
@@ -1,6 +1,6 @@
 [toolchain]
 # begin autogenerated nightly
-channel = "nightly-2025-06-12"
+channel = "nightly-2025-06-26"
 # end autogenerated nightly
 components = ["cargo", "llvm-tools", "rust-src", "rust-std", "rustc", "rustc-dev", "rustfmt"]
 profile = "minimal"
diff --git a/src/tools/clippy/src/driver.rs b/src/tools/clippy/src/driver.rs
index 37adb14169a..c4076cbaa77 100644
--- a/src/tools/clippy/src/driver.rs
+++ b/src/tools/clippy/src/driver.rs
@@ -13,7 +13,13 @@ extern crate rustc_interface;
 extern crate rustc_session;
 extern crate rustc_span;
 
+// See docs in https://github.com/rust-lang/rust/blob/master/compiler/rustc/src/main.rs
+// about jemalloc.
+#[cfg(feature = "jemalloc")]
+extern crate tikv_jemalloc_sys as jemalloc_sys;
+
 use clippy_utils::sym;
+use declare_clippy_lint::LintListBuilder;
 use rustc_interface::interface;
 use rustc_session::EarlyDiagCtxt;
 use rustc_session::config::ErrorOutputType;
@@ -151,8 +157,13 @@ impl rustc_driver::Callbacks for ClippyCallbacks {
                 (previous)(sess, lint_store);
             }
 
+            let mut list_builder = LintListBuilder::default();
+            list_builder.insert(clippy_lints::declared_lints::LINTS);
+            list_builder.register(lint_store);
+
             let conf = clippy_config::Conf::read(sess, &conf_path);
-            clippy_lints::register_lints(lint_store, conf);
+            clippy_lints::register_lint_passes(lint_store, conf);
+
             #[cfg(feature = "internal")]
             clippy_lints_internal::register_lints(lint_store);
         }));
@@ -181,6 +192,36 @@ const BUG_REPORT_URL: &str = "https://github.com/rust-lang/rust-clippy/issues/ne
 #[allow(clippy::too_many_lines)]
 #[allow(clippy::ignored_unit_patterns)]
 pub fn main() {
+    // See docs in https://github.com/rust-lang/rust/blob/master/compiler/rustc/src/main.rs
+    // about jemalloc.
+    #[cfg(feature = "jemalloc")]
+    {
+        use std::os::raw::{c_int, c_void};
+
+        #[used]
+        static _F1: unsafe extern "C" fn(usize, usize) -> *mut c_void = jemalloc_sys::calloc;
+        #[used]
+        static _F2: unsafe extern "C" fn(*mut *mut c_void, usize, usize) -> c_int = jemalloc_sys::posix_memalign;
+        #[used]
+        static _F3: unsafe extern "C" fn(usize, usize) -> *mut c_void = jemalloc_sys::aligned_alloc;
+        #[used]
+        static _F4: unsafe extern "C" fn(usize) -> *mut c_void = jemalloc_sys::malloc;
+        #[used]
+        static _F5: unsafe extern "C" fn(*mut c_void, usize) -> *mut c_void = jemalloc_sys::realloc;
+        #[used]
+        static _F6: unsafe extern "C" fn(*mut c_void) = jemalloc_sys::free;
+
+        #[cfg(target_os = "macos")]
+        {
+            unsafe extern "C" {
+                fn _rjem_je_zone_register();
+            }
+
+            #[used]
+            static _F7: unsafe extern "C" fn() = _rjem_je_zone_register;
+        }
+    }
+
     let early_dcx = EarlyDiagCtxt::new(ErrorOutputType::default());
 
     rustc_driver::init_rustc_env_logger(&early_dcx);
diff --git a/src/tools/clippy/src/main.rs b/src/tools/clippy/src/main.rs
index c9853e53f3b..3c2eec1f05b 100644
--- a/src/tools/clippy/src/main.rs
+++ b/src/tools/clippy/src/main.rs
@@ -107,7 +107,7 @@ impl ClippyCmd {
     }
 
     fn into_std_cmd(self) -> Command {
-        let mut cmd = Command::new(env::var("CARGO").unwrap_or("cargo".into()));
+        let mut cmd = Command::new(env::var("CARGO").unwrap_or_else(|_| "cargo".into()));
         let clippy_args: String = self
             .clippy_args
             .iter()
diff --git a/src/tools/clippy/tests/compile-test.rs b/src/tools/clippy/tests/compile-test.rs
index 99a01257a7b..cefe654fef6 100644
--- a/src/tools/clippy/tests/compile-test.rs
+++ b/src/tools/clippy/tests/compile-test.rs
@@ -7,9 +7,9 @@ use askama::filters::Safe;
 use cargo_metadata::Message;
 use cargo_metadata::diagnostic::{Applicability, Diagnostic};
 use clippy_config::ClippyConfiguration;
-use clippy_lints::LintInfo;
 use clippy_lints::declared_lints::LINTS;
 use clippy_lints::deprecated_lints::{DEPRECATED, DEPRECATED_VERSION, RENAMED};
+use declare_clippy_lint::LintInfo;
 use pulldown_cmark::{Options, Parser, html};
 use serde::Deserialize;
 use test_utils::IS_RUSTC_TEST_SUITE;
@@ -568,10 +568,10 @@ impl LintMetadata {
         Self {
             id: name,
             id_location: Some(lint.location),
-            group: lint.category_str(),
+            group: lint.category.name(),
             level: lint.lint.default_level.as_str(),
             docs,
-            version: lint.version.unwrap(),
+            version: lint.version,
             applicability,
         }
     }
diff --git a/src/tools/clippy/tests/dogfood.rs b/src/tools/clippy/tests/dogfood.rs
index 4ac2bd53285..389616801fc 100644
--- a/src/tools/clippy/tests/dogfood.rs
+++ b/src/tools/clippy/tests/dogfood.rs
@@ -40,6 +40,7 @@ fn dogfood() {
         "clippy_lints",
         "clippy_utils",
         "clippy_config",
+        "declare_clippy_lint",
         "lintcheck",
         "rustc_tools_util",
     ] {
diff --git a/src/tools/clippy/tests/ui-toml/collapsible_if/collapsible_else_if.fixed b/src/tools/clippy/tests/ui-toml/collapsible_if/collapsible_else_if.fixed
new file mode 100644
index 00000000000..0dc0fc230c8
--- /dev/null
+++ b/src/tools/clippy/tests/ui-toml/collapsible_if/collapsible_else_if.fixed
@@ -0,0 +1,50 @@
+#![allow(clippy::eq_op, clippy::nonminimal_bool)]
+
+#[rustfmt::skip]
+#[warn(clippy::collapsible_if)]
+fn main() {
+    let (x, y) = ("hello", "world");
+
+    if x == "hello" {
+        todo!()
+    }
+        // Comment must be kept
+        else if y == "world" {
+            println!("Hello world!");
+        }
+    //~^^^^^^ collapsible_else_if
+
+    if x == "hello" {
+        todo!()
+    } // Inner comment
+        else if y == "world" {
+            println!("Hello world!");
+        }
+    //~^^^^^ collapsible_else_if
+
+    if x == "hello" {
+        todo!()
+    }
+        /* Inner comment */
+        else if y == "world" {
+            println!("Hello world!");
+        }
+    //~^^^^^^ collapsible_else_if
+
+    if x == "hello" { 
+        todo!()
+    } /* Inner comment */
+        else if y == "world" {
+            println!("Hello world!");
+        }
+    //~^^^^^ collapsible_else_if
+
+    if x == "hello" {
+        todo!()
+    } /* This should not be removed */ /* So does this */
+        // Comment must be kept
+        else if y == "world" {
+            println!("Hello world!");
+        }
+    //~^^^^^^ collapsible_else_if
+}
diff --git a/src/tools/clippy/tests/ui-toml/collapsible_if/collapsible_else_if.rs b/src/tools/clippy/tests/ui-toml/collapsible_if/collapsible_else_if.rs
new file mode 100644
index 00000000000..8344c122f16
--- /dev/null
+++ b/src/tools/clippy/tests/ui-toml/collapsible_if/collapsible_else_if.rs
@@ -0,0 +1,55 @@
+#![allow(clippy::eq_op, clippy::nonminimal_bool)]
+
+#[rustfmt::skip]
+#[warn(clippy::collapsible_if)]
+fn main() {
+    let (x, y) = ("hello", "world");
+
+    if x == "hello" {
+        todo!()
+    } else {
+        // Comment must be kept
+        if y == "world" {
+            println!("Hello world!");
+        }
+    }
+    //~^^^^^^ collapsible_else_if
+
+    if x == "hello" {
+        todo!()
+    } else { // Inner comment
+        if y == "world" {
+            println!("Hello world!");
+        }
+    }
+    //~^^^^^ collapsible_else_if
+
+    if x == "hello" {
+        todo!()
+    } else {
+        /* Inner comment */
+        if y == "world" {
+            println!("Hello world!");
+        }
+    }
+    //~^^^^^^ collapsible_else_if
+
+    if x == "hello" { 
+        todo!()
+    } else { /* Inner comment */
+        if y == "world" {
+            println!("Hello world!");
+        }
+    }
+    //~^^^^^ collapsible_else_if
+
+    if x == "hello" {
+        todo!()
+    } /* This should not be removed */ else /* So does this */ {
+        // Comment must be kept
+        if y == "world" {
+            println!("Hello world!");
+        }
+    }
+    //~^^^^^^ collapsible_else_if
+}
diff --git a/src/tools/clippy/tests/ui-toml/collapsible_if/collapsible_else_if.stderr b/src/tools/clippy/tests/ui-toml/collapsible_if/collapsible_else_if.stderr
new file mode 100644
index 00000000000..0ffe5f0a960
--- /dev/null
+++ b/src/tools/clippy/tests/ui-toml/collapsible_if/collapsible_else_if.stderr
@@ -0,0 +1,105 @@
+error: this `else { if .. }` block can be collapsed
+  --> tests/ui-toml/collapsible_if/collapsible_else_if.rs:10:12
+   |
+LL |       } else {
+   |  ____________^
+LL | |         // Comment must be kept
+LL | |         if y == "world" {
+LL | |             println!("Hello world!");
+LL | |         }
+LL | |     }
+   | |_____^
+   |
+   = note: `-D clippy::collapsible-else-if` implied by `-D warnings`
+   = help: to override `-D warnings` add `#[allow(clippy::collapsible_else_if)]`
+help: collapse nested if block
+   |
+LL ~     }
+LL |         // Comment must be kept
+LL ~         else if y == "world" {
+LL |             println!("Hello world!");
+LL ~         }
+   |
+
+error: this `else { if .. }` block can be collapsed
+  --> tests/ui-toml/collapsible_if/collapsible_else_if.rs:20:12
+   |
+LL |       } else { // Inner comment
+   |  ____________^
+LL | |         if y == "world" {
+LL | |             println!("Hello world!");
+LL | |         }
+LL | |     }
+   | |_____^
+   |
+help: collapse nested if block
+   |
+LL ~     } // Inner comment
+LL ~         else if y == "world" {
+LL |             println!("Hello world!");
+LL ~         }
+   |
+
+error: this `else { if .. }` block can be collapsed
+  --> tests/ui-toml/collapsible_if/collapsible_else_if.rs:29:12
+   |
+LL |       } else {
+   |  ____________^
+LL | |         /* Inner comment */
+LL | |         if y == "world" {
+LL | |             println!("Hello world!");
+LL | |         }
+LL | |     }
+   | |_____^
+   |
+help: collapse nested if block
+   |
+LL ~     }
+LL |         /* Inner comment */
+LL ~         else if y == "world" {
+LL |             println!("Hello world!");
+LL ~         }
+   |
+
+error: this `else { if .. }` block can be collapsed
+  --> tests/ui-toml/collapsible_if/collapsible_else_if.rs:39:12
+   |
+LL |       } else { /* Inner comment */
+   |  ____________^
+LL | |         if y == "world" {
+LL | |             println!("Hello world!");
+LL | |         }
+LL | |     }
+   | |_____^
+   |
+help: collapse nested if block
+   |
+LL ~     } /* Inner comment */
+LL ~         else if y == "world" {
+LL |             println!("Hello world!");
+LL ~         }
+   |
+
+error: this `else { if .. }` block can be collapsed
+  --> tests/ui-toml/collapsible_if/collapsible_else_if.rs:48:64
+   |
+LL |       } /* This should not be removed */ else /* So does this */ {
+   |  ________________________________________________________________^
+LL | |         // Comment must be kept
+LL | |         if y == "world" {
+LL | |             println!("Hello world!");
+LL | |         }
+LL | |     }
+   | |_____^
+   |
+help: collapse nested if block
+   |
+LL ~     } /* This should not be removed */ /* So does this */
+LL |         // Comment must be kept
+LL ~         else if y == "world" {
+LL |             println!("Hello world!");
+LL ~         }
+   |
+
+error: aborting due to 5 previous errors
+
diff --git a/src/tools/clippy/tests/ui/assign_ops.fixed b/src/tools/clippy/tests/ui/assign_ops.fixed
index 3bc6885d7c3..99beea850a2 100644
--- a/src/tools/clippy/tests/ui/assign_ops.fixed
+++ b/src/tools/clippy/tests/ui/assign_ops.fixed
@@ -91,7 +91,7 @@ mod issue14871 {
 
     impl<T> const NumberConstants for T
     where
-        T: Number + ~const core::ops::Add,
+        T: Number + [const] core::ops::Add,
     {
         fn constant(value: usize) -> Self {
             let mut res = Self::ZERO;
diff --git a/src/tools/clippy/tests/ui/assign_ops.rs b/src/tools/clippy/tests/ui/assign_ops.rs
index f1f8f9daff9..900d5ad38e0 100644
--- a/src/tools/clippy/tests/ui/assign_ops.rs
+++ b/src/tools/clippy/tests/ui/assign_ops.rs
@@ -91,7 +91,7 @@ mod issue14871 {
 
     impl<T> const NumberConstants for T
     where
-        T: Number + ~const core::ops::Add,
+        T: Number + [const] core::ops::Add,
     {
         fn constant(value: usize) -> Self {
             let mut res = Self::ZERO;
diff --git a/src/tools/clippy/tests/ui/borrow_deref_ref.fixed b/src/tools/clippy/tests/ui/borrow_deref_ref.fixed
index 765dd75fceb..6d06fcc3037 100644
--- a/src/tools/clippy/tests/ui/borrow_deref_ref.fixed
+++ b/src/tools/clippy/tests/ui/borrow_deref_ref.fixed
@@ -124,3 +124,50 @@ mod issue_11346 {
         //~^ borrow_deref_ref
     }
 }
+
+fn issue_14934() {
+    let x: &'static str = "x";
+    let y = "y".to_string();
+    {
+        #[expect(clippy::toplevel_ref_arg)]
+        let ref mut x = &*x; // Do not lint
+        *x = &*y;
+    }
+    {
+        let mut x = x;
+        //~^ borrow_deref_ref
+        x = &*y;
+    }
+    {
+        #[expect(clippy::toplevel_ref_arg, clippy::needless_borrow)]
+        let ref x = x;
+        //~^ borrow_deref_ref
+    }
+    {
+        #[expect(clippy::toplevel_ref_arg)]
+        let ref mut x = std::convert::identity(x);
+        //~^ borrow_deref_ref
+        *x = &*y;
+    }
+    {
+        #[derive(Clone)]
+        struct S(&'static str);
+        let s = S("foo");
+        #[expect(clippy::toplevel_ref_arg)]
+        let ref mut x = &*s.0; // Do not lint
+        *x = "bar";
+        #[expect(clippy::toplevel_ref_arg)]
+        let ref mut x = s.clone().0;
+        //~^ borrow_deref_ref
+        *x = "bar";
+        #[expect(clippy::toplevel_ref_arg)]
+        let ref mut x = &*std::convert::identity(&s).0;
+        *x = "bar";
+    }
+    {
+        let y = &1;
+        #[expect(clippy::toplevel_ref_arg)]
+        let ref mut x = { y };
+        //~^ borrow_deref_ref
+    }
+}
diff --git a/src/tools/clippy/tests/ui/borrow_deref_ref.rs b/src/tools/clippy/tests/ui/borrow_deref_ref.rs
index 8ee66bfa881..b43f4c93bf2 100644
--- a/src/tools/clippy/tests/ui/borrow_deref_ref.rs
+++ b/src/tools/clippy/tests/ui/borrow_deref_ref.rs
@@ -124,3 +124,50 @@ mod issue_11346 {
         //~^ borrow_deref_ref
     }
 }
+
+fn issue_14934() {
+    let x: &'static str = "x";
+    let y = "y".to_string();
+    {
+        #[expect(clippy::toplevel_ref_arg)]
+        let ref mut x = &*x; // Do not lint
+        *x = &*y;
+    }
+    {
+        let mut x = &*x;
+        //~^ borrow_deref_ref
+        x = &*y;
+    }
+    {
+        #[expect(clippy::toplevel_ref_arg, clippy::needless_borrow)]
+        let ref x = &*x;
+        //~^ borrow_deref_ref
+    }
+    {
+        #[expect(clippy::toplevel_ref_arg)]
+        let ref mut x = &*std::convert::identity(x);
+        //~^ borrow_deref_ref
+        *x = &*y;
+    }
+    {
+        #[derive(Clone)]
+        struct S(&'static str);
+        let s = S("foo");
+        #[expect(clippy::toplevel_ref_arg)]
+        let ref mut x = &*s.0; // Do not lint
+        *x = "bar";
+        #[expect(clippy::toplevel_ref_arg)]
+        let ref mut x = &*s.clone().0;
+        //~^ borrow_deref_ref
+        *x = "bar";
+        #[expect(clippy::toplevel_ref_arg)]
+        let ref mut x = &*std::convert::identity(&s).0;
+        *x = "bar";
+    }
+    {
+        let y = &1;
+        #[expect(clippy::toplevel_ref_arg)]
+        let ref mut x = { &*y };
+        //~^ borrow_deref_ref
+    }
+}
diff --git a/src/tools/clippy/tests/ui/borrow_deref_ref.stderr b/src/tools/clippy/tests/ui/borrow_deref_ref.stderr
index 3d55da25b9b..3a1f968b4be 100644
--- a/src/tools/clippy/tests/ui/borrow_deref_ref.stderr
+++ b/src/tools/clippy/tests/ui/borrow_deref_ref.stderr
@@ -25,5 +25,35 @@ error: deref on an immutable reference
 LL |         (&*s).foo();
    |         ^^^^^ help: if you would like to reborrow, try removing `&*`: `s`
 
-error: aborting due to 4 previous errors
+error: deref on an immutable reference
+  --> tests/ui/borrow_deref_ref.rs:137:21
+   |
+LL |         let mut x = &*x;
+   |                     ^^^ help: if you would like to reborrow, try removing `&*`: `x`
+
+error: deref on an immutable reference
+  --> tests/ui/borrow_deref_ref.rs:143:21
+   |
+LL |         let ref x = &*x;
+   |                     ^^^ help: if you would like to reborrow, try removing `&*`: `x`
+
+error: deref on an immutable reference
+  --> tests/ui/borrow_deref_ref.rs:148:25
+   |
+LL |         let ref mut x = &*std::convert::identity(x);
+   |                         ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: if you would like to reborrow, try removing `&*`: `std::convert::identity(x)`
+
+error: deref on an immutable reference
+  --> tests/ui/borrow_deref_ref.rs:160:25
+   |
+LL |         let ref mut x = &*s.clone().0;
+   |                         ^^^^^^^^^^^^^ help: if you would like to reborrow, try removing `&*`: `s.clone().0`
+
+error: deref on an immutable reference
+  --> tests/ui/borrow_deref_ref.rs:170:27
+   |
+LL |         let ref mut x = { &*y };
+   |                           ^^^ help: if you would like to reborrow, try removing `&*`: `y`
+
+error: aborting due to 9 previous errors
 
diff --git a/src/tools/clippy/tests/ui/borrow_interior_mutable_const.rs b/src/tools/clippy/tests/ui/borrow_interior_mutable_const.rs
index 0f439f78915..674450a73ad 100644
--- a/src/tools/clippy/tests/ui/borrow_interior_mutable_const.rs
+++ b/src/tools/clippy/tests/ui/borrow_interior_mutable_const.rs
@@ -218,4 +218,20 @@ fn main() {
         let _ = &S::VALUE.1; //~ borrow_interior_mutable_const
         let _ = &S::VALUE.2;
     }
+    {
+        pub struct Foo<T, const N: usize>(pub Entry<N>, pub T);
+
+        pub struct Entry<const N: usize>(pub Cell<[u32; N]>);
+
+        impl<const N: usize> Entry<N> {
+            const INIT: Self = Self(Cell::new([42; N]));
+        }
+
+        impl<T, const N: usize> Foo<T, N> {
+            pub fn make_foo(v: T) -> Self {
+                // Used to ICE due to incorrect instantiation.
+                Foo(Entry::INIT, v)
+            }
+        }
+    }
 }
diff --git a/src/tools/clippy/tests/ui/box_default.fixed b/src/tools/clippy/tests/ui/box_default.fixed
index 80000f5de4f..ed00494433b 100644
--- a/src/tools/clippy/tests/ui/box_default.fixed
+++ b/src/tools/clippy/tests/ui/box_default.fixed
@@ -126,7 +126,7 @@ fn issue_10381() {
     impl Bar for Foo {}
 
     fn maybe_get_bar(i: u32) -> Option<Box<dyn Bar>> {
-        if i % 2 == 0 {
+        if i.is_multiple_of(2) {
             Some(Box::new(Foo::default()))
         } else {
             None
diff --git a/src/tools/clippy/tests/ui/box_default.rs b/src/tools/clippy/tests/ui/box_default.rs
index 4681016d7cd..801d92f5c29 100644
--- a/src/tools/clippy/tests/ui/box_default.rs
+++ b/src/tools/clippy/tests/ui/box_default.rs
@@ -126,7 +126,7 @@ fn issue_10381() {
     impl Bar for Foo {}
 
     fn maybe_get_bar(i: u32) -> Option<Box<dyn Bar>> {
-        if i % 2 == 0 {
+        if i.is_multiple_of(2) {
             Some(Box::new(Foo::default()))
         } else {
             None
diff --git a/src/tools/clippy/tests/ui/branches_sharing_code/shared_at_bottom.rs b/src/tools/clippy/tests/ui/branches_sharing_code/shared_at_bottom.rs
index 922d30443fc..fa322dc28a7 100644
--- a/src/tools/clippy/tests/ui/branches_sharing_code/shared_at_bottom.rs
+++ b/src/tools/clippy/tests/ui/branches_sharing_code/shared_at_bottom.rs
@@ -276,3 +276,27 @@ mod issue14873 {
         }
     }
 }
+
+fn issue15004() {
+    let a = 12u32;
+    let b = 13u32;
+    let mut c = 8u32;
+
+    let mut result = if b > a {
+        c += 1;
+        0
+    } else {
+        c += 2;
+        0
+        //~^ branches_sharing_code
+    };
+
+    result = if b > a {
+        c += 1;
+        1
+    } else {
+        c += 2;
+        1
+        //~^ branches_sharing_code
+    };
+}
diff --git a/src/tools/clippy/tests/ui/branches_sharing_code/shared_at_bottom.stderr b/src/tools/clippy/tests/ui/branches_sharing_code/shared_at_bottom.stderr
index f437db8b733..1c470fb0da5 100644
--- a/src/tools/clippy/tests/ui/branches_sharing_code/shared_at_bottom.stderr
+++ b/src/tools/clippy/tests/ui/branches_sharing_code/shared_at_bottom.stderr
@@ -172,5 +172,35 @@ LL ~         }
 LL +         let y = 1;
    |
 
-error: aborting due to 10 previous errors
+error: all if blocks contain the same code at the end
+  --> tests/ui/branches_sharing_code/shared_at_bottom.rs:290:5
+   |
+LL | /         0
+LL | |
+LL | |     };
+   | |_____^
+   |
+   = note: the end suggestion probably needs some adjustments to use the expression result correctly
+help: consider moving these statements after the if
+   |
+LL ~     }
+LL ~     0;
+   |
+
+error: all if blocks contain the same code at the end
+  --> tests/ui/branches_sharing_code/shared_at_bottom.rs:299:5
+   |
+LL | /         1
+LL | |
+LL | |     };
+   | |_____^
+   |
+   = note: the end suggestion probably needs some adjustments to use the expression result correctly
+help: consider moving these statements after the if
+   |
+LL ~     }
+LL ~     1;
+   |
+
+error: aborting due to 12 previous errors
 
diff --git a/src/tools/clippy/tests/ui/collapsible_else_if.fixed b/src/tools/clippy/tests/ui/collapsible_else_if.fixed
index 9f530ad670a..fed75244c6f 100644
--- a/src/tools/clippy/tests/ui/collapsible_else_if.fixed
+++ b/src/tools/clippy/tests/ui/collapsible_else_if.fixed
@@ -86,3 +86,21 @@ fn issue_7318() {
     }else if false {}
     //~^^^ collapsible_else_if
 }
+
+fn issue14799() {
+    use std::ops::ControlFlow;
+
+    let c: ControlFlow<_, ()> = ControlFlow::Break(Some(42));
+    if let ControlFlow::Break(Some(_)) = c {
+        todo!();
+    } else {
+        #[cfg(target_os = "freebsd")]
+        todo!();
+
+        if let ControlFlow::Break(None) = c {
+            todo!();
+        } else {
+            todo!();
+        }
+    }
+}
diff --git a/src/tools/clippy/tests/ui/collapsible_else_if.rs b/src/tools/clippy/tests/ui/collapsible_else_if.rs
index 2c646cd1d4d..e50e781fb69 100644
--- a/src/tools/clippy/tests/ui/collapsible_else_if.rs
+++ b/src/tools/clippy/tests/ui/collapsible_else_if.rs
@@ -102,3 +102,21 @@ fn issue_7318() {
     }
     //~^^^ collapsible_else_if
 }
+
+fn issue14799() {
+    use std::ops::ControlFlow;
+
+    let c: ControlFlow<_, ()> = ControlFlow::Break(Some(42));
+    if let ControlFlow::Break(Some(_)) = c {
+        todo!();
+    } else {
+        #[cfg(target_os = "freebsd")]
+        todo!();
+
+        if let ControlFlow::Break(None) = c {
+            todo!();
+        } else {
+            todo!();
+        }
+    }
+}
diff --git a/src/tools/clippy/tests/ui/collapsible_if.fixed b/src/tools/clippy/tests/ui/collapsible_if.fixed
index b553182a445..77bc791ea8e 100644
--- a/src/tools/clippy/tests/ui/collapsible_if.fixed
+++ b/src/tools/clippy/tests/ui/collapsible_if.fixed
@@ -154,3 +154,12 @@ fn issue14722() {
         None
     };
 }
+
+fn issue14799() {
+    if true {
+        #[cfg(target_os = "freebsd")]
+        todo!();
+
+        if true {}
+    };
+}
diff --git a/src/tools/clippy/tests/ui/collapsible_if.rs b/src/tools/clippy/tests/ui/collapsible_if.rs
index f5998457ca6..d30df157d5e 100644
--- a/src/tools/clippy/tests/ui/collapsible_if.rs
+++ b/src/tools/clippy/tests/ui/collapsible_if.rs
@@ -164,3 +164,12 @@ fn issue14722() {
         None
     };
 }
+
+fn issue14799() {
+    if true {
+        #[cfg(target_os = "freebsd")]
+        todo!();
+
+        if true {}
+    };
+}
diff --git a/src/tools/clippy/tests/ui/doc/needless_doctest_main.rs b/src/tools/clippy/tests/ui/doc/needless_doctest_main.rs
index 633a435ca5e..8c3217624d4 100644
--- a/src/tools/clippy/tests/ui/doc/needless_doctest_main.rs
+++ b/src/tools/clippy/tests/ui/doc/needless_doctest_main.rs
@@ -1,5 +1,3 @@
-//@ check-pass
-
 #![warn(clippy::needless_doctest_main)]
 //! issue 10491:
 //! ```rust,no_test
@@ -19,4 +17,114 @@
 /// ```
 fn foo() {}
 
+#[rustfmt::skip]
+/// Description
+/// ```rust
+/// fn main() {
+//~^ error: needless `fn main` in doctest
+///     let a = 0;
+/// }
+/// ```
+fn mulpipulpi() {}
+
+#[rustfmt::skip]
+/// With a `#[no_main]`
+/// ```rust
+/// #[no_main]
+/// fn a() {
+///     let _ = 0;
+/// }
+/// ```
+fn pulpimulpi() {}
+
+// Without a `#[no_main]` attribute
+/// ```rust
+/// fn a() {
+///     let _ = 0;
+/// }
+/// ```
+fn plumilupi() {}
+
+#[rustfmt::skip]
+/// Additional function, shouldn't trigger
+/// ```rust
+/// fn additional_function() {
+///     let _ = 0;
+///     // Thus `fn main` is actually relevant!
+/// }
+/// fn main() {
+///     let _ = 0;
+/// }
+/// ```
+fn mlupipupi() {}
+
+#[rustfmt::skip]
+/// Additional function AFTER main, shouldn't trigger
+/// ```rust
+/// fn main() {
+///     let _ = 0;
+/// }
+/// fn additional_function() {
+///     let _ = 0;
+///     // Thus `fn main` is actually relevant!
+/// }
+/// ```
+fn lumpimupli() {}
+
+#[rustfmt::skip]
+/// Ignore code block, should not lint at all
+/// ```rust, ignore
+/// fn main() {
+//~^ error: needless `fn main` in doctest
+///     // Hi!
+///     let _ = 0;
+/// }
+/// ```
+fn mpulpilumi() {}
+
+#[rustfmt::skip]
+/// Spaces in weird positions (including an \u{A0} after `main`)
+/// ```rust
+/// fn     main (){
+//~^ error: needless `fn main` in doctest
+///     let _ = 0;
+/// }
+/// ```
+fn plumpiplupi() {}
+
+/// 4 Functions, this should not lint because there are several function
+///
+/// ```rust
+/// fn a() {let _ = 0; }
+/// fn b() {let _ = 0; }
+/// fn main() { let _ = 0; }
+/// fn d() { let _ = 0; }
+/// ```
+fn pulmipulmip() {}
+
+/// 3 Functions but main is first, should also not lint
+///
+///```rust
+/// fn main() { let _ = 0; }
+/// fn b() { let _ = 0; }
+/// fn c() { let _ = 0; }
+/// ```
+fn pmuplimulip() {}
+
 fn main() {}
+
+fn issue8244() -> Result<(), ()> {
+    //! ```compile_fail
+    //! fn test() -> Result< {}
+    //! ```
+    Ok(())
+}
+
+/// # Examples
+///
+/// ```
+/// use std::error::Error;
+/// fn main() -> Result<(), Box<dyn Error>/* > */ {
+/// }
+/// ```
+fn issue15041() {}
diff --git a/src/tools/clippy/tests/ui/doc/needless_doctest_main.stderr b/src/tools/clippy/tests/ui/doc/needless_doctest_main.stderr
new file mode 100644
index 00000000000..dd5474ccb85
--- /dev/null
+++ b/src/tools/clippy/tests/ui/doc/needless_doctest_main.stderr
@@ -0,0 +1,36 @@
+error: needless `fn main` in doctest
+  --> tests/ui/doc/needless_doctest_main.rs:23:5
+   |
+LL |   /// fn main() {
+   |  _____^
+LL | |
+LL | | ///     let a = 0;
+LL | | /// }
+   | |_____^
+   |
+   = note: `-D clippy::needless-doctest-main` implied by `-D warnings`
+   = help: to override `-D warnings` add `#[allow(clippy::needless_doctest_main)]`
+
+error: needless `fn main` in doctest
+  --> tests/ui/doc/needless_doctest_main.rs:77:5
+   |
+LL |   /// fn main() {
+   |  _____^
+LL | |
+LL | | ///     // Hi!
+LL | | ///     let _ = 0;
+LL | | /// }
+   | |_____^
+
+error: needless `fn main` in doctest
+  --> tests/ui/doc/needless_doctest_main.rs:88:5
+   |
+LL |   /// fn     main (){
+   |  _____^
+LL | |
+LL | | ///     let _ = 0;
+LL | | /// }
+   | |_____^
+
+error: aborting due to 3 previous errors
+
diff --git a/src/tools/clippy/tests/ui/doc_broken_link.rs b/src/tools/clippy/tests/ui/doc_broken_link.rs
new file mode 100644
index 00000000000..7d9c0ef13b3
--- /dev/null
+++ b/src/tools/clippy/tests/ui/doc_broken_link.rs
@@ -0,0 +1,72 @@
+#![warn(clippy::doc_broken_link)]
+
+fn main() {}
+
+pub struct FakeType {}
+
+/// This might be considered a link false positive
+/// and should be ignored by this lint rule:
+/// Example of referencing some code with brackets [FakeType].
+pub fn doc_ignore_link_false_positive_1() {}
+
+/// This might be considered a link false positive
+/// and should be ignored by this lint rule:
+/// [`FakeType`]. Continue text after brackets,
+/// then (something in
+/// parenthesis).
+pub fn doc_ignore_link_false_positive_2() {}
+
+/// Test valid link, whole link single line.
+/// [doc valid link](https://test.fake/doc_valid_link)
+pub fn doc_valid_link() {}
+
+/// Test valid link, whole link single line but it has special chars such as brackets and
+/// parenthesis. [doc invalid link url invalid char](https://test.fake/doc_valid_link_url_invalid_char?foo[bar]=1&bar(foo)=2)
+pub fn doc_valid_link_url_invalid_char() {}
+
+/// Test valid link, text tag broken across multiple lines.
+/// [doc valid link broken
+/// text](https://test.fake/doc_valid_link_broken_text)
+pub fn doc_valid_link_broken_text() {}
+
+/// Test valid link, url tag broken across multiple lines, but
+/// the whole url part in a single line.
+/// [doc valid link broken url tag two lines first](https://test.fake/doc_valid_link_broken_url_tag_two_lines_first
+/// )
+pub fn doc_valid_link_broken_url_tag_two_lines_first() {}
+
+/// Test valid link, url tag broken across multiple lines, but
+/// the whole url part in a single line.
+/// [doc valid link broken url tag two lines second](
+/// https://test.fake/doc_valid_link_broken_url_tag_two_lines_second)
+pub fn doc_valid_link_broken_url_tag_two_lines_second() {}
+
+/// Test valid link, url tag broken across multiple lines, but
+/// the whole url part in a single line, but the closing pharentesis
+/// in a third line.
+/// [doc valid link broken url tag three lines](
+/// https://test.fake/doc_valid_link_broken_url_tag_three_lines
+/// )
+pub fn doc_valid_link_broken_url_tag_three_lines() {}
+
+/// Test invalid link, url part broken across multiple lines.
+/// [doc invalid link broken url scheme part](https://
+/// test.fake/doc_invalid_link_broken_url_scheme_part)
+//~^^ ERROR: possible broken doc link: broken across multiple lines
+pub fn doc_invalid_link_broken_url_scheme_part() {}
+
+/// Test invalid link, url part broken across multiple lines.
+/// [doc invalid link broken url host part](https://test
+/// .fake/doc_invalid_link_broken_url_host_part)
+//~^^ ERROR: possible broken doc link: broken across multiple lines
+pub fn doc_invalid_link_broken_url_host_part() {}
+
+/// Test invalid link, for multiple urls in the same block of comment.
+/// There is a [fist link - invalid](https://test
+/// .fake) then it continues
+//~^^ ERROR: possible broken doc link: broken across multiple lines
+/// with a [second link - valid](https://test.fake/doc_valid_link) and another [third link - invalid](https://test
+/// .fake). It ends with another
+//~^^ ERROR: possible broken doc link: broken across multiple lines
+/// line of comment.
+pub fn doc_multiple_invalid_link_broken_url() {}
diff --git a/src/tools/clippy/tests/ui/doc_broken_link.stderr b/src/tools/clippy/tests/ui/doc_broken_link.stderr
new file mode 100644
index 00000000000..179ed97635e
--- /dev/null
+++ b/src/tools/clippy/tests/ui/doc_broken_link.stderr
@@ -0,0 +1,29 @@
+error: possible broken doc link: broken across multiple lines
+  --> tests/ui/doc_broken_link.rs:53:5
+   |
+LL | /// [doc invalid link broken url scheme part](https://
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: `-D clippy::doc-broken-link` implied by `-D warnings`
+   = help: to override `-D warnings` add `#[allow(clippy::doc_broken_link)]`
+
+error: possible broken doc link: broken across multiple lines
+  --> tests/ui/doc_broken_link.rs:59:5
+   |
+LL | /// [doc invalid link broken url host part](https://test
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: possible broken doc link: broken across multiple lines
+  --> tests/ui/doc_broken_link.rs:65:16
+   |
+LL | /// There is a [fist link - invalid](https://test
+   |                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: possible broken doc link: broken across multiple lines
+  --> tests/ui/doc_broken_link.rs:68:80
+   |
+LL | /// with a [second link - valid](https://test.fake/doc_valid_link) and another [third link - invalid](https://test
+   |                                                                                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 4 previous errors
+
diff --git a/src/tools/clippy/tests/ui/empty_line_after/outer_attribute.1.fixed b/src/tools/clippy/tests/ui/empty_line_after/outer_attribute.1.fixed
index 36d80a2c95b..e36e3c2aea6 100644
--- a/src/tools/clippy/tests/ui/empty_line_after/outer_attribute.1.fixed
+++ b/src/tools/clippy/tests/ui/empty_line_after/outer_attribute.1.fixed
@@ -105,4 +105,13 @@ second line
 ")]
 pub struct Args;
 
+mod issue_14980 {
+    //~v empty_line_after_outer_attr
+    #[repr(align(536870912))]
+    enum Aligned {
+        Zero = 0,
+        One = 1,
+    }
+}
+
 fn main() {}
diff --git a/src/tools/clippy/tests/ui/empty_line_after/outer_attribute.2.fixed b/src/tools/clippy/tests/ui/empty_line_after/outer_attribute.2.fixed
index 0e8e4129e85..b0908fc7214 100644
--- a/src/tools/clippy/tests/ui/empty_line_after/outer_attribute.2.fixed
+++ b/src/tools/clippy/tests/ui/empty_line_after/outer_attribute.2.fixed
@@ -108,4 +108,13 @@ second line
 ")]
 pub struct Args;
 
+mod issue_14980 {
+    //~v empty_line_after_outer_attr
+    #[repr(align(536870912))]
+    enum Aligned {
+        Zero = 0,
+        One = 1,
+    }
+}
+
 fn main() {}
diff --git a/src/tools/clippy/tests/ui/empty_line_after/outer_attribute.rs b/src/tools/clippy/tests/ui/empty_line_after/outer_attribute.rs
index 1295088ac00..4ae113c68f5 100644
--- a/src/tools/clippy/tests/ui/empty_line_after/outer_attribute.rs
+++ b/src/tools/clippy/tests/ui/empty_line_after/outer_attribute.rs
@@ -116,4 +116,14 @@ second line
 ")]
 pub struct Args;
 
+mod issue_14980 {
+    //~v empty_line_after_outer_attr
+    #[repr(align(536870912))]
+
+    enum Aligned {
+        Zero = 0,
+        One = 1,
+    }
+}
+
 fn main() {}
diff --git a/src/tools/clippy/tests/ui/empty_line_after/outer_attribute.stderr b/src/tools/clippy/tests/ui/empty_line_after/outer_attribute.stderr
index 519ba6e6761..331bc7c8856 100644
--- a/src/tools/clippy/tests/ui/empty_line_after/outer_attribute.stderr
+++ b/src/tools/clippy/tests/ui/empty_line_after/outer_attribute.stderr
@@ -111,5 +111,16 @@ LL |   pub fn isolated_comment() {}
    |
    = help: if the empty lines are unintentional, remove them
 
-error: aborting due to 9 previous errors
+error: empty line after outer attribute
+  --> tests/ui/empty_line_after/outer_attribute.rs:121:5
+   |
+LL | /     #[repr(align(536870912))]
+LL | |
+   | |_^
+LL |       enum Aligned {
+   |       ------------ the attribute applies to this enum
+   |
+   = help: if the empty line is unintentional, remove it
+
+error: aborting due to 10 previous errors
 
diff --git a/src/tools/clippy/tests/ui/eta.fixed b/src/tools/clippy/tests/ui/eta.fixed
index 0ba631fda05..c93b83f53ec 100644
--- a/src/tools/clippy/tests/ui/eta.fixed
+++ b/src/tools/clippy/tests/ui/eta.fixed
@@ -543,3 +543,21 @@ mod issue_13073 {
         //~^ redundant_closure
     }
 }
+
+fn issue_14789() {
+    _ = Some(1u8).map(
+        #[expect(clippy::redundant_closure)]
+        |a| foo(a),
+    );
+
+    _ = Some("foo").map(
+        #[expect(clippy::redundant_closure_for_method_calls)]
+        |s| s.to_owned(),
+    );
+
+    let _: Vec<u8> = None.map_or_else(
+        #[expect(clippy::redundant_closure)]
+        || vec![],
+        std::convert::identity,
+    );
+}
diff --git a/src/tools/clippy/tests/ui/eta.rs b/src/tools/clippy/tests/ui/eta.rs
index 4d8b29d450c..273c8b21f4a 100644
--- a/src/tools/clippy/tests/ui/eta.rs
+++ b/src/tools/clippy/tests/ui/eta.rs
@@ -543,3 +543,21 @@ mod issue_13073 {
         //~^ redundant_closure
     }
 }
+
+fn issue_14789() {
+    _ = Some(1u8).map(
+        #[expect(clippy::redundant_closure)]
+        |a| foo(a),
+    );
+
+    _ = Some("foo").map(
+        #[expect(clippy::redundant_closure_for_method_calls)]
+        |s| s.to_owned(),
+    );
+
+    let _: Vec<u8> = None.map_or_else(
+        #[expect(clippy::redundant_closure)]
+        || vec![],
+        std::convert::identity,
+    );
+}
diff --git a/src/tools/clippy/tests/ui/exhaustive_items.fixed b/src/tools/clippy/tests/ui/exhaustive_items.fixed
index 79c74aeefbd..3b2f33dbd2c 100644
--- a/src/tools/clippy/tests/ui/exhaustive_items.fixed
+++ b/src/tools/clippy/tests/ui/exhaustive_items.fixed
@@ -1,3 +1,4 @@
+#![feature(default_field_values)]
 #![deny(clippy::exhaustive_enums, clippy::exhaustive_structs)]
 #![allow(unused)]
 
@@ -90,3 +91,9 @@ pub mod structs {
         pub bar: String,
     }
 }
+
+pub mod issue14992 {
+    pub struct A {
+        pub a: isize = 42,
+    }
+}
diff --git a/src/tools/clippy/tests/ui/exhaustive_items.rs b/src/tools/clippy/tests/ui/exhaustive_items.rs
index 4e851f4c492..b0a6a717076 100644
--- a/src/tools/clippy/tests/ui/exhaustive_items.rs
+++ b/src/tools/clippy/tests/ui/exhaustive_items.rs
@@ -1,3 +1,4 @@
+#![feature(default_field_values)]
 #![deny(clippy::exhaustive_enums, clippy::exhaustive_structs)]
 #![allow(unused)]
 
@@ -87,3 +88,9 @@ pub mod structs {
         pub bar: String,
     }
 }
+
+pub mod issue14992 {
+    pub struct A {
+        pub a: isize = 42,
+    }
+}
diff --git a/src/tools/clippy/tests/ui/exhaustive_items.stderr b/src/tools/clippy/tests/ui/exhaustive_items.stderr
index c92c8a9efaa..55928fa458d 100644
--- a/src/tools/clippy/tests/ui/exhaustive_items.stderr
+++ b/src/tools/clippy/tests/ui/exhaustive_items.stderr
@@ -1,5 +1,5 @@
 error: exported enums should not be exhaustive
-  --> tests/ui/exhaustive_items.rs:9:5
+  --> tests/ui/exhaustive_items.rs:10:5
    |
 LL | /     pub enum Exhaustive {
 LL | |
@@ -11,7 +11,7 @@ LL | |     }
    | |_____^
    |
 note: the lint level is defined here
-  --> tests/ui/exhaustive_items.rs:1:9
+  --> tests/ui/exhaustive_items.rs:2:9
    |
 LL | #![deny(clippy::exhaustive_enums, clippy::exhaustive_structs)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^
@@ -22,7 +22,7 @@ LL ~     pub enum Exhaustive {
    |
 
 error: exported enums should not be exhaustive
-  --> tests/ui/exhaustive_items.rs:19:5
+  --> tests/ui/exhaustive_items.rs:20:5
    |
 LL | /     pub enum ExhaustiveWithAttrs {
 LL | |
@@ -40,7 +40,7 @@ LL ~     pub enum ExhaustiveWithAttrs {
    |
 
 error: exported structs should not be exhaustive
-  --> tests/ui/exhaustive_items.rs:55:5
+  --> tests/ui/exhaustive_items.rs:56:5
    |
 LL | /     pub struct Exhaustive {
 LL | |
@@ -50,7 +50,7 @@ LL | |     }
    | |_____^
    |
 note: the lint level is defined here
-  --> tests/ui/exhaustive_items.rs:1:35
+  --> tests/ui/exhaustive_items.rs:2:35
    |
 LL | #![deny(clippy::exhaustive_enums, clippy::exhaustive_structs)]
    |                                   ^^^^^^^^^^^^^^^^^^^^^^^^^^
diff --git a/src/tools/clippy/tests/ui/identity_op.fixed b/src/tools/clippy/tests/ui/identity_op.fixed
index a1b55602998..4e14e1a5e33 100644
--- a/src/tools/clippy/tests/ui/identity_op.fixed
+++ b/src/tools/clippy/tests/ui/identity_op.fixed
@@ -312,3 +312,49 @@ fn issue_13470() {
     let _: u64 = 1u64 + ((x as i32 + y as i32) as u64);
     //~^ identity_op
 }
+
+fn issue_14932() {
+    let _ = 0usize + &Default::default(); // no error
+
+    0usize + &Default::default(); // no error
+
+    <usize as Default>::default();
+    //~^ identity_op
+
+    let _ = usize::default();
+    //~^ identity_op
+
+    let _n: usize = Default::default();
+    //~^ identity_op
+}
+
+// Expr's type can be inferred by the function's return type
+fn issue_14932_2() -> usize {
+    Default::default()
+    //~^ identity_op
+}
+
+trait Def {
+    fn def() -> Self;
+}
+
+impl Def for usize {
+    fn def() -> Self {
+        0
+    }
+}
+
+fn issue_14932_3() {
+    let _ = 0usize + &Def::def(); // no error
+
+    0usize + &Def::def(); // no error
+
+    <usize as Def>::def();
+    //~^ identity_op
+
+    let _ = usize::def();
+    //~^ identity_op
+
+    let _n: usize = Def::def();
+    //~^ identity_op
+}
diff --git a/src/tools/clippy/tests/ui/identity_op.rs b/src/tools/clippy/tests/ui/identity_op.rs
index f603e1078e4..ebbef5723ff 100644
--- a/src/tools/clippy/tests/ui/identity_op.rs
+++ b/src/tools/clippy/tests/ui/identity_op.rs
@@ -312,3 +312,49 @@ fn issue_13470() {
     let _: u64 = 1u64 + ((x as i32 + y as i32) as u64 + 0u64);
     //~^ identity_op
 }
+
+fn issue_14932() {
+    let _ = 0usize + &Default::default(); // no error
+
+    0usize + &Default::default(); // no error
+
+    0usize + &<usize as Default>::default();
+    //~^ identity_op
+
+    let _ = 0usize + &usize::default();
+    //~^ identity_op
+
+    let _n: usize = 0usize + &Default::default();
+    //~^ identity_op
+}
+
+// Expr's type can be inferred by the function's return type
+fn issue_14932_2() -> usize {
+    0usize + &Default::default()
+    //~^ identity_op
+}
+
+trait Def {
+    fn def() -> Self;
+}
+
+impl Def for usize {
+    fn def() -> Self {
+        0
+    }
+}
+
+fn issue_14932_3() {
+    let _ = 0usize + &Def::def(); // no error
+
+    0usize + &Def::def(); // no error
+
+    0usize + &<usize as Def>::def();
+    //~^ identity_op
+
+    let _ = 0usize + &usize::def();
+    //~^ identity_op
+
+    let _n: usize = 0usize + &Def::def();
+    //~^ identity_op
+}
diff --git a/src/tools/clippy/tests/ui/identity_op.stderr b/src/tools/clippy/tests/ui/identity_op.stderr
index 8f9c2b603c4..24fa5db08ce 100644
--- a/src/tools/clippy/tests/ui/identity_op.stderr
+++ b/src/tools/clippy/tests/ui/identity_op.stderr
@@ -379,5 +379,47 @@ error: this operation has no effect
 LL |     let _: u64 = 1u64 + ((x as i32 + y as i32) as u64 + 0u64);
    |                         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider reducing it to: `((x as i32 + y as i32) as u64)`
 
-error: aborting due to 63 previous errors
+error: this operation has no effect
+  --> tests/ui/identity_op.rs:321:5
+   |
+LL |     0usize + &<usize as Default>::default();
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider reducing it to: `<usize as Default>::default()`
+
+error: this operation has no effect
+  --> tests/ui/identity_op.rs:324:13
+   |
+LL |     let _ = 0usize + &usize::default();
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider reducing it to: `usize::default()`
+
+error: this operation has no effect
+  --> tests/ui/identity_op.rs:327:21
+   |
+LL |     let _n: usize = 0usize + &Default::default();
+   |                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider reducing it to: `Default::default()`
+
+error: this operation has no effect
+  --> tests/ui/identity_op.rs:333:5
+   |
+LL |     0usize + &Default::default()
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider reducing it to: `Default::default()`
+
+error: this operation has no effect
+  --> tests/ui/identity_op.rs:352:5
+   |
+LL |     0usize + &<usize as Def>::def();
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider reducing it to: `<usize as Def>::def()`
+
+error: this operation has no effect
+  --> tests/ui/identity_op.rs:355:13
+   |
+LL |     let _ = 0usize + &usize::def();
+   |             ^^^^^^^^^^^^^^^^^^^^^^ help: consider reducing it to: `usize::def()`
+
+error: this operation has no effect
+  --> tests/ui/identity_op.rs:358:21
+   |
+LL |     let _n: usize = 0usize + &Def::def();
+   |                     ^^^^^^^^^^^^^^^^^^^^ help: consider reducing it to: `Def::def()`
+
+error: aborting due to 70 previous errors
 
diff --git a/src/tools/clippy/tests/ui/infinite_iter.rs b/src/tools/clippy/tests/ui/infinite_iter.rs
index 002a791a657..701a86534ba 100644
--- a/src/tools/clippy/tests/ui/infinite_iter.rs
+++ b/src/tools/clippy/tests/ui/infinite_iter.rs
@@ -38,7 +38,7 @@ fn infinite_iters() {
     //~^ infinite_iter
 
     // infinite iter
-    (0_u64..).filter(|x| x % 2 == 0).last();
+    (0_u64..).filter(|x| x.is_multiple_of(2)).last();
     //~^ infinite_iter
 
     // not an infinite, because ranges are double-ended
diff --git a/src/tools/clippy/tests/ui/infinite_iter.stderr b/src/tools/clippy/tests/ui/infinite_iter.stderr
index 47133a2ea62..b9e7c008f93 100644
--- a/src/tools/clippy/tests/ui/infinite_iter.stderr
+++ b/src/tools/clippy/tests/ui/infinite_iter.stderr
@@ -42,8 +42,8 @@ LL |     (0_usize..).flat_map(|x| 0..x).product::<usize>();
 error: infinite iteration detected
   --> tests/ui/infinite_iter.rs:41:5
    |
-LL |     (0_u64..).filter(|x| x % 2 == 0).last();
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL |     (0_u64..).filter(|x| x.is_multiple_of(2)).last();
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: possible infinite iteration detected
   --> tests/ui/infinite_iter.rs:53:5
diff --git a/src/tools/clippy/tests/ui/iter_kv_map.fixed b/src/tools/clippy/tests/ui/iter_kv_map.fixed
index 874f749b33d..b18dda35887 100644
--- a/src/tools/clippy/tests/ui/iter_kv_map.fixed
+++ b/src/tools/clippy/tests/ui/iter_kv_map.fixed
@@ -30,15 +30,19 @@ fn main() {
 
     let _ = map.clone().values().collect::<Vec<_>>();
     //~^ iter_kv_map
-    let _ = map.keys().filter(|x| *x % 2 == 0).count();
+    let _ = map.keys().filter(|x| x.is_multiple_of(2)).count();
     //~^ iter_kv_map
 
     // Don't lint
-    let _ = map.iter().filter(|(_, val)| *val % 2 == 0).map(|(key, _)| key).count();
+    let _ = map
+        .iter()
+        .filter(|(_, val)| val.is_multiple_of(2))
+        .map(|(key, _)| key)
+        .count();
     let _ = map.iter().map(get_key).collect::<Vec<_>>();
 
     // Linting the following could be an improvement to the lint
-    // map.iter().filter_map(|(_, val)| (val % 2 == 0).then(val * 17)).count();
+    // map.iter().filter_map(|(_, val)| (val.is_multiple_of(2)).then(val * 17)).count();
 
     // Lint
     let _ = map.keys().map(|key| key * 9).count();
@@ -84,15 +88,19 @@ fn main() {
 
     let _ = map.clone().values().collect::<Vec<_>>();
     //~^ iter_kv_map
-    let _ = map.keys().filter(|x| *x % 2 == 0).count();
+    let _ = map.keys().filter(|x| x.is_multiple_of(2)).count();
     //~^ iter_kv_map
 
     // Don't lint
-    let _ = map.iter().filter(|(_, val)| *val % 2 == 0).map(|(key, _)| key).count();
+    let _ = map
+        .iter()
+        .filter(|(_, val)| val.is_multiple_of(2))
+        .map(|(key, _)| key)
+        .count();
     let _ = map.iter().map(get_key).collect::<Vec<_>>();
 
     // Linting the following could be an improvement to the lint
-    // map.iter().filter_map(|(_, val)| (val % 2 == 0).then(val * 17)).count();
+    // map.iter().filter_map(|(_, val)| (val.is_multiple_of(2)).then(val * 17)).count();
 
     // Lint
     let _ = map.keys().map(|key| key * 9).count();
diff --git a/src/tools/clippy/tests/ui/iter_kv_map.rs b/src/tools/clippy/tests/ui/iter_kv_map.rs
index f570e3c32cb..729e4e8a266 100644
--- a/src/tools/clippy/tests/ui/iter_kv_map.rs
+++ b/src/tools/clippy/tests/ui/iter_kv_map.rs
@@ -30,15 +30,19 @@ fn main() {
 
     let _ = map.clone().iter().map(|(_, val)| val).collect::<Vec<_>>();
     //~^ iter_kv_map
-    let _ = map.iter().map(|(key, _)| key).filter(|x| *x % 2 == 0).count();
+    let _ = map.iter().map(|(key, _)| key).filter(|x| x.is_multiple_of(2)).count();
     //~^ iter_kv_map
 
     // Don't lint
-    let _ = map.iter().filter(|(_, val)| *val % 2 == 0).map(|(key, _)| key).count();
+    let _ = map
+        .iter()
+        .filter(|(_, val)| val.is_multiple_of(2))
+        .map(|(key, _)| key)
+        .count();
     let _ = map.iter().map(get_key).collect::<Vec<_>>();
 
     // Linting the following could be an improvement to the lint
-    // map.iter().filter_map(|(_, val)| (val % 2 == 0).then(val * 17)).count();
+    // map.iter().filter_map(|(_, val)| (val.is_multiple_of(2)).then(val * 17)).count();
 
     // Lint
     let _ = map.iter().map(|(key, _value)| key * 9).count();
@@ -86,15 +90,19 @@ fn main() {
 
     let _ = map.clone().iter().map(|(_, val)| val).collect::<Vec<_>>();
     //~^ iter_kv_map
-    let _ = map.iter().map(|(key, _)| key).filter(|x| *x % 2 == 0).count();
+    let _ = map.iter().map(|(key, _)| key).filter(|x| x.is_multiple_of(2)).count();
     //~^ iter_kv_map
 
     // Don't lint
-    let _ = map.iter().filter(|(_, val)| *val % 2 == 0).map(|(key, _)| key).count();
+    let _ = map
+        .iter()
+        .filter(|(_, val)| val.is_multiple_of(2))
+        .map(|(key, _)| key)
+        .count();
     let _ = map.iter().map(get_key).collect::<Vec<_>>();
 
     // Linting the following could be an improvement to the lint
-    // map.iter().filter_map(|(_, val)| (val % 2 == 0).then(val * 17)).count();
+    // map.iter().filter_map(|(_, val)| (val.is_multiple_of(2)).then(val * 17)).count();
 
     // Lint
     let _ = map.iter().map(|(key, _value)| key * 9).count();
diff --git a/src/tools/clippy/tests/ui/iter_kv_map.stderr b/src/tools/clippy/tests/ui/iter_kv_map.stderr
index 31ee76c25b7..8f73541f503 100644
--- a/src/tools/clippy/tests/ui/iter_kv_map.stderr
+++ b/src/tools/clippy/tests/ui/iter_kv_map.stderr
@@ -52,29 +52,29 @@ LL |     let _ = map.clone().iter().map(|(_, val)| val).collect::<Vec<_>>();
 error: iterating on a map's keys
   --> tests/ui/iter_kv_map.rs:33:13
    |
-LL |     let _ = map.iter().map(|(key, _)| key).filter(|x| *x % 2 == 0).count();
+LL |     let _ = map.iter().map(|(key, _)| key).filter(|x| x.is_multiple_of(2)).count();
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.keys()`
 
 error: iterating on a map's keys
-  --> tests/ui/iter_kv_map.rs:44:13
+  --> tests/ui/iter_kv_map.rs:48:13
    |
 LL |     let _ = map.iter().map(|(key, _value)| key * 9).count();
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.keys().map(|key| key * 9)`
 
 error: iterating on a map's values
-  --> tests/ui/iter_kv_map.rs:46:13
+  --> tests/ui/iter_kv_map.rs:50:13
    |
 LL |     let _ = map.iter().map(|(_key, value)| value * 17).count();
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.values().map(|value| value * 17)`
 
 error: iterating on a map's values
-  --> tests/ui/iter_kv_map.rs:50:13
+  --> tests/ui/iter_kv_map.rs:54:13
    |
 LL |     let _ = map.clone().into_iter().map(|(_, ref val)| ref_acceptor(val)).count();
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.clone().into_values().map(|ref val| ref_acceptor(val))`
 
 error: iterating on a map's values
-  --> tests/ui/iter_kv_map.rs:54:13
+  --> tests/ui/iter_kv_map.rs:58:13
    |
 LL |       let _ = map
    |  _____________^
@@ -97,85 +97,85 @@ LL +         })
    |
 
 error: iterating on a map's values
-  --> tests/ui/iter_kv_map.rs:65:13
+  --> tests/ui/iter_kv_map.rs:69:13
    |
 LL |     let _ = map.clone().into_iter().map(|(_, mut val)| val).count();
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.clone().into_values()`
 
 error: iterating on a map's keys
-  --> tests/ui/iter_kv_map.rs:70:13
+  --> tests/ui/iter_kv_map.rs:74:13
    |
 LL |     let _ = map.iter().map(|(key, _)| key).collect::<Vec<_>>();
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.keys()`
 
 error: iterating on a map's values
-  --> tests/ui/iter_kv_map.rs:72:13
+  --> tests/ui/iter_kv_map.rs:76:13
    |
 LL |     let _ = map.iter().map(|(_, value)| value).collect::<Vec<_>>();
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.values()`
 
 error: iterating on a map's values
-  --> tests/ui/iter_kv_map.rs:74:13
+  --> tests/ui/iter_kv_map.rs:78:13
    |
 LL |     let _ = map.iter().map(|(_, v)| v + 2).collect::<Vec<_>>();
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.values().map(|v| v + 2)`
 
 error: iterating on a map's keys
-  --> tests/ui/iter_kv_map.rs:77:13
+  --> tests/ui/iter_kv_map.rs:81:13
    |
 LL |     let _ = map.clone().into_iter().map(|(key, _)| key).collect::<Vec<_>>();
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.clone().into_keys()`
 
 error: iterating on a map's keys
-  --> tests/ui/iter_kv_map.rs:79:13
+  --> tests/ui/iter_kv_map.rs:83:13
    |
 LL |     let _ = map.clone().into_iter().map(|(key, _)| key + 2).collect::<Vec<_>>();
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.clone().into_keys().map(|key| key + 2)`
 
 error: iterating on a map's values
-  --> tests/ui/iter_kv_map.rs:82:13
+  --> tests/ui/iter_kv_map.rs:86:13
    |
 LL |     let _ = map.clone().into_iter().map(|(_, val)| val).collect::<Vec<_>>();
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.clone().into_values()`
 
 error: iterating on a map's values
-  --> tests/ui/iter_kv_map.rs:84:13
+  --> tests/ui/iter_kv_map.rs:88:13
    |
 LL |     let _ = map.clone().into_iter().map(|(_, val)| val + 2).collect::<Vec<_>>();
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.clone().into_values().map(|val| val + 2)`
 
 error: iterating on a map's values
-  --> tests/ui/iter_kv_map.rs:87:13
+  --> tests/ui/iter_kv_map.rs:91:13
    |
 LL |     let _ = map.clone().iter().map(|(_, val)| val).collect::<Vec<_>>();
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.clone().values()`
 
 error: iterating on a map's keys
-  --> tests/ui/iter_kv_map.rs:89:13
+  --> tests/ui/iter_kv_map.rs:93:13
    |
-LL |     let _ = map.iter().map(|(key, _)| key).filter(|x| *x % 2 == 0).count();
+LL |     let _ = map.iter().map(|(key, _)| key).filter(|x| x.is_multiple_of(2)).count();
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.keys()`
 
 error: iterating on a map's keys
-  --> tests/ui/iter_kv_map.rs:100:13
+  --> tests/ui/iter_kv_map.rs:108:13
    |
 LL |     let _ = map.iter().map(|(key, _value)| key * 9).count();
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.keys().map(|key| key * 9)`
 
 error: iterating on a map's values
-  --> tests/ui/iter_kv_map.rs:102:13
+  --> tests/ui/iter_kv_map.rs:110:13
    |
 LL |     let _ = map.iter().map(|(_key, value)| value * 17).count();
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.values().map(|value| value * 17)`
 
 error: iterating on a map's values
-  --> tests/ui/iter_kv_map.rs:106:13
+  --> tests/ui/iter_kv_map.rs:114:13
    |
 LL |     let _ = map.clone().into_iter().map(|(_, ref val)| ref_acceptor(val)).count();
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.clone().into_values().map(|ref val| ref_acceptor(val))`
 
 error: iterating on a map's values
-  --> tests/ui/iter_kv_map.rs:110:13
+  --> tests/ui/iter_kv_map.rs:118:13
    |
 LL |       let _ = map
    |  _____________^
@@ -198,73 +198,73 @@ LL +         })
    |
 
 error: iterating on a map's values
-  --> tests/ui/iter_kv_map.rs:121:13
+  --> tests/ui/iter_kv_map.rs:129:13
    |
 LL |     let _ = map.clone().into_iter().map(|(_, mut val)| val).count();
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.clone().into_values()`
 
 error: iterating on a map's keys
-  --> tests/ui/iter_kv_map.rs:137:13
+  --> tests/ui/iter_kv_map.rs:145:13
    |
 LL |     let _ = map.iter().map(|(key, _)| key).collect::<Vec<_>>();
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.keys()`
 
 error: iterating on a map's values
-  --> tests/ui/iter_kv_map.rs:140:13
+  --> tests/ui/iter_kv_map.rs:148:13
    |
 LL |     let _ = map.iter().map(|(_, value)| value).collect::<Vec<_>>();
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.values()`
 
 error: iterating on a map's values
-  --> tests/ui/iter_kv_map.rs:143:13
+  --> tests/ui/iter_kv_map.rs:151:13
    |
 LL |     let _ = map.iter().map(|(_, v)| v + 2).collect::<Vec<_>>();
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.values().map(|v| v + 2)`
 
 error: iterating on a map's keys
-  --> tests/ui/iter_kv_map.rs:152:13
+  --> tests/ui/iter_kv_map.rs:160:13
    |
 LL |     let _ = map.clone().into_iter().map(|(key, _)| key).collect::<Vec<_>>();
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.clone().into_keys()`
 
 error: iterating on a map's keys
-  --> tests/ui/iter_kv_map.rs:155:13
+  --> tests/ui/iter_kv_map.rs:163:13
    |
 LL |     let _ = map.clone().into_iter().map(|(key, _)| key + 2).collect::<Vec<_>>();
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.clone().into_keys().map(|key| key + 2)`
 
 error: iterating on a map's values
-  --> tests/ui/iter_kv_map.rs:158:13
+  --> tests/ui/iter_kv_map.rs:166:13
    |
 LL |     let _ = map.clone().into_iter().map(|(_, val)| val).collect::<Vec<_>>();
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.clone().into_values()`
 
 error: iterating on a map's values
-  --> tests/ui/iter_kv_map.rs:161:13
+  --> tests/ui/iter_kv_map.rs:169:13
    |
 LL |     let _ = map.clone().into_iter().map(|(_, val)| val + 2).collect::<Vec<_>>();
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.clone().into_values().map(|val| val + 2)`
 
 error: iterating on a map's keys
-  --> tests/ui/iter_kv_map.rs:164:13
+  --> tests/ui/iter_kv_map.rs:172:13
    |
 LL |     let _ = map.iter().map(|(key, _)| key).collect::<Vec<_>>();
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.keys()`
 
 error: iterating on a map's values
-  --> tests/ui/iter_kv_map.rs:167:13
+  --> tests/ui/iter_kv_map.rs:175:13
    |
 LL |     let _ = map.iter().map(|(_, value)| value).collect::<Vec<_>>();
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.values()`
 
 error: iterating on a map's values
-  --> tests/ui/iter_kv_map.rs:170:13
+  --> tests/ui/iter_kv_map.rs:178:13
    |
 LL |     let _ = map.iter().map(|(_, v)| v + 2).collect::<Vec<_>>();
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.values().map(|v| v + 2)`
 
 error: iterating on a map's values
-  --> tests/ui/iter_kv_map.rs:185:13
+  --> tests/ui/iter_kv_map.rs:193:13
    |
 LL |     let _ = map.as_ref().iter().map(|(_, v)| v).copied().collect::<Vec<_>>();
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.as_ref().values()`
diff --git a/src/tools/clippy/tests/ui/let_unit.fixed b/src/tools/clippy/tests/ui/let_unit.fixed
index 5e7a2ad37a8..304eacecd94 100644
--- a/src/tools/clippy/tests/ui/let_unit.fixed
+++ b/src/tools/clippy/tests/ui/let_unit.fixed
@@ -61,7 +61,7 @@ fn multiline_sugg() {
         //~^ let_unit_value
         .into_iter()
         .map(|i| i * 2)
-        .filter(|i| i % 2 == 0)
+        .filter(|i| i.is_multiple_of(2))
         .map(|_| ())
         .next()
         .unwrap();
diff --git a/src/tools/clippy/tests/ui/let_unit.rs b/src/tools/clippy/tests/ui/let_unit.rs
index 7b06f694012..a02cb346ff9 100644
--- a/src/tools/clippy/tests/ui/let_unit.rs
+++ b/src/tools/clippy/tests/ui/let_unit.rs
@@ -61,7 +61,7 @@ fn multiline_sugg() {
         //~^ let_unit_value
         .into_iter()
         .map(|i| i * 2)
-        .filter(|i| i % 2 == 0)
+        .filter(|i| i.is_multiple_of(2))
         .map(|_| ())
         .next()
         .unwrap();
diff --git a/src/tools/clippy/tests/ui/let_unit.stderr b/src/tools/clippy/tests/ui/let_unit.stderr
index d7d01d304ca..d743110c99d 100644
--- a/src/tools/clippy/tests/ui/let_unit.stderr
+++ b/src/tools/clippy/tests/ui/let_unit.stderr
@@ -25,7 +25,7 @@ LL ~     v
 LL +
 LL +         .into_iter()
 LL +         .map(|i| i * 2)
-LL +         .filter(|i| i % 2 == 0)
+LL +         .filter(|i| i.is_multiple_of(2))
 LL +         .map(|_| ())
 LL +         .next()
 LL +         .unwrap();
diff --git a/src/tools/clippy/tests/ui/manual_contains.fixed b/src/tools/clippy/tests/ui/manual_contains.fixed
index d26c948a781..18171f0b2b4 100644
--- a/src/tools/clippy/tests/ui/manual_contains.fixed
+++ b/src/tools/clippy/tests/ui/manual_contains.fixed
@@ -58,7 +58,7 @@ fn should_not_lint() {
 
     let vec: Vec<u32> = vec![1, 2, 3, 4, 5, 6];
     let values = &vec[..];
-    let _ = values.iter().any(|&v| v % 2 == 0);
+    let _ = values.iter().any(|&v| v.is_multiple_of(2));
     let _ = values.iter().any(|&v| v * 2 == 6);
     let _ = values.iter().any(|&v| v == v);
     let _ = values.iter().any(|&v| 4 == 4);
diff --git a/src/tools/clippy/tests/ui/manual_contains.rs b/src/tools/clippy/tests/ui/manual_contains.rs
index fe67d2ee5d5..918f4d6b8dd 100644
--- a/src/tools/clippy/tests/ui/manual_contains.rs
+++ b/src/tools/clippy/tests/ui/manual_contains.rs
@@ -58,7 +58,7 @@ fn should_not_lint() {
 
     let vec: Vec<u32> = vec![1, 2, 3, 4, 5, 6];
     let values = &vec[..];
-    let _ = values.iter().any(|&v| v % 2 == 0);
+    let _ = values.iter().any(|&v| v.is_multiple_of(2));
     let _ = values.iter().any(|&v| v * 2 == 6);
     let _ = values.iter().any(|&v| v == v);
     let _ = values.iter().any(|&v| 4 == 4);
diff --git a/src/tools/clippy/tests/ui/manual_find_fixable.fixed b/src/tools/clippy/tests/ui/manual_find_fixable.fixed
index 01b3ebacbeb..c69b0cb11e3 100644
--- a/src/tools/clippy/tests/ui/manual_find_fixable.fixed
+++ b/src/tools/clippy/tests/ui/manual_find_fixable.fixed
@@ -11,7 +11,7 @@ fn lookup(n: u32) -> Option<u32> {
 }
 
 fn with_pat(arr: Vec<(u32, u32)>) -> Option<u32> {
-    arr.into_iter().map(|(a, _)| a).find(|&a| a % 2 == 0)
+    arr.into_iter().map(|(a, _)| a).find(|&a| a.is_multiple_of(2))
 }
 
 struct Data {
@@ -63,7 +63,7 @@ fn with_side_effects(arr: Vec<u32>) -> Option<u32> {
 
 fn with_else(arr: Vec<u32>) -> Option<u32> {
     for el in arr {
-        if el % 2 == 0 {
+        if el.is_multiple_of(2) {
             return Some(el);
         } else {
             println!("{}", el);
diff --git a/src/tools/clippy/tests/ui/manual_find_fixable.rs b/src/tools/clippy/tests/ui/manual_find_fixable.rs
index ce62a4beba1..db7092f020c 100644
--- a/src/tools/clippy/tests/ui/manual_find_fixable.rs
+++ b/src/tools/clippy/tests/ui/manual_find_fixable.rs
@@ -19,7 +19,7 @@ fn lookup(n: u32) -> Option<u32> {
 fn with_pat(arr: Vec<(u32, u32)>) -> Option<u32> {
     for (a, _) in arr {
         //~^ manual_find
-        if a % 2 == 0 {
+        if a.is_multiple_of(2) {
             return Some(a);
         }
     }
@@ -111,7 +111,7 @@ fn with_side_effects(arr: Vec<u32>) -> Option<u32> {
 
 fn with_else(arr: Vec<u32>) -> Option<u32> {
     for el in arr {
-        if el % 2 == 0 {
+        if el.is_multiple_of(2) {
             return Some(el);
         } else {
             println!("{}", el);
diff --git a/src/tools/clippy/tests/ui/manual_find_fixable.stderr b/src/tools/clippy/tests/ui/manual_find_fixable.stderr
index 020635d90bb..0c05c0d2c44 100644
--- a/src/tools/clippy/tests/ui/manual_find_fixable.stderr
+++ b/src/tools/clippy/tests/ui/manual_find_fixable.stderr
@@ -17,11 +17,11 @@ error: manual implementation of `Iterator::find`
    |
 LL | /     for (a, _) in arr {
 LL | |
-LL | |         if a % 2 == 0 {
+LL | |         if a.is_multiple_of(2) {
 LL | |             return Some(a);
 ...  |
 LL | |     None
-   | |________^ help: replace with an iterator: `arr.into_iter().map(|(a, _)| a).find(|&a| a % 2 == 0)`
+   | |________^ help: replace with an iterator: `arr.into_iter().map(|(a, _)| a).find(|&a| a.is_multiple_of(2))`
 
 error: manual implementation of `Iterator::find`
   --> tests/ui/manual_find_fixable.rs:34:5
diff --git a/src/tools/clippy/tests/ui/manual_is_multiple_of.fixed b/src/tools/clippy/tests/ui/manual_is_multiple_of.fixed
new file mode 100644
index 00000000000..6735b99f298
--- /dev/null
+++ b/src/tools/clippy/tests/ui/manual_is_multiple_of.fixed
@@ -0,0 +1,25 @@
+//@aux-build: proc_macros.rs
+#![warn(clippy::manual_is_multiple_of)]
+
+fn main() {}
+
+#[clippy::msrv = "1.87"]
+fn f(a: u64, b: u64) {
+    let _ = a.is_multiple_of(b); //~ manual_is_multiple_of
+    let _ = (a + 1).is_multiple_of(b + 1); //~ manual_is_multiple_of
+    let _ = !a.is_multiple_of(b); //~ manual_is_multiple_of
+    let _ = !(a + 1).is_multiple_of(b + 1); //~ manual_is_multiple_of
+
+    let _ = !a.is_multiple_of(b); //~ manual_is_multiple_of
+    let _ = !a.is_multiple_of(b); //~ manual_is_multiple_of
+
+    proc_macros::external! {
+        let a: u64 = 23424;
+        let _ = a % 4096 == 0;
+    }
+}
+
+#[clippy::msrv = "1.86"]
+fn g(a: u64, b: u64) {
+    let _ = a % b == 0;
+}
diff --git a/src/tools/clippy/tests/ui/manual_is_multiple_of.rs b/src/tools/clippy/tests/ui/manual_is_multiple_of.rs
new file mode 100644
index 00000000000..00b638e4fd9
--- /dev/null
+++ b/src/tools/clippy/tests/ui/manual_is_multiple_of.rs
@@ -0,0 +1,25 @@
+//@aux-build: proc_macros.rs
+#![warn(clippy::manual_is_multiple_of)]
+
+fn main() {}
+
+#[clippy::msrv = "1.87"]
+fn f(a: u64, b: u64) {
+    let _ = a % b == 0; //~ manual_is_multiple_of
+    let _ = (a + 1) % (b + 1) == 0; //~ manual_is_multiple_of
+    let _ = a % b != 0; //~ manual_is_multiple_of
+    let _ = (a + 1) % (b + 1) != 0; //~ manual_is_multiple_of
+
+    let _ = a % b > 0; //~ manual_is_multiple_of
+    let _ = 0 < a % b; //~ manual_is_multiple_of
+
+    proc_macros::external! {
+        let a: u64 = 23424;
+        let _ = a % 4096 == 0;
+    }
+}
+
+#[clippy::msrv = "1.86"]
+fn g(a: u64, b: u64) {
+    let _ = a % b == 0;
+}
diff --git a/src/tools/clippy/tests/ui/manual_is_multiple_of.stderr b/src/tools/clippy/tests/ui/manual_is_multiple_of.stderr
new file mode 100644
index 00000000000..0b1ae70c2a7
--- /dev/null
+++ b/src/tools/clippy/tests/ui/manual_is_multiple_of.stderr
@@ -0,0 +1,41 @@
+error: manual implementation of `.is_multiple_of()`
+  --> tests/ui/manual_is_multiple_of.rs:8:13
+   |
+LL |     let _ = a % b == 0;
+   |             ^^^^^^^^^^ help: replace with: `a.is_multiple_of(b)`
+   |
+   = note: `-D clippy::manual-is-multiple-of` implied by `-D warnings`
+   = help: to override `-D warnings` add `#[allow(clippy::manual_is_multiple_of)]`
+
+error: manual implementation of `.is_multiple_of()`
+  --> tests/ui/manual_is_multiple_of.rs:9:13
+   |
+LL |     let _ = (a + 1) % (b + 1) == 0;
+   |             ^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `(a + 1).is_multiple_of(b + 1)`
+
+error: manual implementation of `.is_multiple_of()`
+  --> tests/ui/manual_is_multiple_of.rs:10:13
+   |
+LL |     let _ = a % b != 0;
+   |             ^^^^^^^^^^ help: replace with: `!a.is_multiple_of(b)`
+
+error: manual implementation of `.is_multiple_of()`
+  --> tests/ui/manual_is_multiple_of.rs:11:13
+   |
+LL |     let _ = (a + 1) % (b + 1) != 0;
+   |             ^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `!(a + 1).is_multiple_of(b + 1)`
+
+error: manual implementation of `.is_multiple_of()`
+  --> tests/ui/manual_is_multiple_of.rs:13:13
+   |
+LL |     let _ = a % b > 0;
+   |             ^^^^^^^^^ help: replace with: `!a.is_multiple_of(b)`
+
+error: manual implementation of `.is_multiple_of()`
+  --> tests/ui/manual_is_multiple_of.rs:14:13
+   |
+LL |     let _ = 0 < a % b;
+   |             ^^^^^^^^^ help: replace with: `!a.is_multiple_of(b)`
+
+error: aborting due to 6 previous errors
+
diff --git a/src/tools/clippy/tests/ui/manual_is_variant_and.fixed b/src/tools/clippy/tests/ui/manual_is_variant_and.fixed
index 18a72188ab5..6425f32c09c 100644
--- a/src/tools/clippy/tests/ui/manual_is_variant_and.fixed
+++ b/src/tools/clippy/tests/ui/manual_is_variant_and.fixed
@@ -77,7 +77,7 @@ fn option_methods() {
     let _ = opt_map!(opt2, |x| x == 'a').unwrap_or_default(); // should not lint
 
     // Should not lint.
-    let _ = Foo::<u32>(0).map(|x| x % 2 == 0) == Some(true);
+    let _ = Foo::<u32>(0).map(|x| x.is_multiple_of(2)) == Some(true);
     let _ = Some(2).map(|x| x % 2 == 0) != foo();
     let _ = mac!(eq Some(2).map(|x| x % 2 == 0), Some(true));
     let _ = mac!(some 2).map(|x| x % 2 == 0) == Some(true);
@@ -96,11 +96,11 @@ fn result_methods() {
     });
     let _ = res.is_ok_and(|x| x > 1);
 
-    let _ = Ok::<usize, ()>(2).is_ok_and(|x| x % 2 == 0);
+    let _ = Ok::<usize, ()>(2).is_ok_and(|x| x.is_multiple_of(2));
     //~^ manual_is_variant_and
-    let _ = !Ok::<usize, ()>(2).is_ok_and(|x| x % 2 == 0);
+    let _ = !Ok::<usize, ()>(2).is_ok_and(|x| x.is_multiple_of(2));
     //~^ manual_is_variant_and
-    let _ = !Ok::<usize, ()>(2).is_ok_and(|x| x % 2 == 0);
+    let _ = !Ok::<usize, ()>(2).is_ok_and(|x| x.is_multiple_of(2));
     //~^ manual_is_variant_and
 
     // won't fix because the return type of the closure is not `bool`
diff --git a/src/tools/clippy/tests/ui/manual_is_variant_and.rs b/src/tools/clippy/tests/ui/manual_is_variant_and.rs
index a92f7c04369..e069e97a04d 100644
--- a/src/tools/clippy/tests/ui/manual_is_variant_and.rs
+++ b/src/tools/clippy/tests/ui/manual_is_variant_and.rs
@@ -83,7 +83,7 @@ fn option_methods() {
     let _ = opt_map!(opt2, |x| x == 'a').unwrap_or_default(); // should not lint
 
     // Should not lint.
-    let _ = Foo::<u32>(0).map(|x| x % 2 == 0) == Some(true);
+    let _ = Foo::<u32>(0).map(|x| x.is_multiple_of(2)) == Some(true);
     let _ = Some(2).map(|x| x % 2 == 0) != foo();
     let _ = mac!(eq Some(2).map(|x| x % 2 == 0), Some(true));
     let _ = mac!(some 2).map(|x| x % 2 == 0) == Some(true);
@@ -105,11 +105,11 @@ fn result_methods() {
     //~^ manual_is_variant_and
         .unwrap_or_default();
 
-    let _ = Ok::<usize, ()>(2).map(|x| x % 2 == 0) == Ok(true);
+    let _ = Ok::<usize, ()>(2).map(|x| x.is_multiple_of(2)) == Ok(true);
     //~^ manual_is_variant_and
-    let _ = Ok::<usize, ()>(2).map(|x| x % 2 == 0) != Ok(true);
+    let _ = Ok::<usize, ()>(2).map(|x| x.is_multiple_of(2)) != Ok(true);
     //~^ manual_is_variant_and
-    let _ = Ok::<usize, ()>(2).map(|x| x % 2 == 0) != Ok(true);
+    let _ = Ok::<usize, ()>(2).map(|x| x.is_multiple_of(2)) != Ok(true);
     //~^ manual_is_variant_and
 
     // won't fix because the return type of the closure is not `bool`
diff --git a/src/tools/clippy/tests/ui/manual_is_variant_and.stderr b/src/tools/clippy/tests/ui/manual_is_variant_and.stderr
index 1fb437a8bc7..f770319a268 100644
--- a/src/tools/clippy/tests/ui/manual_is_variant_and.stderr
+++ b/src/tools/clippy/tests/ui/manual_is_variant_and.stderr
@@ -105,20 +105,20 @@ LL | |         .unwrap_or_default();
 error: called `.map() == Ok()`
   --> tests/ui/manual_is_variant_and.rs:108:13
    |
-LL |     let _ = Ok::<usize, ()>(2).map(|x| x % 2 == 0) == Ok(true);
-   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use: `Ok::<usize, ()>(2).is_ok_and(|x| x % 2 == 0)`
+LL |     let _ = Ok::<usize, ()>(2).map(|x| x.is_multiple_of(2)) == Ok(true);
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use: `Ok::<usize, ()>(2).is_ok_and(|x| x.is_multiple_of(2))`
 
 error: called `.map() != Ok()`
   --> tests/ui/manual_is_variant_and.rs:110:13
    |
-LL |     let _ = Ok::<usize, ()>(2).map(|x| x % 2 == 0) != Ok(true);
-   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use: `!Ok::<usize, ()>(2).is_ok_and(|x| x % 2 == 0)`
+LL |     let _ = Ok::<usize, ()>(2).map(|x| x.is_multiple_of(2)) != Ok(true);
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use: `!Ok::<usize, ()>(2).is_ok_and(|x| x.is_multiple_of(2))`
 
 error: called `.map() != Ok()`
   --> tests/ui/manual_is_variant_and.rs:112:13
    |
-LL |     let _ = Ok::<usize, ()>(2).map(|x| x % 2 == 0) != Ok(true);
-   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use: `!Ok::<usize, ()>(2).is_ok_and(|x| x % 2 == 0)`
+LL |     let _ = Ok::<usize, ()>(2).map(|x| x.is_multiple_of(2)) != Ok(true);
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use: `!Ok::<usize, ()>(2).is_ok_and(|x| x.is_multiple_of(2))`
 
 error: called `map(<f>).unwrap_or_default()` on a `Result` value
   --> tests/ui/manual_is_variant_and.rs:119:18
diff --git a/src/tools/clippy/tests/ui/manual_ok_err.fixed b/src/tools/clippy/tests/ui/manual_ok_err.fixed
index e6f799aa58d..9b70ce0df43 100644
--- a/src/tools/clippy/tests/ui/manual_ok_err.fixed
+++ b/src/tools/clippy/tests/ui/manual_ok_err.fixed
@@ -103,3 +103,27 @@ fn issue14239() {
     };
     //~^^^^^ manual_ok_err
 }
+
+mod issue15051 {
+    struct Container {
+        field: Result<bool, ()>,
+    }
+
+    #[allow(clippy::needless_borrow)]
+    fn with_addr_of(x: &Container) -> Option<&bool> {
+        (&x.field).as_ref().ok()
+    }
+
+    fn from_fn(x: &Container) -> Option<&bool> {
+        let result_with_ref = || &x.field;
+        result_with_ref().as_ref().ok()
+    }
+
+    fn result_with_ref_mut(x: &mut Container) -> &mut Result<bool, ()> {
+        &mut x.field
+    }
+
+    fn from_fn_mut(x: &mut Container) -> Option<&mut bool> {
+        result_with_ref_mut(x).as_mut().ok()
+    }
+}
diff --git a/src/tools/clippy/tests/ui/manual_ok_err.rs b/src/tools/clippy/tests/ui/manual_ok_err.rs
index 972b2c41ee7..dee90463824 100644
--- a/src/tools/clippy/tests/ui/manual_ok_err.rs
+++ b/src/tools/clippy/tests/ui/manual_ok_err.rs
@@ -141,3 +141,39 @@ fn issue14239() {
     };
     //~^^^^^ manual_ok_err
 }
+
+mod issue15051 {
+    struct Container {
+        field: Result<bool, ()>,
+    }
+
+    #[allow(clippy::needless_borrow)]
+    fn with_addr_of(x: &Container) -> Option<&bool> {
+        match &x.field {
+            //~^ manual_ok_err
+            Ok(panel) => Some(panel),
+            Err(_) => None,
+        }
+    }
+
+    fn from_fn(x: &Container) -> Option<&bool> {
+        let result_with_ref = || &x.field;
+        match result_with_ref() {
+            //~^ manual_ok_err
+            Ok(panel) => Some(panel),
+            Err(_) => None,
+        }
+    }
+
+    fn result_with_ref_mut(x: &mut Container) -> &mut Result<bool, ()> {
+        &mut x.field
+    }
+
+    fn from_fn_mut(x: &mut Container) -> Option<&mut bool> {
+        match result_with_ref_mut(x) {
+            //~^ manual_ok_err
+            Ok(panel) => Some(panel),
+            Err(_) => None,
+        }
+    }
+}
diff --git a/src/tools/clippy/tests/ui/manual_ok_err.stderr b/src/tools/clippy/tests/ui/manual_ok_err.stderr
index 040e170f397..448fbffc050 100644
--- a/src/tools/clippy/tests/ui/manual_ok_err.stderr
+++ b/src/tools/clippy/tests/ui/manual_ok_err.stderr
@@ -111,5 +111,35 @@ LL +         "1".parse::<u8>().ok()
 LL ~     };
    |
 
-error: aborting due to 9 previous errors
+error: manual implementation of `ok`
+  --> tests/ui/manual_ok_err.rs:152:9
+   |
+LL | /         match &x.field {
+LL | |
+LL | |             Ok(panel) => Some(panel),
+LL | |             Err(_) => None,
+LL | |         }
+   | |_________^ help: replace with: `(&x.field).as_ref().ok()`
+
+error: manual implementation of `ok`
+  --> tests/ui/manual_ok_err.rs:161:9
+   |
+LL | /         match result_with_ref() {
+LL | |
+LL | |             Ok(panel) => Some(panel),
+LL | |             Err(_) => None,
+LL | |         }
+   | |_________^ help: replace with: `result_with_ref().as_ref().ok()`
+
+error: manual implementation of `ok`
+  --> tests/ui/manual_ok_err.rs:173:9
+   |
+LL | /         match result_with_ref_mut(x) {
+LL | |
+LL | |             Ok(panel) => Some(panel),
+LL | |             Err(_) => None,
+LL | |         }
+   | |_________^ help: replace with: `result_with_ref_mut(x).as_mut().ok()`
+
+error: aborting due to 12 previous errors
 
diff --git a/src/tools/clippy/tests/ui/missing_const_for_fn/const_trait.fixed b/src/tools/clippy/tests/ui/missing_const_for_fn/const_trait.fixed
index 7e0d4fccaae..f1d5579a723 100644
--- a/src/tools/clippy/tests/ui/missing_const_for_fn/const_trait.fixed
+++ b/src/tools/clippy/tests/ui/missing_const_for_fn/const_trait.fixed
@@ -25,7 +25,7 @@ const fn can_be_const() {
     0u64.method();
 }
 
-// False negative, see FIXME comment in `clipy_utils::qualify_min_const`
+// False negative, see FIXME comment in `clippy_utils::qualify_min_const_fn`
 fn could_be_const_but_does_not_trigger<T>(t: T)
 where
     T: const ConstTrait,
diff --git a/src/tools/clippy/tests/ui/missing_const_for_fn/const_trait.rs b/src/tools/clippy/tests/ui/missing_const_for_fn/const_trait.rs
index 439da4622d7..d495759526d 100644
--- a/src/tools/clippy/tests/ui/missing_const_for_fn/const_trait.rs
+++ b/src/tools/clippy/tests/ui/missing_const_for_fn/const_trait.rs
@@ -25,7 +25,7 @@ fn can_be_const() {
     0u64.method();
 }
 
-// False negative, see FIXME comment in `clipy_utils::qualify_min_const`
+// False negative, see FIXME comment in `clippy_utils::qualify_min_const_fn`
 fn could_be_const_but_does_not_trigger<T>(t: T)
 where
     T: const ConstTrait,
diff --git a/src/tools/clippy/tests/ui/missing_const_for_fn/could_be_const.fixed b/src/tools/clippy/tests/ui/missing_const_for_fn/could_be_const.fixed
index 65eb2d5938b..95bf63ed1df 100644
--- a/src/tools/clippy/tests/ui/missing_const_for_fn/could_be_const.fixed
+++ b/src/tools/clippy/tests/ui/missing_const_for_fn/could_be_const.fixed
@@ -221,3 +221,60 @@ const fn mut_add(x: &mut i32) {
     //~^ missing_const_for_fn
     *x += 1;
 }
+
+mod issue_15079 {
+    pub trait Trait {}
+
+    pub struct Struct<T: Trait> {
+        _t: Option<T>,
+    }
+
+    impl<T: Trait> Struct<T> {
+        #[clippy::msrv = "1.60"]
+        pub fn new_1_60() -> Self {
+            Self { _t: None }
+        }
+
+        #[clippy::msrv = "1.61"]
+        pub const fn new_1_61() -> Self {
+            //~^ missing_const_for_fn
+            Self { _t: None }
+        }
+    }
+
+    pub struct S2<T> {
+        _t: Option<T>,
+    }
+
+    impl<T> S2<T> {
+        #[clippy::msrv = "1.60"]
+        pub const fn new_1_60() -> Self {
+            //~^ missing_const_for_fn
+            Self { _t: None }
+        }
+
+        #[clippy::msrv = "1.61"]
+        pub const fn new_1_61() -> Self {
+            //~^ missing_const_for_fn
+            Self { _t: None }
+        }
+    }
+
+    pub struct S3<T: ?Sized + 'static> {
+        _t: Option<&'static T>,
+    }
+
+    impl<T: ?Sized + 'static> S3<T> {
+        #[clippy::msrv = "1.60"]
+        pub const fn new_1_60() -> Self {
+            //~^ missing_const_for_fn
+            Self { _t: None }
+        }
+
+        #[clippy::msrv = "1.61"]
+        pub const fn new_1_61() -> Self {
+            //~^ missing_const_for_fn
+            Self { _t: None }
+        }
+    }
+}
diff --git a/src/tools/clippy/tests/ui/missing_const_for_fn/could_be_const.rs b/src/tools/clippy/tests/ui/missing_const_for_fn/could_be_const.rs
index 3690d2f799f..8290be67546 100644
--- a/src/tools/clippy/tests/ui/missing_const_for_fn/could_be_const.rs
+++ b/src/tools/clippy/tests/ui/missing_const_for_fn/could_be_const.rs
@@ -221,3 +221,60 @@ fn mut_add(x: &mut i32) {
     //~^ missing_const_for_fn
     *x += 1;
 }
+
+mod issue_15079 {
+    pub trait Trait {}
+
+    pub struct Struct<T: Trait> {
+        _t: Option<T>,
+    }
+
+    impl<T: Trait> Struct<T> {
+        #[clippy::msrv = "1.60"]
+        pub fn new_1_60() -> Self {
+            Self { _t: None }
+        }
+
+        #[clippy::msrv = "1.61"]
+        pub fn new_1_61() -> Self {
+            //~^ missing_const_for_fn
+            Self { _t: None }
+        }
+    }
+
+    pub struct S2<T> {
+        _t: Option<T>,
+    }
+
+    impl<T> S2<T> {
+        #[clippy::msrv = "1.60"]
+        pub fn new_1_60() -> Self {
+            //~^ missing_const_for_fn
+            Self { _t: None }
+        }
+
+        #[clippy::msrv = "1.61"]
+        pub fn new_1_61() -> Self {
+            //~^ missing_const_for_fn
+            Self { _t: None }
+        }
+    }
+
+    pub struct S3<T: ?Sized + 'static> {
+        _t: Option<&'static T>,
+    }
+
+    impl<T: ?Sized + 'static> S3<T> {
+        #[clippy::msrv = "1.60"]
+        pub fn new_1_60() -> Self {
+            //~^ missing_const_for_fn
+            Self { _t: None }
+        }
+
+        #[clippy::msrv = "1.61"]
+        pub fn new_1_61() -> Self {
+            //~^ missing_const_for_fn
+            Self { _t: None }
+        }
+    }
+}
diff --git a/src/tools/clippy/tests/ui/missing_const_for_fn/could_be_const.stderr b/src/tools/clippy/tests/ui/missing_const_for_fn/could_be_const.stderr
index 10e07d12f5a..17cbc431276 100644
--- a/src/tools/clippy/tests/ui/missing_const_for_fn/could_be_const.stderr
+++ b/src/tools/clippy/tests/ui/missing_const_for_fn/could_be_const.stderr
@@ -332,5 +332,75 @@ help: make the function `const`
 LL | const fn mut_add(x: &mut i32) {
    | +++++
 
-error: aborting due to 25 previous errors
+error: this could be a `const fn`
+  --> tests/ui/missing_const_for_fn/could_be_const.rs:239:9
+   |
+LL | /         pub fn new_1_61() -> Self {
+LL | |
+LL | |             Self { _t: None }
+LL | |         }
+   | |_________^
+   |
+help: make the function `const`
+   |
+LL |         pub const fn new_1_61() -> Self {
+   |             +++++
+
+error: this could be a `const fn`
+  --> tests/ui/missing_const_for_fn/could_be_const.rs:251:9
+   |
+LL | /         pub fn new_1_60() -> Self {
+LL | |
+LL | |             Self { _t: None }
+LL | |         }
+   | |_________^
+   |
+help: make the function `const`
+   |
+LL |         pub const fn new_1_60() -> Self {
+   |             +++++
+
+error: this could be a `const fn`
+  --> tests/ui/missing_const_for_fn/could_be_const.rs:257:9
+   |
+LL | /         pub fn new_1_61() -> Self {
+LL | |
+LL | |             Self { _t: None }
+LL | |         }
+   | |_________^
+   |
+help: make the function `const`
+   |
+LL |         pub const fn new_1_61() -> Self {
+   |             +++++
+
+error: this could be a `const fn`
+  --> tests/ui/missing_const_for_fn/could_be_const.rs:269:9
+   |
+LL | /         pub fn new_1_60() -> Self {
+LL | |
+LL | |             Self { _t: None }
+LL | |         }
+   | |_________^
+   |
+help: make the function `const`
+   |
+LL |         pub const fn new_1_60() -> Self {
+   |             +++++
+
+error: this could be a `const fn`
+  --> tests/ui/missing_const_for_fn/could_be_const.rs:275:9
+   |
+LL | /         pub fn new_1_61() -> Self {
+LL | |
+LL | |             Self { _t: None }
+LL | |         }
+   | |_________^
+   |
+help: make the function `const`
+   |
+LL |         pub const fn new_1_61() -> Self {
+   |             +++++
+
+error: aborting due to 30 previous errors
 
diff --git a/src/tools/clippy/tests/ui/nonminimal_bool.stderr b/src/tools/clippy/tests/ui/nonminimal_bool.stderr
index 0e3e4cf7988..ecb82a23da0 100644
--- a/src/tools/clippy/tests/ui/nonminimal_bool.stderr
+++ b/src/tools/clippy/tests/ui/nonminimal_bool.stderr
@@ -179,7 +179,7 @@ error: inequality checks against true can be replaced by a negation
   --> tests/ui/nonminimal_bool.rs:186:8
    |
 LL |     if !b != true {}
-   |        ^^^^^^^^^^ help: try simplifying it as shown: `!(!b)`
+   |        ^^^^^^^^^^ help: try simplifying it as shown: `!!b`
 
 error: this boolean expression can be simplified
   --> tests/ui/nonminimal_bool.rs:189:8
@@ -209,7 +209,7 @@ error: inequality checks against true can be replaced by a negation
   --> tests/ui/nonminimal_bool.rs:193:8
    |
 LL |     if true != !b {}
-   |        ^^^^^^^^^^ help: try simplifying it as shown: `!(!b)`
+   |        ^^^^^^^^^^ help: try simplifying it as shown: `!!b`
 
 error: this boolean expression can be simplified
   --> tests/ui/nonminimal_bool.rs:196:8
diff --git a/src/tools/clippy/tests/ui/or_fun_call.fixed b/src/tools/clippy/tests/ui/or_fun_call.fixed
index a1119d75c23..34f3e046841 100644
--- a/src/tools/clippy/tests/ui/or_fun_call.fixed
+++ b/src/tools/clippy/tests/ui/or_fun_call.fixed
@@ -5,6 +5,7 @@
     clippy::uninlined_format_args,
     clippy::unnecessary_wraps,
     clippy::unnecessary_literal_unwrap,
+    clippy::unnecessary_result_map_or_else,
     clippy::useless_vec
 )]
 
@@ -409,4 +410,33 @@ fn fn_call_in_nested_expr() {
     //~^ or_fun_call
 }
 
+mod result_map_or {
+    fn g() -> i32 {
+        3
+    }
+
+    fn f(n: i32) -> i32 {
+        n
+    }
+
+    fn test_map_or() {
+        let x: Result<i32, ()> = Ok(4);
+        let _ = x.map_or_else(|_| g(), |v| v);
+        //~^ or_fun_call
+        let _ = x.map_or_else(|_| g(), f);
+        //~^ or_fun_call
+        let _ = x.map_or(0, f);
+    }
+}
+
+fn test_option_get_or_insert() {
+    // assume that this is slow call
+    fn g() -> u8 {
+        99
+    }
+    let mut x = Some(42_u8);
+    let _ = x.get_or_insert_with(g);
+    //~^ or_fun_call
+}
+
 fn main() {}
diff --git a/src/tools/clippy/tests/ui/or_fun_call.rs b/src/tools/clippy/tests/ui/or_fun_call.rs
index a7cd632bf16..dc57bd6060a 100644
--- a/src/tools/clippy/tests/ui/or_fun_call.rs
+++ b/src/tools/clippy/tests/ui/or_fun_call.rs
@@ -5,6 +5,7 @@
     clippy::uninlined_format_args,
     clippy::unnecessary_wraps,
     clippy::unnecessary_literal_unwrap,
+    clippy::unnecessary_result_map_or_else,
     clippy::useless_vec
 )]
 
@@ -409,4 +410,33 @@ fn fn_call_in_nested_expr() {
     //~^ or_fun_call
 }
 
+mod result_map_or {
+    fn g() -> i32 {
+        3
+    }
+
+    fn f(n: i32) -> i32 {
+        n
+    }
+
+    fn test_map_or() {
+        let x: Result<i32, ()> = Ok(4);
+        let _ = x.map_or(g(), |v| v);
+        //~^ or_fun_call
+        let _ = x.map_or(g(), f);
+        //~^ or_fun_call
+        let _ = x.map_or(0, f);
+    }
+}
+
+fn test_option_get_or_insert() {
+    // assume that this is slow call
+    fn g() -> u8 {
+        99
+    }
+    let mut x = Some(42_u8);
+    let _ = x.get_or_insert(g());
+    //~^ or_fun_call
+}
+
 fn main() {}
diff --git a/src/tools/clippy/tests/ui/or_fun_call.stderr b/src/tools/clippy/tests/ui/or_fun_call.stderr
index 35bda7e4d33..0f159fe8bff 100644
--- a/src/tools/clippy/tests/ui/or_fun_call.stderr
+++ b/src/tools/clippy/tests/ui/or_fun_call.stderr
@@ -1,5 +1,5 @@
 error: function call inside of `unwrap_or`
-  --> tests/ui/or_fun_call.rs:52:22
+  --> tests/ui/or_fun_call.rs:53:22
    |
 LL |     with_constructor.unwrap_or(make());
    |                      ^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_else(make)`
@@ -8,7 +8,7 @@ LL |     with_constructor.unwrap_or(make());
    = help: to override `-D warnings` add `#[allow(clippy::or_fun_call)]`
 
 error: use of `unwrap_or` to construct default value
-  --> tests/ui/or_fun_call.rs:56:14
+  --> tests/ui/or_fun_call.rs:57:14
    |
 LL |     with_new.unwrap_or(Vec::new());
    |              ^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_default()`
@@ -17,199 +17,199 @@ LL |     with_new.unwrap_or(Vec::new());
    = help: to override `-D warnings` add `#[allow(clippy::unwrap_or_default)]`
 
 error: function call inside of `unwrap_or`
-  --> tests/ui/or_fun_call.rs:60:21
+  --> tests/ui/or_fun_call.rs:61:21
    |
 LL |     with_const_args.unwrap_or(Vec::with_capacity(12));
    |                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_else(|| Vec::with_capacity(12))`
 
 error: function call inside of `unwrap_or`
-  --> tests/ui/or_fun_call.rs:64:14
+  --> tests/ui/or_fun_call.rs:65:14
    |
 LL |     with_err.unwrap_or(make());
    |              ^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_else(|_| make())`
 
 error: function call inside of `unwrap_or`
-  --> tests/ui/or_fun_call.rs:68:19
+  --> tests/ui/or_fun_call.rs:69:19
    |
 LL |     with_err_args.unwrap_or(Vec::with_capacity(12));
    |                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_else(|_| Vec::with_capacity(12))`
 
 error: use of `unwrap_or` to construct default value
-  --> tests/ui/or_fun_call.rs:72:24
+  --> tests/ui/or_fun_call.rs:73:24
    |
 LL |     with_default_trait.unwrap_or(Default::default());
    |                        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_default()`
 
 error: use of `unwrap_or` to construct default value
-  --> tests/ui/or_fun_call.rs:76:23
+  --> tests/ui/or_fun_call.rs:77:23
    |
 LL |     with_default_type.unwrap_or(u64::default());
    |                       ^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_default()`
 
 error: function call inside of `unwrap_or`
-  --> tests/ui/or_fun_call.rs:80:18
+  --> tests/ui/or_fun_call.rs:81:18
    |
 LL |     self_default.unwrap_or(<FakeDefault>::default());
    |                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_else(<FakeDefault>::default)`
 
 error: use of `unwrap_or` to construct default value
-  --> tests/ui/or_fun_call.rs:84:18
+  --> tests/ui/or_fun_call.rs:85:18
    |
 LL |     real_default.unwrap_or(<FakeDefault as Default>::default());
    |                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_default()`
 
 error: use of `unwrap_or` to construct default value
-  --> tests/ui/or_fun_call.rs:88:14
+  --> tests/ui/or_fun_call.rs:89:14
    |
 LL |     with_vec.unwrap_or(vec![]);
    |              ^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_default()`
 
 error: function call inside of `unwrap_or`
-  --> tests/ui/or_fun_call.rs:92:21
+  --> tests/ui/or_fun_call.rs:93:21
    |
 LL |     without_default.unwrap_or(Foo::new());
    |                     ^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_else(Foo::new)`
 
 error: use of `or_insert` to construct default value
-  --> tests/ui/or_fun_call.rs:96:19
+  --> tests/ui/or_fun_call.rs:97:19
    |
 LL |     map.entry(42).or_insert(String::new());
    |                   ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `or_default()`
 
 error: use of `or_insert` to construct default value
-  --> tests/ui/or_fun_call.rs:100:23
+  --> tests/ui/or_fun_call.rs:101:23
    |
 LL |     map_vec.entry(42).or_insert(vec![]);
    |                       ^^^^^^^^^^^^^^^^^ help: try: `or_default()`
 
 error: use of `or_insert` to construct default value
-  --> tests/ui/or_fun_call.rs:104:21
+  --> tests/ui/or_fun_call.rs:105:21
    |
 LL |     btree.entry(42).or_insert(String::new());
    |                     ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `or_default()`
 
 error: use of `or_insert` to construct default value
-  --> tests/ui/or_fun_call.rs:108:25
+  --> tests/ui/or_fun_call.rs:109:25
    |
 LL |     btree_vec.entry(42).or_insert(vec![]);
    |                         ^^^^^^^^^^^^^^^^^ help: try: `or_default()`
 
 error: use of `unwrap_or` to construct default value
-  --> tests/ui/or_fun_call.rs:112:21
+  --> tests/ui/or_fun_call.rs:113:21
    |
 LL |     let _ = stringy.unwrap_or(String::new());
    |                     ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_default()`
 
 error: function call inside of `ok_or`
-  --> tests/ui/or_fun_call.rs:117:17
+  --> tests/ui/or_fun_call.rs:118:17
    |
 LL |     let _ = opt.ok_or(format!("{} world.", hello));
    |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `ok_or_else(|| format!("{} world.", hello))`
 
 error: function call inside of `unwrap_or`
-  --> tests/ui/or_fun_call.rs:122:21
+  --> tests/ui/or_fun_call.rs:123:21
    |
 LL |     let _ = Some(1).unwrap_or(map[&1]);
    |                     ^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_else(|| map[&1])`
 
 error: function call inside of `unwrap_or`
-  --> tests/ui/or_fun_call.rs:125:21
+  --> tests/ui/or_fun_call.rs:126:21
    |
 LL |     let _ = Some(1).unwrap_or(map[&1]);
    |                     ^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_else(|| map[&1])`
 
 error: function call inside of `or`
-  --> tests/ui/or_fun_call.rs:150:35
+  --> tests/ui/or_fun_call.rs:151:35
    |
 LL |     let _ = Some("a".to_string()).or(Some("b".to_string()));
    |                                   ^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `or_else(|| Some("b".to_string()))`
 
 error: function call inside of `unwrap_or`
-  --> tests/ui/or_fun_call.rs:193:18
+  --> tests/ui/or_fun_call.rs:194:18
    |
 LL |             None.unwrap_or(ptr_to_ref(s));
    |                  ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_else(|| ptr_to_ref(s))`
 
 error: function call inside of `unwrap_or`
-  --> tests/ui/or_fun_call.rs:201:14
+  --> tests/ui/or_fun_call.rs:202:14
    |
 LL |         None.unwrap_or(unsafe { ptr_to_ref(s) });
    |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_else(|| unsafe { ptr_to_ref(s) })`
 
 error: function call inside of `unwrap_or`
-  --> tests/ui/or_fun_call.rs:204:14
+  --> tests/ui/or_fun_call.rs:205:14
    |
 LL |         None.unwrap_or( unsafe { ptr_to_ref(s) }    );
    |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_else(|| unsafe { ptr_to_ref(s) })`
 
 error: function call inside of `map_or`
-  --> tests/ui/or_fun_call.rs:280:25
+  --> tests/ui/or_fun_call.rs:281:25
    |
 LL |         let _ = Some(4).map_or(g(), |v| v);
    |                         ^^^^^^^^^^^^^^^^^^ help: try: `map_or_else(g, |v| v)`
 
 error: function call inside of `map_or`
-  --> tests/ui/or_fun_call.rs:282:25
+  --> tests/ui/or_fun_call.rs:283:25
    |
 LL |         let _ = Some(4).map_or(g(), f);
    |                         ^^^^^^^^^^^^^^ help: try: `map_or_else(g, f)`
 
 error: use of `unwrap_or_else` to construct default value
-  --> tests/ui/or_fun_call.rs:314:18
+  --> tests/ui/or_fun_call.rs:315:18
    |
 LL |         with_new.unwrap_or_else(Vec::new);
    |                  ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_default()`
 
 error: use of `unwrap_or_else` to construct default value
-  --> tests/ui/or_fun_call.rs:318:28
+  --> tests/ui/or_fun_call.rs:319:28
    |
 LL |         with_default_trait.unwrap_or_else(Default::default);
    |                            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_default()`
 
 error: use of `unwrap_or_else` to construct default value
-  --> tests/ui/or_fun_call.rs:322:27
+  --> tests/ui/or_fun_call.rs:323:27
    |
 LL |         with_default_type.unwrap_or_else(u64::default);
    |                           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_default()`
 
 error: use of `unwrap_or_else` to construct default value
-  --> tests/ui/or_fun_call.rs:326:22
+  --> tests/ui/or_fun_call.rs:327:22
    |
 LL |         real_default.unwrap_or_else(<FakeDefault as Default>::default);
    |                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_default()`
 
 error: use of `or_insert_with` to construct default value
-  --> tests/ui/or_fun_call.rs:330:23
+  --> tests/ui/or_fun_call.rs:331:23
    |
 LL |         map.entry(42).or_insert_with(String::new);
    |                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `or_default()`
 
 error: use of `or_insert_with` to construct default value
-  --> tests/ui/or_fun_call.rs:334:25
+  --> tests/ui/or_fun_call.rs:335:25
    |
 LL |         btree.entry(42).or_insert_with(String::new);
    |                         ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `or_default()`
 
 error: use of `unwrap_or_else` to construct default value
-  --> tests/ui/or_fun_call.rs:338:25
+  --> tests/ui/or_fun_call.rs:339:25
    |
 LL |         let _ = stringy.unwrap_or_else(String::new);
    |                         ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_default()`
 
 error: function call inside of `unwrap_or`
-  --> tests/ui/or_fun_call.rs:380:17
+  --> tests/ui/or_fun_call.rs:381:17
    |
 LL |     let _ = opt.unwrap_or({ f() }); // suggest `.unwrap_or_else(f)`
    |                 ^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_else(f)`
 
 error: function call inside of `unwrap_or`
-  --> tests/ui/or_fun_call.rs:385:17
+  --> tests/ui/or_fun_call.rs:386:17
    |
 LL |     let _ = opt.unwrap_or(f() + 1); // suggest `.unwrap_or_else(|| f() + 1)`
    |                 ^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_else(|| f() + 1)`
 
 error: function call inside of `unwrap_or`
-  --> tests/ui/or_fun_call.rs:390:17
+  --> tests/ui/or_fun_call.rs:391:17
    |
 LL |       let _ = opt.unwrap_or({
    |  _________________^
@@ -229,22 +229,40 @@ LL ~     });
    |
 
 error: function call inside of `map_or`
-  --> tests/ui/or_fun_call.rs:396:17
+  --> tests/ui/or_fun_call.rs:397:17
    |
 LL |     let _ = opt.map_or(f() + 1, |v| v); // suggest `.map_or_else(|| f() + 1, |v| v)`
    |                 ^^^^^^^^^^^^^^^^^^^^^^ help: try: `map_or_else(|| f() + 1, |v| v)`
 
 error: use of `unwrap_or` to construct default value
-  --> tests/ui/or_fun_call.rs:401:17
+  --> tests/ui/or_fun_call.rs:402:17
    |
 LL |     let _ = opt.unwrap_or({ i32::default() });
    |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_default()`
 
 error: function call inside of `unwrap_or`
-  --> tests/ui/or_fun_call.rs:408:21
+  --> tests/ui/or_fun_call.rs:409:21
    |
 LL |     let _ = opt_foo.unwrap_or(Foo { val: String::default() });
    |                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_else(|| Foo { val: String::default() })`
 
-error: aborting due to 38 previous errors
+error: function call inside of `map_or`
+  --> tests/ui/or_fun_call.rs:424:19
+   |
+LL |         let _ = x.map_or(g(), |v| v);
+   |                   ^^^^^^^^^^^^^^^^^^ help: try: `map_or_else(|_| g(), |v| v)`
+
+error: function call inside of `map_or`
+  --> tests/ui/or_fun_call.rs:426:19
+   |
+LL |         let _ = x.map_or(g(), f);
+   |                   ^^^^^^^^^^^^^^ help: try: `map_or_else(|_| g(), f)`
+
+error: function call inside of `get_or_insert`
+  --> tests/ui/or_fun_call.rs:438:15
+   |
+LL |     let _ = x.get_or_insert(g());
+   |               ^^^^^^^^^^^^^^^^^^ help: try: `get_or_insert_with(g)`
+
+error: aborting due to 41 previous errors
 
diff --git a/src/tools/clippy/tests/ui/question_mark.fixed b/src/tools/clippy/tests/ui/question_mark.fixed
index 60dc1c101b6..8d6f5fbadca 100644
--- a/src/tools/clippy/tests/ui/question_mark.fixed
+++ b/src/tools/clippy/tests/ui/question_mark.fixed
@@ -453,3 +453,15 @@ fn const_in_pattern(x: Option<(i32, i32)>) -> Option<()> {
 
     None
 }
+
+fn issue_13642(x: Option<i32>) -> Option<()> {
+    let Some(x) = x else {
+        #[cfg(false)]
+        panic!();
+
+        #[cfg(true)]
+        return None;
+    };
+
+    None
+}
diff --git a/src/tools/clippy/tests/ui/question_mark.rs b/src/tools/clippy/tests/ui/question_mark.rs
index 99d0122a98f..f13eee29c11 100644
--- a/src/tools/clippy/tests/ui/question_mark.rs
+++ b/src/tools/clippy/tests/ui/question_mark.rs
@@ -549,3 +549,15 @@ fn const_in_pattern(x: Option<(i32, i32)>) -> Option<()> {
 
     None
 }
+
+fn issue_13642(x: Option<i32>) -> Option<()> {
+    let Some(x) = x else {
+        #[cfg(false)]
+        panic!();
+
+        #[cfg(true)]
+        return None;
+    };
+
+    None
+}
diff --git a/src/tools/clippy/tests/ui/trait_duplication_in_bounds.fixed b/src/tools/clippy/tests/ui/trait_duplication_in_bounds.fixed
index 666ff78b218..cf52ecf2f03 100644
--- a/src/tools/clippy/tests/ui/trait_duplication_in_bounds.fixed
+++ b/src/tools/clippy/tests/ui/trait_duplication_in_bounds.fixed
@@ -169,9 +169,9 @@ where
 // #13476
 #[const_trait]
 trait ConstTrait {}
-const fn const_trait_bounds_good<T: ConstTrait + ~const ConstTrait>() {}
+const fn const_trait_bounds_good<T: ConstTrait + [const] ConstTrait>() {}
 
-const fn const_trait_bounds_bad<T: ~const ConstTrait>() {}
+const fn const_trait_bounds_bad<T: [const] ConstTrait>() {}
 //~^ trait_duplication_in_bounds
 
 fn projections<T, U, V>()
diff --git a/src/tools/clippy/tests/ui/trait_duplication_in_bounds.rs b/src/tools/clippy/tests/ui/trait_duplication_in_bounds.rs
index a1a86fe058e..955562f08dc 100644
--- a/src/tools/clippy/tests/ui/trait_duplication_in_bounds.rs
+++ b/src/tools/clippy/tests/ui/trait_duplication_in_bounds.rs
@@ -169,9 +169,9 @@ where
 // #13476
 #[const_trait]
 trait ConstTrait {}
-const fn const_trait_bounds_good<T: ConstTrait + ~const ConstTrait>() {}
+const fn const_trait_bounds_good<T: ConstTrait + [const] ConstTrait>() {}
 
-const fn const_trait_bounds_bad<T: ~const ConstTrait + ~const ConstTrait>() {}
+const fn const_trait_bounds_bad<T: [const] ConstTrait + [const] ConstTrait>() {}
 //~^ trait_duplication_in_bounds
 
 fn projections<T, U, V>()
diff --git a/src/tools/clippy/tests/ui/trait_duplication_in_bounds.stderr b/src/tools/clippy/tests/ui/trait_duplication_in_bounds.stderr
index d76b4e45848..ab31721ef51 100644
--- a/src/tools/clippy/tests/ui/trait_duplication_in_bounds.stderr
+++ b/src/tools/clippy/tests/ui/trait_duplication_in_bounds.stderr
@@ -61,8 +61,8 @@ LL | fn bad_trait_object(arg0: &(dyn Any + Send + Send)) {
 error: these bounds contain repeated elements
   --> tests/ui/trait_duplication_in_bounds.rs:174:36
    |
-LL | const fn const_trait_bounds_bad<T: ~const ConstTrait + ~const ConstTrait>() {}
-   |                                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `~const ConstTrait`
+LL | const fn const_trait_bounds_bad<T: [const] ConstTrait + [const] ConstTrait>() {}
+   |                                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `[const] ConstTrait`
 
 error: these where clauses contain repeated elements
   --> tests/ui/trait_duplication_in_bounds.rs:181:8
diff --git a/src/tools/clippy/tests/ui/unnecessary_os_str_debug_formatting.rs b/src/tools/clippy/tests/ui/unnecessary_os_str_debug_formatting.rs
index 6652efd9ae1..66590be3d05 100644
--- a/src/tools/clippy/tests/ui/unnecessary_os_str_debug_formatting.rs
+++ b/src/tools/clippy/tests/ui/unnecessary_os_str_debug_formatting.rs
@@ -21,3 +21,16 @@ fn main() {
     let _: String = format!("{:?}", os_str); //~ unnecessary_debug_formatting
     let _: String = format!("{:?}", os_string); //~ unnecessary_debug_formatting
 }
+
+#[clippy::msrv = "1.86"]
+fn msrv_1_86() {
+    let os_str = OsStr::new("test");
+    println!("{:?}", os_str);
+}
+
+#[clippy::msrv = "1.87"]
+fn msrv_1_87() {
+    let os_str = OsStr::new("test");
+    println!("{:?}", os_str);
+    //~^ unnecessary_debug_formatting
+}
diff --git a/src/tools/clippy/tests/ui/unnecessary_os_str_debug_formatting.stderr b/src/tools/clippy/tests/ui/unnecessary_os_str_debug_formatting.stderr
index 382e59b0461..f04d2d5bdc8 100644
--- a/src/tools/clippy/tests/ui/unnecessary_os_str_debug_formatting.stderr
+++ b/src/tools/clippy/tests/ui/unnecessary_os_str_debug_formatting.stderr
@@ -54,5 +54,14 @@ LL |     let _: String = format!("{:?}", os_string);
    = help: use `Display` formatting and change this to `os_string.display()`
    = note: switching to `Display` formatting will change how the value is shown; escaped characters will no longer be escaped and surrounding quotes will be removed
 
-error: aborting due to 6 previous errors
+error: unnecessary `Debug` formatting in `println!` args
+  --> tests/ui/unnecessary_os_str_debug_formatting.rs:34:22
+   |
+LL |     println!("{:?}", os_str);
+   |                      ^^^^^^
+   |
+   = help: use `Display` formatting and change this to `os_str.display()`
+   = note: switching to `Display` formatting will change how the value is shown; escaped characters will no longer be escaped and surrounding quotes will be removed
+
+error: aborting due to 7 previous errors
 
diff --git a/src/tools/clippy/tests/ui/wildcard_enum_match_arm.fixed b/src/tools/clippy/tests/ui/wildcard_enum_match_arm.fixed
index 141ff6eb2ac..5f738a254dc 100644
--- a/src/tools/clippy/tests/ui/wildcard_enum_match_arm.fixed
+++ b/src/tools/clippy/tests/ui/wildcard_enum_match_arm.fixed
@@ -91,6 +91,21 @@ fn main() {
     }
 
     {
+        pub enum Enum {
+            A,
+            B,
+            C(u8),
+            D(u8, u8),
+            E { e: u8 },
+        };
+        match Enum::A {
+            Enum::A => (),
+            Enum::B | Enum::C(_) | Enum::D(..) | Enum::E { .. } => (),
+            //~^ wildcard_enum_match_arm
+        }
+    }
+
+    {
         #![allow(clippy::manual_non_exhaustive)]
         pub enum Enum {
             A,
@@ -105,3 +120,17 @@ fn main() {
         }
     }
 }
+
+fn issue15091() {
+    enum Foo {
+        A,
+        B,
+        C,
+    }
+
+    match Foo::A {
+        Foo::A => {},
+        r#type @ Foo::B | r#type @ Foo::C => {},
+        //~^ wildcard_enum_match_arm
+    }
+}
diff --git a/src/tools/clippy/tests/ui/wildcard_enum_match_arm.rs b/src/tools/clippy/tests/ui/wildcard_enum_match_arm.rs
index a13684e9100..4bc4bfdcb79 100644
--- a/src/tools/clippy/tests/ui/wildcard_enum_match_arm.rs
+++ b/src/tools/clippy/tests/ui/wildcard_enum_match_arm.rs
@@ -91,6 +91,21 @@ fn main() {
     }
 
     {
+        pub enum Enum {
+            A,
+            B,
+            C(u8),
+            D(u8, u8),
+            E { e: u8 },
+        };
+        match Enum::A {
+            Enum::A => (),
+            _ => (),
+            //~^ wildcard_enum_match_arm
+        }
+    }
+
+    {
         #![allow(clippy::manual_non_exhaustive)]
         pub enum Enum {
             A,
@@ -105,3 +120,17 @@ fn main() {
         }
     }
 }
+
+fn issue15091() {
+    enum Foo {
+        A,
+        B,
+        C,
+    }
+
+    match Foo::A {
+        Foo::A => {},
+        r#type => {},
+        //~^ wildcard_enum_match_arm
+    }
+}
diff --git a/src/tools/clippy/tests/ui/wildcard_enum_match_arm.stderr b/src/tools/clippy/tests/ui/wildcard_enum_match_arm.stderr
index 088c6b7b284..d0929989494 100644
--- a/src/tools/clippy/tests/ui/wildcard_enum_match_arm.stderr
+++ b/src/tools/clippy/tests/ui/wildcard_enum_match_arm.stderr
@@ -38,7 +38,19 @@ error: wildcard match will also match any future added variants
   --> tests/ui/wildcard_enum_match_arm.rs:103:13
    |
 LL |             _ => (),
+   |             ^ help: try: `Enum::B | Enum::C(_) | Enum::D(..) | Enum::E { .. }`
+
+error: wildcard match will also match any future added variants
+  --> tests/ui/wildcard_enum_match_arm.rs:118:13
+   |
+LL |             _ => (),
    |             ^ help: try: `Enum::B | Enum::__Private`
 
-error: aborting due to 6 previous errors
+error: wildcard match will also match any future added variants
+  --> tests/ui/wildcard_enum_match_arm.rs:133:9
+   |
+LL |         r#type => {},
+   |         ^^^^^^ help: try: `r#type @ Foo::B | r#type @ Foo::C`
+
+error: aborting due to 8 previous errors
 
diff --git a/src/tools/clippy/tests/versioncheck.rs b/src/tools/clippy/tests/versioncheck.rs
index f6fc2354ca0..b0179387b2b 100644
--- a/src/tools/clippy/tests/versioncheck.rs
+++ b/src/tools/clippy/tests/versioncheck.rs
@@ -27,6 +27,7 @@ fn consistent_clippy_crate_versions() {
         "clippy_config/Cargo.toml",
         "clippy_lints/Cargo.toml",
         "clippy_utils/Cargo.toml",
+        "declare_clippy_lint/Cargo.toml",
     ];
 
     for path in paths {
diff --git a/src/tools/clippy/triagebot.toml b/src/tools/clippy/triagebot.toml
index 16557a4bebb..4f370758c00 100644
--- a/src/tools/clippy/triagebot.toml
+++ b/src/tools/clippy/triagebot.toml
@@ -17,6 +17,9 @@ allow-unauthenticated = [
 
 [issue-links]
 
+[mentions."clippy_lints/src/doc"]
+cc = ["@notriddle"]
+
 # Prevents mentions in commits to avoid users being spammed
 [no-mentions]
 
diff --git a/src/tools/clippy/util/versions.py b/src/tools/clippy/util/versions.py
index fee0d292df1..6e06d77a771 100755
--- a/src/tools/clippy/util/versions.py
+++ b/src/tools/clippy/util/versions.py
@@ -6,11 +6,11 @@ import os
 import sys
 
 def key(v):
-    if v == "master":
-        return sys.maxsize
     if v == "stable":
-        return sys.maxsize - 1
+        return sys.maxsize 
     if v == "beta":
+        return sys.maxsize - 1
+    if v == "master":
         return sys.maxsize - 2
     if v == "pre-1.29.0":
         return -1
diff --git a/src/tools/compiletest/src/errors.rs b/src/tools/compiletest/src/errors.rs
index b5a2b7feac9..9fa26305f6b 100644
--- a/src/tools/compiletest/src/errors.rs
+++ b/src/tools/compiletest/src/errors.rs
@@ -16,6 +16,8 @@ pub enum ErrorKind {
     Suggestion,
     Warning,
     Raw,
+    /// Used for better recovery and diagnostics in compiletest.
+    Unknown,
 }
 
 impl ErrorKind {
@@ -31,21 +33,25 @@ impl ErrorKind {
 
     /// Either the canonical uppercase string, or some additional versions for compatibility.
     /// FIXME: consider keeping only the canonical versions here.
-    pub fn from_user_str(s: &str) -> ErrorKind {
-        match s {
+    fn from_user_str(s: &str) -> Option<ErrorKind> {
+        Some(match s {
             "HELP" | "help" => ErrorKind::Help,
             "ERROR" | "error" => ErrorKind::Error,
-            // `MONO_ITEM` makes annotations in `codegen-units` tests syntactically correct,
-            // but those tests never use the error kind later on.
-            "NOTE" | "note" | "MONO_ITEM" => ErrorKind::Note,
+            "NOTE" | "note" => ErrorKind::Note,
             "SUGGESTION" => ErrorKind::Suggestion,
             "WARN" | "WARNING" | "warn" | "warning" => ErrorKind::Warning,
             "RAW" => ErrorKind::Raw,
-            _ => panic!(
+            _ => return None,
+        })
+    }
+
+    pub fn expect_from_user_str(s: &str) -> ErrorKind {
+        ErrorKind::from_user_str(s).unwrap_or_else(|| {
+            panic!(
                 "unexpected diagnostic kind `{s}`, expected \
-                 `ERROR`, `WARN`, `NOTE`, `HELP` or `SUGGESTION`"
-            ),
-        }
+                 `ERROR`, `WARN`, `NOTE`, `HELP`, `SUGGESTION` or `RAW`"
+            )
+        })
     }
 }
 
@@ -58,6 +64,7 @@ impl fmt::Display for ErrorKind {
             ErrorKind::Suggestion => write!(f, "SUGGESTION"),
             ErrorKind::Warning => write!(f, "WARN"),
             ErrorKind::Raw => write!(f, "RAW"),
+            ErrorKind::Unknown => write!(f, "UNKNOWN"),
         }
     }
 }
@@ -65,6 +72,7 @@ impl fmt::Display for ErrorKind {
 #[derive(Debug)]
 pub struct Error {
     pub line_num: Option<usize>,
+    pub column_num: Option<usize>,
     /// What kind of message we expect (e.g., warning, error, suggestion).
     pub kind: ErrorKind,
     pub msg: String,
@@ -74,17 +82,6 @@ pub struct Error {
     pub require_annotation: bool,
 }
 
-impl Error {
-    pub fn render_for_expected(&self) -> String {
-        use colored::Colorize;
-        format!("{: <10}line {: >3}: {}", self.kind, self.line_num_str(), self.msg.cyan())
-    }
-
-    pub fn line_num_str(&self) -> String {
-        self.line_num.map_or("?".to_string(), |line_num| line_num.to_string())
-    }
-}
-
 /// Looks for either "//~| KIND MESSAGE" or "//~^^... KIND MESSAGE"
 /// The former is a "follow" that inherits its target from the preceding line;
 /// the latter is an "adjusts" that goes that many lines up.
@@ -168,8 +165,10 @@ fn parse_expected(
     let rest = line[tag.end()..].trim_start();
     let (kind_str, _) =
         rest.split_once(|c: char| c != '_' && !c.is_ascii_alphabetic()).unwrap_or((rest, ""));
-    let kind = ErrorKind::from_user_str(kind_str);
-    let untrimmed_msg = &rest[kind_str.len()..];
+    let (kind, untrimmed_msg) = match ErrorKind::from_user_str(kind_str) {
+        Some(kind) => (kind, &rest[kind_str.len()..]),
+        None => (ErrorKind::Unknown, rest),
+    };
     let msg = untrimmed_msg.strip_prefix(':').unwrap_or(untrimmed_msg).trim().to_owned();
 
     let line_num_adjust = &captures["adjust"];
@@ -182,6 +181,7 @@ fn parse_expected(
     } else {
         (false, Some(line_num - line_num_adjust.len()))
     };
+    let column_num = Some(tag.start() + 1);
 
     debug!(
         "line={:?} tag={:?} follow_prev={:?} kind={:?} msg={:?}",
@@ -191,7 +191,7 @@ fn parse_expected(
         kind,
         msg
     );
-    Some((follow_prev, Error { line_num, kind, msg, require_annotation: true }))
+    Some((follow_prev, Error { line_num, column_num, kind, msg, require_annotation: true }))
 }
 
 #[cfg(test)]
diff --git a/src/tools/compiletest/src/executor.rs b/src/tools/compiletest/src/executor.rs
index e774c5e2047..0c4ef36828a 100644
--- a/src/tools/compiletest/src/executor.rs
+++ b/src/tools/compiletest/src/executor.rs
@@ -40,9 +40,9 @@ pub(crate) fn run_tests(config: &Config, tests: Vec<CollectedTest>) -> bool {
     // In that case, the tests will effectively be run serially anyway.
     loop {
         // Spawn new test threads, up to the concurrency limit.
-        // FIXME(let_chains): Use a let-chain here when stable in bootstrap.
-        'spawn: while running_tests.len() < concurrency {
-            let Some((id, test)) = fresh_tests.next() else { break 'spawn };
+        while running_tests.len() < concurrency
+            && let Some((id, test)) = fresh_tests.next()
+        {
             listener.test_started(test);
             deadline_queue.push(id, test);
             let join_handle = spawn_test_thread(id, test, completion_tx.clone());
diff --git a/src/tools/compiletest/src/header.rs b/src/tools/compiletest/src/header.rs
index 8bee9caacc9..2b203bb309c 100644
--- a/src/tools/compiletest/src/header.rs
+++ b/src/tools/compiletest/src/header.rs
@@ -593,7 +593,7 @@ impl TestProps {
                         config.parse_name_value_directive(ln, DONT_REQUIRE_ANNOTATIONS)
                     {
                         self.dont_require_annotations
-                            .insert(ErrorKind::from_user_str(err_kind.trim()));
+                            .insert(ErrorKind::expect_from_user_str(err_kind.trim()));
                     }
                 },
             );
diff --git a/src/tools/compiletest/src/json.rs b/src/tools/compiletest/src/json.rs
index 6ed2b52c66d..a8e6416e56c 100644
--- a/src/tools/compiletest/src/json.rs
+++ b/src/tools/compiletest/src/json.rs
@@ -36,9 +36,7 @@ struct UnusedExternNotification {
 struct DiagnosticSpan {
     file_name: String,
     line_start: usize,
-    line_end: usize,
     column_start: usize,
-    column_end: usize,
     is_primary: bool,
     label: Option<String>,
     suggested_replacement: Option<String>,
@@ -148,6 +146,7 @@ pub fn parse_output(file_name: &str, output: &str) -> Vec<Error> {
             Ok(diagnostic) => push_actual_errors(&mut errors, &diagnostic, &[], file_name),
             Err(_) => errors.push(Error {
                 line_num: None,
+                column_num: None,
                 kind: ErrorKind::Raw,
                 msg: line.to_string(),
                 require_annotation: false,
@@ -193,25 +192,9 @@ fn push_actual_errors(
     // also ensure that `//~ ERROR E123` *always* works. The
     // assumption is that these multi-line error messages are on their
     // way out anyhow.
-    let with_code = |span: Option<&DiagnosticSpan>, text: &str| {
-        // FIXME(#33000) -- it'd be better to use a dedicated
-        // UI harness than to include the line/col number like
-        // this, but some current tests rely on it.
-        //
-        // Note: Do NOT include the filename. These can easily
-        // cause false matches where the expected message
-        // appears in the filename, and hence the message
-        // changes but the test still passes.
-        let span_str = match span {
-            Some(DiagnosticSpan { line_start, column_start, line_end, column_end, .. }) => {
-                format!("{line_start}:{column_start}: {line_end}:{column_end}")
-            }
-            None => format!("?:?: ?:?"),
-        };
-        match &diagnostic.code {
-            Some(code) => format!("{span_str}: {text} [{}]", code.code),
-            None => format!("{span_str}: {text}"),
-        }
+    let with_code = |text| match &diagnostic.code {
+        Some(code) => format!("{text} [{}]", code.code),
+        None => format!("{text}"),
     };
 
     // Convert multi-line messages into multiple errors.
@@ -225,8 +208,9 @@ fn push_actual_errors(
             || Regex::new(r"aborting due to \d+ previous errors?|\d+ warnings? emitted").unwrap();
         errors.push(Error {
             line_num: None,
+            column_num: None,
             kind,
-            msg: with_code(None, first_line),
+            msg: with_code(first_line),
             require_annotation: diagnostic.level != "failure-note"
                 && !RE.get_or_init(re_init).is_match(first_line),
         });
@@ -234,8 +218,9 @@ fn push_actual_errors(
         for span in primary_spans {
             errors.push(Error {
                 line_num: Some(span.line_start),
+                column_num: Some(span.column_start),
                 kind,
-                msg: with_code(Some(span), first_line),
+                msg: with_code(first_line),
                 require_annotation: true,
             });
         }
@@ -244,16 +229,18 @@ fn push_actual_errors(
         if primary_spans.is_empty() {
             errors.push(Error {
                 line_num: None,
+                column_num: None,
                 kind,
-                msg: with_code(None, next_line),
+                msg: with_code(next_line),
                 require_annotation: false,
             });
         } else {
             for span in primary_spans {
                 errors.push(Error {
                     line_num: Some(span.line_start),
+                    column_num: Some(span.column_start),
                     kind,
-                    msg: with_code(Some(span), next_line),
+                    msg: with_code(next_line),
                     require_annotation: false,
                 });
             }
@@ -266,6 +253,7 @@ fn push_actual_errors(
             for (index, line) in suggested_replacement.lines().enumerate() {
                 errors.push(Error {
                     line_num: Some(span.line_start + index),
+                    column_num: Some(span.column_start),
                     kind: ErrorKind::Suggestion,
                     msg: line.to_string(),
                     // Empty suggestions (suggestions to remove something) are common
@@ -288,6 +276,7 @@ fn push_actual_errors(
         if let Some(label) = &span.label {
             errors.push(Error {
                 line_num: Some(span.line_start),
+                column_num: Some(span.column_start),
                 kind: ErrorKind::Note,
                 msg: label.clone(),
                 // Empty labels (only underlining spans) are common and do not need annotations.
@@ -310,6 +299,7 @@ fn push_backtrace(
     if Path::new(&expansion.span.file_name) == Path::new(&file_name) {
         errors.push(Error {
             line_num: Some(expansion.span.line_start),
+            column_num: Some(expansion.span.column_start),
             kind: ErrorKind::Note,
             msg: format!("in this expansion of {}", expansion.macro_decl_name),
             require_annotation: true,
diff --git a/src/tools/compiletest/src/runtest.rs b/src/tools/compiletest/src/runtest.rs
index 42c851ea999..980e89889ab 100644
--- a/src/tools/compiletest/src/runtest.rs
+++ b/src/tools/compiletest/src/runtest.rs
@@ -11,7 +11,7 @@ use std::{env, iter, str};
 
 use build_helper::fs::remove_and_create_dir_all;
 use camino::{Utf8Path, Utf8PathBuf};
-use colored::Colorize;
+use colored::{Color, Colorize};
 use regex::{Captures, Regex};
 use tracing::*;
 
@@ -677,9 +677,6 @@ impl<'test> TestCx<'test> {
             return;
         }
 
-        // On Windows, translate all '\' path separators to '/'
-        let file_name = self.testpaths.file.to_string().replace(r"\", "/");
-
         // On Windows, keep all '\' path separators to match the paths reported in the JSON output
         // from the compiler
         let diagnostic_file_name = if self.props.remap_src_base {
@@ -704,6 +701,7 @@ impl<'test> TestCx<'test> {
             .map(|e| Error { msg: self.normalize_output(&e.msg, &[]), ..e });
 
         let mut unexpected = Vec::new();
+        let mut unimportant = Vec::new();
         let mut found = vec![false; expected_errors.len()];
         for actual_error in actual_errors {
             for pattern in &self.props.error_patterns {
@@ -738,14 +736,9 @@ impl<'test> TestCx<'test> {
                         && expected_kinds.contains(&actual_error.kind)
                         && !self.props.dont_require_annotations.contains(&actual_error.kind)
                     {
-                        self.error(&format!(
-                            "{}:{}: unexpected {}: '{}'",
-                            file_name,
-                            actual_error.line_num_str(),
-                            actual_error.kind,
-                            actual_error.msg
-                        ));
                         unexpected.push(actual_error);
+                    } else {
+                        unimportant.push(actual_error);
                     }
                 }
             }
@@ -755,39 +748,140 @@ impl<'test> TestCx<'test> {
         // anything not yet found is a problem
         for (index, expected_error) in expected_errors.iter().enumerate() {
             if !found[index] {
-                self.error(&format!(
-                    "{}:{}: expected {} not found: {}",
-                    file_name,
-                    expected_error.line_num_str(),
-                    expected_error.kind,
-                    expected_error.msg
-                ));
                 not_found.push(expected_error);
             }
         }
 
         if !unexpected.is_empty() || !not_found.is_empty() {
             self.error(&format!(
-                "{} unexpected errors found, {} expected errors not found",
+                "{} unexpected diagnostics reported, {} expected diagnostics not reported",
                 unexpected.len(),
                 not_found.len()
             ));
-            println!("status: {}\ncommand: {}\n", proc_res.status, proc_res.cmdline);
+
+            // Emit locations in a format that is short (relative paths) but "clickable" in editors.
+            // Also normalize path separators to `/`.
+            let file_name = self
+                .testpaths
+                .file
+                .strip_prefix(self.config.src_root.as_str())
+                .unwrap_or(&self.testpaths.file)
+                .to_string()
+                .replace(r"\", "/");
+            let line_str = |e: &Error| {
+                let line_num = e.line_num.map_or("?".to_string(), |line_num| line_num.to_string());
+                // `file:?:NUM` may be confusing to editors and unclickable.
+                let opt_col_num = match e.column_num {
+                    Some(col_num) if line_num != "?" => format!(":{col_num}"),
+                    _ => "".to_string(),
+                };
+                format!("{file_name}:{line_num}{opt_col_num}")
+            };
+            let print_error = |e| println!("{}: {}: {}", line_str(e), e.kind, e.msg.cyan());
+            let push_suggestion =
+                |suggestions: &mut Vec<_>, e: &Error, kind, line, msg, color, rank| {
+                    let mut ret = String::new();
+                    if kind {
+                        ret += &format!("{} {}", "with kind".color(color), e.kind);
+                    }
+                    if line {
+                        if !ret.is_empty() {
+                            ret.push(' ');
+                        }
+                        ret += &format!("{} {}", "on line".color(color), line_str(e));
+                    }
+                    if msg {
+                        if !ret.is_empty() {
+                            ret.push(' ');
+                        }
+                        ret += &format!("{} {}", "with message".color(color), e.msg.cyan());
+                    }
+                    suggestions.push((ret, rank));
+                };
+            let show_suggestions = |mut suggestions: Vec<_>, prefix: &str, color| {
+                // Only show suggestions with the highest rank.
+                suggestions.sort_by_key(|(_, rank)| *rank);
+                if let Some(&(_, top_rank)) = suggestions.first() {
+                    for (suggestion, rank) in suggestions {
+                        if rank == top_rank {
+                            println!("  {} {suggestion}", prefix.color(color));
+                        }
+                    }
+                }
+            };
+
+            // Fuzzy matching quality:
+            // - message and line / message and kind - great, suggested
+            // - only message - good, suggested
+            // - known line and kind - ok, suggested
+            // - only known line - meh, but suggested
+            // - others are not worth suggesting
             if !unexpected.is_empty() {
-                println!("{}", "--- unexpected errors (from JSON output) ---".green());
+                let header = "--- reported in JSON output but not expected in test file ---";
+                println!("{}", header.green());
                 for error in &unexpected {
-                    println!("{}", error.render_for_expected());
+                    print_error(error);
+                    let mut suggestions = Vec::new();
+                    for candidate in &not_found {
+                        let mut push_red_suggestion = |line, msg, rank| {
+                            push_suggestion(
+                                &mut suggestions,
+                                candidate,
+                                candidate.kind != error.kind,
+                                line,
+                                msg,
+                                Color::Red,
+                                rank,
+                            )
+                        };
+                        if error.msg.contains(&candidate.msg) {
+                            push_red_suggestion(candidate.line_num != error.line_num, false, 0);
+                        } else if candidate.line_num.is_some()
+                            && candidate.line_num == error.line_num
+                        {
+                            push_red_suggestion(false, true, 1);
+                        }
+                    }
+
+                    show_suggestions(suggestions, "expected", Color::Red);
                 }
                 println!("{}", "---".green());
             }
             if !not_found.is_empty() {
-                println!("{}", "--- not found errors (from test file) ---".red());
+                let header = "--- expected in test file but not reported in JSON output ---";
+                println!("{}", header.red());
                 for error in &not_found {
-                    println!("{}", error.render_for_expected());
+                    print_error(error);
+                    let mut suggestions = Vec::new();
+                    for candidate in unexpected.iter().chain(&unimportant) {
+                        let mut push_green_suggestion = |line, msg, rank| {
+                            push_suggestion(
+                                &mut suggestions,
+                                candidate,
+                                candidate.kind != error.kind,
+                                line,
+                                msg,
+                                Color::Green,
+                                rank,
+                            )
+                        };
+                        if candidate.msg.contains(&error.msg) {
+                            push_green_suggestion(candidate.line_num != error.line_num, false, 0);
+                        } else if candidate.line_num.is_some()
+                            && candidate.line_num == error.line_num
+                        {
+                            push_green_suggestion(false, true, 1);
+                        }
+                    }
+
+                    show_suggestions(suggestions, "reported", Color::Green);
                 }
-                println!("{}", "---\n".red());
+                println!("{}", "---".red());
             }
-            panic!("errors differ from expected");
+            panic!(
+                "errors differ from expected\nstatus: {}\ncommand: {}\n",
+                proc_res.status, proc_res.cmdline
+            );
         }
     }
 
@@ -2073,7 +2167,6 @@ impl<'test> TestCx<'test> {
             println!("{}", String::from_utf8_lossy(&output.stdout));
             eprintln!("{}", String::from_utf8_lossy(&output.stderr));
         } else {
-            use colored::Colorize;
             eprintln!("warning: no pager configured, falling back to unified diff");
             eprintln!(
                 "help: try configuring a git pager (e.g. `delta`) with `git config --global core.pager delta`"
diff --git a/src/tools/compiletest/src/runtest/run_make.rs b/src/tools/compiletest/src/runtest/run_make.rs
index 029da1c1898..60e8e16e25e 100644
--- a/src/tools/compiletest/src/runtest/run_make.rs
+++ b/src/tools/compiletest/src/runtest/run_make.rs
@@ -221,6 +221,10 @@ impl TestCx<'_> {
             cmd.env("REMOTE_TEST_CLIENT", remote_test_client);
         }
 
+        if let Some(runner) = &self.config.runner {
+            cmd.env("RUNNER", runner);
+        }
+
         // We don't want RUSTFLAGS set from the outside to interfere with
         // compiler flags set in the test cases:
         cmd.env_remove("RUSTFLAGS");
diff --git a/src/tools/enzyme b/src/tools/enzyme
-Subproject a35f4f773118ccfbd8d05102eb12a34097b1ee5
+Subproject b5098d515d5e1bd0f5470553bc0d18da9794ca8
diff --git a/src/tools/jsondoclint/src/validator.rs b/src/tools/jsondoclint/src/validator.rs
index 8c9e4c8bb3a..0a4051fcbe8 100644
--- a/src/tools/jsondoclint/src/validator.rs
+++ b/src/tools/jsondoclint/src/validator.rs
@@ -271,7 +271,7 @@ impl<'a> Validator<'a> {
             Type::RawPointer { is_mutable: _, type_ } => self.check_type(&**type_),
             Type::BorrowedRef { lifetime: _, is_mutable: _, type_ } => self.check_type(&**type_),
             Type::QualifiedPath { name: _, args, self_type, trait_ } => {
-                self.check_generic_args(&**args);
+                self.check_opt_generic_args(&args);
                 self.check_type(&**self_type);
                 if let Some(trait_) = trait_ {
                     self.check_path(trait_, PathKind::Trait);
@@ -309,13 +309,12 @@ impl<'a> Validator<'a> {
             self.fail(&x.id, ErrorKind::Custom(format!("No entry in '$.paths' for {x:?}")));
         }
 
-        if let Some(args) = &x.args {
-            self.check_generic_args(&**args);
-        }
+        self.check_opt_generic_args(&x.args);
     }
 
-    fn check_generic_args(&mut self, x: &'a GenericArgs) {
-        match x {
+    fn check_opt_generic_args(&mut self, x: &'a Option<Box<GenericArgs>>) {
+        let Some(x) = x else { return };
+        match &**x {
             GenericArgs::AngleBracketed { args, constraints } => {
                 args.iter().for_each(|arg| self.check_generic_arg(arg));
                 constraints.iter().for_each(|bind| self.check_assoc_item_constraint(bind));
@@ -355,7 +354,7 @@ impl<'a> Validator<'a> {
     }
 
     fn check_assoc_item_constraint(&mut self, bind: &'a AssocItemConstraint) {
-        self.check_generic_args(&bind.args);
+        self.check_opt_generic_args(&bind.args);
         match &bind.binding {
             AssocItemConstraintKind::Equality(term) => self.check_term(term),
             AssocItemConstraintKind::Constraint(bounds) => {
diff --git a/src/tools/linkchecker/linkcheck.sh b/src/tools/linkchecker/linkcheck.sh
index 6c1e668a7f0..d230610a6e7 100755
--- a/src/tools/linkchecker/linkcheck.sh
+++ b/src/tools/linkchecker/linkcheck.sh
@@ -98,6 +98,7 @@ then
     nightly_hash=$(rustc +nightly -Vv | grep commit-hash | cut -f2 -d" ")
     url="https://raw.githubusercontent.com/rust-lang/rust"
     mkdir linkchecker
+    curl -o linkchecker/Cargo.lock ${url}/${nightly_hash}/Cargo.lock
     curl -o linkchecker/Cargo.toml ${url}/${nightly_hash}/src/tools/linkchecker/Cargo.toml
     curl -o linkchecker/main.rs ${url}/${nightly_hash}/src/tools/linkchecker/main.rs
 fi
diff --git a/src/tools/lint-docs/Cargo.toml b/src/tools/lint-docs/Cargo.toml
index f1ffda75ac0..e914a2df2ba 100644
--- a/src/tools/lint-docs/Cargo.toml
+++ b/src/tools/lint-docs/Cargo.toml
@@ -7,7 +7,7 @@ description = "A script to extract the lint documentation for the rustc book."
 # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
 
 [dependencies]
-rustc-literal-escaper = "0.0.2"
+rustc-literal-escaper = "0.0.4"
 serde_json = "1.0.57"
 tempfile = "3.1.0"
 walkdir = "2.3.1"
diff --git a/src/tools/lint-docs/src/lib.rs b/src/tools/lint-docs/src/lib.rs
index 6bb18c2bced..b33344ca5dd 100644
--- a/src/tools/lint-docs/src/lib.rs
+++ b/src/tools/lint-docs/src/lib.rs
@@ -4,7 +4,7 @@ use std::fs;
 use std::path::{Path, PathBuf};
 use std::process::Command;
 
-use rustc_literal_escaper::{Mode, unescape_unicode};
+use rustc_literal_escaper::unescape_str;
 use walkdir::WalkDir;
 
 mod groups;
@@ -218,7 +218,7 @@ impl<'a> LintExtractor<'a> {
                         } else if let Some(text) = line.strip_prefix("#[doc = \"") {
                             let escaped = text.strip_suffix("\"]").unwrap();
                             let mut buf = String::new();
-                            unescape_unicode(escaped, Mode::Str, &mut |_, c| match c {
+                            unescape_str(escaped, |_, res| match res {
                                 Ok(c) => buf.push(c),
                                 Err(err) => {
                                     assert!(!err.is_fatal(), "failed to unescape string literal")
diff --git a/src/tools/miri/cargo-miri/src/setup.rs b/src/tools/miri/cargo-miri/src/setup.rs
index b9b58c04f9e..e399f66fbc9 100644
--- a/src/tools/miri/cargo-miri/src/setup.rs
+++ b/src/tools/miri/cargo-miri/src/setup.rs
@@ -83,7 +83,7 @@ pub fn setup(
         SysrootConfig::NoStd
     } else {
         SysrootConfig::WithStd {
-            std_features: ["panic_unwind", "backtrace"].into_iter().map(Into::into).collect(),
+            std_features: ["panic-unwind", "backtrace"].into_iter().map(Into::into).collect(),
         }
     };
     let cargo_cmd = {
diff --git a/src/tools/miri/src/bin/miri.rs b/src/tools/miri/src/bin/miri.rs
index d410d7bcc87..2e82dbee34d 100644
--- a/src/tools/miri/src/bin/miri.rs
+++ b/src/tools/miri/src/bin/miri.rs
@@ -296,6 +296,7 @@ impl rustc_driver::Callbacks for MiriBeRustCompilerCalls {
                                         level: SymbolExportLevel::C,
                                         kind: SymbolExportKind::Text,
                                         used: false,
+                                        rustc_std_internal_symbol: false,
                                     },
                                 ))
                             } else {
diff --git a/src/tools/miri/src/borrow_tracker/stacked_borrows/mod.rs b/src/tools/miri/src/borrow_tracker/stacked_borrows/mod.rs
index bc57ba697b3..b8bcacf7c99 100644
--- a/src/tools/miri/src/borrow_tracker/stacked_borrows/mod.rs
+++ b/src/tools/miri/src/borrow_tracker/stacked_borrows/mod.rs
@@ -814,7 +814,7 @@ trait EvalContextPrivExt<'tcx, 'ecx>: crate::MiriInterpCxExt<'tcx> {
         info: RetagInfo, // diagnostics info about this retag
     ) -> InterpResult<'tcx, MPlaceTy<'tcx>> {
         let this = self.eval_context_mut();
-        let size = this.size_and_align_of_mplace(place)?.map(|(size, _)| size);
+        let size = this.size_and_align_of_val(place)?.map(|(size, _)| size);
         // FIXME: If we cannot determine the size (because the unsized tail is an `extern type`),
         // bail out -- we cannot reasonably figure out which memory range to reborrow.
         // See https://github.com/rust-lang/unsafe-code-guidelines/issues/276.
diff --git a/src/tools/miri/src/borrow_tracker/tree_borrows/mod.rs b/src/tools/miri/src/borrow_tracker/tree_borrows/mod.rs
index ce8fe03ee47..99171b0349e 100644
--- a/src/tools/miri/src/borrow_tracker/tree_borrows/mod.rs
+++ b/src/tools/miri/src/borrow_tracker/tree_borrows/mod.rs
@@ -469,7 +469,7 @@ trait EvalContextPrivExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
         // - if the pointer is not reborrowed (raw pointer) then we override the size
         //   to do a zero-length reborrow.
         let reborrow_size = this
-            .size_and_align_of_mplace(place)?
+            .size_and_align_of_val(place)?
             .map(|(size, _)| size)
             .unwrap_or(place.layout.size);
         trace!("Creating new permission: {:?} with size {:?}", new_perm, reborrow_size);
diff --git a/src/tools/miri/src/eval.rs b/src/tools/miri/src/eval.rs
index 0ad20cefb92..c0dc484187a 100644
--- a/src/tools/miri/src/eval.rs
+++ b/src/tools/miri/src/eval.rs
@@ -11,7 +11,7 @@ use rustc_abi::ExternAbi;
 use rustc_data_structures::fx::{FxHashMap, FxHashSet};
 use rustc_hir::def::Namespace;
 use rustc_hir::def_id::DefId;
-use rustc_middle::ty::layout::{LayoutCx, LayoutOf};
+use rustc_middle::ty::layout::LayoutCx;
 use rustc_middle::ty::{self, Ty, TyCtxt};
 use rustc_session::config::EntryFnType;
 
diff --git a/src/tools/miri/src/helpers.rs b/src/tools/miri/src/helpers.rs
index 4edecc864dd..fb34600fa37 100644
--- a/src/tools/miri/src/helpers.rs
+++ b/src/tools/miri/src/helpers.rs
@@ -489,7 +489,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
         trace!("visit_frozen(place={:?}, size={:?})", *place, size);
         debug_assert_eq!(
             size,
-            this.size_and_align_of_mplace(place)?
+            this.size_and_align_of_val(place)?
                 .map(|(size, _)| size)
                 .unwrap_or_else(|| place.layout.size)
         );
@@ -530,7 +530,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
                     trace!("unsafe_cell_action on {:?}", place.ptr());
                     // We need a size to go on.
                     let unsafe_cell_size = this
-                        .size_and_align_of_mplace(place)?
+                        .size_and_align_of_val(place)?
                         .map(|(size, _)| size)
                         // for extern types, just cover what we can
                         .unwrap_or_else(|| place.layout.size);
diff --git a/src/tools/miri/src/intrinsics/simd.rs b/src/tools/miri/src/intrinsics/simd.rs
index dbe193bdbda..52224f33c73 100644
--- a/src/tools/miri/src/intrinsics/simd.rs
+++ b/src/tools/miri/src/intrinsics/simd.rs
@@ -3,7 +3,6 @@ use rand::Rng;
 use rustc_abi::{Endian, HasDataLayout};
 use rustc_apfloat::{Float, Round};
 use rustc_middle::ty::FloatTy;
-use rustc_middle::ty::layout::LayoutOf;
 use rustc_middle::{mir, ty};
 use rustc_span::{Symbol, sym};
 
diff --git a/src/tools/miri/src/shims/backtrace.rs b/src/tools/miri/src/shims/backtrace.rs
index feb83ca8829..dd00b270b38 100644
--- a/src/tools/miri/src/shims/backtrace.rs
+++ b/src/tools/miri/src/shims/backtrace.rs
@@ -1,5 +1,4 @@
 use rustc_abi::{CanonAbi, FieldIdx, Size};
-use rustc_middle::ty::layout::LayoutOf as _;
 use rustc_middle::ty::{self, Instance, Ty};
 use rustc_span::{BytePos, Loc, Symbol, hygiene};
 use rustc_target::callconv::FnAbi;
diff --git a/src/tools/miri/src/shims/os_str.rs b/src/tools/miri/src/shims/os_str.rs
index 7080edb26a5..b9391a0ffe0 100644
--- a/src/tools/miri/src/shims/os_str.rs
+++ b/src/tools/miri/src/shims/os_str.rs
@@ -7,7 +7,6 @@ use std::os::windows::ffi::{OsStrExt, OsStringExt};
 use std::path::{Path, PathBuf};
 
 use rustc_middle::ty::Ty;
-use rustc_middle::ty::layout::LayoutOf;
 
 use crate::*;
 
diff --git a/src/tools/miri/src/shims/unix/env.rs b/src/tools/miri/src/shims/unix/env.rs
index 62ac7ee3806..604fb0974d2 100644
--- a/src/tools/miri/src/shims/unix/env.rs
+++ b/src/tools/miri/src/shims/unix/env.rs
@@ -6,7 +6,6 @@ use rustc_abi::{FieldIdx, Size};
 use rustc_data_structures::fx::FxHashMap;
 use rustc_index::IndexVec;
 use rustc_middle::ty::Ty;
-use rustc_middle::ty::layout::LayoutOf;
 
 use crate::*;
 
diff --git a/src/tools/miri/src/shims/unix/foreign_items.rs b/src/tools/miri/src/shims/unix/foreign_items.rs
index f34b95e730b..b3c58397a02 100644
--- a/src/tools/miri/src/shims/unix/foreign_items.rs
+++ b/src/tools/miri/src/shims/unix/foreign_items.rs
@@ -3,7 +3,6 @@ use std::str;
 
 use rustc_abi::{CanonAbi, ExternAbi, Size};
 use rustc_middle::ty::Ty;
-use rustc_middle::ty::layout::LayoutOf;
 use rustc_span::Symbol;
 use rustc_target::callconv::FnAbi;
 
diff --git a/src/tools/miri/src/shims/windows/thread.rs b/src/tools/miri/src/shims/windows/thread.rs
index 981742391b9..a155ec65a51 100644
--- a/src/tools/miri/src/shims/windows/thread.rs
+++ b/src/tools/miri/src/shims/windows/thread.rs
@@ -1,5 +1,4 @@
 use rustc_abi::ExternAbi;
-use rustc_middle::ty::layout::LayoutOf;
 
 use self::shims::windows::handle::{EvalContextExt as _, Handle, PseudoHandle};
 use crate::*;
diff --git a/src/tools/miri/src/shims/x86/aesni.rs b/src/tools/miri/src/shims/x86/aesni.rs
index 7191284b5a3..058ca24e730 100644
--- a/src/tools/miri/src/shims/x86/aesni.rs
+++ b/src/tools/miri/src/shims/x86/aesni.rs
@@ -1,6 +1,5 @@
 use rustc_abi::CanonAbi;
 use rustc_middle::ty::Ty;
-use rustc_middle::ty::layout::LayoutOf as _;
 use rustc_span::Symbol;
 use rustc_target::callconv::FnAbi;
 
diff --git a/src/tools/miri/src/shims/x86/avx.rs b/src/tools/miri/src/shims/x86/avx.rs
index 37539fec748..83d23d6ad36 100644
--- a/src/tools/miri/src/shims/x86/avx.rs
+++ b/src/tools/miri/src/shims/x86/avx.rs
@@ -2,7 +2,6 @@ use rustc_abi::CanonAbi;
 use rustc_apfloat::ieee::{Double, Single};
 use rustc_middle::mir;
 use rustc_middle::ty::Ty;
-use rustc_middle::ty::layout::LayoutOf as _;
 use rustc_span::Symbol;
 use rustc_target::callconv::FnAbi;
 
diff --git a/src/tools/miri/src/shims/x86/avx2.rs b/src/tools/miri/src/shims/x86/avx2.rs
index 5dfe5cc2c54..49d5977078b 100644
--- a/src/tools/miri/src/shims/x86/avx2.rs
+++ b/src/tools/miri/src/shims/x86/avx2.rs
@@ -1,7 +1,6 @@
 use rustc_abi::CanonAbi;
 use rustc_middle::mir;
 use rustc_middle::ty::Ty;
-use rustc_middle::ty::layout::LayoutOf as _;
 use rustc_span::Symbol;
 use rustc_target::callconv::FnAbi;
 
diff --git a/src/tools/miri/src/shims/x86/mod.rs b/src/tools/miri/src/shims/x86/mod.rs
index 1e82f521249..fbfe459711e 100644
--- a/src/tools/miri/src/shims/x86/mod.rs
+++ b/src/tools/miri/src/shims/x86/mod.rs
@@ -2,7 +2,6 @@ use rustc_abi::{CanonAbi, FieldIdx, Size};
 use rustc_apfloat::Float;
 use rustc_apfloat::ieee::Single;
 use rustc_middle::ty::Ty;
-use rustc_middle::ty::layout::LayoutOf as _;
 use rustc_middle::{mir, ty};
 use rustc_span::Symbol;
 use rustc_target::callconv::FnAbi;
diff --git a/src/tools/miri/src/shims/x86/sse42.rs b/src/tools/miri/src/shims/x86/sse42.rs
index 830513f0291..7e1e1482ef4 100644
--- a/src/tools/miri/src/shims/x86/sse42.rs
+++ b/src/tools/miri/src/shims/x86/sse42.rs
@@ -1,7 +1,6 @@
 use rustc_abi::{CanonAbi, Size};
 use rustc_middle::mir;
 use rustc_middle::ty::Ty;
-use rustc_middle::ty::layout::LayoutOf as _;
 use rustc_span::Symbol;
 use rustc_target::callconv::FnAbi;
 
diff --git a/src/tools/run-make-support/src/lib.rs b/src/tools/run-make-support/src/lib.rs
index 947f815fd69..67d8c351a59 100644
--- a/src/tools/run-make-support/src/lib.rs
+++ b/src/tools/run-make-support/src/lib.rs
@@ -83,7 +83,7 @@ pub use run::{cmd, run, run_fail, run_with_args};
 
 /// Helpers for checking target information.
 pub use targets::{
-    apple_os, is_aix, is_darwin, is_msvc, is_windows, is_windows_gnu, is_win7, llvm_components_contain,
+    apple_os, is_aix, is_darwin, is_msvc, is_windows, is_windows_gnu, is_windows_msvc, is_win7, llvm_components_contain,
     target, uname,
 };
 
diff --git a/src/tools/run-make-support/src/run.rs b/src/tools/run-make-support/src/run.rs
index 60e711d3402..b95f3a5cfe5 100644
--- a/src/tools/run-make-support/src/run.rs
+++ b/src/tools/run-make-support/src/run.rs
@@ -1,4 +1,4 @@
-use std::ffi::OsStr;
+use std::ffi::{OsStr, OsString};
 use std::path::PathBuf;
 use std::{env, panic};
 
@@ -22,6 +22,20 @@ fn run_common(name: &str, args: Option<&[&str]>) -> Command {
         cmd.arg("0");
         cmd.arg(bin_path);
         cmd
+    } else if let Ok(runner) = std::env::var("RUNNER") {
+        let mut args = split_maybe_args(&runner);
+
+        let prog = args.remove(0);
+        let mut cmd = Command::new(prog);
+
+        for arg in args {
+            cmd.arg(arg);
+        }
+
+        cmd.arg("--");
+        cmd.arg(bin_path);
+
+        cmd
     } else {
         Command::new(bin_path)
     };
@@ -92,3 +106,12 @@ pub fn cmd<S: AsRef<OsStr>>(program: S) -> Command {
     command.env("LC_ALL", "C"); // force english locale
     command
 }
+
+fn split_maybe_args(s: &str) -> Vec<OsString> {
+    // FIXME(132599): implement proper env var/shell argument splitting.
+    s.split(' ')
+        .filter_map(|s| {
+            if s.chars().all(|c| c.is_whitespace()) { None } else { Some(OsString::from(s)) }
+        })
+        .collect()
+}
diff --git a/src/tools/run-make-support/src/targets.rs b/src/tools/run-make-support/src/targets.rs
index 86edbdf750b..1ab2e2ab2be 100644
--- a/src/tools/run-make-support/src/targets.rs
+++ b/src/tools/run-make-support/src/targets.rs
@@ -28,6 +28,12 @@ pub fn is_windows_gnu() -> bool {
     target().ends_with("windows-gnu")
 }
 
+/// Check if target is windows-msvc.
+#[must_use]
+pub fn is_windows_msvc() -> bool {
+    target().ends_with("windows-msvc")
+}
+
 /// Check if target is win7.
 #[must_use]
 pub fn is_win7() -> bool {
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/db.rs b/src/tools/rust-analyzer/crates/hir-def/src/db.rs
index c618e4bdce7..00408e95ae6 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/db.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/db.rs
@@ -11,12 +11,12 @@ use syntax::{AstPtr, ast};
 use triomphe::Arc;
 
 use crate::{
-    AssocItemId, AttrDefId, ConstId, ConstLoc, DefWithBodyId, EnumId, EnumLoc, EnumVariantId,
-    EnumVariantLoc, ExternBlockId, ExternBlockLoc, ExternCrateId, ExternCrateLoc, FunctionId,
-    FunctionLoc, GenericDefId, ImplId, ImplLoc, LocalFieldId, Macro2Id, Macro2Loc, MacroExpander,
-    MacroId, MacroRulesId, MacroRulesLoc, MacroRulesLocFlags, ProcMacroId, ProcMacroLoc, StaticId,
-    StaticLoc, StructId, StructLoc, TraitAliasId, TraitAliasLoc, TraitId, TraitLoc, TypeAliasId,
-    TypeAliasLoc, UnionId, UnionLoc, UseId, UseLoc, VariantId,
+    AssocItemId, AttrDefId, BlockId, BlockLoc, ConstId, ConstLoc, DefWithBodyId, EnumId, EnumLoc,
+    EnumVariantId, EnumVariantLoc, ExternBlockId, ExternBlockLoc, ExternCrateId, ExternCrateLoc,
+    FunctionId, FunctionLoc, GenericDefId, ImplId, ImplLoc, LocalFieldId, Macro2Id, Macro2Loc,
+    MacroExpander, MacroId, MacroRulesId, MacroRulesLoc, MacroRulesLocFlags, ProcMacroId,
+    ProcMacroLoc, StaticId, StaticLoc, StructId, StructLoc, TraitAliasId, TraitAliasLoc, TraitId,
+    TraitLoc, TypeAliasId, TypeAliasLoc, UnionId, UnionLoc, UseId, UseLoc, VariantId,
     attr::{Attrs, AttrsWithOwner},
     expr_store::{
         Body, BodySourceMap, ExpressionStore, ExpressionStoreSourceMap, scope::ExprScopes,
@@ -90,7 +90,10 @@ pub trait InternDatabase: RootQueryDb {
 
     #[salsa::interned]
     fn intern_macro_rules(&self, loc: MacroRulesLoc) -> MacroRulesId;
-    // // endregion: items
+    // endregion: items
+
+    #[salsa::interned]
+    fn intern_block(&self, loc: BlockLoc) -> BlockId;
 }
 
 #[query_group::query_group]
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/expr_store/lower.rs b/src/tools/rust-analyzer/crates/hir-def/src/expr_store/lower.rs
index 03683ec9203..efa1374a446 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/expr_store/lower.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/expr_store/lower.rs
@@ -11,7 +11,7 @@ use base_db::FxIndexSet;
 use cfg::CfgOptions;
 use either::Either;
 use hir_expand::{
-    HirFileId, InFile, Intern, MacroDefId,
+    HirFileId, InFile, MacroDefId,
     mod_path::tool_path,
     name::{AsName, Name},
     span_map::SpanMapRef,
@@ -2148,7 +2148,7 @@ impl ExprCollector<'_> {
     ) -> ExprId {
         let block_id = self.expander.ast_id_map().ast_id_for_block(&block).map(|file_local_id| {
             let ast_id = self.expander.in_file(file_local_id);
-            BlockLoc { ast_id, module: self.module }.intern(self.db)
+            self.db.intern_block(BlockLoc { ast_id, module: self.module })
         });
 
         let (module, def_map) =
@@ -2815,6 +2815,51 @@ impl ExprCollector<'_> {
                 mutability: Mutability::Shared,
             })
         };
+
+        // Assume that rustc version >= 1.89.0 iff lang item `format_arguments` exists
+        // but `format_unsafe_arg` does not
+        let fmt_args =
+            || crate::lang_item::lang_item(self.db, self.module.krate(), LangItem::FormatArguments);
+        let fmt_unsafe_arg =
+            || crate::lang_item::lang_item(self.db, self.module.krate(), LangItem::FormatUnsafeArg);
+        let use_format_args_since_1_89_0 = fmt_args().is_some() && fmt_unsafe_arg().is_none();
+
+        let idx = if use_format_args_since_1_89_0 {
+            self.collect_format_args_impl(
+                syntax_ptr,
+                fmt,
+                hygiene,
+                argmap,
+                lit_pieces,
+                format_options,
+            )
+        } else {
+            self.collect_format_args_before_1_89_0_impl(
+                syntax_ptr,
+                fmt,
+                argmap,
+                lit_pieces,
+                format_options,
+            )
+        };
+
+        self.source_map
+            .template_map
+            .get_or_insert_with(Default::default)
+            .format_args_to_captures
+            .insert(idx, (hygiene, mappings));
+        idx
+    }
+
+    /// `format_args!` expansion implementation for rustc versions < `1.89.0`
+    fn collect_format_args_before_1_89_0_impl(
+        &mut self,
+        syntax_ptr: AstPtr<ast::Expr>,
+        fmt: FormatArgs,
+        argmap: FxIndexSet<(usize, ArgumentType)>,
+        lit_pieces: ExprId,
+        format_options: ExprId,
+    ) -> ExprId {
         let arguments = &*fmt.arguments.arguments;
 
         let args = if arguments.is_empty() {
@@ -2902,19 +2947,181 @@ impl ExprCollector<'_> {
             });
         }
 
-        let idx = self.alloc_expr(
+        self.alloc_expr(
             Expr::Call {
                 callee: new_v1_formatted,
                 args: Box::new([lit_pieces, args, format_options, unsafe_arg_new]),
             },
             syntax_ptr,
-        );
-        self.source_map
-            .template_map
-            .get_or_insert_with(Default::default)
-            .format_args_to_captures
-            .insert(idx, (hygiene, mappings));
-        idx
+        )
+    }
+
+    /// `format_args!` expansion implementation for rustc versions >= `1.89.0`,
+    /// especially since [this PR](https://github.com/rust-lang/rust/pull/140748)
+    fn collect_format_args_impl(
+        &mut self,
+        syntax_ptr: AstPtr<ast::Expr>,
+        fmt: FormatArgs,
+        hygiene: HygieneId,
+        argmap: FxIndexSet<(usize, ArgumentType)>,
+        lit_pieces: ExprId,
+        format_options: ExprId,
+    ) -> ExprId {
+        let arguments = &*fmt.arguments.arguments;
+
+        let (let_stmts, args) = if arguments.is_empty() {
+            (
+                // Generate:
+                //     []
+                vec![],
+                self.alloc_expr_desugared(Expr::Array(Array::ElementList {
+                    elements: Box::default(),
+                })),
+            )
+        } else if argmap.len() == 1 && arguments.len() == 1 {
+            // Only one argument, so we don't need to make the `args` tuple.
+            //
+            // Generate:
+            //     super let args = [<core::fmt::Arguments>::new_display(&arg)];
+            let args = argmap
+                .iter()
+                .map(|&(arg_index, ty)| {
+                    let ref_arg = self.alloc_expr_desugared(Expr::Ref {
+                        expr: arguments[arg_index].expr,
+                        rawness: Rawness::Ref,
+                        mutability: Mutability::Shared,
+                    });
+                    self.make_argument(ref_arg, ty)
+                })
+                .collect();
+            let args =
+                self.alloc_expr_desugared(Expr::Array(Array::ElementList { elements: args }));
+            let args_name = Name::new_symbol_root(sym::args);
+            let args_binding =
+                self.alloc_binding(args_name.clone(), BindingAnnotation::Unannotated, hygiene);
+            let args_pat = self.alloc_pat_desugared(Pat::Bind { id: args_binding, subpat: None });
+            self.add_definition_to_binding(args_binding, args_pat);
+            // TODO: We don't have `super let` yet.
+            let let_stmt = Statement::Let {
+                pat: args_pat,
+                type_ref: None,
+                initializer: Some(args),
+                else_branch: None,
+            };
+            (vec![let_stmt], self.alloc_expr_desugared(Expr::Path(Path::from(args_name))))
+        } else {
+            // Generate:
+            //     super let args = (&arg0, &arg1, &...);
+            let args_name = Name::new_symbol_root(sym::args);
+            let args_binding =
+                self.alloc_binding(args_name.clone(), BindingAnnotation::Unannotated, hygiene);
+            let args_pat = self.alloc_pat_desugared(Pat::Bind { id: args_binding, subpat: None });
+            self.add_definition_to_binding(args_binding, args_pat);
+            let elements = arguments
+                .iter()
+                .map(|arg| {
+                    self.alloc_expr_desugared(Expr::Ref {
+                        expr: arg.expr,
+                        rawness: Rawness::Ref,
+                        mutability: Mutability::Shared,
+                    })
+                })
+                .collect();
+            let args_tuple = self.alloc_expr_desugared(Expr::Tuple { exprs: elements });
+            // TODO: We don't have `super let` yet
+            let let_stmt1 = Statement::Let {
+                pat: args_pat,
+                type_ref: None,
+                initializer: Some(args_tuple),
+                else_branch: None,
+            };
+
+            // Generate:
+            //     super let args = [
+            //         <core::fmt::Argument>::new_display(args.0),
+            //         <core::fmt::Argument>::new_lower_hex(args.1),
+            //         <core::fmt::Argument>::new_debug(args.0),
+            //         …
+            //     ];
+            let args = argmap
+                .iter()
+                .map(|&(arg_index, ty)| {
+                    let args_ident_expr =
+                        self.alloc_expr_desugared(Expr::Path(args_name.clone().into()));
+                    let arg = self.alloc_expr_desugared(Expr::Field {
+                        expr: args_ident_expr,
+                        name: Name::new_tuple_field(arg_index),
+                    });
+                    self.make_argument(arg, ty)
+                })
+                .collect();
+            let array =
+                self.alloc_expr_desugared(Expr::Array(Array::ElementList { elements: args }));
+            let args_binding =
+                self.alloc_binding(args_name.clone(), BindingAnnotation::Unannotated, hygiene);
+            let args_pat = self.alloc_pat_desugared(Pat::Bind { id: args_binding, subpat: None });
+            self.add_definition_to_binding(args_binding, args_pat);
+            let let_stmt2 = Statement::Let {
+                pat: args_pat,
+                type_ref: None,
+                initializer: Some(array),
+                else_branch: None,
+            };
+            (vec![let_stmt1, let_stmt2], self.alloc_expr_desugared(Expr::Path(args_name.into())))
+        };
+
+        // Generate:
+        //     &args
+        let args = self.alloc_expr_desugared(Expr::Ref {
+            expr: args,
+            rawness: Rawness::Ref,
+            mutability: Mutability::Shared,
+        });
+
+        let call_block = {
+            // Generate:
+            //     unsafe {
+            //         <core::fmt::Arguments>::new_v1_formatted(
+            //             lit_pieces,
+            //             args,
+            //             format_options,
+            //         )
+            //     }
+
+            let new_v1_formatted = LangItem::FormatArguments.ty_rel_path(
+                self.db,
+                self.module.krate(),
+                Name::new_symbol_root(sym::new_v1_formatted),
+            );
+            let new_v1_formatted =
+                self.alloc_expr_desugared(new_v1_formatted.map_or(Expr::Missing, Expr::Path));
+            let args = [lit_pieces, args, format_options];
+            let call = self
+                .alloc_expr_desugared(Expr::Call { callee: new_v1_formatted, args: args.into() });
+
+            Expr::Unsafe { id: None, statements: Box::default(), tail: Some(call) }
+        };
+
+        if !let_stmts.is_empty() {
+            // Generate:
+            //     {
+            //         super let …
+            //         super let …
+            //         <core::fmt::Arguments>::new_…(…)
+            //     }
+            let call = self.alloc_expr_desugared(call_block);
+            self.alloc_expr(
+                Expr::Block {
+                    id: None,
+                    statements: let_stmts.into(),
+                    tail: Some(call),
+                    label: None,
+                },
+                syntax_ptr,
+            )
+        } else {
+            self.alloc_expr(call_block, syntax_ptr)
+        }
     }
 
     /// Generate a hir expression for a format_args placeholder specification.
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/expr_store/tests/body.rs b/src/tools/rust-analyzer/crates/hir-def/src/expr_store/tests/body.rs
index 29e249b07a7..927e280d739 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/expr_store/tests/body.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/expr_store/tests/body.rs
@@ -178,14 +178,14 @@ fn main() {
 }
 
 #[test]
-fn desugar_builtin_format_args() {
+fn desugar_builtin_format_args_before_1_89_0() {
     let (db, body, def) = lower(
         r#"
-//- minicore: fmt
+//- minicore: fmt_before_1_89_0
 fn main() {
     let are = "are";
     let count = 10;
-    builtin#format_args("\u{1b}hello {count:02} {} friends, we {are:?} {0}{last}", "fancy", last = "!");
+    builtin#format_args("\u{1b}hello {count:02} {} friends, we {are:?} {0}{last}", "fancy", orphan = (), last = "!");
 }
 "#,
     );
@@ -249,8 +249,11 @@ fn main() {
                         builtin#lang(Count::Implied),
                     ),
                 ],
-                unsafe {
-                    builtin#lang(UnsafeArg::new)()
+                {
+                    ();
+                    unsafe {
+                        builtin#lang(UnsafeArg::new)()
+                    }
                 },
             );
         }"#]]
@@ -258,6 +261,89 @@ fn main() {
 }
 
 #[test]
+fn desugar_builtin_format_args() {
+    let (db, body, def) = lower(
+        r#"
+//- minicore: fmt
+fn main() {
+    let are = "are";
+    let count = 10;
+    builtin#format_args("\u{1b}hello {count:02} {} friends, we {are:?} {0}{last}", "fancy", orphan = (), last = "!");
+}
+"#,
+    );
+
+    expect![[r#"
+        fn main() {
+            let are = "are";
+            let count = 10;
+            {
+                let args = (&"fancy", &(), &"!", &count, &are, );
+                let args = [
+                    builtin#lang(Argument::new_display)(
+                        args.3,
+                    ), builtin#lang(Argument::new_display)(
+                        args.0,
+                    ), builtin#lang(Argument::new_debug)(
+                        args.4,
+                    ), builtin#lang(Argument::new_display)(
+                        args.2,
+                    ),
+                ];
+                unsafe {
+                    builtin#lang(Arguments::new_v1_formatted)(
+                        &[
+                            "\u{1b}hello ", " ", " friends, we ", " ", "",
+                        ],
+                        &args,
+                        &[
+                            builtin#lang(Placeholder::new)(
+                                0usize,
+                                ' ',
+                                builtin#lang(Alignment::Unknown),
+                                8u32,
+                                builtin#lang(Count::Implied),
+                                builtin#lang(Count::Is)(
+                                    2,
+                                ),
+                            ), builtin#lang(Placeholder::new)(
+                                1usize,
+                                ' ',
+                                builtin#lang(Alignment::Unknown),
+                                0u32,
+                                builtin#lang(Count::Implied),
+                                builtin#lang(Count::Implied),
+                            ), builtin#lang(Placeholder::new)(
+                                2usize,
+                                ' ',
+                                builtin#lang(Alignment::Unknown),
+                                0u32,
+                                builtin#lang(Count::Implied),
+                                builtin#lang(Count::Implied),
+                            ), builtin#lang(Placeholder::new)(
+                                1usize,
+                                ' ',
+                                builtin#lang(Alignment::Unknown),
+                                0u32,
+                                builtin#lang(Count::Implied),
+                                builtin#lang(Count::Implied),
+                            ), builtin#lang(Placeholder::new)(
+                                3usize,
+                                ' ',
+                                builtin#lang(Alignment::Unknown),
+                                0u32,
+                                builtin#lang(Count::Implied),
+                                builtin#lang(Count::Implied),
+                            ),
+                        ],
+                    )
+                }
+            };
+        }"#]]
+    .assert_eq(&body.pretty_print(&db, def, Edition::CURRENT))
+}
+
+#[test]
 fn test_macro_hygiene() {
     let (db, body, def) = lower(
         r##"
@@ -295,29 +381,31 @@ impl SsrError {
     expect![[r#"
         fn main() {
             _ = ra_test_fixture::error::SsrError::new(
-                builtin#lang(Arguments::new_v1_formatted)(
-                    &[
-                        "Failed to resolve path `", "`",
-                    ],
-                    &[
+                {
+                    let args = [
                         builtin#lang(Argument::new_display)(
                             &node.text(),
                         ),
-                    ],
-                    &[
-                        builtin#lang(Placeholder::new)(
-                            0usize,
-                            ' ',
-                            builtin#lang(Alignment::Unknown),
-                            0u32,
-                            builtin#lang(Count::Implied),
-                            builtin#lang(Count::Implied),
-                        ),
-                    ],
+                    ];
                     unsafe {
-                        builtin#lang(UnsafeArg::new)()
-                    },
-                ),
+                        builtin#lang(Arguments::new_v1_formatted)(
+                            &[
+                                "Failed to resolve path `", "`",
+                            ],
+                            &args,
+                            &[
+                                builtin#lang(Placeholder::new)(
+                                    0usize,
+                                    ' ',
+                                    builtin#lang(Alignment::Unknown),
+                                    0u32,
+                                    builtin#lang(Count::Implied),
+                                    builtin#lang(Count::Implied),
+                                ),
+                            ],
+                        )
+                    }
+                },
             );
         }"#]]
     .assert_eq(&body.pretty_print(&db, def, Edition::CURRENT))
@@ -327,7 +415,7 @@ impl SsrError {
 fn regression_10300() {
     let (db, body, def) = lower(
         r#"
-//- minicore: concat, panic
+//- minicore: concat, panic, fmt_before_1_89_0
 mod private {
     pub use core::concat;
 }
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/expr_store/tests/body/block.rs b/src/tools/rust-analyzer/crates/hir-def/src/expr_store/tests/body/block.rs
index bb0b70bc5bf..c7707378a5b 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/expr_store/tests/body/block.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/expr_store/tests/body/block.rs
@@ -189,8 +189,8 @@ fn f() {
 }
     "#,
         expect![[r#"
-            BlockIdLt { [salsa id]: Id(3c01) } in BlockRelativeModuleId { block: Some(BlockIdLt { [salsa id]: Id(3c00) }), local_id: Idx::<ModuleData>(1) }
-            BlockIdLt { [salsa id]: Id(3c00) } in BlockRelativeModuleId { block: None, local_id: Idx::<ModuleData>(0) }
+            BlockId(3c01) in BlockRelativeModuleId { block: Some(BlockId(3c00)), local_id: Idx::<ModuleData>(1) }
+            BlockId(3c00) in BlockRelativeModuleId { block: None, local_id: Idx::<ModuleData>(0) }
             crate scope
         "#]],
     );
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/lib.rs b/src/tools/rust-analyzer/crates/hir-def/src/lib.rs
index a542214d303..a562f2d0af2 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/lib.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/lib.rs
@@ -384,26 +384,7 @@ pub struct BlockLoc {
     /// The containing module.
     pub module: ModuleId,
 }
-#[salsa_macros::tracked(debug)]
-#[derive(PartialOrd, Ord)]
-pub struct BlockIdLt<'db> {
-    pub loc: BlockLoc,
-}
-pub type BlockId = BlockIdLt<'static>;
-impl hir_expand::Intern for BlockLoc {
-    type Database = dyn DefDatabase;
-    type ID = BlockId;
-    fn intern(self, db: &Self::Database) -> Self::ID {
-        unsafe { std::mem::transmute::<BlockIdLt<'_>, BlockId>(BlockIdLt::new(db, self)) }
-    }
-}
-impl hir_expand::Lookup for BlockId {
-    type Database = dyn DefDatabase;
-    type Data = BlockLoc;
-    fn lookup(&self, db: &Self::Database) -> Self::Data {
-        self.loc(db)
-    }
-}
+impl_intern!(BlockId, BlockLoc, intern_block, lookup_intern_block);
 
 /// A `ModuleId` that is always a crate's root module.
 #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
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 d1432cacf8d..b756bb859d3 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
@@ -1230,11 +1230,15 @@ impl InferenceContext<'_> {
                     self.select_from_expr(*expr);
                 }
             }
+            Expr::Let { pat: _, expr } => {
+                self.walk_expr(*expr);
+                let place = self.place_of_expr(*expr);
+                self.ref_expr(*expr, place);
+            }
             Expr::UnaryOp { expr, op: _ }
             | Expr::Array(Array::Repeat { initializer: expr, repeat: _ })
             | Expr::Await { expr }
             | Expr::Loop { body: expr, label: _ }
-            | Expr::Let { pat: _, expr }
             | Expr::Box { expr }
             | Expr::Cast { expr, type_ref: _ } => {
                 self.consume_expr(*expr);
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/layout.rs b/src/tools/rust-analyzer/crates/hir-ty/src/layout.rs
index c253fe25672..c58bd1b773e 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/layout.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/layout.rs
@@ -268,7 +268,7 @@ pub fn layout_of_ty_query(
 
             // let pointee = tcx.normalize_erasing_regions(param_env, pointee);
             // if pointee.is_sized(tcx.at(DUMMY_SP), param_env) {
-            //     return Ok(tcx.mk_layout(LayoutS::scalar(cx, data_ptr)));
+            //     return Ok(tcx.mk_layout(LayoutData::scalar(cx, data_ptr)));
             // }
 
             let mut unsized_part = struct_tail_erasing_lifetimes(db, pointee.clone());
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/tests/closure_captures.rs b/src/tools/rust-analyzer/crates/hir-ty/src/tests/closure_captures.rs
index 88d21be81ea..7fb981752de 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/tests/closure_captures.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/tests/closure_captures.rs
@@ -444,3 +444,22 @@ fn main() {
         expect!["99..165;49..54;120..121,133..134 ByRef(Mut { kind: Default }) a &'? mut A"],
     );
 }
+
+#[test]
+fn let_binding_is_a_ref_capture() {
+    check_closure_captures(
+        r#"
+//- minicore:copy
+struct S;
+fn main() {
+    let mut s = S;
+    let s_ref = &mut s;
+    let closure = || {
+        if let ref cb = s_ref {
+        }
+    };
+}
+"#,
+        expect!["83..135;49..54;112..117 ByRef(Shared) s_ref &'? &'? mut S"],
+    );
+}
diff --git a/src/tools/rust-analyzer/crates/hir/src/attrs.rs b/src/tools/rust-analyzer/crates/hir/src/attrs.rs
index b1cf30b98f5..0bce69a179b 100644
--- a/src/tools/rust-analyzer/crates/hir/src/attrs.rs
+++ b/src/tools/rust-analyzer/crates/hir/src/attrs.rs
@@ -242,9 +242,9 @@ fn resolve_assoc_or_field(
     resolve_field(db, variant_def, name, ns)
 }
 
-fn resolve_assoc_item(
-    db: &dyn HirDatabase,
-    ty: &Type,
+fn resolve_assoc_item<'db>(
+    db: &'db dyn HirDatabase,
+    ty: &Type<'db>,
     name: &Name,
     ns: Option<Namespace>,
 ) -> Option<DocLinkDef> {
@@ -256,10 +256,10 @@ fn resolve_assoc_item(
     })
 }
 
-fn resolve_impl_trait_item(
-    db: &dyn HirDatabase,
+fn resolve_impl_trait_item<'db>(
+    db: &'db dyn HirDatabase,
     resolver: Resolver<'_>,
-    ty: &Type,
+    ty: &Type<'db>,
     name: &Name,
     ns: Option<Namespace>,
 ) -> Option<DocLinkDef> {
diff --git a/src/tools/rust-analyzer/crates/hir/src/diagnostics.rs b/src/tools/rust-analyzer/crates/hir/src/diagnostics.rs
index f7b140e03d4..074bde91fb6 100644
--- a/src/tools/rust-analyzer/crates/hir/src/diagnostics.rs
+++ b/src/tools/rust-analyzer/crates/hir/src/diagnostics.rs
@@ -36,15 +36,15 @@ pub use hir_ty::{
 };
 
 macro_rules! diagnostics {
-    ($($diag:ident,)*) => {
+    ($($diag:ident $(<$lt:lifetime>)?,)*) => {
         #[derive(Debug)]
-        pub enum AnyDiagnostic {$(
-            $diag(Box<$diag>),
+        pub enum AnyDiagnostic<'db> {$(
+            $diag(Box<$diag $(<$lt>)?>),
         )*}
 
         $(
-            impl From<$diag> for AnyDiagnostic {
-                fn from(d: $diag) -> AnyDiagnostic {
+            impl<'db> From<$diag $(<$lt>)?> for AnyDiagnostic<'db> {
+                fn from(d: $diag $(<$lt>)?) -> AnyDiagnostic<'db> {
                     AnyDiagnostic::$diag(Box::new(d))
                 }
             }
@@ -69,12 +69,12 @@ macro_rules! diagnostics {
 diagnostics![
     AwaitOutsideOfAsync,
     BreakOutsideOfLoop,
-    CastToUnsized,
-    ExpectedFunction,
+    CastToUnsized<'db>,
+    ExpectedFunction<'db>,
     InactiveCode,
     IncoherentImpl,
     IncorrectCase,
-    InvalidCast,
+    InvalidCast<'db>,
     InvalidDeriveTarget,
     MacroDefError,
     MacroError,
@@ -85,7 +85,7 @@ diagnostics![
     MissingFields,
     MissingMatchArms,
     MissingUnsafe,
-    MovedOutOfRef,
+    MovedOutOfRef<'db>,
     NeedMut,
     NonExhaustiveLet,
     NoSuchField,
@@ -98,17 +98,17 @@ diagnostics![
     TraitImplMissingAssocItems,
     TraitImplOrphan,
     TraitImplRedundantAssocItems,
-    TypedHole,
-    TypeMismatch,
+    TypedHole<'db>,
+    TypeMismatch<'db>,
     UndeclaredLabel,
     UnimplementedBuiltinMacro,
     UnreachableLabel,
     UnresolvedAssocItem,
     UnresolvedExternCrate,
-    UnresolvedField,
+    UnresolvedField<'db>,
     UnresolvedImport,
     UnresolvedMacroCall,
-    UnresolvedMethodCall,
+    UnresolvedMethodCall<'db>,
     UnresolvedModule,
     UnresolvedIdent,
     UnusedMut,
@@ -130,9 +130,9 @@ pub struct BreakOutsideOfLoop {
 }
 
 #[derive(Debug)]
-pub struct TypedHole {
+pub struct TypedHole<'db> {
     pub expr: InFile<ExprOrPatPtr>,
-    pub expected: Type,
+    pub expected: Type<'db>,
 }
 
 #[derive(Debug)]
@@ -242,25 +242,25 @@ pub struct MismatchedTupleStructPatArgCount {
 }
 
 #[derive(Debug)]
-pub struct ExpectedFunction {
+pub struct ExpectedFunction<'db> {
     pub call: InFile<ExprOrPatPtr>,
-    pub found: Type,
+    pub found: Type<'db>,
 }
 
 #[derive(Debug)]
-pub struct UnresolvedField {
+pub struct UnresolvedField<'db> {
     pub expr: InFile<ExprOrPatPtr>,
-    pub receiver: Type,
+    pub receiver: Type<'db>,
     pub name: Name,
     pub method_with_same_name_exists: bool,
 }
 
 #[derive(Debug)]
-pub struct UnresolvedMethodCall {
+pub struct UnresolvedMethodCall<'db> {
     pub expr: InFile<ExprOrPatPtr>,
-    pub receiver: Type,
+    pub receiver: Type<'db>,
     pub name: Name,
-    pub field_with_same_name: Option<Type>,
+    pub field_with_same_name: Option<Type<'db>>,
     pub assoc_func_with_same_name: Option<Function>,
 }
 
@@ -329,10 +329,10 @@ pub struct NonExhaustiveLet {
 }
 
 #[derive(Debug)]
-pub struct TypeMismatch {
+pub struct TypeMismatch<'db> {
     pub expr_or_pat: InFile<ExprOrPatPtr>,
-    pub expected: Type,
-    pub actual: Type,
+    pub expected: Type<'db>,
+    pub actual: Type<'db>,
 }
 
 #[derive(Debug)]
@@ -352,8 +352,8 @@ pub struct UnusedVariable {
 }
 
 #[derive(Debug)]
-pub struct MovedOutOfRef {
-    pub ty: Type,
+pub struct MovedOutOfRef<'db> {
+    pub ty: Type<'db>,
     pub span: InFile<SyntaxNodePtr>,
 }
 
@@ -403,17 +403,17 @@ pub struct RemoveUnnecessaryElse {
 }
 
 #[derive(Debug)]
-pub struct CastToUnsized {
+pub struct CastToUnsized<'db> {
     pub expr: InFile<ExprOrPatPtr>,
-    pub cast_ty: Type,
+    pub cast_ty: Type<'db>,
 }
 
 #[derive(Debug)]
-pub struct InvalidCast {
+pub struct InvalidCast<'db> {
     pub expr: InFile<ExprOrPatPtr>,
     pub error: CastError,
-    pub expr_ty: Type,
-    pub cast_ty: Type,
+    pub expr_ty: Type<'db>,
+    pub cast_ty: Type<'db>,
 }
 
 #[derive(Debug)]
@@ -482,12 +482,12 @@ pub struct IncorrectGenericsOrder {
     pub expected_kind: GenericArgKind,
 }
 
-impl AnyDiagnostic {
+impl<'db> AnyDiagnostic<'db> {
     pub(crate) fn body_validation_diagnostic(
-        db: &dyn HirDatabase,
+        db: &'db dyn HirDatabase,
         diagnostic: BodyValidationDiagnostic,
         source_map: &hir_def::expr_store::BodySourceMap,
-    ) -> Option<AnyDiagnostic> {
+    ) -> Option<AnyDiagnostic<'db>> {
         match diagnostic {
             BodyValidationDiagnostic::RecordMissingFields { record, variant, missed_fields } => {
                 let variant_data = variant.variant_data(db);
@@ -618,12 +618,12 @@ impl AnyDiagnostic {
     }
 
     pub(crate) fn inference_diagnostic(
-        db: &dyn HirDatabase,
+        db: &'db dyn HirDatabase,
         def: DefWithBodyId,
         d: &InferenceDiagnostic,
         source_map: &hir_def::expr_store::BodySourceMap,
         sig_map: &hir_def::expr_store::ExpressionStoreSourceMap,
-    ) -> Option<AnyDiagnostic> {
+    ) -> Option<AnyDiagnostic<'db>> {
         let expr_syntax = |expr| {
             source_map
                 .expr_syntax(expr)
@@ -819,7 +819,7 @@ impl AnyDiagnostic {
     fn path_diagnostic(
         diag: &PathLoweringDiagnostic,
         path: InFile<ast::Path>,
-    ) -> Option<AnyDiagnostic> {
+    ) -> Option<AnyDiagnostic<'db>> {
         Some(match *diag {
             PathLoweringDiagnostic::GenericArgsProhibited { segment, reason } => {
                 let segment = hir_segment_to_ast_segment(&path.value, segment)?;
@@ -912,8 +912,8 @@ impl AnyDiagnostic {
     pub(crate) fn ty_diagnostic(
         diag: &TyLoweringDiagnostic,
         source_map: &ExpressionStoreSourceMap,
-        db: &dyn HirDatabase,
-    ) -> Option<AnyDiagnostic> {
+        db: &'db dyn HirDatabase,
+    ) -> Option<AnyDiagnostic<'db>> {
         let Ok(source) = source_map.type_syntax(diag.source) else {
             stdx::never!("error on synthetic type syntax");
             return None;
diff --git a/src/tools/rust-analyzer/crates/hir/src/display.rs b/src/tools/rust-analyzer/crates/hir/src/display.rs
index 124ab8e274a..112558bdd04 100644
--- a/src/tools/rust-analyzer/crates/hir/src/display.rs
+++ b/src/tools/rust-analyzer/crates/hir/src/display.rs
@@ -431,7 +431,7 @@ impl HirDisplay for Variant {
     }
 }
 
-impl HirDisplay for Type {
+impl HirDisplay for Type<'_> {
     fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> {
         self.ty.hir_fmt(f)
     }
@@ -743,7 +743,7 @@ impl HirDisplay for Static {
     }
 }
 
-impl HirDisplay for TraitRef {
+impl HirDisplay for TraitRef<'_> {
     fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> {
         self.trait_ref.hir_fmt(f)
     }
diff --git a/src/tools/rust-analyzer/crates/hir/src/has_source.rs b/src/tools/rust-analyzer/crates/hir/src/has_source.rs
index fe7429c8672..4767d4792e7 100644
--- a/src/tools/rust-analyzer/crates/hir/src/has_source.rs
+++ b/src/tools/rust-analyzer/crates/hir/src/has_source.rs
@@ -225,7 +225,7 @@ impl HasSource for LocalSource {
     }
 }
 
-impl HasSource for Param {
+impl HasSource for Param<'_> {
     type Ast = Either<ast::SelfParam, ast::Param>;
 
     fn source(self, db: &dyn HirDatabase) -> Option<InFile<Self::Ast>> {
diff --git a/src/tools/rust-analyzer/crates/hir/src/lib.rs b/src/tools/rust-analyzer/crates/hir/src/lib.rs
index adae335627b..3b39707cf60 100644
--- a/src/tools/rust-analyzer/crates/hir/src/lib.rs
+++ b/src/tools/rust-analyzer/crates/hir/src/lib.rs
@@ -84,7 +84,7 @@ use nameres::diagnostics::DefDiagnosticKind;
 use rustc_hash::FxHashSet;
 use smallvec::SmallVec;
 use span::{AstIdNode, Edition, FileId};
-use stdx::{format_to, impl_from, never};
+use stdx::{format_to, impl_from, never, variance::PhantomCovariantLifetime};
 use syntax::{
     AstNode, AstPtr, SmolStr, SyntaxNode, SyntaxNodePtr, T, TextRange, ToSmolStr,
     ast::{self, HasAttrs as _, HasName, HasVisibility as _},
@@ -400,7 +400,11 @@ impl ModuleDef {
         Some(name)
     }
 
-    pub fn diagnostics(self, db: &dyn HirDatabase, style_lints: bool) -> Vec<AnyDiagnostic> {
+    pub fn diagnostics<'db>(
+        self,
+        db: &'db dyn HirDatabase,
+        style_lints: bool,
+    ) -> Vec<AnyDiagnostic<'db>> {
         let id = match self {
             ModuleDef::Adt(it) => match it {
                 Adt::Struct(it) => it.id.into(),
@@ -612,10 +616,10 @@ impl Module {
     }
 
     /// Fills `acc` with the module's diagnostics.
-    pub fn diagnostics(
+    pub fn diagnostics<'db>(
         self,
-        db: &dyn HirDatabase,
-        acc: &mut Vec<AnyDiagnostic>,
+        db: &'db dyn HirDatabase,
+        acc: &mut Vec<AnyDiagnostic<'db>>,
         style_lints: bool,
     ) {
         let _p = tracing::info_span!("diagnostics", name = ?self.name(db)).entered();
@@ -970,10 +974,10 @@ impl Module {
     }
 }
 
-fn macro_call_diagnostics(
-    db: &dyn HirDatabase,
+fn macro_call_diagnostics<'db>(
+    db: &'db dyn HirDatabase,
     macro_call_id: MacroCallId,
-    acc: &mut Vec<AnyDiagnostic>,
+    acc: &mut Vec<AnyDiagnostic<'db>>,
 ) {
     let Some(e) = db.parse_macro_expansion_error(macro_call_id) else {
         return;
@@ -1010,7 +1014,11 @@ fn macro_call_diagnostics(
     }
 }
 
-fn emit_macro_def_diagnostics(db: &dyn HirDatabase, acc: &mut Vec<AnyDiagnostic>, m: Macro) {
+fn emit_macro_def_diagnostics<'db>(
+    db: &'db dyn HirDatabase,
+    acc: &mut Vec<AnyDiagnostic<'db>>,
+    m: Macro,
+) {
     let id = db.macro_def(m.id);
     if let hir_expand::db::TokenExpander::DeclarativeMacro(expander) = db.macro_expander(id) {
         if let Some(e) = expander.mac.err() {
@@ -1030,18 +1038,18 @@ fn emit_macro_def_diagnostics(db: &dyn HirDatabase, acc: &mut Vec<AnyDiagnostic>
     }
 }
 
-fn emit_def_diagnostic(
-    db: &dyn HirDatabase,
-    acc: &mut Vec<AnyDiagnostic>,
+fn emit_def_diagnostic<'db>(
+    db: &'db dyn HirDatabase,
+    acc: &mut Vec<AnyDiagnostic<'db>>,
     diag: &DefDiagnostic,
     edition: Edition,
 ) {
     emit_def_diagnostic_(db, acc, &diag.kind, edition)
 }
 
-fn emit_def_diagnostic_(
-    db: &dyn HirDatabase,
-    acc: &mut Vec<AnyDiagnostic>,
+fn emit_def_diagnostic_<'db>(
+    db: &'db dyn HirDatabase,
+    acc: &mut Vec<AnyDiagnostic<'db>>,
     diag: &DefDiagnosticKind,
     edition: Edition,
 ) {
@@ -1251,14 +1259,18 @@ impl TupleField {
         Name::new_tuple_field(self.index as usize)
     }
 
-    pub fn ty(&self, db: &dyn HirDatabase) -> Type {
+    pub fn ty<'db>(&self, db: &'db dyn HirDatabase) -> Type<'db> {
         let ty = db.infer(self.owner).tuple_field_access_types[&self.tuple]
             .as_slice(Interner)
             .get(self.index as usize)
             .and_then(|arg| arg.ty(Interner))
             .cloned()
             .unwrap_or_else(|| TyKind::Error.intern(Interner));
-        Type { env: db.trait_environment_for_body(self.owner), ty }
+        Type {
+            env: db.trait_environment_for_body(self.owner),
+            ty,
+            _pd: PhantomCovariantLifetime::new(),
+        }
     }
 }
 
@@ -1309,7 +1321,7 @@ impl Field {
     /// Returns the type as in the signature of the struct (i.e., with
     /// placeholder types for type parameters). Only use this in the context of
     /// the field definition.
-    pub fn ty(&self, db: &dyn HirDatabase) -> Type {
+    pub fn ty<'db>(&self, db: &'db dyn HirDatabase) -> Type<'db> {
         let var_id = self.parent.into();
         let generic_def_id: GenericDefId = match self.parent {
             VariantDef::Struct(it) => it.id.into(),
@@ -1322,7 +1334,11 @@ impl Field {
     }
 
     // FIXME: Find better API to also handle const generics
-    pub fn ty_with_args(&self, db: &dyn HirDatabase, generics: impl Iterator<Item = Type>) -> Type {
+    pub fn ty_with_args<'db>(
+        &self,
+        db: &'db dyn HirDatabase,
+        generics: impl Iterator<Item = Type<'db>>,
+    ) -> Type<'db> {
         let var_id = self.parent.into();
         let def_id: AdtId = match self.parent {
             VariantDef::Struct(it) => it.id.into(),
@@ -1394,15 +1410,15 @@ impl Struct {
             .collect()
     }
 
-    pub fn ty(self, db: &dyn HirDatabase) -> Type {
+    pub fn ty(self, db: &dyn HirDatabase) -> Type<'_> {
         Type::from_def(db, self.id)
     }
 
-    pub fn ty_placeholders(self, db: &dyn HirDatabase) -> Type {
+    pub fn ty_placeholders(self, db: &dyn HirDatabase) -> Type<'_> {
         Type::from_def_placeholders(db, self.id)
     }
 
-    pub fn constructor_ty(self, db: &dyn HirDatabase) -> Type {
+    pub fn constructor_ty(self, db: &dyn HirDatabase) -> Type<'_> {
         Type::from_value_def(db, self.id)
     }
 
@@ -1449,15 +1465,15 @@ impl Union {
         Module { id: self.id.lookup(db).container }
     }
 
-    pub fn ty(self, db: &dyn HirDatabase) -> Type {
+    pub fn ty(self, db: &dyn HirDatabase) -> Type<'_> {
         Type::from_def(db, self.id)
     }
 
-    pub fn ty_placeholders(self, db: &dyn HirDatabase) -> Type {
+    pub fn ty_placeholders(self, db: &dyn HirDatabase) -> Type<'_> {
         Type::from_def_placeholders(db, self.id)
     }
 
-    pub fn constructor_ty(self, db: &dyn HirDatabase) -> Type {
+    pub fn constructor_ty(self, db: &dyn HirDatabase) -> Type<'_> {
         Type::from_value_def(db, self.id)
     }
 
@@ -1515,16 +1531,16 @@ impl Enum {
         db.enum_signature(self.id).repr
     }
 
-    pub fn ty(self, db: &dyn HirDatabase) -> Type {
+    pub fn ty<'db>(self, db: &'db dyn HirDatabase) -> Type<'db> {
         Type::from_def(db, self.id)
     }
 
-    pub fn ty_placeholders(self, db: &dyn HirDatabase) -> Type {
+    pub fn ty_placeholders<'db>(self, db: &'db dyn HirDatabase) -> Type<'db> {
         Type::from_def_placeholders(db, self.id)
     }
 
     /// The type of the enum variant bodies.
-    pub fn variant_body_ty(self, db: &dyn HirDatabase) -> Type {
+    pub fn variant_body_ty<'db>(self, db: &'db dyn HirDatabase) -> Type<'db> {
         Type::new_for_crate(
             self.id.lookup(db).container.krate(),
             TyBuilder::builtin(match db.enum_signature(self.id).variant_body_type() {
@@ -1599,7 +1615,7 @@ impl Variant {
         self.id.lookup(db).parent.into()
     }
 
-    pub fn constructor_ty(self, db: &dyn HirDatabase) -> Type {
+    pub fn constructor_ty(self, db: &dyn HirDatabase) -> Type<'_> {
         Type::from_value_def(db, self.id)
     }
 
@@ -1701,14 +1717,18 @@ impl Adt {
     /// Turns this ADT into a type. Any type parameters of the ADT will be
     /// turned into unknown types, which is good for e.g. finding the most
     /// general set of completions, but will not look very nice when printed.
-    pub fn ty(self, db: &dyn HirDatabase) -> Type {
+    pub fn ty(self, db: &dyn HirDatabase) -> Type<'_> {
         let id = AdtId::from(self);
         Type::from_def(db, id)
     }
 
     /// 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: impl Iterator<Item = Type>) -> Type {
+    pub fn ty_with_args<'db>(
+        self,
+        db: &'db dyn HirDatabase,
+        args: impl Iterator<Item = Type<'db>>,
+    ) -> Type<'db> {
         let id = AdtId::from(self);
         let mut it = args.map(|t| t.ty);
         let ty = TyBuilder::def_ty(db, id.into(), None)
@@ -1841,7 +1861,7 @@ impl DefWithBody {
     }
 
     /// Returns the type this def's body has to evaluate to.
-    pub fn body_type(self, db: &dyn HirDatabase) -> Type {
+    pub fn body_type(self, db: &dyn HirDatabase) -> Type<'_> {
         match self {
             DefWithBody::Function(it) => it.ret_type(db),
             DefWithBody::Static(it) => it.ty(db),
@@ -1874,10 +1894,10 @@ impl DefWithBody {
         }
     }
 
-    pub fn diagnostics(
+    pub fn diagnostics<'db>(
         self,
-        db: &dyn HirDatabase,
-        acc: &mut Vec<AnyDiagnostic>,
+        db: &'db dyn HirDatabase,
+        acc: &mut Vec<AnyDiagnostic<'db>>,
         style_lints: bool,
     ) {
         let krate = self.module(db).id.krate();
@@ -2107,7 +2127,7 @@ impl DefWithBody {
 
 fn expr_store_diagnostics(
     db: &dyn HirDatabase,
-    acc: &mut Vec<AnyDiagnostic>,
+    acc: &mut Vec<AnyDiagnostic<'_>>,
     source_map: &ExpressionStoreSourceMap,
 ) {
     for diag in source_map.diagnostics() {
@@ -2172,11 +2192,11 @@ impl Function {
         db.function_signature(self.id).name.clone()
     }
 
-    pub fn ty(self, db: &dyn HirDatabase) -> Type {
+    pub fn ty(self, db: &dyn HirDatabase) -> Type<'_> {
         Type::from_value_def(db, self.id)
     }
 
-    pub fn fn_ptr_type(self, db: &dyn HirDatabase) -> Type {
+    pub fn fn_ptr_type(self, db: &dyn HirDatabase) -> Type<'_> {
         let resolver = self.id.resolver(db);
         let substs = TyBuilder::placeholder_subst(db, self.id);
         let callable_sig = db.callable_item_signature(self.id.into()).substitute(Interner, &substs);
@@ -2185,7 +2205,7 @@ impl Function {
     }
 
     /// Get this function's return type
-    pub fn ret_type(self, db: &dyn HirDatabase) -> Type {
+    pub fn ret_type(self, db: &dyn HirDatabase) -> Type<'_> {
         let resolver = self.id.resolver(db);
         let substs = TyBuilder::placeholder_subst(db, self.id);
         let callable_sig = db.callable_item_signature(self.id.into()).substitute(Interner, &substs);
@@ -2194,11 +2214,11 @@ impl Function {
     }
 
     // FIXME: Find better API to also handle const generics
-    pub fn ret_type_with_args(
+    pub fn ret_type_with_args<'db>(
         self,
-        db: &dyn HirDatabase,
-        generics: impl Iterator<Item = Type>,
-    ) -> Type {
+        db: &'db dyn HirDatabase,
+        generics: impl Iterator<Item = Type<'db>>,
+    ) -> Type<'db> {
         let resolver = self.id.resolver(db);
         let parent_id: Option<GenericDefId> = match self.id.lookup(db).container {
             ItemContainerId::ImplId(it) => Some(it.into()),
@@ -2223,7 +2243,7 @@ impl Function {
         Type::new_with_resolver_inner(db, &resolver, ty)
     }
 
-    pub fn async_ret_type(self, db: &dyn HirDatabase) -> Option<Type> {
+    pub fn async_ret_type<'db>(self, db: &'db dyn HirDatabase) -> Option<Type<'db>> {
         if !self.is_async(db) {
             return None;
         }
@@ -2247,7 +2267,7 @@ impl Function {
         self.has_self_param(db).then_some(SelfParam { func: self.id })
     }
 
-    pub fn assoc_fn_params(self, db: &dyn HirDatabase) -> Vec<Param> {
+    pub fn assoc_fn_params(self, db: &dyn HirDatabase) -> Vec<Param<'_>> {
         let environment = db.trait_environment(self.id.into());
         let substs = TyBuilder::placeholder_subst(db, self.id);
         let callable_sig = db.callable_item_signature(self.id.into()).substitute(Interner, &substs);
@@ -2256,7 +2276,11 @@ impl Function {
             .iter()
             .enumerate()
             .map(|(idx, ty)| {
-                let ty = Type { env: environment.clone(), ty: ty.clone() };
+                let ty = Type {
+                    env: environment.clone(),
+                    ty: ty.clone(),
+                    _pd: PhantomCovariantLifetime::new(),
+                };
                 Param { func: Callee::Def(CallableDefId::FunctionId(self.id)), ty, idx }
             })
             .collect()
@@ -2266,12 +2290,12 @@ impl Function {
         db.function_signature(self.id).params.len()
     }
 
-    pub fn method_params(self, db: &dyn HirDatabase) -> Option<Vec<Param>> {
+    pub fn method_params(self, db: &dyn HirDatabase) -> Option<Vec<Param<'_>>> {
         self.self_param(db)?;
         Some(self.params_without_self(db))
     }
 
-    pub fn params_without_self(self, db: &dyn HirDatabase) -> Vec<Param> {
+    pub fn params_without_self(self, db: &dyn HirDatabase) -> Vec<Param<'_>> {
         let environment = db.trait_environment(self.id.into());
         let substs = TyBuilder::placeholder_subst(db, self.id);
         let callable_sig = db.callable_item_signature(self.id.into()).substitute(Interner, &substs);
@@ -2282,18 +2306,22 @@ impl Function {
             .enumerate()
             .skip(skip)
             .map(|(idx, ty)| {
-                let ty = Type { env: environment.clone(), ty: ty.clone() };
+                let ty = Type {
+                    env: environment.clone(),
+                    ty: ty.clone(),
+                    _pd: PhantomCovariantLifetime::new(),
+                };
                 Param { func: Callee::Def(CallableDefId::FunctionId(self.id)), ty, idx }
             })
             .collect()
     }
 
     // FIXME: Find better API to also handle const generics
-    pub fn params_without_self_with_args(
+    pub fn params_without_self_with_args<'db>(
         self,
-        db: &dyn HirDatabase,
-        generics: impl Iterator<Item = Type>,
-    ) -> Vec<Param> {
+        db: &'db dyn HirDatabase,
+        generics: impl Iterator<Item = Type<'db>>,
+    ) -> Vec<Param<'db>> {
         let environment = db.trait_environment(self.id.into());
         let parent_id: Option<GenericDefId> = match self.id.lookup(db).container {
             ItemContainerId::ImplId(it) => Some(it.into()),
@@ -2328,7 +2356,11 @@ impl Function {
             .enumerate()
             .skip(skip)
             .map(|(idx, ty)| {
-                let ty = Type { env: environment.clone(), ty: ty.clone() };
+                let ty = Type {
+                    env: environment.clone(),
+                    ty: ty.clone(),
+                    _pd: PhantomCovariantLifetime::new(),
+                };
                 Param { func: Callee::Def(CallableDefId::FunctionId(self.id)), ty, idx }
             })
             .collect()
@@ -2358,7 +2390,8 @@ impl Function {
             return true;
         }
 
-        let Some(impl_traits) = self.ret_type(db).as_impl_traits(db) else { return false };
+        let ret_type = self.ret_type(db);
+        let Some(impl_traits) = ret_type.as_impl_traits(db) else { return false };
         let Some(future_trait_id) = LangItem::Future.resolve_trait(db, self.ty(db).env.krate)
         else {
             return false;
@@ -2501,14 +2534,14 @@ impl From<hir_ty::Mutability> for Access {
 }
 
 #[derive(Clone, PartialEq, Eq, Hash, Debug)]
-pub struct Param {
+pub struct Param<'db> {
     func: Callee,
     /// The index in parameter list, including self parameter.
     idx: usize,
-    ty: Type,
+    ty: Type<'db>,
 }
 
-impl Param {
+impl<'db> Param<'db> {
     pub fn parent_fn(&self) -> Option<Function> {
         match self.func {
             Callee::Def(CallableDefId::FunctionId(f)) => Some(f.into()),
@@ -2524,7 +2557,7 @@ impl Param {
         self.idx
     }
 
-    pub fn ty(&self) -> &Type {
+    pub fn ty(&self) -> &Type<'db> {
         &self.ty
     }
 
@@ -2591,17 +2624,21 @@ impl SelfParam {
         Function::from(self.func)
     }
 
-    pub fn ty(&self, db: &dyn HirDatabase) -> Type {
+    pub fn ty<'db>(&self, db: &'db dyn HirDatabase) -> Type<'db> {
         let substs = TyBuilder::placeholder_subst(db, self.func);
         let callable_sig =
             db.callable_item_signature(self.func.into()).substitute(Interner, &substs);
         let environment = db.trait_environment(self.func.into());
         let ty = callable_sig.params()[0].clone();
-        Type { env: environment, ty }
+        Type { env: environment, ty, _pd: PhantomCovariantLifetime::new() }
     }
 
     // FIXME: Find better API to also handle const generics
-    pub fn ty_with_args(&self, db: &dyn HirDatabase, generics: impl Iterator<Item = Type>) -> Type {
+    pub fn ty_with_args<'db>(
+        &self,
+        db: &'db dyn HirDatabase,
+        generics: impl Iterator<Item = Type<'db>>,
+    ) -> Type<'db> {
         let parent_id: GenericDefId = match self.func.lookup(db).container {
             ItemContainerId::ImplId(it) => it.into(),
             ItemContainerId::TraitId(it) => it.into(),
@@ -2626,7 +2663,7 @@ impl SelfParam {
             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 }
+        Type { env: environment, ty, _pd: PhantomCovariantLifetime::new() }
     }
 }
 
@@ -2714,7 +2751,7 @@ impl Const {
         self.source(db)?.value.body()
     }
 
-    pub fn ty(self, db: &dyn HirDatabase) -> Type {
+    pub fn ty(self, db: &dyn HirDatabase) -> Type<'_> {
         Type::from_value_def(db, self.id)
     }
 
@@ -2791,7 +2828,7 @@ impl Static {
         self.source(db)?.value.body()
     }
 
-    pub fn ty(self, db: &dyn HirDatabase) -> Type {
+    pub fn ty(self, db: &dyn HirDatabase) -> Type<'_> {
         Type::from_value_def(db, self.id)
     }
 
@@ -2961,11 +2998,11 @@ impl TypeAlias {
         Module { id: self.id.module(db) }
     }
 
-    pub fn ty(self, db: &dyn HirDatabase) -> Type {
+    pub fn ty(self, db: &dyn HirDatabase) -> Type<'_> {
         Type::from_def(db, self.id)
     }
 
-    pub fn ty_placeholders(self, db: &dyn HirDatabase) -> Type {
+    pub fn ty_placeholders(self, db: &dyn HirDatabase) -> Type<'_> {
         Type::from_def_placeholders(db, self.id)
     }
 
@@ -3010,7 +3047,7 @@ impl BuiltinType {
         BuiltinType { inner: hir_def::builtin_type::BuiltinType::Str }
     }
 
-    pub fn ty(self, db: &dyn HirDatabase) -> Type {
+    pub fn ty<'db>(self, db: &'db dyn HirDatabase) -> Type<'db> {
         let core = Crate::core(db).map(|core| core.id).unwrap_or_else(|| db.all_crates()[0]);
         Type::new_for_crate(core, TyBuilder::builtin(self.inner))
     }
@@ -3472,7 +3509,7 @@ impl AssocItem {
         }
     }
 
-    pub fn implementing_ty(self, db: &dyn HirDatabase) -> Option<Type> {
+    pub fn implementing_ty(self, db: &dyn HirDatabase) -> Option<Type<'_>> {
         match self.container(db) {
             AssocItemContainer::Impl(i) => Some(i.self_ty(db)),
             _ => None,
@@ -3500,10 +3537,10 @@ impl AssocItem {
         }
     }
 
-    pub fn diagnostics(
+    pub fn diagnostics<'db>(
         self,
-        db: &dyn HirDatabase,
-        acc: &mut Vec<AnyDiagnostic>,
+        db: &'db dyn HirDatabase,
+        acc: &mut Vec<AnyDiagnostic<'db>>,
         style_lints: bool,
     ) {
         match self {
@@ -3625,7 +3662,7 @@ impl GenericDef {
         }
     }
 
-    pub fn diagnostics(self, db: &dyn HirDatabase, acc: &mut Vec<AnyDiagnostic>) {
+    pub fn diagnostics<'db>(self, db: &'db dyn HirDatabase, acc: &mut Vec<AnyDiagnostic<'db>>) {
         let def = self.id();
 
         let generics = db.generic_params(def);
@@ -3690,18 +3727,19 @@ impl GenericDef {
 
 // We cannot call this `Substitution` unfortunately...
 #[derive(Debug)]
-pub struct GenericSubstitution {
+pub struct GenericSubstitution<'db> {
     def: GenericDefId,
     subst: Substitution,
     env: Arc<TraitEnvironment>,
+    _pd: PhantomCovariantLifetime<'db>,
 }
 
-impl GenericSubstitution {
+impl<'db> GenericSubstitution<'db> {
     fn new(def: GenericDefId, subst: Substitution, env: Arc<TraitEnvironment>) -> Self {
-        Self { def, subst, env }
+        Self { def, subst, env, _pd: PhantomCovariantLifetime::new() }
     }
 
-    pub fn types(&self, db: &dyn HirDatabase) -> Vec<(Symbol, Type)> {
+    pub fn types(&self, db: &'db dyn HirDatabase) -> Vec<(Symbol, Type<'db>)> {
         let container = match self.def {
             GenericDefId::ConstId(id) => Some(id.lookup(db).container),
             GenericDefId::FunctionId(id) => Some(id.lookup(db).container),
@@ -3744,7 +3782,10 @@ impl GenericSubstitution {
         container_params
             .chain(self_params)
             .filter_map(|(ty, name)| {
-                Some((name?.symbol().clone(), Type { ty, env: self.env.clone() }))
+                Some((
+                    name?.symbol().clone(),
+                    Type { ty, env: self.env.clone(), _pd: PhantomCovariantLifetime::new() },
+                ))
             })
             .collect()
     }
@@ -3847,7 +3888,7 @@ impl Local {
         self.parent(db).module(db)
     }
 
-    pub fn ty(self, db: &dyn HirDatabase) -> Type {
+    pub fn ty(self, db: &dyn HirDatabase) -> Type<'_> {
         let def = self.parent;
         let infer = db.infer(def);
         let ty = infer[self.binding_id].clone();
@@ -4109,6 +4150,10 @@ impl TypeParam {
         self.merge().name(db)
     }
 
+    pub fn parent(self, _db: &dyn HirDatabase) -> GenericDef {
+        self.id.parent().into()
+    }
+
     pub fn module(self, db: &dyn HirDatabase) -> Module {
         self.id.parent().module(db).into()
     }
@@ -4124,7 +4169,7 @@ impl TypeParam {
         }
     }
 
-    pub fn ty(self, db: &dyn HirDatabase) -> Type {
+    pub fn ty(self, db: &dyn HirDatabase) -> Type<'_> {
         let resolver = self.id.parent().resolver(db);
         let ty =
             TyKind::Placeholder(hir_ty::to_placeholder_idx(db, self.id.into())).intern(Interner);
@@ -4146,7 +4191,7 @@ impl TypeParam {
             .collect()
     }
 
-    pub fn default(self, db: &dyn HirDatabase) -> Option<Type> {
+    pub fn default(self, db: &dyn HirDatabase) -> Option<Type<'_>> {
         let ty = generic_arg_from_param(db, self.id.into())?;
         let resolver = self.id.parent().resolver(db);
         match ty.data(Interner) {
@@ -4211,7 +4256,7 @@ impl ConstParam {
         self.id.parent().into()
     }
 
-    pub fn ty(self, db: &dyn HirDatabase) -> Type {
+    pub fn ty(self, db: &dyn HirDatabase) -> Type<'_> {
         Type::new(db, self.id.parent(), db.const_param_ty(self.id))
     }
 
@@ -4268,7 +4313,7 @@ impl TypeOrConstParam {
         }
     }
 
-    pub fn ty(self, db: &dyn HirDatabase) -> Type {
+    pub fn ty(self, db: &dyn HirDatabase) -> Type<'_> {
         match self.split(db) {
             Either::Left(it) => it.ty(db),
             Either::Right(it) => it.ty(db),
@@ -4313,7 +4358,10 @@ impl Impl {
         module.id.def_map(db)[module.id.local_id].scope.impls().map(Into::into).collect()
     }
 
-    pub fn all_for_type(db: &dyn HirDatabase, Type { ty, env }: Type) -> Vec<Impl> {
+    pub fn all_for_type<'db>(
+        db: &'db dyn HirDatabase,
+        Type { ty, env, _pd: _ }: Type<'db>,
+    ) -> Vec<Impl> {
         let def_crates = match method_resolution::def_crates(db, &ty, env.krate) {
             Some(def_crates) => def_crates,
             None => return Vec::new(),
@@ -4398,14 +4446,14 @@ impl Impl {
         Some(Trait { id })
     }
 
-    pub fn trait_ref(self, db: &dyn HirDatabase) -> Option<TraitRef> {
+    pub fn trait_ref(self, db: &dyn HirDatabase) -> Option<TraitRef<'_>> {
         let substs = TyBuilder::placeholder_subst(db, self.id);
         let trait_ref = db.impl_trait(self.id)?.substitute(Interner, &substs);
         let resolver = self.id.resolver(db);
         Some(TraitRef::new_with_resolver(db, &resolver, trait_ref))
     }
 
-    pub fn self_ty(self, db: &dyn HirDatabase) -> Type {
+    pub fn self_ty(self, db: &dyn HirDatabase) -> Type<'_> {
         let resolver = self.id.resolver(db);
         let substs = TyBuilder::placeholder_subst(db, self.id);
         let ty = db.impl_self_ty(self.id).substitute(Interner, &substs);
@@ -4467,21 +4515,22 @@ impl Impl {
 }
 
 #[derive(Clone, PartialEq, Eq, Debug, Hash)]
-pub struct TraitRef {
+pub struct TraitRef<'db> {
     env: Arc<TraitEnvironment>,
     trait_ref: hir_ty::TraitRef,
+    _pd: PhantomCovariantLifetime<'db>,
 }
 
-impl TraitRef {
+impl<'db> TraitRef<'db> {
     pub(crate) fn new_with_resolver(
-        db: &dyn HirDatabase,
+        db: &'db dyn HirDatabase,
         resolver: &Resolver<'_>,
         trait_ref: hir_ty::TraitRef,
-    ) -> TraitRef {
+    ) -> Self {
         let env = resolver
             .generic_def()
             .map_or_else(|| TraitEnvironment::empty(resolver.krate()), |d| db.trait_environment(d));
-        TraitRef { env, trait_ref }
+        TraitRef { env, trait_ref, _pd: PhantomCovariantLifetime::new() }
     }
 
     pub fn trait_(&self) -> Trait {
@@ -4489,21 +4538,21 @@ impl TraitRef {
         Trait { id }
     }
 
-    pub fn self_ty(&self) -> Type {
+    pub fn self_ty(&self) -> Type<'_> {
         let ty = self.trait_ref.self_type_parameter(Interner);
-        Type { env: self.env.clone(), ty }
+        Type { env: self.env.clone(), ty, _pd: PhantomCovariantLifetime::new() }
     }
 
     /// Returns `idx`-th argument of this trait reference if it is a type argument. Note that the
     /// first argument is the `Self` type.
-    pub fn get_type_argument(&self, idx: usize) -> Option<Type> {
+    pub fn get_type_argument(&self, idx: usize) -> Option<Type<'db>> {
         self.trait_ref
             .substitution
             .as_slice(Interner)
             .get(idx)
             .and_then(|arg| arg.ty(Interner))
             .cloned()
-            .map(|ty| Type { env: self.env.clone(), ty })
+            .map(|ty| Type { env: self.env.clone(), ty, _pd: PhantomCovariantLifetime::new() })
     }
 }
 
@@ -4551,7 +4600,7 @@ impl Closure {
             .collect()
     }
 
-    pub fn capture_types(&self, db: &dyn HirDatabase) -> Vec<Type> {
+    pub fn capture_types<'db>(&self, db: &'db dyn HirDatabase) -> Vec<Type<'db>> {
         let owner = db.lookup_intern_closure((self.id).into()).0;
         let infer = &db.infer(owner);
         let (captures, _) = infer.closure_info(&self.id);
@@ -4560,6 +4609,7 @@ impl Closure {
             .map(|capture| Type {
                 env: db.trait_environment_for_body(owner),
                 ty: capture.ty(&self.subst),
+                _pd: PhantomCovariantLifetime::new(),
             })
             .collect()
     }
@@ -4691,40 +4741,45 @@ impl CaptureUsageSource {
 }
 
 #[derive(Clone, PartialEq, Eq, Debug, Hash)]
-pub struct Type {
+pub struct Type<'db> {
     env: Arc<TraitEnvironment>,
     ty: Ty,
+    _pd: PhantomCovariantLifetime<'db>,
 }
 
-impl Type {
-    pub(crate) fn new_with_resolver(db: &dyn HirDatabase, resolver: &Resolver<'_>, ty: Ty) -> Type {
+impl<'db> Type<'db> {
+    pub(crate) fn new_with_resolver(
+        db: &'db dyn HirDatabase,
+        resolver: &Resolver<'_>,
+        ty: Ty,
+    ) -> Self {
         Type::new_with_resolver_inner(db, resolver, ty)
     }
 
     pub(crate) fn new_with_resolver_inner(
-        db: &dyn HirDatabase,
+        db: &'db dyn HirDatabase,
         resolver: &Resolver<'_>,
         ty: Ty,
-    ) -> Type {
+    ) -> Self {
         let environment = resolver
             .generic_def()
             .map_or_else(|| TraitEnvironment::empty(resolver.krate()), |d| db.trait_environment(d));
-        Type { env: environment, ty }
+        Type { env: environment, ty, _pd: PhantomCovariantLifetime::new() }
     }
 
-    pub(crate) fn new_for_crate(krate: base_db::Crate, ty: Ty) -> Type {
-        Type { env: TraitEnvironment::empty(krate), ty }
+    pub(crate) fn new_for_crate(krate: base_db::Crate, ty: Ty) -> Self {
+        Type { env: TraitEnvironment::empty(krate), ty, _pd: PhantomCovariantLifetime::new() }
     }
 
-    fn new(db: &dyn HirDatabase, lexical_env: impl HasResolver, ty: Ty) -> Type {
+    fn new(db: &'db dyn HirDatabase, lexical_env: impl HasResolver, ty: Ty) -> Self {
         let resolver = lexical_env.resolver(db);
         let environment = resolver
             .generic_def()
             .map_or_else(|| TraitEnvironment::empty(resolver.krate()), |d| db.trait_environment(d));
-        Type { env: environment, ty }
+        Type { env: environment, ty, _pd: PhantomCovariantLifetime::new() }
     }
 
-    fn from_def(db: &dyn HirDatabase, def: impl Into<TyDefId> + HasResolver) -> Type {
+    fn from_def(db: &'db dyn HirDatabase, def: impl Into<TyDefId> + HasResolver) -> Self {
         let ty = db.ty(def.into());
         let substs = TyBuilder::unknown_subst(
             db,
@@ -4737,7 +4792,10 @@ impl Type {
         Type::new(db, def, ty.substitute(Interner, &substs))
     }
 
-    fn from_def_placeholders(db: &dyn HirDatabase, def: impl Into<TyDefId> + HasResolver) -> Type {
+    fn from_def_placeholders(
+        db: &'db dyn HirDatabase,
+        def: impl Into<TyDefId> + HasResolver,
+    ) -> Self {
         let ty = db.ty(def.into());
         let substs = TyBuilder::placeholder_subst(
             db,
@@ -4750,7 +4808,10 @@ impl Type {
         Type::new(db, def, ty.substitute(Interner, &substs))
     }
 
-    fn from_value_def(db: &dyn HirDatabase, def: impl Into<ValueTyDefId> + HasResolver) -> Type {
+    fn from_value_def(
+        db: &'db dyn HirDatabase,
+        def: impl Into<ValueTyDefId> + HasResolver,
+    ) -> Self {
         let Some(ty) = db.value_ty(def.into()) else {
             return Type::new(db, def, TyKind::Error.intern(Interner));
         };
@@ -4770,13 +4831,17 @@ impl Type {
         Type::new(db, def, ty.substitute(Interner, &substs))
     }
 
-    pub fn new_slice(ty: Type) -> Type {
-        Type { env: ty.env, ty: TyBuilder::slice(ty.ty) }
+    pub fn new_slice(ty: Self) -> Self {
+        Type { env: ty.env, ty: TyBuilder::slice(ty.ty), _pd: PhantomCovariantLifetime::new() }
     }
 
-    pub fn new_tuple(krate: base_db::Crate, tys: &[Type]) -> Type {
+    pub fn new_tuple(krate: base_db::Crate, tys: &[Self]) -> Self {
         let tys = tys.iter().map(|it| it.ty.clone());
-        Type { env: TraitEnvironment::empty(krate), ty: TyBuilder::tuple_with(tys) }
+        Type {
+            env: TraitEnvironment::empty(krate),
+            ty: TyBuilder::tuple_with(tys),
+            _pd: PhantomCovariantLifetime::new(),
+        }
     }
 
     pub fn is_unit(&self) -> bool {
@@ -4803,7 +4868,7 @@ impl Type {
         matches!(self.ty.kind(Interner), TyKind::Ref(..))
     }
 
-    pub fn contains_reference(&self, db: &dyn HirDatabase) -> bool {
+    pub fn contains_reference(&self, db: &'db dyn HirDatabase) -> bool {
         return go(db, self.env.krate, &self.ty);
 
         fn go(db: &dyn HirDatabase, krate: base_db::Crate, ty: &Ty) -> bool {
@@ -4847,13 +4912,13 @@ impl Type {
         }
     }
 
-    pub fn as_reference(&self) -> Option<(Type, Mutability)> {
+    pub fn as_reference(&self) -> Option<(Type<'db>, Mutability)> {
         let (ty, _lt, m) = self.ty.as_reference()?;
         let m = Mutability::from_mutable(matches!(m, hir_ty::Mutability::Mut));
         Some((self.derived(ty.clone()), m))
     }
 
-    pub fn add_reference(&self, mutability: Mutability) -> Type {
+    pub fn add_reference(&self, mutability: Mutability) -> Self {
         let ty_mutability = match mutability {
             Mutability::Shared => hir_ty::Mutability::Not,
             Mutability::Mut => hir_ty::Mutability::Mut,
@@ -4889,25 +4954,25 @@ impl Type {
         matches!(self.ty.kind(Interner), TyKind::Tuple(..))
     }
 
-    pub fn remove_ref(&self) -> Option<Type> {
+    pub fn remove_ref(&self) -> Option<Type<'db>> {
         match &self.ty.kind(Interner) {
             TyKind::Ref(.., ty) => Some(self.derived(ty.clone())),
             _ => None,
         }
     }
 
-    pub fn as_slice(&self) -> Option<Type> {
+    pub fn as_slice(&self) -> Option<Type<'db>> {
         match &self.ty.kind(Interner) {
             TyKind::Slice(ty) => Some(self.derived(ty.clone())),
             _ => None,
         }
     }
 
-    pub fn strip_references(&self) -> Type {
+    pub fn strip_references(&self) -> Self {
         self.derived(self.ty.strip_references().clone())
     }
 
-    pub fn strip_reference(&self) -> Type {
+    pub fn strip_reference(&self) -> Self {
         self.derived(self.ty.strip_reference().clone())
     }
 
@@ -4918,7 +4983,7 @@ impl Type {
     /// Checks that particular type `ty` implements `std::future::IntoFuture` or
     /// `std::future::Future` and returns the `Output` associated type.
     /// This function is used in `.await` syntax completion.
-    pub fn into_future_output(&self, db: &dyn HirDatabase) -> Option<Type> {
+    pub fn into_future_output(&self, db: &'db dyn HirDatabase) -> Option<Type<'db>> {
         let trait_ = LangItem::IntoFutureIntoFuture
             .resolve_function(db, self.env.krate)
             .and_then(|into_future_fn| {
@@ -4940,13 +5005,13 @@ impl Type {
     }
 
     /// This does **not** resolve `IntoFuture`, only `Future`.
-    pub fn future_output(self, db: &dyn HirDatabase) -> Option<Type> {
+    pub fn future_output(self, db: &'db dyn HirDatabase) -> Option<Type<'db>> {
         let future_output = LangItem::FutureOutput.resolve_type_alias(db, self.env.krate)?;
         self.normalize_trait_assoc_type(db, &[], future_output.into())
     }
 
     /// This does **not** resolve `IntoIterator`, only `Iterator`.
-    pub fn iterator_item(self, db: &dyn HirDatabase) -> Option<Type> {
+    pub fn iterator_item(self, db: &'db dyn HirDatabase) -> Option<Type<'db>> {
         let iterator_trait = LangItem::Iterator.resolve_trait(db, self.env.krate)?;
         let iterator_item = db
             .trait_items(iterator_trait)
@@ -4954,7 +5019,7 @@ impl Type {
         self.normalize_trait_assoc_type(db, &[], iterator_item.into())
     }
 
-    pub fn impls_iterator(self, db: &dyn HirDatabase) -> bool {
+    pub fn impls_iterator(self, db: &'db dyn HirDatabase) -> bool {
         let Some(iterator_trait) = LangItem::Iterator.resolve_trait(db, self.env.krate) else {
             return false;
         };
@@ -4964,7 +5029,7 @@ impl Type {
     }
 
     /// Resolves the projection `<Self as IntoIterator>::IntoIter` and returns the resulting type
-    pub fn into_iterator_iter(self, db: &dyn HirDatabase) -> Option<Type> {
+    pub fn into_iterator_iter(self, db: &'db dyn HirDatabase) -> Option<Type<'db>> {
         let trait_ = LangItem::IntoIterIntoIter.resolve_function(db, self.env.krate).and_then(
             |into_iter_fn| {
                 let assoc_item = as_assoc_item(db, AssocItem::Function, into_iter_fn)?;
@@ -4989,7 +5054,7 @@ impl Type {
     ///
     /// This function can be used to check if a particular type is callable, since FnOnce is a
     /// supertrait of Fn and FnMut, so all callable types implements at least FnOnce.
-    pub fn impls_fnonce(&self, db: &dyn HirDatabase) -> bool {
+    pub fn impls_fnonce(&self, db: &'db dyn HirDatabase) -> bool {
         let fnonce_trait = match FnTrait::FnOnce.get_id(db, self.env.krate) {
             Some(it) => it,
             None => return false,
@@ -5001,7 +5066,7 @@ impl Type {
     }
 
     // FIXME: Find better API that also handles const generics
-    pub fn impls_trait(&self, db: &dyn HirDatabase, trait_: Trait, args: &[Type]) -> bool {
+    pub fn impls_trait(&self, db: &'db dyn HirDatabase, trait_: Trait, args: &[Type<'db>]) -> bool {
         let mut it = args.iter().map(|t| t.ty.clone());
         let trait_ref = TyBuilder::trait_ref(db, trait_.id)
             .push(self.ty.clone())
@@ -5029,10 +5094,10 @@ impl Type {
 
     pub fn normalize_trait_assoc_type(
         &self,
-        db: &dyn HirDatabase,
-        args: &[Type],
+        db: &'db dyn HirDatabase,
+        args: &[Type<'db>],
         alias: TypeAlias,
-    ) -> Option<Type> {
+    ) -> Option<Type<'db>> {
         let mut args = args.iter();
         let trait_id = match alias.id.lookup(db).container {
             ItemContainerId::TraitId(id) => id,
@@ -5056,14 +5121,14 @@ impl Type {
         if ty.is_unknown() { None } else { Some(self.derived(ty)) }
     }
 
-    pub fn is_copy(&self, db: &dyn HirDatabase) -> bool {
+    pub fn is_copy(&self, db: &'db dyn HirDatabase) -> bool {
         let Some(copy_trait) = LangItem::Copy.resolve_trait(db, self.env.krate) else {
             return false;
         };
         self.impls_trait(db, copy_trait.into(), &[])
     }
 
-    pub fn as_callable(&self, db: &dyn HirDatabase) -> Option<Callable> {
+    pub fn as_callable(&self, db: &'db dyn HirDatabase) -> Option<Callable<'db>> {
         let callee = match self.ty.kind(Interner) {
             TyKind::Closure(id, subst) => Callee::Closure(*id, subst.clone()),
             TyKind::Function(_) => Callee::FnPtr,
@@ -5117,7 +5182,7 @@ impl Type {
         matches!(self.ty.kind(Interner), TyKind::Array(..))
     }
 
-    pub fn is_packed(&self, db: &dyn HirDatabase) -> bool {
+    pub fn is_packed(&self, db: &'db dyn HirDatabase) -> bool {
         let adt_id = match *self.ty.kind(Interner) {
             TyKind::Adt(hir_ty::AdtId(adt_id), ..) => adt_id,
             _ => return false,
@@ -5134,7 +5199,7 @@ impl Type {
         matches!(self.ty.kind(Interner), TyKind::Raw(..))
     }
 
-    pub fn remove_raw_ptr(&self) -> Option<Type> {
+    pub fn remove_raw_ptr(&self) -> Option<Type<'db>> {
         if let TyKind::Raw(_, ty) = self.ty.kind(Interner) {
             Some(self.derived(ty.clone()))
         } else {
@@ -5182,7 +5247,7 @@ impl Type {
         }
     }
 
-    pub fn fields(&self, db: &dyn HirDatabase) -> Vec<(Field, Type)> {
+    pub fn fields(&self, db: &'db dyn HirDatabase) -> Vec<(Field, Self)> {
         let (variant_id, substs) = match self.ty.kind(Interner) {
             TyKind::Adt(hir_ty::AdtId(AdtId::StructId(s)), substs) => ((*s).into(), substs),
             TyKind::Adt(hir_ty::AdtId(AdtId::UnionId(u)), substs) => ((*u).into(), substs),
@@ -5199,7 +5264,7 @@ impl Type {
             .collect()
     }
 
-    pub fn tuple_fields(&self, _db: &dyn HirDatabase) -> Vec<Type> {
+    pub fn tuple_fields(&self, _db: &'db dyn HirDatabase) -> Vec<Self> {
         if let TyKind::Tuple(_, substs) = &self.ty.kind(Interner) {
             substs
                 .iter(Interner)
@@ -5210,7 +5275,7 @@ impl Type {
         }
     }
 
-    pub fn as_array(&self, db: &dyn HirDatabase) -> Option<(Type, usize)> {
+    pub fn as_array(&self, db: &'db dyn HirDatabase) -> Option<(Self, usize)> {
         if let TyKind::Array(ty, len) = &self.ty.kind(Interner) {
             try_const_usize(db, len).map(|it| (self.derived(ty.clone()), it as usize))
         } else {
@@ -5228,14 +5293,14 @@ impl Type {
 
     /// Returns types that this type dereferences to (including this type itself). The returned
     /// iterator won't yield the same type more than once even if the deref chain contains a cycle.
-    pub fn autoderef<'db>(
+    pub fn autoderef(
         &self,
         db: &'db dyn HirDatabase,
-    ) -> impl Iterator<Item = Type> + use<'_, 'db> {
+    ) -> impl Iterator<Item = Type<'db>> + use<'_, 'db> {
         self.autoderef_(db).map(move |ty| self.derived(ty))
     }
 
-    fn autoderef_(&self, db: &dyn HirDatabase) -> impl Iterator<Item = Ty> {
+    fn autoderef_(&self, db: &'db dyn HirDatabase) -> impl Iterator<Item = Ty> {
         // There should be no inference vars in types passed here
         let canonical = hir_ty::replace_errors_with_variables(&self.ty);
         autoderef(db, self.env.clone(), canonical)
@@ -5245,7 +5310,7 @@ impl Type {
     // lifetime problems, because we need to borrow temp `CrateImplDefs`.
     pub fn iterate_assoc_items<T>(
         &self,
-        db: &dyn HirDatabase,
+        db: &'db dyn HirDatabase,
         krate: Crate,
         mut callback: impl FnMut(AssocItem) -> Option<T>,
     ) -> Option<T> {
@@ -5259,7 +5324,7 @@ impl Type {
 
     fn iterate_assoc_items_dyn(
         &self,
-        db: &dyn HirDatabase,
+        db: &'db dyn HirDatabase,
         krate: Crate,
         callback: &mut dyn FnMut(AssocItemId) -> bool,
     ) {
@@ -5298,7 +5363,7 @@ impl Type {
     /// - "String"
     /// - "U"
     /// ```
-    pub fn type_arguments(&self) -> impl Iterator<Item = Type> + '_ {
+    pub fn type_arguments(&self) -> impl Iterator<Item = Type<'db>> + '_ {
         self.ty
             .strip_references()
             .as_adt()
@@ -5368,7 +5433,7 @@ impl Type {
 
     pub fn iterate_method_candidates_with_traits<T>(
         &self,
-        db: &dyn HirDatabase,
+        db: &'db dyn HirDatabase,
         scope: &SemanticsScope<'_>,
         traits_in_scope: &FxHashSet<TraitId>,
         with_local_impls: Option<Module>,
@@ -5396,7 +5461,7 @@ impl Type {
 
     pub fn iterate_method_candidates<T>(
         &self,
-        db: &dyn HirDatabase,
+        db: &'db dyn HirDatabase,
         scope: &SemanticsScope<'_>,
         with_local_impls: Option<Module>,
         name: Option<&Name>,
@@ -5418,7 +5483,7 @@ impl Type {
     /// are considered inherent methods.
     pub fn iterate_method_candidates_split_inherent(
         &self,
-        db: &dyn HirDatabase,
+        db: &'db dyn HirDatabase,
         scope: &SemanticsScope<'_>,
         traits_in_scope: &FxHashSet<TraitId>,
         with_local_impls: Option<Module>,
@@ -5486,7 +5551,7 @@ impl Type {
     #[tracing::instrument(skip_all, fields(name = ?name))]
     pub fn iterate_path_candidates<T>(
         &self,
-        db: &dyn HirDatabase,
+        db: &'db dyn HirDatabase,
         scope: &SemanticsScope<'_>,
         traits_in_scope: &FxHashSet<TraitId>,
         with_local_impls: Option<Module>,
@@ -5521,7 +5586,7 @@ impl Type {
     #[tracing::instrument(skip_all, fields(name = ?name))]
     pub fn iterate_path_candidates_split_inherent(
         &self,
-        db: &dyn HirDatabase,
+        db: &'db dyn HirDatabase,
         scope: &SemanticsScope<'_>,
         traits_in_scope: &FxHashSet<TraitId>,
         with_local_impls: Option<Module>,
@@ -5584,10 +5649,10 @@ impl Type {
 
     /// If a type can be represented as `dyn Trait`, returns all traits accessible via this type,
     /// or an empty iterator otherwise.
-    pub fn applicable_inherent_traits<'a>(
-        &'a self,
-        db: &'a dyn HirDatabase,
-    ) -> impl Iterator<Item = Trait> + 'a {
+    pub fn applicable_inherent_traits(
+        &self,
+        db: &'db dyn HirDatabase,
+    ) -> impl Iterator<Item = Trait> {
         let _p = tracing::info_span!("applicable_inherent_traits").entered();
         self.autoderef_(db)
             .filter_map(|ty| ty.dyn_trait())
@@ -5595,7 +5660,7 @@ impl Type {
             .map(Trait::from)
     }
 
-    pub fn env_traits<'a>(&'a self, db: &'a dyn HirDatabase) -> impl Iterator<Item = Trait> + 'a {
+    pub fn env_traits(&self, db: &'db dyn HirDatabase) -> impl Iterator<Item = Trait> {
         let _p = tracing::info_span!("env_traits").entered();
         self.autoderef_(db)
             .filter(|ty| matches!(ty.kind(Interner), TyKind::Placeholder(_)))
@@ -5607,10 +5672,7 @@ impl Type {
             .map(Trait::from)
     }
 
-    pub fn as_impl_traits(
-        &self,
-        db: &dyn HirDatabase,
-    ) -> Option<impl Iterator<Item = Trait> + use<>> {
+    pub fn as_impl_traits(&self, db: &'db dyn HirDatabase) -> Option<impl Iterator<Item = Trait>> {
         self.ty.impl_trait_bounds(db).map(|it| {
             it.into_iter().filter_map(|pred| match pred.skip_binders() {
                 hir_ty::WhereClause::Implemented(trait_ref) => {
@@ -5621,33 +5683,33 @@ impl Type {
         })
     }
 
-    pub fn as_associated_type_parent_trait(&self, db: &dyn HirDatabase) -> Option<Trait> {
+    pub fn as_associated_type_parent_trait(&self, db: &'db dyn HirDatabase) -> Option<Trait> {
         self.ty.associated_type_parent_trait(db).map(Into::into)
     }
 
-    fn derived(&self, ty: Ty) -> Type {
-        Type { env: self.env.clone(), ty }
+    fn derived(&self, ty: Ty) -> Self {
+        Type { env: self.env.clone(), ty, _pd: PhantomCovariantLifetime::new() }
     }
 
     /// Visits every type, including generic arguments, in this type. `cb` is called with type
     /// itself first, and then with its generic arguments.
-    pub fn walk(&self, db: &dyn HirDatabase, mut cb: impl FnMut(Type)) {
-        fn walk_substs(
-            db: &dyn HirDatabase,
-            type_: &Type,
+    pub fn walk(&self, db: &'db dyn HirDatabase, mut cb: impl FnMut(Type<'db>)) {
+        fn walk_substs<'db>(
+            db: &'db dyn HirDatabase,
+            type_: &Type<'db>,
             substs: &Substitution,
-            cb: &mut impl FnMut(Type),
+            cb: &mut impl FnMut(Type<'db>),
         ) {
             for ty in substs.iter(Interner).filter_map(|a| a.ty(Interner)) {
                 walk_type(db, &type_.derived(ty.clone()), cb);
             }
         }
 
-        fn walk_bounds(
-            db: &dyn HirDatabase,
-            type_: &Type,
+        fn walk_bounds<'db>(
+            db: &'db dyn HirDatabase,
+            type_: &Type<'db>,
             bounds: &[QuantifiedWhereClause],
-            cb: &mut impl FnMut(Type),
+            cb: &mut impl FnMut(Type<'db>),
         ) {
             for pred in bounds {
                 if let WhereClause::Implemented(trait_ref) = pred.skip_binders() {
@@ -5664,7 +5726,11 @@ impl Type {
             }
         }
 
-        fn walk_type(db: &dyn HirDatabase, type_: &Type, cb: &mut impl FnMut(Type)) {
+        fn walk_type<'db>(
+            db: &'db dyn HirDatabase,
+            type_: &Type<'db>,
+            cb: &mut impl FnMut(Type<'db>),
+        ) {
             let ty = type_.ty.strip_references();
             match ty.kind(Interner) {
                 TyKind::Adt(_, substs) => {
@@ -5732,7 +5798,7 @@ impl 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 {
+    pub fn could_unify_with(&self, db: &'db dyn HirDatabase, other: &Type<'db>) -> bool {
         let tys = hir_ty::replace_errors_with_variables(&(self.ty.clone(), other.ty.clone()));
         hir_ty::could_unify(db, self.env.clone(), &tys)
     }
@@ -5741,17 +5807,17 @@ impl Type {
     ///
     /// 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 {
+    pub fn could_unify_with_deeply(&self, db: &'db dyn HirDatabase, other: &Type<'db>) -> 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 {
+    pub fn could_coerce_to(&self, db: &'db dyn HirDatabase, to: &Type<'db>) -> bool {
         let tys = hir_ty::replace_errors_with_variables(&(self.ty.clone(), to.ty.clone()));
         hir_ty::could_coerce(db, self.env.clone(), &tys)
     }
 
-    pub fn as_type_param(&self, db: &dyn HirDatabase) -> Option<TypeParam> {
+    pub fn as_type_param(&self, db: &'db dyn HirDatabase) -> Option<TypeParam> {
         match self.ty.kind(Interner) {
             TyKind::Placeholder(p) => Some(TypeParam {
                 id: TypeParamId::from_unchecked(hir_ty::from_placeholder_idx(db, *p)),
@@ -5761,19 +5827,19 @@ impl Type {
     }
 
     /// Returns unique `GenericParam`s contained in this type.
-    pub fn generic_params(&self, db: &dyn HirDatabase) -> FxHashSet<GenericParam> {
+    pub fn generic_params(&self, db: &'db dyn HirDatabase) -> FxHashSet<GenericParam> {
         hir_ty::collect_placeholders(&self.ty, db)
             .into_iter()
             .map(|id| TypeOrConstParam { id }.split(db).either_into())
             .collect()
     }
 
-    pub fn layout(&self, db: &dyn HirDatabase) -> Result<Layout, LayoutError> {
+    pub fn layout(&self, db: &'db dyn HirDatabase) -> Result<Layout, LayoutError> {
         db.layout_of_ty(self.ty.clone(), self.env.clone())
             .map(|layout| Layout(layout, db.target_data_layout(self.env.krate).unwrap()))
     }
 
-    pub fn drop_glue(&self, db: &dyn HirDatabase) -> DropGlue {
+    pub fn drop_glue(&self, db: &'db dyn HirDatabase) -> DropGlue {
         db.has_drop_glue(self.ty.clone(), self.env.clone())
     }
 }
@@ -5800,8 +5866,8 @@ impl InlineAsmOperand {
 
 // FIXME: Document this
 #[derive(Debug)]
-pub struct Callable {
-    ty: Type,
+pub struct Callable<'db> {
+    ty: Type<'db>,
     sig: CallableSig,
     callee: Callee,
     /// Whether this is a method that was called with method call syntax.
@@ -5825,7 +5891,7 @@ pub enum CallableKind {
     FnImpl(FnTrait),
 }
 
-impl Callable {
+impl<'db> Callable<'db> {
     pub fn kind(&self) -> CallableKind {
         match self.callee {
             Callee::Def(CallableDefId::FunctionId(it)) => CallableKind::Function(it.into()),
@@ -5840,7 +5906,7 @@ impl Callable {
             Callee::FnImpl(fn_) => CallableKind::FnImpl(fn_),
         }
     }
-    pub fn receiver_param(&self, db: &dyn HirDatabase) -> Option<(SelfParam, Type)> {
+    pub fn receiver_param(&self, db: &'db dyn HirDatabase) -> Option<(SelfParam, Type<'db>)> {
         let func = match self.callee {
             Callee::Def(CallableDefId::FunctionId(it)) if self.is_bound_method => it,
             _ => return None,
@@ -5851,7 +5917,7 @@ impl Callable {
     pub fn n_params(&self) -> usize {
         self.sig.params().len() - if self.is_bound_method { 1 } else { 0 }
     }
-    pub fn params(&self) -> Vec<Param> {
+    pub fn params(&self) -> Vec<Param<'db>> {
         self.sig
             .params()
             .iter()
@@ -5861,14 +5927,14 @@ impl Callable {
             .map(|(idx, ty)| Param { func: self.callee.clone(), idx, ty })
             .collect()
     }
-    pub fn return_type(&self) -> Type {
+    pub fn return_type(&self) -> Type<'db> {
         self.ty.derived(self.sig.ret().clone())
     }
     pub fn sig(&self) -> &CallableSig {
         &self.sig
     }
 
-    pub fn ty(&self) -> &Type {
+    pub fn ty(&self) -> &Type<'db> {
         &self.ty
     }
 }
@@ -6070,9 +6136,9 @@ impl From<ItemInNs> for ScopeDef {
 }
 
 #[derive(Clone, Debug, PartialEq, Eq)]
-pub struct Adjustment {
-    pub source: Type,
-    pub target: Type,
+pub struct Adjustment<'db> {
+    pub source: Type<'db>,
+    pub target: Type<'db>,
     pub kind: Adjust,
 }
 
@@ -6171,7 +6237,7 @@ impl HasCrate for TypeAlias {
     }
 }
 
-impl HasCrate for Type {
+impl HasCrate for Type<'_> {
     fn krate(&self, _db: &dyn HirDatabase) -> Crate {
         self.env.krate.into()
     }
@@ -6325,9 +6391,9 @@ pub enum DocLinkDef {
     SelfType(Trait),
 }
 
-fn push_ty_diagnostics(
-    db: &dyn HirDatabase,
-    acc: &mut Vec<AnyDiagnostic>,
+fn push_ty_diagnostics<'db>(
+    db: &'db dyn HirDatabase,
+    acc: &mut Vec<AnyDiagnostic<'db>>,
     diagnostics: Option<ThinArc<(), TyLoweringDiagnostic>>,
     source_map: &ExpressionStoreSourceMap,
 ) {
diff --git a/src/tools/rust-analyzer/crates/hir/src/semantics.rs b/src/tools/rust-analyzer/crates/hir/src/semantics.rs
index 10498958242..d96975831e0 100644
--- a/src/tools/rust-analyzer/crates/hir/src/semantics.rs
+++ b/src/tools/rust-analyzer/crates/hir/src/semantics.rs
@@ -123,15 +123,15 @@ impl PathResolutionPerNs {
 }
 
 #[derive(Debug)]
-pub struct TypeInfo {
+pub struct TypeInfo<'db> {
     /// The original type of the expression or pattern.
-    pub original: Type,
+    pub original: Type<'db>,
     /// The adjusted type, if an adjustment happened.
-    pub adjusted: Option<Type>,
+    pub adjusted: Option<Type<'db>>,
 }
 
-impl TypeInfo {
-    pub fn original(self) -> Type {
+impl<'db> TypeInfo<'db> {
+    pub fn original(self) -> Type<'db> {
         self.original
     }
 
@@ -140,7 +140,7 @@ impl TypeInfo {
     }
 
     /// The adjusted type, or the original in case no adjustments occurred.
-    pub fn adjusted(self) -> Type {
+    pub fn adjusted(self) -> Type<'db> {
         self.adjusted.unwrap_or(self.original)
     }
 }
@@ -1534,7 +1534,7 @@ impl<'db> SemanticsImpl<'db> {
         Some(Label { parent, label_id })
     }
 
-    pub fn resolve_type(&self, ty: &ast::Type) -> Option<Type> {
+    pub fn resolve_type(&self, ty: &ast::Type) -> Option<Type<'db>> {
         let analyze = self.analyze(ty.syntax())?;
         analyze.type_of_type(self.db, ty)
     }
@@ -1553,7 +1553,7 @@ impl<'db> SemanticsImpl<'db> {
         }
     }
 
-    pub fn expr_adjustments(&self, expr: &ast::Expr) -> Option<Vec<Adjustment>> {
+    pub fn expr_adjustments(&self, expr: &ast::Expr) -> Option<Vec<Adjustment<'db>>> {
         let mutability = |m| match m {
             hir_ty::Mutability::Not => Mutability::Shared,
             hir_ty::Mutability::Mut => Mutability::Mut,
@@ -1596,13 +1596,13 @@ impl<'db> SemanticsImpl<'db> {
         })
     }
 
-    pub fn type_of_expr(&self, expr: &ast::Expr) -> Option<TypeInfo> {
+    pub fn type_of_expr(&self, expr: &ast::Expr) -> Option<TypeInfo<'db>> {
         self.analyze(expr.syntax())?
             .type_of_expr(self.db, expr)
             .map(|(ty, coerced)| TypeInfo { original: ty, adjusted: coerced })
     }
 
-    pub fn type_of_pat(&self, pat: &ast::Pat) -> Option<TypeInfo> {
+    pub fn type_of_pat(&self, pat: &ast::Pat) -> Option<TypeInfo<'db>> {
         self.analyze(pat.syntax())?
             .type_of_pat(self.db, pat)
             .map(|(ty, coerced)| TypeInfo { original: ty, adjusted: coerced })
@@ -1611,15 +1611,15 @@ impl<'db> SemanticsImpl<'db> {
     /// It also includes the changes that binding mode makes in the type. For example in
     /// `let ref x @ Some(_) = None` the result of `type_of_pat` is `Option<T>` but the result
     /// of this function is `&mut Option<T>`
-    pub fn type_of_binding_in_pat(&self, pat: &ast::IdentPat) -> Option<Type> {
+    pub fn type_of_binding_in_pat(&self, pat: &ast::IdentPat) -> Option<Type<'db>> {
         self.analyze(pat.syntax())?.type_of_binding_in_pat(self.db, pat)
     }
 
-    pub fn type_of_self(&self, param: &ast::SelfParam) -> Option<Type> {
+    pub fn type_of_self(&self, param: &ast::SelfParam) -> Option<Type<'db>> {
         self.analyze(param.syntax())?.type_of_self(self.db, param)
     }
 
-    pub fn pattern_adjustments(&self, pat: &ast::Pat) -> SmallVec<[Type; 1]> {
+    pub fn pattern_adjustments(&self, pat: &ast::Pat) -> SmallVec<[Type<'db>; 1]> {
         self.analyze(pat.syntax())
             .and_then(|it| it.pattern_adjustments(self.db, pat))
             .unwrap_or_default()
@@ -1629,7 +1629,7 @@ impl<'db> SemanticsImpl<'db> {
         self.analyze(pat.syntax())?.binding_mode_of_pat(self.db, pat)
     }
 
-    pub fn resolve_expr_as_callable(&self, call: &ast::Expr) -> Option<Callable> {
+    pub fn resolve_expr_as_callable(&self, call: &ast::Expr) -> Option<Callable<'db>> {
         self.analyze(call.syntax())?.resolve_expr_as_callable(self.db, call)
     }
 
@@ -1641,7 +1641,7 @@ impl<'db> SemanticsImpl<'db> {
     pub fn resolve_method_call_fallback(
         &self,
         call: &ast::MethodCallExpr,
-    ) -> Option<(Either<Function, Field>, Option<GenericSubstitution>)> {
+    ) -> Option<(Either<Function, Field>, Option<GenericSubstitution<'db>>)> {
         self.analyze(call.syntax())?.resolve_method_call_fallback(self.db, call)
     }
 
@@ -1649,10 +1649,10 @@ impl<'db> SemanticsImpl<'db> {
     // FIXME: better api for the trait environment
     pub fn resolve_trait_impl_method(
         &self,
-        env: Type,
+        env: Type<'db>,
         trait_: Trait,
         func: Function,
-        subst: impl IntoIterator<Item = Type>,
+        subst: impl IntoIterator<Item = Type<'db>>,
     ) -> Option<Function> {
         let mut substs = hir_ty::TyBuilder::subst_for_def(self.db, TraitId::from(trait_), None);
         for s in subst {
@@ -1691,7 +1691,10 @@ impl<'db> SemanticsImpl<'db> {
 
     // This does not resolve the method call to the correct trait impl!
     // We should probably fix that.
-    pub fn resolve_method_call_as_callable(&self, call: &ast::MethodCallExpr) -> Option<Callable> {
+    pub fn resolve_method_call_as_callable(
+        &self,
+        call: &ast::MethodCallExpr,
+    ) -> Option<Callable<'db>> {
         self.analyze(call.syntax())?.resolve_method_call_as_callable(self.db, call)
     }
 
@@ -1702,14 +1705,15 @@ impl<'db> SemanticsImpl<'db> {
     pub fn resolve_field_fallback(
         &self,
         field: &ast::FieldExpr,
-    ) -> Option<(Either<Either<Field, TupleField>, Function>, Option<GenericSubstitution>)> {
+    ) -> Option<(Either<Either<Field, TupleField>, Function>, Option<GenericSubstitution<'db>>)>
+    {
         self.analyze(field.syntax())?.resolve_field_fallback(self.db, field)
     }
 
     pub fn resolve_record_field(
         &self,
         field: &ast::RecordExprField,
-    ) -> Option<(Field, Option<Local>, Type)> {
+    ) -> Option<(Field, Option<Local>, Type<'db>)> {
         self.resolve_record_field_with_substitution(field)
             .map(|(field, local, ty, _)| (field, local, ty))
     }
@@ -1717,18 +1721,21 @@ impl<'db> SemanticsImpl<'db> {
     pub fn resolve_record_field_with_substitution(
         &self,
         field: &ast::RecordExprField,
-    ) -> Option<(Field, Option<Local>, Type, GenericSubstitution)> {
+    ) -> Option<(Field, Option<Local>, Type<'db>, GenericSubstitution<'db>)> {
         self.analyze(field.syntax())?.resolve_record_field(self.db, field)
     }
 
-    pub fn resolve_record_pat_field(&self, field: &ast::RecordPatField) -> Option<(Field, Type)> {
+    pub fn resolve_record_pat_field(
+        &self,
+        field: &ast::RecordPatField,
+    ) -> Option<(Field, Type<'db>)> {
         self.resolve_record_pat_field_with_subst(field).map(|(field, ty, _)| (field, ty))
     }
 
     pub fn resolve_record_pat_field_with_subst(
         &self,
         field: &ast::RecordPatField,
-    ) -> Option<(Field, Type, GenericSubstitution)> {
+    ) -> Option<(Field, Type<'db>, GenericSubstitution<'db>)> {
         self.analyze(field.syntax())?.resolve_record_pat_field(self.db, field)
     }
 
@@ -1801,7 +1808,7 @@ impl<'db> SemanticsImpl<'db> {
     pub fn resolve_path_with_subst(
         &self,
         path: &ast::Path,
-    ) -> Option<(PathResolution, Option<GenericSubstitution>)> {
+    ) -> Option<(PathResolution, Option<GenericSubstitution<'db>>)> {
         self.analyze(path.syntax())?.resolve_path(self.db, path)
     }
 
@@ -1812,7 +1819,7 @@ impl<'db> SemanticsImpl<'db> {
     pub fn resolve_offset_of_field(
         &self,
         name_ref: &ast::NameRef,
-    ) -> Option<(Either<Variant, Field>, GenericSubstitution)> {
+    ) -> Option<(Either<Variant, Field>, GenericSubstitution<'db>)> {
         self.analyze_no_infer(name_ref.syntax())?.resolve_offset_of_field(self.db, name_ref)
     }
 
@@ -1834,13 +1841,19 @@ impl<'db> SemanticsImpl<'db> {
         self.analyze(pat.syntax())?.resolve_bind_pat_to_const(self.db, pat)
     }
 
-    pub fn record_literal_missing_fields(&self, literal: &ast::RecordExpr) -> Vec<(Field, Type)> {
+    pub fn record_literal_missing_fields(
+        &self,
+        literal: &ast::RecordExpr,
+    ) -> Vec<(Field, Type<'db>)> {
         self.analyze(literal.syntax())
             .and_then(|it| it.record_literal_missing_fields(self.db, literal))
             .unwrap_or_default()
     }
 
-    pub fn record_pattern_missing_fields(&self, pattern: &ast::RecordPat) -> Vec<(Field, Type)> {
+    pub fn record_pattern_missing_fields(
+        &self,
+        pattern: &ast::RecordPat,
+    ) -> Vec<(Field, Type<'db>)> {
         self.analyze(pattern.syntax())
             .and_then(|it| it.record_pattern_missing_fields(self.db, pattern))
             .unwrap_or_default()
diff --git a/src/tools/rust-analyzer/crates/hir/src/source_analyzer.rs b/src/tools/rust-analyzer/crates/hir/src/source_analyzer.rs
index 3273358b78e..48543ca581f 100644
--- a/src/tools/rust-analyzer/crates/hir/src/source_analyzer.rs
+++ b/src/tools/rust-analyzer/crates/hir/src/source_analyzer.rs
@@ -257,7 +257,11 @@ impl<'db> SourceAnalyzer<'db> {
         infer.expr_adjustments.get(&expr_id).map(|v| &**v)
     }
 
-    pub(crate) fn type_of_type(&self, db: &'db dyn HirDatabase, ty: &ast::Type) -> Option<Type> {
+    pub(crate) fn type_of_type(
+        &self,
+        db: &'db dyn HirDatabase,
+        ty: &ast::Type,
+    ) -> Option<Type<'db>> {
         let type_ref = self.type_id(ty)?;
         let ty = TyLoweringContext::new(
             db,
@@ -277,7 +281,7 @@ impl<'db> SourceAnalyzer<'db> {
         &self,
         db: &'db dyn HirDatabase,
         expr: &ast::Expr,
-    ) -> Option<(Type, Option<Type>)> {
+    ) -> Option<(Type<'db>, Option<Type<'db>>)> {
         let expr_id = self.expr_id(expr.clone())?;
         let infer = self.infer()?;
         let coerced = expr_id
@@ -293,7 +297,7 @@ impl<'db> SourceAnalyzer<'db> {
         &self,
         db: &'db dyn HirDatabase,
         pat: &ast::Pat,
-    ) -> Option<(Type, Option<Type>)> {
+    ) -> Option<(Type<'db>, Option<Type<'db>>)> {
         let expr_or_pat_id = self.pat_id(pat)?;
         let infer = self.infer()?;
         let coerced = match expr_or_pat_id {
@@ -316,7 +320,7 @@ impl<'db> SourceAnalyzer<'db> {
         &self,
         db: &'db dyn HirDatabase,
         pat: &ast::IdentPat,
-    ) -> Option<Type> {
+    ) -> Option<Type<'db>> {
         let binding_id = self.binding_id_of_pat(pat)?;
         let infer = self.infer()?;
         let ty = infer[binding_id].clone();
@@ -328,7 +332,7 @@ impl<'db> SourceAnalyzer<'db> {
         &self,
         db: &'db dyn HirDatabase,
         _param: &ast::SelfParam,
-    ) -> Option<Type> {
+    ) -> Option<Type<'db>> {
         let binding = self.body()?.self_param?;
         let ty = self.infer()?[binding].clone();
         Some(Type::new_with_resolver(db, &self.resolver, ty))
@@ -353,7 +357,7 @@ impl<'db> SourceAnalyzer<'db> {
         &self,
         db: &'db dyn HirDatabase,
         pat: &ast::Pat,
-    ) -> Option<SmallVec<[Type; 1]>> {
+    ) -> Option<SmallVec<[Type<'db>; 1]>> {
         let pat_id = self.pat_id(pat)?;
         let infer = self.infer()?;
         Some(
@@ -370,7 +374,7 @@ impl<'db> SourceAnalyzer<'db> {
         &self,
         db: &'db dyn HirDatabase,
         call: &ast::MethodCallExpr,
-    ) -> Option<Callable> {
+    ) -> Option<Callable<'db>> {
         let expr_id = self.expr_id(call.clone().into())?.as_expr()?;
         let (func, substs) = self.infer()?.method_resolution(expr_id)?;
         let ty = db.value_ty(func.into())?.substitute(Interner, &substs);
@@ -395,7 +399,7 @@ impl<'db> SourceAnalyzer<'db> {
         &self,
         db: &'db dyn HirDatabase,
         call: &ast::MethodCallExpr,
-    ) -> Option<(Either<Function, Field>, Option<GenericSubstitution>)> {
+    ) -> Option<(Either<Function, Field>, Option<GenericSubstitution<'db>>)> {
         let expr_id = self.expr_id(call.clone().into())?.as_expr()?;
         let inference_result = self.infer()?;
         match inference_result.method_resolution(expr_id) {
@@ -419,7 +423,7 @@ impl<'db> SourceAnalyzer<'db> {
         &self,
         db: &'db dyn HirDatabase,
         call: &ast::Expr,
-    ) -> Option<Callable> {
+    ) -> Option<Callable<'db>> {
         let (orig, adjusted) = self.type_of_expr(db, &call.clone())?;
         adjusted.unwrap_or(orig).as_callable(db)
     }
@@ -440,7 +444,7 @@ impl<'db> SourceAnalyzer<'db> {
         field_expr: ExprId,
         infer: &InferenceResult,
         db: &'db dyn HirDatabase,
-    ) -> Option<GenericSubstitution> {
+    ) -> Option<GenericSubstitution<'db>> {
         let body = self.store()?;
         if let Expr::Field { expr: object_expr, name: _ } = body[field_expr] {
             let (adt, subst) = type_of_expr_including_adjust(infer, object_expr)?.as_adt()?;
@@ -457,7 +461,8 @@ impl<'db> SourceAnalyzer<'db> {
         &self,
         db: &'db dyn HirDatabase,
         field: &ast::FieldExpr,
-    ) -> Option<(Either<Either<Field, TupleField>, Function>, Option<GenericSubstitution>)> {
+    ) -> Option<(Either<Either<Field, TupleField>, Function>, Option<GenericSubstitution<'db>>)>
+    {
         let (def, ..) = self.body_()?;
         let expr_id = self.expr_id(field.clone().into())?.as_expr()?;
         let inference_result = self.infer()?;
@@ -680,7 +685,7 @@ impl<'db> SourceAnalyzer<'db> {
         &self,
         db: &'db dyn HirDatabase,
         field: &ast::RecordExprField,
-    ) -> Option<(Field, Option<Local>, Type, GenericSubstitution)> {
+    ) -> Option<(Field, Option<Local>, Type<'db>, GenericSubstitution<'db>)> {
         let record_expr = ast::RecordExpr::cast(field.syntax().parent().and_then(|p| p.parent())?)?;
         let expr = ast::Expr::from(record_expr);
         let expr_id = self.store_sm()?.node_expr(InFile::new(self.file_id, &expr))?;
@@ -724,7 +729,7 @@ impl<'db> SourceAnalyzer<'db> {
         &self,
         db: &'db dyn HirDatabase,
         field: &ast::RecordPatField,
-    ) -> Option<(Field, Type, GenericSubstitution)> {
+    ) -> Option<(Field, Type<'db>, GenericSubstitution<'db>)> {
         let field_name = field.field_name()?.as_name();
         let record_pat = ast::RecordPat::cast(field.syntax().parent().and_then(|p| p.parent())?)?;
         let pat_id = self.pat_id(&record_pat.into())?;
@@ -779,7 +784,7 @@ impl<'db> SourceAnalyzer<'db> {
         &self,
         db: &'db dyn HirDatabase,
         name_ref: &ast::NameRef,
-    ) -> Option<(Either<crate::Variant, crate::Field>, GenericSubstitution)> {
+    ) -> Option<(Either<crate::Variant, crate::Field>, GenericSubstitution<'db>)> {
         let offset_of_expr = ast::OffsetOfExpr::cast(name_ref.syntax().parent()?)?;
         let container = offset_of_expr.ty()?;
         let container = self.type_of_type(db, &container)?;
@@ -851,7 +856,7 @@ impl<'db> SourceAnalyzer<'db> {
         &self,
         db: &'db dyn HirDatabase,
         path: &ast::Path,
-    ) -> Option<(PathResolution, Option<GenericSubstitution>)> {
+    ) -> Option<(PathResolution, Option<GenericSubstitution<'db>>)> {
         let parent = path.syntax().parent();
         let parent = || parent.clone();
 
@@ -1216,7 +1221,7 @@ impl<'db> SourceAnalyzer<'db> {
         &self,
         db: &'db dyn HirDatabase,
         literal: &ast::RecordExpr,
-    ) -> Option<Vec<(Field, Type)>> {
+    ) -> Option<Vec<(Field, Type<'db>)>> {
         let body = self.store()?;
         let infer = self.infer()?;
 
@@ -1239,7 +1244,7 @@ impl<'db> SourceAnalyzer<'db> {
         &self,
         db: &'db dyn HirDatabase,
         pattern: &ast::RecordPat,
-    ) -> Option<Vec<(Field, Type)>> {
+    ) -> Option<Vec<(Field, Type<'db>)>> {
         let body = self.store()?;
         let infer = self.infer()?;
 
@@ -1258,7 +1263,7 @@ impl<'db> SourceAnalyzer<'db> {
         substs: &Substitution,
         variant: VariantId,
         missing_fields: Vec<LocalFieldId>,
-    ) -> Vec<(Field, Type)> {
+    ) -> Vec<(Field, Type<'db>)> {
         let field_types = db.field_types(variant);
 
         missing_fields
diff --git a/src/tools/rust-analyzer/crates/hir/src/term_search.rs b/src/tools/rust-analyzer/crates/hir/src/term_search.rs
index af72179305c..4b354e64062 100644
--- a/src/tools/rust-analyzer/crates/hir/src/term_search.rs
+++ b/src/tools/rust-analyzer/crates/hir/src/term_search.rs
@@ -22,20 +22,20 @@ enum NewTypesKey {
 /// 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 {
+enum AlternativeExprs<'db> {
     /// There are few trees, so we keep track of them all
-    Few(FxHashSet<Expr>),
+    Few(FxHashSet<Expr<'db>>),
     /// There are too many trees to keep track of
     Many,
 }
 
-impl AlternativeExprs {
+impl<'db> AlternativeExprs<'db> {
     /// 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 {
+    fn new(threshold: usize, exprs: impl Iterator<Item = Expr<'db>>) -> AlternativeExprs<'db> {
         let mut it = AlternativeExprs::Few(Default::default());
         it.extend_with_threshold(threshold, exprs);
         it
@@ -45,7 +45,7 @@ impl AlternativeExprs {
     ///
     /// # Arguments
     /// `ty` - Type of expressions queried (this is used to give type to `Expr::Many`)
-    fn exprs(&self, ty: &Type) -> Vec<Expr> {
+    fn exprs(&self, ty: &Type<'db>) -> Vec<Expr<'db>> {
         match self {
             AlternativeExprs::Few(exprs) => exprs.iter().cloned().collect(),
             AlternativeExprs::Many => vec![Expr::Many(ty.clone())],
@@ -57,7 +57,7 @@ impl AlternativeExprs {
     /// # 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>) {
+    fn extend_with_threshold(&mut self, threshold: usize, exprs: impl Iterator<Item = Expr<'db>>) {
         match self {
             AlternativeExprs::Few(tts) => {
                 for it in exprs {
@@ -88,20 +88,20 @@ impl AlternativeExprs {
 /// 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 {
+struct LookupTable<'db> {
     /// All the `Expr`s in "value" produce the type of "key"
-    data: FxHashMap<Type, AlternativeExprs>,
+    data: FxHashMap<Type<'db>, AlternativeExprs<'db>>,
     /// New types reached since last query by the `NewTypesKey`
-    new_types: FxHashMap<NewTypesKey, Vec<Type>>,
+    new_types: FxHashMap<NewTypesKey, Vec<Type<'db>>>,
     /// Types queried but not present
-    types_wishlist: FxHashSet<Type>,
+    types_wishlist: FxHashSet<Type<'db>>,
     /// Threshold to squash trees to `Many`
     many_threshold: usize,
 }
 
-impl LookupTable {
+impl<'db> LookupTable<'db> {
     /// Initialize lookup table
-    fn new(many_threshold: usize, goal: Type) -> Self {
+    fn new(many_threshold: usize, goal: Type<'db>) -> 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());
@@ -110,7 +110,7 @@ impl LookupTable {
     }
 
     /// Find all `Expr`s that unify with the `ty`
-    fn find(&mut self, db: &dyn HirDatabase, ty: &Type) -> Option<Vec<Expr>> {
+    fn find(&mut self, db: &'db dyn HirDatabase, ty: &Type<'db>) -> Option<Vec<Expr<'db>>> {
         let res = self
             .data
             .iter()
@@ -135,7 +135,7 @@ impl LookupTable {
     ///
     /// 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(&mut self, db: &dyn HirDatabase, ty: &Type) -> Option<Vec<Expr>> {
+    fn find_autoref(&mut self, db: &'db dyn HirDatabase, ty: &Type<'db>) -> Option<Vec<Expr<'db>>> {
         let res = self
             .data
             .iter()
@@ -174,7 +174,7 @@ impl LookupTable {
     /// 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>) {
+    fn insert(&mut self, ty: Type<'db>, exprs: impl Iterator<Item = Expr<'db>>) {
         match self.data.get_mut(&ty) {
             Some(it) => {
                 it.extend_with_threshold(self.many_threshold, exprs);
@@ -192,14 +192,14 @@ impl LookupTable {
     }
 
     /// Iterate all the reachable types
-    fn iter_types(&self) -> impl Iterator<Item = Type> + '_ {
+    fn iter_types(&self) -> impl Iterator<Item = Type<'db>> + '_ {
         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> {
+    fn new_types(&mut self, key: NewTypesKey) -> Vec<Type<'db>> {
         match self.new_types.get_mut(&key) {
             Some(it) => std::mem::take(it),
             None => Vec::new(),
@@ -207,20 +207,20 @@ impl LookupTable {
     }
 
     /// Types queried but not found
-    fn types_wishlist(&mut self) -> &FxHashSet<Type> {
+    fn types_wishlist(&mut self) -> &FxHashSet<Type<'db>> {
         &self.types_wishlist
     }
 }
 
 /// Context for the `term_search` function
 #[derive(Debug)]
-pub struct TermSearchCtx<'a, DB: HirDatabase> {
+pub struct TermSearchCtx<'db, DB: HirDatabase> {
     /// Semantics for the program
-    pub sema: &'a Semantics<'a, DB>,
+    pub sema: &'db Semantics<'db, DB>,
     /// Semantic scope, captures context for the term search
-    pub scope: &'a SemanticsScope<'a>,
+    pub scope: &'db SemanticsScope<'db>,
     /// Target / expected output type
-    pub goal: Type,
+    pub goal: Type<'db>,
     /// Configuration for term search
     pub config: TermSearchConfig,
 }
@@ -263,7 +263,7 @@ impl Default for TermSearchConfig {
 /// 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> {
+pub fn term_search<'db, DB: HirDatabase>(ctx: &'db TermSearchCtx<'db, DB>) -> Vec<Expr<'db>> {
     let module = ctx.scope.module();
     let mut defs = FxHashSet::default();
     defs.insert(ScopeDef::ModuleDef(ModuleDef::Module(module)));
@@ -285,7 +285,7 @@ pub fn term_search<DB: HirDatabase>(ctx: &TermSearchCtx<'_, DB>) -> Vec<Expr> {
     };
 
     // Try trivial tactic first, also populates lookup table
-    let mut solutions: Vec<Expr> = tactics::trivial(ctx, &defs, &mut lookup).collect();
+    let mut solutions: Vec<Expr<'db>> = 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));
     solutions.extend(tactics::assoc_const(ctx, &defs, &mut lookup));
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
index 78ee3b5aa68..843831948ad 100644
--- a/src/tools/rust-analyzer/crates/hir/src/term_search/expr.rs
+++ b/src/tools/rust-analyzer/crates/hir/src/term_search/expr.rs
@@ -59,7 +59,7 @@ fn mod_item_path_str(
 /// 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 {
+pub enum Expr<'db> {
     /// Constant
     Const(Const),
     /// Static variable
@@ -69,26 +69,31 @@ pub enum Expr {
     /// Constant generic parameter
     ConstParam(ConstParam),
     /// Well known type (such as `true` for bool)
-    FamousType { ty: Type, value: &'static str },
+    FamousType { ty: Type<'db>, value: &'static str },
     /// Function call (does not take self param)
-    Function { func: Function, generics: Vec<Type>, params: Vec<Expr> },
+    Function { func: Function, generics: Vec<Type<'db>>, params: Vec<Expr<'db>> },
     /// Method call (has self param)
-    Method { func: Function, generics: Vec<Type>, target: Box<Expr>, params: Vec<Expr> },
+    Method {
+        func: Function,
+        generics: Vec<Type<'db>>,
+        target: Box<Expr<'db>>,
+        params: Vec<Expr<'db>>,
+    },
     /// Enum variant construction
-    Variant { variant: Variant, generics: Vec<Type>, params: Vec<Expr> },
+    Variant { variant: Variant, generics: Vec<Type<'db>>, params: Vec<Expr<'db>> },
     /// Struct construction
-    Struct { strukt: Struct, generics: Vec<Type>, params: Vec<Expr> },
+    Struct { strukt: Struct, generics: Vec<Type<'db>>, params: Vec<Expr<'db>> },
     /// Tuple construction
-    Tuple { ty: Type, params: Vec<Expr> },
+    Tuple { ty: Type<'db>, params: Vec<Expr<'db>> },
     /// Struct field access
-    Field { expr: Box<Expr>, field: Field },
+    Field { expr: Box<Expr<'db>>, field: Field },
     /// Passing type as reference (with `&`)
-    Reference(Box<Expr>),
+    Reference(Box<Expr<'db>>),
     /// Indicates possibility of many different options that all evaluate to `ty`
-    Many(Type),
+    Many(Type<'db>),
 }
 
-impl Expr {
+impl<'db> Expr<'db> {
     /// Generate source code for type tree.
     ///
     /// Note that trait imports are not added to generated code.
@@ -96,8 +101,8 @@ impl Expr {
     /// by `traits_used` method are also imported.
     pub fn gen_source_code(
         &self,
-        sema_scope: &SemanticsScope<'_>,
-        many_formatter: &mut dyn FnMut(&Type) -> String,
+        sema_scope: &SemanticsScope<'db>,
+        many_formatter: &mut dyn FnMut(&Type<'db>) -> String,
         cfg: ImportPathConfig,
         display_target: DisplayTarget,
     ) -> Result<String, DisplaySourceCodeError> {
@@ -298,7 +303,7 @@ impl Expr {
     /// Get type of the type tree.
     ///
     /// Same as getting the type of root node
-    pub fn ty(&self, db: &dyn HirDatabase) -> Type {
+    pub fn ty(&self, db: &'db dyn HirDatabase) -> Type<'db> {
         match self {
             Expr::Const(it) => it.ty(db),
             Expr::Static(it) => it.ty(db),
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
index bcff44fcd01..9df131f90e4 100644
--- a/src/tools/rust-analyzer/crates/hir/src/term_search/tactics.rs
+++ b/src/tools/rust-analyzer/crates/hir/src/term_search/tactics.rs
@@ -40,11 +40,11 @@ use super::{LookupTable, NewTypesKey, TermSearchCtx};
 ///
 /// _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>,
+pub(super) fn trivial<'a, 'lt, 'db, DB: HirDatabase>(
+    ctx: &'a TermSearchCtx<'db, DB>,
     defs: &'a FxHashSet<ScopeDef>,
-    lookup: &'a mut LookupTable,
-) -> impl Iterator<Item = Expr> + 'a {
+    lookup: &'lt mut LookupTable<'db>,
+) -> impl Iterator<Item = Expr<'db>> + use<'a, 'db, 'lt, DB> {
     let db = ctx.sema.db;
     defs.iter().filter_map(|def| {
         let expr = match def {
@@ -104,11 +104,11 @@ pub(super) fn trivial<'a, DB: HirDatabase>(
 ///
 /// _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 assoc_const<'a, DB: HirDatabase>(
-    ctx: &'a TermSearchCtx<'a, DB>,
+pub(super) fn assoc_const<'a, 'lt, 'db, DB: HirDatabase>(
+    ctx: &'a TermSearchCtx<'db, DB>,
     defs: &'a FxHashSet<ScopeDef>,
-    lookup: &'a mut LookupTable,
-) -> impl Iterator<Item = Expr> + 'a {
+    lookup: &'lt mut LookupTable<'db>,
+) -> impl Iterator<Item = Expr<'db>> + use<'a, 'db, 'lt, DB> {
     let db = ctx.sema.db;
     let module = ctx.scope.module();
 
@@ -152,12 +152,12 @@ pub(super) fn assoc_const<'a, DB: HirDatabase>(
 /// * `defs` - Set of items in scope at term search target location
 /// * `lookup` - Lookup table for types
 /// * `should_continue` - Function that indicates when to stop iterating
-pub(super) fn data_constructor<'a, DB: HirDatabase>(
-    ctx: &'a TermSearchCtx<'a, DB>,
+pub(super) fn data_constructor<'a, 'lt, 'db, DB: HirDatabase>(
+    ctx: &'a TermSearchCtx<'db, DB>,
     _defs: &'a FxHashSet<ScopeDef>,
-    lookup: &'a mut LookupTable,
+    lookup: &'lt mut LookupTable<'db>,
     should_continue: &'a dyn std::ops::Fn() -> bool,
-) -> impl Iterator<Item = Expr> + 'a {
+) -> impl Iterator<Item = Expr<'db>> + use<'a, 'db, 'lt, DB> {
     let db = ctx.sema.db;
     let module = ctx.scope.module();
     lookup
@@ -199,14 +199,14 @@ pub(super) fn data_constructor<'a, DB: HirDatabase>(
                 let generics: Vec<_> = ty.type_arguments().collect();
 
                 // Early exit if some param cannot be filled from lookup
-                let param_exprs: Vec<Vec<Expr>> = fields
+                let param_exprs: Vec<Vec<Expr<'_>>> = fields
                     .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 exprs: Vec<Expr> = if param_exprs.is_empty() {
+                let exprs: Vec<Expr<'_>> = if param_exprs.is_empty() {
                     vec![Expr::Struct { strukt, generics, params: Vec::new() }]
                 } else {
                     param_exprs
@@ -247,7 +247,7 @@ pub(super) fn data_constructor<'a, DB: HirDatabase>(
                     .into_iter()
                     .filter_map(|variant| {
                         // Early exit if some param cannot be filled from lookup
-                        let param_exprs: Vec<Vec<Expr>> = variant
+                        let param_exprs: Vec<Vec<Expr<'_>>> = variant
                             .fields(db)
                             .into_iter()
                             .map(|field| {
@@ -257,7 +257,7 @@ pub(super) fn data_constructor<'a, DB: HirDatabase>(
 
                         // 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() {
+                        let variant_exprs: Vec<Expr<'_>> = if param_exprs.is_empty() {
                             vec![Expr::Variant {
                                 variant,
                                 generics: generics.clone(),
@@ -301,12 +301,12 @@ pub(super) fn data_constructor<'a, DB: HirDatabase>(
 /// * `defs` - Set of items in scope at term search target location
 /// * `lookup` - Lookup table for types
 /// * `should_continue` - Function that indicates when to stop iterating
-pub(super) fn free_function<'a, DB: HirDatabase>(
-    ctx: &'a TermSearchCtx<'a, DB>,
+pub(super) fn free_function<'a, 'lt, 'db, DB: HirDatabase>(
+    ctx: &'a TermSearchCtx<'db, DB>,
     defs: &'a FxHashSet<ScopeDef>,
-    lookup: &'a mut LookupTable,
+    lookup: &'lt mut LookupTable<'db>,
     should_continue: &'a dyn std::ops::Fn() -> bool,
-) -> impl Iterator<Item = Expr> + 'a {
+) -> impl Iterator<Item = Expr<'db>> + use<'a, 'db, 'lt, DB> {
     let db = ctx.sema.db;
     let module = ctx.scope.module();
     defs.iter()
@@ -375,7 +375,7 @@ pub(super) fn free_function<'a, DB: HirDatabase>(
                         }
 
                         // Early exit if some param cannot be filled from lookup
-                        let param_exprs: Vec<Vec<Expr>> = it
+                        let param_exprs: Vec<Vec<Expr<'_>>> = it
                             .params_without_self_with_args(db, generics.iter().cloned())
                             .into_iter()
                             .map(|field| {
@@ -389,7 +389,7 @@ pub(super) fn free_function<'a, DB: HirDatabase>(
 
                         // 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() {
+                        let fn_exprs: Vec<Expr<'_>> = if param_exprs.is_empty() {
                             vec![Expr::Function { func: *it, generics, params: Vec::new() }]
                         } else {
                             param_exprs
@@ -432,12 +432,12 @@ pub(super) fn free_function<'a, DB: HirDatabase>(
 /// * `defs` - Set of items in scope at term search target location
 /// * `lookup` - Lookup table for types
 /// * `should_continue` - Function that indicates when to stop iterating
-pub(super) fn impl_method<'a, DB: HirDatabase>(
-    ctx: &'a TermSearchCtx<'a, DB>,
+pub(super) fn impl_method<'a, 'lt, 'db, DB: HirDatabase>(
+    ctx: &'a TermSearchCtx<'db, DB>,
     _defs: &'a FxHashSet<ScopeDef>,
-    lookup: &'a mut LookupTable,
+    lookup: &'lt mut LookupTable<'db>,
     should_continue: &'a dyn std::ops::Fn() -> bool,
-) -> impl Iterator<Item = Expr> + 'a {
+) -> impl Iterator<Item = Expr<'db>> + use<'a, 'db, 'lt, DB> {
     let db = ctx.sema.db;
     let module = ctx.scope.module();
     lookup
@@ -507,14 +507,14 @@ pub(super) fn impl_method<'a, DB: HirDatabase>(
             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
+            let param_exprs: Vec<Vec<Expr<'_>>> = it
                 .params_without_self_with_args(db, ty.type_arguments())
                 .into_iter()
                 .map(|field| lookup.find_autoref(db, field.ty()))
                 .collect::<Option<_>>()?;
 
             let generics: Vec<_> = ty.type_arguments().collect();
-            let fn_exprs: Vec<Expr> = std::iter::once(target_type_exprs)
+            let fn_exprs: Vec<Expr<'_>> = std::iter::once(target_type_exprs)
                 .chain(param_exprs)
                 .multi_cartesian_product()
                 .map(|params| {
@@ -547,12 +547,12 @@ pub(super) fn impl_method<'a, DB: HirDatabase>(
 /// * `defs` - Set of items in scope at term search target location
 /// * `lookup` - Lookup table for types
 /// * `should_continue` - Function that indicates when to stop iterating
-pub(super) fn struct_projection<'a, DB: HirDatabase>(
-    ctx: &'a TermSearchCtx<'a, DB>,
+pub(super) fn struct_projection<'a, 'lt, 'db, DB: HirDatabase>(
+    ctx: &'a TermSearchCtx<'db, DB>,
     _defs: &'a FxHashSet<ScopeDef>,
-    lookup: &'a mut LookupTable,
+    lookup: &'lt mut LookupTable<'db>,
     should_continue: &'a dyn std::ops::Fn() -> bool,
-) -> impl Iterator<Item = Expr> + 'a {
+) -> impl Iterator<Item = Expr<'db>> + use<'a, 'db, 'lt, DB> {
     let db = ctx.sema.db;
     let module = ctx.scope.module();
     lookup
@@ -589,11 +589,11 @@ pub(super) fn struct_projection<'a, DB: HirDatabase>(
 /// * `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>,
+pub(super) fn famous_types<'a, 'lt, 'db, DB: HirDatabase>(
+    ctx: &'a TermSearchCtx<'db, DB>,
     _defs: &'a FxHashSet<ScopeDef>,
-    lookup: &'a mut LookupTable,
-) -> impl Iterator<Item = Expr> + 'a {
+    lookup: &'lt mut LookupTable<'db>,
+) -> impl Iterator<Item = Expr<'db>> + use<'a, 'db, 'lt, DB> {
     let db = ctx.sema.db;
     let module = ctx.scope.module();
     [
@@ -620,12 +620,12 @@ pub(super) fn famous_types<'a, DB: HirDatabase>(
 /// * `defs` - Set of items in scope at term search target location
 /// * `lookup` - Lookup table for types
 /// * `should_continue` - Function that indicates when to stop iterating
-pub(super) fn impl_static_method<'a, DB: HirDatabase>(
-    ctx: &'a TermSearchCtx<'a, DB>,
+pub(super) fn impl_static_method<'a, 'lt, 'db, DB: HirDatabase>(
+    ctx: &'a TermSearchCtx<'db, DB>,
     _defs: &'a FxHashSet<ScopeDef>,
-    lookup: &'a mut LookupTable,
+    lookup: &'lt mut LookupTable<'db>,
     should_continue: &'a dyn std::ops::Fn() -> bool,
-) -> impl Iterator<Item = Expr> + 'a {
+) -> impl Iterator<Item = Expr<'db>> + use<'a, 'db, 'lt, DB> {
     let db = ctx.sema.db;
     let module = ctx.scope.module();
     lookup
@@ -683,7 +683,7 @@ pub(super) fn impl_static_method<'a, DB: HirDatabase>(
             }
 
             // Early exit if some param cannot be filled from lookup
-            let param_exprs: Vec<Vec<Expr>> = it
+            let param_exprs: Vec<Vec<Expr<'_>>> = it
                 .params_without_self_with_args(db, ty.type_arguments())
                 .into_iter()
                 .map(|field| lookup.find_autoref(db, field.ty()))
@@ -692,7 +692,7 @@ pub(super) fn impl_static_method<'a, DB: HirDatabase>(
             // Note that we need special case for 0 param constructors because of multi cartesian
             // product
             let generics = ty.type_arguments().collect();
-            let fn_exprs: Vec<Expr> = if param_exprs.is_empty() {
+            let fn_exprs: Vec<Expr<'_>> = if param_exprs.is_empty() {
                 vec![Expr::Function { func: it, generics, params: Vec::new() }]
             } else {
                 param_exprs
@@ -722,12 +722,12 @@ pub(super) fn impl_static_method<'a, DB: HirDatabase>(
 /// * `defs` - Set of items in scope at term search target location
 /// * `lookup` - Lookup table for types
 /// * `should_continue` - Function that indicates when to stop iterating
-pub(super) fn make_tuple<'a, DB: HirDatabase>(
-    ctx: &'a TermSearchCtx<'a, DB>,
+pub(super) fn make_tuple<'a, 'lt, 'db, DB: HirDatabase>(
+    ctx: &'a TermSearchCtx<'db, DB>,
     _defs: &'a FxHashSet<ScopeDef>,
-    lookup: &'a mut LookupTable,
+    lookup: &'lt mut LookupTable<'db>,
     should_continue: &'a dyn std::ops::Fn() -> bool,
-) -> impl Iterator<Item = Expr> + 'a {
+) -> impl Iterator<Item = Expr<'db>> + use<'a, 'db, 'lt, DB> {
     let db = ctx.sema.db;
     let module = ctx.scope.module();
 
@@ -749,15 +749,15 @@ pub(super) fn make_tuple<'a, DB: HirDatabase>(
             }
 
             // Early exit if some param cannot be filled from lookup
-            let param_exprs: Vec<Vec<Expr>> =
+            let param_exprs: Vec<Vec<Expr<'db>>> =
                 ty.type_arguments().map(|field| lookup.find(db, &field)).collect::<Option<_>>()?;
 
-            let exprs: Vec<Expr> = param_exprs
+            let exprs: Vec<Expr<'db>> = param_exprs
                 .into_iter()
                 .multi_cartesian_product()
                 .filter(|_| should_continue())
                 .map(|params| {
-                    let tys: Vec<Type> = params.iter().map(|it| it.ty(db)).collect();
+                    let tys: Vec<Type<'_>> = params.iter().map(|it| it.ty(db)).collect();
                     let tuple_ty = Type::new_tuple(module.krate().into(), &tys);
 
                     let expr = Expr::Tuple { ty: tuple_ty.clone(), params };
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/assist_config.rs b/src/tools/rust-analyzer/crates/ide-assists/src/assist_config.rs
index fb569f8cdae..57ced8d8534 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/assist_config.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/assist_config.rs
@@ -22,6 +22,7 @@ pub struct AssistConfig {
     pub term_search_borrowck: bool,
     pub code_action_grouping: bool,
     pub expr_fill_default: ExprFillDefaultMode,
+    pub prefer_self_ty: bool,
 }
 
 impl AssistConfig {
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/assist_context.rs b/src/tools/rust-analyzer/crates/ide-assists/src/assist_context.rs
index 9eb9452a2b8..207a7548f49 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/assist_context.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/assist_context.rs
@@ -95,7 +95,7 @@ impl<'a> AssistContext<'a> {
         }
     }
 
-    pub(crate) fn db(&self) -> &RootDatabase {
+    pub(crate) fn db(&self) -> &'a RootDatabase {
         self.sema.db
     }
 
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/add_missing_impl_members.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/add_missing_impl_members.rs
index 6a55f39e693..9f9d21923ff 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/add_missing_impl_members.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/add_missing_impl_members.rs
@@ -192,7 +192,7 @@ fn add_missing_impl_members_inner(
 fn try_gen_trait_body(
     ctx: &AssistContext<'_>,
     func: &ast::Fn,
-    trait_ref: hir::TraitRef,
+    trait_ref: hir::TraitRef<'_>,
     impl_def: &ast::Impl,
     edition: Edition,
 ) -> Option<()> {
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/add_missing_match_arms.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/add_missing_match_arms.rs
index 858d4369914..1ece7ddab10 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/add_missing_match_arms.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/add_missing_match_arms.rs
@@ -1,12 +1,13 @@
 use std::iter::{self, Peekable};
 
 use either::Either;
-use hir::{Adt, Crate, HasAttrs, ImportPathConfig, ModuleDef, Semantics, sym};
+use hir::{Adt, AsAssocItem, Crate, HasAttrs, ImportPathConfig, ModuleDef, Semantics, sym};
 use ide_db::RootDatabase;
 use ide_db::assists::ExprFillDefaultMode;
 use ide_db::syntax_helpers::suggest_name;
 use ide_db::{famous_defs::FamousDefs, helpers::mod_path_to_ast};
 use itertools::Itertools;
+use syntax::ToSmolStr;
 use syntax::ast::edit::IndentLevel;
 use syntax::ast::edit_in_place::Indent;
 use syntax::ast::syntax_factory::SyntaxFactory;
@@ -79,12 +80,20 @@ pub(crate) fn add_missing_match_arms(acc: &mut Assists, ctx: &AssistContext<'_>)
 
     let make = SyntaxFactory::with_mappings();
 
-    let module = ctx.sema.scope(expr.syntax())?.module();
+    let scope = ctx.sema.scope(expr.syntax())?;
+    let module = scope.module();
+    let self_ty = if ctx.config.prefer_self_ty {
+        scope
+            .containing_function()
+            .and_then(|function| function.as_assoc_item(ctx.db())?.implementing_ty(ctx.db()))
+    } else {
+        None
+    };
     let (mut missing_pats, is_non_exhaustive, has_hidden_variants): (
         Peekable<Box<dyn Iterator<Item = (ast::Pat, bool)>>>,
         bool,
         bool,
-    ) = if let Some(enum_def) = resolve_enum_def(&ctx.sema, &expr) {
+    ) = if let Some(enum_def) = resolve_enum_def(&ctx.sema, &expr, self_ty.as_ref()) {
         let is_non_exhaustive = enum_def.is_non_exhaustive(ctx.db(), module.krate());
 
         let variants = enum_def.variants(ctx.db());
@@ -102,8 +111,9 @@ pub(crate) fn add_missing_match_arms(acc: &mut Assists, ctx: &AssistContext<'_>)
             })
             .filter(|(variant_pat, _)| is_variant_missing(&top_lvl_pats, variant_pat));
 
-        let option_enum = FamousDefs(&ctx.sema, module.krate()).core_option_Option().map(lift_enum);
-        let missing_pats: Box<dyn Iterator<Item = _>> = if Some(enum_def) == option_enum {
+        let option_enum = FamousDefs(&ctx.sema, module.krate()).core_option_Option();
+        let missing_pats: Box<dyn Iterator<Item = _>> = if matches!(enum_def, ExtendedEnum::Enum { enum_: e, .. } if Some(e) == option_enum)
+        {
             // Match `Some` variant first.
             cov_mark::hit!(option_order);
             Box::new(missing_pats.rev())
@@ -111,7 +121,7 @@ pub(crate) fn add_missing_match_arms(acc: &mut Assists, ctx: &AssistContext<'_>)
             Box::new(missing_pats)
         };
         (missing_pats.peekable(), is_non_exhaustive, has_hidden_variants)
-    } else if let Some(enum_defs) = resolve_tuple_of_enum_def(&ctx.sema, &expr) {
+    } else if let Some(enum_defs) = resolve_tuple_of_enum_def(&ctx.sema, &expr, self_ty.as_ref()) {
         let is_non_exhaustive =
             enum_defs.iter().any(|enum_def| enum_def.is_non_exhaustive(ctx.db(), module.krate()));
 
@@ -159,7 +169,9 @@ pub(crate) fn add_missing_match_arms(acc: &mut Assists, ctx: &AssistContext<'_>)
             is_non_exhaustive,
             has_hidden_variants,
         )
-    } else if let Some((enum_def, len)) = resolve_array_of_enum_def(&ctx.sema, &expr) {
+    } else if let Some((enum_def, len)) =
+        resolve_array_of_enum_def(&ctx.sema, &expr, self_ty.as_ref())
+    {
         let is_non_exhaustive = enum_def.is_non_exhaustive(ctx.db(), module.krate());
         let variants = enum_def.variants(ctx.db());
 
@@ -373,23 +385,23 @@ fn does_pat_match_variant(pat: &Pat, var: &Pat) -> bool {
     }
 }
 
-#[derive(Eq, PartialEq, Clone, Copy)]
+#[derive(Eq, PartialEq, Clone)]
 enum ExtendedEnum {
     Bool,
-    Enum(hir::Enum),
+    Enum { enum_: hir::Enum, use_self: bool },
 }
 
 #[derive(Eq, PartialEq, Clone, Copy, Debug)]
 enum ExtendedVariant {
     True,
     False,
-    Variant(hir::Variant),
+    Variant { variant: hir::Variant, use_self: bool },
 }
 
 impl ExtendedVariant {
     fn should_be_hidden(self, db: &RootDatabase, krate: Crate) -> bool {
         match self {
-            ExtendedVariant::Variant(var) => {
+            ExtendedVariant::Variant { variant: var, .. } => {
                 var.attrs(db).has_doc_hidden() && var.module(db).krate() != krate
             }
             _ => false,
@@ -397,25 +409,35 @@ impl ExtendedVariant {
     }
 }
 
-fn lift_enum(e: hir::Enum) -> ExtendedEnum {
-    ExtendedEnum::Enum(e)
-}
-
 impl ExtendedEnum {
-    fn is_non_exhaustive(self, db: &RootDatabase, krate: Crate) -> bool {
+    fn enum_(
+        db: &RootDatabase,
+        enum_: hir::Enum,
+        enum_ty: &hir::Type<'_>,
+        self_ty: Option<&hir::Type<'_>>,
+    ) -> Self {
+        ExtendedEnum::Enum {
+            enum_,
+            use_self: self_ty.is_some_and(|self_ty| self_ty.could_unify_with_deeply(db, enum_ty)),
+        }
+    }
+
+    fn is_non_exhaustive(&self, db: &RootDatabase, krate: Crate) -> bool {
         match self {
-            ExtendedEnum::Enum(e) => {
+            ExtendedEnum::Enum { enum_: e, .. } => {
                 e.attrs(db).by_key(sym::non_exhaustive).exists() && e.module(db).krate() != krate
             }
             _ => false,
         }
     }
 
-    fn variants(self, db: &RootDatabase) -> Vec<ExtendedVariant> {
-        match self {
-            ExtendedEnum::Enum(e) => {
-                e.variants(db).into_iter().map(ExtendedVariant::Variant).collect::<Vec<_>>()
-            }
+    fn variants(&self, db: &RootDatabase) -> Vec<ExtendedVariant> {
+        match *self {
+            ExtendedEnum::Enum { enum_: e, use_self } => e
+                .variants(db)
+                .into_iter()
+                .map(|variant| ExtendedVariant::Variant { variant, use_self })
+                .collect::<Vec<_>>(),
             ExtendedEnum::Bool => {
                 Vec::<ExtendedVariant>::from([ExtendedVariant::True, ExtendedVariant::False])
             }
@@ -423,9 +445,13 @@ impl ExtendedEnum {
     }
 }
 
-fn resolve_enum_def(sema: &Semantics<'_, RootDatabase>, expr: &ast::Expr) -> Option<ExtendedEnum> {
+fn resolve_enum_def(
+    sema: &Semantics<'_, RootDatabase>,
+    expr: &ast::Expr,
+    self_ty: Option<&hir::Type<'_>>,
+) -> Option<ExtendedEnum> {
     sema.type_of_expr(expr)?.adjusted().autoderef(sema.db).find_map(|ty| match ty.as_adt() {
-        Some(Adt::Enum(e)) => Some(ExtendedEnum::Enum(e)),
+        Some(Adt::Enum(e)) => Some(ExtendedEnum::enum_(sema.db, e, &ty, self_ty)),
         _ => ty.is_bool().then_some(ExtendedEnum::Bool),
     })
 }
@@ -433,6 +459,7 @@ fn resolve_enum_def(sema: &Semantics<'_, RootDatabase>, expr: &ast::Expr) -> Opt
 fn resolve_tuple_of_enum_def(
     sema: &Semantics<'_, RootDatabase>,
     expr: &ast::Expr,
+    self_ty: Option<&hir::Type<'_>>,
 ) -> Option<Vec<ExtendedEnum>> {
     sema.type_of_expr(expr)?
         .adjusted()
@@ -441,7 +468,7 @@ fn resolve_tuple_of_enum_def(
         .map(|ty| {
             ty.autoderef(sema.db).find_map(|ty| {
                 match ty.as_adt() {
-                    Some(Adt::Enum(e)) => Some(lift_enum(e)),
+                    Some(Adt::Enum(e)) => Some(ExtendedEnum::enum_(sema.db, e, &ty, self_ty)),
                     // For now we only handle expansion for a tuple of enums. Here
                     // we map non-enum items to None and rely on `collect` to
                     // convert Vec<Option<hir::Enum>> into Option<Vec<hir::Enum>>.
@@ -456,10 +483,11 @@ fn resolve_tuple_of_enum_def(
 fn resolve_array_of_enum_def(
     sema: &Semantics<'_, RootDatabase>,
     expr: &ast::Expr,
+    self_ty: Option<&hir::Type<'_>>,
 ) -> Option<(ExtendedEnum, usize)> {
     sema.type_of_expr(expr)?.adjusted().as_array(sema.db).and_then(|(ty, len)| {
         ty.autoderef(sema.db).find_map(|ty| match ty.as_adt() {
-            Some(Adt::Enum(e)) => Some((lift_enum(e), len)),
+            Some(Adt::Enum(e)) => Some((ExtendedEnum::enum_(sema.db, e, &ty, self_ty), len)),
             _ => ty.is_bool().then_some((ExtendedEnum::Bool, len)),
         })
     })
@@ -474,9 +502,21 @@ fn build_pat(
 ) -> Option<ast::Pat> {
     let db = ctx.db();
     match var {
-        ExtendedVariant::Variant(var) => {
+        ExtendedVariant::Variant { variant: var, use_self } => {
             let edition = module.krate().edition(db);
-            let path = mod_path_to_ast(&module.find_path(db, ModuleDef::from(var), cfg)?, edition);
+            let path = if use_self {
+                make::path_from_segments(
+                    [
+                        make::path_segment(make::name_ref_self_ty()),
+                        make::path_segment(make::name_ref(
+                            &var.name(db).display(db, edition).to_smolstr(),
+                        )),
+                    ],
+                    false,
+                )
+            } else {
+                mod_path_to_ast(&module.find_path(db, ModuleDef::from(var), cfg)?, edition)
+            };
             let fields = var.fields(db);
             let pat: ast::Pat = match var.kind(db) {
                 hir::StructKind::Tuple => {
@@ -509,8 +549,10 @@ fn build_pat(
 
 #[cfg(test)]
 mod tests {
+    use crate::AssistConfig;
     use crate::tests::{
-        check_assist, check_assist_not_applicable, check_assist_target, check_assist_unresolved,
+        TEST_CONFIG, check_assist, check_assist_not_applicable, check_assist_target,
+        check_assist_unresolved, check_assist_with_config,
     };
 
     use super::add_missing_match_arms;
@@ -2095,4 +2137,111 @@ fn f() {
 "#,
         );
     }
+
+    #[test]
+    fn prefer_self() {
+        check_assist_with_config(
+            add_missing_match_arms,
+            AssistConfig { prefer_self_ty: true, ..TEST_CONFIG },
+            r#"
+enum Foo {
+    Bar,
+    Baz,
+}
+
+impl Foo {
+    fn qux(&self) {
+        match self {
+            $0_ => {}
+        }
+    }
+}
+            "#,
+            r#"
+enum Foo {
+    Bar,
+    Baz,
+}
+
+impl Foo {
+    fn qux(&self) {
+        match self {
+            Self::Bar => ${1:todo!()},
+            Self::Baz => ${2:todo!()},$0
+        }
+    }
+}
+            "#,
+        );
+    }
+
+    #[test]
+    fn prefer_self_with_generics() {
+        check_assist_with_config(
+            add_missing_match_arms,
+            AssistConfig { prefer_self_ty: true, ..TEST_CONFIG },
+            r#"
+enum Foo<T> {
+    Bar(T),
+    Baz,
+}
+
+impl<T> Foo<T> {
+    fn qux(&self) {
+        match self {
+            $0_ => {}
+        }
+    }
+}
+            "#,
+            r#"
+enum Foo<T> {
+    Bar(T),
+    Baz,
+}
+
+impl<T> Foo<T> {
+    fn qux(&self) {
+        match self {
+            Self::Bar(${1:_}) => ${2:todo!()},
+            Self::Baz => ${3:todo!()},$0
+        }
+    }
+}
+            "#,
+        );
+        check_assist_with_config(
+            add_missing_match_arms,
+            AssistConfig { prefer_self_ty: true, ..TEST_CONFIG },
+            r#"
+enum Foo<T> {
+    Bar(T),
+    Baz,
+}
+
+impl<T> Foo<T> {
+    fn qux(v: Foo<i32>) {
+        match v {
+            $0_ => {}
+        }
+    }
+}
+            "#,
+            r#"
+enum Foo<T> {
+    Bar(T),
+    Baz,
+}
+
+impl<T> Foo<T> {
+    fn qux(v: Foo<i32>) {
+        match v {
+            Foo::Bar(${1:_}) => ${2:todo!()},
+            Foo::Baz => ${3:todo!()},$0
+        }
+    }
+}
+            "#,
+        );
+    }
 }
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/auto_import.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/auto_import.rs
index f3243d369a0..bb6a10d40b7 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/auto_import.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/auto_import.rs
@@ -164,9 +164,9 @@ pub(crate) fn auto_import(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<
     Some(())
 }
 
-pub(super) fn find_importable_node(
-    ctx: &AssistContext<'_>,
-) -> Option<(ImportAssets, SyntaxNode, Option<Type>)> {
+pub(super) fn find_importable_node<'a: 'db, 'db>(
+    ctx: &'a AssistContext<'db>,
+) -> Option<(ImportAssets<'db>, SyntaxNode, Option<Type<'db>>)> {
     // Deduplicate this with the `expected_type_and_name` logic for completions
     let expected = |expr_or_pat: Either<ast::Expr, ast::Pat>| match expr_or_pat {
         Either::Left(expr) => {
@@ -226,7 +226,7 @@ pub(super) fn find_importable_node(
     }
 }
 
-fn group_label(import_candidate: &ImportCandidate) -> GroupLabel {
+fn group_label(import_candidate: &ImportCandidate<'_>) -> GroupLabel {
     let name = match import_candidate {
         ImportCandidate::Path(candidate) => format!("Import {}", candidate.name.text()),
         ImportCandidate::TraitAssocItem(candidate) => {
@@ -244,7 +244,7 @@ fn group_label(import_candidate: &ImportCandidate) -> GroupLabel {
 pub(crate) fn relevance_score(
     ctx: &AssistContext<'_>,
     import: &LocatedImport,
-    expected: Option<&Type>,
+    expected: Option<&Type<'_>>,
     current_module: Option<&Module>,
 ) -> i32 {
     let mut score = 0;
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_function.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_function.rs
index cf45ea0a30d..00cbef1c01c 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_function.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_function.rs
@@ -309,23 +309,23 @@ fn extraction_target(node: &SyntaxNode, selection_range: TextRange) -> Option<Fu
 }
 
 #[derive(Debug)]
-struct Function {
+struct Function<'db> {
     name: ast::NameRef,
     self_param: Option<ast::SelfParam>,
-    params: Vec<Param>,
-    control_flow: ControlFlow,
-    ret_ty: RetType,
+    params: Vec<Param<'db>>,
+    control_flow: ControlFlow<'db>,
+    ret_ty: RetType<'db>,
     body: FunctionBody,
     outliving_locals: Vec<OutlivedLocal>,
     /// Whether at least one of the container's tail expr is contained in the range we're extracting.
     contains_tail_expr: bool,
-    mods: ContainerInfo,
+    mods: ContainerInfo<'db>,
 }
 
 #[derive(Debug)]
-struct Param {
+struct Param<'db> {
     var: Local,
-    ty: hir::Type,
+    ty: hir::Type<'db>,
     move_local: bool,
     requires_mut: bool,
     is_copy: bool,
@@ -340,10 +340,10 @@ enum ParamKind {
 }
 
 #[derive(Debug)]
-enum FunType {
+enum FunType<'db> {
     Unit,
-    Single(hir::Type),
-    Tuple(Vec<hir::Type>),
+    Single(hir::Type<'db>),
+    Tuple(Vec<hir::Type<'db>>),
 }
 
 /// Where to put extracted function definition
@@ -358,19 +358,19 @@ enum Anchor {
 // FIXME: ControlFlow and ContainerInfo both track some function modifiers, feels like these two should
 // probably be merged somehow.
 #[derive(Debug)]
-struct ControlFlow {
-    kind: Option<FlowKind>,
+struct ControlFlow<'db> {
+    kind: Option<FlowKind<'db>>,
     is_async: bool,
     is_unsafe: bool,
 }
 
 /// The thing whose expression we are extracting from. Can be a function, const, static, const arg, ...
 #[derive(Clone, Debug)]
-struct ContainerInfo {
+struct ContainerInfo<'db> {
     is_const: bool,
     parent_loop: Option<SyntaxNode>,
     /// The function's return type, const's type etc.
-    ret_type: Option<hir::Type>,
+    ret_type: Option<hir::Type<'db>>,
     generic_param_lists: Vec<ast::GenericParamList>,
     where_clauses: Vec<ast::WhereClause>,
     edition: Edition,
@@ -389,11 +389,11 @@ struct ContainerInfo {
 /// }
 /// ```
 #[derive(Debug, Clone)]
-enum FlowKind {
+enum FlowKind<'db> {
     /// Return with value (`return $expr;`)
     Return(Option<ast::Expr>),
     Try {
-        kind: TryKind,
+        kind: TryKind<'db>,
     },
     /// Break with label and value (`break 'label $expr;`)
     Break(Option<ast::Lifetime>, Option<ast::Expr>),
@@ -402,18 +402,18 @@ enum FlowKind {
 }
 
 #[derive(Debug, Clone)]
-enum TryKind {
+enum TryKind<'db> {
     Option,
-    Result { ty: hir::Type },
+    Result { ty: hir::Type<'db> },
 }
 
 #[derive(Debug)]
-enum RetType {
-    Expr(hir::Type),
+enum RetType<'db> {
+    Expr(hir::Type<'db>),
     Stmt,
 }
 
-impl RetType {
+impl RetType<'_> {
     fn is_unit(&self) -> bool {
         match self {
             RetType::Expr(ty) => ty.is_unit(),
@@ -456,8 +456,8 @@ impl LocalUsages {
     }
 }
 
-impl Function {
-    fn return_type(&self, ctx: &AssistContext<'_>) -> FunType {
+impl<'db> Function<'db> {
+    fn return_type(&self, ctx: &AssistContext<'db>) -> FunType<'db> {
         match &self.ret_ty {
             RetType::Expr(ty) if ty.is_unit() => FunType::Unit,
             RetType::Expr(ty) => FunType::Single(ty.clone()),
@@ -487,7 +487,7 @@ impl ParamKind {
     }
 }
 
-impl Param {
+impl<'db> Param<'db> {
     fn kind(&self) -> ParamKind {
         match (self.move_local, self.requires_mut, self.is_copy) {
             (false, true, _) => ParamKind::MutRef,
@@ -497,7 +497,7 @@ impl Param {
         }
     }
 
-    fn to_arg(&self, ctx: &AssistContext<'_>, edition: Edition) -> ast::Expr {
+    fn to_arg(&self, ctx: &AssistContext<'db>, edition: Edition) -> ast::Expr {
         let var = path_expr_from_local(ctx, self.var, edition);
         match self.kind() {
             ParamKind::Value | ParamKind::MutValue => var,
@@ -532,8 +532,12 @@ impl Param {
     }
 }
 
-impl TryKind {
-    fn of_ty(ty: hir::Type, ctx: &AssistContext<'_>, edition: Edition) -> Option<TryKind> {
+impl<'db> TryKind<'db> {
+    fn of_ty(
+        ty: hir::Type<'db>,
+        ctx: &AssistContext<'db>,
+        edition: Edition,
+    ) -> Option<TryKind<'db>> {
         if ty.is_unknown() {
             // We favour Result for `expr?`
             return Some(TryKind::Result { ty });
@@ -551,7 +555,7 @@ impl TryKind {
     }
 }
 
-impl FlowKind {
+impl<'db> FlowKind<'db> {
     fn make_result_handler(&self, expr: Option<ast::Expr>) -> ast::Expr {
         match self {
             FlowKind::Return(_) => make::expr_return(expr),
@@ -567,7 +571,7 @@ impl FlowKind {
         }
     }
 
-    fn expr_ty(&self, ctx: &AssistContext<'_>) -> Option<hir::Type> {
+    fn expr_ty(&self, ctx: &AssistContext<'db>) -> Option<hir::Type<'db>> {
         match self {
             FlowKind::Return(Some(expr)) | FlowKind::Break(_, Some(expr)) => {
                 ctx.sema.type_of_expr(expr).map(TypeInfo::adjusted)
@@ -876,11 +880,11 @@ impl FunctionBody {
         (res, self_param)
     }
 
-    fn analyze_container(
+    fn analyze_container<'db>(
         &self,
-        sema: &Semantics<'_, RootDatabase>,
+        sema: &Semantics<'db, RootDatabase>,
         edition: Edition,
-    ) -> Option<(ContainerInfo, bool)> {
+    ) -> Option<(ContainerInfo<'db>, bool)> {
         let mut ancestors = self.parent()?.ancestors();
         let infer_expr_opt = |expr| sema.type_of_expr(&expr?).map(TypeInfo::adjusted);
         let mut parent_loop = None;
@@ -985,7 +989,7 @@ impl FunctionBody {
         ))
     }
 
-    fn return_ty(&self, ctx: &AssistContext<'_>) -> Option<RetType> {
+    fn return_ty<'db>(&self, ctx: &AssistContext<'db>) -> Option<RetType<'db>> {
         match self.tail_expr() {
             Some(expr) => ctx.sema.type_of_expr(&expr).map(TypeInfo::original).map(RetType::Expr),
             None => Some(RetType::Stmt),
@@ -1006,11 +1010,11 @@ impl FunctionBody {
     }
 
     /// Analyses the function body for external control flow.
-    fn external_control_flow(
+    fn external_control_flow<'db>(
         &self,
-        ctx: &AssistContext<'_>,
-        container_info: &ContainerInfo,
-    ) -> Option<ControlFlow> {
+        ctx: &AssistContext<'db>,
+        container_info: &ContainerInfo<'db>,
+    ) -> Option<ControlFlow<'db>> {
         let mut ret_expr = None;
         let mut try_expr = None;
         let mut break_expr = None;
@@ -1096,12 +1100,12 @@ impl FunctionBody {
     /// find variables that should be extracted as params
     ///
     /// Computes additional info that affects param type and mutability
-    fn extracted_function_params(
+    fn extracted_function_params<'db>(
         &self,
-        ctx: &AssistContext<'_>,
-        container_info: &ContainerInfo,
+        ctx: &AssistContext<'db>,
+        container_info: &ContainerInfo<'db>,
         locals: FxIndexSet<Local>,
-    ) -> Vec<Param> {
+    ) -> Vec<Param<'db>> {
         locals
             .into_iter()
             .sorted()
@@ -1449,7 +1453,7 @@ fn fixup_call_site(builder: &mut SourceChangeBuilder, body: &FunctionBody) {
     }
 }
 
-fn make_call(ctx: &AssistContext<'_>, fun: &Function, indent: IndentLevel) -> SyntaxNode {
+fn make_call(ctx: &AssistContext<'_>, fun: &Function<'_>, indent: IndentLevel) -> SyntaxNode {
     let ret_ty = fun.return_type(ctx);
 
     let args = make::arg_list(fun.params.iter().map(|param| param.to_arg(ctx, fun.mods.edition)));
@@ -1508,17 +1512,17 @@ fn make_call(ctx: &AssistContext<'_>, fun: &Function, indent: IndentLevel) -> Sy
     }
 }
 
-enum FlowHandler {
+enum FlowHandler<'db> {
     None,
-    Try { kind: TryKind },
-    If { action: FlowKind },
-    IfOption { action: FlowKind },
-    MatchOption { none: FlowKind },
-    MatchResult { err: FlowKind },
+    Try { kind: TryKind<'db> },
+    If { action: FlowKind<'db> },
+    IfOption { action: FlowKind<'db> },
+    MatchOption { none: FlowKind<'db> },
+    MatchResult { err: FlowKind<'db> },
 }
 
-impl FlowHandler {
-    fn from_ret_ty(fun: &Function, ret_ty: &FunType) -> FlowHandler {
+impl<'db> FlowHandler<'db> {
+    fn from_ret_ty(fun: &Function<'db>, ret_ty: &FunType<'db>) -> FlowHandler<'db> {
         if fun.contains_tail_expr {
             return FlowHandler::None;
         }
@@ -1628,7 +1632,7 @@ fn path_expr_from_local(ctx: &AssistContext<'_>, var: Local, edition: Edition) -
 fn format_function(
     ctx: &AssistContext<'_>,
     module: hir::Module,
-    fun: &Function,
+    fun: &Function<'_>,
     old_indent: IndentLevel,
 ) -> ast::Fn {
     let fun_name = make::name(&fun.name.text());
@@ -1654,7 +1658,7 @@ fn format_function(
 
 fn make_generic_params_and_where_clause(
     ctx: &AssistContext<'_>,
-    fun: &Function,
+    fun: &Function<'_>,
 ) -> (Option<ast::GenericParamList>, Option<ast::WhereClause>) {
     let used_type_params = fun.type_params(ctx);
 
@@ -1666,7 +1670,7 @@ fn make_generic_params_and_where_clause(
 
 fn make_generic_param_list(
     ctx: &AssistContext<'_>,
-    fun: &Function,
+    fun: &Function<'_>,
     used_type_params: &[TypeParam],
 ) -> Option<ast::GenericParamList> {
     let mut generic_params = fun
@@ -1703,7 +1707,7 @@ fn param_is_required(
 
 fn make_where_clause(
     ctx: &AssistContext<'_>,
-    fun: &Function,
+    fun: &Function<'_>,
     used_type_params: &[TypeParam],
 ) -> Option<ast::WhereClause> {
     let mut predicates = fun
@@ -1743,9 +1747,9 @@ fn resolved_type_param(ctx: &AssistContext<'_>, pred: &ast::WherePred) -> Option
     }
 }
 
-impl Function {
+impl<'db> Function<'db> {
     /// Collect all the `TypeParam`s used in the `body` and `params`.
-    fn type_params(&self, ctx: &AssistContext<'_>) -> Vec<TypeParam> {
+    fn type_params(&self, ctx: &AssistContext<'db>) -> Vec<TypeParam> {
         let type_params_in_descendant_paths =
             self.body.descendant_paths().filter_map(|it| match ctx.sema.resolve_path(&it) {
                 Some(PathResolution::TypeParam(type_param)) => Some(type_param),
@@ -1808,8 +1812,8 @@ impl Function {
     }
 }
 
-impl FunType {
-    fn make_ty(&self, ctx: &AssistContext<'_>, module: hir::Module) -> ast::Type {
+impl<'db> FunType<'db> {
+    fn make_ty(&self, ctx: &AssistContext<'db>, module: hir::Module) -> ast::Type {
         match self {
             FunType::Unit => make::ty_unit(),
             FunType::Single(ty) => make_ty(ty, ctx, module),
@@ -1831,7 +1835,11 @@ impl FunType {
     }
 }
 
-fn make_body(ctx: &AssistContext<'_>, old_indent: IndentLevel, fun: &Function) -> ast::BlockExpr {
+fn make_body(
+    ctx: &AssistContext<'_>,
+    old_indent: IndentLevel,
+    fun: &Function<'_>,
+) -> ast::BlockExpr {
     let ret_ty = fun.return_type(ctx);
     let handler = FlowHandler::from_ret_ty(fun, &ret_ty);
 
@@ -2009,19 +2017,19 @@ fn with_tail_expr(block: ast::BlockExpr, tail_expr: ast::Expr) -> ast::BlockExpr
     make::hacky_block_expr(elements, Some(tail_expr))
 }
 
-fn format_type(ty: &hir::Type, ctx: &AssistContext<'_>, module: hir::Module) -> String {
+fn format_type(ty: &hir::Type<'_>, ctx: &AssistContext<'_>, module: hir::Module) -> String {
     ty.display_source_code(ctx.db(), module.into(), true).ok().unwrap_or_else(|| "_".to_owned())
 }
 
-fn make_ty(ty: &hir::Type, ctx: &AssistContext<'_>, module: hir::Module) -> ast::Type {
+fn make_ty(ty: &hir::Type<'_>, ctx: &AssistContext<'_>, module: hir::Module) -> ast::Type {
     let ty_str = format_type(ty, ctx, module);
     make::ty(&ty_str)
 }
 
 fn rewrite_body_segment(
     ctx: &AssistContext<'_>,
-    params: &[Param],
-    handler: &FlowHandler,
+    params: &[Param<'_>],
+    handler: &FlowHandler<'_>,
     syntax: &SyntaxNode,
 ) -> SyntaxNode {
     let syntax = fix_param_usages(ctx, params, syntax);
@@ -2030,8 +2038,12 @@ fn rewrite_body_segment(
 }
 
 /// change all usages to account for added `&`/`&mut` for some params
-fn fix_param_usages(ctx: &AssistContext<'_>, params: &[Param], syntax: &SyntaxNode) -> SyntaxNode {
-    let mut usages_for_param: Vec<(&Param, Vec<ast::Expr>)> = Vec::new();
+fn fix_param_usages(
+    ctx: &AssistContext<'_>,
+    params: &[Param<'_>],
+    syntax: &SyntaxNode,
+) -> SyntaxNode {
+    let mut usages_for_param: Vec<(&Param<'_>, Vec<ast::Expr>)> = Vec::new();
 
     let tm = TreeMutator::new(syntax);
 
@@ -2085,7 +2097,7 @@ fn fix_param_usages(ctx: &AssistContext<'_>, params: &[Param], syntax: &SyntaxNo
     res
 }
 
-fn update_external_control_flow(handler: &FlowHandler, syntax: &SyntaxNode) {
+fn update_external_control_flow(handler: &FlowHandler<'_>, syntax: &SyntaxNode) {
     let mut nested_loop = None;
     let mut nested_scope = None;
     for event in syntax.preorder() {
@@ -2146,7 +2158,10 @@ fn update_external_control_flow(handler: &FlowHandler, syntax: &SyntaxNode) {
     }
 }
 
-fn make_rewritten_flow(handler: &FlowHandler, arg_expr: Option<ast::Expr>) -> Option<ast::Expr> {
+fn make_rewritten_flow(
+    handler: &FlowHandler<'_>,
+    arg_expr: Option<ast::Expr>,
+) -> Option<ast::Expr> {
     let value = match handler {
         FlowHandler::None | FlowHandler::Try { .. } => return None,
         FlowHandler::If { .. } => make::expr_call(
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_function.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_function.rs
index 30084d23d1f..78ae815dc87 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_function.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_function.rs
@@ -307,7 +307,7 @@ impl FunctionBuilder {
         ctx: &AssistContext<'_>,
         call: &ast::MethodCallExpr,
         name: &ast::NameRef,
-        receiver_ty: Type,
+        receiver_ty: Type<'_>,
         target_module: Module,
         target: GeneratedFunctionTarget,
     ) -> Option<Self> {
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/inline_call.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/inline_call.rs
index 6f028e58d0c..b7b8bc604a5 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/inline_call.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/inline_call.rs
@@ -283,11 +283,11 @@ impl CallInfo {
     }
 }
 
-fn get_fn_params(
-    db: &dyn HirDatabase,
+fn get_fn_params<'db>(
+    db: &'db dyn HirDatabase,
     function: hir::Function,
     param_list: &ast::ParamList,
-) -> Option<Vec<(ast::Pat, Option<ast::Type>, hir::Param)>> {
+) -> Option<Vec<(ast::Pat, Option<ast::Type>, hir::Param<'db>)>> {
     let mut assoc_fn_params = function.assoc_fn_params(db).into_iter();
 
     let mut params = Vec::new();
@@ -316,7 +316,7 @@ fn inline(
     function_def_file_id: EditionedFileId,
     function: hir::Function,
     fn_body: &ast::BlockExpr,
-    params: &[(ast::Pat, Option<ast::Type>, hir::Param)],
+    params: &[(ast::Pat, Option<ast::Type>, hir::Param<'_>)],
     CallInfo { node, arguments, generic_arg_list, krate }: &CallInfo,
 ) -> ast::Expr {
     let file_id = sema.hir_file_for(fn_body.syntax());
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/inline_const_as_literal.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/inline_const_as_literal.rs
index e5ed04fdc7c..b11d3792bc4 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/inline_const_as_literal.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/inline_const_as_literal.rs
@@ -58,7 +58,7 @@ pub(crate) fn inline_const_as_literal(acc: &mut Assists, ctx: &AssistContext<'_>
 
 fn validate_type_recursively(
     ctx: &AssistContext<'_>,
-    ty_hir: Option<&hir::Type>,
+    ty_hir: Option<&hir::Type<'_>>,
     refed: bool,
     fuel: i32,
 ) -> Option<()> {
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/merge_match_arms.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/merge_match_arms.rs
index 42f35210b49..08170f81b28 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/merge_match_arms.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/merge_match_arms.rs
@@ -105,7 +105,7 @@ fn contains_placeholder(a: &ast::MatchArm) -> bool {
 }
 
 fn are_same_types(
-    current_arm_types: &FxHashMap<String, Option<Type>>,
+    current_arm_types: &FxHashMap<String, Option<Type<'_>>>,
     arm: &ast::MatchArm,
     ctx: &AssistContext<'_>,
 ) -> bool {
@@ -121,15 +121,15 @@ fn are_same_types(
     true
 }
 
-fn get_arm_types(
-    context: &AssistContext<'_>,
+fn get_arm_types<'db>(
+    context: &AssistContext<'db>,
     arm: &ast::MatchArm,
-) -> FxHashMap<String, Option<Type>> {
-    let mut mapping: FxHashMap<String, Option<Type>> = FxHashMap::default();
+) -> FxHashMap<String, Option<Type<'db>>> {
+    let mut mapping: FxHashMap<String, Option<Type<'db>>> = FxHashMap::default();
 
-    fn recurse(
-        map: &mut FxHashMap<String, Option<Type>>,
-        ctx: &AssistContext<'_>,
+    fn recurse<'db>(
+        map: &mut FxHashMap<String, Option<Type<'db>>>,
+        ctx: &AssistContext<'db>,
         pat: &Option<ast::Pat>,
     ) {
         if let Some(local_pat) = pat {
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/qualify_path.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/qualify_path.rs
index 07d2f52a34e..8834ad97652 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/qualify_path.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/qualify_path.rs
@@ -217,7 +217,7 @@ fn item_as_trait(db: &RootDatabase, item: hir::ItemInNs) -> Option<hir::Trait> {
     }
 }
 
-fn group_label(candidate: &ImportCandidate) -> GroupLabel {
+fn group_label(candidate: &ImportCandidate<'_>) -> GroupLabel {
     let name = match candidate {
         ImportCandidate::Path(it) => &it.name,
         ImportCandidate::TraitAssocItem(it) | ImportCandidate::TraitMethod(it) => {
@@ -230,7 +230,7 @@ fn group_label(candidate: &ImportCandidate) -> GroupLabel {
 
 fn label(
     db: &RootDatabase,
-    candidate: &ImportCandidate,
+    candidate: &ImportCandidate<'_>,
     import: &LocatedImport,
     edition: Edition,
 ) -> String {
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/remove_unused_imports.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/remove_unused_imports.rs
index 16debc4d728..c38bdfdccf5 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/remove_unused_imports.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/remove_unused_imports.rs
@@ -117,7 +117,7 @@ pub(crate) fn remove_unused_imports(acc: &mut Assists, ctx: &AssistContext<'_>)
     if unused.peek().is_some() {
         acc.add(
             AssistId::quick_fix("remove_unused_imports"),
-            "Remove all the unused imports",
+            "Remove all unused imports",
             selected_el.text_range(),
             |builder| {
                 let unused: Vec<ast::UseTree> = unused.map(|x| builder.make_mut(x)).collect();
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/term_search.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/term_search.rs
index 6af8e1482c2..019ddaf1441 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/term_search.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/term_search.rs
@@ -46,7 +46,7 @@ pub(crate) fn term_search(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<
         return None;
     }
 
-    let mut formatter = |_: &hir::Type| String::from("todo!()");
+    let mut formatter = |_: &hir::Type<'_>| String::from("todo!()");
 
     let edition = scope.krate().edition(ctx.db());
     let paths = paths
@@ -100,7 +100,9 @@ fn f() { let a: u128 = 1; let b: u128 = todo$0!() }"#,
     fn test_complete_todo_with_msg() {
         check_assist(
             term_search,
-            r#"//- minicore: todo, unimplemented
+            // FIXME: Since we are lacking of `super let`, term search fails due to borrowck failure.
+            // Should implement super let and remove `fmt_before_1_89_0`
+            r#"//- minicore: todo, unimplemented, fmt_before_1_89_0
 fn f() { let a: u128 = 1; let b: u128 = todo$0!("asd") }"#,
             r#"fn f() { let a: u128 = 1; let b: u128 = a }"#,
         )
@@ -110,7 +112,9 @@ fn f() { let a: u128 = 1; let b: u128 = todo$0!("asd") }"#,
     fn test_complete_unimplemented_with_msg() {
         check_assist(
             term_search,
-            r#"//- minicore: todo, unimplemented
+            // FIXME: Since we are lacking of `super let`, term search fails due to borrowck failure.
+            // Should implement super let and remove `fmt_before_1_89_0`
+            r#"//- minicore: todo, unimplemented, fmt_before_1_89_0
 fn f() { let a: u128 = 1; let b: u128 = todo$0!("asd") }"#,
             r#"fn f() { let a: u128 = 1; let b: u128 = a }"#,
         )
@@ -120,7 +124,9 @@ fn f() { let a: u128 = 1; let b: u128 = todo$0!("asd") }"#,
     fn test_complete_unimplemented() {
         check_assist(
             term_search,
-            r#"//- minicore: todo, unimplemented
+            // FIXME: Since we are lacking of `super let`, term search fails due to borrowck failure.
+            // Should implement super let and remove `fmt_before_1_89_0`
+            r#"//- minicore: todo, unimplemented, fmt_before_1_89_0
 fn f() { let a: u128 = 1; let b: u128 = todo$0!("asd") }"#,
             r#"fn f() { let a: u128 = 1; let b: u128 = a }"#,
         )
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/tests.rs b/src/tools/rust-analyzer/crates/ide-assists/src/tests.rs
index 5e6889792db..cda2ad43278 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/tests.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/tests.rs
@@ -37,6 +37,7 @@ pub(crate) const TEST_CONFIG: AssistConfig = AssistConfig {
     term_search_borrowck: true,
     code_action_grouping: true,
     expr_fill_default: ExprFillDefaultMode::Todo,
+    prefer_self_ty: false,
 };
 
 pub(crate) const TEST_CONFIG_NO_GROUPING: AssistConfig = AssistConfig {
@@ -57,6 +58,7 @@ pub(crate) const TEST_CONFIG_NO_GROUPING: AssistConfig = AssistConfig {
     term_search_borrowck: true,
     code_action_grouping: false,
     expr_fill_default: ExprFillDefaultMode::Todo,
+    prefer_self_ty: false,
 };
 
 pub(crate) const TEST_CONFIG_NO_SNIPPET_CAP: AssistConfig = AssistConfig {
@@ -77,6 +79,7 @@ pub(crate) const TEST_CONFIG_NO_SNIPPET_CAP: AssistConfig = AssistConfig {
     term_search_borrowck: true,
     code_action_grouping: true,
     expr_fill_default: ExprFillDefaultMode::Todo,
+    prefer_self_ty: false,
 };
 
 pub(crate) const TEST_CONFIG_IMPORT_ONE: AssistConfig = AssistConfig {
@@ -97,6 +100,7 @@ pub(crate) const TEST_CONFIG_IMPORT_ONE: AssistConfig = AssistConfig {
     term_search_borrowck: true,
     code_action_grouping: true,
     expr_fill_default: ExprFillDefaultMode::Todo,
+    prefer_self_ty: false,
 };
 
 pub(crate) fn with_single_file(text: &str) -> (RootDatabase, EditionedFileId) {
@@ -114,6 +118,23 @@ pub(crate) fn check_assist(
 }
 
 #[track_caller]
+pub(crate) fn check_assist_with_config(
+    assist: Handler,
+    config: AssistConfig,
+    #[rust_analyzer::rust_fixture] ra_fixture_before: &str,
+    #[rust_analyzer::rust_fixture] ra_fixture_after: &str,
+) {
+    let ra_fixture_after = trim_indent(ra_fixture_after);
+    check_with_config(
+        config,
+        assist,
+        ra_fixture_before,
+        ExpectedResult::After(&ra_fixture_after),
+        None,
+    );
+}
+
+#[track_caller]
 pub(crate) fn check_assist_no_snippet_cap(
     assist: Handler,
     #[rust_analyzer::rust_fixture] ra_fixture_before: &str,
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/utils.rs b/src/tools/rust-analyzer/crates/ide-assists/src/utils.rs
index ef6914fda1d..1a91053f93c 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/utils.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/utils.rs
@@ -405,7 +405,7 @@ pub(crate) fn does_pat_variant_nested_or_literal(ctx: &AssistContext<'_>, pat: &
 }
 
 fn check_pat_variant_from_enum(ctx: &AssistContext<'_>, pat: &ast::Pat) -> bool {
-    ctx.sema.type_of_pat(pat).is_none_or(|ty: hir::TypeInfo| {
+    ctx.sema.type_of_pat(pat).is_none_or(|ty: hir::TypeInfo<'_>| {
         ty.adjusted().as_adt().is_some_and(|adt| matches!(adt, hir::Adt::Enum(_)))
     })
 }
@@ -780,9 +780,9 @@ pub(crate) fn add_method_to_adt(
 }
 
 #[derive(Debug)]
-pub(crate) struct ReferenceConversion {
+pub(crate) struct ReferenceConversion<'db> {
     conversion: ReferenceConversionType,
-    ty: hir::Type,
+    ty: hir::Type<'db>,
     impls_deref: bool,
 }
 
@@ -802,10 +802,10 @@ enum ReferenceConversionType {
     Result,
 }
 
-impl ReferenceConversion {
+impl<'db> ReferenceConversion<'db> {
     pub(crate) fn convert_type(
         &self,
-        db: &dyn HirDatabase,
+        db: &'db dyn HirDatabase,
         display_target: DisplayTarget,
     ) -> ast::Type {
         let ty = match self.conversion {
@@ -878,11 +878,11 @@ impl ReferenceConversion {
 // FIXME: It should return a new hir::Type, but currently constructing new types is too cumbersome
 //        and all users of this function operate on string type names, so they can do the conversion
 //        itself themselves.
-pub(crate) fn convert_reference_type(
-    ty: hir::Type,
-    db: &RootDatabase,
-    famous_defs: &FamousDefs<'_, '_>,
-) -> Option<ReferenceConversion> {
+pub(crate) fn convert_reference_type<'db>(
+    ty: hir::Type<'db>,
+    db: &'db RootDatabase,
+    famous_defs: &FamousDefs<'_, 'db>,
+) -> Option<ReferenceConversion<'db>> {
     handle_copy(&ty, db)
         .or_else(|| handle_as_ref_str(&ty, db, famous_defs))
         .or_else(|| handle_as_ref_slice(&ty, db, famous_defs))
@@ -892,18 +892,21 @@ pub(crate) fn convert_reference_type(
         .map(|(conversion, impls_deref)| ReferenceConversion { ty, conversion, impls_deref })
 }
 
-fn could_deref_to_target(ty: &hir::Type, target: &hir::Type, db: &dyn HirDatabase) -> bool {
+fn could_deref_to_target(ty: &hir::Type<'_>, target: &hir::Type<'_>, db: &dyn HirDatabase) -> bool {
     let ty_ref = ty.add_reference(hir::Mutability::Shared);
     let target_ref = target.add_reference(hir::Mutability::Shared);
     ty_ref.could_coerce_to(db, &target_ref)
 }
 
-fn handle_copy(ty: &hir::Type, db: &dyn HirDatabase) -> Option<(ReferenceConversionType, bool)> {
+fn handle_copy(
+    ty: &hir::Type<'_>,
+    db: &dyn HirDatabase,
+) -> Option<(ReferenceConversionType, bool)> {
     ty.is_copy(db).then_some((ReferenceConversionType::Copy, true))
 }
 
 fn handle_as_ref_str(
-    ty: &hir::Type,
+    ty: &hir::Type<'_>,
     db: &dyn HirDatabase,
     famous_defs: &FamousDefs<'_, '_>,
 ) -> Option<(ReferenceConversionType, bool)> {
@@ -914,7 +917,7 @@ fn handle_as_ref_str(
 }
 
 fn handle_as_ref_slice(
-    ty: &hir::Type,
+    ty: &hir::Type<'_>,
     db: &dyn HirDatabase,
     famous_defs: &FamousDefs<'_, '_>,
 ) -> Option<(ReferenceConversionType, bool)> {
@@ -928,7 +931,7 @@ fn handle_as_ref_slice(
 }
 
 fn handle_dereferenced(
-    ty: &hir::Type,
+    ty: &hir::Type<'_>,
     db: &dyn HirDatabase,
     famous_defs: &FamousDefs<'_, '_>,
 ) -> Option<(ReferenceConversionType, bool)> {
@@ -941,7 +944,7 @@ fn handle_dereferenced(
 }
 
 fn handle_option_as_ref(
-    ty: &hir::Type,
+    ty: &hir::Type<'_>,
     db: &dyn HirDatabase,
     famous_defs: &FamousDefs<'_, '_>,
 ) -> Option<(ReferenceConversionType, bool)> {
@@ -953,7 +956,7 @@ fn handle_option_as_ref(
 }
 
 fn handle_result_as_ref(
-    ty: &hir::Type,
+    ty: &hir::Type<'_>,
     db: &dyn HirDatabase,
     famous_defs: &FamousDefs<'_, '_>,
 ) -> Option<(ReferenceConversionType, bool)> {
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/utils/gen_trait_fn_body.rs b/src/tools/rust-analyzer/crates/ide-assists/src/utils/gen_trait_fn_body.rs
index 4ea56dc46aa..c58bdd9e8ed 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/utils/gen_trait_fn_body.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/utils/gen_trait_fn_body.rs
@@ -17,7 +17,7 @@ pub(crate) fn gen_trait_fn_body(
     func: &ast::Fn,
     trait_path: &ast::Path,
     adt: &ast::Adt,
-    trait_ref: Option<TraitRef>,
+    trait_ref: Option<TraitRef<'_>>,
 ) -> Option<()> {
     match trait_path.segment()?.name_ref()?.text().as_str() {
         "Clone" => gen_clone_impl(adt, func),
@@ -405,7 +405,7 @@ fn gen_hash_impl(adt: &ast::Adt, func: &ast::Fn) -> Option<()> {
 }
 
 /// Generate a `PartialEq` impl based on the fields and members of the target type.
-fn gen_partial_eq(adt: &ast::Adt, func: &ast::Fn, trait_ref: Option<TraitRef>) -> Option<()> {
+fn gen_partial_eq(adt: &ast::Adt, func: &ast::Fn, trait_ref: Option<TraitRef<'_>>) -> Option<()> {
     stdx::always!(func.name().is_some_and(|name| name.text() == "eq"));
     fn gen_eq_chain(expr: Option<ast::Expr>, cmp: ast::Expr) -> Option<ast::Expr> {
         match expr {
@@ -599,7 +599,7 @@ fn gen_partial_eq(adt: &ast::Adt, func: &ast::Fn, trait_ref: Option<TraitRef>) -
     Some(())
 }
 
-fn gen_partial_ord(adt: &ast::Adt, func: &ast::Fn, trait_ref: Option<TraitRef>) -> Option<()> {
+fn gen_partial_ord(adt: &ast::Adt, func: &ast::Fn, trait_ref: Option<TraitRef<'_>>) -> Option<()> {
     stdx::always!(func.name().is_some_and(|name| name.text() == "partial_cmp"));
     fn gen_partial_eq_match(match_target: ast::Expr) -> Option<ast::Stmt> {
         let mut arms = vec![];
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 5d68aca9e61..65072d936f6 100644
--- a/src/tools/rust-analyzer/crates/ide-completion/src/completions.rs
+++ b/src/tools/rust-analyzer/crates/ide-completion/src/completions.rs
@@ -161,7 +161,11 @@ impl Completions {
         item.add_to(self, ctx.db);
     }
 
-    pub(crate) fn add_expr(&mut self, ctx: &CompletionContext<'_>, expr: &hir::term_search::Expr) {
+    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)
         }
@@ -170,7 +174,7 @@ impl Completions {
     pub(crate) fn add_crate_roots(
         &mut self,
         ctx: &CompletionContext<'_>,
-        path_ctx: &PathCompletionCtx,
+        path_ctx: &PathCompletionCtx<'_>,
     ) {
         ctx.process_all_names(&mut |name, res, doc_aliases| match res {
             ScopeDef::ModuleDef(hir::ModuleDef::Module(m)) if m.is_crate_root() => {
@@ -183,7 +187,7 @@ impl Completions {
     pub(crate) fn add_path_resolution(
         &mut self,
         ctx: &CompletionContext<'_>,
-        path_ctx: &PathCompletionCtx,
+        path_ctx: &PathCompletionCtx<'_>,
         local_name: hir::Name,
         resolution: hir::ScopeDef,
         doc_aliases: Vec<syntax::SmolStr>,
@@ -232,7 +236,7 @@ impl Completions {
     pub(crate) fn add_enum_variants(
         &mut self,
         ctx: &CompletionContext<'_>,
-        path_ctx: &PathCompletionCtx,
+        path_ctx: &PathCompletionCtx<'_>,
         e: hir::Enum,
     ) {
         if !ctx.check_stability_and_hidden(e) {
@@ -246,7 +250,7 @@ impl Completions {
     pub(crate) fn add_module(
         &mut self,
         ctx: &CompletionContext<'_>,
-        path_ctx: &PathCompletionCtx,
+        path_ctx: &PathCompletionCtx<'_>,
         module: hir::Module,
         local_name: hir::Name,
         doc_aliases: Vec<syntax::SmolStr>,
@@ -263,7 +267,7 @@ impl Completions {
     pub(crate) fn add_macro(
         &mut self,
         ctx: &CompletionContext<'_>,
-        path_ctx: &PathCompletionCtx,
+        path_ctx: &PathCompletionCtx<'_>,
         mac: hir::Macro,
         local_name: hir::Name,
     ) {
@@ -286,7 +290,7 @@ impl Completions {
     pub(crate) fn add_function(
         &mut self,
         ctx: &CompletionContext<'_>,
-        path_ctx: &PathCompletionCtx,
+        path_ctx: &PathCompletionCtx<'_>,
         func: hir::Function,
         local_name: Option<hir::Name>,
     ) {
@@ -312,7 +316,7 @@ impl Completions {
     pub(crate) fn add_method(
         &mut self,
         ctx: &CompletionContext<'_>,
-        dot_access: &DotAccess,
+        dot_access: &DotAccess<'_>,
         func: hir::Function,
         receiver: Option<SmolStr>,
         local_name: Option<hir::Name>,
@@ -340,7 +344,7 @@ impl Completions {
     pub(crate) fn add_method_with_import(
         &mut self,
         ctx: &CompletionContext<'_>,
-        dot_access: &DotAccess,
+        dot_access: &DotAccess<'_>,
         func: hir::Function,
         import: LocatedImport,
     ) {
@@ -407,7 +411,7 @@ impl Completions {
     pub(crate) fn add_qualified_enum_variant(
         &mut self,
         ctx: &CompletionContext<'_>,
-        path_ctx: &PathCompletionCtx,
+        path_ctx: &PathCompletionCtx<'_>,
         variant: hir::Variant,
         path: hir::ModPath,
     ) {
@@ -424,7 +428,7 @@ impl Completions {
     pub(crate) fn add_enum_variant(
         &mut self,
         ctx: &CompletionContext<'_>,
-        path_ctx: &PathCompletionCtx,
+        path_ctx: &PathCompletionCtx<'_>,
         variant: hir::Variant,
         local_name: Option<hir::Name>,
     ) {
@@ -447,10 +451,10 @@ impl Completions {
     pub(crate) fn add_field(
         &mut self,
         ctx: &CompletionContext<'_>,
-        dot_access: &DotAccess,
+        dot_access: &DotAccess<'_>,
         receiver: Option<SmolStr>,
         field: hir::Field,
-        ty: &hir::Type,
+        ty: &hir::Type<'_>,
     ) {
         let is_private_editable = match ctx.is_visible(&field) {
             Visible::Yes => false,
@@ -471,7 +475,7 @@ impl Completions {
     pub(crate) fn add_struct_literal(
         &mut self,
         ctx: &CompletionContext<'_>,
-        path_ctx: &PathCompletionCtx,
+        path_ctx: &PathCompletionCtx<'_>,
         strukt: hir::Struct,
         path: Option<hir::ModPath>,
         local_name: Option<hir::Name>,
@@ -518,7 +522,7 @@ impl Completions {
         ctx: &CompletionContext<'_>,
         receiver: Option<SmolStr>,
         field: usize,
-        ty: &hir::Type,
+        ty: &hir::Type<'_>,
     ) {
         // Only used for (unnamed) tuples, whose all fields *are* stable. No need to check
         // stability here.
@@ -550,7 +554,7 @@ impl Completions {
         &mut self,
         ctx: &CompletionContext<'_>,
         pattern_ctx: &PatternContext,
-        path_ctx: Option<&PathCompletionCtx>,
+        path_ctx: Option<&PathCompletionCtx<'_>>,
         variant: hir::Variant,
         local_name: Option<hir::Name>,
     ) {
@@ -704,7 +708,7 @@ pub(super) fn complete_name(
 pub(super) fn complete_name_ref(
     acc: &mut Completions,
     ctx: &CompletionContext<'_>,
-    NameRefContext { nameref, kind }: &NameRefContext,
+    NameRefContext { nameref, kind }: &NameRefContext<'_>,
 ) {
     match kind {
         NameRefKind::Path(path_ctx) => {
diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/completions/attribute.rs b/src/tools/rust-analyzer/crates/ide-completion/src/completions/attribute.rs
index 705402c785a..c542e140df5 100644
--- a/src/tools/rust-analyzer/crates/ide-completion/src/completions/attribute.rs
+++ b/src/tools/rust-analyzer/crates/ide-completion/src/completions/attribute.rs
@@ -86,7 +86,7 @@ pub(crate) fn complete_known_attribute_input(
 pub(crate) fn complete_attribute_path(
     acc: &mut Completions,
     ctx: &CompletionContext<'_>,
-    path_ctx @ PathCompletionCtx { qualified, .. }: &PathCompletionCtx,
+    path_ctx @ PathCompletionCtx { qualified, .. }: &PathCompletionCtx<'_>,
     &AttrCtx { kind, annotated_item_kind, ref derive_helpers }: &AttrCtx,
 ) {
     let is_inner = kind == AttrKind::Inner;
diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/completions/attribute/derive.rs b/src/tools/rust-analyzer/crates/ide-completion/src/completions/attribute/derive.rs
index 2fc07e01382..267d92b6c09 100644
--- a/src/tools/rust-analyzer/crates/ide-completion/src/completions/attribute/derive.rs
+++ b/src/tools/rust-analyzer/crates/ide-completion/src/completions/attribute/derive.rs
@@ -13,7 +13,7 @@ use crate::{
 pub(crate) fn complete_derive_path(
     acc: &mut Completions,
     ctx: &CompletionContext<'_>,
-    path_ctx @ PathCompletionCtx { qualified, .. }: &PathCompletionCtx,
+    path_ctx @ PathCompletionCtx { qualified, .. }: &PathCompletionCtx<'_>,
     existing_derives: &ExistingDerives,
 ) {
     let core = ctx.famous_defs().core();
diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/completions/dot.rs b/src/tools/rust-analyzer/crates/ide-completion/src/completions/dot.rs
index 4f21136d214..5340d65a142 100644
--- a/src/tools/rust-analyzer/crates/ide-completion/src/completions/dot.rs
+++ b/src/tools/rust-analyzer/crates/ide-completion/src/completions/dot.rs
@@ -18,7 +18,7 @@ use crate::{
 pub(crate) fn complete_dot(
     acc: &mut Completions,
     ctx: &CompletionContext<'_>,
-    dot_access: &DotAccess,
+    dot_access: &DotAccess<'_>,
 ) {
     let receiver_ty = match dot_access {
         DotAccess { receiver_ty: Some(receiver_ty), .. } => &receiver_ty.original,
@@ -130,8 +130,8 @@ pub(crate) fn complete_dot(
 pub(crate) fn complete_undotted_self(
     acc: &mut Completions,
     ctx: &CompletionContext<'_>,
-    path_ctx: &PathCompletionCtx,
-    expr_ctx: &PathExprCtx,
+    path_ctx: &PathCompletionCtx<'_>,
+    expr_ctx: &PathExprCtx<'_>,
 ) {
     if !ctx.config.enable_self_on_the_fly {
         return;
@@ -198,9 +198,9 @@ pub(crate) fn complete_undotted_self(
 fn complete_fields(
     acc: &mut Completions,
     ctx: &CompletionContext<'_>,
-    receiver: &hir::Type,
-    mut named_field: impl FnMut(&mut Completions, hir::Field, hir::Type),
-    mut tuple_index: impl FnMut(&mut Completions, usize, hir::Type),
+    receiver: &hir::Type<'_>,
+    mut named_field: impl FnMut(&mut Completions, hir::Field, hir::Type<'_>),
+    mut tuple_index: impl FnMut(&mut Completions, usize, hir::Type<'_>),
     is_field_access: bool,
     is_method_access_with_parens: bool,
 ) {
@@ -230,7 +230,7 @@ fn complete_fields(
 
 fn complete_methods(
     ctx: &CompletionContext<'_>,
-    receiver: &hir::Type,
+    receiver: &hir::Type<'_>,
     traits_in_scope: &FxHashSet<hir::TraitId>,
     f: impl FnMut(hir::Function),
 ) {
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 7fbd1fbc1af..2133291b1de 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
@@ -47,8 +47,8 @@ where
 pub(crate) fn complete_expr_path(
     acc: &mut Completions,
     ctx: &CompletionContext<'_>,
-    path_ctx @ PathCompletionCtx { qualified, .. }: &PathCompletionCtx,
-    expr_ctx: &PathExprCtx,
+    path_ctx @ PathCompletionCtx { qualified, .. }: &PathCompletionCtx<'_>,
+    expr_ctx: &PathExprCtx<'_>,
 ) {
     let _p = tracing::info_span!("complete_expr_path").entered();
     if !ctx.qualifier_ctx.none() {
@@ -145,10 +145,16 @@ pub(crate) fn complete_expr_path(
             });
             match resolution {
                 hir::PathResolution::Def(hir::ModuleDef::Module(module)) => {
-                    // Set visible_from to None so private items are returned.
-                    // They will be possibly filtered out in add_path_resolution()
-                    // via def_is_visible().
-                    let module_scope = module.scope(ctx.db, None);
+                    let visible_from = if ctx.config.enable_private_editable {
+                        // Set visible_from to None so private items are returned.
+                        // They will be possibly filtered out in add_path_resolution()
+                        // via def_is_visible().
+                        None
+                    } else {
+                        Some(ctx.module)
+                    };
+
+                    let module_scope = module.scope(ctx.db, visible_from);
                     for (name, def) in module_scope {
                         if scope_def_applicable(def) {
                             acc.add_path_resolution(
diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/completions/field.rs b/src/tools/rust-analyzer/crates/ide-completion/src/completions/field.rs
index 1441b0e3a01..26afa9c8ad9 100644
--- a/src/tools/rust-analyzer/crates/ide-completion/src/completions/field.rs
+++ b/src/tools/rust-analyzer/crates/ide-completion/src/completions/field.rs
@@ -8,7 +8,7 @@ use crate::{
 pub(crate) fn complete_field_list_tuple_variant(
     acc: &mut Completions,
     ctx: &CompletionContext<'_>,
-    path_ctx: &PathCompletionCtx,
+    path_ctx: &PathCompletionCtx<'_>,
 ) {
     if ctx.qualifier_ctx.vis_node.is_some() {
     } else if let PathCompletionCtx {
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 a7475613809..dad8a76de87 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
@@ -111,7 +111,7 @@ use crate::{
 pub(crate) fn import_on_the_fly_path(
     acc: &mut Completions,
     ctx: &CompletionContext<'_>,
-    path_ctx: &PathCompletionCtx,
+    path_ctx: &PathCompletionCtx<'_>,
 ) -> Option<()> {
     if !ctx.config.enable_imports_on_the_fly {
         return None;
@@ -175,7 +175,7 @@ pub(crate) fn import_on_the_fly_pat(
 pub(crate) fn import_on_the_fly_dot(
     acc: &mut Completions,
     ctx: &CompletionContext<'_>,
-    dot_access: &DotAccess,
+    dot_access: &DotAccess<'_>,
 ) -> Option<()> {
     if !ctx.config.enable_imports_on_the_fly {
         return None;
@@ -203,8 +203,8 @@ pub(crate) fn import_on_the_fly_dot(
 fn import_on_the_fly(
     acc: &mut Completions,
     ctx: &CompletionContext<'_>,
-    path_ctx @ PathCompletionCtx { kind, .. }: &PathCompletionCtx,
-    import_assets: ImportAssets,
+    path_ctx @ PathCompletionCtx { kind, .. }: &PathCompletionCtx<'_>,
+    import_assets: ImportAssets<'_>,
     position: SyntaxNode,
     potential_import_name: String,
 ) -> Option<()> {
@@ -290,7 +290,7 @@ fn import_on_the_fly_pat_(
     acc: &mut Completions,
     ctx: &CompletionContext<'_>,
     pattern_ctx: &PatternContext,
-    import_assets: ImportAssets,
+    import_assets: ImportAssets<'_>,
     position: SyntaxNode,
     potential_import_name: String,
 ) -> Option<()> {
@@ -335,8 +335,8 @@ fn import_on_the_fly_pat_(
 fn import_on_the_fly_method(
     acc: &mut Completions,
     ctx: &CompletionContext<'_>,
-    dot_access: &DotAccess,
-    import_assets: ImportAssets,
+    dot_access: &DotAccess<'_>,
+    import_assets: ImportAssets<'_>,
     position: SyntaxNode,
     potential_import_name: String,
 ) -> Option<()> {
@@ -400,11 +400,11 @@ fn import_name(ctx: &CompletionContext<'_>) -> String {
     if token_kind.is_any_identifier() { ctx.token.to_string() } else { String::new() }
 }
 
-fn import_assets_for_path(
-    ctx: &CompletionContext<'_>,
+fn import_assets_for_path<'db>(
+    ctx: &CompletionContext<'db>,
     potential_import_name: &str,
     qualifier: Option<ast::Path>,
-) -> Option<ImportAssets> {
+) -> Option<ImportAssets<'db>> {
     let _p =
         tracing::info_span!("import_assets_for_path", ?potential_import_name, ?qualifier).entered();
 
diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/completions/item_list.rs b/src/tools/rust-analyzer/crates/ide-completion/src/completions/item_list.rs
index 893997cee47..6c001bd16bf 100644
--- a/src/tools/rust-analyzer/crates/ide-completion/src/completions/item_list.rs
+++ b/src/tools/rust-analyzer/crates/ide-completion/src/completions/item_list.rs
@@ -10,8 +10,8 @@ pub(crate) mod trait_impl;
 pub(crate) fn complete_item_list_in_expr(
     acc: &mut Completions,
     ctx: &CompletionContext<'_>,
-    path_ctx: &PathCompletionCtx,
-    expr_ctx: &PathExprCtx,
+    path_ctx: &PathCompletionCtx<'_>,
+    expr_ctx: &PathExprCtx<'_>,
 ) {
     if !expr_ctx.in_block_expr {
         return;
@@ -25,7 +25,7 @@ pub(crate) fn complete_item_list_in_expr(
 pub(crate) fn complete_item_list(
     acc: &mut Completions,
     ctx: &CompletionContext<'_>,
-    path_ctx @ PathCompletionCtx { qualified, .. }: &PathCompletionCtx,
+    path_ctx @ PathCompletionCtx { qualified, .. }: &PathCompletionCtx<'_>,
     kind: &ItemListKind,
 ) {
     let _p = tracing::info_span!("complete_item_list").entered();
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 58aead73fd6..092219a058a 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
@@ -122,7 +122,7 @@ fn complete_trait_impl_name(
 pub(crate) fn complete_trait_impl_item_by_name(
     acc: &mut Completions,
     ctx: &CompletionContext<'_>,
-    path_ctx: &PathCompletionCtx,
+    path_ctx: &PathCompletionCtx<'_>,
     name_ref: &Option<ast::NameRef>,
     impl_: &Option<ast::Impl>,
 ) {
diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/completions/pattern.rs b/src/tools/rust-analyzer/crates/ide-completion/src/completions/pattern.rs
index ea3511d31ca..62fae1cb237 100644
--- a/src/tools/rust-analyzer/crates/ide-completion/src/completions/pattern.rs
+++ b/src/tools/rust-analyzer/crates/ide-completion/src/completions/pattern.rs
@@ -124,7 +124,7 @@ pub(crate) fn complete_pattern(
 pub(crate) fn complete_pattern_path(
     acc: &mut Completions,
     ctx: &CompletionContext<'_>,
-    path_ctx @ PathCompletionCtx { qualified, .. }: &PathCompletionCtx,
+    path_ctx @ PathCompletionCtx { qualified, .. }: &PathCompletionCtx<'_>,
 ) {
     match qualified {
         Qualified::With { resolution: Some(resolution), super_chain_len, .. } => {
diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/completions/postfix.rs b/src/tools/rust-analyzer/crates/ide-completion/src/completions/postfix.rs
index 3cdf2112835..d0023852acf 100644
--- a/src/tools/rust-analyzer/crates/ide-completion/src/completions/postfix.rs
+++ b/src/tools/rust-analyzer/crates/ide-completion/src/completions/postfix.rs
@@ -11,6 +11,7 @@ use ide_db::{
     text_edit::TextEdit,
     ty_filter::TryEnum,
 };
+use itertools::Either;
 use stdx::never;
 use syntax::{
     SyntaxKind::{BLOCK_EXPR, EXPR_STMT, FOR_EXPR, IF_EXPR, LOOP_EXPR, STMT_LIST, WHILE_EXPR},
@@ -28,7 +29,7 @@ use crate::{
 pub(crate) fn complete_postfix(
     acc: &mut Completions,
     ctx: &CompletionContext<'_>,
-    dot_access: &DotAccess,
+    dot_access: &DotAccess<'_>,
 ) {
     if !ctx.config.enable_postfix_completions {
         return;
@@ -86,98 +87,10 @@ pub(crate) fn complete_postfix(
         }
     }
 
-    let try_enum = TryEnum::from_ty(&ctx.sema, &receiver_ty.strip_references());
-    if let Some(try_enum) = &try_enum {
-        match try_enum {
-            TryEnum::Result => {
-                postfix_snippet(
-                    "ifl",
-                    "if let Ok {}",
-                    &format!("if let Ok($1) = {receiver_text} {{\n    $0\n}}"),
-                )
-                .add_to(acc, ctx.db);
-
-                postfix_snippet(
-                    "lete",
-                    "let Ok else {}",
-                    &format!("let Ok($1) = {receiver_text} else {{\n    $2\n}};\n$0"),
-                )
-                .add_to(acc, ctx.db);
-
-                postfix_snippet(
-                    "while",
-                    "while let Ok {}",
-                    &format!("while let Ok($1) = {receiver_text} {{\n    $0\n}}"),
-                )
-                .add_to(acc, ctx.db);
-            }
-            TryEnum::Option => {
-                postfix_snippet(
-                    "ifl",
-                    "if let Some {}",
-                    &format!("if let Some($1) = {receiver_text} {{\n    $0\n}}"),
-                )
-                .add_to(acc, ctx.db);
-
-                postfix_snippet(
-                    "lete",
-                    "let Some else {}",
-                    &format!("let Some($1) = {receiver_text} else {{\n    $2\n}};\n$0"),
-                )
-                .add_to(acc, ctx.db);
-
-                postfix_snippet(
-                    "while",
-                    "while let Some {}",
-                    &format!("while let Some($1) = {receiver_text} {{\n    $0\n}}"),
-                )
-                .add_to(acc, ctx.db);
-            }
-        }
-    } else if receiver_ty.is_bool() || receiver_ty.is_unknown() {
-        postfix_snippet("if", "if expr {}", &format!("if {receiver_text} {{\n    $0\n}}"))
-            .add_to(acc, ctx.db);
-        postfix_snippet("while", "while expr {}", &format!("while {receiver_text} {{\n    $0\n}}"))
-            .add_to(acc, ctx.db);
-        postfix_snippet("not", "!expr", &format!("!{receiver_text}")).add_to(acc, ctx.db);
-    } else if let Some(trait_) = ctx.famous_defs().core_iter_IntoIterator() {
-        if receiver_ty.impls_trait(ctx.db, trait_, &[]) {
-            postfix_snippet(
-                "for",
-                "for ele in expr {}",
-                &format!("for ele in {receiver_text} {{\n    $0\n}}"),
-            )
-            .add_to(acc, ctx.db);
-        }
-    }
-
     postfix_snippet("ref", "&expr", &format!("&{receiver_text}")).add_to(acc, ctx.db);
     postfix_snippet("refm", "&mut expr", &format!("&mut {receiver_text}")).add_to(acc, ctx.db);
     postfix_snippet("deref", "*expr", &format!("*{receiver_text}")).add_to(acc, ctx.db);
 
-    let mut block_should_be_wrapped = true;
-    if dot_receiver.syntax().kind() == BLOCK_EXPR {
-        block_should_be_wrapped = false;
-        if let Some(parent) = dot_receiver.syntax().parent() {
-            if matches!(parent.kind(), IF_EXPR | WHILE_EXPR | LOOP_EXPR | FOR_EXPR) {
-                block_should_be_wrapped = true;
-            }
-        }
-    };
-    let unsafe_completion_string = if block_should_be_wrapped {
-        format!("unsafe {{ {receiver_text} }}")
-    } else {
-        format!("unsafe {receiver_text}")
-    };
-    postfix_snippet("unsafe", "unsafe {}", &unsafe_completion_string).add_to(acc, ctx.db);
-
-    let const_completion_string = if block_should_be_wrapped {
-        format!("const {{ {receiver_text} }}")
-    } else {
-        format!("const {receiver_text}")
-    };
-    postfix_snippet("const", "const {}", &const_completion_string).add_to(acc, ctx.db);
-
     // The rest of the postfix completions create an expression that moves an argument,
     // so it's better to consider references now to avoid breaking the compilation
 
@@ -195,18 +108,81 @@ pub(crate) fn complete_postfix(
         add_custom_postfix_completions(acc, ctx, &postfix_snippet, &receiver_text);
     }
 
-    match try_enum {
-        Some(try_enum) => match try_enum {
-            TryEnum::Result => {
-                postfix_snippet(
+    postfix_snippet("box", "Box::new(expr)", &format!("Box::new({receiver_text})"))
+        .add_to(acc, ctx.db);
+    postfix_snippet("dbg", "dbg!(expr)", &format!("dbg!({receiver_text})")).add_to(acc, ctx.db); // fixme
+    postfix_snippet("dbgr", "dbg!(&expr)", &format!("dbg!(&{receiver_text})")).add_to(acc, ctx.db);
+    postfix_snippet("call", "function(expr)", &format!("${{1}}({receiver_text})"))
+        .add_to(acc, ctx.db);
+
+    let try_enum = TryEnum::from_ty(&ctx.sema, &receiver_ty.strip_references());
+    let mut is_in_cond = false;
+    if let Some(parent) = dot_receiver_including_refs.syntax().parent() {
+        if let Some(second_ancestor) = parent.parent() {
+            let sec_ancestor_kind = second_ancestor.kind();
+            if let Some(expr) = <Either<ast::IfExpr, ast::WhileExpr>>::cast(second_ancestor) {
+                is_in_cond = match expr {
+                    Either::Left(it) => it.condition().is_some_and(|cond| *cond.syntax() == parent),
+                    Either::Right(it) => {
+                        it.condition().is_some_and(|cond| *cond.syntax() == parent)
+                    }
+                }
+            }
+            match &try_enum {
+                Some(try_enum) if is_in_cond => match try_enum {
+                    TryEnum::Result => {
+                        postfix_snippet(
+                            "let",
+                            "let Ok(_)",
+                            &format!("let Ok($0) = {receiver_text}"),
+                        )
+                        .add_to(acc, ctx.db);
+                        postfix_snippet(
+                            "letm",
+                            "let Ok(mut _)",
+                            &format!("let Ok(mut $0) = {receiver_text}"),
+                        )
+                        .add_to(acc, ctx.db);
+                    }
+                    TryEnum::Option => {
+                        postfix_snippet(
+                            "let",
+                            "let Some(_)",
+                            &format!("let Some($0) = {receiver_text}"),
+                        )
+                        .add_to(acc, ctx.db);
+                        postfix_snippet(
+                            "letm",
+                            "let Some(mut _)",
+                            &format!("let Some(mut $0) = {receiver_text}"),
+                        )
+                        .add_to(acc, ctx.db);
+                    }
+                },
+                _ if matches!(sec_ancestor_kind, STMT_LIST | EXPR_STMT) => {
+                    postfix_snippet("let", "let", &format!("let $0 = {receiver_text};"))
+                        .add_to(acc, ctx.db);
+                    postfix_snippet("letm", "let mut", &format!("let mut $0 = {receiver_text};"))
+                        .add_to(acc, ctx.db);
+                }
+                _ => (),
+            }
+        }
+    }
+
+    if !is_in_cond {
+        match try_enum {
+            Some(try_enum) => match try_enum {
+                TryEnum::Result => {
+                    postfix_snippet(
                     "match",
                     "match expr {}",
                     &format!("match {receiver_text} {{\n    Ok(${{1:_}}) => {{$2}},\n    Err(${{3:_}}) => {{$0}},\n}}"),
                 )
                 .add_to(acc, ctx.db);
-            }
-            TryEnum::Option => {
-                postfix_snippet(
+                }
+                TryEnum::Option => {
+                    postfix_snippet(
                     "match",
                     "match expr {}",
                     &format!(
@@ -214,32 +190,106 @@ pub(crate) fn complete_postfix(
                     ),
                 )
                 .add_to(acc, ctx.db);
+                }
+            },
+            None => {
+                postfix_snippet(
+                    "match",
+                    "match expr {}",
+                    &format!("match {receiver_text} {{\n    ${{1:_}} => {{$0}},\n}}"),
+                )
+                .add_to(acc, ctx.db);
             }
-        },
-        None => {
+        }
+        if let Some(try_enum) = &try_enum {
+            match try_enum {
+                TryEnum::Result => {
+                    postfix_snippet(
+                        "ifl",
+                        "if let Ok {}",
+                        &format!("if let Ok($1) = {receiver_text} {{\n    $0\n}}"),
+                    )
+                    .add_to(acc, ctx.db);
+
+                    postfix_snippet(
+                        "lete",
+                        "let Ok else {}",
+                        &format!("let Ok($1) = {receiver_text} else {{\n    $2\n}};\n$0"),
+                    )
+                    .add_to(acc, ctx.db);
+
+                    postfix_snippet(
+                        "while",
+                        "while let Ok {}",
+                        &format!("while let Ok($1) = {receiver_text} {{\n    $0\n}}"),
+                    )
+                    .add_to(acc, ctx.db);
+                }
+                TryEnum::Option => {
+                    postfix_snippet(
+                        "ifl",
+                        "if let Some {}",
+                        &format!("if let Some($1) = {receiver_text} {{\n    $0\n}}"),
+                    )
+                    .add_to(acc, ctx.db);
+
+                    postfix_snippet(
+                        "lete",
+                        "let Some else {}",
+                        &format!("let Some($1) = {receiver_text} else {{\n    $2\n}};\n$0"),
+                    )
+                    .add_to(acc, ctx.db);
+
+                    postfix_snippet(
+                        "while",
+                        "while let Some {}",
+                        &format!("while let Some($1) = {receiver_text} {{\n    $0\n}}"),
+                    )
+                    .add_to(acc, ctx.db);
+                }
+            }
+        } else if receiver_ty.is_bool() || receiver_ty.is_unknown() {
+            postfix_snippet("if", "if expr {}", &format!("if {receiver_text} {{\n    $0\n}}"))
+                .add_to(acc, ctx.db);
             postfix_snippet(
-                "match",
-                "match expr {}",
-                &format!("match {receiver_text} {{\n    ${{1:_}} => {{$0}},\n}}"),
+                "while",
+                "while expr {}",
+                &format!("while {receiver_text} {{\n    $0\n}}"),
             )
             .add_to(acc, ctx.db);
+            postfix_snippet("not", "!expr", &format!("!{receiver_text}")).add_to(acc, ctx.db);
+        } else if let Some(trait_) = ctx.famous_defs().core_iter_IntoIterator() {
+            if receiver_ty.impls_trait(ctx.db, trait_, &[]) {
+                postfix_snippet(
+                    "for",
+                    "for ele in expr {}",
+                    &format!("for ele in {receiver_text} {{\n    $0\n}}"),
+                )
+                .add_to(acc, ctx.db);
+            }
         }
     }
 
-    postfix_snippet("box", "Box::new(expr)", &format!("Box::new({receiver_text})"))
-        .add_to(acc, ctx.db);
-    postfix_snippet("dbg", "dbg!(expr)", &format!("dbg!({receiver_text})")).add_to(acc, ctx.db); // fixme
-    postfix_snippet("dbgr", "dbg!(&expr)", &format!("dbg!(&{receiver_text})")).add_to(acc, ctx.db);
-    postfix_snippet("call", "function(expr)", &format!("${{1}}({receiver_text})"))
-        .add_to(acc, ctx.db);
-
-    if let Some(parent) = dot_receiver_including_refs.syntax().parent().and_then(|p| p.parent()) {
-        if matches!(parent.kind(), STMT_LIST | EXPR_STMT) {
-            postfix_snippet("let", "let", &format!("let $0 = {receiver_text};"))
-                .add_to(acc, ctx.db);
-            postfix_snippet("letm", "let mut", &format!("let mut $0 = {receiver_text};"))
-                .add_to(acc, ctx.db);
+    let mut block_should_be_wrapped = true;
+    if dot_receiver.syntax().kind() == BLOCK_EXPR {
+        block_should_be_wrapped = false;
+        if let Some(parent) = dot_receiver.syntax().parent() {
+            if matches!(parent.kind(), IF_EXPR | WHILE_EXPR | LOOP_EXPR | FOR_EXPR) {
+                block_should_be_wrapped = true;
+            }
         }
+    };
+    {
+        let (open_brace, close_brace) =
+            if block_should_be_wrapped { ("{ ", " }") } else { ("", "") };
+        let (open_paren, close_paren) = if is_in_cond { ("(", ")") } else { ("", "") };
+        let unsafe_completion_string =
+            format!("{open_paren}unsafe {open_brace}{receiver_text}{close_brace}{close_paren}");
+        postfix_snippet("unsafe", "unsafe {}", &unsafe_completion_string).add_to(acc, ctx.db);
+
+        let const_completion_string =
+            format!("{open_paren}const {open_brace}{receiver_text}{close_brace}{close_paren}");
+        postfix_snippet("const", "const {}", &const_completion_string).add_to(acc, ctx.db);
     }
 
     if let ast::Expr::Literal(literal) = dot_receiver_including_refs.clone() {
@@ -568,6 +618,54 @@ fn main() {
     }
 
     #[test]
+    fn option_iflet_cond() {
+        check(
+            r#"
+//- minicore: option
+fn main() {
+    let bar = Some(true);
+    if bar.$0
+}
+"#,
+            expect![[r#"
+                me and(…)    fn(self, Option<U>) -> Option<U>
+                me as_ref()     const fn(&self) -> Option<&T>
+                me ok_or(…) const fn(self, E) -> Result<T, E>
+                me unwrap()               const fn(self) -> T
+                me unwrap_or(…)              fn(self, T) -> T
+                sn box                         Box::new(expr)
+                sn call                        function(expr)
+                sn const                             const {}
+                sn dbg                             dbg!(expr)
+                sn dbgr                           dbg!(&expr)
+                sn deref                                *expr
+                sn let                            let Some(_)
+                sn letm                       let Some(mut _)
+                sn ref                                  &expr
+                sn refm                             &mut expr
+                sn return                         return expr
+                sn unsafe                           unsafe {}
+            "#]],
+        );
+        check_edit(
+            "let",
+            r#"
+//- minicore: option
+fn main() {
+    let bar = Some(true);
+    if bar.$0
+}
+"#,
+            r#"
+fn main() {
+    let bar = Some(true);
+    if let Some($0) = bar
+}
+"#,
+        );
+    }
+
+    #[test]
     fn option_letelse() {
         check_edit(
             "lete",
diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/completions/record.rs b/src/tools/rust-analyzer/crates/ide-completion/src/completions/record.rs
index c18aab007b2..36f38a70db6 100644
--- a/src/tools/rust-analyzer/crates/ide-completion/src/completions/record.rs
+++ b/src/tools/rust-analyzer/crates/ide-completion/src/completions/record.rs
@@ -88,7 +88,7 @@ pub(crate) fn complete_record_expr_fields(
 pub(crate) fn add_default_update(
     acc: &mut Completions,
     ctx: &CompletionContext<'_>,
-    ty: Option<hir::TypeInfo>,
+    ty: Option<hir::TypeInfo<'_>>,
 ) {
     let default_trait = ctx.famous_defs().core_default_Default();
     let impls_default_trait = default_trait
@@ -117,7 +117,7 @@ pub(crate) fn add_default_update(
 fn complete_fields(
     acc: &mut Completions,
     ctx: &CompletionContext<'_>,
-    missing_fields: Vec<(hir::Field, hir::Type)>,
+    missing_fields: Vec<(hir::Field, hir::Type<'_>)>,
 ) {
     for (field, ty) in missing_fields {
         // This should call something else, we shouldn't be synthesizing a DotAccess here
diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/completions/snippet.rs b/src/tools/rust-analyzer/crates/ide-completion/src/completions/snippet.rs
index 31aae116762..ead9852eff5 100644
--- a/src/tools/rust-analyzer/crates/ide-completion/src/completions/snippet.rs
+++ b/src/tools/rust-analyzer/crates/ide-completion/src/completions/snippet.rs
@@ -11,8 +11,8 @@ use crate::{
 pub(crate) fn complete_expr_snippet(
     acc: &mut Completions,
     ctx: &CompletionContext<'_>,
-    path_ctx: &PathCompletionCtx,
-    &PathExprCtx { in_block_expr, .. }: &PathExprCtx,
+    path_ctx: &PathCompletionCtx<'_>,
+    &PathExprCtx { in_block_expr, .. }: &PathExprCtx<'_>,
 ) {
     if !matches!(path_ctx.qualified, Qualified::No) {
         return;
@@ -51,7 +51,7 @@ macro_rules! $1 {
 pub(crate) fn complete_item_snippet(
     acc: &mut Completions,
     ctx: &CompletionContext<'_>,
-    path_ctx: &PathCompletionCtx,
+    path_ctx: &PathCompletionCtx<'_>,
     kind: &ItemListKind,
 ) {
     if !matches!(path_ctx.qualified, Qualified::No) {
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 79db705af49..7c38c7d8ce4 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
@@ -12,7 +12,7 @@ use crate::{
 pub(crate) fn complete_type_path(
     acc: &mut Completions,
     ctx: &CompletionContext<'_>,
-    path_ctx @ PathCompletionCtx { qualified, .. }: &PathCompletionCtx,
+    path_ctx @ PathCompletionCtx { qualified, .. }: &PathCompletionCtx<'_>,
     location: &TypeLocation,
 ) {
     let _p = tracing::info_span!("complete_type_path").entered();
@@ -220,7 +220,7 @@ pub(crate) fn complete_type_path(
 pub(crate) fn complete_ascribed_type(
     acc: &mut Completions,
     ctx: &CompletionContext<'_>,
-    path_ctx: &PathCompletionCtx,
+    path_ctx: &PathCompletionCtx<'_>,
     ascription: &TypeAscriptionTarget,
 ) -> Option<()> {
     if !path_ctx.is_trivial_path() {
diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/completions/use_.rs b/src/tools/rust-analyzer/crates/ide-completion/src/completions/use_.rs
index 4d6d0b758a3..d2ab193ec3d 100644
--- a/src/tools/rust-analyzer/crates/ide-completion/src/completions/use_.rs
+++ b/src/tools/rust-analyzer/crates/ide-completion/src/completions/use_.rs
@@ -13,7 +13,7 @@ use crate::{
 pub(crate) fn complete_use_path(
     acc: &mut Completions,
     ctx: &CompletionContext<'_>,
-    path_ctx @ PathCompletionCtx { qualified, use_tree_parent, .. }: &PathCompletionCtx,
+    path_ctx @ PathCompletionCtx { qualified, use_tree_parent, .. }: &PathCompletionCtx<'_>,
     name_ref: &Option<ast::NameRef>,
 ) {
     match qualified {
diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/completions/vis.rs b/src/tools/rust-analyzer/crates/ide-completion/src/completions/vis.rs
index d15c35ac849..38761f77a2c 100644
--- a/src/tools/rust-analyzer/crates/ide-completion/src/completions/vis.rs
+++ b/src/tools/rust-analyzer/crates/ide-completion/src/completions/vis.rs
@@ -8,7 +8,7 @@ use crate::{
 pub(crate) fn complete_vis_path(
     acc: &mut Completions,
     ctx: &CompletionContext<'_>,
-    path_ctx @ PathCompletionCtx { qualified, .. }: &PathCompletionCtx,
+    path_ctx @ PathCompletionCtx { qualified, .. }: &PathCompletionCtx<'_>,
     &has_in_token: &bool,
 ) {
     match qualified {
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 5287627790a..cfd7f80d40b 100644
--- a/src/tools/rust-analyzer/crates/ide-completion/src/context.rs
+++ b/src/tools/rust-analyzer/crates/ide-completion/src/context.rs
@@ -65,13 +65,13 @@ impl QualifierCtx {
 
 /// The state of the path we are currently completing.
 #[derive(Debug)]
-pub(crate) struct PathCompletionCtx {
+pub(crate) struct PathCompletionCtx<'db> {
     /// If this is a call with () already there (or {} in case of record patterns)
     pub(crate) has_call_parens: bool,
     /// If this has a macro call bang !
     pub(crate) has_macro_bang: bool,
     /// The qualifier of the current path.
-    pub(crate) qualified: Qualified,
+    pub(crate) qualified: Qualified<'db>,
     /// The parent of the path we are completing.
     pub(crate) parent: Option<ast::Path>,
     #[allow(dead_code)]
@@ -79,14 +79,14 @@ pub(crate) struct PathCompletionCtx {
     pub(crate) path: ast::Path,
     /// The path of which we are completing the segment in the original file
     pub(crate) original_path: Option<ast::Path>,
-    pub(crate) kind: PathKind,
+    pub(crate) kind: PathKind<'db>,
     /// Whether the path segment has type args or not.
     pub(crate) has_type_args: bool,
     /// Whether the qualifier comes from a use tree parent or not
     pub(crate) use_tree_parent: bool,
 }
 
-impl PathCompletionCtx {
+impl PathCompletionCtx<'_> {
     pub(crate) fn is_trivial_path(&self) -> bool {
         matches!(
             self,
@@ -104,9 +104,9 @@ impl PathCompletionCtx {
 
 /// The kind of path we are completing right now.
 #[derive(Debug, PartialEq, Eq)]
-pub(crate) enum PathKind {
+pub(crate) enum PathKind<'db> {
     Expr {
-        expr_ctx: PathExprCtx,
+        expr_ctx: PathExprCtx<'db>,
     },
     Type {
         location: TypeLocation,
@@ -140,7 +140,7 @@ pub(crate) struct AttrCtx {
 }
 
 #[derive(Debug, PartialEq, Eq)]
-pub(crate) struct PathExprCtx {
+pub(crate) struct PathExprCtx<'db> {
     pub(crate) in_block_expr: bool,
     pub(crate) in_breakable: BreakableKind,
     pub(crate) after_if_expr: bool,
@@ -152,7 +152,7 @@ pub(crate) struct PathExprCtx {
     /// The surrounding RecordExpression we are completing a functional update
     pub(crate) is_func_update: Option<ast::RecordExpr>,
     pub(crate) self_param: Option<hir::SelfParam>,
-    pub(crate) innermost_ret_ty: Option<hir::Type>,
+    pub(crate) innermost_ret_ty: Option<hir::Type<'db>>,
     pub(crate) impl_: Option<ast::Impl>,
     /// Whether this expression occurs in match arm guard position: before the
     /// fat arrow token
@@ -241,7 +241,7 @@ pub(crate) enum ItemListKind {
 }
 
 #[derive(Debug)]
-pub(crate) enum Qualified {
+pub(crate) enum Qualified<'db> {
     No,
     With {
         path: ast::Path,
@@ -260,7 +260,7 @@ pub(crate) enum Qualified {
     },
     /// <_>::
     TypeAnchor {
-        ty: Option<hir::Type>,
+        ty: Option<hir::Type<'db>>,
         trait_: Option<hir::Trait>,
     },
     /// Whether the path is an absolute path
@@ -341,17 +341,17 @@ pub(crate) enum NameKind {
 
 /// The state of the NameRef we are completing.
 #[derive(Debug)]
-pub(crate) struct NameRefContext {
+pub(crate) struct NameRefContext<'db> {
     /// NameRef syntax in the original file
     pub(crate) nameref: Option<ast::NameRef>,
-    pub(crate) kind: NameRefKind,
+    pub(crate) kind: NameRefKind<'db>,
 }
 
 /// The kind of the NameRef we are completing.
 #[derive(Debug)]
-pub(crate) enum NameRefKind {
-    Path(PathCompletionCtx),
-    DotAccess(DotAccess),
+pub(crate) enum NameRefKind<'db> {
+    Path(PathCompletionCtx<'db>),
+    DotAccess(DotAccess<'db>),
     /// Position where we are only interested in keyword completions
     Keyword(ast::Item),
     /// The record expression this nameref is a field of and whether a dot precedes the completion identifier.
@@ -365,9 +365,9 @@ pub(crate) enum NameRefKind {
 
 /// The identifier we are currently completing.
 #[derive(Debug)]
-pub(crate) enum CompletionAnalysis {
+pub(crate) enum CompletionAnalysis<'db> {
     Name(NameContext),
-    NameRef(NameRefContext),
+    NameRef(NameRefContext<'db>),
     Lifetime(LifetimeContext),
     /// The string the cursor is currently inside
     String {
@@ -386,9 +386,9 @@ pub(crate) enum CompletionAnalysis {
 
 /// Information about the field or method access we are completing.
 #[derive(Debug)]
-pub(crate) struct DotAccess {
+pub(crate) struct DotAccess<'db> {
     pub(crate) receiver: Option<ast::Expr>,
-    pub(crate) receiver_ty: Option<TypeInfo>,
+    pub(crate) receiver_ty: Option<TypeInfo<'db>>,
     pub(crate) kind: DotAccessKind,
     pub(crate) ctx: DotAccessExprCtx,
 }
@@ -457,7 +457,7 @@ pub(crate) struct CompletionContext<'a> {
     /// This is usually the parameter name of the function argument we are completing.
     pub(crate) expected_name: Option<NameOrNameRef>,
     /// The expected type of what we are completing.
-    pub(crate) expected_type: Option<Type>,
+    pub(crate) expected_type: Option<Type<'a>>,
 
     pub(crate) qualifier_ctx: QualifierCtx,
 
@@ -608,7 +608,7 @@ impl CompletionContext<'_> {
 
     pub(crate) fn iterate_path_candidates(
         &self,
-        ty: &hir::Type,
+        ty: &hir::Type<'_>,
         mut cb: impl FnMut(hir::AssocItem),
     ) {
         let mut seen = FxHashSet::default();
@@ -695,12 +695,12 @@ impl CompletionContext<'_> {
 }
 
 // CompletionContext construction
-impl<'a> CompletionContext<'a> {
+impl<'db> CompletionContext<'db> {
     pub(crate) fn new(
-        db: &'a RootDatabase,
+        db: &'db RootDatabase,
         position @ FilePosition { file_id, offset }: FilePosition,
-        config: &'a CompletionConfig<'a>,
-    ) -> Option<(CompletionContext<'a>, CompletionAnalysis)> {
+        config: &'db CompletionConfig<'db>,
+    ) -> Option<(CompletionContext<'db>, CompletionAnalysis<'db>)> {
         let _p = tracing::info_span!("CompletionContext::new").entered();
         let sema = Semantics::new(db);
 
diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/context/analysis.rs b/src/tools/rust-analyzer/crates/ide-completion/src/context/analysis.rs
index 7a2230b3e36..6e3a76f346a 100644
--- a/src/tools/rust-analyzer/crates/ide-completion/src/context/analysis.rs
+++ b/src/tools/rust-analyzer/crates/ide-completion/src/context/analysis.rs
@@ -38,9 +38,9 @@ struct ExpansionResult {
     derive_ctx: Option<(SyntaxNode, SyntaxNode, TextSize, ast::Attr)>,
 }
 
-pub(super) struct AnalysisResult {
-    pub(super) analysis: CompletionAnalysis,
-    pub(super) expected: (Option<Type>, Option<ast::NameOrNameRef>),
+pub(super) struct AnalysisResult<'db> {
+    pub(super) analysis: CompletionAnalysis<'db>,
+    pub(super) expected: (Option<Type<'db>>, Option<ast::NameOrNameRef>),
     pub(super) qualifier_ctx: QualifierCtx,
     /// the original token of the expanded file
     pub(super) token: SyntaxToken,
@@ -48,13 +48,13 @@ pub(super) struct AnalysisResult {
     pub(super) original_offset: TextSize,
 }
 
-pub(super) fn expand_and_analyze(
-    sema: &Semantics<'_, RootDatabase>,
+pub(super) fn expand_and_analyze<'db>(
+    sema: &Semantics<'db, RootDatabase>,
     original_file: InFile<SyntaxNode>,
     speculative_file: SyntaxNode,
     offset: TextSize,
     original_token: &SyntaxToken,
-) -> Option<AnalysisResult> {
+) -> Option<AnalysisResult<'db>> {
     // as we insert after the offset, right biased will *always* pick the identifier no matter
     // if there is an ident already typed or not
     let fake_ident_token = speculative_file.token_at_offset(offset).right_biased()?;
@@ -432,12 +432,13 @@ fn expand(
 
 /// Fill the completion context, this is what does semantic reasoning about the surrounding context
 /// of the completion location.
-fn analyze(
-    sema: &Semantics<'_, RootDatabase>,
+fn analyze<'db>(
+    sema: &Semantics<'db, RootDatabase>,
     expansion_result: ExpansionResult,
     original_token: &SyntaxToken,
     self_token: &SyntaxToken,
-) -> Option<(CompletionAnalysis, (Option<Type>, Option<ast::NameOrNameRef>), QualifierCtx)> {
+) -> Option<(CompletionAnalysis<'db>, (Option<Type<'db>>, Option<ast::NameOrNameRef>), QualifierCtx)>
+{
     let _p = tracing::info_span!("CompletionContext::analyze").entered();
     let ExpansionResult {
         original_file,
@@ -555,17 +556,17 @@ fn analyze(
 }
 
 /// Calculate the expected type and name of the cursor position.
-fn expected_type_and_name(
-    sema: &Semantics<'_, RootDatabase>,
+fn expected_type_and_name<'db>(
+    sema: &Semantics<'db, RootDatabase>,
     token: &SyntaxToken,
     name_like: &ast::NameLike,
-) -> (Option<Type>, Option<NameOrNameRef>) {
+) -> (Option<Type<'db>>, Option<NameOrNameRef>) {
     let mut node = match token.parent() {
         Some(it) => it,
         None => return (None, None),
     };
 
-    let strip_refs = |mut ty: Type| match name_like {
+    let strip_refs = |mut ty: Type<'db>| match name_like {
         ast::NameLike::NameRef(n) => {
             let p = match n.syntax().parent() {
                 Some(it) => it,
@@ -805,13 +806,13 @@ fn classify_name(
     Some(NameContext { name, kind })
 }
 
-fn classify_name_ref(
-    sema: &Semantics<'_, RootDatabase>,
+fn classify_name_ref<'db>(
+    sema: &Semantics<'db, RootDatabase>,
     original_file: &SyntaxNode,
     name_ref: ast::NameRef,
     original_offset: TextSize,
     parent: SyntaxNode,
-) -> Option<(NameRefContext, QualifierCtx)> {
+) -> Option<(NameRefContext<'db>, QualifierCtx)> {
     let nameref = find_node_at_offset(original_file, original_offset);
 
     let make_res = |kind| (NameRefContext { nameref: nameref.clone(), kind }, Default::default());
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 19cdef30bd9..dcaac3997b2 100644
--- a/src/tools/rust-analyzer/crates/ide-completion/src/item.rs
+++ b/src/tools/rust-analyzer/crates/ide-completion/src/item.rs
@@ -502,7 +502,7 @@ pub(crate) struct Builder {
 impl Builder {
     pub(crate) fn from_resolution(
         ctx: &CompletionContext<'_>,
-        path_ctx: &PathCompletionCtx,
+        path_ctx: &PathCompletionCtx<'_>,
         local_name: hir::Name,
         resolution: hir::ScopeDef,
     ) -> Self {
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 00c0b470f98..c6b8af3c79a 100644
--- a/src/tools/rust-analyzer/crates/ide-completion/src/render.rs
+++ b/src/tools/rust-analyzer/crates/ide-completion/src/render.rs
@@ -122,10 +122,10 @@ impl<'a> RenderContext<'a> {
 
 pub(crate) fn render_field(
     ctx: RenderContext<'_>,
-    dot_access: &DotAccess,
+    dot_access: &DotAccess<'_>,
     receiver: Option<SmolStr>,
     field: hir::Field,
-    ty: &hir::Type,
+    ty: &hir::Type<'_>,
 ) -> CompletionItem {
     let db = ctx.db();
     let is_deprecated = ctx.is_deprecated(field);
@@ -204,7 +204,7 @@ pub(crate) fn render_tuple_field(
     ctx: RenderContext<'_>,
     receiver: Option<SmolStr>,
     field: usize,
-    ty: &hir::Type,
+    ty: &hir::Type<'_>,
 ) -> CompletionItem {
     let mut item = CompletionItem::new(
         SymbolKind::Field,
@@ -241,7 +241,7 @@ pub(crate) fn render_type_inference(
 
 pub(crate) fn render_path_resolution(
     ctx: RenderContext<'_>,
-    path_ctx: &PathCompletionCtx,
+    path_ctx: &PathCompletionCtx<'_>,
     local_name: hir::Name,
     resolution: ScopeDef,
 ) -> Builder {
@@ -259,7 +259,7 @@ pub(crate) fn render_pattern_resolution(
 
 pub(crate) fn render_resolution_with_import(
     ctx: RenderContext<'_>,
-    path_ctx: &PathCompletionCtx,
+    path_ctx: &PathCompletionCtx<'_>,
     import_edit: LocatedImport,
 ) -> Option<Builder> {
     let resolution = ScopeDef::from(import_edit.original_item);
@@ -282,10 +282,10 @@ pub(crate) fn render_resolution_with_import_pat(
 
 pub(crate) fn render_expr(
     ctx: &CompletionContext<'_>,
-    expr: &hir::term_search::Expr,
+    expr: &hir::term_search::Expr<'_>,
 ) -> Option<Builder> {
     let mut i = 1;
-    let mut snippet_formatter = |ty: &hir::Type| {
+    let mut snippet_formatter = |ty: &hir::Type<'_>| {
         let arg_name = ty
             .as_adt()
             .map(|adt| stdx::to_lower_snake_case(adt.name(ctx.db).as_str()))
@@ -295,7 +295,7 @@ pub(crate) fn render_expr(
         res
     };
 
-    let mut label_formatter = |ty: &hir::Type| {
+    let mut label_formatter = |ty: &hir::Type<'_>| {
         ty.as_adt()
             .map(|adt| stdx::to_lower_snake_case(adt.name(ctx.db).as_str()))
             .unwrap_or_else(|| String::from("..."))
@@ -391,7 +391,7 @@ fn render_resolution_pat(
 
 fn render_resolution_path(
     ctx: RenderContext<'_>,
-    path_ctx: &PathCompletionCtx,
+    path_ctx: &PathCompletionCtx<'_>,
     local_name: hir::Name,
     import_to_add: Option<LocatedImport>,
     resolution: ScopeDef,
@@ -460,7 +460,7 @@ fn render_resolution_path(
         }
     }
 
-    let mut set_item_relevance = |ty: Type| {
+    let mut set_item_relevance = |ty: Type<'_>| {
         if !ty.is_unknown() {
             item.detail(ty.display(db, krate).to_string());
         }
@@ -593,8 +593,8 @@ fn scope_def_is_deprecated(ctx: &RenderContext<'_>, resolution: ScopeDef) -> boo
 // FIXME: This checks types without possible coercions which some completions might want to do
 fn match_types(
     ctx: &CompletionContext<'_>,
-    ty1: &hir::Type,
-    ty2: &hir::Type,
+    ty1: &hir::Type<'_>,
+    ty2: &hir::Type<'_>,
 ) -> Option<CompletionRelevanceTypeMatch> {
     if ty1 == ty2 {
         Some(CompletionRelevanceTypeMatch::Exact)
@@ -607,7 +607,7 @@ fn match_types(
 
 fn compute_type_match(
     ctx: &CompletionContext<'_>,
-    completion_ty: &hir::Type,
+    completion_ty: &hir::Type<'_>,
 ) -> Option<CompletionRelevanceTypeMatch> {
     let expected_type = ctx.expected_type.as_ref()?;
 
@@ -626,7 +626,7 @@ fn compute_exact_name_match(ctx: &CompletionContext<'_>, completion_name: &str)
 
 fn compute_ref_match(
     ctx: &CompletionContext<'_>,
-    completion_ty: &hir::Type,
+    completion_ty: &hir::Type<'_>,
 ) -> Option<CompletionItemRefMode> {
     let expected_type = ctx.expected_type.as_ref()?;
     let expected_without_ref = expected_type.remove_ref();
@@ -658,8 +658,8 @@ fn compute_ref_match(
 
 fn path_ref_match(
     completion: &CompletionContext<'_>,
-    path_ctx: &PathCompletionCtx,
-    ty: &hir::Type,
+    path_ctx: &PathCompletionCtx<'_>,
+    ty: &hir::Type<'_>,
     item: &mut Builder,
 ) {
     if let Some(original_path) = &path_ctx.original_path {
@@ -733,7 +733,7 @@ mod tests {
     ) {
         let mut actual = get_all_items(TEST_CONFIG, ra_fixture, None);
         actual.retain(|it| kinds.contains(&it.kind));
-        actual.sort_by_key(|it| cmp::Reverse(it.relevance.score()));
+        actual.sort_by_key(|it| (cmp::Reverse(it.relevance.score()), it.label.primary.clone()));
         check_relevance_(actual, expect);
     }
 
@@ -743,7 +743,7 @@ mod tests {
         actual.retain(|it| it.kind != CompletionItemKind::Snippet);
         actual.retain(|it| it.kind != CompletionItemKind::Keyword);
         actual.retain(|it| it.kind != CompletionItemKind::BuiltinType);
-        actual.sort_by_key(|it| cmp::Reverse(it.relevance.score()));
+        actual.sort_by_key(|it| (cmp::Reverse(it.relevance.score()), it.label.primary.clone()));
         check_relevance_(actual, expect);
     }
 
@@ -824,9 +824,9 @@ fn main() {
                 st dep::test_mod_b::Struct {…} dep::test_mod_b::Struct {  } [type_could_unify]
                 ex dep::test_mod_b::Struct {  }  [type_could_unify]
                 st Struct Struct [type_could_unify+requires_import]
+                md dep  []
                 fn main() fn() []
                 fn test(…) fn(Struct) []
-                md dep  []
                 st Struct Struct [requires_import]
             "#]],
         );
@@ -862,9 +862,9 @@ fn main() {
 "#,
             expect![[r#"
                 un Union Union [type_could_unify+requires_import]
+                md dep  []
                 fn main() fn() []
                 fn test(…) fn(Union) []
-                md dep  []
                 en Union Union [requires_import]
             "#]],
         );
@@ -900,9 +900,9 @@ fn main() {
                 ev dep::test_mod_b::Enum::variant dep::test_mod_b::Enum::variant [type_could_unify]
                 ex dep::test_mod_b::Enum::variant  [type_could_unify]
                 en Enum Enum [type_could_unify+requires_import]
+                md dep  []
                 fn main() fn() []
                 fn test(…) fn(Enum) []
-                md dep  []
                 en Enum Enum [requires_import]
             "#]],
         );
@@ -937,9 +937,9 @@ fn main() {
             expect![[r#"
                 ev dep::test_mod_b::Enum::Variant dep::test_mod_b::Enum::Variant [type_could_unify]
                 ex dep::test_mod_b::Enum::Variant  [type_could_unify]
+                md dep  []
                 fn main() fn() []
                 fn test(…) fn(Enum) []
-                md dep  []
             "#]],
         );
     }
@@ -967,9 +967,9 @@ fn main() {
 }
 "#,
             expect![[r#"
+                md dep  []
                 fn main() fn() []
                 fn test(…) fn(fn(usize) -> i32) []
-                md dep  []
                 fn function fn(usize) -> i32 [requires_import]
                 fn function(…) fn(isize) -> i32 [requires_import]
             "#]],
@@ -1000,9 +1000,9 @@ fn main() {
 "#,
             expect![[r#"
                 ct CONST i32 [type_could_unify+requires_import]
+                md dep  []
                 fn main() fn() []
                 fn test(…) fn(i32) []
-                md dep  []
                 ct CONST i64 [requires_import]
             "#]],
         );
@@ -1032,9 +1032,9 @@ fn main() {
 "#,
             expect![[r#"
                 sc STATIC i32 [type_could_unify+requires_import]
+                md dep  []
                 fn main() fn() []
                 fn test(…) fn(i32) []
-                md dep  []
                 sc STATIC i64 [requires_import]
             "#]],
         );
@@ -1090,8 +1090,8 @@ fn func(input: Struct) { }
 
 "#,
             expect![[r#"
-                st Struct Struct [type]
                 st Self Self [type]
+                st Struct Struct [type]
                 sp Self Struct [type]
                 st Struct Struct [type]
                 ex Struct  [type]
@@ -1119,9 +1119,9 @@ fn main() {
 "#,
             expect![[r#"
                 lc input bool [type+name+local]
+                ex false  [type]
                 ex input  [type]
                 ex true  [type]
-                ex false  [type]
                 lc inputbad i32 [local]
                 fn main() fn() []
                 fn test(…) fn(bool) []
@@ -2088,9 +2088,9 @@ fn f() { A { bar: b$0 }; }
 "#,
             expect![[r#"
                 fn bar() fn() -> u8 [type+name]
+                ex bar()  [type]
                 fn baz() fn() -> u8 [type]
                 ex baz()  [type]
-                ex bar()  [type]
                 st A A []
                 fn f() fn() []
             "#]],
@@ -2199,8 +2199,8 @@ fn main() {
                 lc s S [type+name+local]
                 st S S [type]
                 st S S [type]
-                ex s  [type]
                 ex S  [type]
+                ex s  [type]
                 fn foo(…) fn(&mut S) []
                 fn main() fn() []
             "#]],
@@ -2218,8 +2218,8 @@ fn main() {
                 st S S [type]
                 lc ssss S [type+local]
                 st S S [type]
-                ex ssss  [type]
                 ex S  [type]
+                ex ssss  [type]
                 fn foo(…) fn(&mut S) []
                 fn main() fn() []
             "#]],
@@ -2252,11 +2252,11 @@ fn main() {
                 ex Foo  [type]
                 lc foo &Foo [local]
                 lc *foo [type+local]
-                fn bar(…) fn(Foo) []
-                fn main() fn() []
-                md core  []
                 tt Clone  []
                 tt Copy  []
+                fn bar(…) fn(Foo) []
+                md core  []
+                fn main() fn() []
             "#]],
         );
     }
@@ -2297,9 +2297,9 @@ fn main() {
                 st &S [type]
                 st T T []
                 st &T [type]
+                md core  []
                 fn foo(…) fn(&S) []
                 fn main() fn() []
-                md core  []
             "#]],
         )
     }
@@ -2346,9 +2346,9 @@ fn main() {
                 st &mut S [type]
                 st T T []
                 st &mut T [type]
+                md core  []
                 fn foo(…) fn(&mut S) []
                 fn main() fn() []
-                md core  []
             "#]],
         )
     }
@@ -2364,8 +2364,8 @@ fn foo(bar: u32) {
 }
 "#,
             expect![[r#"
-                lc baz i32 [local]
                 lc bar u32 [local]
+                lc baz i32 [local]
                 fn foo(…) fn(u32) []
             "#]],
         );
@@ -2449,9 +2449,9 @@ fn main() {
                 st &T [type]
                 fn bar() fn() -> T []
                 fn &bar() [type]
+                md core  []
                 fn foo(…) fn(&S) []
                 fn main() fn() []
-                md core  []
             "#]],
         )
     }
@@ -2702,8 +2702,8 @@ fn test() {
                 fn fn_builder() fn() -> FooBuilder [type_could_unify]
                 fn fn_ctr_wrapped() fn() -> Option<Foo<T>> [type_could_unify]
                 fn fn_ctr_wrapped_2() fn() -> Result<Foo<T>, u32> [type_could_unify]
-                me fn_returns_unit(…) fn(&self) [type_could_unify]
                 fn fn_other() fn() -> Option<u32> [type_could_unify]
+                me fn_returns_unit(…) fn(&self) [type_could_unify]
             "#]],
         );
     }
@@ -2965,12 +2965,12 @@ fn foo() {
                 ev Foo::B Foo::B [type_could_unify]
                 ev Foo::A(…) Foo::A(T) [type_could_unify]
                 lc foo Foo<u32> [type+local]
-                ex foo  [type]
                 ex Foo::B  [type]
+                ex foo  [type]
                 en Foo Foo<{unknown}> [type_could_unify]
-                fn foo() fn() []
                 fn bar() fn() -> Foo<u8> []
                 fn baz() fn() -> Foo<T> []
+                fn foo() fn() []
             "#]],
         );
     }
@@ -3000,19 +3000,19 @@ fn main() {
             expect![[r#"
                 sn not !expr [snippet]
                 me not() fn(self) -> <Self as Not>::Output [type_could_unify+requires_import]
-                sn if if expr {} []
-                sn while while expr {} []
-                sn ref &expr []
-                sn refm &mut expr []
-                sn deref *expr []
-                sn unsafe unsafe {} []
-                sn const const {} []
-                sn match match expr {} []
                 sn box Box::new(expr) []
+                sn call function(expr) []
+                sn const const {} []
                 sn dbg dbg!(expr) []
                 sn dbgr dbg!(&expr) []
-                sn call function(expr) []
+                sn deref *expr []
+                sn if if expr {} []
+                sn match match expr {} []
+                sn ref &expr []
+                sn refm &mut expr []
                 sn return return expr []
+                sn unsafe unsafe {} []
+                sn while while expr {} []
             "#]],
         );
     }
@@ -3033,19 +3033,19 @@ fn main() {
             &[CompletionItemKind::Snippet, CompletionItemKind::SymbolKind(SymbolKind::Method)],
             expect![[r#"
                 me f() fn(&self) []
-                sn ref &expr []
-                sn refm &mut expr []
-                sn deref *expr []
-                sn unsafe unsafe {} []
-                sn const const {} []
-                sn match match expr {} []
                 sn box Box::new(expr) []
+                sn call function(expr) []
+                sn const const {} []
                 sn dbg dbg!(expr) []
                 sn dbgr dbg!(&expr) []
-                sn call function(expr) []
+                sn deref *expr []
                 sn let let []
                 sn letm let mut []
+                sn match match expr {} []
+                sn ref &expr []
+                sn refm &mut expr []
                 sn return return expr []
+                sn unsafe unsafe {} []
             "#]],
         );
     }
diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/render/function.rs b/src/tools/rust-analyzer/crates/ide-completion/src/render/function.rs
index 2fe517fa8cd..7669aec8f53 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
@@ -22,13 +22,13 @@ use crate::{
 
 #[derive(Debug)]
 enum FuncKind<'ctx> {
-    Function(&'ctx PathCompletionCtx),
-    Method(&'ctx DotAccess, Option<SmolStr>),
+    Function(&'ctx PathCompletionCtx<'ctx>),
+    Method(&'ctx DotAccess<'ctx>, Option<SmolStr>),
 }
 
 pub(crate) fn render_fn(
     ctx: RenderContext<'_>,
-    path_ctx: &PathCompletionCtx,
+    path_ctx: &PathCompletionCtx<'_>,
     local_name: Option<hir::Name>,
     func: hir::Function,
 ) -> Builder {
@@ -38,7 +38,7 @@ pub(crate) fn render_fn(
 
 pub(crate) fn render_method(
     ctx: RenderContext<'_>,
-    dot_access: &DotAccess,
+    dot_access: &DotAccess<'_>,
     receiver: Option<SmolStr>,
     local_name: Option<hir::Name>,
     func: hir::Function,
@@ -186,8 +186,8 @@ fn render(
 fn compute_return_type_match(
     db: &dyn HirDatabase,
     ctx: &RenderContext<'_>,
-    self_type: hir::Type,
-    ret_type: &hir::Type,
+    self_type: hir::Type<'_>,
+    ret_type: &hir::Type<'_>,
 ) -> CompletionRelevanceReturnType {
     if match_types(ctx.completion, &self_type, ret_type).is_some() {
         // fn([..]) -> Self
@@ -217,8 +217,8 @@ pub(super) fn add_call_parens<'b>(
     name: SmolStr,
     escaped_name: SmolStr,
     self_param: Option<hir::SelfParam>,
-    params: Vec<hir::Param>,
-    ret_type: &hir::Type,
+    params: Vec<hir::Param<'_>>,
+    ret_type: &hir::Type<'_>,
 ) -> &'b mut Builder {
     cov_mark::hit!(inserts_parens_for_function_calls);
 
@@ -288,7 +288,7 @@ pub(super) fn add_call_parens<'b>(
     builder.label(SmolStr::from_iter([&name, label_suffix])).insert_snippet(cap, snippet)
 }
 
-fn ref_of_param(ctx: &CompletionContext<'_>, arg: &str, ty: &hir::Type) -> &'static str {
+fn ref_of_param(ctx: &CompletionContext<'_>, arg: &str, ty: &hir::Type<'_>) -> &'static str {
     if let Some(derefed_ty) = ty.remove_ref() {
         for (name, local) in ctx.locals.iter().sorted_by_key(|&(k, _)| k.clone()) {
             if name.as_str() == arg {
@@ -369,12 +369,12 @@ fn params_display(ctx: &CompletionContext<'_>, detail: &mut String, func: hir::F
     }
 }
 
-fn params(
-    ctx: &CompletionContext<'_>,
+fn params<'db>(
+    ctx: &CompletionContext<'db>,
     func: hir::Function,
     func_kind: &FuncKind<'_>,
     has_dot_receiver: bool,
-) -> Option<(Option<hir::SelfParam>, Vec<hir::Param>)> {
+) -> Option<(Option<hir::SelfParam>, Vec<hir::Param<'db>>)> {
     ctx.config.callable.as_ref()?;
 
     // Don't add parentheses if the expected type is a function reference with the same signature.
diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/render/literal.rs b/src/tools/rust-analyzer/crates/ide-completion/src/render/literal.rs
index 5a9e35a7290..6c89e49f94e 100644
--- a/src/tools/rust-analyzer/crates/ide-completion/src/render/literal.rs
+++ b/src/tools/rust-analyzer/crates/ide-completion/src/render/literal.rs
@@ -21,7 +21,7 @@ use crate::{
 
 pub(crate) fn render_variant_lit(
     ctx: RenderContext<'_>,
-    path_ctx: &PathCompletionCtx,
+    path_ctx: &PathCompletionCtx<'_>,
     local_name: Option<hir::Name>,
     variant: hir::Variant,
     path: Option<hir::ModPath>,
@@ -35,7 +35,7 @@ pub(crate) fn render_variant_lit(
 
 pub(crate) fn render_struct_literal(
     ctx: RenderContext<'_>,
-    path_ctx: &PathCompletionCtx,
+    path_ctx: &PathCompletionCtx<'_>,
     strukt: hir::Struct,
     path: Option<hir::ModPath>,
     local_name: Option<hir::Name>,
@@ -49,7 +49,7 @@ pub(crate) fn render_struct_literal(
 
 fn render(
     ctx @ RenderContext { completion, .. }: RenderContext<'_>,
-    path_ctx: &PathCompletionCtx,
+    path_ctx: &PathCompletionCtx<'_>,
     thing: Variant,
     name: hir::Name,
     path: Option<hir::ModPath>,
@@ -194,7 +194,7 @@ impl Variant {
         }
     }
 
-    fn ty(self, db: &dyn HirDatabase) -> hir::Type {
+    fn ty(self, db: &dyn HirDatabase) -> hir::Type<'_> {
         match self {
             Variant::Struct(it) => it.ty(db),
             Variant::EnumVariant(it) => it.parent_enum(db).ty(db),
diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/render/macro_.rs b/src/tools/rust-analyzer/crates/ide-completion/src/render/macro_.rs
index 4674dae0314..35fe407b2e6 100644
--- a/src/tools/rust-analyzer/crates/ide-completion/src/render/macro_.rs
+++ b/src/tools/rust-analyzer/crates/ide-completion/src/render/macro_.rs
@@ -12,7 +12,7 @@ use crate::{
 
 pub(crate) fn render_macro(
     ctx: RenderContext<'_>,
-    PathCompletionCtx { kind, has_macro_bang, has_call_parens, .. }: &PathCompletionCtx,
+    PathCompletionCtx { kind, has_macro_bang, has_call_parens, .. }: &PathCompletionCtx<'_>,
 
     name: hir::Name,
     macro_: hir::Macro,
diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/render/pattern.rs b/src/tools/rust-analyzer/crates/ide-completion/src/render/pattern.rs
index dcc51a86a8e..60ec1128233 100644
--- a/src/tools/rust-analyzer/crates/ide-completion/src/render/pattern.rs
+++ b/src/tools/rust-analyzer/crates/ide-completion/src/render/pattern.rs
@@ -46,7 +46,7 @@ pub(crate) fn render_struct_pat(
 pub(crate) fn render_variant_pat(
     ctx: RenderContext<'_>,
     pattern_ctx: &PatternContext,
-    path_ctx: Option<&PathCompletionCtx>,
+    path_ctx: Option<&PathCompletionCtx<'_>>,
     variant: hir::Variant,
     local_name: Option<Name>,
     path: Option<&hir::ModPath>,
@@ -109,7 +109,7 @@ fn build_completion(
     lookup: SmolStr,
     pat: String,
     def: impl HasDocs + Copy,
-    adt_ty: hir::Type,
+    adt_ty: hir::Type<'_>,
     // Missing in context of match statement completions
     is_variant_missing: bool,
 ) -> CompletionItem {
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 b46e4c32061..b2d18b796f1 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
@@ -1474,20 +1474,18 @@ fn main() {
 }
 "#,
         expect![[r#"
+            me foo()     fn(&self)
             sn box  Box::new(expr)
             sn call function(expr)
             sn const      const {}
             sn dbg      dbg!(expr)
             sn dbgr    dbg!(&expr)
             sn deref         *expr
-            sn if       if expr {}
             sn match match expr {}
-            sn not           !expr
             sn ref           &expr
             sn refm      &mut expr
             sn return  return expr
             sn unsafe    unsafe {}
-            sn while while expr {}
         "#]],
     );
 }
diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/tests/visibility.rs b/src/tools/rust-analyzer/crates/ide-completion/src/tests/visibility.rs
index 4b5a0ac1c2b..b404011dfe6 100644
--- a/src/tools/rust-analyzer/crates/ide-completion/src/tests/visibility.rs
+++ b/src/tools/rust-analyzer/crates/ide-completion/src/tests/visibility.rs
@@ -1,7 +1,7 @@
 //! Completion tests for visibility modifiers.
 use expect_test::expect;
 
-use crate::tests::{check, check_with_trigger_character};
+use crate::tests::{check, check_with_private_editable, check_with_trigger_character};
 
 #[test]
 fn empty_pub() {
@@ -78,3 +78,90 @@ mod bar {}
         "#]],
     );
 }
+
+#[test]
+fn use_inner_public_function() {
+    check(
+        r#"
+//- /inner.rs crate:inner
+pub fn inner_public() {}
+fn inner_private() {}
+//- /foo.rs crate:foo deps:inner
+use inner::inner_public;
+pub fn outer_public() {}
+//- /lib.rs crate:lib deps:foo
+fn x() {
+    foo::$0
+}
+        "#,
+        expect![[r#"
+            fn outer_public() fn()
+        "#]],
+    );
+}
+
+#[test]
+fn pub_use_inner_public_function() {
+    check(
+        r#"
+//- /inner.rs crate:inner
+pub fn inner_public() {}
+fn inner_private() {}
+//- /foo.rs crate:foo deps:inner
+pub use inner::inner_public;
+pub fn outer_public() {}
+//- /lib.rs crate:lib deps:foo
+fn x() {
+    foo::$0
+}
+        "#,
+        expect![[r#"
+            fn inner_public() fn()
+            fn outer_public() fn()
+        "#]],
+    );
+}
+
+#[test]
+fn use_inner_public_function_private_editable() {
+    check_with_private_editable(
+        r#"
+//- /inner.rs crate:inner
+pub fn inner_public() {}
+fn inner_private() {}
+//- /foo.rs crate:foo deps:inner
+use inner::inner_public;
+pub fn outer_public() {}
+//- /lib.rs crate:lib deps:foo
+fn x() {
+    foo::$0
+}
+        "#,
+        expect![[r#"
+            fn inner_public() fn()
+            fn outer_public() fn()
+        "#]],
+    );
+}
+
+#[test]
+fn pub_use_inner_public_function_private_editable() {
+    check_with_private_editable(
+        r#"
+//- /inner.rs crate:inner
+pub fn inner_public() {}
+fn inner_private() {}
+//- /foo.rs crate:foo deps:inner
+pub use inner::inner_public;
+pub fn outer_public() {}
+//- /lib.rs crate:lib deps:foo
+fn x() {
+    foo::$0
+}
+        "#,
+        expect![[r#"
+            fn inner_public() fn()
+            fn outer_public() fn()
+        "#]],
+    );
+}
diff --git a/src/tools/rust-analyzer/crates/ide-db/src/active_parameter.rs b/src/tools/rust-analyzer/crates/ide-db/src/active_parameter.rs
index 7b5723f37f7..9edfc113f76 100644
--- a/src/tools/rust-analyzer/crates/ide-db/src/active_parameter.rs
+++ b/src/tools/rust-analyzer/crates/ide-db/src/active_parameter.rs
@@ -13,21 +13,21 @@ use syntax::{
 use crate::RootDatabase;
 
 #[derive(Debug)]
-pub struct ActiveParameter {
-    pub ty: Type,
+pub struct ActiveParameter<'db> {
+    pub ty: Type<'db>,
     pub src: Option<InFile<Either<ast::SelfParam, ast::Param>>>,
 }
 
-impl ActiveParameter {
+impl<'db> ActiveParameter<'db> {
     /// Returns information about the call argument this token is part of.
-    pub fn at_token(sema: &Semantics<'_, RootDatabase>, token: SyntaxToken) -> Option<Self> {
+    pub fn at_token(sema: &Semantics<'db, RootDatabase>, token: SyntaxToken) -> Option<Self> {
         let (signature, active_parameter) = callable_for_token(sema, token)?;
         Self::from_signature_and_active_parameter(sema, signature, active_parameter)
     }
 
     /// Returns information about the call argument this token is part of.
     pub fn at_arg(
-        sema: &Semantics<'_, RootDatabase>,
+        sema: &'db Semantics<'db, RootDatabase>,
         list: ast::ArgList,
         at: TextSize,
     ) -> Option<Self> {
@@ -36,8 +36,8 @@ impl ActiveParameter {
     }
 
     fn from_signature_and_active_parameter(
-        sema: &Semantics<'_, RootDatabase>,
-        signature: hir::Callable,
+        sema: &Semantics<'db, RootDatabase>,
+        signature: hir::Callable<'db>,
         active_parameter: Option<usize>,
     ) -> Option<Self> {
         let idx = active_parameter?;
@@ -63,10 +63,10 @@ impl ActiveParameter {
 }
 
 /// Returns a [`hir::Callable`] this token is a part of and its argument index of said callable.
-pub fn callable_for_token(
-    sema: &Semantics<'_, RootDatabase>,
+pub fn callable_for_token<'db>(
+    sema: &Semantics<'db, RootDatabase>,
     token: SyntaxToken,
-) -> Option<(hir::Callable, Option<usize>)> {
+) -> Option<(hir::Callable<'db>, Option<usize>)> {
     let offset = token.text_range().start();
     // Find the calling expression and its NameRef
     let parent = token.parent()?;
@@ -79,21 +79,21 @@ pub fn callable_for_token(
 }
 
 /// Returns a [`hir::Callable`] this token is a part of and its argument index of said callable.
-pub fn callable_for_arg_list(
-    sema: &Semantics<'_, RootDatabase>,
+pub fn callable_for_arg_list<'db>(
+    sema: &Semantics<'db, RootDatabase>,
     arg_list: ast::ArgList,
     at: TextSize,
-) -> Option<(hir::Callable, Option<usize>)> {
+) -> Option<(hir::Callable<'db>, Option<usize>)> {
     debug_assert!(arg_list.syntax().text_range().contains(at));
     let callable = arg_list.syntax().parent().and_then(ast::CallableExpr::cast)?;
     callable_for_node(sema, &callable, at)
 }
 
-pub fn callable_for_node(
-    sema: &Semantics<'_, RootDatabase>,
+pub fn callable_for_node<'db>(
+    sema: &Semantics<'db, RootDatabase>,
     calling_node: &ast::CallableExpr,
     offset: TextSize,
-) -> Option<(hir::Callable, Option<usize>)> {
+) -> Option<(hir::Callable<'db>, Option<usize>)> {
     let callable = match calling_node {
         ast::CallableExpr::Call(call) => sema.resolve_expr_as_callable(&call.expr()?),
         ast::CallableExpr::MethodCall(call) => sema.resolve_method_call_as_callable(call),
diff --git a/src/tools/rust-analyzer/crates/ide-db/src/defs.rs b/src/tools/rust-analyzer/crates/ide-db/src/defs.rs
index d5db1c481b6..a4a140ec57a 100644
--- a/src/tools/rust-analyzer/crates/ide-db/src/defs.rs
+++ b/src/tools/rust-analyzer/crates/ide-db/src/defs.rs
@@ -385,17 +385,17 @@ fn find_std_module(
 
 // FIXME: IdentClass as a name no longer fits
 #[derive(Debug)]
-pub enum IdentClass {
-    NameClass(NameClass),
-    NameRefClass(NameRefClass),
+pub enum IdentClass<'db> {
+    NameClass(NameClass<'db>),
+    NameRefClass(NameRefClass<'db>),
     Operator(OperatorClass),
 }
 
-impl IdentClass {
+impl<'db> IdentClass<'db> {
     pub fn classify_node(
-        sema: &Semantics<'_, RootDatabase>,
+        sema: &Semantics<'db, RootDatabase>,
         node: &SyntaxNode,
-    ) -> Option<IdentClass> {
+    ) -> Option<IdentClass<'db>> {
         match_ast! {
             match node {
                 ast::Name(name) => NameClass::classify(sema, &name).map(IdentClass::NameClass),
@@ -418,23 +418,23 @@ impl IdentClass {
     }
 
     pub fn classify_token(
-        sema: &Semantics<'_, RootDatabase>,
+        sema: &Semantics<'db, RootDatabase>,
         token: &SyntaxToken,
-    ) -> Option<IdentClass> {
+    ) -> Option<IdentClass<'db>> {
         let parent = token.parent()?;
         Self::classify_node(sema, &parent)
     }
 
     pub fn classify_lifetime(
-        sema: &Semantics<'_, RootDatabase>,
+        sema: &Semantics<'db, RootDatabase>,
         lifetime: &ast::Lifetime,
-    ) -> Option<IdentClass> {
+    ) -> Option<IdentClass<'db>> {
         NameRefClass::classify_lifetime(sema, lifetime)
             .map(IdentClass::NameRefClass)
             .or_else(|| NameClass::classify_lifetime(sema, lifetime).map(IdentClass::NameClass))
     }
 
-    pub fn definitions(self) -> ArrayVec<(Definition, Option<GenericSubstitution>), 2> {
+    pub fn definitions(self) -> ArrayVec<(Definition, Option<GenericSubstitution<'db>>), 2> {
         let mut res = ArrayVec::new();
         match self {
             IdentClass::NameClass(NameClass::Definition(it) | NameClass::ConstReference(it)) => {
@@ -518,7 +518,7 @@ impl IdentClass {
 ///
 /// A model special case is `None` constant in pattern.
 #[derive(Debug)]
-pub enum NameClass {
+pub enum NameClass<'db> {
     Definition(Definition),
     /// `None` in `if let None = Some(82) {}`.
     /// Syntactically, it is a name, but semantically it is a reference.
@@ -528,11 +528,11 @@ pub enum NameClass {
     PatFieldShorthand {
         local_def: Local,
         field_ref: Field,
-        adt_subst: GenericSubstitution,
+        adt_subst: GenericSubstitution<'db>,
     },
 }
 
-impl NameClass {
+impl<'db> NameClass<'db> {
     /// `Definition` defined by this name.
     pub fn defined(self) -> Option<Definition> {
         let res = match self {
@@ -545,7 +545,10 @@ impl NameClass {
         Some(res)
     }
 
-    pub fn classify(sema: &Semantics<'_, RootDatabase>, name: &ast::Name) -> Option<NameClass> {
+    pub fn classify(
+        sema: &Semantics<'db, RootDatabase>,
+        name: &ast::Name,
+    ) -> Option<NameClass<'db>> {
         let _p = tracing::info_span!("NameClass::classify").entered();
 
         let parent = name.syntax().parent()?;
@@ -597,10 +600,10 @@ impl NameClass {
             Some(definition)
         }
 
-        fn classify_ident_pat(
-            sema: &Semantics<'_, RootDatabase>,
+        fn classify_ident_pat<'db>(
+            sema: &Semantics<'db, RootDatabase>,
             ident_pat: ast::IdentPat,
-        ) -> Option<NameClass> {
+        ) -> Option<NameClass<'db>> {
             if let Some(def) = sema.resolve_bind_pat_to_const(&ident_pat) {
                 return Some(NameClass::ConstReference(Definition::from(def)));
             }
@@ -638,9 +641,9 @@ impl NameClass {
     }
 
     pub fn classify_lifetime(
-        sema: &Semantics<'_, RootDatabase>,
+        sema: &Semantics<'db, RootDatabase>,
         lifetime: &ast::Lifetime,
-    ) -> Option<NameClass> {
+    ) -> Option<NameClass<'db>> {
         let _p = tracing::info_span!("NameClass::classify_lifetime", ?lifetime).entered();
         let parent = lifetime.syntax().parent()?;
 
@@ -723,12 +726,12 @@ impl OperatorClass {
 /// A model special case is field shorthand syntax, which uses a single
 /// reference to point to two different defs.
 #[derive(Debug)]
-pub enum NameRefClass {
-    Definition(Definition, Option<GenericSubstitution>),
+pub enum NameRefClass<'db> {
+    Definition(Definition, Option<GenericSubstitution<'db>>),
     FieldShorthand {
         local_ref: Local,
         field_ref: Field,
-        adt_subst: GenericSubstitution,
+        adt_subst: GenericSubstitution<'db>,
     },
     /// The specific situation where we have an extern crate decl without a rename
     /// Here we have both a declaration and a reference.
@@ -741,13 +744,13 @@ pub enum NameRefClass {
     },
 }
 
-impl NameRefClass {
+impl<'db> NameRefClass<'db> {
     // Note: we don't have unit-tests for this rather important function.
     // It is primarily exercised via goto definition tests in `ide`.
     pub fn classify(
-        sema: &Semantics<'_, RootDatabase>,
+        sema: &Semantics<'db, RootDatabase>,
         name_ref: &ast::NameRef,
-    ) -> Option<NameRefClass> {
+    ) -> Option<NameRefClass<'db>> {
         let _p = tracing::info_span!("NameRefClass::classify", ?name_ref).entered();
 
         let parent = name_ref.syntax().parent()?;
@@ -866,9 +869,9 @@ impl NameRefClass {
     }
 
     pub fn classify_lifetime(
-        sema: &Semantics<'_, RootDatabase>,
+        sema: &Semantics<'db, RootDatabase>,
         lifetime: &ast::Lifetime,
-    ) -> Option<NameRefClass> {
+    ) -> Option<NameRefClass<'db>> {
         let _p = tracing::info_span!("NameRefClass::classify_lifetime", ?lifetime).entered();
         if lifetime.text() == "'static" {
             return Some(NameRefClass::Definition(
diff --git a/src/tools/rust-analyzer/crates/ide-db/src/imports/import_assets.rs b/src/tools/rust-analyzer/crates/ide-db/src/imports/import_assets.rs
index ac592dfe93c..9f35988924b 100644
--- a/src/tools/rust-analyzer/crates/ide-db/src/imports/import_assets.rs
+++ b/src/tools/rust-analyzer/crates/ide-db/src/imports/import_assets.rs
@@ -25,26 +25,26 @@ use crate::{
 /// * assists
 /// * etc.
 #[derive(Debug)]
-pub enum ImportCandidate {
+pub enum ImportCandidate<'db> {
     /// A path, qualified (`std::collections::HashMap`) or not (`HashMap`).
     Path(PathImportCandidate),
     /// A trait associated function (with no self parameter) or an associated constant.
     /// For 'test_mod::TestEnum::test_function', `ty` is the `test_mod::TestEnum` expression type
     /// and `name` is the `test_function`
-    TraitAssocItem(TraitImportCandidate),
+    TraitAssocItem(TraitImportCandidate<'db>),
     /// A trait method with self parameter.
     /// For 'test_enum.test_method()', `ty` is the `test_enum` expression type
     /// and `name` is the `test_method`
-    TraitMethod(TraitImportCandidate),
+    TraitMethod(TraitImportCandidate<'db>),
 }
 
 /// A trait import needed for a given associated item access.
 /// For `some::path::SomeStruct::ASSOC_`, contains the
 /// type of `some::path::SomeStruct` and `ASSOC_` as the item name.
 #[derive(Debug)]
-pub struct TraitImportCandidate {
+pub struct TraitImportCandidate<'db> {
     /// A type of the item that has the associated item accessed at.
-    pub receiver_ty: Type,
+    pub receiver_ty: Type<'db>,
     /// The associated item name that the trait to import should contain.
     pub assoc_item_name: NameToImport,
 }
@@ -100,16 +100,16 @@ impl NameToImport {
 
 /// A struct to find imports in the project, given a certain name (or its part) and the context.
 #[derive(Debug)]
-pub struct ImportAssets {
-    import_candidate: ImportCandidate,
+pub struct ImportAssets<'db> {
+    import_candidate: ImportCandidate<'db>,
     candidate_node: SyntaxNode,
     module_with_candidate: Module,
 }
 
-impl ImportAssets {
+impl<'db> ImportAssets<'db> {
     pub fn for_method_call(
         method_call: &ast::MethodCallExpr,
-        sema: &Semantics<'_, RootDatabase>,
+        sema: &Semantics<'db, RootDatabase>,
     ) -> Option<Self> {
         let candidate_node = method_call.syntax().clone();
         Some(Self {
@@ -121,7 +121,7 @@ impl ImportAssets {
 
     pub fn for_exact_path(
         fully_qualified_path: &ast::Path,
-        sema: &Semantics<'_, RootDatabase>,
+        sema: &Semantics<'db, RootDatabase>,
     ) -> Option<Self> {
         let candidate_node = fully_qualified_path.syntax().clone();
         if let Some(use_tree) = candidate_node.ancestors().find_map(ast::UseTree::cast) {
@@ -139,7 +139,7 @@ impl ImportAssets {
         })
     }
 
-    pub fn for_ident_pat(sema: &Semantics<'_, RootDatabase>, pat: &ast::IdentPat) -> Option<Self> {
+    pub fn for_ident_pat(sema: &Semantics<'db, RootDatabase>, pat: &ast::IdentPat) -> Option<Self> {
         if !pat.is_simple_ident() {
             return None;
         }
@@ -156,7 +156,7 @@ impl ImportAssets {
         module_with_candidate: Module,
         qualifier: Option<ast::Path>,
         fuzzy_name: String,
-        sema: &Semantics<'_, RootDatabase>,
+        sema: &Semantics<'db, RootDatabase>,
         candidate_node: SyntaxNode,
     ) -> Option<Self> {
         Some(Self {
@@ -168,7 +168,7 @@ impl ImportAssets {
 
     pub fn for_fuzzy_method_call(
         module_with_method_call: Module,
-        receiver_ty: Type,
+        receiver_ty: Type<'db>,
         fuzzy_method_name: String,
         candidate_node: SyntaxNode,
     ) -> Option<Self> {
@@ -229,14 +229,14 @@ impl LocatedImport {
     }
 }
 
-impl ImportAssets {
-    pub fn import_candidate(&self) -> &ImportCandidate {
+impl<'db> ImportAssets<'db> {
+    pub fn import_candidate(&self) -> &ImportCandidate<'db> {
         &self.import_candidate
     }
 
     pub fn search_for_imports(
         &self,
-        sema: &Semantics<'_, RootDatabase>,
+        sema: &Semantics<'db, RootDatabase>,
         cfg: ImportPathConfig,
         prefix_kind: PrefixKind,
     ) -> impl Iterator<Item = LocatedImport> {
@@ -247,7 +247,7 @@ impl ImportAssets {
     /// This may return non-absolute paths if a part of the returned path is already imported into scope.
     pub fn search_for_relative_paths(
         &self,
-        sema: &Semantics<'_, RootDatabase>,
+        sema: &Semantics<'db, RootDatabase>,
         cfg: ImportPathConfig,
     ) -> impl Iterator<Item = LocatedImport> {
         let _p = tracing::info_span!("ImportAssets::search_for_relative_paths").entered();
@@ -286,7 +286,7 @@ impl ImportAssets {
 
     fn search_for(
         &self,
-        sema: &Semantics<'_, RootDatabase>,
+        sema: &Semantics<'db, RootDatabase>,
         prefixed: Option<PrefixKind>,
         cfg: ImportPathConfig,
     ) -> impl Iterator<Item = LocatedImport> {
@@ -533,11 +533,11 @@ fn item_for_path_search_assoc(db: &RootDatabase, assoc_item: AssocItem) -> Optio
     })
 }
 
-fn trait_applicable_items(
-    db: &RootDatabase,
+fn trait_applicable_items<'db>(
+    db: &'db RootDatabase,
     current_crate: Crate,
-    scope: &SemanticsScope<'_>,
-    trait_candidate: &TraitImportCandidate,
+    scope: &SemanticsScope<'db>,
+    trait_candidate: &TraitImportCandidate<'db>,
     trait_assoc_item: bool,
     mod_path: impl Fn(ItemInNs) -> Option<ModPath>,
     scope_filter: impl Fn(hir::Trait) -> bool,
@@ -709,9 +709,9 @@ fn get_mod_path(
     }
 }
 
-impl ImportCandidate {
+impl<'db> ImportCandidate<'db> {
     fn for_method_call(
-        sema: &Semantics<'_, RootDatabase>,
+        sema: &Semantics<'db, RootDatabase>,
         method_call: &ast::MethodCallExpr,
     ) -> Option<Self> {
         match sema.resolve_method_call(method_call) {
@@ -725,7 +725,7 @@ impl ImportCandidate {
         }
     }
 
-    fn for_regular_path(sema: &Semantics<'_, RootDatabase>, path: &ast::Path) -> Option<Self> {
+    fn for_regular_path(sema: &Semantics<'db, RootDatabase>, path: &ast::Path) -> Option<Self> {
         if sema.resolve_path(path).is_some() {
             return None;
         }
@@ -736,7 +736,7 @@ impl ImportCandidate {
         )
     }
 
-    fn for_name(sema: &Semantics<'_, RootDatabase>, name: &ast::Name) -> Option<Self> {
+    fn for_name(sema: &Semantics<'db, RootDatabase>, name: &ast::Name) -> Option<Self> {
         if sema
             .scope(name.syntax())?
             .speculative_resolve(&make::ext::ident_path(&name.text()))
@@ -753,17 +753,17 @@ impl ImportCandidate {
     fn for_fuzzy_path(
         qualifier: Option<ast::Path>,
         fuzzy_name: String,
-        sema: &Semantics<'_, RootDatabase>,
+        sema: &Semantics<'db, RootDatabase>,
     ) -> Option<Self> {
         path_import_candidate(sema, qualifier, NameToImport::fuzzy(fuzzy_name))
     }
 }
 
-fn path_import_candidate(
-    sema: &Semantics<'_, RootDatabase>,
+fn path_import_candidate<'db>(
+    sema: &Semantics<'db, RootDatabase>,
     qualifier: Option<ast::Path>,
     name: NameToImport,
-) -> Option<ImportCandidate> {
+) -> Option<ImportCandidate<'db>> {
     Some(match qualifier {
         Some(qualifier) => match sema.resolve_path(&qualifier) {
             Some(PathResolution::Def(ModuleDef::BuiltinType(_))) | None => {
diff --git a/src/tools/rust-analyzer/crates/ide-db/src/search.rs b/src/tools/rust-analyzer/crates/ide-db/src/search.rs
index c5ad64ed594..7d460f72492 100644
--- a/src/tools/rust-analyzer/crates/ide-db/src/search.rs
+++ b/src/tools/rust-analyzer/crates/ide-db/src/search.rs
@@ -429,7 +429,7 @@ pub struct FindUsages<'a> {
     /// The container of our definition should it be an assoc item
     assoc_item_container: Option<hir::AssocItemContainer>,
     /// whether to search for the `Self` type of the definition
-    include_self_kw_refs: Option<hir::Type>,
+    include_self_kw_refs: Option<hir::Type<'a>>,
     /// whether to search for the `self` module
     search_self_mod: bool,
 }
@@ -1087,12 +1087,12 @@ impl<'a> FindUsages<'a> {
 
     fn found_self_ty_name_ref(
         &self,
-        self_ty: &hir::Type,
+        self_ty: &hir::Type<'_>,
         name_ref: &ast::NameRef,
         sink: &mut dyn FnMut(EditionedFileId, FileReference) -> bool,
     ) -> bool {
         // See https://github.com/rust-lang/rust-analyzer/pull/15864/files/e0276dc5ddc38c65240edb408522bb869f15afb4#r1389848845
-        let ty_eq = |ty: hir::Type| match (ty.as_adt(), self_ty.as_adt()) {
+        let ty_eq = |ty: hir::Type<'_>| match (ty.as_adt(), self_ty.as_adt()) {
             (Some(ty), Some(self_ty)) => ty == self_ty,
             (None, None) => ty == *self_ty,
             _ => false,
@@ -1315,7 +1315,7 @@ impl<'a> FindUsages<'a> {
     }
 }
 
-fn def_to_ty(sema: &Semantics<'_, RootDatabase>, def: &Definition) -> Option<hir::Type> {
+fn def_to_ty<'db>(sema: &Semantics<'db, RootDatabase>, def: &Definition) -> Option<hir::Type<'db>> {
     match def {
         Definition::Adt(adt) => Some(adt.ty(sema.db)),
         Definition::TypeAlias(it) => Some(it.ty(sema.db)),
diff --git a/src/tools/rust-analyzer/crates/ide-db/src/syntax_helpers/suggest_name.rs b/src/tools/rust-analyzer/crates/ide-db/src/syntax_helpers/suggest_name.rs
index 9b9f450bc73..995bf72dca1 100644
--- a/src/tools/rust-analyzer/crates/ide-db/src/syntax_helpers/suggest_name.rs
+++ b/src/tools/rust-analyzer/crates/ide-db/src/syntax_helpers/suggest_name.rs
@@ -151,10 +151,10 @@ impl NameGenerator {
     /// - If `ty` is an `impl Trait`, it will suggest the name of the first trait.
     ///
     /// If the suggested name conflicts with reserved keywords, it will return `None`.
-    pub fn for_type(
+    pub fn for_type<'db>(
         &mut self,
-        ty: &hir::Type,
-        db: &RootDatabase,
+        ty: &hir::Type<'db>,
+        db: &'db RootDatabase,
         edition: Edition,
     ) -> Option<SmolStr> {
         let name = name_of_type(ty, db, edition)?;
@@ -373,7 +373,11 @@ fn from_type(expr: &ast::Expr, sema: &Semantics<'_, RootDatabase>) -> Option<Smo
     name_of_type(&ty, sema.db, edition)
 }
 
-fn name_of_type(ty: &hir::Type, db: &RootDatabase, edition: Edition) -> Option<SmolStr> {
+fn name_of_type<'db>(
+    ty: &hir::Type<'db>,
+    db: &'db RootDatabase,
+    edition: Edition,
+) -> Option<SmolStr> {
     let name = if let Some(adt) = ty.as_adt() {
         let name = adt.name(db).display(db, edition).to_string();
 
@@ -407,7 +411,11 @@ fn name_of_type(ty: &hir::Type, db: &RootDatabase, edition: Edition) -> Option<S
     normalize(&name)
 }
 
-fn sequence_name(inner_ty: Option<&hir::Type>, db: &RootDatabase, edition: Edition) -> SmolStr {
+fn sequence_name<'db>(
+    inner_ty: Option<&hir::Type<'db>>,
+    db: &'db RootDatabase,
+    edition: Edition,
+) -> SmolStr {
     let items_str = SmolStr::new_static("items");
     let Some(inner_ty) = inner_ty else {
         return items_str;
diff --git a/src/tools/rust-analyzer/crates/ide-db/src/ty_filter.rs b/src/tools/rust-analyzer/crates/ide-db/src/ty_filter.rs
index 63ce0ddbb8f..095256d8294 100644
--- a/src/tools/rust-analyzer/crates/ide-db/src/ty_filter.rs
+++ b/src/tools/rust-analyzer/crates/ide-db/src/ty_filter.rs
@@ -10,7 +10,7 @@ use syntax::ast::{self, Pat, make};
 use crate::RootDatabase;
 
 /// Enum types that implement `std::ops::Try` trait.
-#[derive(Clone, Copy)]
+#[derive(Clone, Copy, Debug)]
 pub enum TryEnum {
     Result,
     Option,
@@ -20,7 +20,7 @@ impl TryEnum {
     const ALL: [TryEnum; 2] = [TryEnum::Option, TryEnum::Result];
 
     /// Returns `Some(..)` if the provided type is an enum that implements `std::ops::Try`.
-    pub fn from_ty(sema: &Semantics<'_, RootDatabase>, ty: &hir::Type) -> Option<TryEnum> {
+    pub fn from_ty(sema: &Semantics<'_, RootDatabase>, ty: &hir::Type<'_>) -> Option<TryEnum> {
         let enum_ = match ty.as_adt() {
             Some(hir::Adt::Enum(it)) => it,
             _ => return None,
diff --git a/src/tools/rust-analyzer/crates/ide-db/src/use_trivial_constructor.rs b/src/tools/rust-analyzer/crates/ide-db/src/use_trivial_constructor.rs
index a4a93e36f0e..f63cd92694b 100644
--- a/src/tools/rust-analyzer/crates/ide-db/src/use_trivial_constructor.rs
+++ b/src/tools/rust-analyzer/crates/ide-db/src/use_trivial_constructor.rs
@@ -11,7 +11,7 @@ use syntax::{
 pub fn use_trivial_constructor(
     db: &crate::RootDatabase,
     path: Path,
-    ty: &hir::Type,
+    ty: &hir::Type<'_>,
     edition: Edition,
 ) -> Option<Expr> {
     match ty.as_adt() {
diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/expected_function.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/expected_function.rs
index 7d2ac373dc0..afd1687ae07 100644
--- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/expected_function.rs
+++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/expected_function.rs
@@ -7,7 +7,7 @@ use crate::{Diagnostic, DiagnosticCode, DiagnosticsContext};
 // This diagnostic is triggered if a call is made on something that is not callable.
 pub(crate) fn expected_function(
     ctx: &DiagnosticsContext<'_>,
-    d: &hir::ExpectedFunction,
+    d: &hir::ExpectedFunction<'_>,
 ) -> Diagnostic {
     Diagnostic::new_with_syntax_node_ptr(
         ctx,
diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/invalid_cast.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/invalid_cast.rs
index 7a6e98fe1b5..a59077b757b 100644
--- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/invalid_cast.rs
+++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/invalid_cast.rs
@@ -18,7 +18,7 @@ macro_rules! format_ty {
 // Diagnostic: invalid-cast
 //
 // This diagnostic is triggered if the code contains an illegal cast
-pub(crate) fn invalid_cast(ctx: &DiagnosticsContext<'_>, d: &hir::InvalidCast) -> Diagnostic {
+pub(crate) fn invalid_cast(ctx: &DiagnosticsContext<'_>, d: &hir::InvalidCast<'_>) -> Diagnostic {
     let display_range = ctx.sema.diagnostics_display_range(d.expr.map(|it| it.into()));
     let (code, message) = match d.error {
         CastError::CastToBool => (
@@ -106,7 +106,10 @@ pub(crate) fn invalid_cast(ctx: &DiagnosticsContext<'_>, d: &hir::InvalidCast) -
 // Diagnostic: cast-to-unsized
 //
 // This diagnostic is triggered when casting to an unsized type
-pub(crate) fn cast_to_unsized(ctx: &DiagnosticsContext<'_>, d: &hir::CastToUnsized) -> Diagnostic {
+pub(crate) fn cast_to_unsized(
+    ctx: &DiagnosticsContext<'_>,
+    d: &hir::CastToUnsized<'_>,
+) -> Diagnostic {
     let display_range = ctx.sema.diagnostics_display_range(d.expr.map(|it| it.into()));
     Diagnostic::new(
         DiagnosticCode::RustcHardError("E0620"),
diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/missing_fields.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/missing_fields.rs
index 2b76efb1965..8a5d82b48c0 100644
--- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/missing_fields.rs
+++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/missing_fields.rs
@@ -106,7 +106,7 @@ fn fixes(ctx: &DiagnosticsContext<'_>, d: &hir::MissingFields) -> Option<Vec<Ass
                 }
             });
 
-            let generate_fill_expr = |ty: &Type| match ctx.config.expr_fill_default {
+            let generate_fill_expr = |ty: &Type<'_>| match ctx.config.expr_fill_default {
                 ExprFillDefaultMode::Todo => make::ext::expr_todo(),
                 ExprFillDefaultMode::Underscore => make::ext::expr_underscore(),
                 ExprFillDefaultMode::Default => {
@@ -180,7 +180,7 @@ fn fixes(ctx: &DiagnosticsContext<'_>, d: &hir::MissingFields) -> Option<Vec<Ass
 }
 
 fn make_ty(
-    ty: &hir::Type,
+    ty: &hir::Type<'_>,
     db: &dyn HirDatabase,
     module: hir::Module,
     edition: Edition,
@@ -198,7 +198,7 @@ fn make_ty(
 fn get_default_constructor(
     ctx: &DiagnosticsContext<'_>,
     d: &hir::MissingFields,
-    ty: &Type,
+    ty: &Type<'_>,
 ) -> Option<ast::Expr> {
     if let Some(builtin_ty) = ty.as_builtin() {
         if builtin_ty.is_int() || builtin_ty.is_uint() {
diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/missing_unsafe.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/missing_unsafe.rs
index 6bd5417b25d..d8f6e813d80 100644
--- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/missing_unsafe.rs
+++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/missing_unsafe.rs
@@ -630,6 +630,17 @@ fn main() {
         // Checks that we don't place orphan arguments for formatting under an unsafe block.
         check_diagnostics(
             r#"
+//- minicore: fmt_before_1_89_0
+fn foo() {
+    let p = 0xDEADBEEF as *const i32;
+    format_args!("", *p);
+                  // ^^ error: dereference of raw pointer is unsafe and requires an unsafe function or block
+}
+        "#,
+        );
+
+        check_diagnostics(
+            r#"
 //- minicore: fmt
 fn foo() {
     let p = 0xDEADBEEF as *const i32;
@@ -958,4 +969,18 @@ impl FooTrait for S2 {
         "#,
         );
     }
+
+    #[test]
+    fn no_false_positive_on_format_args_since_1_89_0() {
+        check_diagnostics(
+            r#"
+//- minicore: fmt
+fn test() {
+    let foo = 10;
+    let bar = true;
+    let _x = format_args!("{} {0} {} {last}", foo, bar, last = "!");
+}
+            "#,
+        );
+    }
 }
diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/moved_out_of_ref.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/moved_out_of_ref.rs
index 01cf5e8fa52..0928262d22f 100644
--- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/moved_out_of_ref.rs
+++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/moved_out_of_ref.rs
@@ -4,7 +4,10 @@ use hir::HirDisplay;
 // Diagnostic: moved-out-of-ref
 //
 // This diagnostic is triggered on moving non copy things out of references.
-pub(crate) fn moved_out_of_ref(ctx: &DiagnosticsContext<'_>, d: &hir::MovedOutOfRef) -> Diagnostic {
+pub(crate) fn moved_out_of_ref(
+    ctx: &DiagnosticsContext<'_>,
+    d: &hir::MovedOutOfRef<'_>,
+) -> Diagnostic {
     Diagnostic::new_with_syntax_node_ptr(
         ctx,
         DiagnosticCode::RustcHardError("E0507"),
@@ -217,4 +220,23 @@ fn test() {
             "#,
         )
     }
+
+    #[test]
+    fn regression_18201() {
+        check_diagnostics(
+            r#"
+//- minicore: copy
+struct NotCopy;
+struct S(NotCopy);
+impl S {
+    fn f(&mut self) {
+        || {
+            if let ref mut _cb = self.0 {
+            }
+        };
+    }
+}
+"#,
+        )
+    }
 }
diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/no_such_field.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/no_such_field.rs
index ef42f2dc744..0edab5e0b3b 100644
--- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/no_such_field.rs
+++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/no_such_field.rs
@@ -1,5 +1,4 @@
 use either::Either;
-use hir::{Field, HasCrate};
 use hir::{HasSource, HirDisplay, Semantics, VariantId, db::ExpandDatabase};
 use ide_db::text_edit::TextEdit;
 use ide_db::{EditionedFileId, RootDatabase, source_change::SourceChange};
@@ -8,7 +7,10 @@ use syntax::{
     ast::{self, edit::IndentLevel, make},
 };
 
-use crate::{Assist, Diagnostic, DiagnosticCode, DiagnosticsContext, fix};
+use crate::{
+    Assist, Diagnostic, DiagnosticCode, DiagnosticsContext, fix,
+    handlers::private_field::field_is_private_fixes,
+};
 
 // Diagnostic: no-such-field
 //
@@ -37,8 +39,8 @@ fn fixes(ctx: &DiagnosticsContext<'_>, d: &hir::NoSuchField) -> Option<Vec<Assis
                 field_is_private_fixes(
                     &ctx.sema,
                     d.field.file_id.original_file(ctx.sema.db),
-                    node,
                     private_field,
+                    ctx.sema.original_range(node.syntax()).range,
                 )
             } else {
                 missing_record_expr_field_fixes(
@@ -52,31 +54,6 @@ fn fixes(ctx: &DiagnosticsContext<'_>, d: &hir::NoSuchField) -> Option<Vec<Assis
     }
 }
 
-fn field_is_private_fixes(
-    sema: &Semantics<'_, RootDatabase>,
-    usage_file_id: EditionedFileId,
-    record_expr_field: &ast::RecordExprField,
-    private_field: Field,
-) -> Option<Vec<Assist>> {
-    let def_crate = private_field.krate(sema.db);
-    let usage_crate = sema.file_to_module_def(usage_file_id.file_id(sema.db))?.krate();
-    let visibility = if usage_crate == def_crate { "pub(crate) " } else { "pub " };
-
-    let source = private_field.source(sema.db)?;
-    let (range, _) = source.syntax().original_file_range_opt(sema.db)?;
-    let source_change = SourceChange::from_text_edit(
-        range.file_id.file_id(sema.db),
-        TextEdit::insert(range.range.start(), visibility.into()),
-    );
-
-    Some(vec![fix(
-        "increase_field_visibility",
-        "Increase field visibility",
-        source_change,
-        sema.original_range(record_expr_field.syntax()).range,
-    )])
-}
-
 fn missing_record_expr_field_fixes(
     sema: &Semantics<'_, RootDatabase>,
     usage_file_id: EditionedFileId,
diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/private_field.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/private_field.rs
index 5b4273a5a62..69cd0d27cb0 100644
--- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/private_field.rs
+++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/private_field.rs
@@ -1,4 +1,8 @@
-use crate::{Diagnostic, DiagnosticCode, DiagnosticsContext};
+use hir::{EditionedFileId, FileRange, HasCrate, HasSource, Semantics};
+use ide_db::{RootDatabase, assists::Assist, source_change::SourceChange, text_edit::TextEdit};
+use syntax::{AstNode, TextRange, TextSize, ast::HasVisibility};
+
+use crate::{Diagnostic, DiagnosticCode, DiagnosticsContext, fix};
 
 // Diagnostic: private-field
 //
@@ -16,11 +20,59 @@ pub(crate) fn private_field(ctx: &DiagnosticsContext<'_>, d: &hir::PrivateField)
         d.expr.map(|it| it.into()),
     )
     .stable()
+    .with_fixes(field_is_private_fixes(
+        &ctx.sema,
+        d.expr.file_id.original_file(ctx.sema.db),
+        d.field,
+        ctx.sema.original_range(d.expr.to_node(ctx.sema.db).syntax()).range,
+    ))
+}
+
+pub(crate) fn field_is_private_fixes(
+    sema: &Semantics<'_, RootDatabase>,
+    usage_file_id: EditionedFileId,
+    private_field: hir::Field,
+    fix_range: TextRange,
+) -> Option<Vec<Assist>> {
+    let def_crate = private_field.krate(sema.db);
+    let usage_crate = sema.file_to_module_def(usage_file_id.file_id(sema.db))?.krate();
+    let mut visibility_text = if usage_crate == def_crate { "pub(crate) " } else { "pub " };
+
+    let source = private_field.source(sema.db)?;
+    let existing_visibility = match &source.value {
+        hir::FieldSource::Named(it) => it.visibility(),
+        hir::FieldSource::Pos(it) => it.visibility(),
+    };
+    let range = match existing_visibility {
+        Some(visibility) => {
+            // If there is an existing visibility, don't insert whitespace after.
+            visibility_text = visibility_text.trim_end();
+            source.with_value(visibility.syntax()).original_file_range_opt(sema.db)?.0
+        }
+        None => {
+            let (range, _) = source.syntax().original_file_range_opt(sema.db)?;
+            FileRange {
+                file_id: range.file_id,
+                range: TextRange::at(range.range.start(), TextSize::new(0)),
+            }
+        }
+    };
+    let source_change = SourceChange::from_text_edit(
+        range.file_id.file_id(sema.db),
+        TextEdit::replace(range.range, visibility_text.into()),
+    );
+
+    Some(vec![fix(
+        "increase_field_visibility",
+        "Increase field visibility",
+        source_change,
+        fix_range,
+    )])
 }
 
 #[cfg(test)]
 mod tests {
-    use crate::tests::check_diagnostics;
+    use crate::tests::{check_diagnostics, check_fix};
 
     #[test]
     fn private_field() {
@@ -29,7 +81,7 @@ mod tests {
 mod module { pub struct Struct { field: u32 } }
 fn main(s: module::Struct) {
     s.field;
-  //^^^^^^^ error: field `field` of `Struct` is private
+  //^^^^^^^ 💡 error: field `field` of `Struct` is private
 }
 "#,
         );
@@ -42,7 +94,7 @@ fn main(s: module::Struct) {
 mod module { pub struct Struct(u32); }
 fn main(s: module::Struct) {
     s.0;
-  //^^^ error: field `0` of `Struct` is private
+  //^^^ 💡 error: field `0` of `Struct` is private
 }
 "#,
         );
@@ -113,4 +165,68 @@ fn main() {
 "#,
         );
     }
+
+    #[test]
+    fn change_visibility_fix() {
+        check_fix(
+            r#"
+pub mod foo {
+    pub mod bar {
+        pub struct Struct {
+            field: i32,
+        }
+    }
+}
+
+fn foo(v: foo::bar::Struct) {
+    v.field$0;
+}
+            "#,
+            r#"
+pub mod foo {
+    pub mod bar {
+        pub struct Struct {
+            pub(crate) field: i32,
+        }
+    }
+}
+
+fn foo(v: foo::bar::Struct) {
+    v.field;
+}
+            "#,
+        );
+    }
+
+    #[test]
+    fn change_visibility_with_existing_visibility() {
+        check_fix(
+            r#"
+pub mod foo {
+    pub mod bar {
+        pub struct Struct {
+            pub(super) field: i32,
+        }
+    }
+}
+
+fn foo(v: foo::bar::Struct) {
+    v.field$0;
+}
+            "#,
+            r#"
+pub mod foo {
+    pub mod bar {
+        pub struct Struct {
+            pub(crate) field: i32,
+        }
+    }
+}
+
+fn foo(v: foo::bar::Struct) {
+    v.field;
+}
+            "#,
+        );
+    }
 }
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 076df1ab0f8..e2957fcaefb 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
@@ -20,7 +20,7 @@ use crate::{Assist, Diagnostic, DiagnosticCode, DiagnosticsContext, adjusted_dis
 //
 // This diagnostic is triggered when the type of an expression or pattern does not match
 // the expected type.
-pub(crate) fn type_mismatch(ctx: &DiagnosticsContext<'_>, d: &hir::TypeMismatch) -> Diagnostic {
+pub(crate) fn type_mismatch(ctx: &DiagnosticsContext<'_>, d: &hir::TypeMismatch<'_>) -> Diagnostic {
     let display_range = adjusted_display_range(ctx, d.expr_or_pat, &|node| {
         let Either::Left(expr) = node else { return None };
         let salient_token_range = match expr {
@@ -39,7 +39,7 @@ pub(crate) fn type_mismatch(ctx: &DiagnosticsContext<'_>, d: &hir::TypeMismatch)
         cov_mark::hit!(type_mismatch_range_adjustment);
         Some(salient_token_range)
     });
-    let mut diag = Diagnostic::new(
+    Diagnostic::new(
         DiagnosticCode::RustcHardError("E0308"),
         format!(
             "expected {}, found {}",
@@ -52,14 +52,10 @@ pub(crate) fn type_mismatch(ctx: &DiagnosticsContext<'_>, d: &hir::TypeMismatch)
         ),
         display_range,
     )
-    .with_fixes(fixes(ctx, d));
-    if diag.fixes.is_some() {
-        diag.experimental = false;
-    }
-    diag
+    .with_fixes(fixes(ctx, d))
 }
 
-fn fixes(ctx: &DiagnosticsContext<'_>, d: &hir::TypeMismatch) -> Option<Vec<Assist>> {
+fn fixes(ctx: &DiagnosticsContext<'_>, d: &hir::TypeMismatch<'_>) -> Option<Vec<Assist>> {
     let mut fixes = Vec::new();
 
     if let Some(expr_ptr) = d.expr_or_pat.value.cast::<ast::Expr>() {
@@ -76,7 +72,7 @@ fn fixes(ctx: &DiagnosticsContext<'_>, d: &hir::TypeMismatch) -> Option<Vec<Assi
 
 fn add_reference(
     ctx: &DiagnosticsContext<'_>,
-    d: &hir::TypeMismatch,
+    d: &hir::TypeMismatch<'_>,
     expr_ptr: &InFile<AstPtr<ast::Expr>>,
     acc: &mut Vec<Assist>,
 ) -> Option<()> {
@@ -98,7 +94,7 @@ fn add_reference(
 
 fn add_missing_ok_or_some(
     ctx: &DiagnosticsContext<'_>,
-    d: &hir::TypeMismatch,
+    d: &hir::TypeMismatch<'_>,
     expr_ptr: &InFile<AstPtr<ast::Expr>>,
     acc: &mut Vec<Assist>,
 ) -> Option<()> {
@@ -188,7 +184,7 @@ fn add_missing_ok_or_some(
 
 fn remove_unnecessary_wrapper(
     ctx: &DiagnosticsContext<'_>,
-    d: &hir::TypeMismatch,
+    d: &hir::TypeMismatch<'_>,
     expr_ptr: &InFile<AstPtr<ast::Expr>>,
     acc: &mut Vec<Assist>,
 ) -> Option<()> {
@@ -271,7 +267,7 @@ fn remove_unnecessary_wrapper(
 
 fn remove_semicolon(
     ctx: &DiagnosticsContext<'_>,
-    d: &hir::TypeMismatch,
+    d: &hir::TypeMismatch<'_>,
     expr_ptr: &InFile<AstPtr<ast::Expr>>,
     acc: &mut Vec<Assist>,
 ) -> Option<()> {
@@ -301,7 +297,7 @@ fn remove_semicolon(
 
 fn str_ref_to_owned(
     ctx: &DiagnosticsContext<'_>,
-    d: &hir::TypeMismatch,
+    d: &hir::TypeMismatch<'_>,
     expr_ptr: &InFile<AstPtr<ast::Expr>>,
     acc: &mut Vec<Assist>,
 ) -> Option<()> {
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 1915a88dd00..8d427702690 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
@@ -20,7 +20,7 @@ use syntax::AstNode;
 // Diagnostic: typed-hole
 //
 // This diagnostic is triggered when an underscore expression is used in an invalid position.
-pub(crate) fn typed_hole(ctx: &DiagnosticsContext<'_>, d: &hir::TypedHole) -> Diagnostic {
+pub(crate) fn typed_hole(ctx: &DiagnosticsContext<'_>, d: &hir::TypedHole<'_>) -> Diagnostic {
     let display_range = ctx.sema.diagnostics_display_range(d.expr.map(|it| it.into()));
     let (message, fixes) = if d.expected.is_unknown() {
         ("`_` expressions may only appear on the left-hand side of an assignment".to_owned(), None)
@@ -41,7 +41,7 @@ pub(crate) fn typed_hole(ctx: &DiagnosticsContext<'_>, d: &hir::TypedHole) -> Di
         .with_fixes(fixes)
 }
 
-fn fixes(ctx: &DiagnosticsContext<'_>, d: &hir::TypedHole) -> Option<Vec<Assist>> {
+fn fixes(ctx: &DiagnosticsContext<'_>, d: &hir::TypedHole<'_>) -> Option<Vec<Assist>> {
     let db = ctx.sema.db;
     let root = db.parse_or_expand(d.expr.file_id);
     let (original_range, _) =
@@ -61,7 +61,7 @@ fn fixes(ctx: &DiagnosticsContext<'_>, d: &hir::TypedHole) -> Option<Vec<Assist>
     };
     let paths = term_search(&term_search_ctx);
 
-    let mut formatter = |_: &hir::Type| String::from("_");
+    let mut formatter = |_: &hir::Type<'_>| String::from("_");
 
     let assists: Vec<Assist> = d
         .expected
diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unresolved_field.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unresolved_field.rs
index 0649c97f820..69015898967 100644
--- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unresolved_field.rs
+++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unresolved_field.rs
@@ -25,7 +25,7 @@ use crate::{Diagnostic, DiagnosticCode, DiagnosticsContext, adjusted_display_ran
 // This diagnostic is triggered if a field does not exist on a given type.
 pub(crate) fn unresolved_field(
     ctx: &DiagnosticsContext<'_>,
-    d: &hir::UnresolvedField,
+    d: &hir::UnresolvedField<'_>,
 ) -> Diagnostic {
     let method_suffix = if d.method_with_same_name_exists {
         ", but a method with a similar name exists"
@@ -54,7 +54,7 @@ pub(crate) fn unresolved_field(
     .with_fixes(fixes(ctx, d))
 }
 
-fn fixes(ctx: &DiagnosticsContext<'_>, d: &hir::UnresolvedField) -> Option<Vec<Assist>> {
+fn fixes(ctx: &DiagnosticsContext<'_>, d: &hir::UnresolvedField<'_>) -> Option<Vec<Assist>> {
     let mut fixes = Vec::new();
     if d.method_with_same_name_exists {
         fixes.extend(method_fix(ctx, &d.expr));
@@ -64,7 +64,7 @@ fn fixes(ctx: &DiagnosticsContext<'_>, d: &hir::UnresolvedField) -> Option<Vec<A
 }
 
 // FIXME: Add Snippet Support
-fn field_fix(ctx: &DiagnosticsContext<'_>, d: &hir::UnresolvedField) -> Option<Assist> {
+fn field_fix(ctx: &DiagnosticsContext<'_>, d: &hir::UnresolvedField<'_>) -> Option<Assist> {
     // Get the FileRange of the invalid field access
     let root = ctx.sema.db.parse_or_expand(d.expr.file_id);
     let expr = d.expr.value.to_node(&root).left()?;
diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unresolved_method.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unresolved_method.rs
index 00c2a8c4c46..1f2d671249d 100644
--- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unresolved_method.rs
+++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unresolved_method.rs
@@ -18,7 +18,7 @@ use crate::{Diagnostic, DiagnosticCode, DiagnosticsContext, adjusted_display_ran
 // This diagnostic is triggered if a method does not exist on a given type.
 pub(crate) fn unresolved_method(
     ctx: &DiagnosticsContext<'_>,
-    d: &hir::UnresolvedMethodCall,
+    d: &hir::UnresolvedMethodCall<'_>,
 ) -> Diagnostic {
     let suffix = if d.field_with_same_name.is_some() {
         ", but a field with a similar name exists"
@@ -49,7 +49,7 @@ pub(crate) fn unresolved_method(
     .with_fixes(fixes(ctx, d))
 }
 
-fn fixes(ctx: &DiagnosticsContext<'_>, d: &hir::UnresolvedMethodCall) -> Option<Vec<Assist>> {
+fn fixes(ctx: &DiagnosticsContext<'_>, d: &hir::UnresolvedMethodCall<'_>) -> Option<Vec<Assist>> {
     let field_fix = if let Some(ty) = &d.field_with_same_name {
         field_fix(ctx, d, ty)
     } else {
@@ -72,8 +72,8 @@ fn fixes(ctx: &DiagnosticsContext<'_>, d: &hir::UnresolvedMethodCall) -> Option<
 
 fn field_fix(
     ctx: &DiagnosticsContext<'_>,
-    d: &hir::UnresolvedMethodCall,
-    ty: &hir::Type,
+    d: &hir::UnresolvedMethodCall<'_>,
+    ty: &hir::Type<'_>,
 ) -> Option<Assist> {
     if !ty.impls_fnonce(ctx.sema.db) {
         return None;
@@ -107,7 +107,10 @@ fn field_fix(
     })
 }
 
-fn assoc_func_fix(ctx: &DiagnosticsContext<'_>, d: &hir::UnresolvedMethodCall) -> Option<Assist> {
+fn assoc_func_fix(
+    ctx: &DiagnosticsContext<'_>,
+    d: &hir::UnresolvedMethodCall<'_>,
+) -> Option<Assist> {
     if let Some(f) = d.assoc_func_with_same_name {
         let db = ctx.sema.db;
 
diff --git a/src/tools/rust-analyzer/crates/ide-ssr/src/lib.rs b/src/tools/rust-analyzer/crates/ide-ssr/src/lib.rs
index 43c56ac8bec..e4b20f3f1aa 100644
--- a/src/tools/rust-analyzer/crates/ide-ssr/src/lib.rs
+++ b/src/tools/rust-analyzer/crates/ide-ssr/src/lib.rs
@@ -110,7 +110,7 @@ pub struct SsrMatches {
 pub struct MatchFinder<'db> {
     /// Our source of information about the user's code.
     sema: Semantics<'db, ide_db::RootDatabase>,
-    rules: Vec<ResolvedRule>,
+    rules: Vec<ResolvedRule<'db>>,
     resolution_scope: resolving::ResolutionScope<'db>,
     restrict_ranges: Vec<ide_db::FileRange>,
 }
diff --git a/src/tools/rust-analyzer/crates/ide-ssr/src/matching.rs b/src/tools/rust-analyzer/crates/ide-ssr/src/matching.rs
index cff4eede042..b350315ba54 100644
--- a/src/tools/rust-analyzer/crates/ide-ssr/src/matching.rs
+++ b/src/tools/rust-analyzer/crates/ide-ssr/src/matching.rs
@@ -84,12 +84,12 @@ pub(crate) struct MatchFailed {
 /// Checks if `code` matches the search pattern found in `search_scope`, returning information about
 /// the match, if it does. Since we only do matching in this module and searching is done by the
 /// parent module, we don't populate nested matches.
-pub(crate) fn get_match(
+pub(crate) fn get_match<'db>(
     debug_active: bool,
-    rule: &ResolvedRule,
+    rule: &ResolvedRule<'db>,
     code: &SyntaxNode,
     restrict_range: &Option<FileRange>,
-    sema: &Semantics<'_, ide_db::RootDatabase>,
+    sema: &Semantics<'db, ide_db::RootDatabase>,
 ) -> Result<Match, MatchFailed> {
     record_match_fails_reasons_scope(debug_active, || {
         Matcher::try_match(rule, code, restrict_range, sema)
@@ -102,7 +102,7 @@ struct Matcher<'db, 'sema> {
     /// If any placeholders come from anywhere outside of this range, then the match will be
     /// rejected.
     restrict_range: Option<FileRange>,
-    rule: &'sema ResolvedRule,
+    rule: &'sema ResolvedRule<'db>,
 }
 
 /// Which phase of matching we're currently performing. We do two phases because most attempted
@@ -117,7 +117,7 @@ enum Phase<'a> {
 
 impl<'db, 'sema> Matcher<'db, 'sema> {
     fn try_match(
-        rule: &ResolvedRule,
+        rule: &ResolvedRule<'db>,
         code: &SyntaxNode,
         restrict_range: &Option<FileRange>,
         sema: &'sema Semantics<'db, ide_db::RootDatabase>,
@@ -535,7 +535,7 @@ impl<'db, 'sema> Matcher<'db, 'sema> {
     fn attempt_match_ufcs_to_method_call(
         &self,
         phase: &mut Phase<'_>,
-        pattern_ufcs: &UfcsCallInfo,
+        pattern_ufcs: &UfcsCallInfo<'db>,
         code: &ast::MethodCallExpr,
     ) -> Result<(), MatchFailed> {
         use ast::HasArgList;
@@ -597,7 +597,7 @@ impl<'db, 'sema> Matcher<'db, 'sema> {
     fn attempt_match_ufcs_to_ufcs(
         &self,
         phase: &mut Phase<'_>,
-        pattern_ufcs: &UfcsCallInfo,
+        pattern_ufcs: &UfcsCallInfo<'db>,
         code: &ast::CallExpr,
     ) -> Result<(), MatchFailed> {
         use ast::HasArgList;
@@ -615,7 +615,7 @@ impl<'db, 'sema> Matcher<'db, 'sema> {
     /// times. Returns the number of times it needed to be dereferenced.
     fn check_expr_type(
         &self,
-        pattern_type: &hir::Type,
+        pattern_type: &hir::Type<'db>,
         expr: &ast::Expr,
     ) -> Result<usize, MatchFailed> {
         use hir::HirDisplay;
@@ -656,10 +656,10 @@ impl<'db, 'sema> Matcher<'db, 'sema> {
 }
 
 impl Match {
-    fn render_template_paths(
+    fn render_template_paths<'db>(
         &mut self,
-        template: &ResolvedPattern,
-        sema: &Semantics<'_, ide_db::RootDatabase>,
+        template: &ResolvedPattern<'db>,
+        sema: &Semantics<'db, ide_db::RootDatabase>,
     ) -> Result<(), MatchFailed> {
         let module = sema
             .scope(&self.matched_node)
diff --git a/src/tools/rust-analyzer/crates/ide-ssr/src/replacing.rs b/src/tools/rust-analyzer/crates/ide-ssr/src/replacing.rs
index 3c92697926f..752edd6535a 100644
--- a/src/tools/rust-analyzer/crates/ide-ssr/src/replacing.rs
+++ b/src/tools/rust-analyzer/crates/ide-ssr/src/replacing.rs
@@ -14,21 +14,21 @@ use crate::{Match, SsrMatches, fragments, resolving::ResolvedRule};
 /// Returns a text edit that will replace each match in `matches` with its corresponding replacement
 /// template. Placeholders in the template will have been substituted with whatever they matched to
 /// in the original code.
-pub(crate) fn matches_to_edit(
-    db: &dyn hir::db::ExpandDatabase,
+pub(crate) fn matches_to_edit<'db>(
+    db: &'db dyn hir::db::ExpandDatabase,
     matches: &SsrMatches,
     file_src: &str,
-    rules: &[ResolvedRule],
+    rules: &[ResolvedRule<'db>],
 ) -> TextEdit {
     matches_to_edit_at_offset(db, matches, file_src, 0.into(), rules)
 }
 
-fn matches_to_edit_at_offset(
-    db: &dyn hir::db::ExpandDatabase,
+fn matches_to_edit_at_offset<'db>(
+    db: &'db dyn hir::db::ExpandDatabase,
     matches: &SsrMatches,
     file_src: &str,
     relative_start: TextSize,
-    rules: &[ResolvedRule],
+    rules: &[ResolvedRule<'db>],
 ) -> TextEdit {
     let mut edit_builder = TextEdit::builder();
     for m in &matches.matches {
@@ -40,12 +40,12 @@ fn matches_to_edit_at_offset(
     edit_builder.finish()
 }
 
-struct ReplacementRenderer<'a> {
-    db: &'a dyn hir::db::ExpandDatabase,
+struct ReplacementRenderer<'a, 'db> {
+    db: &'db dyn hir::db::ExpandDatabase,
     match_info: &'a Match,
     file_src: &'a str,
-    rules: &'a [ResolvedRule],
-    rule: &'a ResolvedRule,
+    rules: &'a [ResolvedRule<'db>],
+    rule: &'a ResolvedRule<'db>,
     out: String,
     // Map from a range within `out` to a token in `template` that represents a placeholder. This is
     // used to validate that the generated source code doesn't split any placeholder expansions (see
@@ -58,11 +58,11 @@ struct ReplacementRenderer<'a> {
     edition: Edition,
 }
 
-fn render_replace(
-    db: &dyn hir::db::ExpandDatabase,
+fn render_replace<'db>(
+    db: &'db dyn hir::db::ExpandDatabase,
     match_info: &Match,
     file_src: &str,
-    rules: &[ResolvedRule],
+    rules: &[ResolvedRule<'db>],
     edition: Edition,
 ) -> String {
     let rule = &rules[match_info.rule_index];
@@ -89,7 +89,7 @@ fn render_replace(
     renderer.out
 }
 
-impl ReplacementRenderer<'_> {
+impl<'db> ReplacementRenderer<'_, 'db> {
     fn render_node_children(&mut self, node: &SyntaxNode) {
         for node_or_token in node.children_with_tokens() {
             self.render_node_or_token(&node_or_token);
diff --git a/src/tools/rust-analyzer/crates/ide-ssr/src/resolving.rs b/src/tools/rust-analyzer/crates/ide-ssr/src/resolving.rs
index a687db4bf58..8f28a1cd3a6 100644
--- a/src/tools/rust-analyzer/crates/ide-ssr/src/resolving.rs
+++ b/src/tools/rust-analyzer/crates/ide-ssr/src/resolving.rs
@@ -15,18 +15,18 @@ pub(crate) struct ResolutionScope<'db> {
     node: SyntaxNode,
 }
 
-pub(crate) struct ResolvedRule {
-    pub(crate) pattern: ResolvedPattern,
-    pub(crate) template: Option<ResolvedPattern>,
+pub(crate) struct ResolvedRule<'db> {
+    pub(crate) pattern: ResolvedPattern<'db>,
+    pub(crate) template: Option<ResolvedPattern<'db>>,
     pub(crate) index: usize,
 }
 
-pub(crate) struct ResolvedPattern {
+pub(crate) struct ResolvedPattern<'db> {
     pub(crate) placeholders_by_stand_in: FxHashMap<SmolStr, parsing::Placeholder>,
     pub(crate) node: SyntaxNode,
     // Paths in `node` that we've resolved.
     pub(crate) resolved_paths: FxHashMap<SyntaxNode, ResolvedPath>,
-    pub(crate) ufcs_function_calls: FxHashMap<SyntaxNode, UfcsCallInfo>,
+    pub(crate) ufcs_function_calls: FxHashMap<SyntaxNode, UfcsCallInfo<'db>>,
     pub(crate) contains_self: bool,
 }
 
@@ -36,18 +36,18 @@ pub(crate) struct ResolvedPath {
     pub(crate) depth: u32,
 }
 
-pub(crate) struct UfcsCallInfo {
+pub(crate) struct UfcsCallInfo<'db> {
     pub(crate) call_expr: ast::CallExpr,
     pub(crate) function: hir::Function,
-    pub(crate) qualifier_type: Option<hir::Type>,
+    pub(crate) qualifier_type: Option<hir::Type<'db>>,
 }
 
-impl ResolvedRule {
+impl<'db> ResolvedRule<'db> {
     pub(crate) fn new(
         rule: parsing::ParsedRule,
-        resolution_scope: &ResolutionScope<'_>,
+        resolution_scope: &ResolutionScope<'db>,
         index: usize,
-    ) -> Result<ResolvedRule, SsrError> {
+    ) -> Result<ResolvedRule<'db>, SsrError> {
         let resolver =
             Resolver { resolution_scope, placeholders_by_stand_in: rule.placeholders_by_stand_in };
         let resolved_template = match rule.template {
@@ -74,8 +74,8 @@ struct Resolver<'a, 'db> {
     placeholders_by_stand_in: FxHashMap<SmolStr, parsing::Placeholder>,
 }
 
-impl Resolver<'_, '_> {
-    fn resolve_pattern_tree(&self, pattern: SyntaxNode) -> Result<ResolvedPattern, SsrError> {
+impl<'db> Resolver<'_, 'db> {
+    fn resolve_pattern_tree(&self, pattern: SyntaxNode) -> Result<ResolvedPattern<'db>, SsrError> {
         use syntax::ast::AstNode;
         use syntax::{SyntaxElement, T};
         let mut resolved_paths = FxHashMap::default();
@@ -250,7 +250,7 @@ impl<'db> ResolutionScope<'db> {
         }
     }
 
-    fn qualifier_type(&self, path: &SyntaxNode) -> Option<hir::Type> {
+    fn qualifier_type(&self, path: &SyntaxNode) -> Option<hir::Type<'db>> {
         use syntax::ast::AstNode;
         if let Some(path) = ast::Path::cast(path.clone()) {
             if let Some(qualifier) = path.qualifier() {
diff --git a/src/tools/rust-analyzer/crates/ide-ssr/src/search.rs b/src/tools/rust-analyzer/crates/ide-ssr/src/search.rs
index 9afbedbb1ab..99a98fb2a71 100644
--- a/src/tools/rust-analyzer/crates/ide-ssr/src/search.rs
+++ b/src/tools/rust-analyzer/crates/ide-ssr/src/search.rs
@@ -21,13 +21,13 @@ pub(crate) struct UsageCache {
     usages: Vec<(Definition, UsageSearchResult)>,
 }
 
-impl MatchFinder<'_> {
+impl<'db> MatchFinder<'db> {
     /// Adds all matches for `rule` to `matches_out`. Matches may overlap in ways that make
     /// replacement impossible, so further processing is required in order to properly nest matches
     /// and remove overlapping matches. This is done in the `nesting` module.
     pub(crate) fn find_matches_for_rule(
         &self,
-        rule: &ResolvedRule,
+        rule: &ResolvedRule<'db>,
         usage_cache: &mut UsageCache,
         matches_out: &mut Vec<Match>,
     ) {
@@ -49,8 +49,8 @@ impl MatchFinder<'_> {
 
     fn find_matches_for_pattern_tree(
         &self,
-        rule: &ResolvedRule,
-        pattern: &ResolvedPattern,
+        rule: &ResolvedRule<'db>,
+        pattern: &ResolvedPattern<'db>,
         usage_cache: &mut UsageCache,
         matches_out: &mut Vec<Match>,
     ) {
@@ -144,7 +144,7 @@ impl MatchFinder<'_> {
         SearchScope::files(&files)
     }
 
-    fn slow_scan(&self, rule: &ResolvedRule, matches_out: &mut Vec<Match>) {
+    fn slow_scan(&self, rule: &ResolvedRule<'db>, matches_out: &mut Vec<Match>) {
         self.search_files_do(|file_id| {
             let file = self.sema.parse_guess_edition(file_id);
             let code = file.syntax();
@@ -177,7 +177,7 @@ impl MatchFinder<'_> {
     fn slow_scan_node(
         &self,
         code: &SyntaxNode,
-        rule: &ResolvedRule,
+        rule: &ResolvedRule<'db>,
         restrict_range: &Option<FileRange>,
         matches_out: &mut Vec<Match>,
     ) {
@@ -206,7 +206,7 @@ impl MatchFinder<'_> {
 
     fn try_add_match(
         &self,
-        rule: &ResolvedRule,
+        rule: &ResolvedRule<'db>,
         code: &SyntaxNode,
         restrict_range: &Option<FileRange>,
         matches_out: &mut Vec<Match>,
@@ -274,7 +274,7 @@ impl UsageCache {
 /// Returns a path that's suitable for path resolution. We exclude builtin types, since they aren't
 /// something that we can find references to. We then somewhat arbitrarily pick the path that is the
 /// longest as this is hopefully more likely to be less common, making it faster to find.
-fn pick_path_for_usages(pattern: &ResolvedPattern) -> Option<&ResolvedPath> {
+fn pick_path_for_usages<'a>(pattern: &'a ResolvedPattern<'_>) -> Option<&'a ResolvedPath> {
     // FIXME: Take the scope of the resolved path into account. e.g. if there are any paths that are
     // private to the current module, then we definitely would want to pick them over say a path
     // from std. Possibly we should go further than this and intersect the search scopes for all
diff --git a/src/tools/rust-analyzer/crates/ide/src/goto_implementation.rs b/src/tools/rust-analyzer/crates/ide/src/goto_implementation.rs
index 1bc28f28b6f..02d96a64732 100644
--- a/src/tools/rust-analyzer/crates/ide/src/goto_implementation.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/goto_implementation.rs
@@ -83,7 +83,7 @@ pub(crate) fn goto_implementation(
     Some(RangeInfo { range, info: navs })
 }
 
-fn impls_for_ty(sema: &Semantics<'_, RootDatabase>, ty: hir::Type) -> Vec<NavigationTarget> {
+fn impls_for_ty(sema: &Semantics<'_, RootDatabase>, ty: hir::Type<'_>) -> Vec<NavigationTarget> {
     Impl::all_for_type(sema.db, ty)
         .into_iter()
         .filter_map(|imp| imp.try_to_nav(sema.db))
diff --git a/src/tools/rust-analyzer/crates/ide/src/goto_type_definition.rs b/src/tools/rust-analyzer/crates/ide/src/goto_type_definition.rs
index 9781e7116de..86d72fefe05 100644
--- a/src/tools/rust-analyzer/crates/ide/src/goto_type_definition.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/goto_type_definition.rs
@@ -38,7 +38,7 @@ pub(crate) fn goto_type_definition(
             }
         }
     };
-    let mut process_ty = |ty: hir::Type| {
+    let mut process_ty = |ty: hir::Type<'_>| {
         // collect from each `ty` into the `res` result vec
         let ty = ty.strip_references();
         ty.walk(db, |t| {
diff --git a/src/tools/rust-analyzer/crates/ide/src/hover.rs b/src/tools/rust-analyzer/crates/ide/src/hover.rs
index 5404a9dc2ce..e4d6279759e 100644
--- a/src/tools/rust-analyzer/crates/ide/src/hover.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/hover.rs
@@ -426,7 +426,7 @@ pub(crate) fn hover_for_definition(
     sema: &Semantics<'_, RootDatabase>,
     file_id: FileId,
     def: Definition,
-    subst: Option<GenericSubstitution>,
+    subst: Option<GenericSubstitution<'_>>,
     scope_node: &SyntaxNode,
     macro_arm: Option<u32>,
     render_extras: bool,
@@ -483,10 +483,10 @@ pub(crate) fn hover_for_definition(
     }
 }
 
-fn notable_traits(
-    db: &RootDatabase,
-    ty: &hir::Type,
-) -> Vec<(hir::Trait, Vec<(Option<hir::Type>, hir::Name)>)> {
+fn notable_traits<'db>(
+    db: &'db RootDatabase,
+    ty: &hir::Type<'db>,
+) -> Vec<(hir::Trait, Vec<(Option<hir::Type<'db>>, hir::Name)>)> {
     db.notable_traits_in_deps(ty.krate(db).into())
         .iter()
         .flat_map(|it| &**it)
@@ -567,8 +567,8 @@ fn runnable_action(
 fn goto_type_action_for_def(
     db: &RootDatabase,
     def: Definition,
-    notable_traits: &[(hir::Trait, Vec<(Option<hir::Type>, hir::Name)>)],
-    subst_types: Option<Vec<(hir::Symbol, hir::Type)>>,
+    notable_traits: &[(hir::Trait, Vec<(Option<hir::Type<'_>>, hir::Name)>)],
+    subst_types: Option<Vec<(hir::Symbol, hir::Type<'_>)>>,
     edition: Edition,
 ) -> Option<HoverAction> {
     let mut targets: Vec<hir::ModuleDef> = Vec::new();
@@ -622,7 +622,7 @@ fn goto_type_action_for_def(
 
 fn walk_and_push_ty(
     db: &RootDatabase,
-    ty: &hir::Type,
+    ty: &hir::Type<'_>,
     push_new_def: &mut dyn FnMut(hir::ModuleDef),
 ) {
     ty.walk(db, |t| {
diff --git a/src/tools/rust-analyzer/crates/ide/src/hover/render.rs b/src/tools/rust-analyzer/crates/ide/src/hover/render.rs
index c24864a18bd..670210d4998 100644
--- a/src/tools/rust-analyzer/crates/ide/src/hover/render.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/hover/render.rs
@@ -476,10 +476,10 @@ pub(super) fn definition(
     db: &RootDatabase,
     def: Definition,
     famous_defs: Option<&FamousDefs<'_, '_>>,
-    notable_traits: &[(Trait, Vec<(Option<Type>, Name)>)],
+    notable_traits: &[(Trait, Vec<(Option<Type<'_>>, Name)>)],
     macro_arm: Option<u32>,
     render_extras: bool,
-    subst_types: Option<&Vec<(Symbol, Type)>>,
+    subst_types: Option<&Vec<(Symbol, Type<'_>)>>,
     config: &HoverConfig,
     edition: Edition,
     display_target: DisplayTarget,
@@ -938,7 +938,7 @@ pub(super) fn literal(
 
 fn render_notable_trait(
     db: &RootDatabase,
-    notable_traits: &[(Trait, Vec<(Option<Type>, Name)>)],
+    notable_traits: &[(Trait, Vec<(Option<Type<'_>>, Name)>)],
     edition: Edition,
     display_target: DisplayTarget,
 ) -> Option<String> {
@@ -979,7 +979,7 @@ fn render_notable_trait(
 fn type_info(
     sema: &Semantics<'_, RootDatabase>,
     config: &HoverConfig,
-    ty: TypeInfo,
+    ty: TypeInfo<'_>,
     edition: Edition,
     display_target: DisplayTarget,
 ) -> Option<HoverResult> {
@@ -1038,7 +1038,7 @@ fn type_info(
 fn closure_ty(
     sema: &Semantics<'_, RootDatabase>,
     config: &HoverConfig,
-    TypeInfo { original, adjusted }: &TypeInfo,
+    TypeInfo { original, adjusted }: &TypeInfo<'_>,
     edition: Edition,
     display_target: DisplayTarget,
 ) -> Option<HoverResult> {
diff --git a/src/tools/rust-analyzer/crates/ide/src/inlay_hints.rs b/src/tools/rust-analyzer/crates/ide/src/inlay_hints.rs
index b094b098462..19e5509681a 100644
--- a/src/tools/rust-analyzer/crates/ide/src/inlay_hints.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/inlay_hints.rs
@@ -722,14 +722,14 @@ impl InlayHintLabelBuilder<'_> {
 fn label_of_ty(
     famous_defs @ FamousDefs(sema, _): &FamousDefs<'_, '_>,
     config: &InlayHintsConfig,
-    ty: &hir::Type,
+    ty: &hir::Type<'_>,
     display_target: DisplayTarget,
 ) -> Option<InlayHintLabel> {
     fn rec(
         sema: &Semantics<'_, RootDatabase>,
         famous_defs: &FamousDefs<'_, '_>,
         mut max_length: Option<usize>,
-        ty: &hir::Type,
+        ty: &hir::Type<'_>,
         label_builder: &mut InlayHintLabelBuilder<'_>,
         config: &InlayHintsConfig,
         display_target: DisplayTarget,
@@ -788,11 +788,11 @@ fn label_of_ty(
 }
 
 /// Checks if the type is an Iterator from std::iter and returns the iterator trait and the item type of the concrete iterator.
-fn hint_iterator(
-    sema: &Semantics<'_, RootDatabase>,
-    famous_defs: &FamousDefs<'_, '_>,
-    ty: &hir::Type,
-) -> Option<(hir::Trait, hir::TypeAlias, hir::Type)> {
+fn hint_iterator<'db>(
+    sema: &Semantics<'db, RootDatabase>,
+    famous_defs: &FamousDefs<'_, 'db>,
+    ty: &hir::Type<'db>,
+) -> Option<(hir::Trait, hir::TypeAlias, hir::Type<'db>)> {
     let db = sema.db;
     let strukt = ty.strip_references().as_adt()?;
     let krate = strukt.module(db).krate();
@@ -826,7 +826,7 @@ fn ty_to_text_edit(
     sema: &Semantics<'_, RootDatabase>,
     config: &InlayHintsConfig,
     node_for_hint: &SyntaxNode,
-    ty: &hir::Type,
+    ty: &hir::Type<'_>,
     offset_to_insert_ty: TextSize,
     additional_edits: &dyn Fn(&mut TextEditBuilder),
     prefix: impl Into<String>,
diff --git a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/param_name.rs b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/param_name.rs
index 5ff9fee60ab..5174228466c 100644
--- a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/param_name.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/param_name.rs
@@ -87,10 +87,10 @@ pub(super) fn hints(
     Some(())
 }
 
-fn get_callable(
-    sema: &Semantics<'_, RootDatabase>,
+fn get_callable<'db>(
+    sema: &Semantics<'db, RootDatabase>,
     expr: &ast::Expr,
-) -> Option<(hir::Callable, ast::ArgList)> {
+) -> Option<(hir::Callable<'db>, ast::ArgList)> {
     match expr {
         ast::Expr::CallExpr(expr) => {
             let descended = sema.descend_node_into_attributes(expr.clone()).pop();
diff --git a/src/tools/rust-analyzer/crates/ide/src/lib.rs b/src/tools/rust-analyzer/crates/ide/src/lib.rs
index 82dbcde4c06..b3b8deb61fc 100644
--- a/src/tools/rust-analyzer/crates/ide/src/lib.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/lib.rs
@@ -409,7 +409,7 @@ impl Analysis {
         self.with_db(|db| typing::on_enter(db, position))
     }
 
-    pub const SUPPORTED_TRIGGER_CHARS: &'static str = typing::TRIGGER_CHARS;
+    pub const SUPPORTED_TRIGGER_CHARS: &[char] = typing::TRIGGER_CHARS;
 
     /// Returns an edit which should be applied after a character was typed.
     ///
@@ -421,7 +421,7 @@ impl Analysis {
         char_typed: char,
     ) -> Cancellable<Option<SourceChange>> {
         // Fast path to not even parse the file.
-        if !typing::TRIGGER_CHARS.contains(char_typed) {
+        if !typing::TRIGGER_CHARS.contains(&char_typed) {
             return Ok(None);
         }
 
diff --git a/src/tools/rust-analyzer/crates/ide/src/signature_help.rs b/src/tools/rust-analyzer/crates/ide/src/signature_help.rs
index 0e17b355907..e30a3ebefb9 100644
--- a/src/tools/rust-analyzer/crates/ide/src/signature_help.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/signature_help.rs
@@ -278,7 +278,7 @@ fn signature_help_for_call(
     }
     res.signature.push(')');
 
-    let mut render = |ret_type: hir::Type| {
+    let mut render = |ret_type: hir::Type<'_>| {
         if !ret_type.is_unit() {
             format_to!(res.signature, " -> {}", ret_type.display(db, display_target));
         }
@@ -597,11 +597,11 @@ fn signature_help_for_tuple_expr(
     Some(res)
 }
 
-fn signature_help_for_record_(
-    sema: &Semantics<'_, RootDatabase>,
+fn signature_help_for_record_<'db>(
+    sema: &Semantics<'db, RootDatabase>,
     field_list_children: SyntaxElementChildren,
     path: &ast::Path,
-    fields2: impl Iterator<Item = (hir::Field, hir::Type)>,
+    fields2: impl Iterator<Item = (hir::Field, hir::Type<'db>)>,
     token: SyntaxToken,
     edition: Edition,
     display_target: DisplayTarget,
@@ -689,13 +689,13 @@ fn signature_help_for_record_(
     Some(res)
 }
 
-fn signature_help_for_tuple_pat_ish(
-    db: &RootDatabase,
+fn signature_help_for_tuple_pat_ish<'db>(
+    db: &'db RootDatabase,
     mut res: SignatureHelp,
     pat: &SyntaxNode,
     token: SyntaxToken,
     mut field_pats: AstChildren<ast::Pat>,
-    fields: impl ExactSizeIterator<Item = hir::Type>,
+    fields: impl ExactSizeIterator<Item = hir::Type<'db>>,
     display_target: DisplayTarget,
 ) -> SignatureHelp {
     let rest_pat = field_pats.find(|it| matches!(it, ast::Pat::RestPat(_)));
diff --git a/src/tools/rust-analyzer/crates/ide/src/typing.rs b/src/tools/rust-analyzer/crates/ide/src/typing.rs
index 4df7e25223d..ed55ac5bf04 100644
--- a/src/tools/rust-analyzer/crates/ide/src/typing.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/typing.rs
@@ -15,6 +15,7 @@
 
 mod on_enter;
 
+use either::Either;
 use hir::EditionedFileId;
 use ide_db::{FilePosition, RootDatabase, base_db::RootQueryDb};
 use span::Edition;
@@ -33,7 +34,7 @@ use crate::SourceChange;
 pub(crate) use on_enter::on_enter;
 
 // Don't forget to add new trigger characters to `server_capabilities` in `caps.rs`.
-pub(crate) const TRIGGER_CHARS: &str = ".=<>{(|";
+pub(crate) const TRIGGER_CHARS: &[char] = &['.', '=', '<', '>', '{', '(', '|', '+'];
 
 struct ExtendedTextEdit {
     edit: TextEdit,
@@ -66,7 +67,7 @@ pub(crate) fn on_char_typed(
     position: FilePosition,
     char_typed: char,
 ) -> Option<SourceChange> {
-    if !stdx::always!(TRIGGER_CHARS.contains(char_typed)) {
+    if !TRIGGER_CHARS.contains(&char_typed) {
         return None;
     }
     // FIXME: We need to figure out the edition of the file here, but that means hitting the
@@ -101,6 +102,7 @@ fn on_char_typed_(
         '>' => on_right_angle_typed(&file.tree(), offset),
         '{' | '(' | '<' => on_opening_delimiter_typed(file, offset, char_typed, edition),
         '|' => on_pipe_typed(&file.tree(), offset),
+        '+' => on_plus_typed(&file.tree(), offset),
         _ => None,
     }
     .map(conv)
@@ -402,6 +404,28 @@ fn on_pipe_typed(file: &SourceFile, offset: TextSize) -> Option<TextEdit> {
     Some(TextEdit::insert(after_lpipe, "|".to_owned()))
 }
 
+fn on_plus_typed(file: &SourceFile, offset: TextSize) -> Option<TextEdit> {
+    let plus_token = file.syntax().token_at_offset(offset).right_biased()?;
+    if plus_token.kind() != SyntaxKind::PLUS {
+        return None;
+    }
+    let mut ancestors = plus_token.parent_ancestors();
+    ancestors.next().and_then(ast::TypeBoundList::cast)?;
+    let trait_type =
+        ancestors.next().and_then(<Either<ast::DynTraitType, ast::ImplTraitType>>::cast)?;
+    let kind = ancestors.next()?.kind();
+
+    if ast::RefType::can_cast(kind) || ast::PtrType::can_cast(kind) || ast::RetType::can_cast(kind)
+    {
+        let mut builder = TextEdit::builder();
+        builder.insert(trait_type.syntax().text_range().start(), "(".to_owned());
+        builder.insert(trait_type.syntax().text_range().end(), ")".to_owned());
+        Some(builder.finish())
+    } else {
+        None
+    }
+}
+
 /// Adds a space after an arrow when `fn foo() { ... }` is turned into `fn foo() -> { ... }`
 fn on_right_angle_typed(file: &SourceFile, offset: TextSize) -> Option<TextEdit> {
     let file_text = file.syntax().text();
@@ -1597,4 +1621,64 @@ fn foo() {
 "#,
         );
     }
+
+    #[test]
+    fn adds_parentheses_around_trait_object_in_ref_type() {
+        type_char(
+            '+',
+            r#"
+fn foo(x: &dyn A$0) {}
+"#,
+            r#"
+fn foo(x: &(dyn A+)) {}
+"#,
+        );
+        type_char(
+            '+',
+            r#"
+fn foo(x: &'static dyn A$0B) {}
+"#,
+            r#"
+fn foo(x: &'static (dyn A+B)) {}
+"#,
+        );
+        type_char_noop(
+            '+',
+            r#"
+fn foo(x: &(dyn A$0)) {}
+"#,
+        );
+        type_char_noop(
+            '+',
+            r#"
+fn foo(x: Box<dyn A$0>) {}
+"#,
+        );
+    }
+
+    #[test]
+    fn adds_parentheses_around_trait_object_in_ptr_type() {
+        type_char(
+            '+',
+            r#"
+fn foo(x: *const dyn A$0) {}
+"#,
+            r#"
+fn foo(x: *const (dyn A+)) {}
+"#,
+        );
+    }
+
+    #[test]
+    fn adds_parentheses_around_trait_object_in_return_type() {
+        type_char(
+            '+',
+            r#"
+fn foo(x: fn() -> dyn A$0) {}
+"#,
+            r#"
+fn foo(x: fn() -> (dyn A+)) {}
+"#,
+        );
+    }
 }
diff --git a/src/tools/rust-analyzer/crates/ide/src/view_memory_layout.rs b/src/tools/rust-analyzer/crates/ide/src/view_memory_layout.rs
index 140ae4265be..63701a4d15e 100644
--- a/src/tools/rust-analyzer/crates/ide/src/view_memory_layout.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/view_memory_layout.rs
@@ -107,7 +107,7 @@ pub(crate) fn view_memory_layout(
     fn read_layout(
         nodes: &mut Vec<MemoryLayoutNode>,
         db: &RootDatabase,
-        ty: &Type,
+        ty: &Type<'_>,
         layout: &Layout,
         parent_idx: usize,
         display_target: DisplayTarget,
diff --git a/src/tools/rust-analyzer/crates/intern/src/symbol/symbols.rs b/src/tools/rust-analyzer/crates/intern/src/symbol/symbols.rs
index d5cbb7328c1..adc581309d1 100644
--- a/src/tools/rust-analyzer/crates/intern/src/symbol/symbols.rs
+++ b/src/tools/rust-analyzer/crates/intern/src/symbol/symbols.rs
@@ -496,6 +496,7 @@ define_symbols! {
     vectorcall,
     wasm,
     win64,
+    args,
     array,
     boxed_slice,
     completions,
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 89b8631cd25..52f59679b58 100644
--- a/src/tools/rust-analyzer/crates/load-cargo/src/lib.rs
+++ b/src/tools/rust-analyzer/crates/load-cargo/src/lib.rs
@@ -42,7 +42,7 @@ pub fn load_workspace_at(
     root: &Path,
     cargo_config: &CargoConfig,
     load_config: &LoadCargoConfig,
-    progress: &dyn Fn(String),
+    progress: &(dyn Fn(String) + Sync),
 ) -> anyhow::Result<(RootDatabase, vfs::Vfs, Option<ProcMacroClient>)> {
     let root = AbsPathBuf::assert_utf8(std::env::current_dir()?.join(root));
     let root = ProjectManifest::discover_single(&root)?;
diff --git a/src/tools/rust-analyzer/crates/project-model/src/build_dependencies.rs b/src/tools/rust-analyzer/crates/project-model/src/build_dependencies.rs
index e0c38ccf333..4435376eab6 100644
--- a/src/tools/rust-analyzer/crates/project-model/src/build_dependencies.rs
+++ b/src/tools/rust-analyzer/crates/project-model/src/build_dependencies.rs
@@ -20,7 +20,9 @@ use toolchain::Tool;
 
 use crate::{
     CargoConfig, CargoFeatures, CargoWorkspace, InvocationStrategy, ManifestPath, Package, Sysroot,
-    TargetKind, utf8_stdout,
+    TargetKind,
+    toolchain_info::{QueryConfig, version},
+    utf8_stdout,
 };
 
 /// Output of the build script and proc-macro building steps for a workspace.
@@ -446,10 +448,30 @@ impl WorkspaceBuildScripts {
             }
         };
 
-        if config.wrap_rustc_in_build_scripts {
+        // If [`--compile-time-deps` flag](https://github.com/rust-lang/cargo/issues/14434) is
+        // available in current toolchain's cargo, use it to build compile time deps only.
+        const COMP_TIME_DEPS_MIN_TOOLCHAIN_VERSION: semver::Version = semver::Version {
+            major: 1,
+            minor: 90,
+            patch: 0,
+            pre: semver::Prerelease::EMPTY,
+            build: semver::BuildMetadata::EMPTY,
+        };
+
+        let query_config = QueryConfig::Cargo(sysroot, manifest_path);
+        let toolchain = version::get(query_config, &config.extra_env).ok().flatten();
+        let cargo_comp_time_deps_available =
+            toolchain.is_some_and(|v| v >= COMP_TIME_DEPS_MIN_TOOLCHAIN_VERSION);
+
+        if cargo_comp_time_deps_available {
+            cmd.env("__CARGO_TEST_CHANNEL_OVERRIDE_DO_NOT_USE_THIS", "nightly");
+            cmd.arg("-Zunstable-options");
+            cmd.arg("--compile-time-deps");
+        } else if config.wrap_rustc_in_build_scripts {
             // Setup RUSTC_WRAPPER to point to `rust-analyzer` binary itself. We use
             // that to compile only proc macros and build scripts during the initial
             // `cargo check`.
+            // We don't need this if we are using `--compile-time-deps` flag.
             let myself = std::env::current_exe()?;
             cmd.env("RUSTC_WRAPPER", myself);
             cmd.env("RA_RUSTC_WRAPPER", "1");
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 1fade7b3323..58507418e4d 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
@@ -7,16 +7,25 @@ use anyhow::Context;
 use base_db::Env;
 use cargo_metadata::{CargoOpt, MetadataCommand};
 use la_arena::{Arena, Idx};
-use paths::{AbsPath, AbsPathBuf, Utf8PathBuf};
+use paths::{AbsPath, AbsPathBuf, Utf8Path, Utf8PathBuf};
 use rustc_hash::{FxHashMap, FxHashSet};
 use serde_derive::Deserialize;
 use serde_json::from_value;
 use span::Edition;
+use stdx::process::spawn_with_streaming_output;
 use toolchain::Tool;
 
 use crate::{CfgOverrides, InvocationStrategy};
 use crate::{ManifestPath, Sysroot};
 
+const MINIMUM_TOOLCHAIN_VERSION_SUPPORTING_LOCKFILE_PATH: semver::Version = semver::Version {
+    major: 1,
+    minor: 82,
+    patch: 0,
+    pre: semver::Prerelease::EMPTY,
+    build: semver::BuildMetadata::EMPTY,
+};
+
 /// [`CargoWorkspace`] represents the logical structure of, well, a Cargo
 /// workspace. It pretty closely mirrors `cargo metadata` output.
 ///
@@ -290,6 +299,13 @@ pub struct CargoMetadataConfig {
     pub extra_args: Vec<String>,
     /// Extra env vars to set when invoking the cargo command
     pub extra_env: FxHashMap<String, Option<String>>,
+    /// The target dir for this workspace load.
+    pub target_dir: Utf8PathBuf,
+    /// What kind of metadata are we fetching: workspace, rustc, or sysroot.
+    pub kind: &'static str,
+    /// The toolchain version, if known.
+    /// Used to conditionally enable unstable cargo features.
+    pub toolchain_version: Option<semver::Version>,
 }
 
 // Deserialize helper for the cargo metadata
@@ -382,28 +398,74 @@ impl CargoWorkspace {
                 config.targets.iter().flat_map(|it| ["--filter-platform".to_owned(), it.clone()]),
             );
         }
+        if no_deps {
+            other_options.push("--no-deps".to_owned());
+        }
+
+        let mut using_lockfile_copy = false;
         // The manifest is a rust file, so this means its a script manifest
         if cargo_toml.is_rust_manifest() {
-            // Deliberately don't set up RUSTC_BOOTSTRAP or a nightly override here, the user should
-            // opt into it themselves.
             other_options.push("-Zscript".to_owned());
+        } else if config
+            .toolchain_version
+            .as_ref()
+            .is_some_and(|v| *v >= MINIMUM_TOOLCHAIN_VERSION_SUPPORTING_LOCKFILE_PATH)
+        {
+            let lockfile = <_ as AsRef<Utf8Path>>::as_ref(cargo_toml).with_extension("lock");
+            let target_lockfile = config
+                .target_dir
+                .join("rust-analyzer")
+                .join("metadata")
+                .join(config.kind)
+                .join("Cargo.lock");
+            match std::fs::copy(&lockfile, &target_lockfile) {
+                Ok(_) => {
+                    using_lockfile_copy = true;
+                    other_options.push("--lockfile-path".to_owned());
+                    other_options.push(target_lockfile.to_string());
+                }
+                Err(e) if e.kind() == std::io::ErrorKind::NotFound => {
+                    // There exists no lockfile yet
+                    using_lockfile_copy = true;
+                    other_options.push("--lockfile-path".to_owned());
+                    other_options.push(target_lockfile.to_string());
+                }
+                Err(e) => {
+                    tracing::warn!(
+                        "Failed to copy lock file from `{lockfile}` to `{target_lockfile}`: {e}",
+                    );
+                }
+            }
         }
-        if locked {
-            other_options.push("--locked".to_owned());
+        if using_lockfile_copy {
+            other_options.push("-Zunstable-options".to_owned());
+            meta.env("RUSTC_BOOTSTRAP", "1");
         }
-        if no_deps {
-            other_options.push("--no-deps".to_owned());
+        // No need to lock it if we copied the lockfile, we won't modify the original after all/
+        // This way cargo cannot error out on us if the lockfile requires updating.
+        if !using_lockfile_copy && locked {
+            other_options.push("--locked".to_owned());
         }
         meta.other_options(other_options);
 
         // FIXME: Fetching metadata is a slow process, as it might require
         // calling crates.io. We should be reporting progress here, but it's
         // unclear whether cargo itself supports it.
-        progress("metadata".to_owned());
-
-        (|| -> anyhow::Result<(_, _)> {
-            let output = meta.cargo_command().output()?;
+        progress("cargo metadata: started".to_owned());
+
+        let res = (|| -> anyhow::Result<(_, _)> {
+            let mut errored = false;
+            let output =
+                spawn_with_streaming_output(meta.cargo_command(), &mut |_| (), &mut |line| {
+                    errored = errored || line.starts_with("error") || line.starts_with("warning");
+                    if errored {
+                        progress("cargo metadata: ?".to_owned());
+                        return;
+                    }
+                    progress(format!("cargo metadata: {line}"));
+                })?;
             if !output.status.success() {
+                progress(format!("cargo metadata: failed {}", output.status));
                 let error = cargo_metadata::Error::CargoMetadata {
                     stderr: String::from_utf8(output.stderr)?,
                 }
@@ -416,8 +478,8 @@ impl CargoWorkspace {
                         current_dir,
                         config,
                         sysroot,
-                        locked,
                         true,
+                        locked,
                         progress,
                     ) {
                         return Ok((metadata, Some(error)));
@@ -431,7 +493,9 @@ impl CargoWorkspace {
                 .ok_or(cargo_metadata::Error::NoJson)?;
             Ok((cargo_metadata::MetadataCommand::parse(stdout)?, None))
         })()
-        .with_context(|| format!("Failed to run `{:?}`", meta.cargo_command()))
+        .with_context(|| format!("Failed to run `{:?}`", meta.cargo_command()));
+        progress("cargo metadata: finished".to_owned());
+        res
     }
 
     pub fn new(
diff --git a/src/tools/rust-analyzer/crates/project-model/src/manifest_path.rs b/src/tools/rust-analyzer/crates/project-model/src/manifest_path.rs
index 4f43be2f38f..fba8cc9709d 100644
--- a/src/tools/rust-analyzer/crates/project-model/src/manifest_path.rs
+++ b/src/tools/rust-analyzer/crates/project-model/src/manifest_path.rs
@@ -1,7 +1,7 @@
 //! See [`ManifestPath`].
 use std::{borrow::Borrow, fmt, ops};
 
-use paths::{AbsPath, AbsPathBuf};
+use paths::{AbsPath, AbsPathBuf, Utf8Path};
 
 /// More or less [`AbsPathBuf`] with non-None parent.
 ///
@@ -78,6 +78,12 @@ impl AsRef<std::ffi::OsStr> for ManifestPath {
     }
 }
 
+impl AsRef<Utf8Path> for ManifestPath {
+    fn as_ref(&self) -> &Utf8Path {
+        self.file.as_ref()
+    }
+}
+
 impl Borrow<AbsPath> for ManifestPath {
     fn borrow(&self) -> &AbsPath {
         self.file.borrow()
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 ebd86e3dc48..4b34fc00711 100644
--- a/src/tools/rust-analyzer/crates/project-model/src/sysroot.rs
+++ b/src/tools/rust-analyzer/crates/project-model/src/sysroot.rs
@@ -4,6 +4,7 @@
 //! 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 core::fmt;
 use std::{env, fs, ops::Not, path::Path, process::Command};
 
 use anyhow::{Result, format_err};
@@ -34,6 +35,19 @@ pub enum RustLibSrcWorkspace {
     Empty,
 }
 
+impl fmt::Display for RustLibSrcWorkspace {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        match self {
+            RustLibSrcWorkspace::Workspace(ws) => write!(f, "workspace {}", ws.workspace_root()),
+            RustLibSrcWorkspace::Json(json) => write!(f, "json {}", json.manifest_or_root()),
+            RustLibSrcWorkspace::Stitched(stitched) => {
+                write!(f, "stitched with {} crates", stitched.crates.len())
+            }
+            RustLibSrcWorkspace::Empty => write!(f, "empty"),
+        }
+    }
+}
+
 impl Sysroot {
     pub const fn empty() -> Sysroot {
         Sysroot {
@@ -195,6 +209,8 @@ impl Sysroot {
     pub fn load_workspace(
         &self,
         sysroot_source_config: &RustSourceWorkspaceConfig,
+        current_dir: &AbsPath,
+        progress: &dyn Fn(String),
     ) -> Option<RustLibSrcWorkspace> {
         assert!(matches!(self.workspace, RustLibSrcWorkspace::Empty), "workspace already loaded");
         let Self { root: _, rust_lib_src_root: Some(src_root), workspace: _, error: _ } = self
@@ -204,10 +220,16 @@ impl Sysroot {
         if let RustSourceWorkspaceConfig::CargoMetadata(cargo_config) = sysroot_source_config {
             let library_manifest = ManifestPath::try_from(src_root.join("Cargo.toml")).unwrap();
             if fs::metadata(&library_manifest).is_ok() {
-                if let Some(loaded) =
-                    self.load_library_via_cargo(library_manifest, src_root, cargo_config)
-                {
-                    return Some(loaded);
+                match self.load_library_via_cargo(
+                    &library_manifest,
+                    current_dir,
+                    cargo_config,
+                    progress,
+                ) {
+                    Ok(loaded) => return Some(loaded),
+                    Err(e) => {
+                        tracing::error!("`cargo metadata` failed on `{library_manifest}` : {e}")
+                    }
                 }
             }
             tracing::debug!("Stitching sysroot library: {src_root}");
@@ -293,10 +315,11 @@ impl Sysroot {
 
     fn load_library_via_cargo(
         &self,
-        library_manifest: ManifestPath,
-        rust_lib_src_dir: &AbsPathBuf,
+        library_manifest: &ManifestPath,
+        current_dir: &AbsPath,
         cargo_config: &CargoMetadataConfig,
-    ) -> Option<RustLibSrcWorkspace> {
+        progress: &dyn Fn(String),
+    ) -> Result<RustLibSrcWorkspace> {
         tracing::debug!("Loading library metadata: {library_manifest}");
         let mut cargo_config = cargo_config.clone();
         // the sysroot uses `public-dependency`, so we make cargo think it's a nightly
@@ -305,22 +328,16 @@ impl Sysroot {
             Some("nightly".to_owned()),
         );
 
-        let (mut res, _) = match CargoWorkspace::fetch_metadata(
-            &library_manifest,
-            rust_lib_src_dir,
+        let (mut res, _) = CargoWorkspace::fetch_metadata(
+            library_manifest,
+            current_dir,
             &cargo_config,
             self,
             false,
             // Make sure we never attempt to write to the sysroot
             true,
-            &|_| (),
-        ) {
-            Ok(it) => it,
-            Err(e) => {
-                tracing::error!("`cargo metadata` failed on `{library_manifest}` : {e}");
-                return None;
-            }
-        };
+            progress,
+        )?;
 
         // Patch out `rustc-std-workspace-*` crates to point to the real crates.
         // This is done prior to `CrateGraph` construction to prevent de-duplication logic from failing.
@@ -371,8 +388,9 @@ impl Sysroot {
             res.packages.remove(idx);
         });
 
-        let cargo_workspace = CargoWorkspace::new(res, library_manifest, Default::default(), true);
-        Some(RustLibSrcWorkspace::Workspace(cargo_workspace))
+        let cargo_workspace =
+            CargoWorkspace::new(res, library_manifest.clone(), Default::default(), true);
+        Ok(RustLibSrcWorkspace::Workspace(cargo_workspace))
     }
 }
 
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 c69891b7463..4f11af2d06c 100644
--- a/src/tools/rust-analyzer/crates/project-model/src/tests.rs
+++ b/src/tools/rust-analyzer/crates/project-model/src/tests.rs
@@ -1,3 +1,5 @@
+use std::env::temp_dir;
+
 use base_db::{CrateGraphBuilder, ProcMacroPaths};
 use cargo_metadata::Metadata;
 use cfg::{CfgAtom, CfgDiff};
@@ -235,11 +237,18 @@ fn smoke_test_real_sysroot_cargo() {
         AbsPath::assert(Utf8Path::new(env!("CARGO_MANIFEST_DIR"))),
         &Default::default(),
     );
-    let loaded_sysroot = sysroot.load_workspace(&RustSourceWorkspaceConfig::default_cargo());
+    let cwd = AbsPathBuf::assert_utf8(temp_dir().join("smoke_test_real_sysroot_cargo"));
+    std::fs::create_dir_all(&cwd).unwrap();
+    let loaded_sysroot =
+        sysroot.load_workspace(&RustSourceWorkspaceConfig::default_cargo(), &cwd, &|_| ());
     if let Some(loaded_sysroot) = loaded_sysroot {
         sysroot.set_workspace(loaded_sysroot);
     }
-    assert!(matches!(sysroot.workspace(), RustLibSrcWorkspace::Workspace(_)));
+    assert!(
+        matches!(sysroot.workspace(), RustLibSrcWorkspace::Workspace(_)),
+        "got {}",
+        sysroot.workspace()
+    );
     let project_workspace = ProjectWorkspace {
         kind: ProjectWorkspaceKind::Cargo {
             cargo: cargo_workspace,
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 eec0077ea6e..a6743a32b14 100644
--- a/src/tools/rust-analyzer/crates/project-model/src/workspace.rs
+++ b/src/tools/rust-analyzer/crates/project-model/src/workspace.rs
@@ -12,7 +12,7 @@ use base_db::{
 };
 use cfg::{CfgAtom, CfgDiff, CfgOptions};
 use intern::{Symbol, sym};
-use paths::{AbsPath, AbsPathBuf};
+use paths::{AbsPath, AbsPathBuf, Utf8PathBuf};
 use rustc_hash::{FxHashMap, FxHashSet};
 use semver::Version;
 use span::{Edition, FileId};
@@ -170,7 +170,7 @@ impl ProjectWorkspace {
     pub fn load(
         manifest: ProjectManifest,
         config: &CargoConfig,
-        progress: &dyn Fn(String),
+        progress: &(dyn Fn(String) + Sync),
     ) -> anyhow::Result<ProjectWorkspace> {
         ProjectWorkspace::load_inner(&manifest, config, progress)
             .with_context(|| format!("Failed to load the project at {manifest}"))
@@ -179,7 +179,7 @@ impl ProjectWorkspace {
     fn load_inner(
         manifest: &ProjectManifest,
         config: &CargoConfig,
-        progress: &dyn Fn(String),
+        progress: &(dyn Fn(String) + Sync),
     ) -> anyhow::Result<ProjectWorkspace> {
         let res = match manifest {
             ProjectManifest::ProjectJson(project_json) => {
@@ -206,9 +206,10 @@ impl ProjectWorkspace {
     fn load_cargo(
         cargo_toml: &ManifestPath,
         config: &CargoConfig,
-        progress: &dyn Fn(String),
+        progress: &(dyn Fn(String) + Sync),
     ) -> Result<ProjectWorkspace, anyhow::Error> {
         progress("Discovering sysroot".to_owned());
+        let workspace_dir = cargo_toml.parent();
         let CargoConfig {
             features,
             rustc_source,
@@ -224,15 +225,9 @@ impl ProjectWorkspace {
             ..
         } = config;
         let mut sysroot = match (sysroot, sysroot_src) {
-            (Some(RustLibSource::Discover), None) => {
-                Sysroot::discover(cargo_toml.parent(), extra_env)
-            }
+            (Some(RustLibSource::Discover), None) => Sysroot::discover(workspace_dir, extra_env),
             (Some(RustLibSource::Discover), Some(sysroot_src)) => {
-                Sysroot::discover_with_src_override(
-                    cargo_toml.parent(),
-                    extra_env,
-                    sysroot_src.clone(),
-                )
+                Sysroot::discover_with_src_override(workspace_dir, extra_env, sysroot_src.clone())
             }
             (Some(RustLibSource::Path(path)), None) => {
                 Sysroot::discover_rust_lib_src_dir(path.clone())
@@ -248,24 +243,23 @@ impl ProjectWorkspace {
         let toolchain_config = QueryConfig::Cargo(&sysroot, cargo_toml);
         let targets =
             target_tuple::get(toolchain_config, target.as_deref(), extra_env).unwrap_or_default();
+        let toolchain = version::get(toolchain_config, extra_env)
+            .inspect_err(|e| {
+                tracing::error!(%e,
+                    "failed fetching toolchain version for {cargo_toml:?} workspace"
+                )
+            })
+            .ok()
+            .flatten();
+
+        let target_dir =
+            config.target_dir.clone().unwrap_or_else(|| workspace_dir.join("target").into());
 
         // We spawn a bunch of processes to query various information about the workspace's
         // toolchain and sysroot
         // We can speed up loading a bit by spawning all of these processes in parallel (especially
         // on systems were process spawning is delayed)
         let join = thread::scope(|s| {
-            let workspace_dir = cargo_toml.parent();
-            let toolchain = s.spawn(|| {
-                version::get(toolchain_config, extra_env)
-                    .inspect_err(|e| {
-                        tracing::error!(%e,
-                            "failed fetching toolchain version for {cargo_toml:?} workspace"
-                        )
-                    })
-                    .ok()
-                    .flatten()
-            });
-
             let rustc_cfg = s.spawn(|| {
                 rustc_cfg::get(toolchain_config, targets.first().map(Deref::deref), extra_env)
             });
@@ -300,11 +294,14 @@ impl ProjectWorkspace {
                             targets: targets.clone(),
                             extra_args: extra_args.clone(),
                             extra_env: extra_env.clone(),
+                            target_dir: target_dir.clone(),
+                            toolchain_version: toolchain.clone(),
+                            kind: "rustc-dev"
                         },
                         &sysroot,
                         *no_deps,
-                        false,
-                        &|_| (),
+                        true,
+                        progress,
                     ) {
                         Ok((meta, _error)) => {
                             let workspace = CargoWorkspace::new(
@@ -343,22 +340,31 @@ impl ProjectWorkspace {
                         targets: targets.clone(),
                         extra_args: extra_args.clone(),
                         extra_env: extra_env.clone(),
+                        target_dir: target_dir.clone(),
+                        toolchain_version: toolchain.clone(),
+                        kind: "workspace",
                     },
                     &sysroot,
                     *no_deps,
                     false,
-                    &|_| (),
+                    progress,
                 )
             });
             let loaded_sysroot = s.spawn(|| {
-                sysroot.load_workspace(&RustSourceWorkspaceConfig::CargoMetadata(
-                    sysroot_metadata_config(extra_env, &targets),
-                ))
+                sysroot.load_workspace(
+                    &RustSourceWorkspaceConfig::CargoMetadata(sysroot_metadata_config(
+                        config,
+                        &targets,
+                        toolchain.clone(),
+                        target_dir.clone(),
+                    )),
+                    workspace_dir,
+                    progress,
+                )
             });
             let cargo_config_extra_env =
                 s.spawn(|| cargo_config_env(cargo_toml, extra_env, &sysroot));
             thread::Result::Ok((
-                toolchain.join()?,
                 rustc_cfg.join()?,
                 data_layout.join()?,
                 rustc_dir.join()?,
@@ -368,18 +374,11 @@ impl ProjectWorkspace {
             ))
         });
 
-        let (
-            toolchain,
-            rustc_cfg,
-            data_layout,
-            rustc,
-            loaded_sysroot,
-            cargo_metadata,
-            cargo_config_extra_env,
-        ) = match join {
-            Ok(it) => it,
-            Err(e) => std::panic::resume_unwind(e),
-        };
+        let (rustc_cfg, data_layout, rustc, loaded_sysroot, cargo_metadata, cargo_config_extra_env) =
+            match join {
+                Ok(it) => it,
+                Err(e) => std::panic::resume_unwind(e),
+            };
 
         let (meta, error) = cargo_metadata.with_context(|| {
             format!(
@@ -388,6 +387,7 @@ impl ProjectWorkspace {
         })?;
         let cargo = CargoWorkspace::new(meta, cargo_toml.clone(), cargo_config_extra_env, false);
         if let Some(loaded_sysroot) = loaded_sysroot {
+            tracing::info!(src_root = ?sysroot.rust_lib_src_root(), root = %loaded_sysroot, "Loaded sysroot");
             sysroot.set_workspace(loaded_sysroot);
         }
 
@@ -411,7 +411,7 @@ impl ProjectWorkspace {
     pub fn load_inline(
         mut project_json: ProjectJson,
         config: &CargoConfig,
-        progress: &dyn Fn(String),
+        progress: &(dyn Fn(String) + Sync),
     ) -> ProjectWorkspace {
         progress("Discovering sysroot".to_owned());
         let mut sysroot =
@@ -423,14 +423,13 @@ impl ProjectWorkspace {
         let query_config = QueryConfig::Rustc(&sysroot, project_json.path().as_ref());
         let targets = target_tuple::get(query_config, config.target.as_deref(), &config.extra_env)
             .unwrap_or_default();
+        let toolchain = version::get(query_config, &config.extra_env).ok().flatten();
 
         // We spawn a bunch of processes to query various information about the workspace's
         // toolchain and sysroot
         // We can speed up loading a bit by spawning all of these processes in parallel (especially
         // on systems were process spawning is delayed)
         let join = thread::scope(|s| {
-            let toolchain =
-                s.spawn(|| version::get(query_config, &config.extra_env).ok().flatten());
             let rustc_cfg = s.spawn(|| {
                 rustc_cfg::get(query_config, targets.first().map(Deref::deref), &config.extra_env)
             });
@@ -442,24 +441,35 @@ impl ProjectWorkspace {
                 )
             });
             let loaded_sysroot = s.spawn(|| {
+                let project_root = project_json.project_root();
                 if let Some(sysroot_project) = sysroot_project {
-                    sysroot.load_workspace(&RustSourceWorkspaceConfig::Json(*sysroot_project))
+                    sysroot.load_workspace(
+                        &RustSourceWorkspaceConfig::Json(*sysroot_project),
+                        project_root,
+                        progress,
+                    )
                 } else {
-                    sysroot.load_workspace(&RustSourceWorkspaceConfig::CargoMetadata(
-                        sysroot_metadata_config(&config.extra_env, &targets),
-                    ))
+                    let target_dir = config
+                        .target_dir
+                        .clone()
+                        .unwrap_or_else(|| project_root.join("target").into());
+                    sysroot.load_workspace(
+                        &RustSourceWorkspaceConfig::CargoMetadata(sysroot_metadata_config(
+                            config,
+                            &targets,
+                            toolchain.clone(),
+                            target_dir,
+                        )),
+                        project_root,
+                        progress,
+                    )
                 }
             });
 
-            thread::Result::Ok((
-                toolchain.join()?,
-                rustc_cfg.join()?,
-                data_layout.join()?,
-                loaded_sysroot.join()?,
-            ))
+            thread::Result::Ok((rustc_cfg.join()?, data_layout.join()?, loaded_sysroot.join()?))
         });
 
-        let (toolchain, rustc_cfg, target_layout, loaded_sysroot) = match join {
+        let (rustc_cfg, target_layout, loaded_sysroot) = match join {
             Ok(it) => it,
             Err(e) => std::panic::resume_unwind(e),
         };
@@ -497,9 +507,17 @@ impl ProjectWorkspace {
             .unwrap_or_default();
         let rustc_cfg = rustc_cfg::get(query_config, None, &config.extra_env);
         let data_layout = target_data_layout::get(query_config, None, &config.extra_env);
-        let loaded_sysroot = sysroot.load_workspace(&RustSourceWorkspaceConfig::CargoMetadata(
-            sysroot_metadata_config(&config.extra_env, &targets),
-        ));
+        let target_dir = config.target_dir.clone().unwrap_or_else(|| dir.join("target").into());
+        let loaded_sysroot = sysroot.load_workspace(
+            &RustSourceWorkspaceConfig::CargoMetadata(sysroot_metadata_config(
+                config,
+                &targets,
+                toolchain.clone(),
+                target_dir.clone(),
+            )),
+            dir,
+            &|_| (),
+        );
         if let Some(loaded_sysroot) = loaded_sysroot {
             sysroot.set_workspace(loaded_sysroot);
         }
@@ -512,6 +530,9 @@ impl ProjectWorkspace {
                 targets,
                 extra_args: config.extra_args.clone(),
                 extra_env: config.extra_env.clone(),
+                target_dir,
+                toolchain_version: toolchain.clone(),
+                kind: "detached-file",
             },
             &sysroot,
             config.no_deps,
@@ -1804,13 +1825,18 @@ fn add_dep_inner(graph: &mut CrateGraphBuilder, from: CrateBuilderId, dep: Depen
 }
 
 fn sysroot_metadata_config(
-    extra_env: &FxHashMap<String, Option<String>>,
+    config: &CargoConfig,
     targets: &[String],
+    toolchain_version: Option<Version>,
+    target_dir: Utf8PathBuf,
 ) -> CargoMetadataConfig {
     CargoMetadataConfig {
         features: Default::default(),
         targets: targets.to_vec(),
         extra_args: Default::default(),
-        extra_env: extra_env.clone(),
+        extra_env: config.extra_env.clone(),
+        target_dir,
+        toolchain_version,
+        kind: "sysroot",
     }
 }
diff --git a/src/tools/rust-analyzer/crates/query-group-macro/src/queries.rs b/src/tools/rust-analyzer/crates/query-group-macro/src/queries.rs
index baac3e8bbfe..c151cca0727 100644
--- a/src/tools/rust-analyzer/crates/query-group-macro/src/queries.rs
+++ b/src/tools/rust-analyzer/crates/query-group-macro/src/queries.rs
@@ -74,8 +74,8 @@ impl ToTokens for TrackedQuery {
                 quote! {
                     #sig {
                         #annotation
-                        fn #shim(
-                            db: &dyn #trait_name,
+                        fn #shim<'db>(
+                            db: &'db dyn #trait_name,
                             _input: #input_struct_name,
                             #(#pat_and_tys),*
                         ) #ret
@@ -88,8 +88,8 @@ impl ToTokens for TrackedQuery {
                 quote! {
                     #sig {
                         #annotation
-                        fn #shim(
-                            db: &dyn #trait_name,
+                        fn #shim<'db>(
+                            db: &'db dyn #trait_name,
                             #(#pat_and_tys),*
                         ) #ret
                             #invoke_block
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 12b393b80c0..0ee01982fea 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
@@ -532,7 +532,7 @@ impl flags::AnalysisStats {
                 }
 
                 let todo = syntax::ast::make::ext::expr_todo().to_string();
-                let mut formatter = |_: &hir::Type| todo.clone();
+                let mut formatter = |_: &hir::Type<'_>| todo.clone();
                 let mut syntax_hit_found = false;
                 for term in found_terms {
                     let generated = term
diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/rustc_tests.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/rustc_tests.rs
index e3b372c9149..740fcd81ea9 100644
--- a/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/rustc_tests.rs
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/rustc_tests.rs
@@ -9,7 +9,6 @@ use hir::{ChangeWithProcMacros, Crate};
 use ide::{AnalysisHost, DiagnosticCode, DiagnosticsConfig};
 use ide_db::base_db;
 use itertools::Either;
-use paths::Utf8PathBuf;
 use profile::StopWatch;
 use project_model::toolchain_info::{QueryConfig, target_data_layout};
 use project_model::{
@@ -64,9 +63,9 @@ fn detect_errors_from_rustc_stderr_file(p: PathBuf) -> FxHashMap<DiagnosticCode,
 
 impl Tester {
     fn new() -> Result<Self> {
-        let mut path = std::env::temp_dir();
-        path.push("ra-rustc-test.rs");
-        let tmp_file = AbsPathBuf::try_from(Utf8PathBuf::from_path_buf(path).unwrap()).unwrap();
+        let mut path = AbsPathBuf::assert_utf8(std::env::temp_dir());
+        path.push("ra-rustc-test");
+        let tmp_file = path.join("ra-rustc-test.rs");
         std::fs::write(&tmp_file, "")?;
         let cargo_config = CargoConfig {
             sysroot: Some(RustLibSource::Discover),
@@ -76,7 +75,8 @@ impl Tester {
         };
 
         let mut sysroot = Sysroot::discover(tmp_file.parent().unwrap(), &cargo_config.extra_env);
-        let loaded_sysroot = sysroot.load_workspace(&RustSourceWorkspaceConfig::default_cargo());
+        let loaded_sysroot =
+            sysroot.load_workspace(&RustSourceWorkspaceConfig::default_cargo(), &path, &|_| ());
         if let Some(loaded_sysroot) = loaded_sysroot {
             sysroot.set_workspace(loaded_sysroot);
         }
diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/config.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/config.rs
index 762b63f54b0..05e1b832cd1 100644
--- a/src/tools/rust-analyzer/crates/rust-analyzer/src/config.rs
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/config.rs
@@ -452,6 +452,8 @@ config_data! {
         assist_emitMustUse: bool               = false,
         /// Placeholder expression to use for missing expressions in assists.
         assist_expressionFillDefault: ExprFillDefaultDef              = ExprFillDefaultDef::Todo,
+        /// When inserting a type (e.g. in "fill match arms" assist), prefer to use `Self` over the type name where possible.
+        assist_preferSelf: bool = false,
         /// Enable borrow checking for term search code assists. If set to false, also there will be more suggestions, but some of them may not borrow-check.
         assist_termSearch_borrowcheck: bool = true,
         /// Term search fuel in "units of work" for assists (Defaults to 1800).
@@ -760,7 +762,11 @@ config_data! {
         /// though Cargo might be the eventual consumer.
         vfs_extraIncludes: Vec<String> = vec![],
 
-        /// Exclude imports from symbol search.
+        /// Exclude all imports from workspace symbol search.
+        ///
+        /// In addition to regular imports (which are always excluded),
+        /// this option removes public imports (better known as re-exports)
+        /// and removes imports that rename the imported symbol.
         workspace_symbol_search_excludeImports: bool = false,
         /// Workspace symbol search kind.
         workspace_symbol_search_kind: WorkspaceSymbolSearchKindDef = WorkspaceSymbolSearchKindDef::OnlyTypes,
@@ -1505,6 +1511,7 @@ impl Config {
                 ExprFillDefaultDef::Default => ExprFillDefaultMode::Default,
                 ExprFillDefaultDef::Underscore => ExprFillDefaultMode::Underscore,
             },
+            prefer_self_ty: *self.assist_preferSelf(source_root),
         }
     }
 
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 b7373f274f0..200e972e428 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
@@ -239,7 +239,7 @@ pub(crate) fn handle_did_change_configuration(
                         let (config, e, _) = config.apply_change(change);
                         this.config_errors = e.is_empty().not().then_some(e);
 
-                        // Client config changes neccesitates .update_config method to be called.
+                        // Client config changes necessitates .update_config method to be called.
                         this.update_configuration(config);
                     }
                 }
diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/lsp/capabilities.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/lsp/capabilities.rs
index 418fe957590..04e31f37fd2 100644
--- a/src/tools/rust-analyzer/crates/rust-analyzer/src/lsp/capabilities.rs
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/lsp/capabilities.rs
@@ -77,7 +77,7 @@ pub fn server_capabilities(config: &Config) -> ServerCapabilities {
             _ => Some(OneOf::Left(false)),
         },
         document_on_type_formatting_provider: Some({
-            let mut chars = ide::Analysis::SUPPORTED_TRIGGER_CHARS.chars();
+            let mut chars = ide::Analysis::SUPPORTED_TRIGGER_CHARS.iter();
             DocumentOnTypeFormattingOptions {
                 first_trigger_character: chars.next().unwrap().to_string(),
                 more_trigger_character: Some(chars.map(|c| c.to_string()).collect()),
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 4677880daaf..189d95ec7ed 100644
--- a/src/tools/rust-analyzer/crates/rust-analyzer/src/reload.rs
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/reload.rs
@@ -114,6 +114,16 @@ impl GlobalState {
                 Durability::HIGH,
             );
         }
+
+        if self.config.cargo(None) != old_config.cargo(None) {
+            let req = FetchWorkspaceRequest { path: None, force_crate_graph_reload: false };
+            self.fetch_workspaces_queue.request_op("cargo config changed".to_owned(), req)
+        }
+
+        if self.config.cfg_set_test(None) != old_config.cfg_set_test(None) {
+            let req = FetchWorkspaceRequest { path: None, force_crate_graph_reload: false };
+            self.fetch_workspaces_queue.request_op("cfg_set_test config changed".to_owned(), req)
+        }
     }
 
     pub(crate) fn current_status(&self) -> lsp_ext::ServerStatusParams {
diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/test_runner.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/test_runner.rs
index 9c0bc33af64..e7528dbc939 100644
--- a/src/tools/rust-analyzer/crates/rust-analyzer/src/test_runner.rs
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/test_runner.rs
@@ -103,6 +103,7 @@ impl CargoTestHandle {
     ) -> std::io::Result<Self> {
         let mut cmd = toolchain::command(Tool::Cargo.path(), root, &options.extra_env);
         cmd.env("RUSTC_BOOTSTRAP", "1");
+        cmd.arg("--color=always");
         cmd.arg("test");
 
         cmd.arg("--package");
diff --git a/src/tools/rust-analyzer/crates/stdx/src/lib.rs b/src/tools/rust-analyzer/crates/stdx/src/lib.rs
index 9a292eacd7f..978c50d807b 100644
--- a/src/tools/rust-analyzer/crates/stdx/src/lib.rs
+++ b/src/tools/rust-analyzer/crates/stdx/src/lib.rs
@@ -13,6 +13,7 @@ pub mod panic_context;
 pub mod process;
 pub mod rand;
 pub mod thread;
+pub mod variance;
 
 pub use itertools;
 
diff --git a/src/tools/rust-analyzer/crates/stdx/src/variance.rs b/src/tools/rust-analyzer/crates/stdx/src/variance.rs
new file mode 100644
index 00000000000..8465d72bf37
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/stdx/src/variance.rs
@@ -0,0 +1,270 @@
+//! This is a copy of [`std::marker::variance`].
+
+use std::any::type_name;
+use std::cmp::Ordering;
+use std::fmt;
+use std::hash::{Hash, Hasher};
+use std::marker::PhantomData;
+
+macro_rules! first_token {
+    ($first:tt $($rest:tt)*) => {
+        $first
+    };
+}
+macro_rules! phantom_type {
+    ($(
+        $(#[$attr:meta])*
+        pub struct $name:ident <$t:ident> ($($inner:tt)*);
+    )*) => {$(
+        $(#[$attr])*
+        pub struct $name<$t>($($inner)*) where T: ?Sized;
+
+        impl<T> $name<T>
+            where T: ?Sized
+        {
+            /// Constructs a new instance of the variance marker.
+            pub const fn new() -> Self {
+                Self(PhantomData)
+            }
+        }
+
+        impl<T> self::sealed::Sealed for $name<T> where T: ?Sized {
+            const VALUE: Self = Self::new();
+        }
+
+        impl<T> Variance for $name<T> where T: ?Sized {}
+
+        impl<T> Default for $name<T>
+            where T: ?Sized
+        {
+            fn default() -> Self {
+                Self(PhantomData)
+            }
+        }
+
+        impl<T> fmt::Debug for $name<T>
+            where T: ?Sized
+        {
+            fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+                write!(f, "{}<{}>", stringify!($name), type_name::<T>())
+            }
+        }
+
+        impl<T> Clone for $name<T>
+            where T: ?Sized
+        {
+            fn clone(&self) -> Self {
+                *self
+            }
+        }
+
+        impl<T> Copy for $name<T> where T: ?Sized {}
+
+        impl<T> PartialEq for $name<T>
+            where T: ?Sized
+        {
+            fn eq(&self, _: &Self) -> bool {
+                true
+            }
+        }
+
+        impl<T> Eq for $name<T> where T: ?Sized {}
+
+        #[allow(clippy::non_canonical_partial_ord_impl)]
+        impl<T> PartialOrd for $name<T>
+            where T: ?Sized
+        {
+            fn partial_cmp(&self, _: &Self) -> Option<Ordering> {
+                Some(Ordering::Equal)
+            }
+        }
+
+        impl<T> Ord for $name<T>
+            where T: ?Sized
+        {
+            fn cmp(&self, _: &Self) -> Ordering {
+                Ordering::Equal
+            }
+        }
+
+        impl<T> Hash for $name<T>
+            where T: ?Sized
+        {
+            fn hash<H: Hasher>(&self, _: &mut H) {}
+        }
+    )*};
+}
+
+macro_rules! phantom_lifetime {
+    ($(
+        $(#[$attr:meta])*
+        pub struct $name:ident <$lt:lifetime> ($($inner:tt)*);
+    )*) => {$(
+        $(#[$attr])*
+
+        #[derive(Default, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
+        pub struct $name<$lt>($($inner)*);
+
+        impl $name<'_> {
+            /// Constructs a new instance of the variance marker.
+            pub const fn new() -> Self {
+                Self(first_token!($($inner)*)(PhantomData))
+            }
+        }
+
+        impl self::sealed::Sealed for $name<'_> {
+            const VALUE: Self = Self::new();
+        }
+
+        impl Variance for $name<'_> {}
+
+        impl fmt::Debug for $name<'_> {
+            fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+                write!(f, "{}", stringify!($name))
+            }
+        }
+    )*};
+}
+
+phantom_lifetime! {
+    /// Zero-sized type used to mark a lifetime as covariant.
+    ///
+    /// Covariant lifetimes must live at least as long as declared. See [the reference][1] for more
+    /// information.
+    ///
+    /// [1]: https://doc.rust-lang.org/stable/reference/subtyping.html#variance
+    ///
+    /// ## Layout
+    ///
+    /// For all `'a`, the following are guaranteed:
+    /// * `size_of::<PhantomCovariantLifetime<'a>>() == 0`
+    /// * `align_of::<PhantomCovariantLifetime<'a>>() == 1`
+
+    pub struct PhantomCovariantLifetime<'a>(PhantomCovariant<&'a ()>);
+    /// Zero-sized type used to mark a lifetime as contravariant.
+    ///
+    /// Contravariant lifetimes must live at most as long as declared. See [the reference][1] for
+    /// more information.
+    ///
+    /// [1]: https://doc.rust-lang.org/stable/reference/subtyping.html#variance
+    ///
+    /// ## Layout
+    ///
+    /// For all `'a`, the following are guaranteed:
+    /// * `size_of::<PhantomContravariantLifetime<'a>>() == 0`
+    /// * `align_of::<PhantomContravariantLifetime<'a>>() == 1`
+
+    pub struct PhantomContravariantLifetime<'a>(PhantomContravariant<&'a ()>);
+    /// Zero-sized type used to mark a lifetime as invariant.
+    ///
+    /// Invariant lifetimes must be live for the exact length declared, neither shorter nor longer.
+    /// See [the reference][1] for more information.
+    ///
+    /// [1]: https://doc.rust-lang.org/stable/reference/subtyping.html#variance
+    ///
+    /// ## Layout
+    ///
+    /// For all `'a`, the following are guaranteed:
+    /// * `size_of::<PhantomInvariantLifetime<'a>>() == 0`
+    /// * `align_of::<PhantomInvariantLifetime<'a>>() == 1`
+
+    pub struct PhantomInvariantLifetime<'a>(PhantomInvariant<&'a ()>);
+
+}
+
+phantom_type! {
+    /// Zero-sized type used to mark a type parameter as covariant.
+    ///
+    /// Types used as part of the return value from a function are covariant. If the type is _also_
+    /// passed as a parameter then it is [invariant][PhantomInvariant]. See [the reference][1] for
+    /// more information.
+    ///
+    /// [1]: https://doc.rust-lang.org/stable/reference/subtyping.html#variance
+    ///
+    /// ## Layout
+    ///
+    /// For all `T`, the following are guaranteed:
+    /// * `size_of::<PhantomCovariant<T>>() == 0`
+    /// * `align_of::<PhantomCovariant<T>>() == 1`
+
+    pub struct PhantomCovariant<T>(PhantomData<fn() -> T>);
+    /// Zero-sized type used to mark a type parameter as contravariant.
+    ///
+    /// Types passed as arguments to a function are contravariant. If the type is _also_ part of the
+    /// return value from a function then it is [invariant][PhantomInvariant]. See [the
+    /// reference][1] for more information.
+    ///
+    /// [1]: https://doc.rust-lang.org/stable/reference/subtyping.html#variance
+    ///
+    /// ## Layout
+    ///
+    /// For all `T`, the following are guaranteed:
+    /// * `size_of::<PhantomContravariant<T>>() == 0`
+    /// * `align_of::<PhantomContravariant<T>>() == 1`
+
+    pub struct PhantomContravariant<T>(PhantomData<fn(T)>);
+    /// Zero-sized type used to mark a type parameter as invariant.
+    ///
+    /// Types that are both passed as an argument _and_ used as part of the return value from a
+    /// function are invariant. See [the reference][1] for more information.
+    ///
+    /// [1]: https://doc.rust-lang.org/stable/reference/subtyping.html#variance
+    ///
+    /// ## Layout
+    ///
+    /// For all `T`, the following are guaranteed:
+    /// * `size_of::<PhantomInvariant<T>>() == 0`
+    /// * `align_of::<PhantomInvariant<T>>() == 1`
+
+    pub struct PhantomInvariant<T>(PhantomData<fn(T) -> T>);
+
+}
+
+mod sealed {
+
+    pub trait Sealed {
+        const VALUE: Self;
+    }
+}
+/// A marker trait for phantom variance types.
+pub trait Variance: sealed::Sealed + Default {}
+/// Construct a variance marker; equivalent to [`Default::default`].
+///
+/// This type can be any of the following. You generally should not need to explicitly name the
+/// type, however.
+///
+/// - [`PhantomCovariant`]
+/// - [`PhantomContravariant`]
+/// - [`PhantomInvariant`]
+/// - [`PhantomCovariantLifetime`]
+/// - [`PhantomContravariantLifetime`]
+/// - [`PhantomInvariantLifetime`]
+///
+/// # Example
+///
+/// ```rust
+/// #![feature(phantom_variance_markers)]
+///
+/// use core::marker::{PhantomCovariant, variance};
+///
+/// struct BoundFn<F, P, R>
+/// where
+///     F: Fn(P) -> R,
+/// {
+///     function: F,
+///     parameter: P,
+///     return_value: PhantomCovariant<R>,
+/// }
+///
+/// let bound_fn = BoundFn {
+///     function: core::convert::identity,
+///     parameter: 5u8,
+///     return_value: variance(),
+/// };
+/// ```
+pub const fn variance<T>() -> T
+where
+    T: Variance,
+{
+    T::VALUE
+}
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 fab4cb287c3..955aadaa25d 100644
--- a/src/tools/rust-analyzer/crates/syntax/src/ast/make.rs
+++ b/src/tools/rust-analyzer/crates/syntax/src/ast/make.rs
@@ -134,6 +134,13 @@ pub fn name_ref(name_ref: &str) -> ast::NameRef {
         }
     }
 }
+pub fn name_ref_self_ty() -> ast::NameRef {
+    quote! {
+        NameRef {
+            [Self]
+        }
+    }
+}
 fn raw_ident_esc(ident: &str) -> &'static str {
     if is_raw_identifier(ident, Edition::CURRENT) { "r#" } else { "" }
 }
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 7240069753e..1d821e96e55 100644
--- a/src/tools/rust-analyzer/crates/test-utils/src/fixture.rs
+++ b/src/tools/rust-analyzer/crates/test-utils/src/fixture.rs
@@ -412,22 +412,36 @@ impl MiniCore {
         }
 
         let mut active_regions = Vec::new();
+        let mut inactive_regions = Vec::new();
         let mut seen_regions = Vec::new();
         for line in lines {
             let trimmed = line.trim();
             if let Some(region) = trimmed.strip_prefix("// region:") {
-                active_regions.push(region);
-                continue;
+                if let Some(region) = region.strip_prefix('!') {
+                    inactive_regions.push(region);
+                    continue;
+                } else {
+                    active_regions.push(region);
+                    continue;
+                }
             }
             if let Some(region) = trimmed.strip_prefix("// endregion:") {
-                let prev = active_regions.pop().unwrap();
+                let (prev, region) = if let Some(region) = region.strip_prefix('!') {
+                    (inactive_regions.pop().unwrap(), region)
+                } else {
+                    (active_regions.pop().unwrap(), region)
+                };
                 assert_eq!(prev, region, "unbalanced region pairs");
                 continue;
             }
 
-            let mut line_region = false;
-            if let Some(idx) = trimmed.find("// :") {
-                line_region = true;
+            let mut active_line_region = false;
+            let mut inactive_line_region = false;
+            if let Some(idx) = trimmed.find("// :!") {
+                inactive_line_region = true;
+                inactive_regions.push(&trimmed[idx + "// :!".len()..]);
+            } else if let Some(idx) = trimmed.find("// :") {
+                active_line_region = true;
                 active_regions.push(&trimmed[idx + "// :".len()..]);
             }
 
@@ -438,18 +452,30 @@ impl MiniCore {
                 seen_regions.push(region);
                 keep &= self.has_flag(region);
             }
+            for &region in &inactive_regions {
+                assert!(!region.starts_with(' '), "region marker starts with a space: {region:?}");
+                self.assert_valid_flag(region);
+                seen_regions.push(region);
+                keep &= !self.has_flag(region);
+            }
 
             if keep {
                 buf.push_str(line);
             }
-            if line_region {
+            if active_line_region {
                 active_regions.pop().unwrap();
             }
+            if inactive_line_region {
+                inactive_regions.pop().unwrap();
+            }
         }
 
         if !active_regions.is_empty() {
             panic!("unclosed regions: {active_regions:?} Add an `endregion` comment");
         }
+        if !inactive_regions.is_empty() {
+            panic!("unclosed regions: {inactive_regions:?} Add an `endregion` comment");
+        }
 
         for flag in &self.valid_flags {
             if !seen_regions.iter().any(|it| it == flag) {
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 4bdd791eb16..d13a81d287f 100644
--- a/src/tools/rust-analyzer/crates/test-utils/src/minicore.rs
+++ b/src/tools/rust-analyzer/crates/test-utils/src/minicore.rs
@@ -31,6 +31,7 @@
 //!     eq: sized
 //!     error: fmt
 //!     fmt: option, result, transmute, coerce_unsized, copy, clone, derive
+//!     fmt_before_1_89_0: fmt
 //!     fn: tuple
 //!     from: sized, result
 //!     future: pin
@@ -1175,6 +1176,7 @@ pub mod fmt {
             }
         }
 
+        // region:fmt_before_1_89_0
         #[lang = "format_unsafe_arg"]
         pub struct UnsafeArg {
             _private: (),
@@ -1185,6 +1187,7 @@ pub mod fmt {
                 UnsafeArg { _private: () }
             }
         }
+        // endregion:fmt_before_1_89_0
     }
 
     #[derive(Copy, Clone)]
@@ -1204,6 +1207,7 @@ pub mod fmt {
             Arguments { pieces, fmt: None, args: &[] }
         }
 
+        // region:fmt_before_1_89_0
         pub fn new_v1_formatted(
             pieces: &'a [&'static str],
             args: &'a [rt::Argument<'a>],
@@ -1212,6 +1216,17 @@ pub mod fmt {
         ) -> Arguments<'a> {
             Arguments { pieces, fmt: Some(fmt), args }
         }
+        // endregion:fmt_before_1_89_0
+
+        // region:!fmt_before_1_89_0
+        pub unsafe fn new_v1_formatted(
+            pieces: &'a [&'static str],
+            args: &'a [rt::Argument<'a>],
+            fmt: &'a [rt::Placeholder],
+        ) -> Arguments<'a> {
+            Arguments { pieces, fmt: Some(fmt), args }
+        }
+        // endregion:!fmt_before_1_89_0
 
         pub const fn as_str(&self) -> Option<&'static str> {
             match (self.pieces, self.args) {
diff --git a/src/tools/rust-analyzer/docs/book/src/configuration_generated.md b/src/tools/rust-analyzer/docs/book/src/configuration_generated.md
index 4eb9cfc4e5b..9404b1454a0 100644
--- a/src/tools/rust-analyzer/docs/book/src/configuration_generated.md
+++ b/src/tools/rust-analyzer/docs/book/src/configuration_generated.md
@@ -13,6 +13,13 @@ Default: `"todo"`
 Placeholder expression to use for missing expressions in assists.
 
 
+## rust-analyzer.assist.preferSelf {#assist.preferSelf}
+
+Default: `false`
+
+When inserting a type (e.g. in "fill match arms" assist), prefer to use `Self` over the type name where possible.
+
+
 ## rust-analyzer.assist.termSearch.borrowcheck {#assist.termSearch.borrowcheck}
 
 Default: `true`
@@ -1535,7 +1542,11 @@ https://github.com/facebook/buck2/tree/main/integrations/rust-project.
 
 Default: `false`
 
-Exclude imports from symbol search.
+Exclude all imports from workspace symbol search.
+
+In addition to regular imports (which are always excluded),
+this option removes public imports (better known as re-exports)
+and removes imports that rename the imported symbol.
 
 
 ## rust-analyzer.workspace.symbol.search.kind {#workspace.symbol.search.kind}
diff --git a/src/tools/rust-analyzer/editors/code/package.json b/src/tools/rust-analyzer/editors/code/package.json
index dcdb4fe30ee..26a21c1468d 100644
--- a/src/tools/rust-analyzer/editors/code/package.json
+++ b/src/tools/rust-analyzer/editors/code/package.json
@@ -683,6 +683,16 @@
             {
                 "title": "assist",
                 "properties": {
+                    "rust-analyzer.assist.preferSelf": {
+                        "markdownDescription": "When inserting a type (e.g. in \"fill match arms\" assist), prefer to use `Self` over the type name where possible.",
+                        "default": false,
+                        "type": "boolean"
+                    }
+                }
+            },
+            {
+                "title": "assist",
+                "properties": {
                     "rust-analyzer.assist.termSearch.borrowcheck": {
                         "markdownDescription": "Enable borrow checking for term search code assists. If set to false, also there will be more suggestions, but some of them may not borrow-check.",
                         "default": true,
@@ -2895,7 +2905,7 @@
                 "title": "workspace",
                 "properties": {
                     "rust-analyzer.workspace.symbol.search.excludeImports": {
-                        "markdownDescription": "Exclude imports from symbol search.",
+                        "markdownDescription": "Exclude all imports from workspace symbol search.\n\nIn addition to regular imports (which are always excluded),\nthis option removes public imports (better known as re-exports)\nand removes imports that rename the imported symbol.",
                         "default": false,
                         "type": "boolean"
                     }
diff --git a/src/tools/rust-analyzer/editors/code/src/config.ts b/src/tools/rust-analyzer/editors/code/src/config.ts
index f36e18a73da..d2dc740c09b 100644
--- a/src/tools/rust-analyzer/editors/code/src/config.ts
+++ b/src/tools/rust-analyzer/editors/code/src/config.ts
@@ -20,15 +20,9 @@ export class Config {
     configureLang: vscode.Disposable | undefined;
 
     readonly rootSection = "rust-analyzer";
-    private readonly requiresServerReloadOpts = [
-        "cargo",
-        "procMacro",
-        "serverPath",
-        "server",
-        "files",
-        "cfg",
-        "showSyntaxTree",
-    ].map((opt) => `${this.rootSection}.${opt}`);
+    private readonly requiresServerReloadOpts = ["server", "files", "showSyntaxTree"].map(
+        (opt) => `${this.rootSection}.${opt}`,
+    );
 
     private readonly requiresWindowReloadOpts = ["testExplorer"].map(
         (opt) => `${this.rootSection}.${opt}`,
@@ -208,7 +202,7 @@ export class Config {
     }
 
     get serverPath() {
-        return this.get<null | string>("server.path") ?? this.get<null | string>("serverPath");
+        return this.get<null | string>("server.path");
     }
 
     get serverExtraEnv(): Env {
diff --git a/src/tools/rust-analyzer/rust-version b/src/tools/rust-analyzer/rust-version
index af0dd5c9acd..a454087b0cd 100644
--- a/src/tools/rust-analyzer/rust-version
+++ b/src/tools/rust-analyzer/rust-version
@@ -1 +1 @@
-7c10378e1fee5ddc6573b916aeb884ab10e0de17
+27733d46d79f4eb92e240fbba502c43022665735
diff --git a/src/tools/rust-installer/install-template.sh b/src/tools/rust-installer/install-template.sh
index f7f408be882..337aaa95b9a 100644
--- a/src/tools/rust-installer/install-template.sh
+++ b/src/tools/rust-installer/install-template.sh
@@ -160,7 +160,7 @@ valopt() {
     local doc="$*"
     if [ $HELP -eq 0 ]
     then
-        local uop=$(echo $op | tr 'a-z-' 'A-Z_')
+        local uop=$(echo $op | tr '[a-z]-' '[A-Z]_')
         local v="CFG_${uop}"
         eval $v="$default"
         for arg in $CFG_ARGS
@@ -206,8 +206,8 @@ opt() {
         do
             if [ "$arg" = "--${flag}-${op}" ]
             then
-                op=$(echo $op | tr 'a-z-' 'A-Z_')
-                flag=$(echo $flag | tr 'a-z' 'A-Z')
+                op=$(echo $op | tr '[a-z]-' '[A-Z]_')
+                flag=$(echo $flag | tr '[a-z]' '[A-Z]')
                 local v="CFG_${flag}_${op}"
                 eval $v=1
                 putvar $v
@@ -235,7 +235,7 @@ flag() {
         do
             if [ "$arg" = "--${op}" ]
             then
-                op=$(echo $op | tr 'a-z-' 'A-Z_')
+                op=$(echo $op | tr '[a-z]-' '[A-Z]_')
                 local v="CFG_${op}"
                 eval $v=1
                 putvar $v
diff --git a/src/tools/rustfmt/src/expr.rs b/src/tools/rustfmt/src/expr.rs
index be6b483bfff..08aedff2b20 100644
--- a/src/tools/rustfmt/src/expr.rs
+++ b/src/tools/rustfmt/src/expr.rs
@@ -2289,8 +2289,10 @@ fn rewrite_expr_addrof(
 ) -> RewriteResult {
     let operator_str = match (mutability, borrow_kind) {
         (ast::Mutability::Not, ast::BorrowKind::Ref) => "&",
+        (ast::Mutability::Not, ast::BorrowKind::Pin) => "&pin const ",
         (ast::Mutability::Not, ast::BorrowKind::Raw) => "&raw const ",
         (ast::Mutability::Mut, ast::BorrowKind::Ref) => "&mut ",
+        (ast::Mutability::Mut, ast::BorrowKind::Pin) => "&pin mut ",
         (ast::Mutability::Mut, ast::BorrowKind::Raw) => "&raw mut ",
     };
     rewrite_unary_prefix(context, operator_str, expr, shape)
diff --git a/src/tools/rustfmt/src/imports.rs b/src/tools/rustfmt/src/imports.rs
index b741dd9b5da..788fed013ad 100644
--- a/src/tools/rustfmt/src/imports.rs
+++ b/src/tools/rustfmt/src/imports.rs
@@ -184,7 +184,7 @@ impl UseSegment {
         modsep: bool,
     ) -> Option<UseSegment> {
         let name = rewrite_ident(context, path_seg.ident);
-        if name.is_empty() || name == "{{root}}" {
+        if name.is_empty() {
             return None;
         }
         let kind = match name {
diff --git a/src/tools/rustfmt/src/parse/session.rs b/src/tools/rustfmt/src/parse/session.rs
index afd847f9515..10e2809e58b 100644
--- a/src/tools/rustfmt/src/parse/session.rs
+++ b/src/tools/rustfmt/src/parse/session.rs
@@ -5,7 +5,7 @@ use std::sync::atomic::{AtomicBool, Ordering};
 use rustc_data_structures::sync::IntoDynSyncSend;
 use rustc_errors::emitter::{DynEmitter, Emitter, HumanEmitter, SilentEmitter, stderr_destination};
 use rustc_errors::registry::Registry;
-use rustc_errors::translation::Translate;
+use rustc_errors::translation::Translator;
 use rustc_errors::{ColorConfig, Diag, DiagCtxt, DiagInner, Level as DiagnosticLevel};
 use rustc_session::parse::ParseSess as RawParseSess;
 use rustc_span::{
@@ -47,16 +47,6 @@ impl SilentOnIgnoredFilesEmitter {
     }
 }
 
-impl Translate for SilentOnIgnoredFilesEmitter {
-    fn fluent_bundle(&self) -> Option<&rustc_errors::FluentBundle> {
-        self.emitter.fluent_bundle()
-    }
-
-    fn fallback_fluent_bundle(&self) -> &rustc_errors::FluentBundle {
-        self.emitter.fallback_fluent_bundle()
-    }
-}
-
 impl Emitter for SilentOnIgnoredFilesEmitter {
     fn source_map(&self) -> Option<&SourceMap> {
         None
@@ -84,6 +74,10 @@ impl Emitter for SilentOnIgnoredFilesEmitter {
         }
         self.handle_non_ignoreable_error(diag, registry);
     }
+
+    fn translator(&self) -> &Translator {
+        self.emitter.translator()
+    }
 }
 
 impl From<Color> for ColorConfig {
@@ -110,23 +104,15 @@ fn default_dcx(
         ColorConfig::Never
     };
 
-    let fallback_bundle = rustc_errors::fallback_fluent_bundle(
-        rustc_driver::DEFAULT_LOCALE_RESOURCES.to_vec(),
-        false,
-    );
-    let emitter = Box::new(
-        HumanEmitter::new(stderr_destination(emit_color), fallback_bundle)
-            .sm(Some(source_map.clone())),
-    );
-
-    let emitter: Box<DynEmitter> = if !show_parse_errors {
-        Box::new(SilentEmitter {
-            fatal_emitter: emitter,
-            fatal_note: None,
-            emit_fatal_diagnostic: false,
-        })
+    let translator = rustc_driver::default_translator();
+
+    let emitter: Box<DynEmitter> = if show_parse_errors {
+        Box::new(
+            HumanEmitter::new(stderr_destination(emit_color), translator)
+                .sm(Some(source_map.clone())),
+        )
     } else {
-        emitter
+        Box::new(SilentEmitter { translator })
     };
     DiagCtxt::new(Box::new(SilentOnIgnoredFilesEmitter {
         has_non_ignorable_parser_errors: false,
@@ -205,7 +191,7 @@ impl ParseSess {
     }
 
     pub(crate) fn set_silent_emitter(&mut self) {
-        self.raw_psess.dcx().make_silent(None, false);
+        self.raw_psess.dcx().make_silent();
     }
 
     pub(crate) fn span_to_filename(&self, span: Span) -> FileName {
@@ -335,16 +321,6 @@ mod tests {
             num_emitted_errors: Arc<AtomicU32>,
         }
 
-        impl Translate for TestEmitter {
-            fn fluent_bundle(&self) -> Option<&rustc_errors::FluentBundle> {
-                None
-            }
-
-            fn fallback_fluent_bundle(&self) -> &rustc_errors::FluentBundle {
-                panic!("test emitter attempted to translate a diagnostic");
-            }
-        }
-
         impl Emitter for TestEmitter {
             fn source_map(&self) -> Option<&SourceMap> {
                 None
@@ -353,6 +329,10 @@ mod tests {
             fn emit_diagnostic(&mut self, _diag: DiagInner, _registry: &Registry) {
                 self.num_emitted_errors.fetch_add(1, Ordering::Release);
             }
+
+            fn translator(&self) -> &Translator {
+                panic!("test emitter attempted to translate a diagnostic");
+            }
         }
 
         fn build_diagnostic(level: DiagnosticLevel, span: Option<MultiSpan>) -> DiagInner {
diff --git a/src/tools/rustfmt/tests/source/pin_sugar.rs b/src/tools/rustfmt/tests/source/pin_sugar.rs
index 370dfbc196a..e5b47339b92 100644
--- a/src/tools/rustfmt/tests/source/pin_sugar.rs
+++ b/src/tools/rustfmt/tests/source/pin_sugar.rs
@@ -18,3 +18,13 @@ impl Foo {
 mut self) {}
     fn i(&pin      mut   self) {}
 }
+
+fn borrows() {
+    let mut foo = 0_i32;
+    let x: Pin<&mut _> = & pin 
+    mut    foo;
+
+    let x: Pin<&_> = &
+    pin                const 
+    foo;
+}
diff --git a/src/tools/rustfmt/tests/source/type.rs b/src/tools/rustfmt/tests/source/type.rs
index 7a232f85198..213fad7cb16 100644
--- a/src/tools/rustfmt/tests/source/type.rs
+++ b/src/tools/rustfmt/tests/source/type.rs
@@ -142,18 +142,18 @@ type MyFn = fn(a: SomeLongComplexType, b: SomeOtherLongComplexType,) -> Box<Futu
 
 // Const bound
 
-trait T: ~   const  Super {}
+trait T: [   const ] Super {}
 
-const fn not_quite_const<S: ~  const    T>() -> i32 { <S as T>::CONST }
+const fn not_quite_const<S: [  const  ]  T>() -> i32 { <S as T>::CONST }
 
-impl ~    const T {}
+impl     const T for U {}
 
-fn apit(_: impl ~   const T) {}
+fn apit(_: impl [   const ] T) {}
 
-fn rpit() -> impl ~  const T { S }
+fn rpit() -> impl [  const] T { S }
 
 pub struct Foo<T: Trait>(T);
-impl<T:   ~  const Trait> Foo<T> {
+impl<T:   [  const] Trait> Foo<T> {
     fn new(t: T) -> Self {
         Self(t)
     }
diff --git a/src/tools/rustfmt/tests/target/pin_sugar.rs b/src/tools/rustfmt/tests/target/pin_sugar.rs
index 7d04efb1b32..09ad23a5807 100644
--- a/src/tools/rustfmt/tests/target/pin_sugar.rs
+++ b/src/tools/rustfmt/tests/target/pin_sugar.rs
@@ -16,3 +16,10 @@ impl Foo {
     fn h<'a>(&'a pin mut self) {}
     fn i(&pin mut self) {}
 }
+
+fn borrows() {
+    let mut foo = 0_i32;
+    let x: Pin<&mut _> = &pin mut foo;
+
+    let x: Pin<&_> = &pin const foo;
+}
diff --git a/src/tools/rustfmt/tests/target/type.rs b/src/tools/rustfmt/tests/target/type.rs
index 325adb52f3f..93479f8b484 100644
--- a/src/tools/rustfmt/tests/target/type.rs
+++ b/src/tools/rustfmt/tests/target/type.rs
@@ -147,22 +147,22 @@ type MyFn = fn(
 
 // Const bound
 
-trait T: ~const Super {}
+trait T: [const] Super {}
 
-const fn not_quite_const<S: ~const T>() -> i32 {
+const fn not_quite_const<S: [const] T>() -> i32 {
     <S as T>::CONST
 }
 
-impl ~const T {}
+impl const T for U {}
 
-fn apit(_: impl ~const T) {}
+fn apit(_: impl [const] T) {}
 
-fn rpit() -> impl ~const T {
+fn rpit() -> impl [const] T {
     S
 }
 
 pub struct Foo<T: Trait>(T);
-impl<T: ~const Trait> Foo<T> {
+impl<T: [const] Trait> Foo<T> {
     fn new(t: T) -> Self {
         Self(t)
     }
diff --git a/src/tools/tidy/src/alphabetical.rs b/src/tools/tidy/src/alphabetical.rs
index a29286fa2c5..141083290c6 100644
--- a/src/tools/tidy/src/alphabetical.rs
+++ b/src/tools/tidy/src/alphabetical.rs
@@ -19,7 +19,9 @@
 //! If a line ends with an opening delimiter, we effectively join the following line to it before
 //! checking it. E.g. `foo(\nbar)` is treated like `foo(bar)`.
 
+use std::cmp::Ordering;
 use std::fmt::Display;
+use std::iter::Peekable;
 use std::path::Path;
 
 use crate::walk::{filter_dirs, walk};
@@ -99,9 +101,9 @@ fn check_section<'a>(
             continue;
         }
 
-        let prev_line_trimmed_lowercase = prev_line.trim_start_matches(' ').to_lowercase();
+        let prev_line_trimmed_lowercase = prev_line.trim_start_matches(' ');
 
-        if trimmed_line.to_lowercase() < prev_line_trimmed_lowercase {
+        if version_sort(&trimmed_line, &prev_line_trimmed_lowercase).is_lt() {
             tidy_error_ext!(err, bad, "{file}:{}: line not in alphabetical order", idx + 1);
         }
 
@@ -143,3 +145,56 @@ pub fn check(path: &Path, bad: &mut bool) {
         check_lines(file, lines, &mut crate::tidy_error, bad)
     });
 }
+
+fn consume_numeric_prefix<I: Iterator<Item = char>>(it: &mut Peekable<I>) -> String {
+    let mut result = String::new();
+
+    while let Some(&c) = it.peek() {
+        if !c.is_numeric() {
+            break;
+        }
+
+        result.push(c);
+        it.next();
+    }
+
+    result
+}
+
+// A sorting function that is case-sensitive, and sorts sequences of digits by their numeric value,
+// so that `9` sorts before `12`.
+fn version_sort(a: &str, b: &str) -> Ordering {
+    let mut it1 = a.chars().peekable();
+    let mut it2 = b.chars().peekable();
+
+    while let (Some(x), Some(y)) = (it1.peek(), it2.peek()) {
+        match (x.is_numeric(), y.is_numeric()) {
+            (true, true) => {
+                let num1: String = consume_numeric_prefix(it1.by_ref());
+                let num2: String = consume_numeric_prefix(it2.by_ref());
+
+                let int1: u64 = num1.parse().unwrap();
+                let int2: u64 = num2.parse().unwrap();
+
+                // Compare strings when the numeric value is equal to handle "00" versus "0".
+                match int1.cmp(&int2).then_with(|| num1.cmp(&num2)) {
+                    Ordering::Equal => continue,
+                    different => return different,
+                }
+            }
+            (false, false) => match x.cmp(y) {
+                Ordering::Equal => {
+                    it1.next();
+                    it2.next();
+                    continue;
+                }
+                different => return different,
+            },
+            (false, true) | (true, false) => {
+                return x.cmp(y);
+            }
+        }
+    }
+
+    it1.next().cmp(&it2.next())
+}
diff --git a/src/tools/tidy/src/alphabetical/tests.rs b/src/tools/tidy/src/alphabetical/tests.rs
index 29e89a693bf..4d05bc33ced 100644
--- a/src/tools/tidy/src/alphabetical/tests.rs
+++ b/src/tools/tidy/src/alphabetical/tests.rs
@@ -3,6 +3,7 @@ use std::str::from_utf8;
 
 use super::*;
 
+#[track_caller]
 fn test(lines: &str, name: &str, expected_msg: &str, expected_bad: bool) {
     let mut actual_msg = Vec::new();
     let mut actual_bad = false;
@@ -15,10 +16,12 @@ fn test(lines: &str, name: &str, expected_msg: &str, expected_bad: bool) {
     assert_eq!(expected_bad, actual_bad);
 }
 
+#[track_caller]
 fn good(lines: &str) {
     test(lines, "good", "", false);
 }
 
+#[track_caller]
 fn bad(lines: &str, expected_msg: &str) {
     test(lines, "bad", expected_msg, true);
 }
@@ -187,3 +190,147 @@ fn test_double_end() {
     ";
     bad(lines, "bad:5 found `tidy-alphabetical-end` expecting `tidy-alphabetical-start`");
 }
+
+#[test]
+fn test_numeric_good() {
+    good(
+        "\
+        # tidy-alphabetical-start
+        rustc_ast = { path = \"../rustc_ast\" }
+        rustc_ast_lowering = { path = \"../rustc_ast_lowering\" }
+        # tidy-alphabetical-end
+    ",
+    );
+
+    good(
+        "\
+        # tidy-alphabetical-start
+        fp-armv8
+        fp16
+        # tidy-alphabetical-end
+    ",
+    );
+
+    good(
+        "\
+        # tidy-alphabetical-start
+        item1
+        item2
+        item10
+        # tidy-alphabetical-end
+    ",
+    );
+
+    good(
+        "\
+        # tidy-alphabetical-start
+        foo
+        foo_
+        # tidy-alphabetical-end
+    ",
+    );
+
+    good(
+        "\
+        # tidy-alphabetical-start
+        foo-bar
+        foo_bar
+        # tidy-alphabetical-end
+    ",
+    );
+
+    good(
+        "\
+        # tidy-alphabetical-start
+        sme-lutv2
+        sme2
+        # tidy-alphabetical-end
+    ",
+    );
+
+    good(
+        "\
+        # tidy-alphabetical-start
+        v5te
+        v6
+        v6k
+        v6t2
+        # tidy-alphabetical-end
+    ",
+    );
+
+    good(
+        "\
+        # tidy-alphabetical-start
+        zve64d
+        zve64f
+        # tidy-alphabetical-end
+    ",
+    );
+
+    // Case is significant.
+    good(
+        "\
+        # tidy-alphabetical-start
+        _ZYXW
+        _abcd
+        # tidy-alphabetical-end
+    ",
+    );
+
+    good(
+        "\
+        # tidy-alphabetical-start
+        v0
+        v00
+        v000
+        # tidy-alphabetical-end
+    ",
+    );
+
+    good(
+        "\
+        # tidy-alphabetical-start
+        w005s09t
+        w5s009t
+        # tidy-alphabetical-end
+    ",
+    );
+
+    good(
+        "\
+        # tidy-alphabetical-start
+        v0s
+        v00t
+        # tidy-alphabetical-end
+    ",
+    );
+}
+
+#[test]
+fn test_numeric_bad() {
+    let lines = "\
+        # tidy-alphabetical-start
+        item1
+        item10
+        item2
+        # tidy-alphabetical-end
+    ";
+    bad(lines, "bad:4: line not in alphabetical order");
+
+    let lines = "\
+        # tidy-alphabetical-start
+        zve64f
+        zve64d
+        # tidy-alphabetical-end
+    ";
+    bad(lines, "bad:3: line not in alphabetical order");
+
+    let lines = "\
+        # tidy-alphabetical-start
+        000
+        00
+        # tidy-alphabetical-end
+    ";
+    bad(lines, "bad:3: line not in alphabetical order");
+}
diff --git a/src/tools/tidy/src/deps.rs b/src/tools/tidy/src/deps.rs
index 170dcd626a2..bf813d2131e 100644
--- a/src/tools/tidy/src/deps.rs
+++ b/src/tools/tidy/src/deps.rs
@@ -206,6 +206,7 @@ const EXCEPTIONS_CRANELIFT: ExceptionList = &[
     ("regalloc2", "Apache-2.0 WITH LLVM-exception"),
     ("target-lexicon", "Apache-2.0 WITH LLVM-exception"),
     ("wasmtime-jit-icache-coherence", "Apache-2.0 WITH LLVM-exception"),
+    ("wasmtime-math", "Apache-2.0 WITH LLVM-exception"),
     // tidy-alphabetical-end
 ];
 
@@ -356,6 +357,7 @@ const PERMITTED_RUSTC_DEPENDENCIES: &[&str] = &[
     "rand",
     "rand_chacha",
     "rand_core",
+    "rand_xorshift", // dependency for doc-tests in rustc_thread_pool
     "rand_xoshiro",
     "redox_syscall",
     "regex",
@@ -364,7 +366,6 @@ const PERMITTED_RUSTC_DEPENDENCIES: &[&str] = &[
     "rustc-demangle",
     "rustc-hash",
     "rustc-literal-escaper",
-    "rustc-rayon-core",
     "rustc-stable-hash",
     "rustc_apfloat",
     "rustix",
@@ -373,6 +374,7 @@ const PERMITTED_RUSTC_DEPENDENCIES: &[&str] = &[
     "scoped-tls",
     "scopeguard",
     "self_cell",
+    "semver",
     "serde",
     "serde_derive",
     "serde_json",
@@ -537,6 +539,7 @@ const PERMITTED_CRANELIFT_DEPENDENCIES: &[&str] = &[
     "indexmap",
     "libc",
     "libloading",
+    "libm",
     "log",
     "mach2",
     "memchr",
@@ -554,6 +557,7 @@ const PERMITTED_CRANELIFT_DEPENDENCIES: &[&str] = &[
     "target-lexicon",
     "unicode-ident",
     "wasmtime-jit-icache-coherence",
+    "wasmtime-math",
     "windows-sys",
     "windows-targets",
     "windows_aarch64_gnullvm",
diff --git a/src/tools/tidy/src/error_codes.rs b/src/tools/tidy/src/error_codes.rs
index e2d1b85797f..bb61412f678 100644
--- a/src/tools/tidy/src/error_codes.rs
+++ b/src/tools/tidy/src/error_codes.rs
@@ -43,9 +43,18 @@ macro_rules! verbose_print {
     };
 }
 
-pub fn check(root_path: &Path, search_paths: &[&Path], verbose: bool, bad: &mut bool) {
+pub fn check(
+    root_path: &Path,
+    search_paths: &[&Path],
+    verbose: bool,
+    ci_info: &crate::CiInfo,
+    bad: &mut bool,
+) {
     let mut errors = Vec::new();
 
+    // Check that no error code explanation was removed.
+    check_removed_error_code_explanation(ci_info, bad);
+
     // Stage 1: create list
     let error_codes = extract_error_codes(root_path, &mut errors);
     if verbose {
@@ -68,6 +77,27 @@ pub fn check(root_path: &Path, search_paths: &[&Path], verbose: bool, bad: &mut
     }
 }
 
+fn check_removed_error_code_explanation(ci_info: &crate::CiInfo, bad: &mut bool) {
+    let Some(base_commit) = &ci_info.base_commit else {
+        eprintln!("Skipping error code explanation removal check");
+        return;
+    };
+    let Some(diff) = crate::git_diff(base_commit, "--name-status") else {
+        *bad = true;
+        eprintln!("removed error code explanation tidy check: Failed to run git diff");
+        return;
+    };
+    if diff.lines().any(|line| {
+        line.starts_with('D') && line.contains("compiler/rustc_error_codes/src/error_codes/")
+    }) {
+        *bad = true;
+        eprintln!("tidy check error: Error code explanations should never be removed!");
+        eprintln!("Take a look at E0001 to see how to handle it.");
+        return;
+    }
+    println!("No error code explanation was removed!");
+}
+
 /// Stage 1: Parses a list of error codes from `error_codes.rs`.
 fn extract_error_codes(root_path: &Path, errors: &mut Vec<String>) -> Vec<String> {
     let path = root_path.join(Path::new(ERROR_CODES_PATH));
diff --git a/src/tools/tidy/src/issues.txt b/src/tools/tidy/src/issues.txt
index b3517b2e9da..7e27e0258c2 100644
--- a/src/tools/tidy/src/issues.txt
+++ b/src/tools/tidy/src/issues.txt
@@ -2070,7 +2070,6 @@ ui/issues/issue-32782.rs
 ui/issues/issue-32797.rs
 ui/issues/issue-32805.rs
 ui/issues/issue-3290.rs
-ui/issues/issue-32950.rs
 ui/issues/issue-32995-2.rs
 ui/issues/issue-32995.rs
 ui/issues/issue-33202.rs
@@ -2340,7 +2339,6 @@ ui/issues/issue-49934.rs
 ui/issues/issue-49955.rs
 ui/issues/issue-49973.rs
 ui/issues/issue-50187.rs
-ui/issues/issue-50403.rs
 ui/issues/issue-50411.rs
 ui/issues/issue-50415.rs
 ui/issues/issue-50442.rs
@@ -3921,7 +3919,6 @@ ui/traits/const-traits/issue-79450.rs
 ui/traits/const-traits/issue-88155.rs
 ui/traits/const-traits/issue-92111.rs
 ui/traits/const-traits/issue-92230-wf-super-trait-env.rs
-ui/traits/const-traits/specialization/issue-95186-specialize-on-tilde-const.rs
 ui/traits/const-traits/specialization/issue-95187-same-trait-bound-different-constness.rs
 ui/traits/issue-103563.rs
 ui/traits/issue-104322.rs
diff --git a/src/tools/tidy/src/lib.rs b/src/tools/tidy/src/lib.rs
index e8a12d56335..237737f0f16 100644
--- a/src/tools/tidy/src/lib.rs
+++ b/src/tools/tidy/src/lib.rs
@@ -3,6 +3,12 @@
 //! This library contains the tidy lints and exposes it
 //! to be used by tools.
 
+use std::ffi::OsStr;
+use std::process::Command;
+
+use build_helper::ci::CiEnv;
+use build_helper::git::{GitConfig, get_closest_upstream_commit};
+use build_helper::stage0_parser::{Stage0Config, parse_stage0_file};
 use termcolor::WriteColor;
 
 macro_rules! static_regex {
@@ -63,6 +69,61 @@ fn tidy_error(args: &str) -> std::io::Result<()> {
     Ok(())
 }
 
+pub struct CiInfo {
+    pub git_merge_commit_email: String,
+    pub nightly_branch: String,
+    pub base_commit: Option<String>,
+    pub ci_env: CiEnv,
+}
+
+impl CiInfo {
+    pub fn new(bad: &mut bool) -> Self {
+        let stage0 = parse_stage0_file();
+        let Stage0Config { nightly_branch, git_merge_commit_email, .. } = stage0.config;
+
+        let mut info = Self {
+            nightly_branch,
+            git_merge_commit_email,
+            ci_env: CiEnv::current(),
+            base_commit: None,
+        };
+        let base_commit = match get_closest_upstream_commit(None, &info.git_config(), info.ci_env) {
+            Ok(Some(commit)) => Some(commit),
+            Ok(None) => {
+                info.error_if_in_ci("no base commit found", bad);
+                None
+            }
+            Err(error) => {
+                info.error_if_in_ci(&format!("failed to retrieve base commit: {error}"), bad);
+                None
+            }
+        };
+        info.base_commit = base_commit;
+        info
+    }
+
+    pub fn git_config(&self) -> GitConfig<'_> {
+        GitConfig {
+            nightly_branch: &self.nightly_branch,
+            git_merge_commit_email: &self.git_merge_commit_email,
+        }
+    }
+
+    pub fn error_if_in_ci(&self, msg: &str, bad: &mut bool) {
+        if self.ci_env.is_running_in_ci() {
+            *bad = true;
+            eprintln!("tidy check error: {msg}");
+        } else {
+            eprintln!("tidy check warning: {msg}. Some checks will be skipped.");
+        }
+    }
+}
+
+pub fn git_diff<S: AsRef<OsStr>>(base_commit: &str, extra_arg: S) -> Option<String> {
+    let output = Command::new("git").arg("diff").arg(base_commit).arg(extra_arg).output().ok()?;
+    Some(String::from_utf8_lossy(&output.stdout).into())
+}
+
 pub mod alphabetical;
 pub mod bins;
 pub mod debug_artifacts;
@@ -83,6 +144,7 @@ pub mod pal;
 pub mod rustdoc_css_themes;
 pub mod rustdoc_gui_tests;
 pub mod rustdoc_js;
+pub mod rustdoc_json;
 pub mod rustdoc_templates;
 pub mod style;
 pub mod target_policy;
diff --git a/src/tools/tidy/src/main.rs b/src/tools/tidy/src/main.rs
index 776f1bde2eb..ef6ff5c9277 100644
--- a/src/tools/tidy/src/main.rs
+++ b/src/tools/tidy/src/main.rs
@@ -48,7 +48,9 @@ fn main() {
     let extra_checks =
         cfg_args.iter().find(|s| s.starts_with("--extra-checks=")).map(String::as_str);
 
-    let bad = std::sync::Arc::new(AtomicBool::new(false));
+    let mut bad = false;
+    let ci_info = CiInfo::new(&mut bad);
+    let bad = std::sync::Arc::new(AtomicBool::new(bad));
 
     let drain_handles = |handles: &mut VecDeque<ScopedJoinHandle<'_, ()>>| {
         // poll all threads for completion before awaiting the oldest one
@@ -110,11 +112,12 @@ fn main() {
         check!(rustdoc_css_themes, &librustdoc_path);
         check!(rustdoc_templates, &librustdoc_path);
         check!(rustdoc_js, &librustdoc_path, &tools_path, &src_path);
+        check!(rustdoc_json, &src_path, &ci_info);
         check!(known_bug, &crashes_path);
         check!(unknown_revision, &tests_path);
 
         // Checks that only make sense for the compiler.
-        check!(error_codes, &root_path, &[&compiler_path, &librustdoc_path], verbose);
+        check!(error_codes, &root_path, &[&compiler_path, &librustdoc_path], verbose, &ci_info);
         check!(fluent_alphabetical, &compiler_path, bless);
         check!(fluent_period, &compiler_path);
         check!(target_policy, &root_path);
diff --git a/src/tools/tidy/src/rustdoc_js.rs b/src/tools/tidy/src/rustdoc_js.rs
index 2517e2de12c..720f0712ee0 100644
--- a/src/tools/tidy/src/rustdoc_js.rs
+++ b/src/tools/tidy/src/rustdoc_js.rs
@@ -62,6 +62,9 @@ pub fn check(librustdoc_path: &Path, tools_path: &Path, src_path: &Path, bad: &m
             return;
         }
     };
+    // Having the correct `eslint` version installed via `npm` isn't strictly necessary, since we're invoking it via `npx`,
+    // but this check allows the vast majority that is not working on the rustdoc frontend to avoid the penalty of running
+    // `eslint` in tidy. See also: https://github.com/rust-lang/rust/pull/142851
     match get_eslint_version() {
         Some(version) => {
             if version != eslint_version {
diff --git a/src/tools/tidy/src/rustdoc_json.rs b/src/tools/tidy/src/rustdoc_json.rs
new file mode 100644
index 00000000000..dfbb35d69f1
--- /dev/null
+++ b/src/tools/tidy/src/rustdoc_json.rs
@@ -0,0 +1,90 @@
+//! Tidy check to ensure that `FORMAT_VERSION` was correctly updated if `rustdoc-json-types` was
+//! updated as well.
+
+use std::path::Path;
+use std::str::FromStr;
+
+const RUSTDOC_JSON_TYPES: &str = "src/rustdoc-json-types";
+
+pub fn check(src_path: &Path, ci_info: &crate::CiInfo, bad: &mut bool) {
+    println!("Checking tidy rustdoc_json...");
+    let Some(base_commit) = &ci_info.base_commit else {
+        eprintln!("No base commit, skipping rustdoc_json check");
+        return;
+    };
+
+    // First we check that `src/rustdoc-json-types` was modified.
+    match crate::git_diff(&base_commit, "--name-status") {
+        Some(output) => {
+            if !output
+                .lines()
+                .any(|line| line.starts_with("M") && line.contains(RUSTDOC_JSON_TYPES))
+            {
+                // `rustdoc-json-types` was not modified so nothing more to check here.
+                println!("`rustdoc-json-types` was not modified.");
+                return;
+            }
+        }
+        None => {
+            *bad = true;
+            eprintln!("error: failed to run `git diff` in rustdoc_json check");
+            return;
+        }
+    }
+    // Then we check that if `FORMAT_VERSION` was updated, the `Latest feature:` was also updated.
+    match crate::git_diff(&base_commit, src_path.join("rustdoc-json-types")) {
+        Some(output) => {
+            let mut format_version_updated = false;
+            let mut latest_feature_comment_updated = false;
+            let mut new_version = None;
+            let mut old_version = None;
+            for line in output.lines() {
+                if line.starts_with("+pub const FORMAT_VERSION: u32 =") {
+                    format_version_updated = true;
+                    new_version = line
+                        .split('=')
+                        .nth(1)
+                        .and_then(|s| s.trim().split(';').next())
+                        .and_then(|s| u32::from_str(s.trim()).ok());
+                } else if line.starts_with("-pub const FORMAT_VERSION: u32 =") {
+                    old_version = line
+                        .split('=')
+                        .nth(1)
+                        .and_then(|s| s.trim().split(';').next())
+                        .and_then(|s| u32::from_str(s.trim()).ok());
+                } else if line.starts_with("+// Latest feature:") {
+                    latest_feature_comment_updated = true;
+                }
+            }
+            if format_version_updated != latest_feature_comment_updated {
+                *bad = true;
+                if latest_feature_comment_updated {
+                    eprintln!(
+                        "error in `rustdoc_json` tidy check: `Latest feature` comment was updated \
+                         whereas `FORMAT_VERSION` wasn't in `{RUSTDOC_JSON_TYPES}/lib.rs`"
+                    );
+                } else {
+                    eprintln!(
+                        "error in `rustdoc_json` tidy check: `Latest feature` comment was not \
+                         updated whereas `FORMAT_VERSION` was in `{RUSTDOC_JSON_TYPES}/lib.rs`"
+                    );
+                }
+            }
+            match (new_version, old_version) {
+                (Some(new_version), Some(old_version)) if new_version != old_version + 1 => {
+                    *bad = true;
+                    eprintln!(
+                        "error in `rustdoc_json` tidy check: invalid `FORMAT_VERSION` increase in \
+                         `{RUSTDOC_JSON_TYPES}/lib.rs`, should be `{}`, found `{new_version}`",
+                        old_version + 1,
+                    );
+                }
+                _ => {}
+            }
+        }
+        None => {
+            *bad = true;
+            eprintln!("error: failed to run `git diff` in rustdoc_json check");
+        }
+    }
+}
diff --git a/src/tools/tidy/src/ui_tests.rs b/src/tools/tidy/src/ui_tests.rs
index 8f9b07c49ac..53226fcb80e 100644
--- a/src/tools/tidy/src/ui_tests.rs
+++ b/src/tools/tidy/src/ui_tests.rs
@@ -17,7 +17,7 @@ use ignore::Walk;
 const ENTRY_LIMIT: u32 = 901;
 // FIXME: The following limits should be reduced eventually.
 
-const ISSUES_ENTRY_LIMIT: u32 = 1623;
+const ISSUES_ENTRY_LIMIT: u32 = 1619;
 
 const EXPECTED_TEST_FILE_EXTENSIONS: &[&str] = &[
     "rs",     // test source files
diff --git a/src/tools/wasm-component-ld/Cargo.toml b/src/tools/wasm-component-ld/Cargo.toml
index 642d48b9952..ce718902b29 100644
--- a/src/tools/wasm-component-ld/Cargo.toml
+++ b/src/tools/wasm-component-ld/Cargo.toml
@@ -10,4 +10,4 @@ name = "wasm-component-ld"
 path = "src/main.rs"
 
 [dependencies]
-wasm-component-ld = "0.5.13"
+wasm-component-ld = "0.5.14"