about summary refs log tree commit diff
path: root/src/tools
diff options
context:
space:
mode:
authorThe Miri Cronjob Bot <miri@cron.bot>2025-09-20 05:00:06 +0000
committerThe Miri Cronjob Bot <miri@cron.bot>2025-09-20 05:00:06 +0000
commit340c6e76ec16aae2110596b8b3fa7f05fee7858e (patch)
treee5f4a0c1b6c8c14eabab0b89b839f2f7fec53aa8 /src/tools
parent88ceae98c57e17bf9923861d7c91319d7ca44f69 (diff)
parent42ebba214b3c570761dc99f5fc1517ad092778ac (diff)
downloadrust-340c6e76ec16aae2110596b8b3fa7f05fee7858e.tar.gz
rust-340c6e76ec16aae2110596b8b3fa7f05fee7858e.zip
Merge ref 'ec3867107526' from rust-lang/rust
Pull recent changes from https://github.com/rust-lang/rust via Josh.

Upstream ref: ec38671075266e9cee0348701da2e133379e7c6c
Filtered ref: ed8e25574abf50600d9d2fd61eda90708ccce6c2
Upstream diff: https://github.com/rust-lang/rust/compare/3f1552a273e43e15f6ed240d00e1efdd6a53e65e...ec38671075266e9cee0348701da2e133379e7c6c

This merge was created using https://github.com/rust-lang/josh-sync.
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.yml45
-rw-r--r--src/tools/clippy/.gitignore3
-rw-r--r--src/tools/clippy/CHANGELOG.md148
-rw-r--r--src/tools/clippy/Cargo.toml2
-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/clippy_config/Cargo.toml2
-rw-r--r--src/tools/clippy/clippy_lints/Cargo.toml2
-rw-r--r--src/tools/clippy/clippy_lints/src/attrs/useless_attribute.rs1
-rw-r--r--src/tools/clippy/clippy_lints/src/casts/as_underscore.rs8
-rw-r--r--src/tools/clippy/clippy_lints/src/casts/cast_possible_wrap.rs30
-rw-r--r--src/tools/clippy/clippy_lints/src/casts/cast_sign_loss.rs29
-rw-r--r--src/tools/clippy/clippy_lints/src/casts/mod.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/casts/utils.rs15
-rw-r--r--src/tools/clippy/clippy_lints/src/declared_lints.rs5
-rw-r--r--src/tools/clippy/clippy_lints/src/dereference.rs7
-rw-r--r--src/tools/clippy/clippy_lints/src/derive.rs527
-rw-r--r--src/tools/clippy/clippy_lints/src/derive/derive_ord_xor_partial_ord.rs50
-rw-r--r--src/tools/clippy/clippy_lints/src/derive/derive_partial_eq_without_eq.rs87
-rw-r--r--src/tools/clippy/clippy_lints/src/derive/derived_hash_with_manual_eq.rs49
-rw-r--r--src/tools/clippy/clippy_lints/src/derive/expl_impl_clone_on_copy.rs65
-rw-r--r--src/tools/clippy/clippy_lints/src/derive/mod.rs215
-rw-r--r--src/tools/clippy/clippy_lints/src/derive/unsafe_derive_deserialize.rs93
-rw-r--r--src/tools/clippy/clippy_lints/src/disallowed_macros.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/eta_reduction.rs27
-rw-r--r--src/tools/clippy/clippy_lints/src/functions/not_unsafe_ptr_arg_deref.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/functions/ref_option.rs48
-rw-r--r--src/tools/clippy/clippy_lints/src/future_not_send.rs109
-rw-r--r--src/tools/clippy/clippy_lints/src/invalid_upcast_comparisons.rs13
-rw-r--r--src/tools/clippy/clippy_lints/src/len_zero.rs6
-rw-r--r--src/tools/clippy/clippy_lints/src/let_with_type_underscore.rs16
-rw-r--r--src/tools/clippy/clippy_lints/src/lib.rs6
-rw-r--r--src/tools/clippy/clippy_lints/src/lifetimes.rs109
-rw-r--r--src/tools/clippy/clippy_lints/src/loops/explicit_iter_loop.rs6
-rw-r--r--src/tools/clippy/clippy_lints/src/loops/never_loop.rs59
-rw-r--r--src/tools/clippy/clippy_lints/src/manual_abs_diff.rs6
-rw-r--r--src/tools/clippy/clippy_lints/src/manual_option_as_slice.rs6
-rw-r--r--src/tools/clippy/clippy_lints/src/manual_slice_size_calculation.rs3
-rw-r--r--src/tools/clippy/clippy_lints/src/matches/manual_ok_err.rs16
-rw-r--r--src/tools/clippy/clippy_lints/src/matches/manual_utils.rs9
-rw-r--r--src/tools/clippy/clippy_lints/src/matches/needless_match.rs6
-rw-r--r--src/tools/clippy/clippy_lints/src/matches/rest_pat_in_fully_bound_struct.rs10
-rw-r--r--src/tools/clippy/clippy_lints/src/matches/single_match.rs8
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/implicit_clone.rs6
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/inefficient_to_string.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/iter_overeager_cloned.rs5
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/mod.rs75
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/mut_mutex_lock.rs5
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/or_fun_call.rs7
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/ptr_offset_with_cast.rs82
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/unnecessary_to_owned.rs13
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/useless_asref.rs6
-rw-r--r--src/tools/clippy/clippy_lints/src/min_ident_chars.rs6
-rw-r--r--src/tools/clippy/clippy_lints/src/misc.rs118
-rw-r--r--src/tools/clippy/clippy_lints/src/missing_doc.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/multiple_unsafe_ops_per_block.rs8
-rw-r--r--src/tools/clippy/clippy_lints/src/only_used_in_recursion.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/operators/erasing_op.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/ptr_offset_with_cast.rs151
-rw-r--r--src/tools/clippy/clippy_lints/src/question_mark.rs21
-rw-r--r--src/tools/clippy/clippy_lints/src/read_zero_byte_vec.rs27
-rw-r--r--src/tools/clippy/clippy_lints/src/redundant_clone.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/redundant_slicing.rs8
-rw-r--r--src/tools/clippy/clippy_lints/src/returns.rs513
-rw-r--r--src/tools/clippy/clippy_lints/src/returns/let_and_return.rs86
-rw-r--r--src/tools/clippy/clippy_lints/src/returns/mod.rs140
-rw-r--r--src/tools/clippy/clippy_lints/src/returns/needless_return.rs269
-rw-r--r--src/tools/clippy/clippy_lints/src/returns/needless_return_with_question_mark.rs60
-rw-r--r--src/tools/clippy/clippy_lints/src/semicolon_block.rs14
-rw-r--r--src/tools/clippy/clippy_lints/src/size_of_ref.rs5
-rw-r--r--src/tools/clippy/clippy_lints/src/toplevel_ref_arg.rs119
-rw-r--r--src/tools/clippy/clippy_lints/src/transmute/transmute_ptr_to_ref.rs44
-rw-r--r--src/tools/clippy/clippy_lints/src/transmute/transmute_ref_to_ref.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/uninit_vec.rs11
-rw-r--r--src/tools/clippy/clippy_lints/src/unused_peekable.rs6
-rw-r--r--src/tools/clippy/clippy_lints/src/unwrap.rs1
-rw-r--r--src/tools/clippy/clippy_lints/src/use_self.rs81
-rw-r--r--src/tools/clippy/clippy_lints/src/useless_conversion.rs14
-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/check_proc_macro.rs146
-rw-r--r--src/tools/clippy/clippy_utils/src/lib.rs29
-rw-r--r--src/tools/clippy/clippy_utils/src/msrvs.rs4
-rw-r--r--src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs4
-rw-r--r--src/tools/clippy/clippy_utils/src/source.rs5
-rw-r--r--src/tools/clippy/clippy_utils/src/sym.rs1
-rw-r--r--src/tools/clippy/clippy_utils/src/ty/mod.rs92
-rw-r--r--src/tools/clippy/declare_clippy_lint/Cargo.toml2
-rw-r--r--src/tools/clippy/rust-toolchain.toml2
-rw-r--r--src/tools/clippy/tests/no-profile-in-cargo-toml.rs3
-rw-r--r--src/tools/clippy/tests/ui-toml/ref_option/all/clippy.toml (renamed from src/tools/clippy/tests/ui/ref_option/all/clippy.toml)0
-rw-r--r--src/tools/clippy/tests/ui-toml/ref_option/private/clippy.toml (renamed from src/tools/clippy/tests/ui/ref_option/private/clippy.toml)0
-rw-r--r--src/tools/clippy/tests/ui-toml/ref_option/ref_option.all.fixed114
-rw-r--r--src/tools/clippy/tests/ui-toml/ref_option/ref_option.all.stderr (renamed from src/tools/clippy/tests/ui/ref_option/ref_option.all.stderr)68
-rw-r--r--src/tools/clippy/tests/ui-toml/ref_option/ref_option.private.fixed114
-rw-r--r--src/tools/clippy/tests/ui-toml/ref_option/ref_option.private.stderr (renamed from src/tools/clippy/tests/ui/ref_option/ref_option.private.stderr)44
-rw-r--r--src/tools/clippy/tests/ui-toml/ref_option/ref_option.rs114
-rw-r--r--src/tools/clippy/tests/ui-toml/ref_option/ref_option_traits.all.stderr (renamed from src/tools/clippy/tests/ui/ref_option/ref_option_traits.all.stderr)8
-rw-r--r--src/tools/clippy/tests/ui-toml/ref_option/ref_option_traits.private.stderr (renamed from src/tools/clippy/tests/ui/ref_option/ref_option_traits.private.stderr)4
-rw-r--r--src/tools/clippy/tests/ui-toml/ref_option/ref_option_traits.rs71
-rw-r--r--src/tools/clippy/tests/ui/as_underscore_unfixable.rs14
-rw-r--r--src/tools/clippy/tests/ui/as_underscore_unfixable.stderr20
-rw-r--r--src/tools/clippy/tests/ui/cast.rs13
-rw-r--r--src/tools/clippy/tests/ui/cast.stderr96
-rw-r--r--src/tools/clippy/tests/ui/checked_unwrap/simple_conditionals.rs22
-rw-r--r--src/tools/clippy/tests/ui/checked_unwrap/simple_conditionals.stderr36
-rw-r--r--src/tools/clippy/tests/ui/crashes/ice-15657.rs11
-rw-r--r--src/tools/clippy/tests/ui/crashes/ice-15666.fixed6
-rw-r--r--src/tools/clippy/tests/ui/crashes/ice-15666.rs6
-rw-r--r--src/tools/clippy/tests/ui/crashes/ice-15666.stderr16
-rw-r--r--src/tools/clippy/tests/ui/elidable_lifetime_names.fixed82
-rw-r--r--src/tools/clippy/tests/ui/elidable_lifetime_names.rs82
-rw-r--r--src/tools/clippy/tests/ui/elidable_lifetime_names.stderr146
-rw-r--r--src/tools/clippy/tests/ui/eta.fixed8
-rw-r--r--src/tools/clippy/tests/ui/eta.rs8
-rw-r--r--src/tools/clippy/tests/ui/invalid_upcast_comparisons.rs12
-rw-r--r--src/tools/clippy/tests/ui/invalid_upcast_comparisons.stderr8
-rw-r--r--src/tools/clippy/tests/ui/iter_overeager_cloned.fixed12
-rw-r--r--src/tools/clippy/tests/ui/iter_overeager_cloned.rs12
-rw-r--r--src/tools/clippy/tests/ui/iter_overeager_cloned.stderr4
-rw-r--r--src/tools/clippy/tests/ui/match_as_ref.fixed30
-rw-r--r--src/tools/clippy/tests/ui/match_as_ref.rs30
-rw-r--r--src/tools/clippy/tests/ui/multiple_unsafe_ops_per_block.rs119
-rw-r--r--src/tools/clippy/tests/ui/multiple_unsafe_ops_per_block.stderr143
-rw-r--r--src/tools/clippy/tests/ui/needless_return.fixed7
-rw-r--r--src/tools/clippy/tests/ui/needless_return.rs7
-rw-r--r--src/tools/clippy/tests/ui/never_loop.rs24
-rw-r--r--src/tools/clippy/tests/ui/never_loop.stderr97
-rw-r--r--src/tools/clippy/tests/ui/option_if_let_else.fixed10
-rw-r--r--src/tools/clippy/tests/ui/option_if_let_else.rs16
-rw-r--r--src/tools/clippy/tests/ui/option_if_let_else.stderr50
-rw-r--r--src/tools/clippy/tests/ui/or_fun_call.fixed16
-rw-r--r--src/tools/clippy/tests/ui/or_fun_call.rs22
-rw-r--r--src/tools/clippy/tests/ui/or_fun_call.stderr88
-rw-r--r--src/tools/clippy/tests/ui/ptr_offset_with_cast.fixed22
-rw-r--r--src/tools/clippy/tests/ui/ptr_offset_with_cast.rs22
-rw-r--r--src/tools/clippy/tests/ui/ptr_offset_with_cast.stderr41
-rw-r--r--src/tools/clippy/tests/ui/question_mark.fixed14
-rw-r--r--src/tools/clippy/tests/ui/question_mark.rs26
-rw-r--r--src/tools/clippy/tests/ui/question_mark.stderr92
-rw-r--r--src/tools/clippy/tests/ui/read_zero_byte_vec.rs27
-rw-r--r--src/tools/clippy/tests/ui/read_zero_byte_vec.stderr65
-rw-r--r--src/tools/clippy/tests/ui/ref_option/ref_option.all.fixed79
-rw-r--r--src/tools/clippy/tests/ui/ref_option/ref_option.private.fixed79
-rw-r--r--src/tools/clippy/tests/ui/ref_option/ref_option.rs79
-rw-r--r--src/tools/clippy/tests/ui/ref_option/ref_option_traits.rs40
-rw-r--r--src/tools/clippy/tests/ui/rest_pat_in_fully_bound_structs.fixed61
-rw-r--r--src/tools/clippy/tests/ui/rest_pat_in_fully_bound_structs.stderr18
-rw-r--r--src/tools/clippy/tests/ui/semicolon_inside_block.fixed17
-rw-r--r--src/tools/clippy/tests/ui/semicolon_inside_block.rs17
-rw-r--r--src/tools/clippy/tests/ui/semicolon_inside_block.stderr8
-rw-r--r--src/tools/clippy/tests/ui/track-diagnostics-clippy.stderr2
-rw-r--r--src/tools/clippy/tests/ui/transmute_ptr_to_ref.fixed39
-rw-r--r--src/tools/clippy/tests/ui/transmute_ptr_to_ref.rs39
-rw-r--r--src/tools/clippy/tests/ui/transmute_ptr_to_ref.stderr54
-rw-r--r--src/tools/clippy/tests/ui/use_self.fixed18
-rw-r--r--src/tools/clippy/tests/ui/use_self.rs16
-rw-r--r--src/tools/clippy/tests/ui/use_self.stderr8
-rw-r--r--src/tools/clippy/tests/ui/useless_attribute.fixed10
-rw-r--r--src/tools/clippy/tests/ui/useless_attribute.rs10
m---------src/tools/enzyme0
-rw-r--r--src/tools/miri/src/clock.rs16
-rw-r--r--src/tools/miri/src/lib.rs2
-rw-r--r--src/tools/tidy/Readme.md112
-rw-r--r--src/tools/tidy/src/lib.rs2
-rw-r--r--src/tools/tidy/src/pal.rs1
171 files changed, 4509 insertions, 2481 deletions
diff --git a/src/tools/cargo b/src/tools/cargo
-Subproject 24bb93c388fb8c211a37986539f24a819dc669d
+Subproject 966f94733bbc94ca51ff9f1e4c49ad250ebbdc5
diff --git a/src/tools/clippy/.github/ISSUE_TEMPLATE/new_lint.yml b/src/tools/clippy/.github/ISSUE_TEMPLATE/new_lint.yml
index a8202f6378f..6ad16aead60 100644
--- a/src/tools/clippy/.github/ISSUE_TEMPLATE/new_lint.yml
+++ b/src/tools/clippy/.github/ISSUE_TEMPLATE/new_lint.yml
@@ -1,7 +1,5 @@
 name: New lint suggestion
-description: |
-  Suggest a new Clippy lint (currently not accepting new lints)
-  Check out the Clippy book for more information about the feature freeze.
+description: Suggest a new Clippy lint.
 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 83bfd8e9c68..9e49f60892d 100644
--- a/src/tools/clippy/.github/PULL_REQUEST_TEMPLATE.md
+++ b/src/tools/clippy/.github/PULL_REQUEST_TEMPLATE.md
@@ -32,10 +32,6 @@ 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
deleted file mode 100644
index 5b139e76700..00000000000
--- a/src/tools/clippy/.github/workflows/feature_freeze.yml
+++ /dev/null
@@ -1,45 +0,0 @@
-name: Feature freeze check
-
-on:
-  pull_request_target:
-    types:
-      - opened
-    branches:
-      - master
-    paths:
-      - 'clippy_lints/src/declared_lints.rs'
-
-jobs:
-  auto-comment:
-    runs-on: ubuntu-latest
-
-    permissions:
-      pull-requests: write
-
-    # Do not in any case add code that runs anything coming from the content
-    # of the pull request, as malicious code would be able to access the private
-    # GitHub token.
-    steps:
-      - name: Add freeze warning comment
-        env:
-          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
-          GITHUB_REPOSITORY: ${{ github.repository }}
-          PR_NUMBER: ${{ github.event.pull_request.number }}
-        run: |
-          COMMENT=$(echo "**Seems that you are trying to add a new lint!**\n\
-          \n\
-          We 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 September 18 and [focusing on bugfixes](https://github.com/rust-lang/rust-clippy/issues/15086).\n\
-          \n\
-          Thanks a lot for your contribution, and sorry for the inconvenience.\n\
-          \n\
-          With ❤ from the Clippy team.\n\
-          \n\
-          @rustbot note Feature-freeze\n\
-          @rustbot blocked\n\
-          @rustbot label +A-lint"
-          )
-          curl -s -H "Authorization: Bearer $GITHUB_TOKEN" \
-             -H "Content-Type: application/vnd.github.raw+json" \
-             -X POST \
-             --data "{\"body\":\"${COMMENT}\"}" \
-             "https://api.github.com/repos/${GITHUB_REPOSITORY}/issues/${PR_NUMBER}/comments"
diff --git a/src/tools/clippy/.gitignore b/src/tools/clippy/.gitignore
index 36a4cdc1c35..666c4ceac4d 100644
--- a/src/tools/clippy/.gitignore
+++ b/src/tools/clippy/.gitignore
@@ -48,3 +48,6 @@ helper.txt
 
 # mdbook generated output
 /book/book
+
+# Remove jujutsu directory from search tools
+.jj
diff --git a/src/tools/clippy/CHANGELOG.md b/src/tools/clippy/CHANGELOG.md
index eb2a76a8183..3f26b9470e8 100644
--- a/src/tools/clippy/CHANGELOG.md
+++ b/src/tools/clippy/CHANGELOG.md
@@ -6,7 +6,152 @@ document.
 
 ## Unreleased / Beta / In Rust Nightly
 
-[4ef75291...master](https://github.com/rust-lang/rust-clippy/compare/4ef75291...master)
+[e9b7045...master](https://github.com/rust-lang/rust-clippy/compare/e9b7045...master)
+
+## Rust 1.90
+
+Current stable, released 2025-09-18
+
+[View all 118 merged pull requests](https://github.com/rust-lang/rust-clippy/pulls?q=merged%3A2025-06-13T15%3A55%3A04Z..2025-07-25T13%3A24%3A00Z+base%3Amaster)
+
+Note: This Clippy release does not introduce many new lints and is focused entirely on bug fixes — see
+[#15086](https://github.com/rust-lang/rust-clippy/issues/15086) for more details.
+
+## New Lints
+
+* Added [`manual_is_multiple_of`] to `complexity` [#14292](https://github.com/rust-lang/rust-clippy/pull/14292)
+* Added [`doc_broken_link`] to `pedantic` [#13696](https://github.com/rust-lang/rust-clippy/pull/13696)
+
+### Moves and Deprecations
+
+* Move [`uninlined_format_args`] to `pedantic` (from `style`, now allow-by-default) [#15287](https://github.com/rust-lang/rust-clippy/pull/15287)
+
+### Enhancements
+
+* [`or_fun_call`] now lints `Option::get_or_insert`, `Result::map_or`, `Option/Result::and` methods 
+  [#15071](https://github.com/rust-lang/rust-clippy/pull/15071) 
+  [#15073](https://github.com/rust-lang/rust-clippy/pull/15073) 
+  [#15074](https://github.com/rust-lang/rust-clippy/pull/15074)
+* [`incompatible_msrv`] now recognizes types exceeding MSRV 
+  [#15296](https://github.com/rust-lang/rust-clippy/pull/15296)
+* [`incompatible_msrv`] now checks the right MSRV when in a `const` context 
+  [#15297](https://github.com/rust-lang/rust-clippy/pull/15297)
+* [`zero_ptr`] now lints in `const` context as well 
+  [#15152](https://github.com/rust-lang/rust-clippy/pull/15152)
+* [`map_identity`],[`flat_map_identity`] now recognizes `|[x, y]| [x, y]` as an identity function
+  [#15229](https://github.com/rust-lang/rust-clippy/pull/15229)
+* [`exit`] no longer fails on the main function when using `--test` or `--all-targets` flag 
+  [#15222](https://github.com/rust-lang/rust-clippy/pull/15222)
+
+### False Positive Fixes
+
+* [`if_then_some_else_none`] fixed FP when require type coercion
+  [#15267](https://github.com/rust-lang/rust-clippy/pull/15267)
+* [`module_name_repetitions`] fixed FP on exported macros
+  [#15319](https://github.com/rust-lang/rust-clippy/pull/15319)
+* [`unused_async`] fixed FP on function with `todo!`
+  [#15308](https://github.com/rust-lang/rust-clippy/pull/15308)
+* [`useless_attribute`] fixed FP when using `#[expect(redundant_imports)]` and similar lint attributes 
+  on `use` statements
+  [#15318](https://github.com/rust-lang/rust-clippy/pull/15318)
+* [`pattern_type_mismatch`] fixed FP in external macro
+  [#15306](https://github.com/rust-lang/rust-clippy/pull/15306)
+* [`large_enum_variant`] fixed FP by not suggesting `Box` in `no_std` mode
+  [#15241](https://github.com/rust-lang/rust-clippy/pull/15241)
+* [`missing_inline_in_public_items`] fixed FP on functions with `extern`
+  [#15313](https://github.com/rust-lang/rust-clippy/pull/15313)
+* [`needless_range_loop`] fixed FP on array literals
+  [#15314](https://github.com/rust-lang/rust-clippy/pull/15314)
+* [`ptr_as_ptr`] fixed wrong suggestions with turbo fish
+  [#15289](https://github.com/rust-lang/rust-clippy/pull/15289)
+* [`range_plus_one`], [`range_minus_one`] fixed FP by restricting lint to cases where it is safe 
+  to switch the range type
+  [#14432](https://github.com/rust-lang/rust-clippy/pull/14432)
+* [`ptr_arg`] fixed FP with underscore binding to `&T` or `&mut T` argument
+  [#15105](https://github.com/rust-lang/rust-clippy/pull/15105)
+* [`unsafe_derive_deserialize`] fixed FP caused by the standard library's `pin!()` macro
+  [#15137](https://github.com/rust-lang/rust-clippy/pull/15137)
+* [`unused_trait_names`] fixed FP in macros
+  [#14947](https://github.com/rust-lang/rust-clippy/pull/14947)
+* [`expect_fun_call`] fixed invalid suggestions
+  [#15122](https://github.com/rust-lang/rust-clippy/pull/15122)
+* [`manual_is_multiple_of`] fixed various false positives
+  [#15205](https://github.com/rust-lang/rust-clippy/pull/15205)
+* [`manual_assert`] fixed wrong suggestions for macros
+  [#15264](https://github.com/rust-lang/rust-clippy/pull/15264)
+* [`expect_used`] fixed false negative when meeting `Option::ok().expect`
+  [#15253](https://github.com/rust-lang/rust-clippy/pull/15253)
+* [`manual_abs_diff`] fixed wrong suggestions behind refs
+  [#15265](https://github.com/rust-lang/rust-clippy/pull/15265)
+* [`approx_constant`] fixed FP with overly precise literals and non trivially formatted numerals
+  [#15236](https://github.com/rust-lang/rust-clippy/pull/15236)
+* [`arithmetic_side_effects`] fixed FP on `NonZeroU*.get() - 1`
+  [#15238](https://github.com/rust-lang/rust-clippy/pull/15238)
+* [`legacy_numeric_constants`] fixed suggestion when call is inside parentheses
+  [#15191](https://github.com/rust-lang/rust-clippy/pull/15191)
+* [`manual_is_variant_and`] fixed inverted suggestions that could lead to code with different semantics
+  [#15206](https://github.com/rust-lang/rust-clippy/pull/15206)
+* [`unnecessary_map_or`] fixed FP by not proposing to replace `map_or` call when types wouldn't be correct
+  [#15181](https://github.com/rust-lang/rust-clippy/pull/15181)
+* [`return_and_then`] fixed FP in case of a partially used expression
+  [#15115](https://github.com/rust-lang/rust-clippy/pull/15115)
+* [`manual_let_else`] fixed FP with binding subpattern with unused name
+  [#15118](https://github.com/rust-lang/rust-clippy/pull/15118)
+* [`suboptimal_flops`] fixed FP with ambiguous float types in mul_add suggestions
+  [#15133](https://github.com/rust-lang/rust-clippy/pull/15133)
+* [`borrow_as_ptr`] fixed FP by not removing cast to trait object pointer
+  [#15145](https://github.com/rust-lang/rust-clippy/pull/15145)
+* [`unnecessary_operation`] fixed FP by not removing casts if they are useful to type the expression
+  [#15182](https://github.com/rust-lang/rust-clippy/pull/15182)
+* [`empty_loop`] fixed FP on intrinsic function declaration
+  [#15201](https://github.com/rust-lang/rust-clippy/pull/15201)
+* [`doc_nested_refdefs`] fixed FP where task lists are reported as refdefs
+  [#15146](https://github.com/rust-lang/rust-clippy/pull/15146)
+* [`std_instead_of_core`] fixed FP when not all items come from the new crate
+  [#15165](https://github.com/rust-lang/rust-clippy/pull/15165)
+* [`swap_with_temporary`] fixed FP leading to different semantics being suggested
+  [#15172](https://github.com/rust-lang/rust-clippy/pull/15172)
+* [`cast_possible_truncation`] fixed FP by not giving suggestions inside const context
+  [#15164](https://github.com/rust-lang/rust-clippy/pull/15164)
+* [`missing_panics_doc`] fixed FP by allowing unwrap() and expect()s in const-only contexts
+  [#15170](https://github.com/rust-lang/rust-clippy/pull/15170)
+* [`disallowed_script_idents`] fixed FP on identifiers with `_`
+  [#15123](https://github.com/rust-lang/rust-clippy/pull/15123)
+* [`wildcard_enum_match_arm`] fixed wrong suggestions with raw identifiers
+  [#15093](https://github.com/rust-lang/rust-clippy/pull/15093)
+* [`borrow_deref_ref`] fixed FP by not proposing replacing a reborrow when the reborrow is itself mutably borrowed
+  [#14967](https://github.com/rust-lang/rust-clippy/pull/14967)
+* [`manual_ok_err`] fixed wrong suggestions with references
+  [#15053](https://github.com/rust-lang/rust-clippy/pull/15053)
+* [`identity_op`] fixed FP when encountering `Default::default()`
+  [#15028](https://github.com/rust-lang/rust-clippy/pull/15028)
+* [`exhaustive_structs`] fixed FP on structs with default valued field
+  [#15022](https://github.com/rust-lang/rust-clippy/pull/15022)
+* [`collapsible_else_if`] fixed FP on conditionally compiled stmt
+  [#14906](https://github.com/rust-lang/rust-clippy/pull/14906)
+* [`missing_const_for_fn`] fixed FP by checking MSRV before emitting lint on function containing 
+  non-`Sized` trait bounds
+  [#15080](https://github.com/rust-lang/rust-clippy/pull/15080)
+* [`question_mark`] fixed FP when else branch of let-else contains `#[cfg]`
+  [#15082](https://github.com/rust-lang/rust-clippy/pull/15082)
+
+### ICE Fixes
+
+* [`single_match`] fixed ICE with deref patterns and string literals 
+  [#15124](https://github.com/rust-lang/rust-clippy/pull/15124)
+* [`needless_doctest_main`] fixed panic when doctest is invalid
+  [#15052](https://github.com/rust-lang/rust-clippy/pull/15052)
+* [`zero_sized_map_values`] do not attempt to compute size of a type with escaping lifetimes
+  [#15434](https://github.com/rust-lang/rust-clippy/pull/15434)
+
+### Documentation Improvements
+
+* [`manual_is_variant_and`] improved documentation to include equality comparison patterns 
+  [#15239](https://github.com/rust-lang/rust-clippy/pull/15239)
+* [`uninlined_format_args`] improved documentation with example of how to fix a `{:?}` parameter
+  [#15228](https://github.com/rust-lang/rust-clippy/pull/15228)
+* [`undocumented_unsafe_blocks`] improved documentation wording 
+  [#15213](https://github.com/rust-lang/rust-clippy/pull/15213)
 
 ## Rust 1.89
 
@@ -6408,6 +6553,7 @@ Released 2018-09-13
 [`redundant_feature_names`]: https://rust-lang.github.io/rust-clippy/master/index.html#redundant_feature_names
 [`redundant_field_names`]: https://rust-lang.github.io/rust-clippy/master/index.html#redundant_field_names
 [`redundant_guards`]: https://rust-lang.github.io/rust-clippy/master/index.html#redundant_guards
+[`redundant_iter_cloned`]: https://rust-lang.github.io/rust-clippy/master/index.html#redundant_iter_cloned
 [`redundant_locals`]: https://rust-lang.github.io/rust-clippy/master/index.html#redundant_locals
 [`redundant_pattern`]: https://rust-lang.github.io/rust-clippy/master/index.html#redundant_pattern
 [`redundant_pattern_matching`]: https://rust-lang.github.io/rust-clippy/master/index.html#redundant_pattern_matching
diff --git a/src/tools/clippy/Cargo.toml b/src/tools/clippy/Cargo.toml
index b3618932ded..e0638349989 100644
--- a/src/tools/clippy/Cargo.toml
+++ b/src/tools/clippy/Cargo.toml
@@ -1,6 +1,6 @@
 [package]
 name = "clippy"
-version = "0.1.91"
+version = "0.1.92"
 description = "A bunch of helpful lints to avoid common pitfalls in Rust"
 repository = "https://github.com/rust-lang/rust-clippy"
 readme = "README.md"
diff --git a/src/tools/clippy/book/src/README.md b/src/tools/clippy/book/src/README.md
index db73b49ecc2..5d2c3972b06 100644
--- a/src/tools/clippy/book/src/README.md
+++ b/src/tools/clippy/book/src/README.md
@@ -1,9 +1,5 @@
 # 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 b66c3481e49..39fe7358ed8 100644
--- a/src/tools/clippy/book/src/SUMMARY.md
+++ b/src/tools/clippy/book/src/SUMMARY.md
@@ -13,7 +13,6 @@
     - [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 a42a2983744..2b89e94cf8f 100644
--- a/src/tools/clippy/book/src/development/adding_lints.md
+++ b/src/tools/clippy/book/src/development/adding_lints.md
@@ -1,8 +1,5 @@
 # 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
deleted file mode 100644
index 260cb136cc0..00000000000
--- a/src/tools/clippy/book/src/development/feature_freeze.md
+++ /dev/null
@@ -1,55 +0,0 @@
-# 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/clippy_config/Cargo.toml b/src/tools/clippy/clippy_config/Cargo.toml
index 6ad2cf0d0b1..f8c748290e4 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.91"
+version = "0.1.92"
 edition = "2024"
 publish = false
 
diff --git a/src/tools/clippy/clippy_lints/Cargo.toml b/src/tools/clippy/clippy_lints/Cargo.toml
index 70184ee2ca5..51e59ae2050 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.91"
+version = "0.1.92"
 description = "A bunch of helpful lints to avoid common pitfalls in Rust"
 repository = "https://github.com/rust-lang/rust-clippy"
 readme = "README.md"
diff --git a/src/tools/clippy/clippy_lints/src/attrs/useless_attribute.rs b/src/tools/clippy/clippy_lints/src/attrs/useless_attribute.rs
index b9b5cedb5aa..1cebc18edc9 100644
--- a/src/tools/clippy/clippy_lints/src/attrs/useless_attribute.rs
+++ b/src/tools/clippy/clippy_lints/src/attrs/useless_attribute.rs
@@ -30,6 +30,7 @@ pub(super) fn check(cx: &EarlyContext<'_>, item: &Item, attrs: &[Attribute]) {
                                 sym::ambiguous_glob_reexports
                                     | sym::dead_code
                                     | sym::deprecated
+                                    | sym::deprecated_in_future
                                     | sym::hidden_glob_reexports
                                     | sym::unreachable_pub
                                     | sym::unused
diff --git a/src/tools/clippy/clippy_lints/src/casts/as_underscore.rs b/src/tools/clippy/clippy_lints/src/casts/as_underscore.rs
index 3ac486dd63f..a73e48e5fd5 100644
--- a/src/tools/clippy/clippy_lints/src/casts/as_underscore.rs
+++ b/src/tools/clippy/clippy_lints/src/casts/as_underscore.rs
@@ -2,7 +2,7 @@ use clippy_utils::diagnostics::span_lint_and_then;
 use rustc_errors::Applicability;
 use rustc_hir::{Expr, Ty, TyKind};
 use rustc_lint::LateContext;
-use rustc_middle::ty;
+use rustc_middle::ty::IsSuggestable;
 
 use super::AS_UNDERSCORE;
 
@@ -10,15 +10,15 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, ty: &'tc
     if matches!(ty.kind, TyKind::Infer(())) {
         span_lint_and_then(cx, AS_UNDERSCORE, expr.span, "using `as _` conversion", |diag| {
             let ty_resolved = cx.typeck_results().expr_ty(expr);
-            if let ty::Error(_) = ty_resolved.kind() {
-                diag.help("consider giving the type explicitly");
-            } else {
+            if ty_resolved.is_suggestable(cx.tcx, true) {
                 diag.span_suggestion(
                     ty.span,
                     "consider giving the type explicitly",
                     ty_resolved,
                     Applicability::MachineApplicable,
                 );
+            } else {
+                diag.help("consider giving the type explicitly");
             }
         });
     }
diff --git a/src/tools/clippy/clippy_lints/src/casts/cast_possible_wrap.rs b/src/tools/clippy/clippy_lints/src/casts/cast_possible_wrap.rs
index e26c03ccda9..9eaa6e4cf26 100644
--- a/src/tools/clippy/clippy_lints/src/casts/cast_possible_wrap.rs
+++ b/src/tools/clippy/clippy_lints/src/casts/cast_possible_wrap.rs
@@ -1,4 +1,7 @@
 use clippy_utils::diagnostics::span_lint_and_then;
+use clippy_utils::msrvs::{self, Msrv};
+use clippy_utils::sugg::Sugg;
+use rustc_errors::Applicability;
 use rustc_hir::Expr;
 use rustc_lint::LateContext;
 use rustc_middle::ty::Ty;
@@ -16,7 +19,14 @@ enum EmitState {
     LintOnPtrSize(u64),
 }
 
-pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, cast_from: Ty<'_>, cast_to: Ty<'_>) {
+pub(super) fn check(
+    cx: &LateContext<'_>,
+    expr: &Expr<'_>,
+    cast_op: &Expr<'_>,
+    cast_from: Ty<'_>,
+    cast_to: Ty<'_>,
+    msrv: Msrv,
+) {
     let (Some(from_nbits), Some(to_nbits)) = (
         utils::int_ty_to_nbits(cx.tcx, cast_from),
         utils::int_ty_to_nbits(cx.tcx, cast_to),
@@ -85,5 +95,23 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, cast_from: Ty<'_>, ca
                 .note("`usize` and `isize` may be as small as 16 bits on some platforms")
                 .note("for more information see https://doc.rust-lang.org/reference/types/numeric.html#machine-dependent-integer-types");
         }
+
+        if msrv.meets(cx, msrvs::INTEGER_SIGN_CAST)
+            && let Some(cast) = utils::is_signedness_cast(cast_from, cast_to)
+        {
+            let method = match cast {
+                utils::CastTo::Signed => "cast_signed()",
+                utils::CastTo::Unsigned => "cast_unsigned()",
+            };
+            let mut app = Applicability::MaybeIncorrect;
+            let sugg = Sugg::hir_with_context(cx, cast_op, expr.span.ctxt(), "..", &mut app);
+
+            diag.span_suggestion(
+                expr.span,
+                format!("if this is intentional, use `{method}` instead"),
+                format!("{}.{method}", sugg.maybe_paren()),
+                app,
+            );
+        }
     });
 }
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 a70bd886191..f870d27b796 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
@@ -2,15 +2,18 @@ use std::convert::Infallible;
 use std::ops::ControlFlow;
 
 use clippy_utils::consts::{ConstEvalCtxt, Constant};
-use clippy_utils::diagnostics::span_lint;
+use clippy_utils::diagnostics::span_lint_and_then;
+use clippy_utils::msrvs::{self, Msrv};
+use clippy_utils::sugg::Sugg;
 use clippy_utils::visitors::{Descend, for_each_expr_without_closures};
 use clippy_utils::{method_chain_args, sext, sym};
+use rustc_errors::Applicability;
 use rustc_hir::{BinOpKind, Expr, ExprKind};
 use rustc_lint::LateContext;
 use rustc_middle::ty::{self, Ty};
 use rustc_span::Symbol;
 
-use super::CAST_SIGN_LOSS;
+use super::{CAST_SIGN_LOSS, utils};
 
 /// A list of methods that can never return a negative value.
 /// Includes methods that panic rather than returning a negative value.
@@ -42,13 +45,33 @@ pub(super) fn check<'cx>(
     cast_op: &Expr<'_>,
     cast_from: Ty<'cx>,
     cast_to: Ty<'_>,
+    msrv: Msrv,
 ) {
     if should_lint(cx, cast_op, cast_from, cast_to) {
-        span_lint(
+        span_lint_and_then(
             cx,
             CAST_SIGN_LOSS,
             expr.span,
             format!("casting `{cast_from}` to `{cast_to}` may lose the sign of the value"),
+            |diag| {
+                if msrv.meets(cx, msrvs::INTEGER_SIGN_CAST)
+                    && let Some(cast) = utils::is_signedness_cast(cast_from, cast_to)
+                {
+                    let method = match cast {
+                        utils::CastTo::Signed => "cast_signed()",
+                        utils::CastTo::Unsigned => "cast_unsigned()",
+                    };
+                    let mut app = Applicability::MaybeIncorrect;
+                    let sugg = Sugg::hir_with_context(cx, cast_op, expr.span.ctxt(), "..", &mut app);
+
+                    diag.span_suggestion(
+                        expr.span,
+                        format!("if this is intentional, use `{method}` instead"),
+                        format!("{}.{method}", sugg.maybe_paren()),
+                        app,
+                    );
+                }
+            },
         );
     }
 }
diff --git a/src/tools/clippy/clippy_lints/src/casts/mod.rs b/src/tools/clippy/clippy_lints/src/casts/mod.rs
index d2e62ee56e4..47cc1da0a6e 100644
--- a/src/tools/clippy/clippy_lints/src/casts/mod.rs
+++ b/src/tools/clippy/clippy_lints/src/casts/mod.rs
@@ -890,9 +890,9 @@ impl<'tcx> LateLintPass<'tcx> for Casts {
             if cast_to.is_numeric() {
                 cast_possible_truncation::check(cx, expr, cast_from_expr, cast_from, cast_to, cast_to_hir.span);
                 if cast_from.is_numeric() {
-                    cast_possible_wrap::check(cx, expr, cast_from, cast_to);
+                    cast_possible_wrap::check(cx, expr, cast_from_expr, cast_from, cast_to, self.msrv);
                     cast_precision_loss::check(cx, expr, cast_from, cast_to);
-                    cast_sign_loss::check(cx, expr, cast_from_expr, cast_from, cast_to);
+                    cast_sign_loss::check(cx, expr, cast_from_expr, cast_from, cast_to, self.msrv);
                     cast_abs_to_unsigned::check(cx, expr, cast_from_expr, cast_from, cast_to, self.msrv);
                     cast_nan_to_int::check(cx, expr, cast_from_expr, cast_from, cast_to);
                 }
diff --git a/src/tools/clippy/clippy_lints/src/casts/utils.rs b/src/tools/clippy/clippy_lints/src/casts/utils.rs
index d846d78b9ee..707fc2a8eed 100644
--- a/src/tools/clippy/clippy_lints/src/casts/utils.rs
+++ b/src/tools/clippy/clippy_lints/src/casts/utils.rs
@@ -60,3 +60,18 @@ pub(super) fn enum_ty_to_nbits(adt: AdtDef<'_>, tcx: TyCtxt<'_>) -> u64 {
         neg_bits.max(pos_bits).into()
     }
 }
+
+pub(super) enum CastTo {
+    Signed,
+    Unsigned,
+}
+/// Returns `Some` if the type cast is between 2 integral types that differ
+/// only in signedness, otherwise `None`. The value of `Some` is which
+/// signedness is casted to.
+pub(super) fn is_signedness_cast(cast_from: Ty<'_>, cast_to: Ty<'_>) -> Option<CastTo> {
+    match (cast_from.kind(), cast_to.kind()) {
+        (ty::Int(from), ty::Uint(to)) if from.to_unsigned() == *to => Some(CastTo::Unsigned),
+        (ty::Uint(from), ty::Int(to)) if *from == to.to_unsigned() => Some(CastTo::Signed),
+        _ => None,
+    }
+}
diff --git a/src/tools/clippy/clippy_lints/src/declared_lints.rs b/src/tools/clippy/clippy_lints/src/declared_lints.rs
index d0c7443a4a4..2a4bedc1845 100644
--- a/src/tools/clippy/clippy_lints/src/declared_lints.rs
+++ b/src/tools/clippy/clippy_lints/src/declared_lints.rs
@@ -448,10 +448,12 @@ pub static LINTS: &[&::declare_clippy_lint::LintInfo] = &[
     crate::methods::OR_THEN_UNWRAP_INFO,
     crate::methods::PATH_BUF_PUSH_OVERWRITE_INFO,
     crate::methods::PATH_ENDS_WITH_EXT_INFO,
+    crate::methods::PTR_OFFSET_WITH_CAST_INFO,
     crate::methods::RANGE_ZIP_WITH_LEN_INFO,
     crate::methods::READONLY_WRITE_LOCK_INFO,
     crate::methods::READ_LINE_WITHOUT_TRIM_INFO,
     crate::methods::REDUNDANT_AS_STR_INFO,
+    crate::methods::REDUNDANT_ITER_CLONED_INFO,
     crate::methods::REPEAT_ONCE_INFO,
     crate::methods::RESULT_FILTER_MAP_INFO,
     crate::methods::RESULT_MAP_OR_INTO_OPTION_INFO,
@@ -503,7 +505,6 @@ pub static LINTS: &[&::declare_clippy_lint::LintInfo] = &[
     crate::min_ident_chars::MIN_IDENT_CHARS_INFO,
     crate::minmax::MIN_MAX_INFO,
     crate::misc::SHORT_CIRCUIT_STATEMENT_INFO,
-    crate::misc::TOPLEVEL_REF_ARG_INFO,
     crate::misc::USED_UNDERSCORE_BINDING_INFO,
     crate::misc::USED_UNDERSCORE_ITEMS_INFO,
     crate::misc_early::BUILTIN_TYPE_SHADOW_INFO,
@@ -625,7 +626,6 @@ pub static LINTS: &[&::declare_clippy_lint::LintInfo] = &[
     crate::ptr::MUT_FROM_REF_INFO,
     crate::ptr::PTR_ARG_INFO,
     crate::ptr::PTR_EQ_INFO,
-    crate::ptr_offset_with_cast::PTR_OFFSET_WITH_CAST_INFO,
     crate::pub_underscore_fields::PUB_UNDERSCORE_FIELDS_INFO,
     crate::pub_use::PUB_USE_INFO,
     crate::question_mark::QUESTION_MARK_INFO,
@@ -706,6 +706,7 @@ pub static LINTS: &[&::declare_clippy_lint::LintInfo] = &[
     crate::tests_outside_test_module::TESTS_OUTSIDE_TEST_MODULE_INFO,
     crate::to_digit_is_some::TO_DIGIT_IS_SOME_INFO,
     crate::to_string_trait_impl::TO_STRING_TRAIT_IMPL_INFO,
+    crate::toplevel_ref_arg::TOPLEVEL_REF_ARG_INFO,
     crate::trailing_empty_array::TRAILING_EMPTY_ARRAY_INFO,
     crate::trait_bounds::TRAIT_DUPLICATION_IN_BOUNDS_INFO,
     crate::trait_bounds::TYPE_REPETITION_IN_BOUNDS_INFO,
diff --git a/src/tools/clippy/clippy_lints/src/dereference.rs b/src/tools/clippy/clippy_lints/src/dereference.rs
index 9645a26a68a..a70105db194 100644
--- a/src/tools/clippy/clippy_lints/src/dereference.rs
+++ b/src/tools/clippy/clippy_lints/src/dereference.rs
@@ -1,10 +1,9 @@
 use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_hir_and_then};
 use clippy_utils::source::{snippet_with_applicability, snippet_with_context};
 use clippy_utils::sugg::has_enclosing_paren;
-use clippy_utils::ty::{adjust_derefs_manually_drop, implements_trait, is_manually_drop};
+use clippy_utils::ty::{adjust_derefs_manually_drop, implements_trait, is_manually_drop, peel_and_count_ty_refs};
 use clippy_utils::{
     DefinedTy, ExprUseNode, expr_use_ctxt, get_parent_expr, is_block_like, is_lint_allowed, path_to_local,
-    peel_middle_ty_refs,
 };
 use rustc_ast::util::parser::ExprPrecedence;
 use rustc_data_structures::fx::FxIndexMap;
@@ -942,7 +941,7 @@ fn report<'tcx>(
             let (expr_str, expr_is_macro_call) =
                 snippet_with_context(cx, expr.span, data.first_expr.span.ctxt(), "..", &mut app);
             let ty = typeck.expr_ty(expr);
-            let (_, ref_count) = peel_middle_ty_refs(ty);
+            let (_, ref_count, _) = peel_and_count_ty_refs(ty);
             let deref_str = if ty_changed_count >= ref_count && ref_count != 0 {
                 // a deref call changing &T -> &U requires two deref operators the first time
                 // this occurs. One to remove the reference, a second to call the deref impl.
@@ -1045,7 +1044,7 @@ fn report<'tcx>(
             if let ty::Ref(_, dst, _) = data.adjusted_ty.kind()
                 && dst.is_slice()
             {
-                let (src, n_src_refs) = peel_middle_ty_refs(ty);
+                let (src, n_src_refs, _) = peel_and_count_ty_refs(ty);
                 if n_src_refs >= 2 && src.is_array() {
                     return;
                 }
diff --git a/src/tools/clippy/clippy_lints/src/derive.rs b/src/tools/clippy/clippy_lints/src/derive.rs
deleted file mode 100644
index c53a957f6a8..00000000000
--- a/src/tools/clippy/clippy_lints/src/derive.rs
+++ /dev/null
@@ -1,527 +0,0 @@
-use std::ops::ControlFlow;
-
-use clippy_utils::diagnostics::{span_lint_and_note, span_lint_and_then, span_lint_hir_and_then};
-use clippy_utils::ty::{implements_trait, implements_trait_with_env, is_copy};
-use clippy_utils::{has_non_exhaustive_attr, is_lint_allowed, paths};
-use rustc_errors::Applicability;
-use rustc_hir::def_id::DefId;
-use rustc_hir::intravisit::{FnKind, Visitor, walk_expr, walk_fn, walk_item};
-use rustc_hir::{self as hir, BlockCheckMode, BodyId, Expr, ExprKind, FnDecl, Impl, Item, ItemKind, UnsafeSource};
-use rustc_lint::{LateContext, LateLintPass};
-use rustc_middle::hir::nested_filter;
-use rustc_middle::ty::{
-    self, ClauseKind, GenericArgKind, GenericParamDefKind, ParamEnv, TraitPredicate, Ty, TyCtxt, Upcast,
-};
-use rustc_session::declare_lint_pass;
-use rustc_span::def_id::LocalDefId;
-use rustc_span::{Span, sym};
-
-declare_clippy_lint! {
-    /// ### What it does
-    /// Lints against manual `PartialEq` implementations for types with a derived `Hash`
-    /// implementation.
-    ///
-    /// ### Why is this bad?
-    /// The implementation of these traits must agree (for
-    /// example for use with `HashMap`) so it’s probably a bad idea to use a
-    /// default-generated `Hash` implementation with an explicitly defined
-    /// `PartialEq`. In particular, the following must hold for any type:
-    ///
-    /// ```text
-    /// k1 == k2 ⇒ hash(k1) == hash(k2)
-    /// ```
-    ///
-    /// ### Example
-    /// ```ignore
-    /// #[derive(Hash)]
-    /// struct Foo;
-    ///
-    /// impl PartialEq for Foo {
-    ///     ...
-    /// }
-    /// ```
-    #[clippy::version = "pre 1.29.0"]
-    pub DERIVED_HASH_WITH_MANUAL_EQ,
-    correctness,
-    "deriving `Hash` but implementing `PartialEq` explicitly"
-}
-
-declare_clippy_lint! {
-    /// ### What it does
-    /// Lints against manual `PartialOrd` and `Ord` implementations for types with a derived `Ord`
-    /// or `PartialOrd` implementation.
-    ///
-    /// ### Why is this bad?
-    /// The implementation of these traits must agree (for
-    /// example for use with `sort`) so it’s probably a bad idea to use a
-    /// default-generated `Ord` implementation with an explicitly defined
-    /// `PartialOrd`. In particular, the following must hold for any type
-    /// implementing `Ord`:
-    ///
-    /// ```text
-    /// k1.cmp(&k2) == k1.partial_cmp(&k2).unwrap()
-    /// ```
-    ///
-    /// ### Example
-    /// ```rust,ignore
-    /// #[derive(Ord, PartialEq, Eq)]
-    /// struct Foo;
-    ///
-    /// impl PartialOrd for Foo {
-    ///     ...
-    /// }
-    /// ```
-    /// Use instead:
-    /// ```rust,ignore
-    /// #[derive(PartialEq, Eq)]
-    /// struct Foo;
-    ///
-    /// impl PartialOrd for Foo {
-    ///     fn partial_cmp(&self, other: &Foo) -> Option<Ordering> {
-    ///        Some(self.cmp(other))
-    ///     }
-    /// }
-    ///
-    /// impl Ord for Foo {
-    ///     ...
-    /// }
-    /// ```
-    /// or, if you don't need a custom ordering:
-    /// ```rust,ignore
-    /// #[derive(Ord, PartialOrd, PartialEq, Eq)]
-    /// struct Foo;
-    /// ```
-    #[clippy::version = "1.47.0"]
-    pub DERIVE_ORD_XOR_PARTIAL_ORD,
-    correctness,
-    "deriving `Ord` but implementing `PartialOrd` explicitly"
-}
-
-declare_clippy_lint! {
-    /// ### What it does
-    /// Checks for explicit `Clone` implementations for `Copy`
-    /// types.
-    ///
-    /// ### Why is this bad?
-    /// To avoid surprising behavior, these traits should
-    /// agree and the behavior of `Copy` cannot be overridden. In almost all
-    /// situations a `Copy` type should have a `Clone` implementation that does
-    /// nothing more than copy the object, which is what `#[derive(Copy, Clone)]`
-    /// gets you.
-    ///
-    /// ### Example
-    /// ```rust,ignore
-    /// #[derive(Copy)]
-    /// struct Foo;
-    ///
-    /// impl Clone for Foo {
-    ///     // ..
-    /// }
-    /// ```
-    #[clippy::version = "pre 1.29.0"]
-    pub EXPL_IMPL_CLONE_ON_COPY,
-    pedantic,
-    "implementing `Clone` explicitly on `Copy` types"
-}
-
-declare_clippy_lint! {
-    /// ### What it does
-    /// Checks for deriving `serde::Deserialize` on a type that
-    /// has methods using `unsafe`.
-    ///
-    /// ### Why is this bad?
-    /// Deriving `serde::Deserialize` will create a constructor
-    /// that may violate invariants held by another constructor.
-    ///
-    /// ### Example
-    /// ```rust,ignore
-    /// use serde::Deserialize;
-    ///
-    /// #[derive(Deserialize)]
-    /// pub struct Foo {
-    ///     // ..
-    /// }
-    ///
-    /// impl Foo {
-    ///     pub fn new() -> Self {
-    ///         // setup here ..
-    ///     }
-    ///
-    ///     pub unsafe fn parts() -> (&str, &str) {
-    ///         // assumes invariants hold
-    ///     }
-    /// }
-    /// ```
-    #[clippy::version = "1.45.0"]
-    pub UNSAFE_DERIVE_DESERIALIZE,
-    pedantic,
-    "deriving `serde::Deserialize` on a type that has methods using `unsafe`"
-}
-
-declare_clippy_lint! {
-    /// ### What it does
-    /// Checks for types that derive `PartialEq` and could implement `Eq`.
-    ///
-    /// ### Why is this bad?
-    /// If a type `T` derives `PartialEq` and all of its members implement `Eq`,
-    /// then `T` can always implement `Eq`. Implementing `Eq` allows `T` to be used
-    /// in APIs that require `Eq` types. It also allows structs containing `T` to derive
-    /// `Eq` themselves.
-    ///
-    /// ### Example
-    /// ```no_run
-    /// #[derive(PartialEq)]
-    /// struct Foo {
-    ///     i_am_eq: i32,
-    ///     i_am_eq_too: Vec<String>,
-    /// }
-    /// ```
-    /// Use instead:
-    /// ```no_run
-    /// #[derive(PartialEq, Eq)]
-    /// struct Foo {
-    ///     i_am_eq: i32,
-    ///     i_am_eq_too: Vec<String>,
-    /// }
-    /// ```
-    #[clippy::version = "1.63.0"]
-    pub DERIVE_PARTIAL_EQ_WITHOUT_EQ,
-    nursery,
-    "deriving `PartialEq` on a type that can implement `Eq`, without implementing `Eq`"
-}
-
-declare_lint_pass!(Derive => [
-    EXPL_IMPL_CLONE_ON_COPY,
-    DERIVED_HASH_WITH_MANUAL_EQ,
-    DERIVE_ORD_XOR_PARTIAL_ORD,
-    UNSAFE_DERIVE_DESERIALIZE,
-    DERIVE_PARTIAL_EQ_WITHOUT_EQ
-]);
-
-impl<'tcx> LateLintPass<'tcx> for Derive {
-    fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'_>) {
-        if let ItemKind::Impl(Impl {
-            of_trait: Some(of_trait),
-            ..
-        }) = item.kind
-        {
-            let trait_ref = &of_trait.trait_ref;
-            let ty = cx.tcx.type_of(item.owner_id).instantiate_identity();
-            let is_automatically_derived = cx.tcx.is_automatically_derived(item.owner_id.to_def_id());
-
-            check_hash_peq(cx, item.span, trait_ref, ty, is_automatically_derived);
-            check_ord_partial_ord(cx, item.span, trait_ref, ty, is_automatically_derived);
-
-            if is_automatically_derived {
-                check_unsafe_derive_deserialize(cx, item, trait_ref, ty);
-                check_partial_eq_without_eq(cx, item.span, trait_ref, ty);
-            } else {
-                check_copy_clone(cx, item, trait_ref, ty);
-            }
-        }
-    }
-}
-
-/// Implementation of the `DERIVED_HASH_WITH_MANUAL_EQ` lint.
-fn check_hash_peq<'tcx>(
-    cx: &LateContext<'tcx>,
-    span: Span,
-    trait_ref: &hir::TraitRef<'_>,
-    ty: Ty<'tcx>,
-    hash_is_automatically_derived: bool,
-) {
-    if let Some(peq_trait_def_id) = cx.tcx.lang_items().eq_trait()
-        && let Some(def_id) = trait_ref.trait_def_id()
-        && cx.tcx.is_diagnostic_item(sym::Hash, def_id)
-    {
-        // Look for the PartialEq implementations for `ty`
-        cx.tcx.for_each_relevant_impl(peq_trait_def_id, ty, |impl_id| {
-            let peq_is_automatically_derived = cx.tcx.is_automatically_derived(impl_id);
-
-            if !hash_is_automatically_derived || peq_is_automatically_derived {
-                return;
-            }
-
-            let trait_ref = cx.tcx.impl_trait_ref(impl_id).expect("must be a trait implementation");
-
-            // Only care about `impl PartialEq<Foo> for Foo`
-            // For `impl PartialEq<B> for A, input_types is [A, B]
-            if trait_ref.instantiate_identity().args.type_at(1) == ty {
-                span_lint_and_then(
-                    cx,
-                    DERIVED_HASH_WITH_MANUAL_EQ,
-                    span,
-                    "you are deriving `Hash` but have implemented `PartialEq` explicitly",
-                    |diag| {
-                        if let Some(local_def_id) = impl_id.as_local() {
-                            let hir_id = cx.tcx.local_def_id_to_hir_id(local_def_id);
-                            diag.span_note(cx.tcx.hir_span(hir_id), "`PartialEq` implemented here");
-                        }
-                    },
-                );
-            }
-        });
-    }
-}
-
-/// Implementation of the `DERIVE_ORD_XOR_PARTIAL_ORD` lint.
-fn check_ord_partial_ord<'tcx>(
-    cx: &LateContext<'tcx>,
-    span: Span,
-    trait_ref: &hir::TraitRef<'_>,
-    ty: Ty<'tcx>,
-    ord_is_automatically_derived: bool,
-) {
-    if let Some(ord_trait_def_id) = cx.tcx.get_diagnostic_item(sym::Ord)
-        && let Some(partial_ord_trait_def_id) = cx.tcx.lang_items().partial_ord_trait()
-        && let Some(def_id) = &trait_ref.trait_def_id()
-        && *def_id == ord_trait_def_id
-    {
-        // Look for the PartialOrd implementations for `ty`
-        cx.tcx.for_each_relevant_impl(partial_ord_trait_def_id, ty, |impl_id| {
-            let partial_ord_is_automatically_derived = cx.tcx.is_automatically_derived(impl_id);
-
-            if partial_ord_is_automatically_derived == ord_is_automatically_derived {
-                return;
-            }
-
-            let trait_ref = cx.tcx.impl_trait_ref(impl_id).expect("must be a trait implementation");
-
-            // Only care about `impl PartialOrd<Foo> for Foo`
-            // For `impl PartialOrd<B> for A, input_types is [A, B]
-            if trait_ref.instantiate_identity().args.type_at(1) == ty {
-                let mess = if partial_ord_is_automatically_derived {
-                    "you are implementing `Ord` explicitly but have derived `PartialOrd`"
-                } else {
-                    "you are deriving `Ord` but have implemented `PartialOrd` explicitly"
-                };
-
-                span_lint_and_then(cx, DERIVE_ORD_XOR_PARTIAL_ORD, span, mess, |diag| {
-                    if let Some(local_def_id) = impl_id.as_local() {
-                        let hir_id = cx.tcx.local_def_id_to_hir_id(local_def_id);
-                        diag.span_note(cx.tcx.hir_span(hir_id), "`PartialOrd` implemented here");
-                    }
-                });
-            }
-        });
-    }
-}
-
-/// Implementation of the `EXPL_IMPL_CLONE_ON_COPY` lint.
-fn check_copy_clone<'tcx>(cx: &LateContext<'tcx>, item: &Item<'_>, trait_ref: &hir::TraitRef<'_>, ty: Ty<'tcx>) {
-    let clone_id = match cx.tcx.lang_items().clone_trait() {
-        Some(id) if trait_ref.trait_def_id() == Some(id) => id,
-        _ => return,
-    };
-    let Some(copy_id) = cx.tcx.lang_items().copy_trait() else {
-        return;
-    };
-    let (ty_adt, ty_subs) = match *ty.kind() {
-        // Unions can't derive clone.
-        ty::Adt(adt, subs) if !adt.is_union() => (adt, subs),
-        _ => return,
-    };
-    // If the current self type doesn't implement Copy (due to generic constraints), search to see if
-    // there's a Copy impl for any instance of the adt.
-    if !is_copy(cx, ty) {
-        if ty_subs.non_erasable_generics().next().is_some() {
-            let has_copy_impl = cx.tcx.local_trait_impls(copy_id).iter().any(|&id| {
-                matches!(cx.tcx.type_of(id).instantiate_identity().kind(), ty::Adt(adt, _)
-                                        if ty_adt.did() == adt.did())
-            });
-            if !has_copy_impl {
-                return;
-            }
-        } else {
-            return;
-        }
-    }
-    // Derive constrains all generic types to requiring Clone. Check if any type is not constrained for
-    // this impl.
-    if ty_subs.types().any(|ty| !implements_trait(cx, ty, clone_id, &[])) {
-        return;
-    }
-    // `#[repr(packed)]` structs with type/const parameters can't derive `Clone`.
-    // https://github.com/rust-lang/rust-clippy/issues/10188
-    if ty_adt.repr().packed()
-        && ty_subs
-            .iter()
-            .any(|arg| matches!(arg.kind(), GenericArgKind::Type(_) | GenericArgKind::Const(_)))
-    {
-        return;
-    }
-    // The presence of `unsafe` fields prevents deriving `Clone` automatically
-    if ty_adt.all_fields().any(|f| f.safety.is_unsafe()) {
-        return;
-    }
-
-    span_lint_and_note(
-        cx,
-        EXPL_IMPL_CLONE_ON_COPY,
-        item.span,
-        "you are implementing `Clone` explicitly on a `Copy` type",
-        Some(item.span),
-        "consider deriving `Clone` or removing `Copy`",
-    );
-}
-
-/// Implementation of the `UNSAFE_DERIVE_DESERIALIZE` lint.
-fn check_unsafe_derive_deserialize<'tcx>(
-    cx: &LateContext<'tcx>,
-    item: &Item<'_>,
-    trait_ref: &hir::TraitRef<'_>,
-    ty: Ty<'tcx>,
-) {
-    fn has_unsafe<'tcx>(cx: &LateContext<'tcx>, item: &'tcx Item<'_>) -> bool {
-        let mut visitor = UnsafeVisitor { cx };
-        walk_item(&mut visitor, item).is_break()
-    }
-
-    if let Some(trait_def_id) = trait_ref.trait_def_id()
-        && paths::SERDE_DESERIALIZE.matches(cx, trait_def_id)
-        && let ty::Adt(def, _) = ty.kind()
-        && let Some(local_def_id) = def.did().as_local()
-        && let adt_hir_id = cx.tcx.local_def_id_to_hir_id(local_def_id)
-        && !is_lint_allowed(cx, UNSAFE_DERIVE_DESERIALIZE, adt_hir_id)
-        && cx
-            .tcx
-            .inherent_impls(def.did())
-            .iter()
-            .map(|imp_did| cx.tcx.hir_expect_item(imp_did.expect_local()))
-            .any(|imp| has_unsafe(cx, imp))
-    {
-        span_lint_hir_and_then(
-            cx,
-            UNSAFE_DERIVE_DESERIALIZE,
-            adt_hir_id,
-            item.span,
-            "you are deriving `serde::Deserialize` on a type that has methods using `unsafe`",
-            |diag| {
-                diag.help(
-                    "consider implementing `serde::Deserialize` manually. See https://serde.rs/impl-deserialize.html",
-                );
-            },
-        );
-    }
-}
-
-struct UnsafeVisitor<'a, 'tcx> {
-    cx: &'a LateContext<'tcx>,
-}
-
-impl<'tcx> Visitor<'tcx> for UnsafeVisitor<'_, 'tcx> {
-    type Result = ControlFlow<()>;
-    type NestedFilter = nested_filter::All;
-
-    fn visit_fn(
-        &mut self,
-        kind: FnKind<'tcx>,
-        decl: &'tcx FnDecl<'_>,
-        body_id: BodyId,
-        _: Span,
-        id: LocalDefId,
-    ) -> Self::Result {
-        if let Some(header) = kind.header()
-            && header.is_unsafe()
-        {
-            ControlFlow::Break(())
-        } else {
-            walk_fn(self, kind, decl, body_id, id)
-        }
-    }
-
-    fn visit_expr(&mut self, expr: &'tcx Expr<'_>) -> Self::Result {
-        if let ExprKind::Block(block, _) = expr.kind
-            && block.rules == BlockCheckMode::UnsafeBlock(UnsafeSource::UserProvided)
-            && block
-                .span
-                .source_callee()
-                .and_then(|expr| expr.macro_def_id)
-                .is_none_or(|did| !self.cx.tcx.is_diagnostic_item(sym::pin_macro, did))
-        {
-            return ControlFlow::Break(());
-        }
-
-        walk_expr(self, expr)
-    }
-
-    fn maybe_tcx(&mut self) -> Self::MaybeTyCtxt {
-        self.cx.tcx
-    }
-}
-
-/// Implementation of the `DERIVE_PARTIAL_EQ_WITHOUT_EQ` lint.
-fn check_partial_eq_without_eq<'tcx>(cx: &LateContext<'tcx>, span: Span, trait_ref: &hir::TraitRef<'_>, ty: Ty<'tcx>) {
-    if let ty::Adt(adt, args) = ty.kind()
-        && cx.tcx.visibility(adt.did()).is_public()
-        && let Some(eq_trait_def_id) = cx.tcx.get_diagnostic_item(sym::Eq)
-        && let Some(def_id) = trait_ref.trait_def_id()
-        && cx.tcx.is_diagnostic_item(sym::PartialEq, def_id)
-        && !has_non_exhaustive_attr(cx.tcx, *adt)
-        && !ty_implements_eq_trait(cx.tcx, ty, eq_trait_def_id)
-        && let typing_env = typing_env_for_derived_eq(cx.tcx, adt.did(), eq_trait_def_id)
-        && let Some(local_def_id) = adt.did().as_local()
-        // If all of our fields implement `Eq`, we can implement `Eq` too
-        && adt
-            .all_fields()
-            .map(|f| f.ty(cx.tcx, args))
-            .all(|ty| implements_trait_with_env(cx.tcx, typing_env, ty, eq_trait_def_id, None, &[]))
-    {
-        span_lint_hir_and_then(
-            cx,
-            DERIVE_PARTIAL_EQ_WITHOUT_EQ,
-            cx.tcx.local_def_id_to_hir_id(local_def_id),
-            span.ctxt().outer_expn_data().call_site,
-            "you are deriving `PartialEq` and can implement `Eq`",
-            |diag| {
-                diag.span_suggestion(
-                    span.ctxt().outer_expn_data().call_site,
-                    "consider deriving `Eq` as well",
-                    "PartialEq, Eq",
-                    Applicability::MachineApplicable,
-                );
-            },
-        );
-    }
-}
-
-fn ty_implements_eq_trait<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>, eq_trait_id: DefId) -> bool {
-    tcx.non_blanket_impls_for_ty(eq_trait_id, ty).next().is_some()
-}
-
-/// Creates the `ParamEnv` used for the given type's derived `Eq` impl.
-fn typing_env_for_derived_eq(tcx: TyCtxt<'_>, did: DefId, eq_trait_id: DefId) -> ty::TypingEnv<'_> {
-    // Initial map from generic index to param def.
-    // Vec<(param_def, needs_eq)>
-    let mut params = tcx
-        .generics_of(did)
-        .own_params
-        .iter()
-        .map(|p| (p, matches!(p.kind, GenericParamDefKind::Type { .. })))
-        .collect::<Vec<_>>();
-
-    let ty_predicates = tcx.predicates_of(did).predicates;
-    for (p, _) in ty_predicates {
-        if let ClauseKind::Trait(p) = p.kind().skip_binder()
-            && p.trait_ref.def_id == eq_trait_id
-            && let ty::Param(self_ty) = p.trait_ref.self_ty().kind()
-        {
-            // Flag types which already have an `Eq` bound.
-            params[self_ty.index as usize].1 = false;
-        }
-    }
-
-    let param_env = ParamEnv::new(tcx.mk_clauses_from_iter(ty_predicates.iter().map(|&(p, _)| p).chain(
-        params.iter().filter(|&&(_, needs_eq)| needs_eq).map(|&(param, _)| {
-            ClauseKind::Trait(TraitPredicate {
-                trait_ref: ty::TraitRef::new(tcx, eq_trait_id, [tcx.mk_param_from_def(param)]),
-                polarity: ty::PredicatePolarity::Positive,
-            })
-            .upcast(tcx)
-        }),
-    )));
-    ty::TypingEnv {
-        typing_mode: ty::TypingMode::non_body_analysis(),
-        param_env,
-    }
-}
diff --git a/src/tools/clippy/clippy_lints/src/derive/derive_ord_xor_partial_ord.rs b/src/tools/clippy/clippy_lints/src/derive/derive_ord_xor_partial_ord.rs
new file mode 100644
index 00000000000..cbbcb2f7a3b
--- /dev/null
+++ b/src/tools/clippy/clippy_lints/src/derive/derive_ord_xor_partial_ord.rs
@@ -0,0 +1,50 @@
+use clippy_utils::diagnostics::span_lint_and_then;
+use rustc_hir as hir;
+use rustc_lint::LateContext;
+use rustc_middle::ty::Ty;
+use rustc_span::{Span, sym};
+
+use super::DERIVE_ORD_XOR_PARTIAL_ORD;
+
+/// Implementation of the `DERIVE_ORD_XOR_PARTIAL_ORD` lint.
+pub(super) fn check<'tcx>(
+    cx: &LateContext<'tcx>,
+    span: Span,
+    trait_ref: &hir::TraitRef<'_>,
+    ty: Ty<'tcx>,
+    ord_is_automatically_derived: bool,
+) {
+    if let Some(ord_trait_def_id) = cx.tcx.get_diagnostic_item(sym::Ord)
+        && let Some(partial_ord_trait_def_id) = cx.tcx.lang_items().partial_ord_trait()
+        && let Some(def_id) = &trait_ref.trait_def_id()
+        && *def_id == ord_trait_def_id
+    {
+        // Look for the PartialOrd implementations for `ty`
+        cx.tcx.for_each_relevant_impl(partial_ord_trait_def_id, ty, |impl_id| {
+            let partial_ord_is_automatically_derived = cx.tcx.is_automatically_derived(impl_id);
+
+            if partial_ord_is_automatically_derived == ord_is_automatically_derived {
+                return;
+            }
+
+            let trait_ref = cx.tcx.impl_trait_ref(impl_id).expect("must be a trait implementation");
+
+            // Only care about `impl PartialOrd<Foo> for Foo`
+            // For `impl PartialOrd<B> for A, input_types is [A, B]
+            if trait_ref.instantiate_identity().args.type_at(1) == ty {
+                let mess = if partial_ord_is_automatically_derived {
+                    "you are implementing `Ord` explicitly but have derived `PartialOrd`"
+                } else {
+                    "you are deriving `Ord` but have implemented `PartialOrd` explicitly"
+                };
+
+                span_lint_and_then(cx, DERIVE_ORD_XOR_PARTIAL_ORD, span, mess, |diag| {
+                    if let Some(local_def_id) = impl_id.as_local() {
+                        let hir_id = cx.tcx.local_def_id_to_hir_id(local_def_id);
+                        diag.span_note(cx.tcx.hir_span(hir_id), "`PartialOrd` implemented here");
+                    }
+                });
+            }
+        });
+    }
+}
diff --git a/src/tools/clippy/clippy_lints/src/derive/derive_partial_eq_without_eq.rs b/src/tools/clippy/clippy_lints/src/derive/derive_partial_eq_without_eq.rs
new file mode 100644
index 00000000000..ed7881c461f
--- /dev/null
+++ b/src/tools/clippy/clippy_lints/src/derive/derive_partial_eq_without_eq.rs
@@ -0,0 +1,87 @@
+use clippy_utils::diagnostics::span_lint_hir_and_then;
+use clippy_utils::has_non_exhaustive_attr;
+use clippy_utils::ty::implements_trait_with_env;
+use rustc_errors::Applicability;
+use rustc_hir as hir;
+use rustc_hir::def_id::DefId;
+use rustc_lint::LateContext;
+use rustc_middle::ty::{self, ClauseKind, GenericParamDefKind, ParamEnv, TraitPredicate, Ty, TyCtxt, Upcast};
+use rustc_span::{Span, sym};
+
+use super::DERIVE_PARTIAL_EQ_WITHOUT_EQ;
+
+/// Implementation of the `DERIVE_PARTIAL_EQ_WITHOUT_EQ` lint.
+pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, span: Span, trait_ref: &hir::TraitRef<'_>, ty: Ty<'tcx>) {
+    if let ty::Adt(adt, args) = ty.kind()
+        && cx.tcx.visibility(adt.did()).is_public()
+        && let Some(eq_trait_def_id) = cx.tcx.get_diagnostic_item(sym::Eq)
+        && let Some(def_id) = trait_ref.trait_def_id()
+        && cx.tcx.is_diagnostic_item(sym::PartialEq, def_id)
+        && !has_non_exhaustive_attr(cx.tcx, *adt)
+        && !ty_implements_eq_trait(cx.tcx, ty, eq_trait_def_id)
+        && let typing_env = typing_env_for_derived_eq(cx.tcx, adt.did(), eq_trait_def_id)
+        && let Some(local_def_id) = adt.did().as_local()
+        // If all of our fields implement `Eq`, we can implement `Eq` too
+        && adt
+            .all_fields()
+            .map(|f| f.ty(cx.tcx, args))
+            .all(|ty| implements_trait_with_env(cx.tcx, typing_env, ty, eq_trait_def_id, None, &[]))
+    {
+        span_lint_hir_and_then(
+            cx,
+            DERIVE_PARTIAL_EQ_WITHOUT_EQ,
+            cx.tcx.local_def_id_to_hir_id(local_def_id),
+            span.ctxt().outer_expn_data().call_site,
+            "you are deriving `PartialEq` and can implement `Eq`",
+            |diag| {
+                diag.span_suggestion(
+                    span.ctxt().outer_expn_data().call_site,
+                    "consider deriving `Eq` as well",
+                    "PartialEq, Eq",
+                    Applicability::MachineApplicable,
+                );
+            },
+        );
+    }
+}
+
+fn ty_implements_eq_trait<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>, eq_trait_id: DefId) -> bool {
+    tcx.non_blanket_impls_for_ty(eq_trait_id, ty).next().is_some()
+}
+
+/// Creates the `ParamEnv` used for the given type's derived `Eq` impl.
+fn typing_env_for_derived_eq(tcx: TyCtxt<'_>, did: DefId, eq_trait_id: DefId) -> ty::TypingEnv<'_> {
+    // Initial map from generic index to param def.
+    // Vec<(param_def, needs_eq)>
+    let mut params = tcx
+        .generics_of(did)
+        .own_params
+        .iter()
+        .map(|p| (p, matches!(p.kind, GenericParamDefKind::Type { .. })))
+        .collect::<Vec<_>>();
+
+    let ty_predicates = tcx.predicates_of(did).predicates;
+    for (p, _) in ty_predicates {
+        if let ClauseKind::Trait(p) = p.kind().skip_binder()
+            && p.trait_ref.def_id == eq_trait_id
+            && let ty::Param(self_ty) = p.trait_ref.self_ty().kind()
+        {
+            // Flag types which already have an `Eq` bound.
+            params[self_ty.index as usize].1 = false;
+        }
+    }
+
+    let param_env = ParamEnv::new(tcx.mk_clauses_from_iter(ty_predicates.iter().map(|&(p, _)| p).chain(
+        params.iter().filter(|&&(_, needs_eq)| needs_eq).map(|&(param, _)| {
+            ClauseKind::Trait(TraitPredicate {
+                trait_ref: ty::TraitRef::new(tcx, eq_trait_id, [tcx.mk_param_from_def(param)]),
+                polarity: ty::PredicatePolarity::Positive,
+            })
+            .upcast(tcx)
+        }),
+    )));
+    ty::TypingEnv {
+        typing_mode: ty::TypingMode::non_body_analysis(),
+        param_env,
+    }
+}
diff --git a/src/tools/clippy/clippy_lints/src/derive/derived_hash_with_manual_eq.rs b/src/tools/clippy/clippy_lints/src/derive/derived_hash_with_manual_eq.rs
new file mode 100644
index 00000000000..6f36a58025a
--- /dev/null
+++ b/src/tools/clippy/clippy_lints/src/derive/derived_hash_with_manual_eq.rs
@@ -0,0 +1,49 @@
+use clippy_utils::diagnostics::span_lint_and_then;
+use rustc_hir as hir;
+use rustc_lint::LateContext;
+use rustc_middle::ty::Ty;
+use rustc_span::{Span, sym};
+
+use super::DERIVED_HASH_WITH_MANUAL_EQ;
+
+/// Implementation of the `DERIVED_HASH_WITH_MANUAL_EQ` lint.
+pub(super) fn check<'tcx>(
+    cx: &LateContext<'tcx>,
+    span: Span,
+    trait_ref: &hir::TraitRef<'_>,
+    ty: Ty<'tcx>,
+    hash_is_automatically_derived: bool,
+) {
+    if let Some(peq_trait_def_id) = cx.tcx.lang_items().eq_trait()
+        && let Some(def_id) = trait_ref.trait_def_id()
+        && cx.tcx.is_diagnostic_item(sym::Hash, def_id)
+    {
+        // Look for the PartialEq implementations for `ty`
+        cx.tcx.for_each_relevant_impl(peq_trait_def_id, ty, |impl_id| {
+            let peq_is_automatically_derived = cx.tcx.is_automatically_derived(impl_id);
+
+            if !hash_is_automatically_derived || peq_is_automatically_derived {
+                return;
+            }
+
+            let trait_ref = cx.tcx.impl_trait_ref(impl_id).expect("must be a trait implementation");
+
+            // Only care about `impl PartialEq<Foo> for Foo`
+            // For `impl PartialEq<B> for A, input_types is [A, B]
+            if trait_ref.instantiate_identity().args.type_at(1) == ty {
+                span_lint_and_then(
+                    cx,
+                    DERIVED_HASH_WITH_MANUAL_EQ,
+                    span,
+                    "you are deriving `Hash` but have implemented `PartialEq` explicitly",
+                    |diag| {
+                        if let Some(local_def_id) = impl_id.as_local() {
+                            let hir_id = cx.tcx.local_def_id_to_hir_id(local_def_id);
+                            diag.span_note(cx.tcx.hir_span(hir_id), "`PartialEq` implemented here");
+                        }
+                    },
+                );
+            }
+        });
+    }
+}
diff --git a/src/tools/clippy/clippy_lints/src/derive/expl_impl_clone_on_copy.rs b/src/tools/clippy/clippy_lints/src/derive/expl_impl_clone_on_copy.rs
new file mode 100644
index 00000000000..6b97b4bd6b4
--- /dev/null
+++ b/src/tools/clippy/clippy_lints/src/derive/expl_impl_clone_on_copy.rs
@@ -0,0 +1,65 @@
+use clippy_utils::diagnostics::span_lint_and_note;
+use clippy_utils::ty::{implements_trait, is_copy};
+use rustc_hir::{self as hir, Item};
+use rustc_lint::LateContext;
+use rustc_middle::ty::{self, GenericArgKind, Ty};
+
+use super::EXPL_IMPL_CLONE_ON_COPY;
+
+/// Implementation of the `EXPL_IMPL_CLONE_ON_COPY` lint.
+pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, item: &Item<'_>, trait_ref: &hir::TraitRef<'_>, ty: Ty<'tcx>) {
+    let clone_id = match cx.tcx.lang_items().clone_trait() {
+        Some(id) if trait_ref.trait_def_id() == Some(id) => id,
+        _ => return,
+    };
+    let Some(copy_id) = cx.tcx.lang_items().copy_trait() else {
+        return;
+    };
+    let (ty_adt, ty_subs) = match *ty.kind() {
+        // Unions can't derive clone.
+        ty::Adt(adt, subs) if !adt.is_union() => (adt, subs),
+        _ => return,
+    };
+    // If the current self type doesn't implement Copy (due to generic constraints), search to see if
+    // there's a Copy impl for any instance of the adt.
+    if !is_copy(cx, ty) {
+        if ty_subs.non_erasable_generics().next().is_some() {
+            let has_copy_impl = cx.tcx.local_trait_impls(copy_id).iter().any(|&id| {
+                matches!(cx.tcx.type_of(id).instantiate_identity().kind(), ty::Adt(adt, _)
+                                        if ty_adt.did() == adt.did())
+            });
+            if !has_copy_impl {
+                return;
+            }
+        } else {
+            return;
+        }
+    }
+    // Derive constrains all generic types to requiring Clone. Check if any type is not constrained for
+    // this impl.
+    if ty_subs.types().any(|ty| !implements_trait(cx, ty, clone_id, &[])) {
+        return;
+    }
+    // `#[repr(packed)]` structs with type/const parameters can't derive `Clone`.
+    // https://github.com/rust-lang/rust-clippy/issues/10188
+    if ty_adt.repr().packed()
+        && ty_subs
+            .iter()
+            .any(|arg| matches!(arg.kind(), GenericArgKind::Type(_) | GenericArgKind::Const(_)))
+    {
+        return;
+    }
+    // The presence of `unsafe` fields prevents deriving `Clone` automatically
+    if ty_adt.all_fields().any(|f| f.safety.is_unsafe()) {
+        return;
+    }
+
+    span_lint_and_note(
+        cx,
+        EXPL_IMPL_CLONE_ON_COPY,
+        item.span,
+        "you are implementing `Clone` explicitly on a `Copy` type",
+        Some(item.span),
+        "consider deriving `Clone` or removing `Copy`",
+    );
+}
diff --git a/src/tools/clippy/clippy_lints/src/derive/mod.rs b/src/tools/clippy/clippy_lints/src/derive/mod.rs
new file mode 100644
index 00000000000..1d63394ce37
--- /dev/null
+++ b/src/tools/clippy/clippy_lints/src/derive/mod.rs
@@ -0,0 +1,215 @@
+use rustc_hir::{Impl, Item, ItemKind};
+use rustc_lint::{LateContext, LateLintPass};
+use rustc_session::declare_lint_pass;
+
+mod derive_ord_xor_partial_ord;
+mod derive_partial_eq_without_eq;
+mod derived_hash_with_manual_eq;
+mod expl_impl_clone_on_copy;
+mod unsafe_derive_deserialize;
+
+declare_clippy_lint! {
+    /// ### What it does
+    /// Lints against manual `PartialEq` implementations for types with a derived `Hash`
+    /// implementation.
+    ///
+    /// ### Why is this bad?
+    /// The implementation of these traits must agree (for
+    /// example for use with `HashMap`) so it’s probably a bad idea to use a
+    /// default-generated `Hash` implementation with an explicitly defined
+    /// `PartialEq`. In particular, the following must hold for any type:
+    ///
+    /// ```text
+    /// k1 == k2 ⇒ hash(k1) == hash(k2)
+    /// ```
+    ///
+    /// ### Example
+    /// ```ignore
+    /// #[derive(Hash)]
+    /// struct Foo;
+    ///
+    /// impl PartialEq for Foo {
+    ///     ...
+    /// }
+    /// ```
+    #[clippy::version = "pre 1.29.0"]
+    pub DERIVED_HASH_WITH_MANUAL_EQ,
+    correctness,
+    "deriving `Hash` but implementing `PartialEq` explicitly"
+}
+
+declare_clippy_lint! {
+    /// ### What it does
+    /// Lints against manual `PartialOrd` and `Ord` implementations for types with a derived `Ord`
+    /// or `PartialOrd` implementation.
+    ///
+    /// ### Why is this bad?
+    /// The implementation of these traits must agree (for
+    /// example for use with `sort`) so it’s probably a bad idea to use a
+    /// default-generated `Ord` implementation with an explicitly defined
+    /// `PartialOrd`. In particular, the following must hold for any type
+    /// implementing `Ord`:
+    ///
+    /// ```text
+    /// k1.cmp(&k2) == k1.partial_cmp(&k2).unwrap()
+    /// ```
+    ///
+    /// ### Example
+    /// ```rust,ignore
+    /// #[derive(Ord, PartialEq, Eq)]
+    /// struct Foo;
+    ///
+    /// impl PartialOrd for Foo {
+    ///     ...
+    /// }
+    /// ```
+    /// Use instead:
+    /// ```rust,ignore
+    /// #[derive(PartialEq, Eq)]
+    /// struct Foo;
+    ///
+    /// impl PartialOrd for Foo {
+    ///     fn partial_cmp(&self, other: &Foo) -> Option<Ordering> {
+    ///        Some(self.cmp(other))
+    ///     }
+    /// }
+    ///
+    /// impl Ord for Foo {
+    ///     ...
+    /// }
+    /// ```
+    /// or, if you don't need a custom ordering:
+    /// ```rust,ignore
+    /// #[derive(Ord, PartialOrd, PartialEq, Eq)]
+    /// struct Foo;
+    /// ```
+    #[clippy::version = "1.47.0"]
+    pub DERIVE_ORD_XOR_PARTIAL_ORD,
+    correctness,
+    "deriving `Ord` but implementing `PartialOrd` explicitly"
+}
+
+declare_clippy_lint! {
+    /// ### What it does
+    /// Checks for explicit `Clone` implementations for `Copy`
+    /// types.
+    ///
+    /// ### Why is this bad?
+    /// To avoid surprising behavior, these traits should
+    /// agree and the behavior of `Copy` cannot be overridden. In almost all
+    /// situations a `Copy` type should have a `Clone` implementation that does
+    /// nothing more than copy the object, which is what `#[derive(Copy, Clone)]`
+    /// gets you.
+    ///
+    /// ### Example
+    /// ```rust,ignore
+    /// #[derive(Copy)]
+    /// struct Foo;
+    ///
+    /// impl Clone for Foo {
+    ///     // ..
+    /// }
+    /// ```
+    #[clippy::version = "pre 1.29.0"]
+    pub EXPL_IMPL_CLONE_ON_COPY,
+    pedantic,
+    "implementing `Clone` explicitly on `Copy` types"
+}
+
+declare_clippy_lint! {
+    /// ### What it does
+    /// Checks for deriving `serde::Deserialize` on a type that
+    /// has methods using `unsafe`.
+    ///
+    /// ### Why is this bad?
+    /// Deriving `serde::Deserialize` will create a constructor
+    /// that may violate invariants held by another constructor.
+    ///
+    /// ### Example
+    /// ```rust,ignore
+    /// use serde::Deserialize;
+    ///
+    /// #[derive(Deserialize)]
+    /// pub struct Foo {
+    ///     // ..
+    /// }
+    ///
+    /// impl Foo {
+    ///     pub fn new() -> Self {
+    ///         // setup here ..
+    ///     }
+    ///
+    ///     pub unsafe fn parts() -> (&str, &str) {
+    ///         // assumes invariants hold
+    ///     }
+    /// }
+    /// ```
+    #[clippy::version = "1.45.0"]
+    pub UNSAFE_DERIVE_DESERIALIZE,
+    pedantic,
+    "deriving `serde::Deserialize` on a type that has methods using `unsafe`"
+}
+
+declare_clippy_lint! {
+    /// ### What it does
+    /// Checks for types that derive `PartialEq` and could implement `Eq`.
+    ///
+    /// ### Why is this bad?
+    /// If a type `T` derives `PartialEq` and all of its members implement `Eq`,
+    /// then `T` can always implement `Eq`. Implementing `Eq` allows `T` to be used
+    /// in APIs that require `Eq` types. It also allows structs containing `T` to derive
+    /// `Eq` themselves.
+    ///
+    /// ### Example
+    /// ```no_run
+    /// #[derive(PartialEq)]
+    /// struct Foo {
+    ///     i_am_eq: i32,
+    ///     i_am_eq_too: Vec<String>,
+    /// }
+    /// ```
+    /// Use instead:
+    /// ```no_run
+    /// #[derive(PartialEq, Eq)]
+    /// struct Foo {
+    ///     i_am_eq: i32,
+    ///     i_am_eq_too: Vec<String>,
+    /// }
+    /// ```
+    #[clippy::version = "1.63.0"]
+    pub DERIVE_PARTIAL_EQ_WITHOUT_EQ,
+    nursery,
+    "deriving `PartialEq` on a type that can implement `Eq`, without implementing `Eq`"
+}
+
+declare_lint_pass!(Derive => [
+    EXPL_IMPL_CLONE_ON_COPY,
+    DERIVED_HASH_WITH_MANUAL_EQ,
+    DERIVE_ORD_XOR_PARTIAL_ORD,
+    UNSAFE_DERIVE_DESERIALIZE,
+    DERIVE_PARTIAL_EQ_WITHOUT_EQ
+]);
+
+impl<'tcx> LateLintPass<'tcx> for Derive {
+    fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'_>) {
+        if let ItemKind::Impl(Impl {
+            of_trait: Some(of_trait),
+            ..
+        }) = item.kind
+        {
+            let trait_ref = &of_trait.trait_ref;
+            let ty = cx.tcx.type_of(item.owner_id).instantiate_identity();
+            let is_automatically_derived = cx.tcx.is_automatically_derived(item.owner_id.to_def_id());
+
+            derived_hash_with_manual_eq::check(cx, item.span, trait_ref, ty, is_automatically_derived);
+            derive_ord_xor_partial_ord::check(cx, item.span, trait_ref, ty, is_automatically_derived);
+
+            if is_automatically_derived {
+                unsafe_derive_deserialize::check(cx, item, trait_ref, ty);
+                derive_partial_eq_without_eq::check(cx, item.span, trait_ref, ty);
+            } else {
+                expl_impl_clone_on_copy::check(cx, item, trait_ref, ty);
+            }
+        }
+    }
+}
diff --git a/src/tools/clippy/clippy_lints/src/derive/unsafe_derive_deserialize.rs b/src/tools/clippy/clippy_lints/src/derive/unsafe_derive_deserialize.rs
new file mode 100644
index 00000000000..c391e7b6228
--- /dev/null
+++ b/src/tools/clippy/clippy_lints/src/derive/unsafe_derive_deserialize.rs
@@ -0,0 +1,93 @@
+use std::ops::ControlFlow;
+
+use clippy_utils::diagnostics::span_lint_hir_and_then;
+use clippy_utils::{is_lint_allowed, paths};
+use rustc_hir::def_id::LocalDefId;
+use rustc_hir::intravisit::{FnKind, Visitor, walk_expr, walk_fn, walk_item};
+use rustc_hir::{self as hir, BlockCheckMode, BodyId, Expr, ExprKind, FnDecl, Item, UnsafeSource};
+use rustc_lint::LateContext;
+use rustc_middle::hir::nested_filter;
+use rustc_middle::ty::{self, Ty};
+use rustc_span::{Span, sym};
+
+use super::UNSAFE_DERIVE_DESERIALIZE;
+
+/// Implementation of the `UNSAFE_DERIVE_DESERIALIZE` lint.
+pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, item: &Item<'_>, trait_ref: &hir::TraitRef<'_>, ty: Ty<'tcx>) {
+    fn has_unsafe<'tcx>(cx: &LateContext<'tcx>, item: &'tcx Item<'_>) -> bool {
+        let mut visitor = UnsafeVisitor { cx };
+        walk_item(&mut visitor, item).is_break()
+    }
+
+    if let Some(trait_def_id) = trait_ref.trait_def_id()
+        && paths::SERDE_DESERIALIZE.matches(cx, trait_def_id)
+        && let ty::Adt(def, _) = ty.kind()
+        && let Some(local_def_id) = def.did().as_local()
+        && let adt_hir_id = cx.tcx.local_def_id_to_hir_id(local_def_id)
+        && !is_lint_allowed(cx, UNSAFE_DERIVE_DESERIALIZE, adt_hir_id)
+        && cx
+            .tcx
+            .inherent_impls(def.did())
+            .iter()
+            .map(|imp_did| cx.tcx.hir_expect_item(imp_did.expect_local()))
+            .any(|imp| has_unsafe(cx, imp))
+    {
+        span_lint_hir_and_then(
+            cx,
+            UNSAFE_DERIVE_DESERIALIZE,
+            adt_hir_id,
+            item.span,
+            "you are deriving `serde::Deserialize` on a type that has methods using `unsafe`",
+            |diag| {
+                diag.help(
+                    "consider implementing `serde::Deserialize` manually. See https://serde.rs/impl-deserialize.html",
+                );
+            },
+        );
+    }
+}
+
+struct UnsafeVisitor<'a, 'tcx> {
+    cx: &'a LateContext<'tcx>,
+}
+
+impl<'tcx> Visitor<'tcx> for UnsafeVisitor<'_, 'tcx> {
+    type Result = ControlFlow<()>;
+    type NestedFilter = nested_filter::All;
+
+    fn visit_fn(
+        &mut self,
+        kind: FnKind<'tcx>,
+        decl: &'tcx FnDecl<'_>,
+        body_id: BodyId,
+        _: Span,
+        id: LocalDefId,
+    ) -> Self::Result {
+        if let Some(header) = kind.header()
+            && header.is_unsafe()
+        {
+            ControlFlow::Break(())
+        } else {
+            walk_fn(self, kind, decl, body_id, id)
+        }
+    }
+
+    fn visit_expr(&mut self, expr: &'tcx Expr<'_>) -> Self::Result {
+        if let ExprKind::Block(block, _) = expr.kind
+            && block.rules == BlockCheckMode::UnsafeBlock(UnsafeSource::UserProvided)
+            && block
+                .span
+                .source_callee()
+                .and_then(|expr| expr.macro_def_id)
+                .is_none_or(|did| !self.cx.tcx.is_diagnostic_item(sym::pin_macro, did))
+        {
+            return ControlFlow::Break(());
+        }
+
+        walk_expr(self, expr)
+    }
+
+    fn maybe_tcx(&mut self) -> Self::MaybeTyCtxt {
+        self.cx.tcx
+    }
+}
diff --git a/src/tools/clippy/clippy_lints/src/disallowed_macros.rs b/src/tools/clippy/clippy_lints/src/disallowed_macros.rs
index 49cd2671dc0..1c9c971730f 100644
--- a/src/tools/clippy/clippy_lints/src/disallowed_macros.rs
+++ b/src/tools/clippy/clippy_lints/src/disallowed_macros.rs
@@ -1,4 +1,3 @@
-
 use clippy_config::Conf;
 use clippy_config::types::{DisallowedPath, create_disallowed_map};
 use clippy_utils::diagnostics::{span_lint_and_then, span_lint_hir_and_then};
@@ -8,7 +7,8 @@ use rustc_data_structures::fx::FxHashSet;
 use rustc_hir::def::DefKind;
 use rustc_hir::def_id::DefIdMap;
 use rustc_hir::{
-    AmbigArg, Expr, ExprKind, ForeignItem, HirId, ImplItem, ImplItemImplKind, Item, ItemKind, OwnerId, Pat, Path, Stmt, TraitItem, Ty,
+    AmbigArg, Expr, ExprKind, ForeignItem, HirId, ImplItem, ImplItemImplKind, Item, ItemKind, OwnerId, Pat, Path, Stmt,
+    TraitItem, Ty,
 };
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_middle::ty::TyCtxt;
diff --git a/src/tools/clippy/clippy_lints/src/eta_reduction.rs b/src/tools/clippy/clippy_lints/src/eta_reduction.rs
index 2da1c2bad11..752f39b4e6d 100644
--- a/src/tools/clippy/clippy_lints/src/eta_reduction.rs
+++ b/src/tools/clippy/clippy_lints/src/eta_reduction.rs
@@ -197,6 +197,18 @@ fn check_closure<'tcx>(cx: &LateContext<'tcx>, outer_receiver: Option<&Expr<'tcx
                 // in a type which is `'static`.
                 // For now ignore all callee types which reference a type parameter.
                 && !generic_args.types().any(|t| matches!(t.kind(), ty::Param(_)))
+                // Rule out `AsyncFn*`s, because while they can be called as `|x| f(x)`,
+                // they can't be passed directly into a place expecting an `Fn*` (#13892)
+                && let Ok((closure_kind, _)) = 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,
+                    )
             {
                 span_lint_hir_and_then(
                     cx,
@@ -213,19 +225,10 @@ fn check_closure<'tcx>(cx: &LateContext<'tcx>, outer_receiver: Option<&Expr<'tcx
                                 // '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,
-                                    ) {
+                                match closure_kind {
                                     // 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() => {
+                                    ClosureKind::FnMut => snippet = format!("&mut {snippet}"),
+                                    ClosureKind::Fn if !callee_ty_raw.is_ref() => {
                                         snippet = format!("&{snippet}");
                                     },
                                     _ => (),
diff --git a/src/tools/clippy/clippy_lints/src/functions/not_unsafe_ptr_arg_deref.rs b/src/tools/clippy/clippy_lints/src/functions/not_unsafe_ptr_arg_deref.rs
index 906bbd006d4..72f87953040 100644
--- a/src/tools/clippy/clippy_lints/src/functions/not_unsafe_ptr_arg_deref.rs
+++ b/src/tools/clippy/clippy_lints/src/functions/not_unsafe_ptr_arg_deref.rs
@@ -4,7 +4,7 @@ use rustc_middle::ty;
 use rustc_span::def_id::LocalDefId;
 
 use clippy_utils::diagnostics::span_lint;
-use clippy_utils::ty::type_is_unsafe_function;
+use clippy_utils::ty::is_unsafe_fn;
 use clippy_utils::visitors::for_each_expr;
 use clippy_utils::{iter_input_pats, path_to_local};
 
@@ -51,7 +51,7 @@ fn check_raw_ptr<'tcx>(
             let typeck = cx.tcx.typeck_body(body.id());
             let _: Option<!> = for_each_expr(cx, body.value, |e| {
                 match e.kind {
-                    hir::ExprKind::Call(f, args) if type_is_unsafe_function(cx, typeck.expr_ty(f)) => {
+                    hir::ExprKind::Call(f, args) if is_unsafe_fn(cx, typeck.expr_ty(f)) => {
                         for arg in args {
                             check_arg(cx, &raw_ptrs, arg);
                         }
diff --git a/src/tools/clippy/clippy_lints/src/functions/ref_option.rs b/src/tools/clippy/clippy_lints/src/functions/ref_option.rs
index 106202d00d4..5dc1b7269b7 100644
--- a/src/tools/clippy/clippy_lints/src/functions/ref_option.rs
+++ b/src/tools/clippy/clippy_lints/src/functions/ref_option.rs
@@ -1,23 +1,20 @@
 use crate::functions::REF_OPTION;
 use clippy_utils::diagnostics::span_lint_and_then;
-use clippy_utils::is_trait_impl_item;
 use clippy_utils::source::snippet;
-use clippy_utils::ty::is_type_diagnostic_item;
+use clippy_utils::ty::option_arg_ty;
+use clippy_utils::{is_from_proc_macro, is_trait_impl_item};
 use rustc_errors::Applicability;
-use rustc_hir as hir;
 use rustc_hir::intravisit::FnKind;
-use rustc_hir::{FnDecl, HirId};
-use rustc_lint::LateContext;
-use rustc_middle::ty::{self, GenericArgKind, Mutability, Ty};
+use rustc_hir::{self as hir, FnDecl, HirId};
+use rustc_lint::{LateContext, LintContext};
+use rustc_middle::ty::{self, Mutability, Ty};
+use rustc_span::Span;
 use rustc_span::def_id::LocalDefId;
-use rustc_span::{Span, sym};
 
-fn check_ty<'a>(cx: &LateContext<'a>, param: &rustc_hir::Ty<'a>, param_ty: Ty<'a>, fixes: &mut Vec<(Span, String)>) {
-    if let ty::Ref(_, opt_ty, Mutability::Not) = param_ty.kind()
-        && is_type_diagnostic_item(cx, *opt_ty, sym::Option)
-        && let ty::Adt(_, opt_gen_args) = opt_ty.kind()
-        && let [gen_arg] = opt_gen_args.as_slice()
-        && let GenericArgKind::Type(gen_ty) = gen_arg.kind()
+fn check_ty<'a>(cx: &LateContext<'a>, param: &hir::Ty<'a>, param_ty: Ty<'a>, fixes: &mut Vec<(Span, String)>) {
+    if !param.span.in_external_macro(cx.sess().source_map())
+        && let ty::Ref(_, opt_ty, Mutability::Not) = param_ty.kind()
+        && let Some(gen_ty) = option_arg_ty(cx, *opt_ty)
         && !gen_ty.is_ref()
         // Need to gen the original spans, so first parsing mid, and hir parsing afterward
         && let hir::TyKind::Ref(lifetime, hir::MutTy { ty, .. }) = param.kind
@@ -27,6 +24,7 @@ fn check_ty<'a>(cx: &LateContext<'a>, param: &rustc_hir::Ty<'a>, param_ty: Ty<'a
             args: [hir::GenericArg::Type(opt_ty)],
             ..
         }) = last.args
+        && !is_from_proc_macro(cx, param)
     {
         let lifetime = snippet(cx, lifetime.ident.span, "..");
         fixes.push((
@@ -67,21 +65,24 @@ fn check_fn_sig<'a>(cx: &LateContext<'a>, decl: &FnDecl<'a>, span: Span, sig: ty
 #[allow(clippy::too_many_arguments)]
 pub(crate) fn check_fn<'a>(
     cx: &LateContext<'a>,
-    kind: FnKind<'_>,
+    kind: FnKind<'a>,
     decl: &FnDecl<'a>,
     span: Span,
     hir_id: HirId,
     def_id: LocalDefId,
-    body: &hir::Body<'_>,
+    body: &hir::Body<'a>,
     avoid_breaking_exported_api: bool,
 ) {
     if avoid_breaking_exported_api && cx.effective_visibilities.is_exported(def_id) {
         return;
     }
+    if span.in_external_macro(cx.sess().source_map()) {
+        return;
+    }
 
     if let FnKind::Closure = kind {
         // Compute the span of the closure parameters + return type if set
-        let span = if let hir::FnRetTy::Return(out_ty) = &decl.output {
+        let inputs_output_span = if let hir::FnRetTy::Return(out_ty) = &decl.output {
             if decl.inputs.is_empty() {
                 out_ty.span
             } else {
@@ -100,9 +101,18 @@ pub(crate) fn check_fn<'a>(
         };
         let sig = args.as_closure().sig().skip_binder();
 
-        check_fn_sig(cx, decl, span, sig);
+        if is_from_proc_macro(cx, &(&kind, body, hir_id, span)) {
+            return;
+        }
+
+        check_fn_sig(cx, decl, inputs_output_span, sig);
     } else if !is_trait_impl_item(cx, hir_id) {
         let sig = cx.tcx.fn_sig(def_id).instantiate_identity().skip_binder();
+
+        if is_from_proc_macro(cx, &(&kind, body, hir_id, span)) {
+            return;
+        }
+
         check_fn_sig(cx, decl, span, sig);
     }
 }
@@ -112,8 +122,10 @@ pub(super) fn check_trait_item<'a>(
     trait_item: &hir::TraitItem<'a>,
     avoid_breaking_exported_api: bool,
 ) {
-    if let hir::TraitItemKind::Fn(ref sig, _) = trait_item.kind
+    if !trait_item.span.in_external_macro(cx.sess().source_map())
+        && let hir::TraitItemKind::Fn(ref sig, _) = trait_item.kind
         && !(avoid_breaking_exported_api && cx.effective_visibilities.is_exported(trait_item.owner_id.def_id))
+        && !is_from_proc_macro(cx, trait_item)
     {
         let def_id = trait_item.owner_id.def_id;
         let ty_sig = cx.tcx.fn_sig(def_id).instantiate_identity().skip_binder();
diff --git a/src/tools/clippy/clippy_lints/src/future_not_send.rs b/src/tools/clippy/clippy_lints/src/future_not_send.rs
index 3ccfa51ab70..596047977a9 100644
--- a/src/tools/clippy/clippy_lints/src/future_not_send.rs
+++ b/src/tools/clippy/clippy_lints/src/future_not_send.rs
@@ -78,66 +78,65 @@ impl<'tcx> LateLintPass<'tcx> for FutureNotSend {
         if let ty::Alias(ty::Opaque, AliasTy { def_id, args, .. }) = *ret_ty.kind()
             && let Some(future_trait) = cx.tcx.lang_items().future_trait()
             && let Some(send_trait) = cx.tcx.get_diagnostic_item(sym::Send)
+            && let preds = cx.tcx.explicit_item_self_bounds(def_id)
+            // If is a Future
+            && preds
+                .iter_instantiated_copied(cx.tcx, args)
+                .filter_map(|(p, _)| p.as_trait_clause())
+                .any(|trait_pred| trait_pred.skip_binder().trait_ref.def_id == future_trait)
         {
-            let preds = cx.tcx.explicit_item_self_bounds(def_id);
-            let is_future = preds.iter_instantiated_copied(cx.tcx, args).any(|(p, _)| {
-                p.as_trait_clause()
-                    .is_some_and(|trait_pred| trait_pred.skip_binder().trait_ref.def_id == future_trait)
-            });
-            if is_future {
-                let span = decl.output.span();
-                let infcx = cx.tcx.infer_ctxt().build(cx.typing_mode());
-                let ocx = ObligationCtxt::new_with_diagnostics(&infcx);
-                let cause = traits::ObligationCause::misc(span, fn_def_id);
-                ocx.register_bound(cause, cx.param_env, ret_ty, send_trait);
-                let send_errors = ocx.select_all_or_error();
+            let span = decl.output.span();
+            let infcx = cx.tcx.infer_ctxt().build(cx.typing_mode());
+            let ocx = ObligationCtxt::new_with_diagnostics(&infcx);
+            let cause = traits::ObligationCause::misc(span, fn_def_id);
+            ocx.register_bound(cause, cx.param_env, ret_ty, send_trait);
+            let send_errors = ocx.select_all_or_error();
 
-                // Allow errors that try to prove `Send` for types that "mention" a generic parameter at the "top
-                // level".
-                // For example, allow errors that `T: Send` can't be proven, but reject `Rc<T>: Send` errors,
-                // which is always unconditionally `!Send` for any possible type `T`.
-                //
-                // We also allow associated type projections if the self type is either itself a projection or a
-                // type parameter.
-                // This is to prevent emitting warnings for e.g. holding a `<Fut as Future>::Output` across await
-                // points, where `Fut` is a type parameter.
+            // Allow errors that try to prove `Send` for types that "mention" a generic parameter at the "top
+            // level".
+            // For example, allow errors that `T: Send` can't be proven, but reject `Rc<T>: Send` errors,
+            // which is always unconditionally `!Send` for any possible type `T`.
+            //
+            // We also allow associated type projections if the self type is either itself a projection or a
+            // type parameter.
+            // This is to prevent emitting warnings for e.g. holding a `<Fut as Future>::Output` across await
+            // points, where `Fut` is a type parameter.
 
-                let is_send = send_errors.iter().all(|err| {
-                    err.obligation
-                        .predicate
-                        .as_trait_clause()
-                        .map(Binder::skip_binder)
-                        .is_some_and(|pred| {
-                            pred.def_id() == send_trait
-                                && pred.self_ty().has_param()
-                                && TyParamAtTopLevelVisitor.visit_ty(pred.self_ty()) == ControlFlow::Break(true)
-                        })
-                });
+            let is_send = send_errors.iter().all(|err| {
+                err.obligation
+                    .predicate
+                    .as_trait_clause()
+                    .map(Binder::skip_binder)
+                    .is_some_and(|pred| {
+                        pred.def_id() == send_trait
+                            && pred.self_ty().has_param()
+                            && TyParamAtTopLevelVisitor.visit_ty(pred.self_ty()) == ControlFlow::Break(true)
+                    })
+            });
 
-                if !is_send {
-                    span_lint_and_then(
-                        cx,
-                        FUTURE_NOT_SEND,
-                        span,
-                        "future cannot be sent between threads safely",
-                        |db| {
-                            for FulfillmentError { obligation, .. } in send_errors {
-                                infcx
-                                    .err_ctxt()
-                                    .maybe_note_obligation_cause_for_async_await(db, &obligation);
-                                if let PredicateKind::Clause(ClauseKind::Trait(trait_pred)) =
-                                    obligation.predicate.kind().skip_binder()
-                                {
-                                    db.note(format!(
-                                        "`{}` doesn't implement `{}`",
-                                        trait_pred.self_ty(),
-                                        trait_pred.trait_ref.print_only_trait_path(),
-                                    ));
-                                }
+            if !is_send {
+                span_lint_and_then(
+                    cx,
+                    FUTURE_NOT_SEND,
+                    span,
+                    "future cannot be sent between threads safely",
+                    |db| {
+                        for FulfillmentError { obligation, .. } in send_errors {
+                            infcx
+                                .err_ctxt()
+                                .maybe_note_obligation_cause_for_async_await(db, &obligation);
+                            if let PredicateKind::Clause(ClauseKind::Trait(trait_pred)) =
+                                obligation.predicate.kind().skip_binder()
+                            {
+                                db.note(format!(
+                                    "`{}` doesn't implement `{}`",
+                                    trait_pred.self_ty(),
+                                    trait_pred.trait_ref.print_only_trait_path(),
+                                ));
                             }
-                        },
-                    );
-                }
+                        }
+                    },
+                );
             }
         }
     }
diff --git a/src/tools/clippy/clippy_lints/src/invalid_upcast_comparisons.rs b/src/tools/clippy/clippy_lints/src/invalid_upcast_comparisons.rs
index b0ecc5d52dd..1666e8e5ae3 100644
--- a/src/tools/clippy/clippy_lints/src/invalid_upcast_comparisons.rs
+++ b/src/tools/clippy/clippy_lints/src/invalid_upcast_comparisons.rs
@@ -1,3 +1,4 @@
+use rustc_errors::Applicability;
 use rustc_hir::{Expr, ExprKind};
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_middle::ty::layout::LayoutOf;
@@ -9,7 +10,7 @@ use clippy_utils::comparisons;
 use clippy_utils::comparisons::Rel;
 use clippy_utils::consts::{ConstEvalCtxt, FullInt};
 use clippy_utils::diagnostics::span_lint;
-use clippy_utils::source::snippet;
+use clippy_utils::source::snippet_with_context;
 
 declare_clippy_lint! {
     /// ### What it does
@@ -69,13 +70,21 @@ fn numeric_cast_precast_bounds(cx: &LateContext<'_>, expr: &Expr<'_>) -> Option<
 
 fn err_upcast_comparison(cx: &LateContext<'_>, span: Span, expr: &Expr<'_>, always: bool) {
     if let ExprKind::Cast(cast_val, _) = expr.kind {
+        let mut applicability = Applicability::MachineApplicable;
+        let (cast_val_snip, _) = snippet_with_context(
+            cx,
+            cast_val.span,
+            expr.span.ctxt(),
+            "the expression",
+            &mut applicability,
+        );
         span_lint(
             cx,
             INVALID_UPCAST_COMPARISONS,
             span,
             format!(
                 "because of the numeric bounds on `{}` prior to casting, this expression is always {}",
-                snippet(cx, cast_val.span, "the expression"),
+                cast_val_snip,
                 if always { "true" } else { "false" },
             ),
         );
diff --git a/src/tools/clippy/clippy_lints/src/len_zero.rs b/src/tools/clippy/clippy_lints/src/len_zero.rs
index f44a5fdf715..28a0fbc0511 100644
--- a/src/tools/clippy/clippy_lints/src/len_zero.rs
+++ b/src/tools/clippy/clippy_lints/src/len_zero.rs
@@ -371,9 +371,9 @@ fn parse_len_output<'tcx>(cx: &LateContext<'tcx>, sig: FnSig<'tcx>) -> Option<Le
 
     match *sig.output().kind() {
         ty::Int(_) | ty::Uint(_) => Some(LenOutput::Integral),
-        ty::Adt(adt, subs) if subs.type_at(0).is_integral() => match cx.tcx.get_diagnostic_name(adt.did()) {
-            Some(sym::Option) => Some(LenOutput::Option(adt.did())),
-            Some(sym::Result) => Some(LenOutput::Result(adt.did())),
+        ty::Adt(adt, subs) => match cx.tcx.get_diagnostic_name(adt.did()) {
+            Some(sym::Option) => subs.type_at(0).is_integral().then(|| LenOutput::Option(adt.did())),
+            Some(sym::Result) => subs.type_at(0).is_integral().then(|| LenOutput::Result(adt.did())),
             _ => None,
         },
         _ => None,
diff --git a/src/tools/clippy/clippy_lints/src/let_with_type_underscore.rs b/src/tools/clippy/clippy_lints/src/let_with_type_underscore.rs
index 5b0f95ffc37..24a4c321bda 100644
--- a/src/tools/clippy/clippy_lints/src/let_with_type_underscore.rs
+++ b/src/tools/clippy/clippy_lints/src/let_with_type_underscore.rs
@@ -1,9 +1,9 @@
 use clippy_utils::diagnostics::span_lint_and_then;
 use clippy_utils::is_from_proc_macro;
 use clippy_utils::source::{IntoSpan, SpanRangeExt};
+use rustc_ast::{Local, TyKind};
 use rustc_errors::Applicability;
-use rustc_hir::{LetStmt, TyKind};
-use rustc_lint::{LateContext, LateLintPass};
+use rustc_lint::{EarlyContext, EarlyLintPass, LintContext};
 use rustc_session::declare_lint_pass;
 
 declare_clippy_lint! {
@@ -26,14 +26,14 @@ declare_clippy_lint! {
 }
 declare_lint_pass!(UnderscoreTyped => [LET_WITH_TYPE_UNDERSCORE]);
 
-impl<'tcx> LateLintPass<'tcx> for UnderscoreTyped {
-    fn check_local(&mut self, cx: &LateContext<'tcx>, local: &'tcx LetStmt<'_>) {
-        if let Some(ty) = local.ty // Ensure that it has a type defined
-            && let TyKind::Infer(()) = &ty.kind // that type is '_'
+impl EarlyLintPass for UnderscoreTyped {
+    fn check_local(&mut self, cx: &EarlyContext<'_>, local: &Local) {
+        if let Some(ty) = &local.ty // Ensure that it has a type defined
+            && let TyKind::Infer = ty.kind // that type is '_'
             && local.span.eq_ctxt(ty.span)
-            && let sm = cx.tcx.sess.source_map()
+            && let sm = cx.sess().source_map()
             && !local.span.in_external_macro(sm)
-            && !is_from_proc_macro(cx, ty)
+            && !is_from_proc_macro(cx, &**ty)
         {
             let span_to_remove = sm
                 .span_extend_to_prev_char_before(ty.span, ':', true)
diff --git a/src/tools/clippy/clippy_lints/src/lib.rs b/src/tools/clippy/clippy_lints/src/lib.rs
index a89cf3fdc1e..c56fa257b06 100644
--- a/src/tools/clippy/clippy_lints/src/lib.rs
+++ b/src/tools/clippy/clippy_lints/src/lib.rs
@@ -302,7 +302,6 @@ mod permissions_set_readonly_false;
 mod pointers_in_nomem_asm_block;
 mod precedence;
 mod ptr;
-mod ptr_offset_with_cast;
 mod pub_underscore_fields;
 mod pub_use;
 mod question_mark;
@@ -360,6 +359,7 @@ mod temporary_assignment;
 mod tests_outside_test_module;
 mod to_digit_is_some;
 mod to_string_trait_impl;
+mod toplevel_ref_arg;
 mod trailing_empty_array;
 mod trait_bounds;
 mod transmute;
@@ -592,7 +592,6 @@ pub fn register_lint_passes(store: &mut rustc_lint::LintStore, conf: &'static Co
     store.register_late_pass(|_| Box::new(unwrap::Unwrap));
     store.register_late_pass(move |_| Box::new(indexing_slicing::IndexingSlicing::new(conf)));
     store.register_late_pass(move |tcx| Box::new(non_copy_const::NonCopyConst::new(tcx, conf)));
-    store.register_late_pass(|_| Box::new(ptr_offset_with_cast::PtrOffsetWithCast));
     store.register_late_pass(|_| Box::new(redundant_clone::RedundantClone));
     store.register_late_pass(|_| Box::new(slow_vector_initialization::SlowVectorInit));
     store.register_late_pass(move |_| Box::new(unnecessary_wraps::UnnecessaryWraps::new(conf)));
@@ -744,7 +743,7 @@ pub fn register_lint_passes(store: &mut rustc_lint::LintStore, conf: &'static Co
     store.register_late_pass(|_| Box::new(missing_assert_message::MissingAssertMessage));
     store.register_late_pass(|_| Box::new(needless_maybe_sized::NeedlessMaybeSized));
     store.register_late_pass(|_| Box::new(redundant_async_block::RedundantAsyncBlock));
-    store.register_late_pass(|_| Box::new(let_with_type_underscore::UnderscoreTyped));
+    store.register_early_pass(|| Box::new(let_with_type_underscore::UnderscoreTyped));
     store.register_late_pass(move |_| Box::new(manual_main_separator_str::ManualMainSeparatorStr::new(conf)));
     store.register_late_pass(|_| Box::new(unnecessary_struct_initialization::UnnecessaryStruct));
     store.register_late_pass(move |_| Box::new(unnecessary_box_returns::UnnecessaryBoxReturns::new(conf)));
@@ -831,5 +830,6 @@ pub fn register_lint_passes(store: &mut rustc_lint::LintStore, conf: &'static Co
     store.register_late_pass(|_| Box::new(cloned_ref_to_slice_refs::ClonedRefToSliceRefs::new(conf)));
     store.register_late_pass(|_| Box::new(infallible_try_from::InfallibleTryFrom));
     store.register_late_pass(|_| Box::new(coerce_container_to_any::CoerceContainerToAny));
+    store.register_late_pass(|_| Box::new(toplevel_ref_arg::ToplevelRefArg));
     // add lints here, do not remove this comment, it's used in `new_lint`
 }
diff --git a/src/tools/clippy/clippy_lints/src/lifetimes.rs b/src/tools/clippy/clippy_lints/src/lifetimes.rs
index 149ae5e710c..d8b186b6787 100644
--- a/src/tools/clippy/clippy_lints/src/lifetimes.rs
+++ b/src/tools/clippy/clippy_lints/src/lifetimes.rs
@@ -745,7 +745,7 @@ fn report_elidable_impl_lifetimes<'tcx>(
     impl_: &'tcx Impl<'_>,
     map: &FxIndexMap<LocalDefId, Vec<Usage>>,
 ) {
-    let single_usages = map
+    let (elidable_lts, usages): (Vec<_>, Vec<_>) = map
         .iter()
         .filter_map(|(def_id, usages)| {
             if let [
@@ -762,14 +762,12 @@ fn report_elidable_impl_lifetimes<'tcx>(
                 None
             }
         })
-        .collect::<Vec<_>>();
+        .unzip();
 
-    if single_usages.is_empty() {
+    if elidable_lts.is_empty() {
         return;
     }
 
-    let (elidable_lts, usages): (Vec<_>, Vec<_>) = single_usages.into_iter().unzip();
-
     report_elidable_lifetimes(cx, impl_.generics, &elidable_lts, &usages, true);
 }
 
@@ -795,9 +793,7 @@ fn report_elidable_lifetimes(
         // In principle, the result of the call to `Node::ident` could be `unwrap`ped, as `DefId` should refer to a
         // `Node::GenericParam`.
         .filter_map(|&def_id| cx.tcx.hir_node_by_def_id(def_id).ident())
-        .map(|ident| ident.to_string())
-        .collect::<Vec<_>>()
-        .join(", ");
+        .format(", ");
 
     let elidable_usages: Vec<ElidableUsage> = usages
         .iter()
@@ -860,36 +856,89 @@ fn elision_suggestions(
         .filter(|param| !param.is_elided_lifetime() && !param.is_impl_trait())
         .collect::<Vec<_>>();
 
-    let mut suggestions = if elidable_lts.len() == explicit_params.len() {
+    if !elidable_lts
+        .iter()
+        .all(|lt| explicit_params.iter().any(|param| param.def_id == *lt))
+    {
+        return None;
+    }
+
+    let mut suggestions = if elidable_lts.is_empty() {
+        vec![]
+    } else if elidable_lts.len() == explicit_params.len() {
         // if all the params are elided remove the whole generic block
         //
         // fn x<'a>() {}
         //     ^^^^
         vec![(generics.span, String::new())]
     } else {
-        elidable_lts
-            .iter()
-            .map(|&id| {
-                let pos = explicit_params.iter().position(|param| param.def_id == id)?;
-                let param = explicit_params.get(pos)?;
-
-                let span = if let Some(next) = explicit_params.get(pos + 1) {
-                    // fn x<'prev, 'a, 'next>() {}
-                    //             ^^^^
-                    param.span.until(next.span)
+        match &explicit_params[..] {
+            // no params, nothing to elide
+            [] => unreachable!("handled by `elidable_lts.is_empty()`"),
+            [param] => {
+                if elidable_lts.contains(&param.def_id) {
+                    unreachable!("handled by `elidable_lts.len() == explicit_params.len()`")
                 } else {
-                    // `pos` should be at least 1 here, because the param in position 0 would either have a `next`
-                    // param or would have taken the `elidable_lts.len() == explicit_params.len()` branch.
-                    let prev = explicit_params.get(pos - 1)?;
-
-                    // fn x<'prev, 'a>() {}
-                    //           ^^^^
-                    param.span.with_lo(prev.span.hi())
+                    unreachable!("handled by `elidable_lts.is_empty()`")
+                }
+            },
+            [_, _, ..] => {
+                // Given a list like `<'a, 'b, 'c, 'd, ..>`,
+                //
+                // If there is a cluster of elidable lifetimes at the beginning, say `'a` and `'b`, we should
+                // suggest removing them _and_ the trailing comma. The span for that is `a.span.until(c.span)`:
+                // <'a, 'b, 'c, 'd, ..> => <'a, 'b, 'c, 'd, ..>
+                //  ^^  ^^                  ^^^^^^^^
+                //
+                // And since we know that `'c` isn't elidable--otherwise it would've been in the cluster--we can go
+                // over all the lifetimes after it, and for each elidable one, add a suggestion spanning the
+                // lifetime itself and the comma before, because each individual suggestion is guaranteed to leave
+                // the list valid:
+                // <.., 'c, 'd, 'e, 'f, 'g, ..> => <.., 'c, 'd, 'e, 'f, 'g, ..>
+                //          ^^      ^^  ^^                ^^^^    ^^^^^^^^
+                //
+                // In case there is no such starting cluster, we only need to do the second part of the algorithm:
+                // <'a, 'b, 'c, 'd, 'e, 'f, 'g, ..> => <'a, 'b , 'c, 'd, 'e, 'f, 'g, ..>
+                //      ^^  ^^      ^^  ^^                ^^^^^^^^^    ^^^^^^^^
+
+                // Split off the starting cluster
+                // TODO: use `slice::split_once` once stabilized (github.com/rust-lang/rust/issues/112811):
+                // ```
+                // let Some(split) = explicit_params.split_once(|param| !elidable_lts.contains(&param.def_id)) else {
+                //     // there were no lifetime param that couldn't be elided
+                //     unreachable!("handled by `elidable_lts.len() == explicit_params.len()`")
+                // };
+                // match split { /* .. */ }
+                // ```
+                let Some(split_pos) = explicit_params
+                    .iter()
+                    .position(|param| !elidable_lts.contains(&param.def_id))
+                else {
+                    // there were no lifetime param that couldn't be elided
+                    unreachable!("handled by `elidable_lts.len() == explicit_params.len()`")
                 };
-
-                Some((span, String::new()))
-            })
-            .collect::<Option<Vec<_>>>()?
+                let split = explicit_params
+                    .split_at_checked(split_pos)
+                    .expect("got `split_pos` from `position` on the same Vec");
+
+                match split {
+                    ([..], []) => unreachable!("handled by `elidable_lts.len() == explicit_params.len()`"),
+                    ([], [_]) => unreachable!("handled by `explicit_params.len() == 1`"),
+                    (cluster, rest @ [rest_first, ..]) => {
+                        // the span for the cluster
+                        (cluster.first().map(|fw| fw.span.until(rest_first.span)).into_iter())
+                            // the span for the remaining lifetimes (calculations independent of the cluster)
+                            .chain(
+                                rest.array_windows()
+                                    .filter(|[_, curr]| elidable_lts.contains(&curr.def_id))
+                                    .map(|[prev, curr]| curr.span.with_lo(prev.span.hi())),
+                            )
+                            .map(|sp| (sp, String::new()))
+                            .collect()
+                    },
+                }
+            },
+        }
     };
 
     suggestions.extend(usages.iter().map(|&usage| {
diff --git a/src/tools/clippy/clippy_lints/src/loops/explicit_iter_loop.rs b/src/tools/clippy/clippy_lints/src/loops/explicit_iter_loop.rs
index 6ce7f0b1f0b..af475c40586 100644
--- a/src/tools/clippy/clippy_lints/src/loops/explicit_iter_loop.rs
+++ b/src/tools/clippy/clippy_lints/src/loops/explicit_iter_loop.rs
@@ -138,9 +138,9 @@ fn is_ref_iterable<'tcx>(
             return Some((AdjustKind::None, self_ty));
         }
 
-        let res_ty = cx
-            .tcx
-            .erase_and_anonymize_regions(EarlyBinder::bind(req_res_ty).instantiate(cx.tcx, typeck.node_args(call_expr.hir_id)));
+        let res_ty = cx.tcx.erase_and_anonymize_regions(
+            EarlyBinder::bind(req_res_ty).instantiate(cx.tcx, typeck.node_args(call_expr.hir_id)),
+        );
         let mutbl = if let ty::Ref(_, _, mutbl) = *req_self_ty.kind() {
             Some(mutbl)
         } else {
diff --git a/src/tools/clippy/clippy_lints/src/loops/never_loop.rs b/src/tools/clippy/clippy_lints/src/loops/never_loop.rs
index 2ccff768097..544c3c34d02 100644
--- a/src/tools/clippy/clippy_lints/src/loops/never_loop.rs
+++ b/src/tools/clippy/clippy_lints/src/loops/never_loop.rs
@@ -22,7 +22,10 @@ pub(super) fn check<'tcx>(
     for_loop: Option<&ForLoop<'_>>,
 ) {
     match never_loop_block(cx, block, &mut Vec::new(), loop_id) {
-        NeverLoopResult::Diverging { ref break_spans } => {
+        NeverLoopResult::Diverging {
+            ref break_spans,
+            ref never_spans,
+        } => {
             span_lint_and_then(cx, NEVER_LOOP, span, "this loop never actually loops", |diag| {
                 if let Some(ForLoop {
                     arg: iterator,
@@ -34,12 +37,16 @@ pub(super) fn check<'tcx>(
                 {
                     // If the block contains a break or continue, or if the loop has a label, `MachineApplicable` is not
                     // appropriate.
-                    let app = if !contains_any_break_or_continue(block) && label.is_none() {
+                    let mut app = if !contains_any_break_or_continue(block) && label.is_none() {
                         Applicability::MachineApplicable
                     } else {
                         Applicability::Unspecified
                     };
 
+                    if !never_spans.is_empty() {
+                        app = Applicability::HasPlaceholders;
+                    }
+
                     let mut suggestions = vec![(
                         for_span.with_hi(iterator.span.hi()),
                         for_to_if_let_sugg(cx, iterator, pat),
@@ -51,6 +58,13 @@ pub(super) fn check<'tcx>(
                         suggestions,
                         app,
                     );
+
+                    for span in never_spans {
+                        diag.span_help(
+                            *span,
+                            "this code is unreachable. Consider moving the reachable parts out",
+                        );
+                    }
                 }
             });
         },
@@ -77,13 +91,16 @@ fn contains_any_break_or_continue(block: &Block<'_>) -> bool {
 /// The first two bits of information are in this enum, and the last part is in the
 /// `local_labels` variable, which contains a list of `(block_id, reachable)` pairs ordered by
 /// scope.
-#[derive(Clone)]
+#[derive(Clone, Debug)]
 enum NeverLoopResult {
     /// A continue may occur for the main loop.
     MayContinueMainLoop,
     /// We have not encountered any main loop continue,
     /// but we are diverging (subsequent control flow is not reachable)
-    Diverging { break_spans: Vec<Span> },
+    Diverging {
+        break_spans: Vec<Span>,
+        never_spans: Vec<Span>,
+    },
     /// We have not encountered any main loop continue,
     /// and subsequent control flow is (possibly) reachable
     Normal,
@@ -128,14 +145,18 @@ fn combine_branches(b1: NeverLoopResult, b2: NeverLoopResult) -> NeverLoopResult
         (
             NeverLoopResult::Diverging {
                 break_spans: mut break_spans1,
+                never_spans: mut never_spans1,
             },
             NeverLoopResult::Diverging {
                 break_spans: mut break_spans2,
+                never_spans: mut never_spans2,
             },
         ) => {
             break_spans1.append(&mut break_spans2);
+            never_spans1.append(&mut never_spans2);
             NeverLoopResult::Diverging {
                 break_spans: break_spans1,
+                never_spans: never_spans1,
             }
         },
     }
@@ -207,6 +228,8 @@ fn all_spans_after_expr(cx: &LateContext<'_>, expr: &Expr<'_>) -> Vec<Span> {
         }
 
         return vec![stmt.span];
+    } else if let Node::Block(_) = cx.tcx.parent_hir_node(expr.hir_id) {
+        return vec![expr.span];
     }
 
     vec![]
@@ -270,10 +293,13 @@ fn never_loop_expr<'tcx>(
         ExprKind::Match(e, arms, _) => {
             let e = never_loop_expr(cx, e, local_labels, main_loop_id);
             combine_seq(e, || {
-                arms.iter()
-                    .fold(NeverLoopResult::Diverging { break_spans: vec![] }, |a, b| {
-                        combine_branches(a, never_loop_expr(cx, b.body, local_labels, main_loop_id))
-                    })
+                arms.iter().fold(
+                    NeverLoopResult::Diverging {
+                        break_spans: vec![],
+                        never_spans: vec![],
+                    },
+                    |a, b| combine_branches(a, never_loop_expr(cx, b.body, local_labels, main_loop_id)),
+                )
             })
         },
         ExprKind::Block(b, _) => {
@@ -296,6 +322,7 @@ fn never_loop_expr<'tcx>(
             } else {
                 NeverLoopResult::Diverging {
                     break_spans: all_spans_after_expr(cx, expr),
+                    never_spans: vec![],
                 }
             }
         },
@@ -306,7 +333,10 @@ fn never_loop_expr<'tcx>(
             combine_seq(first, || {
                 // checks if break targets a block instead of a loop
                 mark_block_as_reachable(expr, local_labels);
-                NeverLoopResult::Diverging { break_spans: vec![] }
+                NeverLoopResult::Diverging {
+                    break_spans: vec![],
+                    never_spans: vec![],
+                }
             })
         },
         ExprKind::Break(dest, e) => {
@@ -322,11 +352,15 @@ fn never_loop_expr<'tcx>(
                     } else {
                         all_spans_after_expr(cx, expr)
                     },
+                    never_spans: vec![],
                 }
             })
         },
         ExprKind::Become(e) => combine_seq(never_loop_expr(cx, e, local_labels, main_loop_id), || {
-            NeverLoopResult::Diverging { break_spans: vec![] }
+            NeverLoopResult::Diverging {
+                break_spans: vec![],
+                never_spans: vec![],
+            }
         }),
         ExprKind::InlineAsm(asm) => combine_seq_many(asm.operands.iter().map(|(o, _)| match o {
             InlineAsmOperand::In { expr, .. } | InlineAsmOperand::InOut { expr, .. } => {
@@ -356,7 +390,10 @@ fn never_loop_expr<'tcx>(
     };
     let result = combine_seq(result, || {
         if cx.typeck_results().expr_ty(expr).is_never() {
-            NeverLoopResult::Diverging { break_spans: vec![] }
+            NeverLoopResult::Diverging {
+                break_spans: vec![],
+                never_spans: all_spans_after_expr(cx, expr),
+            }
         } else {
             NeverLoopResult::Normal
         }
diff --git a/src/tools/clippy/clippy_lints/src/manual_abs_diff.rs b/src/tools/clippy/clippy_lints/src/manual_abs_diff.rs
index 288f27db8ca..5814b6815a1 100644
--- a/src/tools/clippy/clippy_lints/src/manual_abs_diff.rs
+++ b/src/tools/clippy/clippy_lints/src/manual_abs_diff.rs
@@ -4,8 +4,8 @@ use clippy_utils::higher::If;
 use clippy_utils::msrvs::{self, Msrv};
 use clippy_utils::source::HasSession as _;
 use clippy_utils::sugg::Sugg;
-use clippy_utils::ty::is_type_diagnostic_item;
-use clippy_utils::{eq_expr_value, peel_blocks, peel_middle_ty_refs, span_contains_comment};
+use clippy_utils::ty::{is_type_diagnostic_item, peel_and_count_ty_refs};
+use clippy_utils::{eq_expr_value, peel_blocks, span_contains_comment};
 use rustc_errors::Applicability;
 use rustc_hir::{BinOpKind, Expr, ExprKind};
 use rustc_lint::{LateContext, LateLintPass};
@@ -107,7 +107,7 @@ impl ManualAbsDiff {
             |ty| is_type_diagnostic_item(cx, ty, sym::Duration) && self.msrv.meets(cx, msrvs::DURATION_ABS_DIFF);
 
         let a_ty = cx.typeck_results().expr_ty(a).peel_refs();
-        let (b_ty, b_n_refs) = peel_middle_ty_refs(cx.typeck_results().expr_ty(b));
+        let (b_ty, b_n_refs, _) = peel_and_count_ty_refs(cx.typeck_results().expr_ty(b));
 
         (a_ty == b_ty && (is_int(a_ty) || is_duration(a_ty))).then_some((a_ty, b_n_refs))
     }
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 922db174e3d..b036e78cded 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, peel_hir_expr_refs, sym};
+use clippy_utils::{is_none_pattern, 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};
@@ -60,8 +60,8 @@ impl LateLintPass<'_> for ManualOptionAsSlice {
         }
         match expr.kind {
             ExprKind::Match(scrutinee, [arm1, arm2], _) => {
-                if is_none_arm(cx, arm2) && check_arms(cx, arm2, arm1)
-                    || is_none_arm(cx, arm1) && check_arms(cx, arm1, arm2)
+                if is_none_pattern(cx, arm2.pat) && check_arms(cx, arm2, arm1)
+                    || is_none_pattern(cx, arm1.pat) && check_arms(cx, arm1, arm2)
                 {
                     check_as_ref(cx, scrutinee, span, self.msrv);
                 }
diff --git a/src/tools/clippy/clippy_lints/src/manual_slice_size_calculation.rs b/src/tools/clippy/clippy_lints/src/manual_slice_size_calculation.rs
index 0c09a47c965..de12fa29d02 100644
--- a/src/tools/clippy/clippy_lints/src/manual_slice_size_calculation.rs
+++ b/src/tools/clippy/clippy_lints/src/manual_slice_size_calculation.rs
@@ -2,6 +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_context;
+use clippy_utils::ty::peel_and_count_ty_refs;
 use clippy_utils::{expr_or_init, is_in_const_context, std_or_core};
 use rustc_errors::Applicability;
 use rustc_hir::{BinOpKind, Expr, ExprKind};
@@ -102,7 +103,7 @@ fn simplify_half<'tcx>(
         && let ExprKind::MethodCall(method_path, receiver, [], _) = expr1.kind
         && method_path.ident.name == sym::len
         && let receiver_ty = cx.typeck_results().expr_ty(receiver)
-        && let (receiver_ty, refs_count) = clippy_utils::ty::walk_ptrs_ty_depth(receiver_ty)
+        && let (receiver_ty, refs_count, _) = peel_and_count_ty_refs(receiver_ty)
         && let ty::Slice(ty1) = receiver_ty.kind()
         // expr2 is `size_of::<T2>()`?
         && let ExprKind::Call(func, []) = expr2.kind
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 edbb556fd97..a8490d6aa7d 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,7 +1,7 @@
 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, peel_mid_ty_refs_is_mutable};
+use clippy_utils::ty::{option_arg_ty, peel_and_count_ty_refs};
 use clippy_utils::{get_parent_expr, is_res_lang_ctor, path_res, peel_blocks, span_contains_comment};
 use rustc_ast::{BindingMode, Mutability};
 use rustc_errors::Applicability;
@@ -135,15 +135,11 @@ fn apply_lint(cx: &LateContext<'_>, expr: &Expr<'_>, scrutinee: &Expr<'_>, is_ok
     let scrut = Sugg::hir_with_applicability(cx, scrutinee, "..", &mut app).maybe_paren();
 
     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 (_, _, mutability) = peel_and_count_ty_refs(scrutinee_ty);
+    let prefix = match mutability {
+        Some(Mutability::Mut) => ".as_mut()",
+        Some(Mutability::Not) => ".as_ref()",
+        None => "",
     };
 
     let sugg = format!("{scrut}{prefix}.{method}()");
diff --git a/src/tools/clippy/clippy_lints/src/matches/manual_utils.rs b/src/tools/clippy/clippy_lints/src/matches/manual_utils.rs
index dbae71bbb1b..d4bfdb7e440 100644
--- a/src/tools/clippy/clippy_lints/src/matches/manual_utils.rs
+++ b/src/tools/clippy/clippy_lints/src/matches/manual_utils.rs
@@ -2,7 +2,7 @@ use crate::map_unit_fn::OPTION_MAP_UNIT_FN;
 use crate::matches::MATCH_AS_REF;
 use clippy_utils::source::{snippet_with_applicability, snippet_with_context};
 use clippy_utils::sugg::Sugg;
-use clippy_utils::ty::{is_copy, is_type_diagnostic_item, peel_mid_ty_refs_is_mutable, type_is_unsafe_function};
+use clippy_utils::ty::{is_copy, is_type_diagnostic_item, is_unsafe_fn, peel_and_count_ty_refs};
 use clippy_utils::{
     CaptureKind, can_move_expr_to_closure, expr_requires_coercion, is_else_clause, is_lint_allowed, is_res_lang_ctor,
     path_res, path_to_local_id, peel_blocks, peel_hir_expr_refs, peel_hir_expr_while,
@@ -30,8 +30,9 @@ pub(super) fn check_with<'tcx, F>(
 where
     F: Fn(&LateContext<'tcx>, &'tcx Pat<'_>, &'tcx Expr<'_>, SyntaxContext) -> Option<SomeExpr<'tcx>>,
 {
-    let (scrutinee_ty, ty_ref_count, ty_mutability) =
-        peel_mid_ty_refs_is_mutable(cx.typeck_results().expr_ty(scrutinee));
+    let (scrutinee_ty, ty_ref_count, ty_mutability) = peel_and_count_ty_refs(cx.typeck_results().expr_ty(scrutinee));
+    let ty_mutability = ty_mutability.unwrap_or(Mutability::Mut);
+
     if !(is_type_diagnostic_item(cx, scrutinee_ty, sym::Option)
         && is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(expr), sym::Option))
     {
@@ -191,7 +192,7 @@ fn can_pass_as_func<'tcx>(cx: &LateContext<'tcx>, binding: HirId, expr: &'tcx Ex
         ExprKind::Call(func, [arg])
             if path_to_local_id(arg, binding)
                 && cx.typeck_results().expr_adjustments(arg).is_empty()
-                && !type_is_unsafe_function(cx, cx.typeck_results().expr_ty(func).peel_refs()) =>
+                && !is_unsafe_fn(cx, cx.typeck_results().expr_ty(func).peel_refs()) =>
         {
             Some(func)
         },
diff --git a/src/tools/clippy/clippy_lints/src/matches/needless_match.rs b/src/tools/clippy/clippy_lints/src/matches/needless_match.rs
index b04db03f8d2..3a2097c3df2 100644
--- a/src/tools/clippy/clippy_lints/src/matches/needless_match.rs
+++ b/src/tools/clippy/clippy_lints/src/matches/needless_match.rs
@@ -1,7 +1,7 @@
 use super::NEEDLESS_MATCH;
 use clippy_utils::diagnostics::span_lint_and_sugg;
 use clippy_utils::source::snippet_with_applicability;
-use clippy_utils::ty::{is_type_diagnostic_item, same_type_and_consts};
+use clippy_utils::ty::{is_type_diagnostic_item, same_type_modulo_regions};
 use clippy_utils::{
     SpanlessEq, eq_expr_value, get_parent_expr_for_hir, higher, is_else_clause, is_res_lang_ctor, over, path_res,
     peel_blocks_with_stmt,
@@ -122,7 +122,7 @@ fn expr_ty_matches_p_ty(cx: &LateContext<'_>, expr: &Expr<'_>, p_expr: &Expr<'_>
         // Compare match_expr ty with local in `let local = match match_expr {..}`
         Node::LetStmt(local) => {
             let results = cx.typeck_results();
-            return same_type_and_consts(results.node_type(local.hir_id), results.expr_ty(expr));
+            return same_type_modulo_regions(results.node_type(local.hir_id), results.expr_ty(expr));
         },
         // compare match_expr ty with RetTy in `fn foo() -> RetTy`
         Node::Item(item) => {
@@ -133,7 +133,7 @@ fn expr_ty_matches_p_ty(cx: &LateContext<'_>, expr: &Expr<'_>, p_expr: &Expr<'_>
                     .instantiate_identity()
                     .output()
                     .skip_binder();
-                return same_type_and_consts(output, cx.typeck_results().expr_ty(expr));
+                return same_type_modulo_regions(output, cx.typeck_results().expr_ty(expr));
             }
         },
         // check the parent expr for this whole block `{ match match_expr {..} }`
diff --git a/src/tools/clippy/clippy_lints/src/matches/rest_pat_in_fully_bound_struct.rs b/src/tools/clippy/clippy_lints/src/matches/rest_pat_in_fully_bound_struct.rs
index ae09c2e87d6..1130d82ab78 100644
--- a/src/tools/clippy/clippy_lints/src/matches/rest_pat_in_fully_bound_struct.rs
+++ b/src/tools/clippy/clippy_lints/src/matches/rest_pat_in_fully_bound_struct.rs
@@ -7,7 +7,7 @@ use super::REST_PAT_IN_FULLY_BOUND_STRUCTS;
 
 pub(crate) fn check(cx: &LateContext<'_>, pat: &Pat<'_>) {
     if !pat.span.from_expansion()
-        && let PatKind::Struct(QPath::Resolved(_, path), fields, Some(_)) = pat.kind
+        && let PatKind::Struct(QPath::Resolved(_, path), fields, Some(dotdot)) = pat.kind
         && let Some(def_id) = path.res.opt_def_id()
         && let ty = cx.tcx.type_of(def_id).instantiate_identity()
         && let ty::Adt(def, _) = ty.kind()
@@ -15,14 +15,18 @@ pub(crate) fn check(cx: &LateContext<'_>, pat: &Pat<'_>) {
         && fields.len() == def.non_enum_variant().fields.len()
         && !def.non_enum_variant().is_field_list_non_exhaustive()
     {
-        #[expect(clippy::collapsible_span_lint_calls, reason = "rust-clippy#7797")]
         span_lint_and_then(
             cx,
             REST_PAT_IN_FULLY_BOUND_STRUCTS,
             pat.span,
             "unnecessary use of `..` pattern in struct binding. All fields were already bound",
             |diag| {
-                diag.help("consider removing `..` from this binding");
+                diag.span_suggestion_verbose(
+                    dotdot,
+                    "consider removing `..` from this binding",
+                    "",
+                    rustc_errors::Applicability::MachineApplicable,
+                );
             },
         );
     }
diff --git a/src/tools/clippy/clippy_lints/src/matches/single_match.rs b/src/tools/clippy/clippy_lints/src/matches/single_match.rs
index bcf079b7007..83939d32579 100644
--- a/src/tools/clippy/clippy_lints/src/matches/single_match.rs
+++ b/src/tools/clippy/clippy_lints/src/matches/single_match.rs
@@ -2,10 +2,8 @@ use clippy_utils::diagnostics::span_lint_and_then;
 use clippy_utils::source::{
     SpanRangeExt, expr_block, snippet, snippet_block_with_context, snippet_with_applicability, snippet_with_context,
 };
-use clippy_utils::ty::implements_trait;
-use clippy_utils::{
-    is_lint_allowed, is_unit_expr, peel_blocks, peel_hir_pat_refs, peel_middle_ty_refs, peel_n_hir_expr_refs,
-};
+use clippy_utils::ty::{implements_trait, peel_and_count_ty_refs};
+use clippy_utils::{is_lint_allowed, is_unit_expr, peel_blocks, peel_hir_pat_refs, peel_n_hir_expr_refs};
 use core::ops::ControlFlow;
 use rustc_arena::DroplessArena;
 use rustc_errors::{Applicability, Diag};
@@ -133,7 +131,7 @@ fn report_single_pattern(
 
     let (pat, pat_ref_count) = peel_hir_pat_refs(arm.pat);
     let (msg, sugg) = if let PatKind::Expr(_) = pat.kind
-        && let (ty, ty_ref_count) = peel_middle_ty_refs(cx.typeck_results().expr_ty(ex))
+        && let (ty, ty_ref_count, _) = peel_and_count_ty_refs(cx.typeck_results().expr_ty(ex))
         && let Some(spe_trait_id) = cx.tcx.lang_items().structural_peq_trait()
         && let Some(pe_trait_id) = cx.tcx.lang_items().eq_trait()
         && (ty.is_integral()
diff --git a/src/tools/clippy/clippy_lints/src/methods/implicit_clone.rs b/src/tools/clippy/clippy_lints/src/methods/implicit_clone.rs
index 8a976d1b4dc..0ba84919395 100644
--- a/src/tools/clippy/clippy_lints/src/methods/implicit_clone.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/implicit_clone.rs
@@ -1,7 +1,7 @@
 use clippy_utils::diagnostics::span_lint_and_sugg;
 use clippy_utils::source::snippet_with_context;
-use clippy_utils::ty::implements_trait;
-use clippy_utils::{is_diag_item_method, is_diag_trait_item, peel_middle_ty_refs, sym};
+use clippy_utils::ty::{implements_trait, peel_and_count_ty_refs};
+use clippy_utils::{is_diag_item_method, is_diag_trait_item, sym};
 use rustc_errors::Applicability;
 use rustc_hir as hir;
 use rustc_lint::LateContext;
@@ -14,7 +14,7 @@ pub fn check(cx: &LateContext<'_>, method_name: Symbol, expr: &hir::Expr<'_>, re
         && is_clone_like(cx, method_name, method_def_id)
         && let return_type = cx.typeck_results().expr_ty(expr)
         && let input_type = cx.typeck_results().expr_ty(recv)
-        && let (input_type, ref_count) = peel_middle_ty_refs(input_type)
+        && let (input_type, ref_count, _) = peel_and_count_ty_refs(input_type)
         && !(ref_count > 0 && is_diag_trait_item(cx, method_def_id, sym::ToOwned))
         && let Some(ty_name) = input_type.ty_adt_def().map(|adt_def| cx.tcx.item_name(adt_def.did()))
         && return_type == input_type
diff --git a/src/tools/clippy/clippy_lints/src/methods/inefficient_to_string.rs b/src/tools/clippy/clippy_lints/src/methods/inefficient_to_string.rs
index 4ed7de81ea3..47195fdd65f 100644
--- a/src/tools/clippy/clippy_lints/src/methods/inefficient_to_string.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/inefficient_to_string.rs
@@ -1,6 +1,6 @@
 use clippy_utils::diagnostics::span_lint_and_then;
 use clippy_utils::source::snippet_with_applicability;
-use clippy_utils::ty::{is_type_lang_item, walk_ptrs_ty_depth};
+use clippy_utils::ty::{is_type_lang_item, peel_and_count_ty_refs};
 use rustc_errors::Applicability;
 use rustc_hir as hir;
 use rustc_lint::LateContext;
@@ -24,7 +24,7 @@ pub fn check(
         && let Some(args) = cx.typeck_results().node_args_opt(expr.hir_id)
         && let arg_ty = cx.typeck_results().expr_ty_adjusted(receiver)
         && let self_ty = args.type_at(0)
-        && let (deref_self_ty, deref_count) = walk_ptrs_ty_depth(self_ty)
+        && let (deref_self_ty, deref_count, _) = peel_and_count_ty_refs(self_ty)
         && deref_count >= 1
         && specializes_tostring(cx, deref_self_ty)
     {
diff --git a/src/tools/clippy/clippy_lints/src/methods/iter_overeager_cloned.rs b/src/tools/clippy/clippy_lints/src/methods/iter_overeager_cloned.rs
index f851ebe91f3..d43dc23a86b 100644
--- a/src/tools/clippy/clippy_lints/src/methods/iter_overeager_cloned.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/iter_overeager_cloned.rs
@@ -10,8 +10,7 @@ use rustc_middle::mir::{FakeReadCause, Mutability};
 use rustc_middle::ty::{self, BorrowKind};
 use rustc_span::{Symbol, sym};
 
-use super::ITER_OVEREAGER_CLONED;
-use crate::redundant_clone::REDUNDANT_CLONE;
+use super::{ITER_OVEREAGER_CLONED, REDUNDANT_ITER_CLONED};
 
 #[derive(Clone, Copy)]
 pub(super) enum Op<'a> {
@@ -96,7 +95,7 @@ pub(super) fn check<'tcx>(
         }
 
         let (lint, msg, trailing_clone) = match op {
-            Op::RmCloned | Op::NeedlessMove(_) => (REDUNDANT_CLONE, "unneeded cloning of iterator items", ""),
+            Op::RmCloned | Op::NeedlessMove(_) => (REDUNDANT_ITER_CLONED, "unneeded cloning of iterator items", ""),
             Op::LaterCloned | Op::FixClosure(_, _) => (
                 ITER_OVEREAGER_CLONED,
                 "unnecessarily eager cloning of iterator items",
diff --git a/src/tools/clippy/clippy_lints/src/methods/mod.rs b/src/tools/clippy/clippy_lints/src/methods/mod.rs
index 49ca81dafc2..8679689c8ad 100644
--- a/src/tools/clippy/clippy_lints/src/methods/mod.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/mod.rs
@@ -91,6 +91,7 @@ mod or_fun_call;
 mod or_then_unwrap;
 mod path_buf_push_overwrite;
 mod path_ends_with_ext;
+mod ptr_offset_with_cast;
 mod range_zip_with_len;
 mod read_line_without_trim;
 mod readonly_write_lock;
@@ -1727,6 +1728,43 @@ declare_clippy_lint! {
 
 declare_clippy_lint! {
     /// ### What it does
+    /// Checks for usage of the `offset` pointer method with a `usize` casted to an
+    /// `isize`.
+    ///
+    /// ### Why is this bad?
+    /// If we’re always increasing the pointer address, we can avoid the numeric
+    /// cast by using the `add` method instead.
+    ///
+    /// ### Example
+    /// ```no_run
+    /// let vec = vec![b'a', b'b', b'c'];
+    /// let ptr = vec.as_ptr();
+    /// let offset = 1_usize;
+    ///
+    /// unsafe {
+    ///     ptr.offset(offset as isize);
+    /// }
+    /// ```
+    ///
+    /// Could be written:
+    ///
+    /// ```no_run
+    /// let vec = vec![b'a', b'b', b'c'];
+    /// let ptr = vec.as_ptr();
+    /// let offset = 1_usize;
+    ///
+    /// unsafe {
+    ///     ptr.add(offset);
+    /// }
+    /// ```
+    #[clippy::version = "1.30.0"]
+    pub PTR_OFFSET_WITH_CAST,
+    complexity,
+    "unneeded pointer offset cast"
+}
+
+declare_clippy_lint! {
+    /// ### What it does
     /// Checks for `FileType::is_file()`.
     ///
     /// ### Why restrict this?
@@ -4576,6 +4614,31 @@ declare_clippy_lint! {
     "hardcoded localhost IP address"
 }
 
+declare_clippy_lint! {
+    /// ### What it does
+    /// Checks for calls to `Iterator::cloned` where the original value could be used
+    /// instead.
+    ///
+    /// ### Why is this bad?
+    /// It is not always possible for the compiler to eliminate useless allocations and
+    /// deallocations generated by redundant `clone()`s.
+    ///
+    /// ### Example
+    /// ```no_run
+    /// let x = vec![String::new()];
+    /// let _ = x.iter().cloned().map(|x| x.len());
+    /// ```
+    /// Use instead:
+    /// ```no_run
+    /// let x = vec![String::new()];
+    /// let _ = x.iter().map(|x| x.len());
+    /// ```
+    #[clippy::version = "1.90.0"]
+    pub REDUNDANT_ITER_CLONED,
+    perf,
+    "detects redundant calls to `Iterator::cloned`"
+}
+
 #[expect(clippy::struct_excessive_bools)]
 pub struct Methods {
     avoid_breaking_exported_api: bool,
@@ -4665,6 +4728,7 @@ impl_lint_pass!(Methods => [
     UNINIT_ASSUMED_INIT,
     MANUAL_SATURATING_ARITHMETIC,
     ZST_OFFSET,
+    PTR_OFFSET_WITH_CAST,
     FILETYPE_IS_FILE,
     OPTION_AS_REF_DEREF,
     UNNECESSARY_LAZY_EVALUATIONS,
@@ -4755,6 +4819,7 @@ impl_lint_pass!(Methods => [
     IO_OTHER_ERROR,
     SWAP_WITH_TEMPORARY,
     IP_CONSTANT,
+    REDUNDANT_ITER_CLONED,
 ]);
 
 /// Extracts a method call name, args, and `Span` of the method name.
@@ -4960,10 +5025,7 @@ impl Methods {
         // Handle method calls whose receiver and arguments may not come from expansion
         if let Some((name, recv, args, span, call_span)) = method_call(expr) {
             match (name, args) {
-                (
-                    sym::add | sym::offset | sym::sub | sym::wrapping_offset | sym::wrapping_add | sym::wrapping_sub,
-                    [_arg],
-                ) => {
+                (sym::add | sym::sub | sym::wrapping_add | sym::wrapping_sub, [_arg]) => {
                     zst_offset::check(cx, expr, recv);
                 },
                 (sym::all, [arg]) => {
@@ -5334,6 +5396,11 @@ impl Methods {
                     },
                     _ => iter_nth_zero::check(cx, expr, recv, n_arg),
                 },
+                (sym::offset | sym::wrapping_offset, [arg]) => {
+                    zst_offset::check(cx, expr, recv);
+
+                    ptr_offset_with_cast::check(cx, name, expr, recv, arg, self.msrv);
+                },
                 (sym::ok_or_else, [arg]) => {
                     unnecessary_lazy_eval::check(cx, expr, recv, arg, "ok_or");
                 },
diff --git a/src/tools/clippy/clippy_lints/src/methods/mut_mutex_lock.rs b/src/tools/clippy/clippy_lints/src/methods/mut_mutex_lock.rs
index 4235af882b0..9d2c5e6232d 100644
--- a/src/tools/clippy/clippy_lints/src/methods/mut_mutex_lock.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/mut_mutex_lock.rs
@@ -1,6 +1,6 @@
 use clippy_utils::diagnostics::span_lint_and_sugg;
 use clippy_utils::expr_custom_deref_adjustment;
-use clippy_utils::ty::{is_type_diagnostic_item, peel_mid_ty_refs_is_mutable};
+use clippy_utils::ty::{is_type_diagnostic_item, peel_and_count_ty_refs};
 use rustc_errors::Applicability;
 use rustc_hir::{Expr, Mutability};
 use rustc_lint::LateContext;
@@ -10,8 +10,7 @@ use super::MUT_MUTEX_LOCK;
 
 pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, ex: &'tcx Expr<'tcx>, recv: &'tcx Expr<'tcx>, name_span: Span) {
     if matches!(expr_custom_deref_adjustment(cx, recv), None | Some(Mutability::Mut))
-        && let (_, ref_depth, Mutability::Mut) = peel_mid_ty_refs_is_mutable(cx.typeck_results().expr_ty(recv))
-        && ref_depth >= 1
+        && let (_, _, Some(Mutability::Mut)) = peel_and_count_ty_refs(cx.typeck_results().expr_ty(recv))
         && let Some(method_id) = cx.typeck_results().type_dependent_def_id(ex.hir_id)
         && let Some(impl_id) = cx.tcx.impl_of_assoc(method_id)
         && is_type_diagnostic_item(cx, cx.tcx.type_of(impl_id).instantiate_identity(), sym::Mutex)
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 04f0e3c0479..71b2f251ede 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
@@ -2,6 +2,7 @@ use std::ops::ControlFlow;
 
 use clippy_utils::diagnostics::span_lint_and_sugg;
 use clippy_utils::eager_or_lazy::switch_to_lazy_eval;
+use clippy_utils::higher::VecArgs;
 use clippy_utils::source::snippet_with_context;
 use clippy_utils::ty::{expr_type_is_certain, implements_trait, is_type_diagnostic_item};
 use clippy_utils::visitors::for_each_expr;
@@ -97,6 +98,12 @@ pub(super) fn check<'tcx>(
             return false;
         }
 
+        // `.unwrap_or(vec![])` is as readable as `.unwrap_or_default()`. And if the expression is a
+        // non-empty `Vec`, then it will not be a default value anyway. Bail out in all cases.
+        if call_expr.and_then(|call_expr| VecArgs::hir(cx, call_expr)).is_some() {
+            return false;
+        }
+
         // needs to target Default::default in particular or be *::new and have a Default impl
         // available
         if (is_new(fun) && output_type_implements_default(fun))
diff --git a/src/tools/clippy/clippy_lints/src/methods/ptr_offset_with_cast.rs b/src/tools/clippy/clippy_lints/src/methods/ptr_offset_with_cast.rs
new file mode 100644
index 00000000000..d19d3b8eb89
--- /dev/null
+++ b/src/tools/clippy/clippy_lints/src/methods/ptr_offset_with_cast.rs
@@ -0,0 +1,82 @@
+use clippy_utils::diagnostics::span_lint_and_then;
+use clippy_utils::msrvs::{self, Msrv};
+use clippy_utils::sym;
+use rustc_errors::Applicability;
+use rustc_hir::{Expr, ExprKind};
+use rustc_lint::LateContext;
+use rustc_span::Symbol;
+use std::fmt;
+
+use super::PTR_OFFSET_WITH_CAST;
+
+pub(super) fn check(
+    cx: &LateContext<'_>,
+    method: Symbol,
+    expr: &Expr<'_>,
+    recv: &Expr<'_>,
+    arg: &Expr<'_>,
+    msrv: Msrv,
+) {
+    // `pointer::add` and `pointer::wrapping_add` are only stable since 1.26.0. These functions
+    // became const-stable in 1.61.0, the same version that `pointer::offset` became const-stable.
+    if !msrv.meets(cx, msrvs::POINTER_ADD_SUB_METHODS) {
+        return;
+    }
+
+    let method = match method {
+        sym::offset => Method::Offset,
+        sym::wrapping_offset => Method::WrappingOffset,
+        _ => return,
+    };
+
+    if !cx.typeck_results().expr_ty_adjusted(recv).is_raw_ptr() {
+        return;
+    }
+
+    // Check if the argument to the method call is a cast from usize.
+    let cast_lhs_expr = match arg.kind {
+        ExprKind::Cast(lhs, _) if cx.typeck_results().expr_ty(lhs).is_usize() => lhs,
+        _ => return,
+    };
+
+    let ExprKind::MethodCall(method_name, _, _, _) = expr.kind else {
+        return;
+    };
+
+    let msg = format!("use of `{method}` with a `usize` casted to an `isize`");
+    span_lint_and_then(cx, PTR_OFFSET_WITH_CAST, expr.span, msg, |diag| {
+        diag.multipart_suggestion(
+            format!("use `{}` instead", method.suggestion()),
+            vec![
+                (method_name.ident.span, method.suggestion().to_string()),
+                (arg.span.with_lo(cast_lhs_expr.span.hi()), String::new()),
+            ],
+            Applicability::MachineApplicable,
+        );
+    });
+}
+
+#[derive(Copy, Clone)]
+enum Method {
+    Offset,
+    WrappingOffset,
+}
+
+impl Method {
+    #[must_use]
+    fn suggestion(self) -> &'static str {
+        match self {
+            Self::Offset => "add",
+            Self::WrappingOffset => "wrapping_add",
+        }
+    }
+}
+
+impl fmt::Display for Method {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        match self {
+            Self::Offset => write!(f, "offset"),
+            Self::WrappingOffset => write!(f, "wrapping_offset"),
+        }
+    }
+}
diff --git a/src/tools/clippy/clippy_lints/src/methods/unnecessary_to_owned.rs b/src/tools/clippy/clippy_lints/src/methods/unnecessary_to_owned.rs
index c1f4904af7c..640931a8289 100644
--- a/src/tools/clippy/clippy_lints/src/methods/unnecessary_to_owned.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/unnecessary_to_owned.rs
@@ -3,11 +3,12 @@ use super::unnecessary_iter_cloned::{self, is_into_iter};
 use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_and_then};
 use clippy_utils::msrvs::{self, Msrv};
 use clippy_utils::source::{SpanRangeExt, snippet};
-use clippy_utils::ty::{get_iterator_item_ty, implements_trait, is_copy, is_type_diagnostic_item, is_type_lang_item};
+use clippy_utils::ty::{
+    get_iterator_item_ty, implements_trait, is_copy, is_type_diagnostic_item, is_type_lang_item, peel_and_count_ty_refs,
+};
 use clippy_utils::visitors::find_all_ret_expressions;
 use clippy_utils::{
-    fn_def_id, get_parent_expr, is_diag_item_method, is_diag_trait_item, is_expr_temporary_value, peel_middle_ty_refs,
-    return_ty, sym,
+    fn_def_id, get_parent_expr, is_diag_item_method, is_diag_trait_item, is_expr_temporary_value, return_ty, sym,
 };
 use rustc_errors::Applicability;
 use rustc_hir::def::{DefKind, Res};
@@ -119,8 +120,8 @@ fn check_addr_of_expr(
                 },
             ] = adjustments[..]
         && let receiver_ty = cx.typeck_results().expr_ty(receiver)
-        && let (target_ty, n_target_refs) = peel_middle_ty_refs(*target_ty)
-        && let (receiver_ty, n_receiver_refs) = peel_middle_ty_refs(receiver_ty)
+        && let (target_ty, n_target_refs, _) = peel_and_count_ty_refs(*target_ty)
+        && let (receiver_ty, n_receiver_refs, _) = peel_and_count_ty_refs(receiver_ty)
         // Only flag cases satisfying at least one of the following three conditions:
         // * the referent and receiver types are distinct
         // * the referent/receiver type is a copyable array
@@ -385,7 +386,7 @@ fn check_other_call_arg<'tcx>(
         && let fn_sig = cx.tcx.fn_sig(callee_def_id).instantiate_identity().skip_binder()
         && let Some(i) = recv.into_iter().chain(call_args).position(|arg| arg.hir_id == maybe_arg.hir_id)
         && let Some(input) = fn_sig.inputs().get(i)
-        && let (input, n_refs) = peel_middle_ty_refs(*input)
+        && let (input, n_refs, _) = peel_and_count_ty_refs(*input)
         && let (trait_predicates, _) = get_input_traits_and_projections(cx, callee_def_id, input)
         && let Some(sized_def_id) = cx.tcx.lang_items().sized_trait()
         && let Some(meta_sized_def_id) = cx.tcx.lang_items().meta_sized_trait()
diff --git a/src/tools/clippy/clippy_lints/src/methods/useless_asref.rs b/src/tools/clippy/clippy_lints/src/methods/useless_asref.rs
index 38fad239f67..e56f4b80d01 100644
--- a/src/tools/clippy/clippy_lints/src/methods/useless_asref.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/useless_asref.rs
@@ -1,6 +1,6 @@
 use clippy_utils::diagnostics::span_lint_and_sugg;
 use clippy_utils::source::snippet_with_applicability;
-use clippy_utils::ty::{implements_trait, should_call_clone_as_function, walk_ptrs_ty_depth};
+use clippy_utils::ty::{implements_trait, peel_and_count_ty_refs, should_call_clone_as_function};
 use clippy_utils::{get_parent_expr, is_diag_trait_item, path_to_local_id, peel_blocks, strip_pat_refs};
 use rustc_errors::Applicability;
 use rustc_hir::{self as hir, LangItem};
@@ -50,8 +50,8 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, call_name: Symbo
         // check if the type after `as_ref` or `as_mut` is the same as before
         let rcv_ty = cx.typeck_results().expr_ty(recvr);
         let res_ty = cx.typeck_results().expr_ty(expr);
-        let (base_res_ty, res_depth) = walk_ptrs_ty_depth(res_ty);
-        let (base_rcv_ty, rcv_depth) = walk_ptrs_ty_depth(rcv_ty);
+        let (base_res_ty, res_depth, _) = peel_and_count_ty_refs(res_ty);
+        let (base_rcv_ty, rcv_depth, _) = peel_and_count_ty_refs(rcv_ty);
         if base_rcv_ty == base_res_ty && rcv_depth >= res_depth {
             if let Some(parent) = get_parent_expr(cx, expr) {
                 // allow the `as_ref` or `as_mut` if it is followed by another method call
diff --git a/src/tools/clippy/clippy_lints/src/min_ident_chars.rs b/src/tools/clippy/clippy_lints/src/min_ident_chars.rs
index 6258e408217..1ceee836732 100644
--- a/src/tools/clippy/clippy_lints/src/min_ident_chars.rs
+++ b/src/tools/clippy/clippy_lints/src/min_ident_chars.rs
@@ -256,7 +256,11 @@ fn is_not_in_trait_impl(cx: &LateContext<'_>, pat: &Pat<'_>, ident: Ident) -> bo
 }
 
 fn get_param_name(impl_item: &ImplItem<'_>, cx: &LateContext<'_>, ident: Ident) -> Option<Symbol> {
-    if let ImplItemImplKind::Trait { trait_item_def_id: Ok(trait_item_def_id), .. } = impl_item.impl_kind {
+    if let ImplItemImplKind::Trait {
+        trait_item_def_id: Ok(trait_item_def_id),
+        ..
+    } = impl_item.impl_kind
+    {
         let trait_param_names = cx.tcx.fn_arg_idents(trait_item_def_id);
 
         let ImplItemKind::Fn(_, body_id) = impl_item.kind else {
diff --git a/src/tools/clippy/clippy_lints/src/misc.rs b/src/tools/clippy/clippy_lints/src/misc.rs
index 09ee6f7037c..19e9910dfe9 100644
--- a/src/tools/clippy/clippy_lints/src/misc.rs
+++ b/src/tools/clippy/clippy_lints/src/misc.rs
@@ -1,57 +1,11 @@
-use clippy_utils::diagnostics::{span_lint_and_then, span_lint_hir, span_lint_hir_and_then};
-use clippy_utils::source::{snippet, snippet_with_context};
+use clippy_utils::diagnostics::{span_lint_and_then, span_lint_hir_and_then};
 use clippy_utils::sugg::Sugg;
-use clippy_utils::{
-    SpanlessEq, fulfill_or_allowed, get_parent_expr, in_automatically_derived, is_lint_allowed, iter_input_pats,
-    last_path_segment,
-};
+use clippy_utils::{SpanlessEq, fulfill_or_allowed, get_parent_expr, in_automatically_derived, last_path_segment};
 use rustc_errors::Applicability;
 use rustc_hir::def::Res;
-use rustc_hir::intravisit::FnKind;
-use rustc_hir::{
-    BinOpKind, BindingMode, Body, ByRef, Expr, ExprKind, FnDecl, Mutability, PatKind, QPath, Stmt, StmtKind,
-};
+use rustc_hir::{BinOpKind, Expr, ExprKind, QPath, Stmt, StmtKind};
 use rustc_lint::{LateContext, LateLintPass, LintContext};
 use rustc_session::declare_lint_pass;
-use rustc_span::Span;
-use rustc_span::def_id::LocalDefId;
-
-use crate::ref_patterns::REF_PATTERNS;
-
-declare_clippy_lint! {
-    /// ### What it does
-    /// Checks for function arguments and let bindings denoted as
-    /// `ref`.
-    ///
-    /// ### Why is this bad?
-    /// The `ref` declaration makes the function take an owned
-    /// value, but turns the argument into a reference (which means that the value
-    /// is destroyed when exiting the function). This adds not much value: either
-    /// take a reference type, or take an owned value and create references in the
-    /// body.
-    ///
-    /// For let bindings, `let x = &foo;` is preferred over `let ref x = foo`. The
-    /// type of `x` is more obvious with the former.
-    ///
-    /// ### Known problems
-    /// If the argument is dereferenced within the function,
-    /// removing the `ref` will lead to errors. This can be fixed by removing the
-    /// dereferences, e.g., changing `*x` to `x` within the function.
-    ///
-    /// ### Example
-    /// ```no_run
-    /// fn foo(ref _x: u8) {}
-    /// ```
-    ///
-    /// Use instead:
-    /// ```no_run
-    /// fn foo(_x: &u8) {}
-    /// ```
-    #[clippy::version = "pre 1.29.0"]
-    pub TOPLEVEL_REF_ARG,
-    style,
-    "an entire binding declared as `ref`, in a function argument or a `let` statement"
-}
 
 declare_clippy_lint! {
     /// ### What it does
@@ -140,79 +94,13 @@ declare_clippy_lint! {
 }
 
 declare_lint_pass!(LintPass => [
-    TOPLEVEL_REF_ARG,
     USED_UNDERSCORE_BINDING,
     USED_UNDERSCORE_ITEMS,
     SHORT_CIRCUIT_STATEMENT,
 ]);
 
 impl<'tcx> LateLintPass<'tcx> for LintPass {
-    fn check_fn(
-        &mut self,
-        cx: &LateContext<'tcx>,
-        k: FnKind<'tcx>,
-        decl: &'tcx FnDecl<'_>,
-        body: &'tcx Body<'_>,
-        _: Span,
-        _: LocalDefId,
-    ) {
-        if !matches!(k, FnKind::Closure) {
-            for arg in iter_input_pats(decl, body) {
-                if let PatKind::Binding(BindingMode(ByRef::Yes(_), _), ..) = arg.pat.kind
-                    && is_lint_allowed(cx, REF_PATTERNS, arg.pat.hir_id)
-                    && !arg.span.in_external_macro(cx.tcx.sess.source_map())
-                {
-                    span_lint_hir(
-                        cx,
-                        TOPLEVEL_REF_ARG,
-                        arg.hir_id,
-                        arg.pat.span,
-                        "`ref` directly on a function parameter does not prevent taking ownership of the passed argument. \
-                        Consider using a reference type instead",
-                    );
-                }
-            }
-        }
-    }
-
     fn check_stmt(&mut self, cx: &LateContext<'tcx>, stmt: &'tcx Stmt<'_>) {
-        if let StmtKind::Let(local) = stmt.kind
-            && let PatKind::Binding(BindingMode(ByRef::Yes(mutabl), _), .., name, None) = local.pat.kind
-            && let Some(init) = local.init
-            // Do not emit if clippy::ref_patterns is not allowed to avoid having two lints for the same issue.
-            && is_lint_allowed(cx, REF_PATTERNS, local.pat.hir_id)
-            && !stmt.span.in_external_macro(cx.tcx.sess.source_map())
-        {
-            let ctxt = local.span.ctxt();
-            let mut app = Applicability::MachineApplicable;
-            let sugg_init = Sugg::hir_with_context(cx, init, ctxt, "..", &mut app);
-            let (mutopt, initref) = if mutabl == Mutability::Mut {
-                ("mut ", sugg_init.mut_addr())
-            } else {
-                ("", sugg_init.addr())
-            };
-            let tyopt = if let Some(ty) = local.ty {
-                let ty_snip = snippet_with_context(cx, ty.span, ctxt, "_", &mut app).0;
-                format!(": &{mutopt}{ty_snip}")
-            } else {
-                String::new()
-            };
-            span_lint_hir_and_then(
-                cx,
-                TOPLEVEL_REF_ARG,
-                init.hir_id,
-                local.pat.span,
-                "`ref` on an entire `let` pattern is discouraged, take a reference with `&` instead",
-                |diag| {
-                    diag.span_suggestion(
-                        stmt.span,
-                        "try",
-                        format!("let {name}{tyopt} = {initref};", name = snippet(cx, name.span, ".."),),
-                        app,
-                    );
-                },
-            );
-        }
         if let StmtKind::Semi(expr) = stmt.kind
             && let ExprKind::Binary(binop, a, b) = &expr.kind
             && matches!(binop.node, BinOpKind::And | BinOpKind::Or)
diff --git a/src/tools/clippy/clippy_lints/src/missing_doc.rs b/src/tools/clippy/clippy_lints/src/missing_doc.rs
index 39b5964bd87..1c62caa1c82 100644
--- a/src/tools/clippy/clippy_lints/src/missing_doc.rs
+++ b/src/tools/clippy/clippy_lints/src/missing_doc.rs
@@ -250,7 +250,7 @@ impl<'tcx> LateLintPass<'tcx> for MissingDoc {
             AssocContainer::Trait | AssocContainer::TraitImpl(_) => {
                 note_prev_span_then_ret!(self.prev_span, impl_item.span);
             },
-            AssocContainer::InherentImpl => {}
+            AssocContainer::InherentImpl => {},
         }
 
         let (article, desc) = cx.tcx.article_and_description(impl_item.owner_id.to_def_id());
diff --git a/src/tools/clippy/clippy_lints/src/multiple_unsafe_ops_per_block.rs b/src/tools/clippy/clippy_lints/src/multiple_unsafe_ops_per_block.rs
index c6c27e22b90..bc5e72270f4 100644
--- a/src/tools/clippy/clippy_lints/src/multiple_unsafe_ops_per_block.rs
+++ b/src/tools/clippy/clippy_lints/src/multiple_unsafe_ops_per_block.rs
@@ -1,3 +1,4 @@
+use clippy_utils::desugar_await;
 use clippy_utils::diagnostics::span_lint_and_then;
 use clippy_utils::visitors::{Descend, Visitable, for_each_expr};
 use core::ops::ControlFlow::Continue;
@@ -97,6 +98,13 @@ fn collect_unsafe_exprs<'tcx>(
 ) {
     for_each_expr(cx, node, |expr| {
         match expr.kind {
+            // The `await` itself will desugar to two unsafe calls, but we should ignore those.
+            // Instead, check the expression that is `await`ed
+            _ if let Some(e) = desugar_await(expr) => {
+                collect_unsafe_exprs(cx, e, unsafe_ops);
+                return Continue(Descend::No);
+            },
+
             ExprKind::InlineAsm(_) => unsafe_ops.push(("inline assembly used here", expr.span)),
 
             ExprKind::Field(e, _) => {
diff --git a/src/tools/clippy/clippy_lints/src/only_used_in_recursion.rs b/src/tools/clippy/clippy_lints/src/only_used_in_recursion.rs
index c4cad592e36..a21c361356e 100644
--- a/src/tools/clippy/clippy_lints/src/only_used_in_recursion.rs
+++ b/src/tools/clippy/clippy_lints/src/only_used_in_recursion.rs
@@ -252,7 +252,9 @@ impl<'tcx> LateLintPass<'tcx> for OnlyUsedInRecursion {
                 {
                     (
                         trait_item_id,
-                        FnKind::ImplTraitFn(std::ptr::from_ref(cx.tcx.erase_and_anonymize_regions(trait_ref.args)) as usize),
+                        FnKind::ImplTraitFn(
+                            std::ptr::from_ref(cx.tcx.erase_and_anonymize_regions(trait_ref.args)) as usize
+                        ),
                         usize::from(sig.decl.implicit_self.has_implicit_self()),
                     )
                 } else {
diff --git a/src/tools/clippy/clippy_lints/src/operators/erasing_op.rs b/src/tools/clippy/clippy_lints/src/operators/erasing_op.rs
index e3fc8d8fea7..8f5ee390f72 100644
--- a/src/tools/clippy/clippy_lints/src/operators/erasing_op.rs
+++ b/src/tools/clippy/clippy_lints/src/operators/erasing_op.rs
@@ -1,6 +1,6 @@
 use clippy_utils::consts::{ConstEvalCtxt, Constant};
 use clippy_utils::diagnostics::span_lint;
-use clippy_utils::ty::same_type_and_consts;
+use clippy_utils::ty::same_type_modulo_regions;
 
 use rustc_hir::{BinOpKind, Expr};
 use rustc_lint::LateContext;
@@ -29,7 +29,7 @@ pub(super) fn check<'tcx>(
 fn different_types(tck: &TypeckResults<'_>, input: &Expr<'_>, output: &Expr<'_>) -> bool {
     let input_ty = tck.expr_ty(input).peel_refs();
     let output_ty = tck.expr_ty(output).peel_refs();
-    !same_type_and_consts(input_ty, output_ty)
+    !same_type_modulo_regions(input_ty, output_ty)
 }
 
 fn check_op<'tcx>(
diff --git a/src/tools/clippy/clippy_lints/src/ptr_offset_with_cast.rs b/src/tools/clippy/clippy_lints/src/ptr_offset_with_cast.rs
deleted file mode 100644
index d8d813f9846..00000000000
--- a/src/tools/clippy/clippy_lints/src/ptr_offset_with_cast.rs
+++ /dev/null
@@ -1,151 +0,0 @@
-use clippy_utils::diagnostics::{span_lint, span_lint_and_sugg};
-use clippy_utils::source::SpanRangeExt;
-use clippy_utils::sym;
-use rustc_errors::Applicability;
-use rustc_hir::{Expr, ExprKind};
-use rustc_lint::{LateContext, LateLintPass};
-use rustc_session::declare_lint_pass;
-use std::fmt;
-
-declare_clippy_lint! {
-    /// ### What it does
-    /// Checks for usage of the `offset` pointer method with a `usize` casted to an
-    /// `isize`.
-    ///
-    /// ### Why is this bad?
-    /// If we’re always increasing the pointer address, we can avoid the numeric
-    /// cast by using the `add` method instead.
-    ///
-    /// ### Example
-    /// ```no_run
-    /// let vec = vec![b'a', b'b', b'c'];
-    /// let ptr = vec.as_ptr();
-    /// let offset = 1_usize;
-    ///
-    /// unsafe {
-    ///     ptr.offset(offset as isize);
-    /// }
-    /// ```
-    ///
-    /// Could be written:
-    ///
-    /// ```no_run
-    /// let vec = vec![b'a', b'b', b'c'];
-    /// let ptr = vec.as_ptr();
-    /// let offset = 1_usize;
-    ///
-    /// unsafe {
-    ///     ptr.add(offset);
-    /// }
-    /// ```
-    #[clippy::version = "1.30.0"]
-    pub PTR_OFFSET_WITH_CAST,
-    complexity,
-    "unneeded pointer offset cast"
-}
-
-declare_lint_pass!(PtrOffsetWithCast => [PTR_OFFSET_WITH_CAST]);
-
-impl<'tcx> LateLintPass<'tcx> for PtrOffsetWithCast {
-    fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
-        // Check if the expressions is a ptr.offset or ptr.wrapping_offset method call
-        let Some((receiver_expr, arg_expr, method)) = expr_as_ptr_offset_call(cx, expr) else {
-            return;
-        };
-
-        // Check if the argument to the method call is a cast from usize
-        let Some(cast_lhs_expr) = expr_as_cast_from_usize(cx, arg_expr) else {
-            return;
-        };
-
-        let msg = format!("use of `{method}` with a `usize` casted to an `isize`");
-        if let Some(sugg) = build_suggestion(cx, method, receiver_expr, cast_lhs_expr) {
-            span_lint_and_sugg(
-                cx,
-                PTR_OFFSET_WITH_CAST,
-                expr.span,
-                msg,
-                "try",
-                sugg,
-                Applicability::MachineApplicable,
-            );
-        } else {
-            span_lint(cx, PTR_OFFSET_WITH_CAST, expr.span, msg);
-        }
-    }
-}
-
-// If the given expression is a cast from a usize, return the lhs of the cast
-fn expr_as_cast_from_usize<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) -> Option<&'tcx Expr<'tcx>> {
-    if let ExprKind::Cast(cast_lhs_expr, _) = expr.kind
-        && is_expr_ty_usize(cx, cast_lhs_expr)
-    {
-        return Some(cast_lhs_expr);
-    }
-    None
-}
-
-// If the given expression is a ptr::offset  or ptr::wrapping_offset method call, return the
-// receiver, the arg of the method call, and the method.
-fn expr_as_ptr_offset_call<'tcx>(
-    cx: &LateContext<'tcx>,
-    expr: &'tcx Expr<'_>,
-) -> Option<(&'tcx Expr<'tcx>, &'tcx Expr<'tcx>, Method)> {
-    if let ExprKind::MethodCall(path_segment, arg_0, [arg_1], _) = &expr.kind
-        && is_expr_ty_raw_ptr(cx, arg_0)
-    {
-        if path_segment.ident.name == sym::offset {
-            return Some((arg_0, arg_1, Method::Offset));
-        }
-        if path_segment.ident.name == sym::wrapping_offset {
-            return Some((arg_0, arg_1, Method::WrappingOffset));
-        }
-    }
-    None
-}
-
-// Is the type of the expression a usize?
-fn is_expr_ty_usize(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
-    cx.typeck_results().expr_ty(expr) == cx.tcx.types.usize
-}
-
-// Is the type of the expression a raw pointer?
-fn is_expr_ty_raw_ptr(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
-    cx.typeck_results().expr_ty(expr).is_raw_ptr()
-}
-
-fn build_suggestion(
-    cx: &LateContext<'_>,
-    method: Method,
-    receiver_expr: &Expr<'_>,
-    cast_lhs_expr: &Expr<'_>,
-) -> Option<String> {
-    let receiver = receiver_expr.span.get_source_text(cx)?;
-    let cast_lhs = cast_lhs_expr.span.get_source_text(cx)?;
-    Some(format!("{receiver}.{}({cast_lhs})", method.suggestion()))
-}
-
-#[derive(Copy, Clone)]
-enum Method {
-    Offset,
-    WrappingOffset,
-}
-
-impl Method {
-    #[must_use]
-    fn suggestion(self) -> &'static str {
-        match self {
-            Self::Offset => "add",
-            Self::WrappingOffset => "wrapping_add",
-        }
-    }
-}
-
-impl fmt::Display for Method {
-    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        match self {
-            Self::Offset => write!(f, "offset"),
-            Self::WrappingOffset => write!(f, "wrapping_offset"),
-        }
-    }
-}
diff --git a/src/tools/clippy/clippy_lints/src/question_mark.rs b/src/tools/clippy/clippy_lints/src/question_mark.rs
index de12a25b03d..4aa100a50e0 100644
--- a/src/tools/clippy/clippy_lints/src/question_mark.rs
+++ b/src/tools/clippy/clippy_lints/src/question_mark.rs
@@ -8,9 +8,9 @@ use clippy_utils::source::snippet_with_applicability;
 use clippy_utils::sugg::Sugg;
 use clippy_utils::ty::{implements_trait, is_type_diagnostic_item};
 use clippy_utils::{
-    eq_expr_value, higher, is_else_clause, is_in_const_context, is_lint_allowed, is_path_lang_item, is_res_lang_ctor,
-    pat_and_expr_can_be_question_mark, path_res, path_to_local, path_to_local_id, peel_blocks, peel_blocks_with_stmt,
-    span_contains_cfg, span_contains_comment, sym,
+    eq_expr_value, fn_def_id_with_node_args, higher, is_else_clause, is_in_const_context, is_lint_allowed,
+    is_path_lang_item, is_res_lang_ctor, pat_and_expr_can_be_question_mark, path_res, path_to_local, path_to_local_id,
+    peel_blocks, peel_blocks_with_stmt, span_contains_cfg, span_contains_comment, sym,
 };
 use rustc_errors::Applicability;
 use rustc_hir::LangItem::{self, OptionNone, OptionSome, ResultErr, ResultOk};
@@ -393,8 +393,8 @@ fn check_arm_is_none_or_err<'tcx>(cx: &LateContext<'tcx>, mode: TryMode, arm: &A
                 && let ExprKind::Ret(Some(wrapped_ret_expr)) = arm_body.kind
                 && let ExprKind::Call(ok_ctor, [ret_expr]) = wrapped_ret_expr.kind
                 && is_res_lang_ctor(cx, path_res(cx, ok_ctor), ResultErr)
-                // check `...` is `val` from binding
-                && path_to_local_id(ret_expr, ok_val)
+                // check if `...` is `val` from binding or `val.into()`
+                && is_local_or_local_into(cx, ret_expr, ok_val)
             {
                 true
             } else {
@@ -417,6 +417,17 @@ fn check_arm_is_none_or_err<'tcx>(cx: &LateContext<'tcx>, mode: TryMode, arm: &A
     }
 }
 
+/// Check if `expr` is `val` or `val.into()`
+fn is_local_or_local_into(cx: &LateContext<'_>, expr: &Expr<'_>, val: HirId) -> bool {
+    let is_into_call = fn_def_id_with_node_args(cx, expr)
+        .and_then(|(fn_def_id, _)| cx.tcx.trait_of_assoc(fn_def_id))
+        .is_some_and(|trait_def_id| cx.tcx.is_diagnostic_item(sym::Into, trait_def_id));
+    match expr.kind {
+        ExprKind::MethodCall(_, recv, [], _) | ExprKind::Call(_, [recv]) => is_into_call && path_to_local_id(recv, val),
+        _ => path_to_local_id(expr, val),
+    }
+}
+
 fn check_arms_are_try<'tcx>(cx: &LateContext<'tcx>, mode: TryMode, arm1: &Arm<'tcx>, arm2: &Arm<'tcx>) -> bool {
     (check_arm_is_some_or_ok(cx, mode, arm1) && check_arm_is_none_or_err(cx, mode, arm2))
         || (check_arm_is_some_or_ok(cx, mode, arm2) && check_arm_is_none_or_err(cx, mode, arm1))
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 acd840401c6..b8d4e7c4651 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
@@ -1,6 +1,6 @@
 use clippy_utils::diagnostics::{span_lint_hir, span_lint_hir_and_then};
 use clippy_utils::higher::{VecInitKind, get_vec_init_kind};
-use clippy_utils::source::snippet;
+use clippy_utils::source::{indent_of, snippet};
 use clippy_utils::{get_enclosing_block, sym};
 
 use rustc_errors::Applicability;
@@ -83,10 +83,12 @@ impl<'tcx> LateLintPass<'tcx> for ReadZeroByteVec {
                             expr.span,
                             "reading zero byte data to `Vec`",
                             |diag| {
+                                let span = first_stmt_containing_expr(cx, expr).map_or(expr.span, |stmt| stmt.span);
+                                let indent = indent_of(cx, span).unwrap_or(0);
                                 diag.span_suggestion(
-                                    expr.span,
+                                    span.shrink_to_lo(),
                                     "try",
-                                    format!("{}.resize({len}, 0); {}", ident, snippet(cx, expr.span, "..")),
+                                    format!("{ident}.resize({len}, 0);\n{}", " ".repeat(indent)),
                                     applicability,
                                 );
                             },
@@ -100,14 +102,15 @@ impl<'tcx> LateLintPass<'tcx> for ReadZeroByteVec {
                                 expr.span,
                                 "reading zero byte data to `Vec`",
                                 |diag| {
+                                    let span = first_stmt_containing_expr(cx, expr).map_or(expr.span, |stmt| stmt.span);
+                                    let indent = indent_of(cx, span).unwrap_or(0);
                                     diag.span_suggestion(
-                                        expr.span,
+                                        span.shrink_to_lo(),
                                         "try",
                                         format!(
-                                            "{}.resize({}, 0); {}",
-                                            ident,
+                                            "{ident}.resize({}, 0);\n{}",
                                             snippet(cx, e.span, ".."),
-                                            snippet(cx, expr.span, "..")
+                                            " ".repeat(indent)
                                         ),
                                         applicability,
                                     );
@@ -130,6 +133,16 @@ impl<'tcx> LateLintPass<'tcx> for ReadZeroByteVec {
     }
 }
 
+fn first_stmt_containing_expr<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) -> Option<&'tcx hir::Stmt<'tcx>> {
+    cx.tcx.hir_parent_iter(expr.hir_id).find_map(|(_, node)| {
+        if let hir::Node::Stmt(stmt) = node {
+            Some(stmt)
+        } else {
+            None
+        }
+    })
+}
+
 struct ReadVecVisitor<'tcx> {
     local_id: HirId,
     read_zero_expr: Option<&'tcx Expr<'tcx>>,
diff --git a/src/tools/clippy/clippy_lints/src/redundant_clone.rs b/src/tools/clippy/clippy_lints/src/redundant_clone.rs
index 1d58cdd26d8..de6766cbe94 100644
--- a/src/tools/clippy/clippy_lints/src/redundant_clone.rs
+++ b/src/tools/clippy/clippy_lints/src/redundant_clone.rs
@@ -2,7 +2,7 @@ use clippy_utils::diagnostics::{span_lint_hir, span_lint_hir_and_then};
 use clippy_utils::fn_has_unsatisfiable_preds;
 use clippy_utils::mir::{LocalUsage, PossibleBorrowerMap, visit_local_usage};
 use clippy_utils::source::SpanRangeExt;
-use clippy_utils::ty::{has_drop, is_copy, is_type_lang_item, walk_ptrs_ty_depth};
+use clippy_utils::ty::{has_drop, is_copy, is_type_lang_item, peel_and_count_ty_refs};
 use rustc_errors::Applicability;
 use rustc_hir::intravisit::FnKind;
 use rustc_hir::{Body, FnDecl, LangItem, def_id};
@@ -263,7 +263,7 @@ fn is_call_with_ref_arg<'tcx>(
         && args.len() == 1
         && let mir::Operand::Move(mir::Place { local, .. }) = &args[0].node
         && let ty::FnDef(def_id, _) = *func.ty(mir, cx.tcx).kind()
-        && let (inner_ty, 1) = walk_ptrs_ty_depth(args[0].node.ty(mir, cx.tcx))
+        && let (inner_ty, 1, _) = peel_and_count_ty_refs(args[0].node.ty(mir, cx.tcx))
         && !is_copy(cx, inner_ty)
     {
         Some((def_id, *local, inner_ty, destination.as_local()?))
diff --git a/src/tools/clippy/clippy_lints/src/redundant_slicing.rs b/src/tools/clippy/clippy_lints/src/redundant_slicing.rs
index 324a05cdcc0..a358eff2ce5 100644
--- a/src/tools/clippy/clippy_lints/src/redundant_slicing.rs
+++ b/src/tools/clippy/clippy_lints/src/redundant_slicing.rs
@@ -1,7 +1,7 @@
 use clippy_utils::diagnostics::span_lint_and_then;
+use clippy_utils::get_parent_expr;
 use clippy_utils::source::snippet_with_context;
-use clippy_utils::ty::is_type_lang_item;
-use clippy_utils::{get_parent_expr, peel_middle_ty_refs};
+use clippy_utils::ty::{is_type_lang_item, peel_and_count_ty_refs};
 use rustc_ast::util::parser::ExprPrecedence;
 use rustc_errors::Applicability;
 use rustc_hir::{BorrowKind, Expr, ExprKind, LangItem, Mutability};
@@ -82,8 +82,8 @@ impl<'tcx> LateLintPass<'tcx> for RedundantSlicing {
             && let ExprKind::Index(indexed, range, _) = addressee.kind
             && is_type_lang_item(cx, cx.typeck_results().expr_ty_adjusted(range), LangItem::RangeFull)
         {
-            let (expr_ty, expr_ref_count) = peel_middle_ty_refs(cx.typeck_results().expr_ty(expr));
-            let (indexed_ty, indexed_ref_count) = peel_middle_ty_refs(cx.typeck_results().expr_ty(indexed));
+            let (expr_ty, expr_ref_count, _) = peel_and_count_ty_refs(cx.typeck_results().expr_ty(expr));
+            let (indexed_ty, indexed_ref_count, _) = peel_and_count_ty_refs(cx.typeck_results().expr_ty(indexed));
             let parent_expr = get_parent_expr(cx, expr);
             let needs_parens_for_prefix =
                 parent_expr.is_some_and(|parent| cx.precedence(parent) > ExprPrecedence::Prefix);
diff --git a/src/tools/clippy/clippy_lints/src/returns.rs b/src/tools/clippy/clippy_lints/src/returns.rs
deleted file mode 100644
index e0c93153a77..00000000000
--- a/src/tools/clippy/clippy_lints/src/returns.rs
+++ /dev/null
@@ -1,513 +0,0 @@
-use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_hir_and_then};
-use clippy_utils::source::{SpanRangeExt, snippet_with_context};
-use clippy_utils::sugg::has_enclosing_paren;
-use clippy_utils::visitors::for_each_expr;
-use clippy_utils::{
-    binary_expr_needs_parentheses, fn_def_id, is_from_proc_macro, is_inside_let_else, is_res_lang_ctor,
-    leaks_droppable_temporary_with_limited_lifetime, path_res, path_to_local_id, span_contains_cfg,
-    span_find_starting_semi, sym,
-};
-use core::ops::ControlFlow;
-use rustc_ast::MetaItemInner;
-use rustc_errors::Applicability;
-use rustc_hir::LangItem::ResultErr;
-use rustc_hir::intravisit::FnKind;
-use rustc_hir::{
-    Block, Body, Expr, ExprKind, FnDecl, HirId, ItemKind, LangItem, MatchSource, Node, OwnerNode, PatKind, QPath, Stmt,
-    StmtKind,
-};
-use rustc_lint::{LateContext, LateLintPass, Level, LintContext};
-use rustc_middle::ty::adjustment::Adjust;
-use rustc_middle::ty::{self, GenericArgKind, Ty};
-use rustc_session::declare_lint_pass;
-use rustc_span::def_id::LocalDefId;
-use rustc_span::edition::Edition;
-use rustc_span::{BytePos, Pos, Span};
-use std::borrow::Cow;
-use std::fmt::Display;
-
-declare_clippy_lint! {
-    /// ### What it does
-    /// Checks for `let`-bindings, which are subsequently
-    /// returned.
-    ///
-    /// ### Why is this bad?
-    /// It is just extraneous code. Remove it to make your code
-    /// more rusty.
-    ///
-    /// ### Known problems
-    /// In the case of some temporaries, e.g. locks, eliding the variable binding could lead
-    /// to deadlocks. See [this issue](https://github.com/rust-lang/rust/issues/37612).
-    /// This could become relevant if the code is later changed to use the code that would have been
-    /// bound without first assigning it to a let-binding.
-    ///
-    /// ### Example
-    /// ```no_run
-    /// fn foo() -> String {
-    ///     let x = String::new();
-    ///     x
-    /// }
-    /// ```
-    /// instead, use
-    /// ```no_run
-    /// fn foo() -> String {
-    ///     String::new()
-    /// }
-    /// ```
-    #[clippy::version = "pre 1.29.0"]
-    pub LET_AND_RETURN,
-    style,
-    "creating a let-binding and then immediately returning it like `let x = expr; x` at the end of a block"
-}
-
-declare_clippy_lint! {
-    /// ### What it does
-    /// Checks for return statements at the end of a block.
-    ///
-    /// ### Why is this bad?
-    /// Removing the `return` and semicolon will make the code
-    /// more rusty.
-    ///
-    /// ### Example
-    /// ```no_run
-    /// fn foo(x: usize) -> usize {
-    ///     return x;
-    /// }
-    /// ```
-    /// simplify to
-    /// ```no_run
-    /// fn foo(x: usize) -> usize {
-    ///     x
-    /// }
-    /// ```
-    #[clippy::version = "pre 1.29.0"]
-    pub NEEDLESS_RETURN,
-    // This lint requires some special handling in `check_final_expr` for `#[expect]`.
-    // This handling needs to be updated if the group gets changed. This should also
-    // be caught by tests.
-    style,
-    "using a return statement like `return expr;` where an expression would suffice"
-}
-
-declare_clippy_lint! {
-    /// ### What it does
-    /// Checks for return statements on `Err` paired with the `?` operator.
-    ///
-    /// ### Why is this bad?
-    /// The `return` is unnecessary.
-    ///
-    /// Returns may be used to add attributes to the return expression. Return
-    /// statements with attributes are therefore be accepted by this lint.
-    ///
-    /// ### Example
-    /// ```rust,ignore
-    /// fn foo(x: usize) -> Result<(), Box<dyn Error>> {
-    ///     if x == 0 {
-    ///         return Err(...)?;
-    ///     }
-    ///     Ok(())
-    /// }
-    /// ```
-    /// simplify to
-    /// ```rust,ignore
-    /// fn foo(x: usize) -> Result<(), Box<dyn Error>> {
-    ///     if x == 0 {
-    ///         Err(...)?;
-    ///     }
-    ///     Ok(())
-    /// }
-    /// ```
-    /// if paired with `try_err`, use instead:
-    /// ```rust,ignore
-    /// fn foo(x: usize) -> Result<(), Box<dyn Error>> {
-    ///     if x == 0 {
-    ///         return Err(...);
-    ///     }
-    ///     Ok(())
-    /// }
-    /// ```
-    #[clippy::version = "1.73.0"]
-    pub NEEDLESS_RETURN_WITH_QUESTION_MARK,
-    style,
-    "using a return statement like `return Err(expr)?;` where removing it would suffice"
-}
-
-#[derive(PartialEq, Eq)]
-enum RetReplacement<'tcx> {
-    Empty,
-    Block,
-    Unit,
-    NeedsPar(Cow<'tcx, str>, Applicability),
-    Expr(Cow<'tcx, str>, Applicability),
-}
-
-impl RetReplacement<'_> {
-    fn sugg_help(&self) -> &'static str {
-        match self {
-            Self::Empty | Self::Expr(..) => "remove `return`",
-            Self::Block => "replace `return` with an empty block",
-            Self::Unit => "replace `return` with a unit value",
-            Self::NeedsPar(..) => "remove `return` and wrap the sequence with parentheses",
-        }
-    }
-
-    fn applicability(&self) -> Applicability {
-        match self {
-            Self::Expr(_, ap) | Self::NeedsPar(_, ap) => *ap,
-            _ => Applicability::MachineApplicable,
-        }
-    }
-}
-
-impl Display for RetReplacement<'_> {
-    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
-        match self {
-            Self::Empty => write!(f, ""),
-            Self::Block => write!(f, "{{}}"),
-            Self::Unit => write!(f, "()"),
-            Self::NeedsPar(inner, _) => write!(f, "({inner})"),
-            Self::Expr(inner, _) => write!(f, "{inner}"),
-        }
-    }
-}
-
-declare_lint_pass!(Return => [LET_AND_RETURN, NEEDLESS_RETURN, NEEDLESS_RETURN_WITH_QUESTION_MARK]);
-
-/// Checks if a return statement is "needed" in the middle of a block, or if it can be removed. This
-/// is the case when the enclosing block expression is coerced to some other type, which only works
-/// because of the never-ness of `return` expressions
-fn stmt_needs_never_type(cx: &LateContext<'_>, stmt_hir_id: HirId) -> bool {
-    cx.tcx
-        .hir_parent_iter(stmt_hir_id)
-        .find_map(|(_, node)| if let Node::Expr(expr) = node { Some(expr) } else { None })
-        .is_some_and(|e| {
-            cx.typeck_results()
-                .expr_adjustments(e)
-                .iter()
-                .any(|adjust| adjust.target != cx.tcx.types.unit && matches!(adjust.kind, Adjust::NeverToAny))
-        })
-}
-
-impl<'tcx> LateLintPass<'tcx> for Return {
-    fn check_stmt(&mut self, cx: &LateContext<'tcx>, stmt: &'tcx Stmt<'_>) {
-        if !stmt.span.in_external_macro(cx.sess().source_map())
-            && let StmtKind::Semi(expr) = stmt.kind
-            && let ExprKind::Ret(Some(ret)) = expr.kind
-            // return Err(...)? desugars to a match
-            // over a Err(...).branch()
-            // which breaks down to a branch call, with the callee being
-            // the constructor of the Err variant
-            && let ExprKind::Match(maybe_cons, _, MatchSource::TryDesugar(_)) = ret.kind
-            && let ExprKind::Call(_, [maybe_result_err]) = maybe_cons.kind
-            && let ExprKind::Call(maybe_constr, _) = maybe_result_err.kind
-            && is_res_lang_ctor(cx, path_res(cx, maybe_constr), ResultErr)
-
-            // Ensure this is not the final stmt, otherwise removing it would cause a compile error
-            && let OwnerNode::Item(item) = cx.tcx.hir_owner_node(cx.tcx.hir_get_parent_item(expr.hir_id))
-            && let ItemKind::Fn { body, .. } = item.kind
-            && let block = cx.tcx.hir_body(body).value
-            && let ExprKind::Block(block, _) = block.kind
-            && !is_inside_let_else(cx.tcx, expr)
-            && let [.., final_stmt] = block.stmts
-            && final_stmt.hir_id != stmt.hir_id
-            && !is_from_proc_macro(cx, expr)
-            && !stmt_needs_never_type(cx, stmt.hir_id)
-        {
-            span_lint_and_sugg(
-                cx,
-                NEEDLESS_RETURN_WITH_QUESTION_MARK,
-                expr.span.until(ret.span),
-                "unneeded `return` statement with `?` operator",
-                "remove it",
-                String::new(),
-                Applicability::MachineApplicable,
-            );
-        }
-    }
-
-    fn check_block(&mut self, cx: &LateContext<'tcx>, block: &'tcx Block<'_>) {
-        // we need both a let-binding stmt and an expr
-        if let Some(retexpr) = block.expr
-            && let Some(stmt) = block.stmts.iter().last()
-            && let StmtKind::Let(local) = &stmt.kind
-            && local.ty.is_none()
-            && cx.tcx.hir_attrs(local.hir_id).is_empty()
-            && let Some(initexpr) = &local.init
-            && let PatKind::Binding(_, local_id, _, _) = local.pat.kind
-            && path_to_local_id(retexpr, local_id)
-            && (cx.sess().edition() >= Edition::Edition2024 || !last_statement_borrows(cx, initexpr))
-            && !initexpr.span.in_external_macro(cx.sess().source_map())
-            && !retexpr.span.in_external_macro(cx.sess().source_map())
-            && !local.span.from_expansion()
-            && !span_contains_cfg(cx, stmt.span.between(retexpr.span))
-        {
-            span_lint_hir_and_then(
-                cx,
-                LET_AND_RETURN,
-                retexpr.hir_id,
-                retexpr.span,
-                "returning the result of a `let` binding from a block",
-                |err| {
-                    err.span_label(local.span, "unnecessary `let` binding");
-
-                    if let Some(src) = initexpr.span.get_source_text(cx) {
-                        let sugg = if binary_expr_needs_parentheses(initexpr) {
-                            if has_enclosing_paren(&src) {
-                                src.to_owned()
-                            } else {
-                                format!("({src})")
-                            }
-                        } else if !cx.typeck_results().expr_adjustments(retexpr).is_empty() {
-                            if has_enclosing_paren(&src) {
-                                format!("{src} as _")
-                            } else {
-                                format!("({src}) as _")
-                            }
-                        } else {
-                            src.to_owned()
-                        };
-                        err.multipart_suggestion(
-                            "return the expression directly",
-                            vec![(local.span, String::new()), (retexpr.span, sugg)],
-                            Applicability::MachineApplicable,
-                        );
-                    } else {
-                        err.span_help(initexpr.span, "this expression can be directly returned");
-                    }
-                },
-            );
-        }
-    }
-
-    fn check_fn(
-        &mut self,
-        cx: &LateContext<'tcx>,
-        kind: FnKind<'tcx>,
-        _: &'tcx FnDecl<'tcx>,
-        body: &'tcx Body<'tcx>,
-        sp: Span,
-        _: LocalDefId,
-    ) {
-        if sp.from_expansion() {
-            return;
-        }
-
-        match kind {
-            FnKind::Closure => {
-                // when returning without value in closure, replace this `return`
-                // with an empty block to prevent invalid suggestion (see #6501)
-                let replacement = if let ExprKind::Ret(None) = &body.value.kind {
-                    RetReplacement::Block
-                } else {
-                    RetReplacement::Empty
-                };
-                check_final_expr(cx, body.value, vec![], replacement, None);
-            },
-            FnKind::ItemFn(..) | FnKind::Method(..) => {
-                check_block_return(cx, &body.value.kind, sp, vec![]);
-            },
-        }
-    }
-}
-
-// if `expr` is a block, check if there are needless returns in it
-fn check_block_return<'tcx>(cx: &LateContext<'tcx>, expr_kind: &ExprKind<'tcx>, sp: Span, mut semi_spans: Vec<Span>) {
-    if let ExprKind::Block(block, _) = expr_kind {
-        if let Some(block_expr) = block.expr {
-            check_final_expr(cx, block_expr, semi_spans, RetReplacement::Empty, None);
-        } else if let Some(stmt) = block.stmts.iter().last() {
-            match stmt.kind {
-                StmtKind::Expr(expr) => {
-                    check_final_expr(cx, expr, semi_spans, RetReplacement::Empty, None);
-                },
-                StmtKind::Semi(semi_expr) => {
-                    // Remove ending semicolons and any whitespace ' ' in between.
-                    // Without `return`, the suggestion might not compile if the semicolon is retained
-                    if let Some(semi_span) = stmt.span.trim_start(semi_expr.span) {
-                        let semi_span_to_remove =
-                            span_find_starting_semi(cx.sess().source_map(), semi_span.with_hi(sp.hi()));
-                        semi_spans.push(semi_span_to_remove);
-                    }
-                    check_final_expr(cx, semi_expr, semi_spans, RetReplacement::Empty, None);
-                },
-                _ => (),
-            }
-        }
-    }
-}
-
-fn check_final_expr<'tcx>(
-    cx: &LateContext<'tcx>,
-    expr: &'tcx Expr<'tcx>,
-    semi_spans: Vec<Span>, /* containing all the places where we would need to remove semicolons if finding an
-                            * needless return */
-    replacement: RetReplacement<'tcx>,
-    match_ty_opt: Option<Ty<'_>>,
-) {
-    let peeled_drop_expr = expr.peel_drop_temps();
-    match &peeled_drop_expr.kind {
-        // simple return is always "bad"
-        ExprKind::Ret(inner) => {
-            // check if expr return nothing
-            let ret_span = if inner.is_none() && replacement == RetReplacement::Empty {
-                extend_span_to_previous_non_ws(cx, peeled_drop_expr.span)
-            } else {
-                peeled_drop_expr.span
-            };
-
-            let replacement = if let Some(inner_expr) = inner {
-                // if desugar of `do yeet`, don't lint
-                if let ExprKind::Call(path_expr, [_]) = inner_expr.kind
-                    && let ExprKind::Path(QPath::LangItem(LangItem::TryTraitFromYeet, ..)) = path_expr.kind
-                {
-                    return;
-                }
-
-                let mut applicability = Applicability::MachineApplicable;
-                let (snippet, _) = snippet_with_context(cx, inner_expr.span, ret_span.ctxt(), "..", &mut applicability);
-                if binary_expr_needs_parentheses(inner_expr) {
-                    RetReplacement::NeedsPar(snippet, applicability)
-                } else {
-                    RetReplacement::Expr(snippet, applicability)
-                }
-            } else {
-                match match_ty_opt {
-                    Some(match_ty) => {
-                        match match_ty.kind() {
-                            // If the code got till here with
-                            // tuple not getting detected before it,
-                            // then we are sure it's going to be Unit
-                            // type
-                            ty::Tuple(_) => RetReplacement::Unit,
-                            // We don't want to anything in this case
-                            // cause we can't predict what the user would
-                            // want here
-                            _ => return,
-                        }
-                    },
-                    None => replacement,
-                }
-            };
-
-            if inner.is_some_and(|inner| leaks_droppable_temporary_with_limited_lifetime(cx, inner)) {
-                return;
-            }
-
-            if ret_span.from_expansion() || is_from_proc_macro(cx, expr) {
-                return;
-            }
-
-            // Returns may be used to turn an expression into a statement in rustc's AST.
-            // This allows the addition of attributes, like `#[allow]` (See: clippy#9361)
-            // `#[expect(clippy::needless_return)]` needs to be handled separately to
-            // actually fulfill the expectation (clippy::#12998)
-            match cx.tcx.hir_attrs(expr.hir_id) {
-                [] => {},
-                [attr] => {
-                    if matches!(Level::from_attr(attr), Some((Level::Expect, _)))
-                        && let metas = attr.meta_item_list()
-                        && let Some(lst) = metas
-                        && let [MetaItemInner::MetaItem(meta_item), ..] = lst.as_slice()
-                        && let [tool, lint_name] = meta_item.path.segments.as_slice()
-                        && tool.ident.name == sym::clippy
-                        && matches!(
-                            lint_name.ident.name,
-                            sym::needless_return | sym::style | sym::all | sym::warnings
-                        )
-                    {
-                        // This is an expectation of the `needless_return` lint
-                    } else {
-                        return;
-                    }
-                },
-                _ => return,
-            }
-
-            emit_return_lint(
-                cx,
-                peeled_drop_expr.span,
-                ret_span,
-                semi_spans,
-                &replacement,
-                expr.hir_id,
-            );
-        },
-        ExprKind::If(_, then, else_clause_opt) => {
-            check_block_return(cx, &then.kind, peeled_drop_expr.span, semi_spans.clone());
-            if let Some(else_clause) = else_clause_opt {
-                // The `RetReplacement` won't be used there as `else_clause` will be either a block or
-                // a `if` expression.
-                check_final_expr(cx, else_clause, semi_spans, RetReplacement::Empty, match_ty_opt);
-            }
-        },
-        // a match expr, check all arms
-        // an if/if let expr, check both exprs
-        // note, if without else is going to be a type checking error anyways
-        // (except for unit type functions) so we don't match it
-        ExprKind::Match(_, arms, MatchSource::Normal) => {
-            let match_ty = cx.typeck_results().expr_ty(peeled_drop_expr);
-            for arm in *arms {
-                check_final_expr(cx, arm.body, semi_spans.clone(), RetReplacement::Unit, Some(match_ty));
-            }
-        },
-        // if it's a whole block, check it
-        other_expr_kind => check_block_return(cx, other_expr_kind, peeled_drop_expr.span, semi_spans),
-    }
-}
-
-fn emit_return_lint(
-    cx: &LateContext<'_>,
-    lint_span: Span,
-    ret_span: Span,
-    semi_spans: Vec<Span>,
-    replacement: &RetReplacement<'_>,
-    at: HirId,
-) {
-    span_lint_hir_and_then(
-        cx,
-        NEEDLESS_RETURN,
-        at,
-        lint_span,
-        "unneeded `return` statement",
-        |diag| {
-            let suggestions = std::iter::once((ret_span, replacement.to_string()))
-                .chain(semi_spans.into_iter().map(|span| (span, String::new())))
-                .collect();
-
-            diag.multipart_suggestion_verbose(replacement.sugg_help(), suggestions, replacement.applicability());
-        },
-    );
-}
-
-fn last_statement_borrows<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) -> bool {
-    for_each_expr(cx, expr, |e| {
-        if let Some(def_id) = fn_def_id(cx, e)
-            && cx
-                .tcx
-                .fn_sig(def_id)
-                .instantiate_identity()
-                .skip_binder()
-                .output()
-                .walk()
-                .any(|arg| matches!(arg.kind(), GenericArgKind::Lifetime(re) if !re.is_static()))
-        {
-            ControlFlow::Break(())
-        } else {
-            ControlFlow::Continue(())
-        }
-    })
-    .is_some()
-}
-
-// Go backwards while encountering whitespace and extend the given Span to that point.
-fn extend_span_to_previous_non_ws(cx: &LateContext<'_>, sp: Span) -> Span {
-    if let Ok(prev_source) = cx.sess().source_map().span_to_prev_source(sp) {
-        let ws = [b' ', b'\t', b'\n'];
-        if let Some(non_ws_pos) = prev_source.bytes().rposition(|c| !ws.contains(&c)) {
-            let len = prev_source.len() - non_ws_pos - 1;
-            return sp.with_lo(sp.lo() - BytePos::from_usize(len));
-        }
-    }
-
-    sp
-}
diff --git a/src/tools/clippy/clippy_lints/src/returns/let_and_return.rs b/src/tools/clippy/clippy_lints/src/returns/let_and_return.rs
new file mode 100644
index 00000000000..e2002fb36e5
--- /dev/null
+++ b/src/tools/clippy/clippy_lints/src/returns/let_and_return.rs
@@ -0,0 +1,86 @@
+use clippy_utils::diagnostics::span_lint_hir_and_then;
+use clippy_utils::source::SpanRangeExt;
+use clippy_utils::sugg::has_enclosing_paren;
+use clippy_utils::visitors::for_each_expr;
+use clippy_utils::{binary_expr_needs_parentheses, fn_def_id, path_to_local_id, span_contains_cfg};
+use core::ops::ControlFlow;
+use rustc_errors::Applicability;
+use rustc_hir::{Block, Expr, PatKind, StmtKind};
+use rustc_lint::{LateContext, LintContext};
+use rustc_middle::ty::GenericArgKind;
+use rustc_span::edition::Edition;
+
+use super::LET_AND_RETURN;
+
+pub(super) fn check_block<'tcx>(cx: &LateContext<'tcx>, block: &'tcx Block<'_>) {
+    // we need both a let-binding stmt and an expr
+    if let Some(retexpr) = block.expr
+        && let Some(stmt) = block.stmts.last()
+        && let StmtKind::Let(local) = &stmt.kind
+        && local.ty.is_none()
+        && cx.tcx.hir_attrs(local.hir_id).is_empty()
+        && let Some(initexpr) = &local.init
+        && let PatKind::Binding(_, local_id, _, _) = local.pat.kind
+        && path_to_local_id(retexpr, local_id)
+        && (cx.sess().edition() >= Edition::Edition2024 || !last_statement_borrows(cx, initexpr))
+        && !initexpr.span.in_external_macro(cx.sess().source_map())
+        && !retexpr.span.in_external_macro(cx.sess().source_map())
+        && !local.span.from_expansion()
+        && !span_contains_cfg(cx, stmt.span.between(retexpr.span))
+    {
+        span_lint_hir_and_then(
+            cx,
+            LET_AND_RETURN,
+            retexpr.hir_id,
+            retexpr.span,
+            "returning the result of a `let` binding from a block",
+            |err| {
+                err.span_label(local.span, "unnecessary `let` binding");
+
+                if let Some(src) = initexpr.span.get_source_text(cx) {
+                    let sugg = if binary_expr_needs_parentheses(initexpr) {
+                        if has_enclosing_paren(&src) {
+                            src.to_owned()
+                        } else {
+                            format!("({src})")
+                        }
+                    } else if !cx.typeck_results().expr_adjustments(retexpr).is_empty() {
+                        if has_enclosing_paren(&src) {
+                            format!("{src} as _")
+                        } else {
+                            format!("({src}) as _")
+                        }
+                    } else {
+                        src.to_owned()
+                    };
+                    err.multipart_suggestion(
+                        "return the expression directly",
+                        vec![(local.span, String::new()), (retexpr.span, sugg)],
+                        Applicability::MachineApplicable,
+                    );
+                } else {
+                    err.span_help(initexpr.span, "this expression can be directly returned");
+                }
+            },
+        );
+    }
+}
+fn last_statement_borrows<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) -> bool {
+    for_each_expr(cx, expr, |e| {
+        if let Some(def_id) = fn_def_id(cx, e)
+            && cx
+                .tcx
+                .fn_sig(def_id)
+                .instantiate_identity()
+                .skip_binder()
+                .output()
+                .walk()
+                .any(|arg| matches!(arg.kind(), GenericArgKind::Lifetime(re) if !re.is_static()))
+        {
+            ControlFlow::Break(())
+        } else {
+            ControlFlow::Continue(())
+        }
+    })
+    .is_some()
+}
diff --git a/src/tools/clippy/clippy_lints/src/returns/mod.rs b/src/tools/clippy/clippy_lints/src/returns/mod.rs
new file mode 100644
index 00000000000..47c6332b9b8
--- /dev/null
+++ b/src/tools/clippy/clippy_lints/src/returns/mod.rs
@@ -0,0 +1,140 @@
+use rustc_hir::intravisit::FnKind;
+use rustc_hir::{Block, Body, FnDecl, Stmt};
+use rustc_lint::{LateContext, LateLintPass};
+use rustc_session::declare_lint_pass;
+use rustc_span::Span;
+use rustc_span::def_id::LocalDefId;
+
+mod let_and_return;
+mod needless_return;
+mod needless_return_with_question_mark;
+
+declare_clippy_lint! {
+    /// ### What it does
+    /// Checks for `let`-bindings, which are subsequently
+    /// returned.
+    ///
+    /// ### Why is this bad?
+    /// It is just extraneous code. Remove it to make your code
+    /// more rusty.
+    ///
+    /// ### Known problems
+    /// In the case of some temporaries, e.g. locks, eliding the variable binding could lead
+    /// to deadlocks. See [this issue](https://github.com/rust-lang/rust/issues/37612).
+    /// This could become relevant if the code is later changed to use the code that would have been
+    /// bound without first assigning it to a let-binding.
+    ///
+    /// ### Example
+    /// ```no_run
+    /// fn foo() -> String {
+    ///     let x = String::new();
+    ///     x
+    /// }
+    /// ```
+    /// instead, use
+    /// ```no_run
+    /// fn foo() -> String {
+    ///     String::new()
+    /// }
+    /// ```
+    #[clippy::version = "pre 1.29.0"]
+    pub LET_AND_RETURN,
+    style,
+    "creating a let-binding and then immediately returning it like `let x = expr; x` at the end of a block"
+}
+
+declare_clippy_lint! {
+    /// ### What it does
+    /// Checks for return statements at the end of a block.
+    ///
+    /// ### Why is this bad?
+    /// Removing the `return` and semicolon will make the code
+    /// more rusty.
+    ///
+    /// ### Example
+    /// ```no_run
+    /// fn foo(x: usize) -> usize {
+    ///     return x;
+    /// }
+    /// ```
+    /// simplify to
+    /// ```no_run
+    /// fn foo(x: usize) -> usize {
+    ///     x
+    /// }
+    /// ```
+    #[clippy::version = "pre 1.29.0"]
+    pub NEEDLESS_RETURN,
+    // This lint requires some special handling in `check_final_expr` for `#[expect]`.
+    // This handling needs to be updated if the group gets changed. This should also
+    // be caught by tests.
+    style,
+    "using a return statement like `return expr;` where an expression would suffice"
+}
+
+declare_clippy_lint! {
+    /// ### What it does
+    /// Checks for return statements on `Err` paired with the `?` operator.
+    ///
+    /// ### Why is this bad?
+    /// The `return` is unnecessary.
+    ///
+    /// Returns may be used to add attributes to the return expression. Return
+    /// statements with attributes are therefore be accepted by this lint.
+    ///
+    /// ### Example
+    /// ```rust,ignore
+    /// fn foo(x: usize) -> Result<(), Box<dyn Error>> {
+    ///     if x == 0 {
+    ///         return Err(...)?;
+    ///     }
+    ///     Ok(())
+    /// }
+    /// ```
+    /// simplify to
+    /// ```rust,ignore
+    /// fn foo(x: usize) -> Result<(), Box<dyn Error>> {
+    ///     if x == 0 {
+    ///         Err(...)?;
+    ///     }
+    ///     Ok(())
+    /// }
+    /// ```
+    /// if paired with `try_err`, use instead:
+    /// ```rust,ignore
+    /// fn foo(x: usize) -> Result<(), Box<dyn Error>> {
+    ///     if x == 0 {
+    ///         return Err(...);
+    ///     }
+    ///     Ok(())
+    /// }
+    /// ```
+    #[clippy::version = "1.73.0"]
+    pub NEEDLESS_RETURN_WITH_QUESTION_MARK,
+    style,
+    "using a return statement like `return Err(expr)?;` where removing it would suffice"
+}
+
+declare_lint_pass!(Return => [LET_AND_RETURN, NEEDLESS_RETURN, NEEDLESS_RETURN_WITH_QUESTION_MARK]);
+
+impl<'tcx> LateLintPass<'tcx> for Return {
+    fn check_stmt(&mut self, cx: &LateContext<'tcx>, stmt: &'tcx Stmt<'_>) {
+        needless_return_with_question_mark::check_stmt(cx, stmt);
+    }
+
+    fn check_block(&mut self, cx: &LateContext<'tcx>, block: &'tcx Block<'_>) {
+        let_and_return::check_block(cx, block);
+    }
+
+    fn check_fn(
+        &mut self,
+        cx: &LateContext<'tcx>,
+        kind: FnKind<'tcx>,
+        _: &'tcx FnDecl<'tcx>,
+        body: &'tcx Body<'tcx>,
+        sp: Span,
+        _: LocalDefId,
+    ) {
+        needless_return::check_fn(cx, kind, body, sp);
+    }
+}
diff --git a/src/tools/clippy/clippy_lints/src/returns/needless_return.rs b/src/tools/clippy/clippy_lints/src/returns/needless_return.rs
new file mode 100644
index 00000000000..04739fc1b22
--- /dev/null
+++ b/src/tools/clippy/clippy_lints/src/returns/needless_return.rs
@@ -0,0 +1,269 @@
+use clippy_utils::diagnostics::span_lint_hir_and_then;
+use clippy_utils::source::snippet_with_context;
+use clippy_utils::{
+    binary_expr_needs_parentheses, is_from_proc_macro, leaks_droppable_temporary_with_limited_lifetime,
+    span_contains_cfg, span_find_starting_semi, sym,
+};
+use rustc_ast::MetaItemInner;
+use rustc_errors::Applicability;
+use rustc_hir::intravisit::FnKind;
+use rustc_hir::{Body, Expr, ExprKind, HirId, LangItem, MatchSource, QPath, StmtKind};
+use rustc_lint::{LateContext, Level, LintContext};
+use rustc_middle::ty::{self, Ty};
+use rustc_span::{BytePos, Pos, Span};
+use std::borrow::Cow;
+use std::fmt::Display;
+
+use super::NEEDLESS_RETURN;
+
+#[derive(PartialEq, Eq)]
+enum RetReplacement<'tcx> {
+    Empty,
+    Block,
+    Unit,
+    NeedsPar(Cow<'tcx, str>, Applicability),
+    Expr(Cow<'tcx, str>, Applicability),
+}
+
+impl RetReplacement<'_> {
+    fn sugg_help(&self) -> &'static str {
+        match self {
+            Self::Empty | Self::Expr(..) => "remove `return`",
+            Self::Block => "replace `return` with an empty block",
+            Self::Unit => "replace `return` with a unit value",
+            Self::NeedsPar(..) => "remove `return` and wrap the sequence with parentheses",
+        }
+    }
+
+    fn applicability(&self) -> Applicability {
+        match self {
+            Self::Expr(_, ap) | Self::NeedsPar(_, ap) => *ap,
+            _ => Applicability::MachineApplicable,
+        }
+    }
+}
+
+impl Display for RetReplacement<'_> {
+    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+        match self {
+            Self::Empty => f.write_str(""),
+            Self::Block => f.write_str("{}"),
+            Self::Unit => f.write_str("()"),
+            Self::NeedsPar(inner, _) => write!(f, "({inner})"),
+            Self::Expr(inner, _) => write!(f, "{inner}"),
+        }
+    }
+}
+
+pub(super) fn check_fn<'tcx>(cx: &LateContext<'tcx>, kind: FnKind<'tcx>, body: &'tcx Body<'tcx>, sp: Span) {
+    if sp.from_expansion() {
+        return;
+    }
+
+    match kind {
+        FnKind::Closure => {
+            // when returning without value in closure, replace this `return`
+            // with an empty block to prevent invalid suggestion (see #6501)
+            let replacement = if let ExprKind::Ret(None) = &body.value.kind {
+                RetReplacement::Block
+            } else {
+                RetReplacement::Empty
+            };
+            check_final_expr(cx, body.value, vec![], replacement, None);
+        },
+        FnKind::ItemFn(..) | FnKind::Method(..) => {
+            check_block_return(cx, &body.value.kind, sp, vec![]);
+        },
+    }
+}
+
+// if `expr` is a block, check if there are needless returns in it
+fn check_block_return<'tcx>(cx: &LateContext<'tcx>, expr_kind: &ExprKind<'tcx>, sp: Span, mut semi_spans: Vec<Span>) {
+    if let ExprKind::Block(block, _) = expr_kind {
+        if let Some(block_expr) = block.expr {
+            check_final_expr(cx, block_expr, semi_spans, RetReplacement::Empty, None);
+        } else if let Some(stmt) = block.stmts.last() {
+            if span_contains_cfg(
+                cx,
+                Span::between(
+                    stmt.span,
+                    cx.sess().source_map().end_point(block.span), // the closing brace of the block
+                ),
+            ) {
+                return;
+            }
+            match stmt.kind {
+                StmtKind::Expr(expr) => {
+                    check_final_expr(cx, expr, semi_spans, RetReplacement::Empty, None);
+                },
+                StmtKind::Semi(semi_expr) => {
+                    // Remove ending semicolons and any whitespace ' ' in between.
+                    // Without `return`, the suggestion might not compile if the semicolon is retained
+                    if let Some(semi_span) = stmt.span.trim_start(semi_expr.span) {
+                        let semi_span_to_remove =
+                            span_find_starting_semi(cx.sess().source_map(), semi_span.with_hi(sp.hi()));
+                        semi_spans.push(semi_span_to_remove);
+                    }
+                    check_final_expr(cx, semi_expr, semi_spans, RetReplacement::Empty, None);
+                },
+                _ => (),
+            }
+        }
+    }
+}
+
+fn check_final_expr<'tcx>(
+    cx: &LateContext<'tcx>,
+    expr: &'tcx Expr<'tcx>,
+    semi_spans: Vec<Span>, /* containing all the places where we would need to remove semicolons if finding an
+                            * needless return */
+    replacement: RetReplacement<'tcx>,
+    match_ty_opt: Option<Ty<'_>>,
+) {
+    let peeled_drop_expr = expr.peel_drop_temps();
+    match &peeled_drop_expr.kind {
+        // simple return is always "bad"
+        ExprKind::Ret(inner) => {
+            // check if expr return nothing
+            let ret_span = if inner.is_none() && replacement == RetReplacement::Empty {
+                extend_span_to_previous_non_ws(cx, peeled_drop_expr.span)
+            } else {
+                peeled_drop_expr.span
+            };
+
+            let replacement = if let Some(inner_expr) = inner {
+                // if desugar of `do yeet`, don't lint
+                if let ExprKind::Call(path_expr, [_]) = inner_expr.kind
+                    && let ExprKind::Path(QPath::LangItem(LangItem::TryTraitFromYeet, ..)) = path_expr.kind
+                {
+                    return;
+                }
+
+                let mut applicability = Applicability::MachineApplicable;
+                let (snippet, _) = snippet_with_context(cx, inner_expr.span, ret_span.ctxt(), "..", &mut applicability);
+                if binary_expr_needs_parentheses(inner_expr) {
+                    RetReplacement::NeedsPar(snippet, applicability)
+                } else {
+                    RetReplacement::Expr(snippet, applicability)
+                }
+            } else {
+                match match_ty_opt {
+                    Some(match_ty) => {
+                        match match_ty.kind() {
+                            // If the code got till here with
+                            // tuple not getting detected before it,
+                            // then we are sure it's going to be Unit
+                            // type
+                            ty::Tuple(_) => RetReplacement::Unit,
+                            // We don't want to anything in this case
+                            // cause we can't predict what the user would
+                            // want here
+                            _ => return,
+                        }
+                    },
+                    None => replacement,
+                }
+            };
+
+            if inner.is_some_and(|inner| leaks_droppable_temporary_with_limited_lifetime(cx, inner)) {
+                return;
+            }
+
+            if ret_span.from_expansion() || is_from_proc_macro(cx, expr) {
+                return;
+            }
+
+            // Returns may be used to turn an expression into a statement in rustc's AST.
+            // This allows the addition of attributes, like `#[allow]` (See: clippy#9361)
+            // `#[expect(clippy::needless_return)]` needs to be handled separately to
+            // actually fulfill the expectation (clippy::#12998)
+            match cx.tcx.hir_attrs(expr.hir_id) {
+                [] => {},
+                [attr] => {
+                    if matches!(Level::from_attr(attr), Some((Level::Expect, _)))
+                        && let metas = attr.meta_item_list()
+                        && let Some(lst) = metas
+                        && let [MetaItemInner::MetaItem(meta_item), ..] = lst.as_slice()
+                        && let [tool, lint_name] = meta_item.path.segments.as_slice()
+                        && tool.ident.name == sym::clippy
+                        && matches!(
+                            lint_name.ident.name,
+                            sym::needless_return | sym::style | sym::all | sym::warnings
+                        )
+                    {
+                        // This is an expectation of the `needless_return` lint
+                    } else {
+                        return;
+                    }
+                },
+                _ => return,
+            }
+
+            emit_return_lint(
+                cx,
+                peeled_drop_expr.span,
+                ret_span,
+                semi_spans,
+                &replacement,
+                expr.hir_id,
+            );
+        },
+        ExprKind::If(_, then, else_clause_opt) => {
+            check_block_return(cx, &then.kind, peeled_drop_expr.span, semi_spans.clone());
+            if let Some(else_clause) = else_clause_opt {
+                // The `RetReplacement` won't be used there as `else_clause` will be either a block or
+                // a `if` expression.
+                check_final_expr(cx, else_clause, semi_spans, RetReplacement::Empty, match_ty_opt);
+            }
+        },
+        // a match expr, check all arms
+        // an if/if let expr, check both exprs
+        // note, if without else is going to be a type checking error anyways
+        // (except for unit type functions) so we don't match it
+        ExprKind::Match(_, arms, MatchSource::Normal) => {
+            let match_ty = cx.typeck_results().expr_ty(peeled_drop_expr);
+            for arm in *arms {
+                check_final_expr(cx, arm.body, semi_spans.clone(), RetReplacement::Unit, Some(match_ty));
+            }
+        },
+        // if it's a whole block, check it
+        other_expr_kind => check_block_return(cx, other_expr_kind, peeled_drop_expr.span, semi_spans),
+    }
+}
+
+fn emit_return_lint(
+    cx: &LateContext<'_>,
+    lint_span: Span,
+    ret_span: Span,
+    semi_spans: Vec<Span>,
+    replacement: &RetReplacement<'_>,
+    at: HirId,
+) {
+    span_lint_hir_and_then(
+        cx,
+        NEEDLESS_RETURN,
+        at,
+        lint_span,
+        "unneeded `return` statement",
+        |diag| {
+            let suggestions = std::iter::once((ret_span, replacement.to_string()))
+                .chain(semi_spans.into_iter().map(|span| (span, String::new())))
+                .collect();
+
+            diag.multipart_suggestion_verbose(replacement.sugg_help(), suggestions, replacement.applicability());
+        },
+    );
+}
+
+// Go backwards while encountering whitespace and extend the given Span to that point.
+fn extend_span_to_previous_non_ws(cx: &LateContext<'_>, sp: Span) -> Span {
+    if let Ok(prev_source) = cx.sess().source_map().span_to_prev_source(sp) {
+        let ws = [b' ', b'\t', b'\n'];
+        if let Some(non_ws_pos) = prev_source.bytes().rposition(|c| !ws.contains(&c)) {
+            let len = prev_source.len() - non_ws_pos - 1;
+            return sp.with_lo(sp.lo() - BytePos::from_usize(len));
+        }
+    }
+
+    sp
+}
diff --git a/src/tools/clippy/clippy_lints/src/returns/needless_return_with_question_mark.rs b/src/tools/clippy/clippy_lints/src/returns/needless_return_with_question_mark.rs
new file mode 100644
index 00000000000..c05038cd1e5
--- /dev/null
+++ b/src/tools/clippy/clippy_lints/src/returns/needless_return_with_question_mark.rs
@@ -0,0 +1,60 @@
+use clippy_utils::diagnostics::span_lint_and_sugg;
+use clippy_utils::{is_from_proc_macro, is_inside_let_else, is_res_lang_ctor, path_res};
+use rustc_errors::Applicability;
+use rustc_hir::LangItem::ResultErr;
+use rustc_hir::{ExprKind, HirId, ItemKind, MatchSource, Node, OwnerNode, Stmt, StmtKind};
+use rustc_lint::{LateContext, LintContext};
+use rustc_middle::ty::adjustment::Adjust;
+
+use super::NEEDLESS_RETURN_WITH_QUESTION_MARK;
+
+pub(super) fn check_stmt<'tcx>(cx: &LateContext<'tcx>, stmt: &'tcx Stmt<'_>) {
+    if !stmt.span.in_external_macro(cx.sess().source_map())
+        && let StmtKind::Semi(expr) = stmt.kind
+        && let ExprKind::Ret(Some(ret)) = expr.kind
+        // return Err(...)? desugars to a match
+        // over a Err(...).branch()
+        // which breaks down to a branch call, with the callee being
+        // the constructor of the Err variant
+        && let ExprKind::Match(maybe_cons, _, MatchSource::TryDesugar(_)) = ret.kind
+        && let ExprKind::Call(_, [maybe_result_err]) = maybe_cons.kind
+        && let ExprKind::Call(maybe_constr, _) = maybe_result_err.kind
+        && is_res_lang_ctor(cx, path_res(cx, maybe_constr), ResultErr)
+
+        // Ensure this is not the final stmt, otherwise removing it would cause a compile error
+        && let OwnerNode::Item(item) = cx.tcx.hir_owner_node(cx.tcx.hir_get_parent_item(expr.hir_id))
+        && let ItemKind::Fn { body, .. } = item.kind
+        && let block = cx.tcx.hir_body(body).value
+        && let ExprKind::Block(block, _) = block.kind
+        && !is_inside_let_else(cx.tcx, expr)
+        && let [.., final_stmt] = block.stmts
+        && final_stmt.hir_id != stmt.hir_id
+        && !is_from_proc_macro(cx, expr)
+        && !stmt_needs_never_type(cx, stmt.hir_id)
+    {
+        span_lint_and_sugg(
+            cx,
+            NEEDLESS_RETURN_WITH_QUESTION_MARK,
+            expr.span.until(ret.span),
+            "unneeded `return` statement with `?` operator",
+            "remove it",
+            String::new(),
+            Applicability::MachineApplicable,
+        );
+    }
+}
+
+/// Checks if a return statement is "needed" in the middle of a block, or if it can be removed.
+/// This is the case when the enclosing block expression is coerced to some other type,
+/// which only works because of the never-ness of `return` expressions
+fn stmt_needs_never_type(cx: &LateContext<'_>, stmt_hir_id: HirId) -> bool {
+    cx.tcx
+        .hir_parent_iter(stmt_hir_id)
+        .find_map(|(_, node)| if let Node::Expr(expr) = node { Some(expr) } else { None })
+        .is_some_and(|e| {
+            cx.typeck_results()
+                .expr_adjustments(e)
+                .iter()
+                .any(|adjust| adjust.target != cx.tcx.types.unit && matches!(adjust.kind, Adjust::NeverToAny))
+        })
+}
diff --git a/src/tools/clippy/clippy_lints/src/semicolon_block.rs b/src/tools/clippy/clippy_lints/src/semicolon_block.rs
index 1dea8f17c34..371d62a0684 100644
--- a/src/tools/clippy/clippy_lints/src/semicolon_block.rs
+++ b/src/tools/clippy/clippy_lints/src/semicolon_block.rs
@@ -1,5 +1,6 @@
 use clippy_config::Conf;
 use clippy_utils::diagnostics::span_lint_and_then;
+use clippy_utils::source::SpanRangeExt;
 use rustc_errors::Applicability;
 use rustc_hir::{Block, Expr, ExprKind, Stmt, StmtKind};
 use rustc_lint::{LateContext, LateLintPass, LintContext};
@@ -82,6 +83,19 @@ impl SemicolonBlock {
         let insert_span = tail.span.source_callsite().shrink_to_hi();
         let remove_span = semi_span.with_lo(block.span.hi());
 
+        // If the block is surrounded by parens (`({ 0 });`), the author probably knows what
+        // they're doing and why, so don't get in their way.
+        //
+        // This has the additional benefit of stopping the block being parsed as a function call:
+        // ```
+        // fn foo() {
+        //     ({ 0 }); // if we remove this `;`, this will parse as a `({ 0 })(5);` function call
+        //     (5);
+        // }
+        if remove_span.check_source_text(cx, |src| src.contains(')')) {
+            return;
+        }
+
         if self.semicolon_inside_block_ignore_singleline && get_line(cx, remove_span) == get_line(cx, insert_span) {
             return;
         }
diff --git a/src/tools/clippy/clippy_lints/src/size_of_ref.rs b/src/tools/clippy/clippy_lints/src/size_of_ref.rs
index 60d923bcd77..606e852aae9 100644
--- a/src/tools/clippy/clippy_lints/src/size_of_ref.rs
+++ b/src/tools/clippy/clippy_lints/src/size_of_ref.rs
@@ -1,5 +1,6 @@
 use clippy_utils::diagnostics::span_lint_and_help;
-use clippy_utils::{path_def_id, peel_middle_ty_refs};
+use clippy_utils::path_def_id;
+use clippy_utils::ty::peel_and_count_ty_refs;
 use rustc_hir::{Expr, ExprKind};
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_session::declare_lint_pass;
@@ -59,7 +60,7 @@ impl LateLintPass<'_> for SizeOfRef {
             && let Some(def_id) = path_def_id(cx, path)
             && cx.tcx.is_diagnostic_item(sym::mem_size_of_val, def_id)
             && let arg_ty = cx.typeck_results().expr_ty(arg)
-            && peel_middle_ty_refs(arg_ty).1 > 1
+            && peel_and_count_ty_refs(arg_ty).1 > 1
         {
             span_lint_and_help(
                 cx,
diff --git a/src/tools/clippy/clippy_lints/src/toplevel_ref_arg.rs b/src/tools/clippy/clippy_lints/src/toplevel_ref_arg.rs
new file mode 100644
index 00000000000..074b79263d3
--- /dev/null
+++ b/src/tools/clippy/clippy_lints/src/toplevel_ref_arg.rs
@@ -0,0 +1,119 @@
+use clippy_utils::diagnostics::{span_lint_hir, span_lint_hir_and_then};
+use clippy_utils::source::{snippet, snippet_with_context};
+use clippy_utils::sugg::Sugg;
+use clippy_utils::{is_lint_allowed, iter_input_pats};
+use rustc_errors::Applicability;
+use rustc_hir::intravisit::FnKind;
+use rustc_hir::{BindingMode, Body, ByRef, FnDecl, Mutability, PatKind, Stmt, StmtKind};
+use rustc_lint::{LateContext, LateLintPass};
+use rustc_session::declare_lint_pass;
+use rustc_span::Span;
+use rustc_span::def_id::LocalDefId;
+
+use crate::ref_patterns::REF_PATTERNS;
+
+declare_clippy_lint! {
+    /// ### What it does
+    /// Checks for function arguments and let bindings denoted as
+    /// `ref`.
+    ///
+    /// ### Why is this bad?
+    /// The `ref` declaration makes the function take an owned
+    /// value, but turns the argument into a reference (which means that the value
+    /// is destroyed when exiting the function). This adds not much value: either
+    /// take a reference type, or take an owned value and create references in the
+    /// body.
+    ///
+    /// For let bindings, `let x = &foo;` is preferred over `let ref x = foo`. The
+    /// type of `x` is more obvious with the former.
+    ///
+    /// ### Known problems
+    /// If the argument is dereferenced within the function,
+    /// removing the `ref` will lead to errors. This can be fixed by removing the
+    /// dereferences, e.g., changing `*x` to `x` within the function.
+    ///
+    /// ### Example
+    /// ```no_run
+    /// fn foo(ref _x: u8) {}
+    /// ```
+    ///
+    /// Use instead:
+    /// ```no_run
+    /// fn foo(_x: &u8) {}
+    /// ```
+    #[clippy::version = "pre 1.29.0"]
+    pub TOPLEVEL_REF_ARG,
+    style,
+    "an entire binding declared as `ref`, in a function argument or a `let` statement"
+}
+
+declare_lint_pass!(ToplevelRefArg => [TOPLEVEL_REF_ARG]);
+
+impl<'tcx> LateLintPass<'tcx> for ToplevelRefArg {
+    fn check_fn(
+        &mut self,
+        cx: &LateContext<'tcx>,
+        k: FnKind<'tcx>,
+        decl: &'tcx FnDecl<'_>,
+        body: &'tcx Body<'_>,
+        _: Span,
+        _: LocalDefId,
+    ) {
+        if !matches!(k, FnKind::Closure) {
+            for arg in iter_input_pats(decl, body) {
+                if let PatKind::Binding(BindingMode(ByRef::Yes(_), _), ..) = arg.pat.kind
+                    && is_lint_allowed(cx, REF_PATTERNS, arg.pat.hir_id)
+                    && !arg.span.in_external_macro(cx.tcx.sess.source_map())
+                {
+                    span_lint_hir(
+                        cx,
+                        TOPLEVEL_REF_ARG,
+                        arg.hir_id,
+                        arg.pat.span,
+                        "`ref` directly on a function parameter does not prevent taking ownership of the passed argument. \
+                            Consider using a reference type instead",
+                    );
+                }
+            }
+        }
+    }
+
+    fn check_stmt(&mut self, cx: &LateContext<'tcx>, stmt: &'tcx Stmt<'_>) {
+        if let StmtKind::Let(local) = stmt.kind
+            && let PatKind::Binding(BindingMode(ByRef::Yes(mutabl), _), .., name, None) = local.pat.kind
+            && let Some(init) = local.init
+            // Do not emit if clippy::ref_patterns is not allowed to avoid having two lints for the same issue.
+            && is_lint_allowed(cx, REF_PATTERNS, local.pat.hir_id)
+            && !stmt.span.in_external_macro(cx.tcx.sess.source_map())
+        {
+            let ctxt = local.span.ctxt();
+            let mut app = Applicability::MachineApplicable;
+            let sugg_init = Sugg::hir_with_context(cx, init, ctxt, "..", &mut app);
+            let (mutopt, initref) = match mutabl {
+                Mutability::Mut => ("mut ", sugg_init.mut_addr()),
+                Mutability::Not => ("", sugg_init.addr()),
+            };
+            let tyopt = if let Some(ty) = local.ty {
+                let ty_snip = snippet_with_context(cx, ty.span, ctxt, "_", &mut app).0;
+                format!(": &{mutopt}{ty_snip}")
+            } else {
+                String::new()
+            };
+            span_lint_hir_and_then(
+                cx,
+                TOPLEVEL_REF_ARG,
+                init.hir_id,
+                local.pat.span,
+                "`ref` on an entire `let` pattern is discouraged, take a reference with `&` instead",
+                |diag| {
+                    diag.span_suggestion(
+                        stmt.span,
+                        "try",
+                        format!("let {name}{tyopt} = {initref};", name = snippet(cx, name.span, ".."),),
+                        app,
+                    );
+                },
+            );
+        }
+    }
+}
diff --git a/src/tools/clippy/clippy_lints/src/transmute/transmute_ptr_to_ref.rs b/src/tools/clippy/clippy_lints/src/transmute/transmute_ptr_to_ref.rs
index e58212fae15..e67ab6a73d2 100644
--- a/src/tools/clippy/clippy_lints/src/transmute/transmute_ptr_to_ref.rs
+++ b/src/tools/clippy/clippy_lints/src/transmute/transmute_ptr_to_ref.rs
@@ -28,16 +28,27 @@ pub(super) fn check<'tcx>(
                 format!("transmute from a pointer type (`{from_ty}`) to a reference type (`{to_ty}`)"),
                 |diag| {
                     let arg = sugg::Sugg::hir(cx, arg, "..");
-                    let (deref, cast) = if *mutbl == Mutability::Mut {
-                        ("&mut *", "*mut")
-                    } else {
-                        ("&*", "*const")
+                    let (deref, cast) = match mutbl {
+                        Mutability::Mut => ("&mut *", "*mut"),
+                        Mutability::Not => ("&*", "*const"),
                     };
                     let mut app = Applicability::MachineApplicable;
 
                     let sugg = if let Some(ty) = get_explicit_type(path) {
                         let ty_snip = snippet_with_applicability(cx, ty.span, "..", &mut app);
-                        if msrv.meets(cx, msrvs::POINTER_CAST) {
+                        if !to_ref_ty.is_sized(cx.tcx, cx.typing_env()) {
+                            // We can't suggest `.cast()`, because that requires `to_ref_ty` to be Sized.
+                            if from_ptr_ty.has_erased_regions() {
+                                // We can't suggest `as *mut/const () as *mut/const to_ref_ty`, because the former is a
+                                // thin pointer, whereas the latter is a wide pointer, due of its pointee, `to_ref_ty`,
+                                // being !Sized.
+                                //
+                                // The only remaining option is be to skip `*mut/const ()`, but that might not be safe
+                                // to do because of the erased regions in `from_ptr_ty`, so reduce the applicability.
+                                app = Applicability::MaybeIncorrect;
+                            }
+                            sugg::make_unop(deref, arg.as_ty(format!("{cast} {ty_snip}"))).to_string()
+                        } else if msrv.meets(cx, msrvs::POINTER_CAST) {
                             format!("{deref}{}.cast::<{ty_snip}>()", arg.maybe_paren())
                         } else if from_ptr_ty.has_erased_regions() {
                             sugg::make_unop(deref, arg.as_ty(format!("{cast} () as {cast} {ty_snip}"))).to_string()
@@ -45,15 +56,22 @@ pub(super) fn check<'tcx>(
                             sugg::make_unop(deref, arg.as_ty(format!("{cast} {ty_snip}"))).to_string()
                         }
                     } else if *from_ptr_ty == *to_ref_ty {
-                        if from_ptr_ty.has_erased_regions() {
-                            if msrv.meets(cx, msrvs::POINTER_CAST) {
-                                format!("{deref}{}.cast::<{to_ref_ty}>()", arg.maybe_paren())
-                            } else {
-                                sugg::make_unop(deref, arg.as_ty(format!("{cast} () as {cast} {to_ref_ty}")))
-                                    .to_string()
-                            }
-                        } else {
+                        if !from_ptr_ty.has_erased_regions() {
                             sugg::make_unop(deref, arg).to_string()
+                        } else if !to_ref_ty.is_sized(cx.tcx, cx.typing_env()) {
+                            // 1. We can't suggest `.cast()`, because that requires `to_ref_ty` to be Sized.
+                            // 2. We can't suggest `as *mut/const () as *mut/const to_ref_ty`, because the former is a
+                            //    thin pointer, whereas the latter is a wide pointer, due of its pointee, `to_ref_ty`,
+                            //    being !Sized.
+                            //
+                            // The only remaining option is be to skip `*mut/const ()`, but that might not be safe to do
+                            // because of the erased regions in `from_ptr_ty`, so reduce the applicability.
+                            app = Applicability::MaybeIncorrect;
+                            sugg::make_unop(deref, arg.as_ty(format!("{cast} {to_ref_ty}"))).to_string()
+                        } else if msrv.meets(cx, msrvs::POINTER_CAST) {
+                            format!("{deref}{}.cast::<{to_ref_ty}>()", arg.maybe_paren())
+                        } else {
+                            sugg::make_unop(deref, arg.as_ty(format!("{cast} () as {cast} {to_ref_ty}"))).to_string()
                         }
                     } else {
                         sugg::make_unop(deref, arg.as_ty(format!("{cast} {to_ref_ty}"))).to_string()
diff --git a/src/tools/clippy/clippy_lints/src/transmute/transmute_ref_to_ref.rs b/src/tools/clippy/clippy_lints/src/transmute/transmute_ref_to_ref.rs
index 6aeb22d41a7..70c2a73ce6e 100644
--- a/src/tools/clippy/clippy_lints/src/transmute/transmute_ref_to_ref.rs
+++ b/src/tools/clippy/clippy_lints/src/transmute/transmute_ref_to_ref.rs
@@ -45,7 +45,9 @@ pub(super) fn check<'tcx>(
                 Applicability::MaybeIncorrect,
             );
             triggered = true;
-        } else if (cx.tcx.erase_and_anonymize_regions(from_ty) != cx.tcx.erase_and_anonymize_regions(to_ty)) && !const_context {
+        } else if (cx.tcx.erase_and_anonymize_regions(from_ty) != cx.tcx.erase_and_anonymize_regions(to_ty))
+            && !const_context
+        {
             span_lint_and_then(
                 cx,
                 TRANSMUTE_PTR_TO_PTR,
diff --git a/src/tools/clippy/clippy_lints/src/uninit_vec.rs b/src/tools/clippy/clippy_lints/src/uninit_vec.rs
index cee4a53f03c..51116b5eba9 100644
--- a/src/tools/clippy/clippy_lints/src/uninit_vec.rs
+++ b/src/tools/clippy/clippy_lints/src/uninit_vec.rs
@@ -1,4 +1,4 @@
-use clippy_utils::diagnostics::{span_lint, span_lint_and_then};
+use clippy_utils::diagnostics::{span_lint, span_lint_and_help};
 use clippy_utils::higher::{VecInitKind, get_vec_init_kind};
 use clippy_utils::ty::{is_type_diagnostic_item, is_uninit_value_valid_for_ty};
 use clippy_utils::{SpanlessEq, is_integer_literal, is_lint_allowed, path_to_local_id, peel_hir_expr_while, sym};
@@ -95,16 +95,13 @@ fn handle_uninit_vec_pair<'tcx>(
 
             // Check T of Vec<T>
             if !is_uninit_value_valid_for_ty(cx, args.type_at(0)) {
-                // FIXME: #7698, false positive of the internal lints
-                #[expect(clippy::collapsible_span_lint_calls)]
-                span_lint_and_then(
+                span_lint_and_help(
                     cx,
                     UNINIT_VEC,
                     vec![call_span, maybe_init_or_reserve.span],
                     "calling `set_len()` immediately after reserving a buffer creates uninitialized values",
-                    |diag| {
-                        diag.help("initialize the buffer or wrap the content in `MaybeUninit`");
-                    },
+                    None,
+                    "initialize the buffer or wrap the content in `MaybeUninit`",
                 );
             }
         } else {
diff --git a/src/tools/clippy/clippy_lints/src/unused_peekable.rs b/src/tools/clippy/clippy_lints/src/unused_peekable.rs
index 1f5351e32aa..5224b62e9fc 100644
--- a/src/tools/clippy/clippy_lints/src/unused_peekable.rs
+++ b/src/tools/clippy/clippy_lints/src/unused_peekable.rs
@@ -1,5 +1,5 @@
 use clippy_utils::diagnostics::span_lint_hir_and_then;
-use clippy_utils::ty::{is_type_diagnostic_item, peel_mid_ty_refs_is_mutable};
+use clippy_utils::ty::{is_type_diagnostic_item, peel_and_count_ty_refs};
 use clippy_utils::{fn_def_id, is_trait_method, path_to_local_id, peel_ref_operators, sym};
 use rustc_ast::Mutability;
 use rustc_hir::intravisit::{Visitor, walk_expr};
@@ -61,7 +61,7 @@ impl<'tcx> LateLintPass<'tcx> for UnusedPeekable {
                 && let Some(init) = local.init
                 && !init.span.from_expansion()
                 && let Some(ty) = cx.typeck_results().expr_ty_opt(init)
-                && let (ty, _, Mutability::Mut) = peel_mid_ty_refs_is_mutable(ty)
+                && let (ty, _, None | Some(Mutability::Mut)) = peel_and_count_ty_refs(ty)
                 && is_type_diagnostic_item(cx, ty, sym::IterPeekable)
             {
                 let mut vis = PeekableVisitor::new(cx, binding);
@@ -211,7 +211,7 @@ impl<'tcx> Visitor<'tcx> for PeekableVisitor<'_, 'tcx> {
 
 fn arg_is_mut_peekable(cx: &LateContext<'_>, arg: &Expr<'_>) -> bool {
     if let Some(ty) = cx.typeck_results().expr_ty_opt(arg)
-        && let (ty, _, Mutability::Mut) = peel_mid_ty_refs_is_mutable(ty)
+        && let (ty, _, None | Some(Mutability::Mut)) = peel_and_count_ty_refs(ty)
         && is_type_diagnostic_item(cx, ty, sym::IterPeekable)
     {
         true
diff --git a/src/tools/clippy/clippy_lints/src/unwrap.rs b/src/tools/clippy/clippy_lints/src/unwrap.rs
index 490da4f1e03..34dfe5b6546 100644
--- a/src/tools/clippy/clippy_lints/src/unwrap.rs
+++ b/src/tools/clippy/clippy_lints/src/unwrap.rs
@@ -292,6 +292,7 @@ impl<'tcx> Visitor<'tcx> for UnwrappableVariablesVisitor<'_, 'tcx> {
     fn visit_expr(&mut self, expr: &'tcx Expr<'_>) {
         // Shouldn't lint when `expr` is in macro.
         if expr.span.in_external_macro(self.cx.tcx.sess.source_map()) {
+            walk_expr(self, expr);
             return;
         }
         // Skip checking inside closures since they are visited through `Unwrap::check_fn()` already.
diff --git a/src/tools/clippy/clippy_lints/src/use_self.rs b/src/tools/clippy/clippy_lints/src/use_self.rs
index 8252e6d4869..9d5be922f43 100644
--- a/src/tools/clippy/clippy_lints/src/use_self.rs
+++ b/src/tools/clippy/clippy_lints/src/use_self.rs
@@ -2,20 +2,21 @@ use clippy_config::Conf;
 use clippy_utils::diagnostics::span_lint_and_sugg;
 use clippy_utils::is_from_proc_macro;
 use clippy_utils::msrvs::{self, Msrv};
-use clippy_utils::ty::{same_type_and_consts, ty_from_hir_ty};
+use clippy_utils::ty::{same_type_modulo_regions, ty_from_hir_ty};
 use rustc_data_structures::fx::FxHashSet;
 use rustc_errors::Applicability;
 use rustc_hir::def::{CtorOf, DefKind, Res};
 use rustc_hir::def_id::LocalDefId;
 use rustc_hir::intravisit::{InferKind, Visitor, VisitorExt, walk_ty};
 use rustc_hir::{
-    self as hir, AmbigArg, Expr, ExprKind, FnRetTy, FnSig, GenericArgsParentheses, GenericParam, GenericParamKind,
-    HirId, Impl, ImplItemKind, Item, ItemKind, Pat, PatExpr, PatExprKind, PatKind, Path, QPath, Ty, TyKind,
+    self as hir, AmbigArg, Expr, ExprKind, FnRetTy, FnSig, GenericArgsParentheses, GenericParamKind, HirId, Impl,
+    ImplItemKind, Item, ItemKind, Pat, PatExpr, PatExprKind, PatKind, Path, QPath, Ty, TyKind,
 };
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_middle::ty::Ty as MiddleTy;
 use rustc_session::impl_lint_pass;
 use rustc_span::Span;
+use std::iter;
 
 declare_clippy_lint! {
     /// ### What it does
@@ -101,17 +102,11 @@ impl<'tcx> LateLintPass<'tcx> for UseSelf {
             let types_to_skip = generics
                 .params
                 .iter()
-                .filter_map(|param| match param {
-                    GenericParam {
-                        kind:
-                            GenericParamKind::Const {
-                                ty: Ty { hir_id, .. }, ..
-                            },
-                        ..
-                    } => Some(*hir_id),
+                .filter_map(|param| match param.kind {
+                    GenericParamKind::Const { ty, .. } => Some(ty.hir_id),
                     _ => None,
                 })
-                .chain(std::iter::once(self_ty.hir_id))
+                .chain([self_ty.hir_id])
                 .collect();
             StackItem::Check {
                 impl_id: item.owner_id.def_id,
@@ -209,11 +204,11 @@ impl<'tcx> LateLintPass<'tcx> for UseSelf {
             && !types_to_skip.contains(&hir_ty.hir_id)
             && let ty = ty_from_hir_ty(cx, hir_ty.as_unambig_ty())
             && let impl_ty = cx.tcx.type_of(impl_id).instantiate_identity()
-            && same_type_and_consts(ty, impl_ty)
+            && same_type_modulo_regions(ty, impl_ty)
             // Ensure the type we encounter and the one from the impl have the same lifetime parameters. It may be that
-            // the lifetime parameters of `ty` are elided (`impl<'a> Foo<'a> { fn new() -> Self { Foo{..} } }`, in
+            // the lifetime parameters of `ty` are elided (`impl<'a> Foo<'a> { fn new() -> Self { Foo{..} } }`), in
             // which case we must still trigger the lint.
-            && (has_no_lifetime(ty) || same_lifetimes(ty, impl_ty))
+            && same_lifetimes(ty, impl_ty)
             && self.msrv.meets(cx, msrvs::TYPE_ALIAS_ENUM_VARIANTS)
         {
             span_lint(cx, hir_ty.span);
@@ -226,18 +221,16 @@ impl<'tcx> LateLintPass<'tcx> for UseSelf {
             && cx.typeck_results().expr_ty(expr) == cx.tcx.type_of(impl_id).instantiate_identity()
             && self.msrv.meets(cx, msrvs::TYPE_ALIAS_ENUM_VARIANTS)
         {
-        } else {
-            return;
-        }
-        match expr.kind {
-            ExprKind::Struct(QPath::Resolved(_, path), ..) => check_path(cx, path),
-            ExprKind::Call(fun, _) => {
-                if let ExprKind::Path(QPath::Resolved(_, path)) = fun.kind {
-                    check_path(cx, path);
-                }
-            },
-            ExprKind::Path(QPath::Resolved(_, path)) => check_path(cx, path),
-            _ => (),
+            match expr.kind {
+                ExprKind::Struct(QPath::Resolved(_, path), ..) => check_path(cx, path),
+                ExprKind::Call(fun, _) => {
+                    if let ExprKind::Path(QPath::Resolved(_, path)) = fun.kind {
+                        check_path(cx, path);
+                    }
+                },
+                ExprKind::Path(QPath::Resolved(_, path)) => check_path(cx, path),
+                _ => (),
+            }
         }
     }
 
@@ -307,36 +300,20 @@ fn lint_path_to_variant(cx: &LateContext<'_>, path: &Path<'_>) {
     }
 }
 
-/// Returns `true` if types `a` and `b` have the same lifetime parameters, otherwise returns
-/// `false`.
+/// Checks whether types `a` and `b` have the same lifetime parameters.
 ///
 /// This function does not check that types `a` and `b` are the same types.
 fn same_lifetimes<'tcx>(a: MiddleTy<'tcx>, b: MiddleTy<'tcx>) -> bool {
     use rustc_middle::ty::{Adt, GenericArgKind};
-    match (&a.kind(), &b.kind()) {
-        (&Adt(_, args_a), &Adt(_, args_b)) => {
-            args_a
-                .iter()
-                .zip(args_b.iter())
-                .all(|(arg_a, arg_b)| match (arg_a.kind(), arg_b.kind()) {
-                    // TODO: Handle inferred lifetimes
-                    (GenericArgKind::Lifetime(inner_a), GenericArgKind::Lifetime(inner_b)) => inner_a == inner_b,
-                    (GenericArgKind::Type(type_a), GenericArgKind::Type(type_b)) => same_lifetimes(type_a, type_b),
-                    _ => true,
-                })
+    match (a.kind(), b.kind()) {
+        (Adt(_, args_a), Adt(_, args_b)) => {
+            iter::zip(*args_a, *args_b).all(|(arg_a, arg_b)| match (arg_a.kind(), arg_b.kind()) {
+                // TODO: Handle inferred lifetimes
+                (GenericArgKind::Lifetime(inner_a), GenericArgKind::Lifetime(inner_b)) => inner_a == inner_b,
+                (GenericArgKind::Type(type_a), GenericArgKind::Type(type_b)) => same_lifetimes(type_a, type_b),
+                _ => true,
+            })
         },
         _ => a == b,
     }
 }
-
-/// Returns `true` if `ty` has no lifetime parameter, otherwise returns `false`.
-fn has_no_lifetime(ty: MiddleTy<'_>) -> bool {
-    use rustc_middle::ty::{Adt, GenericArgKind};
-    match ty.kind() {
-        &Adt(_, args) => !args
-            .iter()
-            // TODO: Handle inferred lifetimes
-            .any(|arg| matches!(arg.kind(), GenericArgKind::Lifetime(..))),
-        _ => true,
-    }
-}
diff --git a/src/tools/clippy/clippy_lints/src/useless_conversion.rs b/src/tools/clippy/clippy_lints/src/useless_conversion.rs
index e45f884cfcb..1b137017ecb 100644
--- a/src/tools/clippy/clippy_lints/src/useless_conversion.rs
+++ b/src/tools/clippy/clippy_lints/src/useless_conversion.rs
@@ -1,7 +1,7 @@
 use clippy_utils::diagnostics::{span_lint_and_help, span_lint_and_sugg, span_lint_and_then};
 use clippy_utils::source::{snippet, snippet_with_context};
 use clippy_utils::sugg::{DiagExt as _, Sugg};
-use clippy_utils::ty::{get_type_diagnostic_name, is_copy, is_type_diagnostic_item, same_type_and_consts};
+use clippy_utils::ty::{get_type_diagnostic_name, is_copy, is_type_diagnostic_item, same_type_modulo_regions};
 use clippy_utils::{
     get_parent_expr, is_inherent_method_call, is_trait_item, is_trait_method, is_ty_alias, path_to_local, sym,
 };
@@ -184,7 +184,7 @@ impl<'tcx> LateLintPass<'tcx> for UselessConversion {
                     && (is_trait_item(cx, arg, sym::Into) || is_trait_item(cx, arg, sym::From))
                     && let ty::FnDef(_, args) = cx.typeck_results().expr_ty(arg).kind()
                     && let &[from_ty, to_ty] = args.into_type_list(cx.tcx).as_slice()
-                    && same_type_and_consts(from_ty, to_ty)
+                    && same_type_modulo_regions(from_ty, to_ty)
                 {
                     span_lint_and_then(
                         cx,
@@ -207,7 +207,7 @@ impl<'tcx> LateLintPass<'tcx> for UselessConversion {
                 if is_trait_method(cx, e, sym::Into) && name.ident.name == sym::into {
                     let a = cx.typeck_results().expr_ty(e);
                     let b = cx.typeck_results().expr_ty(recv);
-                    if same_type_and_consts(a, b) {
+                    if same_type_modulo_regions(a, b) {
                         let mut app = Applicability::MachineApplicable;
                         let sugg = snippet_with_context(cx, recv.span, e.span.ctxt(), "<expr>", &mut app).0;
                         span_lint_and_sugg(
@@ -324,7 +324,7 @@ impl<'tcx> LateLintPass<'tcx> for UselessConversion {
                     // If the types are identical then .into_iter() can be removed, unless the type
                     // implements Copy, in which case .into_iter() returns a copy of the receiver and
                     // cannot be safely omitted.
-                    if same_type_and_consts(a, b) && !is_copy(cx, b) {
+                    if same_type_modulo_regions(a, b) && !is_copy(cx, b) {
                         // Below we check if the parent method call meets the following conditions:
                         // 1. First parameter is `&mut self` (requires mutable reference)
                         // 2. Second parameter implements the `FnMut` trait (e.g., Iterator::any)
@@ -371,7 +371,7 @@ impl<'tcx> LateLintPass<'tcx> for UselessConversion {
                     && is_type_diagnostic_item(cx, a, sym::Result)
                     && let ty::Adt(_, args) = a.kind()
                     && let Some(a_type) = args.types().next()
-                    && same_type_and_consts(a_type, b)
+                    && same_type_modulo_regions(a_type, b)
                 {
                     span_lint_and_help(
                         cx,
@@ -396,7 +396,7 @@ impl<'tcx> LateLintPass<'tcx> for UselessConversion {
                         && is_type_diagnostic_item(cx, a, sym::Result)
                         && let ty::Adt(_, args) = a.kind()
                         && let Some(a_type) = args.types().next()
-                        && same_type_and_consts(a_type, b)
+                        && same_type_modulo_regions(a_type, b)
                     {
                         let hint = format!("consider removing `{}()`", snippet(cx, path.span, "TryFrom::try_from"));
                         span_lint_and_help(
@@ -407,7 +407,7 @@ impl<'tcx> LateLintPass<'tcx> for UselessConversion {
                             None,
                             hint,
                         );
-                    } else if name == sym::from_fn && same_type_and_consts(a, b) {
+                    } else if name == sym::from_fn && same_type_modulo_regions(a, b) {
                         let mut app = Applicability::MachineApplicable;
                         let sugg = Sugg::hir_with_context(cx, arg, e.span.ctxt(), "<expr>", &mut app).maybe_paren();
                         let sugg_msg = format!("consider removing `{}()`", snippet(cx, path.span, "From::from"));
diff --git a/src/tools/clippy/clippy_utils/Cargo.toml b/src/tools/clippy/clippy_utils/Cargo.toml
index bdf7431f29f..d58b47bf6de 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.91"
+version = "0.1.92"
 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 e01f563c49e..2c66fdc73f5 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-09-04
+nightly-2025-09-18
 ```
 <!-- end autogenerated nightly -->
 
diff --git a/src/tools/clippy/clippy_utils/src/check_proc_macro.rs b/src/tools/clippy/clippy_utils/src/check_proc_macro.rs
index 1a25c90d735..948a7203402 100644
--- a/src/tools/clippy/clippy_utils/src/check_proc_macro.rs
+++ b/src/tools/clippy/clippy_utils/src/check_proc_macro.rs
@@ -13,20 +13,24 @@
 //! if the span is not from a `macro_rules` based macro.
 
 use rustc_abi::ExternAbi;
+use rustc_ast as ast;
 use rustc_ast::AttrStyle;
-use rustc_ast::ast::{AttrKind, Attribute, IntTy, LitIntType, LitKind, StrStyle, TraitObjectSyntax, UintTy};
+use rustc_ast::ast::{
+    AttrKind, Attribute, GenericArgs, IntTy, LitIntType, LitKind, StrStyle, TraitObjectSyntax, UintTy,
+};
 use rustc_ast::token::CommentKind;
 use rustc_hir::intravisit::FnKind;
 use rustc_hir::{
     Block, BlockCheckMode, Body, Closure, Destination, Expr, ExprKind, FieldDef, FnHeader, FnRetTy, HirId, Impl,
-    ImplItem, ImplItemImplKind, ImplItemKind, IsAuto, Item, ItemKind, Lit, LoopSource, MatchSource, MutTy, Node, Path, QPath, Safety,
-    TraitImplHeader, TraitItem, TraitItemKind, Ty, TyKind, UnOp, UnsafeSource, Variant, VariantData, YieldSource,
+    ImplItem, ImplItemImplKind, ImplItemKind, IsAuto, Item, ItemKind, Lit, LoopSource, MatchSource, MutTy, Node, Path,
+    QPath, Safety, TraitImplHeader, TraitItem, TraitItemKind, Ty, TyKind, UnOp, UnsafeSource, Variant, VariantData,
+    YieldSource,
 };
 use rustc_lint::{EarlyContext, LateContext, LintContext};
 use rustc_middle::ty::TyCtxt;
 use rustc_session::Session;
 use rustc_span::symbol::{Ident, kw};
-use rustc_span::{Span, Symbol};
+use rustc_span::{Span, Symbol, sym};
 
 /// The search pattern to look for. Used by `span_matches_pat`
 #[derive(Clone)]
@@ -289,7 +293,7 @@ fn impl_item_search_pat(item: &ImplItem<'_>) -> (Pat, Pat) {
         && !vis_span.is_empty()
     {
         start_pat = Pat::Str("pub");
-    };
+    }
     (start_pat, end_pat)
 }
 
@@ -321,14 +325,17 @@ fn fn_kind_pat(tcx: TyCtxt<'_>, kind: &FnKind<'_>, body: &Body<'_>, hir_id: HirI
     };
     match tcx.hir_node(hir_id) {
         Node::Item(Item { vis_span, .. })
-        | Node::ImplItem(ImplItem { impl_kind: ImplItemImplKind::Inherent { vis_span, .. }, .. }) => {
+        | Node::ImplItem(ImplItem {
+            impl_kind: ImplItemImplKind::Inherent { vis_span, .. },
+            ..
+        }) => {
             if !vis_span.is_empty() {
-                start_pat = Pat::Str("pub")
+                start_pat = Pat::Str("pub");
             }
         },
         Node::ImplItem(_) | Node::TraitItem(_) => {},
         _ => start_pat = Pat::Str(""),
-    };
+    }
     (start_pat, end_pat)
 }
 
@@ -403,6 +410,7 @@ fn ty_search_pat(ty: &Ty<'_>) -> (Pat, Pat) {
         TyKind::OpaqueDef(..) => (Pat::Str("impl"), Pat::Str("")),
         TyKind::Path(qpath) => qpath_search_pat(&qpath),
         TyKind::Infer(()) => (Pat::Str("_"), Pat::Str("_")),
+        TyKind::UnsafeBinder(binder_ty) => (Pat::Str("unsafe"), ty_search_pat(binder_ty.inner_ty).1),
         TyKind::TraitObject(_, tagged_ptr) if let TraitObjectSyntax::Dyn = tagged_ptr.tag() => {
             (Pat::Str("dyn"), Pat::Str(""))
         },
@@ -411,6 +419,127 @@ fn ty_search_pat(ty: &Ty<'_>) -> (Pat, Pat) {
     }
 }
 
+fn ast_ty_search_pat(ty: &ast::Ty) -> (Pat, Pat) {
+    use ast::{Extern, FnRetTy, MutTy, Safety, TraitObjectSyntax, TyKind};
+
+    match &ty.kind {
+        TyKind::Slice(..) | TyKind::Array(..) => (Pat::Str("["), Pat::Str("]")),
+        TyKind::Ptr(MutTy { ty, .. }) => (Pat::Str("*"), ast_ty_search_pat(ty).1),
+        TyKind::Ref(_, MutTy { ty, .. }) | TyKind::PinnedRef(_, MutTy { ty, .. }) => {
+            (Pat::Str("&"), ast_ty_search_pat(ty).1)
+        },
+        TyKind::FnPtr(fn_ptr) => (
+            if let Safety::Unsafe(_) = fn_ptr.safety {
+                Pat::Str("unsafe")
+            } else if let Extern::Explicit(strlit, _) = fn_ptr.ext
+                && strlit.symbol == sym::rust
+            {
+                Pat::MultiStr(&["fn", "extern"])
+            } else {
+                Pat::Str("extern")
+            },
+            match &fn_ptr.decl.output {
+                FnRetTy::Default(_) => {
+                    if let [.., param] = &*fn_ptr.decl.inputs {
+                        ast_ty_search_pat(&param.ty).1
+                    } else {
+                        Pat::Str("(")
+                    }
+                },
+                FnRetTy::Ty(ty) => ast_ty_search_pat(ty).1,
+            },
+        ),
+        TyKind::Never => (Pat::Str("!"), Pat::Str("!")),
+        // Parenthesis are trimmed from the text before the search patterns are matched.
+        // See: `span_matches_pat`
+        TyKind::Tup(tup) => match &**tup {
+            [] => (Pat::Str(")"), Pat::Str("(")),
+            [ty] => ast_ty_search_pat(ty),
+            [head, .., tail] => (ast_ty_search_pat(head).0, ast_ty_search_pat(tail).1),
+        },
+        TyKind::ImplTrait(..) => (Pat::Str("impl"), Pat::Str("")),
+        TyKind::Path(qself_path, path) => {
+            let start = if qself_path.is_some() {
+                Pat::Str("<")
+            } else if let Some(first) = path.segments.first() {
+                ident_search_pat(first.ident).0
+            } else {
+                // this shouldn't be possible, but sure
+                Pat::Str("")
+            };
+            let end = if let Some(last) = path.segments.last() {
+                match last.args.as_deref() {
+                    // last `>` in `std::foo::Bar<T>`
+                    Some(GenericArgs::AngleBracketed(_)) => Pat::Str(">"),
+                    Some(GenericArgs::Parenthesized(par_args)) => match &par_args.output {
+                        FnRetTy::Default(_) => {
+                            if let Some(last) = par_args.inputs.last() {
+                                // `B` in `(A, B)` -- `)` gets stripped
+                                ast_ty_search_pat(last).1
+                            } else {
+                                // `(` in `()` -- `)` gets stripped
+                                Pat::Str("(")
+                            }
+                        },
+                        // `C` in `(A, B) -> C`
+                        FnRetTy::Ty(ty) => ast_ty_search_pat(ty).1,
+                    },
+                    // last `..` in `(..)` -- `)` gets stripped
+                    Some(GenericArgs::ParenthesizedElided(_)) => Pat::Str(".."),
+                    // `bar` in `std::foo::bar`
+                    None => ident_search_pat(last.ident).1,
+                }
+            } else {
+                // this shouldn't be possible, but sure
+                #[allow(
+                    clippy::collapsible_else_if,
+                    reason = "we want to keep these cases together, since they are both impossible"
+                )]
+                if qself_path.is_some() {
+                    // last `>` in `<Vec as IntoIterator>`
+                    Pat::Str(">")
+                } else {
+                    Pat::Str("")
+                }
+            };
+            (start, end)
+        },
+        TyKind::Infer => (Pat::Str("_"), Pat::Str("_")),
+        TyKind::Paren(ty) => ast_ty_search_pat(ty),
+        TyKind::UnsafeBinder(binder_ty) => (Pat::Str("unsafe"), ast_ty_search_pat(&binder_ty.inner_ty).1),
+        TyKind::TraitObject(_, trait_obj_syntax) => {
+            if let TraitObjectSyntax::Dyn = trait_obj_syntax {
+                (Pat::Str("dyn"), Pat::Str(""))
+            } else {
+                // NOTE: `TraitObject` is incomplete. It will always return true then.
+                (Pat::Str(""), Pat::Str(""))
+            }
+        },
+        TyKind::MacCall(mac_call) => {
+            let start = if let Some(first) = mac_call.path.segments.first() {
+                ident_search_pat(first.ident).0
+            } else {
+                Pat::Str("")
+            };
+            (start, Pat::Str(""))
+        },
+
+        // implicit, so has no contents to match against
+        TyKind::ImplicitSelf
+
+        // experimental
+        |TyKind::Pat(..)
+
+        // unused
+        | TyKind::CVarArgs
+        | TyKind::Typeof(_)
+
+        // placeholder
+        | TyKind::Dummy
+        | TyKind::Err(_) => (Pat::Str(""), Pat::Str("")),
+    }
+}
+
 fn ident_search_pat(ident: Ident) -> (Pat, Pat) {
     (Pat::Sym(ident.name), Pat::Sym(ident.name))
 }
@@ -445,6 +574,7 @@ impl_with_search_pat!((_cx: LateContext<'tcx>, self: Lit) => lit_search_pat(&sel
 impl_with_search_pat!((_cx: LateContext<'tcx>, self: Path<'_>) => path_search_pat(self));
 
 impl_with_search_pat!((_cx: EarlyContext<'tcx>, self: Attribute) => attr_search_pat(self));
+impl_with_search_pat!((_cx: EarlyContext<'tcx>, self: ast::Ty) => ast_ty_search_pat(self));
 
 impl<'cx> WithSearchPat<'cx> for (&FnKind<'cx>, &Body<'cx>, HirId, Span) {
     type Context = LateContext<'cx>;
diff --git a/src/tools/clippy/clippy_utils/src/lib.rs b/src/tools/clippy/clippy_utils/src/lib.rs
index 120ab2e717d..feadc0ecf65 100644
--- a/src/tools/clippy/clippy_utils/src/lib.rs
+++ b/src/tools/clippy/clippy_utils/src/lib.rs
@@ -329,13 +329,17 @@ pub fn is_wild(pat: &Pat<'_>) -> bool {
     matches!(pat.kind, PatKind::Wild)
 }
 
-// Checks if arm has the form `None => None`
-pub fn is_none_arm(cx: &LateContext<'_>, arm: &Arm<'_>) -> bool {
-    matches!(
-        arm.pat.kind,
+/// Checks if the `pat` is `None`.
+pub fn is_none_pattern(cx: &LateContext<'_>, pat: &Pat<'_>) -> bool {
+    matches!(pat.kind,
         PatKind::Expr(PatExpr { kind: PatExprKind::Path(qpath), .. })
-            if is_res_lang_ctor(cx, cx.qpath_res(qpath, arm.pat.hir_id), OptionNone)
-    )
+            if is_res_lang_ctor(cx, cx.qpath_res(qpath, pat.hir_id), OptionNone))
+}
+
+/// Checks if `arm` has the form `None => None`.
+pub fn is_none_arm(cx: &LateContext<'_>, arm: &Arm<'_>) -> bool {
+    is_none_pattern(cx, arm.pat)
+        && matches!(peel_blocks(arm.body).kind, ExprKind::Path(qpath) if is_res_lang_ctor(cx, cx.qpath_res(&qpath, arm.body.hir_id), OptionNone))
 }
 
 /// Checks if the given `QPath` belongs to a type alias.
@@ -2374,15 +2378,12 @@ pub fn peel_hir_ty_refs<'a>(mut ty: &'a hir::Ty<'a>) -> (&'a hir::Ty<'a>, usize)
     }
 }
 
-/// Peels off all references on the type. Returns the underlying type and the number of references
-/// removed.
-pub fn peel_middle_ty_refs(mut ty: Ty<'_>) -> (Ty<'_>, usize) {
-    let mut count = 0;
-    while let rustc_ty::Ref(_, dest_ty, _) = ty.kind() {
-        ty = *dest_ty;
-        count += 1;
+/// Returns the base type for HIR references and pointers.
+pub fn peel_hir_ty_refs_and_ptrs<'tcx>(ty: &'tcx hir::Ty<'tcx>) -> &'tcx hir::Ty<'tcx> {
+    match &ty.kind {
+        TyKind::Ptr(mut_ty) | TyKind::Ref(_, mut_ty) => peel_hir_ty_refs_and_ptrs(mut_ty.ty),
+        _ => ty,
     }
-    (ty, count)
 }
 
 /// Removes `AddrOf` operators (`&`) or deref operators (`*`), but only if a reference type is
diff --git a/src/tools/clippy/clippy_utils/src/msrvs.rs b/src/tools/clippy/clippy_utils/src/msrvs.rs
index 896d607fbcd..6e07ed9ffcc 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, UNSIGNED_IS_MULTIPLE_OF }
+    1,87,0 { OS_STR_DISPLAY, INT_MIDPOINT, CONST_CHAR_IS_DIGIT, UNSIGNED_IS_MULTIPLE_OF, INTEGER_SIGN_CAST }
     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 }
@@ -73,7 +73,7 @@ msrv_aliases! {
     1,29,0 { ITER_FLATTEN }
     1,28,0 { FROM_BOOL, REPEAT_WITH, SLICE_FROM_REF }
     1,27,0 { ITERATOR_TRY_FOLD }
-    1,26,0 { RANGE_INCLUSIVE, STRING_RETAIN }
+    1,26,0 { RANGE_INCLUSIVE, STRING_RETAIN, POINTER_ADD_SUB_METHODS }
     1,24,0 { IS_ASCII_DIGIT, PTR_NULL }
     1,18,0 { HASH_MAP_RETAIN, HASH_SET_RETAIN }
     1,17,0 { FIELD_INIT_SHORTHAND, STATIC_IN_CONST, EXPECT_ERR }
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 68f0b5ea255..2bda6d50373 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
@@ -86,7 +86,7 @@ fn check_ty<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>, span: Span, msrv: Msrv)
             ty::FnPtr(..) => {
                 return Err((span, "function pointers in const fn are unstable".into()));
             },
-            ty::Dynamic(preds, _, _) => {
+            ty::Dynamic(preds, _) => {
                 for pred in *preds {
                     match pred.skip_binder() {
                         ty::ExistentialPredicate::AutoTrait(_) | ty::ExistentialPredicate::Projection(_) => {
@@ -126,7 +126,7 @@ fn check_rvalue<'tcx>(
 ) -> McfResult {
     match rvalue {
         Rvalue::ThreadLocalRef(_) => Err((span, "cannot access thread local storage in const fn".into())),
-        Rvalue::Len(place) | Rvalue::Discriminant(place) | Rvalue::Ref(_, _, place) | Rvalue::RawPtr(_, place) => {
+        Rvalue::Discriminant(place) | Rvalue::Ref(_, _, place) | Rvalue::RawPtr(_, place) => {
             check_place(cx, *place, span, body, msrv)
         },
         Rvalue::CopyForDeref(place) => check_place(cx, *place, span, body, msrv),
diff --git a/src/tools/clippy/clippy_utils/src/source.rs b/src/tools/clippy/clippy_utils/src/source.rs
index e675291b6f3..638d3290312 100644
--- a/src/tools/clippy/clippy_utils/src/source.rs
+++ b/src/tools/clippy/clippy_utils/src/source.rs
@@ -215,6 +215,11 @@ impl fmt::Display for SourceText {
         self.as_str().fmt(f)
     }
 }
+impl fmt::Debug for SourceText {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        self.as_str().fmt(f)
+    }
+}
 
 fn get_source_range(sm: &SourceMap, sp: Range<BytePos>) -> Option<SourceFileRange> {
     let start = sm.lookup_byte_offset(sp.start);
diff --git a/src/tools/clippy/clippy_utils/src/sym.rs b/src/tools/clippy/clippy_utils/src/sym.rs
index 8033b74a8d2..7530d3bc715 100644
--- a/src/tools/clippy/clippy_utils/src/sym.rs
+++ b/src/tools/clippy/clippy_utils/src/sym.rs
@@ -125,6 +125,7 @@ generate! {
     cycle,
     cyclomatic_complexity,
     de,
+    deprecated_in_future,
     diagnostics,
     disallowed_types,
     drain,
diff --git a/src/tools/clippy/clippy_utils/src/ty/mod.rs b/src/tools/clippy/clippy_utils/src/ty/mod.rs
index 9f77a1c4d9b..e4bc3b76829 100644
--- a/src/tools/clippy/clippy_utils/src/ty/mod.rs
+++ b/src/tools/clippy/clippy_utils/src/ty/mod.rs
@@ -11,7 +11,7 @@ use rustc_hir as hir;
 use rustc_hir::attrs::AttributeKind;
 use rustc_hir::def::{CtorKind, CtorOf, DefKind, Res};
 use rustc_hir::def_id::DefId;
-use rustc_hir::{Expr, FnDecl, LangItem, TyKind, find_attr};
+use rustc_hir::{Expr, FnDecl, LangItem, find_attr};
 use rustc_hir_analysis::lower_ty;
 use rustc_infer::infer::TyCtxtInferExt;
 use rustc_lint::LateContext;
@@ -43,13 +43,8 @@ pub use type_certainty::expr_type_is_certain;
 /// Lower a [`hir::Ty`] to a [`rustc_middle::ty::Ty`].
 pub fn ty_from_hir_ty<'tcx>(cx: &LateContext<'tcx>, hir_ty: &hir::Ty<'tcx>) -> Ty<'tcx> {
     cx.maybe_typeck_results()
-        .and_then(|results| {
-            if results.hir_owner == hir_ty.hir_id.owner {
-                results.node_type_opt(hir_ty.hir_id)
-            } else {
-                None
-            }
-        })
+        .filter(|results| results.hir_owner == hir_ty.hir_id.owner)
+        .and_then(|results| results.node_type_opt(hir_ty.hir_id))
         .unwrap_or_else(|| lower_ty(cx.tcx, hir_ty))
 }
 
@@ -349,7 +344,7 @@ pub fn is_must_use_ty<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool {
             }
             false
         },
-        ty::Dynamic(binder, _, _) => {
+        ty::Dynamic(binder, _) => {
             for predicate in *binder {
                 if let ty::ExistentialPredicate::Trait(ref trait_ref) = predicate.skip_binder()
                     && find_attr!(cx.tcx.get_all_attrs(trait_ref.def_id), AttributeKind::MustUse { .. })
@@ -475,63 +470,50 @@ pub fn needs_ordered_drop<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool {
     needs_ordered_drop_inner(cx, ty, &mut FxHashSet::default())
 }
 
-/// Peels off all references on the type. Returns the underlying type, the number of references
-/// removed, and whether the pointer is ultimately mutable or not.
-pub fn peel_mid_ty_refs_is_mutable(ty: Ty<'_>) -> (Ty<'_>, usize, Mutability) {
-    fn f(ty: Ty<'_>, count: usize, mutability: Mutability) -> (Ty<'_>, usize, Mutability) {
-        match ty.kind() {
-            ty::Ref(_, ty, Mutability::Mut) => f(*ty, count + 1, mutability),
-            ty::Ref(_, ty, Mutability::Not) => f(*ty, count + 1, Mutability::Not),
-            _ => (ty, count, mutability),
-        }
-    }
-    f(ty, 0, Mutability::Mut)
-}
-
-/// Returns `true` if the given type is an `unsafe` function.
-pub fn type_is_unsafe_function<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool {
+/// Returns `true` if `ty` denotes an `unsafe fn`.
+pub fn is_unsafe_fn<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool {
     ty.is_fn() && ty.fn_sig(cx.tcx).safety().is_unsafe()
 }
 
-/// Returns the base type for HIR references and pointers.
-pub fn walk_ptrs_hir_ty<'tcx>(ty: &'tcx hir::Ty<'tcx>) -> &'tcx hir::Ty<'tcx> {
-    match ty.kind {
-        TyKind::Ptr(ref mut_ty) | TyKind::Ref(_, ref mut_ty) => walk_ptrs_hir_ty(mut_ty.ty),
-        _ => ty,
-    }
-}
-
-/// Returns the base type for references and raw pointers, and count reference
-/// depth.
-pub fn walk_ptrs_ty_depth(ty: Ty<'_>) -> (Ty<'_>, usize) {
-    fn inner(ty: Ty<'_>, depth: usize) -> (Ty<'_>, usize) {
-        match ty.kind() {
-            ty::Ref(_, ty, _) => inner(*ty, depth + 1),
-            _ => (ty, depth),
-        }
+/// Peels off all references on the type. Returns the underlying type, the number of references
+/// removed, and, if there were any such references, whether the pointer is ultimately mutable or
+/// not.
+pub fn peel_and_count_ty_refs(mut ty: Ty<'_>) -> (Ty<'_>, usize, Option<Mutability>) {
+    let mut count = 0;
+    let mut mutbl = None;
+    while let ty::Ref(_, dest_ty, m) = ty.kind() {
+        ty = *dest_ty;
+        count += 1;
+        mutbl.replace(mutbl.map_or(*m, |mutbl: Mutability| mutbl.min(*m)));
     }
-    inner(ty, 0)
+    (ty, count, mutbl)
 }
 
-/// Returns `true` if types `a` and `b` are same types having same `Const` generic args,
-/// otherwise returns `false`
-pub fn same_type_and_consts<'tcx>(a: Ty<'tcx>, b: Ty<'tcx>) -> bool {
+/// Checks whether `a` and `b` are same types having same `Const` generic args, but ignores
+/// lifetimes.
+///
+/// For example, the function would return `true` for
+/// - `u32` and `u32`
+/// - `[u8; N]` and `[u8; M]`, if `N=M`
+/// - `Option<T>` and `Option<U>`, if `same_type_modulo_regions(T, U)` holds
+/// - `&'a str` and `&'b str`
+///
+/// and `false` for:
+/// - `Result<u32, String>` and `Result<usize, String>`
+pub fn same_type_modulo_regions<'tcx>(a: Ty<'tcx>, b: Ty<'tcx>) -> bool {
     match (&a.kind(), &b.kind()) {
         (&ty::Adt(did_a, args_a), &ty::Adt(did_b, args_b)) => {
             if did_a != did_b {
                 return false;
             }
 
-            args_a
-                .iter()
-                .zip(args_b.iter())
-                .all(|(arg_a, arg_b)| match (arg_a.kind(), arg_b.kind()) {
-                    (GenericArgKind::Const(inner_a), GenericArgKind::Const(inner_b)) => inner_a == inner_b,
-                    (GenericArgKind::Type(type_a), GenericArgKind::Type(type_b)) => {
-                        same_type_and_consts(type_a, type_b)
-                    },
-                    _ => true,
-                })
+            iter::zip(*args_a, *args_b).all(|(arg_a, arg_b)| match (arg_a.kind(), arg_b.kind()) {
+                (GenericArgKind::Const(inner_a), GenericArgKind::Const(inner_b)) => inner_a == inner_b,
+                (GenericArgKind::Type(type_a), GenericArgKind::Type(type_b)) => {
+                    same_type_modulo_regions(type_a, type_b)
+                },
+                _ => true,
+            })
         },
         _ => a == b,
     }
@@ -673,7 +655,7 @@ pub fn ty_sig<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> Option<ExprFnSig<'t
             cx.tcx.opt_parent(def_id),
         ),
         ty::FnPtr(sig_tys, hdr) => Some(ExprFnSig::Sig(sig_tys.with(hdr), None)),
-        ty::Dynamic(bounds, _, _) => {
+        ty::Dynamic(bounds, _) => {
             let lang_items = cx.tcx.lang_items();
             match bounds.principal() {
                 Some(bound)
diff --git a/src/tools/clippy/declare_clippy_lint/Cargo.toml b/src/tools/clippy/declare_clippy_lint/Cargo.toml
index ec0e59e7054..4de7b5fb592 100644
--- a/src/tools/clippy/declare_clippy_lint/Cargo.toml
+++ b/src/tools/clippy/declare_clippy_lint/Cargo.toml
@@ -1,6 +1,6 @@
 [package]
 name = "declare_clippy_lint"
-version = "0.1.91"
+version = "0.1.92"
 edition = "2024"
 repository = "https://github.com/rust-lang/rust-clippy"
 license = "MIT OR Apache-2.0"
diff --git a/src/tools/clippy/rust-toolchain.toml b/src/tools/clippy/rust-toolchain.toml
index ec2f24a0a6d..9c102de4482 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-09-04"
+channel = "nightly-2025-09-18"
 # end autogenerated nightly
 components = ["cargo", "llvm-tools", "rust-src", "rust-std", "rustc", "rustc-dev", "rustfmt"]
 profile = "minimal"
diff --git a/src/tools/clippy/tests/no-profile-in-cargo-toml.rs b/src/tools/clippy/tests/no-profile-in-cargo-toml.rs
index 2ad9bfb75de..1f8c4fae9b3 100644
--- a/src/tools/clippy/tests/no-profile-in-cargo-toml.rs
+++ b/src/tools/clippy/tests/no-profile-in-cargo-toml.rs
@@ -17,6 +17,9 @@ fn no_profile_in_cargo_toml() {
     // keep it fast and simple.
     for entry in WalkDir::new(".")
         .into_iter()
+        // Do not recurse into `target` as lintcheck might put some sources (and their
+        //  `Cargo.toml`) there.
+        .filter_entry(|e| e.file_name() != "target")
         .filter_map(Result::ok)
         .filter(|e| e.file_name().to_str() == Some("Cargo.toml"))
     {
diff --git a/src/tools/clippy/tests/ui/ref_option/all/clippy.toml b/src/tools/clippy/tests/ui-toml/ref_option/all/clippy.toml
index cda8d17eed4..cda8d17eed4 100644
--- a/src/tools/clippy/tests/ui/ref_option/all/clippy.toml
+++ b/src/tools/clippy/tests/ui-toml/ref_option/all/clippy.toml
diff --git a/src/tools/clippy/tests/ui/ref_option/private/clippy.toml b/src/tools/clippy/tests/ui-toml/ref_option/private/clippy.toml
index 5f304987aa9..5f304987aa9 100644
--- a/src/tools/clippy/tests/ui/ref_option/private/clippy.toml
+++ b/src/tools/clippy/tests/ui-toml/ref_option/private/clippy.toml
diff --git a/src/tools/clippy/tests/ui-toml/ref_option/ref_option.all.fixed b/src/tools/clippy/tests/ui-toml/ref_option/ref_option.all.fixed
new file mode 100644
index 00000000000..f8f097e9a75
--- /dev/null
+++ b/src/tools/clippy/tests/ui-toml/ref_option/ref_option.all.fixed
@@ -0,0 +1,114 @@
+//@aux-build:../../ui/auxiliary/proc_macros.rs
+//@revisions: private all
+//@[private] rustc-env:CLIPPY_CONF_DIR=tests/ui-toml/ref_option/private
+//@[all] rustc-env:CLIPPY_CONF_DIR=tests/ui-toml/ref_option/all
+
+#![allow(unused, clippy::needless_lifetimes, clippy::borrowed_box)]
+#![warn(clippy::ref_option)]
+
+fn opt_u8(a: Option<&u8>) {}
+//~^ ref_option
+fn opt_gen<T>(a: Option<&T>) {}
+//~^ ref_option
+fn opt_string(a: std::option::Option<&String>) {}
+//~^ ref_option
+fn ret_u8<'a>(p: &'a str) -> Option<&'a u8> {
+    //~^ ref_option
+    panic!()
+}
+fn ret_u8_static() -> Option<&'static u8> {
+    //~^ ref_option
+    panic!()
+}
+fn mult_string(a: Option<&String>, b: Option<&Vec<u8>>) {}
+//~^ ref_option
+fn ret_box<'a>() -> Option<&'a Box<u8>> {
+    //~^ ref_option
+    panic!()
+}
+
+pub fn pub_opt_string(a: Option<&String>) {}
+//~[all]^ ref_option
+pub fn pub_mult_string(a: Option<&String>, b: Option<&Vec<u8>>) {}
+//~[all]^ ref_option
+
+pub struct PubStruct;
+
+impl PubStruct {
+    pub fn pub_opt_params(&self, a: Option<&()>) {}
+    //~[all]^ ref_option
+    pub fn pub_opt_ret(&self) -> Option<&String> {
+        //~[all]^ ref_option
+        panic!()
+    }
+
+    fn private_opt_params(&self, a: Option<&()>) {}
+    //~^ ref_option
+    fn private_opt_ret(&self) -> Option<&String> {
+        //~^ ref_option
+        panic!()
+    }
+}
+
+// valid, don't change
+fn mut_u8(a: &mut Option<u8>) {}
+pub fn pub_mut_u8(a: &mut Option<String>) {}
+
+// might be good to catch in the future
+fn mut_u8_ref(a: &mut &Option<u8>) {}
+pub fn pub_mut_u8_ref(a: &mut &Option<String>) {}
+fn lambdas() {
+    // Not handled for now, not sure if we should
+    let x = |a: &Option<String>| {};
+    let x = |a: &Option<String>| -> &Option<String> { panic!() };
+}
+
+pub mod external {
+    proc_macros::external!(
+        fn opt_u8(a: &Option<u8>) {}
+        fn ret_u8<'a>(p: &'a str) -> &'a Option<u8> {
+            panic!()
+        }
+        pub fn pub_opt_u8(a: &Option<u8>) {}
+
+        pub struct PubStruct;
+        impl PubStruct {
+            pub fn pub_opt_params(&self, a: &Option<()>) {}
+            pub fn pub_opt_ret(&self) -> &Option<String> {
+                panic!()
+            }
+
+            fn private_opt_params(&self, a: &Option<()>) {}
+            fn private_opt_ret(&self) -> &Option<String> {
+                panic!()
+            }
+        }
+    );
+}
+
+pub mod proc_macros {
+    proc_macros::with_span!(
+        span
+
+        fn opt_u8(a: &Option<u8>) {}
+        fn ret_u8<'a>(p: &'a str) -> &'a Option<u8> {
+            panic!()
+        }
+        pub fn pub_opt_u8(a: &Option<u8>) {}
+
+        pub struct PubStruct;
+        impl PubStruct {
+            pub fn pub_opt_params(&self, a: &Option<()>) {}
+            pub fn pub_opt_ret(&self) -> &Option<String> {
+                panic!()
+            }
+
+            fn private_opt_params(&self, a: &Option<()>) {}
+            fn private_opt_ret(&self) -> &Option<String> {
+                panic!()
+            }
+        }
+    );
+}
+
+fn main() {}
diff --git a/src/tools/clippy/tests/ui/ref_option/ref_option.all.stderr b/src/tools/clippy/tests/ui-toml/ref_option/ref_option.all.stderr
index bd43c28336e..45ce105e030 100644
--- a/src/tools/clippy/tests/ui/ref_option/ref_option.all.stderr
+++ b/src/tools/clippy/tests/ui-toml/ref_option/ref_option.all.stderr
@@ -1,5 +1,5 @@
 error: it is more idiomatic to use `Option<&T>` instead of `&Option<T>`
-  --> tests/ui/ref_option/ref_option.rs:8:1
+  --> tests/ui-toml/ref_option/ref_option.rs:9:1
    |
 LL | fn opt_u8(a: &Option<u8>) {}
    | ^^^^^^^^^^^^^-----------^^^^
@@ -10,7 +10,7 @@ LL | fn opt_u8(a: &Option<u8>) {}
    = help: to override `-D warnings` add `#[allow(clippy::ref_option)]`
 
 error: it is more idiomatic to use `Option<&T>` instead of `&Option<T>`
-  --> tests/ui/ref_option/ref_option.rs:10:1
+  --> tests/ui-toml/ref_option/ref_option.rs:11:1
    |
 LL | fn opt_gen<T>(a: &Option<T>) {}
    | ^^^^^^^^^^^^^^^^^----------^^^^
@@ -18,7 +18,7 @@ LL | fn opt_gen<T>(a: &Option<T>) {}
    |                  help: change this to: `Option<&T>`
 
 error: it is more idiomatic to use `Option<&T>` instead of `&Option<T>`
-  --> tests/ui/ref_option/ref_option.rs:12:1
+  --> tests/ui-toml/ref_option/ref_option.rs:13:1
    |
 LL | fn opt_string(a: &std::option::Option<String>) {}
    | ^^^^^^^^^^^^^^^^^----------------------------^^^^
@@ -26,10 +26,10 @@ LL | fn opt_string(a: &std::option::Option<String>) {}
    |                  help: change this to: `std::option::Option<&String>`
 
 error: it is more idiomatic to use `Option<&T>` instead of `&Option<T>`
-  --> tests/ui/ref_option/ref_option.rs:14:1
+  --> tests/ui-toml/ref_option/ref_option.rs:15:1
    |
-LL |   fn ret_string<'a>(p: &'a str) -> &'a Option<u8> {
-   |   ^                                -------------- help: change this to: `Option<&'a u8>`
+LL |   fn ret_u8<'a>(p: &'a str) -> &'a Option<u8> {
+   |   ^                            -------------- help: change this to: `Option<&'a u8>`
    |  _|
    | |
 LL | |
@@ -38,10 +38,10 @@ LL | | }
    | |_^
 
 error: it is more idiomatic to use `Option<&T>` instead of `&Option<T>`
-  --> tests/ui/ref_option/ref_option.rs:18:1
+  --> tests/ui-toml/ref_option/ref_option.rs:19:1
    |
-LL |   fn ret_string_static() -> &'static Option<u8> {
-   |   ^                         ------------------- help: change this to: `Option<&'static u8>`
+LL |   fn ret_u8_static() -> &'static Option<u8> {
+   |   ^                     ------------------- help: change this to: `Option<&'static u8>`
    |  _|
    | |
 LL | |
@@ -50,7 +50,7 @@ LL | | }
    | |_^
 
 error: it is more idiomatic to use `Option<&T>` instead of `&Option<T>`
-  --> tests/ui/ref_option/ref_option.rs:22:1
+  --> tests/ui-toml/ref_option/ref_option.rs:23:1
    |
 LL | fn mult_string(a: &Option<String>, b: &Option<Vec<u8>>) {}
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -62,7 +62,7 @@ LL + fn mult_string(a: Option<&String>, b: Option<&Vec<u8>>) {}
    |
 
 error: it is more idiomatic to use `Option<&T>` instead of `&Option<T>`
-  --> tests/ui/ref_option/ref_option.rs:24:1
+  --> tests/ui-toml/ref_option/ref_option.rs:25:1
    |
 LL |   fn ret_box<'a>() -> &'a Option<Box<u8>> {
    |   ^                   ------------------- help: change this to: `Option<&'a Box<u8>>`
@@ -74,7 +74,7 @@ LL | | }
    | |_^
 
 error: it is more idiomatic to use `Option<&T>` instead of `&Option<T>`
-  --> tests/ui/ref_option/ref_option.rs:29:1
+  --> tests/ui-toml/ref_option/ref_option.rs:30:1
    |
 LL | pub fn pub_opt_string(a: &Option<String>) {}
    | ^^^^^^^^^^^^^^^^^^^^^^^^^---------------^^^^
@@ -82,7 +82,7 @@ LL | pub fn pub_opt_string(a: &Option<String>) {}
    |                          help: change this to: `Option<&String>`
 
 error: it is more idiomatic to use `Option<&T>` instead of `&Option<T>`
-  --> tests/ui/ref_option/ref_option.rs:31:1
+  --> tests/ui-toml/ref_option/ref_option.rs:32:1
    |
 LL | pub fn pub_mult_string(a: &Option<String>, b: &Option<Vec<u8>>) {}
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -94,39 +94,7 @@ LL + pub fn pub_mult_string(a: Option<&String>, b: Option<&Vec<u8>>) {}
    |
 
 error: it is more idiomatic to use `Option<&T>` instead of `&Option<T>`
-  --> tests/ui/ref_option/ref_option.rs:35:5
-   |
-LL |     fn pub_trait_opt(&self, a: &Option<Vec<u8>>);
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^----------------^^
-   |                                |
-   |                                help: change this to: `Option<&Vec<u8>>`
-
-error: it is more idiomatic to use `Option<&T>` instead of `&Option<T>`
-  --> tests/ui/ref_option/ref_option.rs:37:5
-   |
-LL |     fn pub_trait_ret(&self) -> &Option<Vec<u8>>;
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^----------------^
-   |                                |
-   |                                help: change this to: `Option<&Vec<u8>>`
-
-error: it is more idiomatic to use `Option<&T>` instead of `&Option<T>`
-  --> tests/ui/ref_option/ref_option.rs:42:5
-   |
-LL |     fn trait_opt(&self, a: &Option<String>);
-   |     ^^^^^^^^^^^^^^^^^^^^^^^---------------^^
-   |                            |
-   |                            help: change this to: `Option<&String>`
-
-error: it is more idiomatic to use `Option<&T>` instead of `&Option<T>`
-  --> tests/ui/ref_option/ref_option.rs:44:5
-   |
-LL |     fn trait_ret(&self) -> &Option<String>;
-   |     ^^^^^^^^^^^^^^^^^^^^^^^---------------^
-   |                            |
-   |                            help: change this to: `Option<&String>`
-
-error: it is more idiomatic to use `Option<&T>` instead of `&Option<T>`
-  --> tests/ui/ref_option/ref_option.rs:51:5
+  --> tests/ui-toml/ref_option/ref_option.rs:38:5
    |
 LL |     pub fn pub_opt_params(&self, a: &Option<()>) {}
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-----------^^^^
@@ -134,7 +102,7 @@ LL |     pub fn pub_opt_params(&self, a: &Option<()>) {}
    |                                     help: change this to: `Option<&()>`
 
 error: it is more idiomatic to use `Option<&T>` instead of `&Option<T>`
-  --> tests/ui/ref_option/ref_option.rs:53:5
+  --> tests/ui-toml/ref_option/ref_option.rs:40:5
    |
 LL |       pub fn pub_opt_ret(&self) -> &Option<String> {
    |       ^                            --------------- help: change this to: `Option<&String>`
@@ -146,7 +114,7 @@ LL | |     }
    | |_____^
 
 error: it is more idiomatic to use `Option<&T>` instead of `&Option<T>`
-  --> tests/ui/ref_option/ref_option.rs:58:5
+  --> tests/ui-toml/ref_option/ref_option.rs:45:5
    |
 LL |     fn private_opt_params(&self, a: &Option<()>) {}
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-----------^^^^
@@ -154,7 +122,7 @@ LL |     fn private_opt_params(&self, a: &Option<()>) {}
    |                                     help: change this to: `Option<&()>`
 
 error: it is more idiomatic to use `Option<&T>` instead of `&Option<T>`
-  --> tests/ui/ref_option/ref_option.rs:60:5
+  --> tests/ui-toml/ref_option/ref_option.rs:47:5
    |
 LL |       fn private_opt_ret(&self) -> &Option<String> {
    |       ^                            --------------- help: change this to: `Option<&String>`
@@ -165,5 +133,5 @@ LL | |         panic!()
 LL | |     }
    | |_____^
 
-error: aborting due to 17 previous errors
+error: aborting due to 13 previous errors
 
diff --git a/src/tools/clippy/tests/ui-toml/ref_option/ref_option.private.fixed b/src/tools/clippy/tests/ui-toml/ref_option/ref_option.private.fixed
new file mode 100644
index 00000000000..4dd14a82206
--- /dev/null
+++ b/src/tools/clippy/tests/ui-toml/ref_option/ref_option.private.fixed
@@ -0,0 +1,114 @@
+//@aux-build:../../ui/auxiliary/proc_macros.rs
+//@revisions: private all
+//@[private] rustc-env:CLIPPY_CONF_DIR=tests/ui-toml/ref_option/private
+//@[all] rustc-env:CLIPPY_CONF_DIR=tests/ui-toml/ref_option/all
+
+#![allow(unused, clippy::needless_lifetimes, clippy::borrowed_box)]
+#![warn(clippy::ref_option)]
+
+fn opt_u8(a: Option<&u8>) {}
+//~^ ref_option
+fn opt_gen<T>(a: Option<&T>) {}
+//~^ ref_option
+fn opt_string(a: std::option::Option<&String>) {}
+//~^ ref_option
+fn ret_u8<'a>(p: &'a str) -> Option<&'a u8> {
+    //~^ ref_option
+    panic!()
+}
+fn ret_u8_static() -> Option<&'static u8> {
+    //~^ ref_option
+    panic!()
+}
+fn mult_string(a: Option<&String>, b: Option<&Vec<u8>>) {}
+//~^ ref_option
+fn ret_box<'a>() -> Option<&'a Box<u8>> {
+    //~^ ref_option
+    panic!()
+}
+
+pub fn pub_opt_string(a: &Option<String>) {}
+//~[all]^ ref_option
+pub fn pub_mult_string(a: &Option<String>, b: &Option<Vec<u8>>) {}
+//~[all]^ ref_option
+
+pub struct PubStruct;
+
+impl PubStruct {
+    pub fn pub_opt_params(&self, a: &Option<()>) {}
+    //~[all]^ ref_option
+    pub fn pub_opt_ret(&self) -> &Option<String> {
+        //~[all]^ ref_option
+        panic!()
+    }
+
+    fn private_opt_params(&self, a: Option<&()>) {}
+    //~^ ref_option
+    fn private_opt_ret(&self) -> Option<&String> {
+        //~^ ref_option
+        panic!()
+    }
+}
+
+// valid, don't change
+fn mut_u8(a: &mut Option<u8>) {}
+pub fn pub_mut_u8(a: &mut Option<String>) {}
+
+// might be good to catch in the future
+fn mut_u8_ref(a: &mut &Option<u8>) {}
+pub fn pub_mut_u8_ref(a: &mut &Option<String>) {}
+fn lambdas() {
+    // Not handled for now, not sure if we should
+    let x = |a: &Option<String>| {};
+    let x = |a: &Option<String>| -> &Option<String> { panic!() };
+}
+
+pub mod external {
+    proc_macros::external!(
+        fn opt_u8(a: &Option<u8>) {}
+        fn ret_u8<'a>(p: &'a str) -> &'a Option<u8> {
+            panic!()
+        }
+        pub fn pub_opt_u8(a: &Option<u8>) {}
+
+        pub struct PubStruct;
+        impl PubStruct {
+            pub fn pub_opt_params(&self, a: &Option<()>) {}
+            pub fn pub_opt_ret(&self) -> &Option<String> {
+                panic!()
+            }
+
+            fn private_opt_params(&self, a: &Option<()>) {}
+            fn private_opt_ret(&self) -> &Option<String> {
+                panic!()
+            }
+        }
+    );
+}
+
+pub mod proc_macros {
+    proc_macros::with_span!(
+        span
+
+        fn opt_u8(a: &Option<u8>) {}
+        fn ret_u8<'a>(p: &'a str) -> &'a Option<u8> {
+            panic!()
+        }
+        pub fn pub_opt_u8(a: &Option<u8>) {}
+
+        pub struct PubStruct;
+        impl PubStruct {
+            pub fn pub_opt_params(&self, a: &Option<()>) {}
+            pub fn pub_opt_ret(&self) -> &Option<String> {
+                panic!()
+            }
+
+            fn private_opt_params(&self, a: &Option<()>) {}
+            fn private_opt_ret(&self) -> &Option<String> {
+                panic!()
+            }
+        }
+    );
+}
+
+fn main() {}
diff --git a/src/tools/clippy/tests/ui/ref_option/ref_option.private.stderr b/src/tools/clippy/tests/ui-toml/ref_option/ref_option.private.stderr
index 88c65e429d8..a63efd60a03 100644
--- a/src/tools/clippy/tests/ui/ref_option/ref_option.private.stderr
+++ b/src/tools/clippy/tests/ui-toml/ref_option/ref_option.private.stderr
@@ -1,5 +1,5 @@
 error: it is more idiomatic to use `Option<&T>` instead of `&Option<T>`
-  --> tests/ui/ref_option/ref_option.rs:8:1
+  --> tests/ui-toml/ref_option/ref_option.rs:9:1
    |
 LL | fn opt_u8(a: &Option<u8>) {}
    | ^^^^^^^^^^^^^-----------^^^^
@@ -10,7 +10,7 @@ LL | fn opt_u8(a: &Option<u8>) {}
    = help: to override `-D warnings` add `#[allow(clippy::ref_option)]`
 
 error: it is more idiomatic to use `Option<&T>` instead of `&Option<T>`
-  --> tests/ui/ref_option/ref_option.rs:10:1
+  --> tests/ui-toml/ref_option/ref_option.rs:11:1
    |
 LL | fn opt_gen<T>(a: &Option<T>) {}
    | ^^^^^^^^^^^^^^^^^----------^^^^
@@ -18,7 +18,7 @@ LL | fn opt_gen<T>(a: &Option<T>) {}
    |                  help: change this to: `Option<&T>`
 
 error: it is more idiomatic to use `Option<&T>` instead of `&Option<T>`
-  --> tests/ui/ref_option/ref_option.rs:12:1
+  --> tests/ui-toml/ref_option/ref_option.rs:13:1
    |
 LL | fn opt_string(a: &std::option::Option<String>) {}
    | ^^^^^^^^^^^^^^^^^----------------------------^^^^
@@ -26,10 +26,10 @@ LL | fn opt_string(a: &std::option::Option<String>) {}
    |                  help: change this to: `std::option::Option<&String>`
 
 error: it is more idiomatic to use `Option<&T>` instead of `&Option<T>`
-  --> tests/ui/ref_option/ref_option.rs:14:1
+  --> tests/ui-toml/ref_option/ref_option.rs:15:1
    |
-LL |   fn ret_string<'a>(p: &'a str) -> &'a Option<u8> {
-   |   ^                                -------------- help: change this to: `Option<&'a u8>`
+LL |   fn ret_u8<'a>(p: &'a str) -> &'a Option<u8> {
+   |   ^                            -------------- help: change this to: `Option<&'a u8>`
    |  _|
    | |
 LL | |
@@ -38,10 +38,10 @@ LL | | }
    | |_^
 
 error: it is more idiomatic to use `Option<&T>` instead of `&Option<T>`
-  --> tests/ui/ref_option/ref_option.rs:18:1
+  --> tests/ui-toml/ref_option/ref_option.rs:19:1
    |
-LL |   fn ret_string_static() -> &'static Option<u8> {
-   |   ^                         ------------------- help: change this to: `Option<&'static u8>`
+LL |   fn ret_u8_static() -> &'static Option<u8> {
+   |   ^                     ------------------- help: change this to: `Option<&'static u8>`
    |  _|
    | |
 LL | |
@@ -50,7 +50,7 @@ LL | | }
    | |_^
 
 error: it is more idiomatic to use `Option<&T>` instead of `&Option<T>`
-  --> tests/ui/ref_option/ref_option.rs:22:1
+  --> tests/ui-toml/ref_option/ref_option.rs:23:1
    |
 LL | fn mult_string(a: &Option<String>, b: &Option<Vec<u8>>) {}
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -62,7 +62,7 @@ LL + fn mult_string(a: Option<&String>, b: Option<&Vec<u8>>) {}
    |
 
 error: it is more idiomatic to use `Option<&T>` instead of `&Option<T>`
-  --> tests/ui/ref_option/ref_option.rs:24:1
+  --> tests/ui-toml/ref_option/ref_option.rs:25:1
    |
 LL |   fn ret_box<'a>() -> &'a Option<Box<u8>> {
    |   ^                   ------------------- help: change this to: `Option<&'a Box<u8>>`
@@ -74,23 +74,7 @@ LL | | }
    | |_^
 
 error: it is more idiomatic to use `Option<&T>` instead of `&Option<T>`
-  --> tests/ui/ref_option/ref_option.rs:42:5
-   |
-LL |     fn trait_opt(&self, a: &Option<String>);
-   |     ^^^^^^^^^^^^^^^^^^^^^^^---------------^^
-   |                            |
-   |                            help: change this to: `Option<&String>`
-
-error: it is more idiomatic to use `Option<&T>` instead of `&Option<T>`
-  --> tests/ui/ref_option/ref_option.rs:44:5
-   |
-LL |     fn trait_ret(&self) -> &Option<String>;
-   |     ^^^^^^^^^^^^^^^^^^^^^^^---------------^
-   |                            |
-   |                            help: change this to: `Option<&String>`
-
-error: it is more idiomatic to use `Option<&T>` instead of `&Option<T>`
-  --> tests/ui/ref_option/ref_option.rs:58:5
+  --> tests/ui-toml/ref_option/ref_option.rs:45:5
    |
 LL |     fn private_opt_params(&self, a: &Option<()>) {}
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-----------^^^^
@@ -98,7 +82,7 @@ LL |     fn private_opt_params(&self, a: &Option<()>) {}
    |                                     help: change this to: `Option<&()>`
 
 error: it is more idiomatic to use `Option<&T>` instead of `&Option<T>`
-  --> tests/ui/ref_option/ref_option.rs:60:5
+  --> tests/ui-toml/ref_option/ref_option.rs:47:5
    |
 LL |       fn private_opt_ret(&self) -> &Option<String> {
    |       ^                            --------------- help: change this to: `Option<&String>`
@@ -109,5 +93,5 @@ LL | |         panic!()
 LL | |     }
    | |_____^
 
-error: aborting due to 11 previous errors
+error: aborting due to 9 previous errors
 
diff --git a/src/tools/clippy/tests/ui-toml/ref_option/ref_option.rs b/src/tools/clippy/tests/ui-toml/ref_option/ref_option.rs
new file mode 100644
index 00000000000..8397c2213d1
--- /dev/null
+++ b/src/tools/clippy/tests/ui-toml/ref_option/ref_option.rs
@@ -0,0 +1,114 @@
+//@aux-build:../../ui/auxiliary/proc_macros.rs
+//@revisions: private all
+//@[private] rustc-env:CLIPPY_CONF_DIR=tests/ui-toml/ref_option/private
+//@[all] rustc-env:CLIPPY_CONF_DIR=tests/ui-toml/ref_option/all
+
+#![allow(unused, clippy::needless_lifetimes, clippy::borrowed_box)]
+#![warn(clippy::ref_option)]
+
+fn opt_u8(a: &Option<u8>) {}
+//~^ ref_option
+fn opt_gen<T>(a: &Option<T>) {}
+//~^ ref_option
+fn opt_string(a: &std::option::Option<String>) {}
+//~^ ref_option
+fn ret_u8<'a>(p: &'a str) -> &'a Option<u8> {
+    //~^ ref_option
+    panic!()
+}
+fn ret_u8_static() -> &'static Option<u8> {
+    //~^ ref_option
+    panic!()
+}
+fn mult_string(a: &Option<String>, b: &Option<Vec<u8>>) {}
+//~^ ref_option
+fn ret_box<'a>() -> &'a Option<Box<u8>> {
+    //~^ ref_option
+    panic!()
+}
+
+pub fn pub_opt_string(a: &Option<String>) {}
+//~[all]^ ref_option
+pub fn pub_mult_string(a: &Option<String>, b: &Option<Vec<u8>>) {}
+//~[all]^ ref_option
+
+pub struct PubStruct;
+
+impl PubStruct {
+    pub fn pub_opt_params(&self, a: &Option<()>) {}
+    //~[all]^ ref_option
+    pub fn pub_opt_ret(&self) -> &Option<String> {
+        //~[all]^ ref_option
+        panic!()
+    }
+
+    fn private_opt_params(&self, a: &Option<()>) {}
+    //~^ ref_option
+    fn private_opt_ret(&self) -> &Option<String> {
+        //~^ ref_option
+        panic!()
+    }
+}
+
+// valid, don't change
+fn mut_u8(a: &mut Option<u8>) {}
+pub fn pub_mut_u8(a: &mut Option<String>) {}
+
+// might be good to catch in the future
+fn mut_u8_ref(a: &mut &Option<u8>) {}
+pub fn pub_mut_u8_ref(a: &mut &Option<String>) {}
+fn lambdas() {
+    // Not handled for now, not sure if we should
+    let x = |a: &Option<String>| {};
+    let x = |a: &Option<String>| -> &Option<String> { panic!() };
+}
+
+pub mod external {
+    proc_macros::external!(
+        fn opt_u8(a: &Option<u8>) {}
+        fn ret_u8<'a>(p: &'a str) -> &'a Option<u8> {
+            panic!()
+        }
+        pub fn pub_opt_u8(a: &Option<u8>) {}
+
+        pub struct PubStruct;
+        impl PubStruct {
+            pub fn pub_opt_params(&self, a: &Option<()>) {}
+            pub fn pub_opt_ret(&self) -> &Option<String> {
+                panic!()
+            }
+
+            fn private_opt_params(&self, a: &Option<()>) {}
+            fn private_opt_ret(&self) -> &Option<String> {
+                panic!()
+            }
+        }
+    );
+}
+
+pub mod proc_macros {
+    proc_macros::with_span!(
+        span
+
+        fn opt_u8(a: &Option<u8>) {}
+        fn ret_u8<'a>(p: &'a str) -> &'a Option<u8> {
+            panic!()
+        }
+        pub fn pub_opt_u8(a: &Option<u8>) {}
+
+        pub struct PubStruct;
+        impl PubStruct {
+            pub fn pub_opt_params(&self, a: &Option<()>) {}
+            pub fn pub_opt_ret(&self) -> &Option<String> {
+                panic!()
+            }
+
+            fn private_opt_params(&self, a: &Option<()>) {}
+            fn private_opt_ret(&self) -> &Option<String> {
+                panic!()
+            }
+        }
+    );
+}
+
+fn main() {}
diff --git a/src/tools/clippy/tests/ui/ref_option/ref_option_traits.all.stderr b/src/tools/clippy/tests/ui-toml/ref_option/ref_option_traits.all.stderr
index 886bf2b0349..602e148be60 100644
--- a/src/tools/clippy/tests/ui/ref_option/ref_option_traits.all.stderr
+++ b/src/tools/clippy/tests/ui-toml/ref_option/ref_option_traits.all.stderr
@@ -1,5 +1,5 @@
 error: it is more idiomatic to use `Option<&T>` instead of `&Option<T>`
-  --> tests/ui/ref_option/ref_option_traits.rs:9:5
+  --> tests/ui-toml/ref_option/ref_option_traits.rs:10:5
    |
 LL |     fn pub_trait_opt(&self, a: &Option<Vec<u8>>);
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^----------------^^
@@ -10,7 +10,7 @@ LL |     fn pub_trait_opt(&self, a: &Option<Vec<u8>>);
    = help: to override `-D warnings` add `#[allow(clippy::ref_option)]`
 
 error: it is more idiomatic to use `Option<&T>` instead of `&Option<T>`
-  --> tests/ui/ref_option/ref_option_traits.rs:11:5
+  --> tests/ui-toml/ref_option/ref_option_traits.rs:12:5
    |
 LL |     fn pub_trait_ret(&self) -> &Option<Vec<u8>>;
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^----------------^
@@ -18,7 +18,7 @@ LL |     fn pub_trait_ret(&self) -> &Option<Vec<u8>>;
    |                                help: change this to: `Option<&Vec<u8>>`
 
 error: it is more idiomatic to use `Option<&T>` instead of `&Option<T>`
-  --> tests/ui/ref_option/ref_option_traits.rs:16:5
+  --> tests/ui-toml/ref_option/ref_option_traits.rs:17:5
    |
 LL |     fn trait_opt(&self, a: &Option<String>);
    |     ^^^^^^^^^^^^^^^^^^^^^^^---------------^^
@@ -26,7 +26,7 @@ LL |     fn trait_opt(&self, a: &Option<String>);
    |                            help: change this to: `Option<&String>`
 
 error: it is more idiomatic to use `Option<&T>` instead of `&Option<T>`
-  --> tests/ui/ref_option/ref_option_traits.rs:18:5
+  --> tests/ui-toml/ref_option/ref_option_traits.rs:19:5
    |
 LL |     fn trait_ret(&self) -> &Option<String>;
    |     ^^^^^^^^^^^^^^^^^^^^^^^---------------^
diff --git a/src/tools/clippy/tests/ui/ref_option/ref_option_traits.private.stderr b/src/tools/clippy/tests/ui-toml/ref_option/ref_option_traits.private.stderr
index cfab7fa5734..20bea400edf 100644
--- a/src/tools/clippy/tests/ui/ref_option/ref_option_traits.private.stderr
+++ b/src/tools/clippy/tests/ui-toml/ref_option/ref_option_traits.private.stderr
@@ -1,5 +1,5 @@
 error: it is more idiomatic to use `Option<&T>` instead of `&Option<T>`
-  --> tests/ui/ref_option/ref_option_traits.rs:16:5
+  --> tests/ui-toml/ref_option/ref_option_traits.rs:17:5
    |
 LL |     fn trait_opt(&self, a: &Option<String>);
    |     ^^^^^^^^^^^^^^^^^^^^^^^---------------^^
@@ -10,7 +10,7 @@ LL |     fn trait_opt(&self, a: &Option<String>);
    = help: to override `-D warnings` add `#[allow(clippy::ref_option)]`
 
 error: it is more idiomatic to use `Option<&T>` instead of `&Option<T>`
-  --> tests/ui/ref_option/ref_option_traits.rs:18:5
+  --> tests/ui-toml/ref_option/ref_option_traits.rs:19:5
    |
 LL |     fn trait_ret(&self) -> &Option<String>;
    |     ^^^^^^^^^^^^^^^^^^^^^^^---------------^
diff --git a/src/tools/clippy/tests/ui-toml/ref_option/ref_option_traits.rs b/src/tools/clippy/tests/ui-toml/ref_option/ref_option_traits.rs
new file mode 100644
index 00000000000..e1477d7f846
--- /dev/null
+++ b/src/tools/clippy/tests/ui-toml/ref_option/ref_option_traits.rs
@@ -0,0 +1,71 @@
+//@no-rustfix: fixes are only done to traits, not the impls
+//@aux-build:../../ui/auxiliary/proc_macros.rs
+//@revisions: private all
+//@[private] rustc-env:CLIPPY_CONF_DIR=tests/ui-toml/ref_option/private
+//@[all] rustc-env:CLIPPY_CONF_DIR=tests/ui-toml/ref_option/all
+
+#![warn(clippy::ref_option)]
+
+pub trait PubTrait {
+    fn pub_trait_opt(&self, a: &Option<Vec<u8>>);
+    //~[all]^ ref_option
+    fn pub_trait_ret(&self) -> &Option<Vec<u8>>;
+    //~[all]^ ref_option
+}
+
+trait PrivateTrait {
+    fn trait_opt(&self, a: &Option<String>);
+    //~^ ref_option
+    fn trait_ret(&self) -> &Option<String>;
+    //~^ ref_option
+}
+
+pub struct PubStruct;
+
+impl PubTrait for PubStruct {
+    fn pub_trait_opt(&self, a: &Option<Vec<u8>>) {}
+    fn pub_trait_ret(&self) -> &Option<Vec<u8>> {
+        panic!()
+    }
+}
+
+struct PrivateStruct;
+
+impl PrivateTrait for PrivateStruct {
+    fn trait_opt(&self, a: &Option<String>) {}
+    fn trait_ret(&self) -> &Option<String> {
+        panic!()
+    }
+}
+
+pub mod external {
+    proc_macros::external!(
+        pub trait PubTrait {
+            fn pub_trait_opt(&self, a: &Option<Vec<u8>>);
+            fn pub_trait_ret(&self) -> &Option<Vec<u8>>;
+        }
+
+        trait PrivateTrait {
+            fn trait_opt(&self, a: &Option<String>);
+            fn trait_ret(&self) -> &Option<String>;
+        }
+    );
+}
+
+pub mod proc_macros {
+    proc_macros::with_span!(
+        span
+
+        pub trait PubTrait {
+            fn pub_trait_opt(&self, a: &Option<Vec<u8>>);
+            fn pub_trait_ret(&self) -> &Option<Vec<u8>>;
+        }
+
+        trait PrivateTrait {
+            fn trait_opt(&self, a: &Option<String>);
+            fn trait_ret(&self) -> &Option<String>;
+        }
+    );
+}
+
+fn main() {}
diff --git a/src/tools/clippy/tests/ui/as_underscore_unfixable.rs b/src/tools/clippy/tests/ui/as_underscore_unfixable.rs
new file mode 100644
index 00000000000..854feca7174
--- /dev/null
+++ b/src/tools/clippy/tests/ui/as_underscore_unfixable.rs
@@ -0,0 +1,14 @@
+//@no-rustfix
+
+#![warn(clippy::as_underscore)]
+
+fn main() {
+    // From issue #15282
+    let f = async || ();
+    let _: Box<dyn FnOnce() -> _> = Box::new(f) as _;
+    //~^ as_underscore
+
+    let barr = || (|| ());
+    let _: Box<dyn Fn() -> _> = Box::new(barr) as _;
+    //~^ as_underscore
+}
diff --git a/src/tools/clippy/tests/ui/as_underscore_unfixable.stderr b/src/tools/clippy/tests/ui/as_underscore_unfixable.stderr
new file mode 100644
index 00000000000..7385bea5c65
--- /dev/null
+++ b/src/tools/clippy/tests/ui/as_underscore_unfixable.stderr
@@ -0,0 +1,20 @@
+error: using `as _` conversion
+  --> tests/ui/as_underscore_unfixable.rs:8:37
+   |
+LL |     let _: Box<dyn FnOnce() -> _> = Box::new(f) as _;
+   |                                     ^^^^^^^^^^^^^^^^
+   |
+   = help: consider giving the type explicitly
+   = note: `-D clippy::as-underscore` implied by `-D warnings`
+   = help: to override `-D warnings` add `#[allow(clippy::as_underscore)]`
+
+error: using `as _` conversion
+  --> tests/ui/as_underscore_unfixable.rs:12:33
+   |
+LL |     let _: Box<dyn Fn() -> _> = Box::new(barr) as _;
+   |                                 ^^^^^^^^^^^^^^^^^^^
+   |
+   = help: consider giving the type explicitly
+
+error: aborting due to 2 previous errors
+
diff --git a/src/tools/clippy/tests/ui/cast.rs b/src/tools/clippy/tests/ui/cast.rs
index 525be821650..fab02bf7b24 100644
--- a/src/tools/clippy/tests/ui/cast.rs
+++ b/src/tools/clippy/tests/ui/cast.rs
@@ -569,3 +569,16 @@ fn issue12721() {
     (255 % 999999u64) as u8;
     //~^ cast_possible_truncation
 }
+
+mod issue14150 {
+    #[clippy::msrv = "1.87"]
+    fn msrv_supports_cast_signed() {
+        _ = 1u8 as i8;
+        //~^ cast_possible_wrap
+    }
+    #[clippy::msrv = "1.86"]
+    fn msrv_doesnt_supports_cast_signed() {
+        _ = 1u8 as i8;
+        //~^ cast_possible_wrap
+    }
+}
diff --git a/src/tools/clippy/tests/ui/cast.stderr b/src/tools/clippy/tests/ui/cast.stderr
index 1cb30d95667..8c48855123f 100644
--- a/src/tools/clippy/tests/ui/cast.stderr
+++ b/src/tools/clippy/tests/ui/cast.stderr
@@ -194,7 +194,7 @@ error: casting `u8` to `i8` may wrap around the value
   --> tests/ui/cast.rs:88:5
    |
 LL |     1u8 as i8;
-   |     ^^^^^^^^^
+   |     ^^^^^^^^^ help: if this is intentional, use `cast_signed()` instead: `1u8.cast_signed()`
    |
    = note: `-D clippy::cast-possible-wrap` implied by `-D warnings`
    = help: to override `-D warnings` add `#[allow(clippy::cast_possible_wrap)]`
@@ -203,25 +203,25 @@ error: casting `u16` to `i16` may wrap around the value
   --> tests/ui/cast.rs:91:5
    |
 LL |     1u16 as i16;
-   |     ^^^^^^^^^^^
+   |     ^^^^^^^^^^^ help: if this is intentional, use `cast_signed()` instead: `1u16.cast_signed()`
 
 error: casting `u32` to `i32` may wrap around the value
   --> tests/ui/cast.rs:94:5
    |
 LL |     1u32 as i32;
-   |     ^^^^^^^^^^^
+   |     ^^^^^^^^^^^ help: if this is intentional, use `cast_signed()` instead: `1u32.cast_signed()`
 
 error: casting `u64` to `i64` may wrap around the value
   --> tests/ui/cast.rs:97:5
    |
 LL |     1u64 as i64;
-   |     ^^^^^^^^^^^
+   |     ^^^^^^^^^^^ help: if this is intentional, use `cast_signed()` instead: `1u64.cast_signed()`
 
 error: casting `usize` to `isize` may wrap around the value
   --> tests/ui/cast.rs:100:5
    |
 LL |     1usize as isize;
-   |     ^^^^^^^^^^^^^^^
+   |     ^^^^^^^^^^^^^^^ help: if this is intentional, use `cast_signed()` instead: `1usize.cast_signed()`
 
 error: casting `usize` to `i8` may truncate the value
   --> tests/ui/cast.rs:104:5
@@ -321,43 +321,43 @@ error: casting `i32` to `u32` may lose the sign of the value
   --> tests/ui/cast.rs:138:5
    |
 LL |     -1i32 as u32;
-   |     ^^^^^^^^^^^^
+   |     ^^^^^^^^^^^^ help: if this is intentional, use `cast_unsigned()` instead: `(-1i32).cast_unsigned()`
 
 error: casting `isize` to `usize` may lose the sign of the value
   --> tests/ui/cast.rs:142:5
    |
 LL |     -1isize as usize;
-   |     ^^^^^^^^^^^^^^^^
+   |     ^^^^^^^^^^^^^^^^ help: if this is intentional, use `cast_unsigned()` instead: `(-1isize).cast_unsigned()`
 
 error: casting `i8` to `u8` may lose the sign of the value
   --> tests/ui/cast.rs:154:5
    |
 LL |     (i8::MIN).abs() as u8;
-   |     ^^^^^^^^^^^^^^^^^^^^^
+   |     ^^^^^^^^^^^^^^^^^^^^^ help: if this is intentional, use `cast_unsigned()` instead: `(i8::MIN).abs().cast_unsigned()`
 
 error: casting `i64` to `u64` may lose the sign of the value
   --> tests/ui/cast.rs:159:5
    |
 LL |     (-1i64).abs() as u64;
-   |     ^^^^^^^^^^^^^^^^^^^^
+   |     ^^^^^^^^^^^^^^^^^^^^ help: if this is intentional, use `cast_unsigned()` instead: `(-1i64).abs().cast_unsigned()`
 
 error: casting `isize` to `usize` may lose the sign of the value
   --> tests/ui/cast.rs:161:5
    |
 LL |     (-1isize).abs() as usize;
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^ help: if this is intentional, use `cast_unsigned()` instead: `(-1isize).abs().cast_unsigned()`
 
 error: casting `i64` to `u64` may lose the sign of the value
   --> tests/ui/cast.rs:169:5
    |
 LL |     (unsafe { (-1i64).checked_abs().unwrap_unchecked() }) as u64;
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: if this is intentional, use `cast_unsigned()` instead: `(unsafe { (-1i64).checked_abs().unwrap_unchecked() }).cast_unsigned()`
 
 error: casting `i64` to `u64` may lose the sign of the value
   --> tests/ui/cast.rs:185:5
    |
 LL |     (unsafe { (-1i64).checked_isqrt().unwrap_unchecked() }) as u64;
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: if this is intentional, use `cast_unsigned()` instead: `(unsafe { (-1i64).checked_isqrt().unwrap_unchecked() }).cast_unsigned()`
 
 error: casting `i64` to `i8` may truncate the value
   --> tests/ui/cast.rs:237:5
@@ -495,79 +495,79 @@ error: casting `i32` to `u32` may lose the sign of the value
   --> tests/ui/cast.rs:438:9
    |
 LL |         (x * x) as u32;
-   |         ^^^^^^^^^^^^^^
+   |         ^^^^^^^^^^^^^^ help: if this is intentional, use `cast_unsigned()` instead: `(x * x).cast_unsigned()`
 
 error: casting `i32` to `u32` may lose the sign of the value
   --> tests/ui/cast.rs:444:32
    |
 LL |     let _a = |x: i32| -> u32 { (x * x * x * x) as u32 };
-   |                                ^^^^^^^^^^^^^^^^^^^^^^
+   |                                ^^^^^^^^^^^^^^^^^^^^^^ help: if this is intentional, use `cast_unsigned()` instead: `(x * x * x * x).cast_unsigned()`
 
 error: casting `i32` to `u32` may lose the sign of the value
   --> tests/ui/cast.rs:447:5
    |
 LL |     (2_i32).checked_pow(3).unwrap() as u32;
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: if this is intentional, use `cast_unsigned()` instead: `(2_i32).checked_pow(3).unwrap().cast_unsigned()`
 
 error: casting `i32` to `u32` may lose the sign of the value
   --> tests/ui/cast.rs:449:5
    |
 LL |     (-2_i32).pow(3) as u32;
-   |     ^^^^^^^^^^^^^^^^^^^^^^
+   |     ^^^^^^^^^^^^^^^^^^^^^^ help: if this is intentional, use `cast_unsigned()` instead: `(-2_i32).pow(3).cast_unsigned()`
 
 error: casting `i32` to `u32` may lose the sign of the value
   --> tests/ui/cast.rs:454:5
    |
 LL |     (-5_i32 % 2) as u32;
-   |     ^^^^^^^^^^^^^^^^^^^
+   |     ^^^^^^^^^^^^^^^^^^^ help: if this is intentional, use `cast_unsigned()` instead: `(-5_i32 % 2).cast_unsigned()`
 
 error: casting `i32` to `u32` may lose the sign of the value
   --> tests/ui/cast.rs:457:5
    |
 LL |     (-5_i32 % -2) as u32;
-   |     ^^^^^^^^^^^^^^^^^^^^
+   |     ^^^^^^^^^^^^^^^^^^^^ help: if this is intentional, use `cast_unsigned()` instead: `(-5_i32 % -2).cast_unsigned()`
 
 error: casting `i32` to `u32` may lose the sign of the value
   --> tests/ui/cast.rs:461:5
    |
 LL |     (-2_i32 >> 1) as u32;
-   |     ^^^^^^^^^^^^^^^^^^^^
+   |     ^^^^^^^^^^^^^^^^^^^^ help: if this is intentional, use `cast_unsigned()` instead: `(-2_i32 >> 1).cast_unsigned()`
 
 error: casting `i32` to `u32` may lose the sign of the value
   --> tests/ui/cast.rs:465:5
    |
 LL |     (x * x) as u32;
-   |     ^^^^^^^^^^^^^^
+   |     ^^^^^^^^^^^^^^ help: if this is intentional, use `cast_unsigned()` instead: `(x * x).cast_unsigned()`
 
 error: casting `i32` to `u32` may lose the sign of the value
   --> tests/ui/cast.rs:467:5
    |
 LL |     (x * x * x) as u32;
-   |     ^^^^^^^^^^^^^^^^^^
+   |     ^^^^^^^^^^^^^^^^^^ help: if this is intentional, use `cast_unsigned()` instead: `(x * x * x).cast_unsigned()`
 
 error: casting `i16` to `u16` may lose the sign of the value
   --> tests/ui/cast.rs:471:5
    |
 LL |     (y * y * y * y * -2) as u16;
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: if this is intentional, use `cast_unsigned()` instead: `(y * y * y * y * -2).cast_unsigned()`
 
 error: casting `i16` to `u16` may lose the sign of the value
   --> tests/ui/cast.rs:474:5
    |
 LL |     (y * y * y / y * 2) as u16;
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: if this is intentional, use `cast_unsigned()` instead: `(y * y * y / y * 2).cast_unsigned()`
 
 error: casting `i16` to `u16` may lose the sign of the value
   --> tests/ui/cast.rs:476:5
    |
 LL |     (y * y / y * 2) as u16;
-   |     ^^^^^^^^^^^^^^^^^^^^^^
+   |     ^^^^^^^^^^^^^^^^^^^^^^ help: if this is intentional, use `cast_unsigned()` instead: `(y * y / y * 2).cast_unsigned()`
 
 error: casting `i16` to `u16` may lose the sign of the value
   --> tests/ui/cast.rs:479:5
    |
 LL |     (y / y * y * -2) as u16;
-   |     ^^^^^^^^^^^^^^^^^^^^^^^
+   |     ^^^^^^^^^^^^^^^^^^^^^^^ help: if this is intentional, use `cast_unsigned()` instead: `(y / y * y * -2).cast_unsigned()`
 
 error: equal expressions as operands to `/`
   --> tests/ui/cast.rs:479:6
@@ -581,97 +581,97 @@ error: casting `i16` to `u16` may lose the sign of the value
   --> tests/ui/cast.rs:483:5
    |
 LL |     (y + y + y + -2) as u16;
-   |     ^^^^^^^^^^^^^^^^^^^^^^^
+   |     ^^^^^^^^^^^^^^^^^^^^^^^ help: if this is intentional, use `cast_unsigned()` instead: `(y + y + y + -2).cast_unsigned()`
 
 error: casting `i16` to `u16` may lose the sign of the value
   --> tests/ui/cast.rs:486:5
    |
 LL |     (y + y + y + 2) as u16;
-   |     ^^^^^^^^^^^^^^^^^^^^^^
+   |     ^^^^^^^^^^^^^^^^^^^^^^ help: if this is intentional, use `cast_unsigned()` instead: `(y + y + y + 2).cast_unsigned()`
 
 error: casting `i16` to `u16` may lose the sign of the value
   --> tests/ui/cast.rs:490:5
    |
 LL |     (z + -2) as u16;
-   |     ^^^^^^^^^^^^^^^
+   |     ^^^^^^^^^^^^^^^ help: if this is intentional, use `cast_unsigned()` instead: `(z + -2).cast_unsigned()`
 
 error: casting `i16` to `u16` may lose the sign of the value
   --> tests/ui/cast.rs:493:5
    |
 LL |     (z + z + 2) as u16;
-   |     ^^^^^^^^^^^^^^^^^^
+   |     ^^^^^^^^^^^^^^^^^^ help: if this is intentional, use `cast_unsigned()` instead: `(z + z + 2).cast_unsigned()`
 
 error: casting `i32` to `u32` may lose the sign of the value
   --> tests/ui/cast.rs:497:9
    |
 LL |         (a * a * b * b * c * c) as u32;
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: if this is intentional, use `cast_unsigned()` instead: `(a * a * b * b * c * c).cast_unsigned()`
 
 error: casting `i32` to `u32` may lose the sign of the value
   --> tests/ui/cast.rs:499:9
    |
 LL |         (a * b * c) as u32;
-   |         ^^^^^^^^^^^^^^^^^^
+   |         ^^^^^^^^^^^^^^^^^^ help: if this is intentional, use `cast_unsigned()` instead: `(a * b * c).cast_unsigned()`
 
 error: casting `i32` to `u32` may lose the sign of the value
   --> tests/ui/cast.rs:502:9
    |
 LL |         (a * -b * c) as u32;
-   |         ^^^^^^^^^^^^^^^^^^^
+   |         ^^^^^^^^^^^^^^^^^^^ help: if this is intentional, use `cast_unsigned()` instead: `(a * -b * c).cast_unsigned()`
 
 error: casting `i32` to `u32` may lose the sign of the value
   --> tests/ui/cast.rs:505:9
    |
 LL |         (a * b * c * c) as u32;
-   |         ^^^^^^^^^^^^^^^^^^^^^^
+   |         ^^^^^^^^^^^^^^^^^^^^^^ help: if this is intentional, use `cast_unsigned()` instead: `(a * b * c * c).cast_unsigned()`
 
 error: casting `i32` to `u32` may lose the sign of the value
   --> tests/ui/cast.rs:507:9
    |
 LL |         (a * -2) as u32;
-   |         ^^^^^^^^^^^^^^^
+   |         ^^^^^^^^^^^^^^^ help: if this is intentional, use `cast_unsigned()` instead: `(a * -2).cast_unsigned()`
 
 error: casting `i32` to `u32` may lose the sign of the value
   --> tests/ui/cast.rs:510:9
    |
 LL |         (a * b * c * -2) as u32;
-   |         ^^^^^^^^^^^^^^^^^^^^^^^
+   |         ^^^^^^^^^^^^^^^^^^^^^^^ help: if this is intentional, use `cast_unsigned()` instead: `(a * b * c * -2).cast_unsigned()`
 
 error: casting `i32` to `u32` may lose the sign of the value
   --> tests/ui/cast.rs:513:9
    |
 LL |         (a / b) as u32;
-   |         ^^^^^^^^^^^^^^
+   |         ^^^^^^^^^^^^^^ help: if this is intentional, use `cast_unsigned()` instead: `(a / b).cast_unsigned()`
 
 error: casting `i32` to `u32` may lose the sign of the value
   --> tests/ui/cast.rs:515:9
    |
 LL |         (a / b * c) as u32;
-   |         ^^^^^^^^^^^^^^^^^^
+   |         ^^^^^^^^^^^^^^^^^^ help: if this is intentional, use `cast_unsigned()` instead: `(a / b * c).cast_unsigned()`
 
 error: casting `i32` to `u32` may lose the sign of the value
   --> tests/ui/cast.rs:518:9
    |
 LL |         (a / b + b * c) as u32;
-   |         ^^^^^^^^^^^^^^^^^^^^^^
+   |         ^^^^^^^^^^^^^^^^^^^^^^ help: if this is intentional, use `cast_unsigned()` instead: `(a / b + b * c).cast_unsigned()`
 
 error: casting `i32` to `u32` may lose the sign of the value
   --> tests/ui/cast.rs:521:9
    |
 LL |         a.saturating_pow(3) as u32;
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: if this is intentional, use `cast_unsigned()` instead: `a.saturating_pow(3).cast_unsigned()`
 
 error: casting `i32` to `u32` may lose the sign of the value
   --> tests/ui/cast.rs:524:9
    |
 LL |         (a.abs() * b.pow(2) / c.abs()) as u32
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: if this is intentional, use `cast_unsigned()` instead: `(a.abs() * b.pow(2) / c.abs()).cast_unsigned()`
 
 error: casting `i32` to `u32` may lose the sign of the value
   --> tests/ui/cast.rs:532:21
    |
 LL |             let _ = i32::MIN as u32; // cast_sign_loss
-   |                     ^^^^^^^^^^^^^^^
+   |                     ^^^^^^^^^^^^^^^ help: if this is intentional, use `cast_unsigned()` instead: `i32::MIN.cast_unsigned()`
 ...
 LL |     m!();
    |     ---- in this macro invocation
@@ -752,5 +752,17 @@ LL -     (255 % 999999u64) as u8;
 LL +     u8::try_from(255 % 999999u64);
    |
 
-error: aborting due to 92 previous errors
+error: casting `u8` to `i8` may wrap around the value
+  --> tests/ui/cast.rs:576:13
+   |
+LL |         _ = 1u8 as i8;
+   |             ^^^^^^^^^ help: if this is intentional, use `cast_signed()` instead: `1u8.cast_signed()`
+
+error: casting `u8` to `i8` may wrap around the value
+  --> tests/ui/cast.rs:581:13
+   |
+LL |         _ = 1u8 as i8;
+   |             ^^^^^^^^^
+
+error: aborting due to 94 previous errors
 
diff --git a/src/tools/clippy/tests/ui/checked_unwrap/simple_conditionals.rs b/src/tools/clippy/tests/ui/checked_unwrap/simple_conditionals.rs
index 785b2473c05..bba264080b4 100644
--- a/src/tools/clippy/tests/ui/checked_unwrap/simple_conditionals.rs
+++ b/src/tools/clippy/tests/ui/checked_unwrap/simple_conditionals.rs
@@ -273,6 +273,28 @@ const ISSUE14763: fn(Option<String>) = |x| {
     }
 };
 
+fn issue12295() {
+    let option = Some(());
+
+    if option.is_some() {
+        println!("{:?}", option.unwrap());
+        //~^ unnecessary_unwrap
+    } else {
+        println!("{:?}", option.unwrap());
+        //~^ panicking_unwrap
+    }
+
+    let result = Ok::<(), ()>(());
+
+    if result.is_ok() {
+        println!("{:?}", result.unwrap());
+        //~^ unnecessary_unwrap
+    } else {
+        println!("{:?}", result.unwrap());
+        //~^ panicking_unwrap
+    }
+}
+
 fn check_expect() {
     let x = Some(());
     if x.is_some() {
diff --git a/src/tools/clippy/tests/ui/checked_unwrap/simple_conditionals.stderr b/src/tools/clippy/tests/ui/checked_unwrap/simple_conditionals.stderr
index 939b509d85c..2007a859541 100644
--- a/src/tools/clippy/tests/ui/checked_unwrap/simple_conditionals.stderr
+++ b/src/tools/clippy/tests/ui/checked_unwrap/simple_conditionals.stderr
@@ -322,6 +322,40 @@ LL |         if x.is_some() {
 LL |             _ = x.unwrap();
    |                 ^^^^^^^^^^
 
+error: called `unwrap` on `option` after checking its variant with `is_some`
+  --> tests/ui/checked_unwrap/simple_conditionals.rs:280:26
+   |
+LL |     if option.is_some() {
+   |     ------------------- help: try: `if let Some(<item>) = option`
+LL |         println!("{:?}", option.unwrap());
+   |                          ^^^^^^^^^^^^^^^
+
+error: this call to `unwrap()` will always panic
+  --> tests/ui/checked_unwrap/simple_conditionals.rs:283:26
+   |
+LL |     if option.is_some() {
+   |        ---------------- because of this check
+...
+LL |         println!("{:?}", option.unwrap());
+   |                          ^^^^^^^^^^^^^^^
+
+error: called `unwrap` on `result` after checking its variant with `is_ok`
+  --> tests/ui/checked_unwrap/simple_conditionals.rs:290:26
+   |
+LL |     if result.is_ok() {
+   |     ----------------- help: try: `if let Ok(<item>) = result`
+LL |         println!("{:?}", result.unwrap());
+   |                          ^^^^^^^^^^^^^^^
+
+error: this call to `unwrap()` will always panic
+  --> tests/ui/checked_unwrap/simple_conditionals.rs:293:26
+   |
+LL |     if result.is_ok() {
+   |        -------------- because of this check
+...
+LL |         println!("{:?}", result.unwrap());
+   |                          ^^^^^^^^^^^^^^^
+
 error: creating a shared reference to mutable static
   --> tests/ui/checked_unwrap/simple_conditionals.rs:183:12
    |
@@ -332,5 +366,5 @@ LL |         if X.is_some() {
    = note: shared references to mutable statics are dangerous; it's undefined behavior if the static is mutated or if a mutable reference is created for it while the shared reference lives
    = note: `#[deny(static_mut_refs)]` (part of `#[deny(rust_2024_compatibility)]`) on by default
 
-error: aborting due to 36 previous errors
+error: aborting due to 40 previous errors
 
diff --git a/src/tools/clippy/tests/ui/crashes/ice-15657.rs b/src/tools/clippy/tests/ui/crashes/ice-15657.rs
new file mode 100644
index 00000000000..c6f6506cd8d
--- /dev/null
+++ b/src/tools/clippy/tests/ui/crashes/ice-15657.rs
@@ -0,0 +1,11 @@
+//@check-pass
+#![warn(clippy::len_zero)]
+
+pub struct S1;
+pub struct S2;
+
+impl S1 {
+    pub fn len(&self) -> S2 {
+        S2
+    }
+}
diff --git a/src/tools/clippy/tests/ui/crashes/ice-15666.fixed b/src/tools/clippy/tests/ui/crashes/ice-15666.fixed
new file mode 100644
index 00000000000..53b618765c0
--- /dev/null
+++ b/src/tools/clippy/tests/ui/crashes/ice-15666.fixed
@@ -0,0 +1,6 @@
+#![warn(clippy::elidable_lifetime_names)]
+
+struct UnitVariantAccess<'a, 'b, 's>(&'a &'b &'s ());
+trait Trait<'de> {}
+impl<'de> Trait<'de> for UnitVariantAccess<'_, 'de, '_> {}
+//~^ elidable_lifetime_names
diff --git a/src/tools/clippy/tests/ui/crashes/ice-15666.rs b/src/tools/clippy/tests/ui/crashes/ice-15666.rs
new file mode 100644
index 00000000000..1414b3d2035
--- /dev/null
+++ b/src/tools/clippy/tests/ui/crashes/ice-15666.rs
@@ -0,0 +1,6 @@
+#![warn(clippy::elidable_lifetime_names)]
+
+struct UnitVariantAccess<'a, 'b, 's>(&'a &'b &'s ());
+trait Trait<'de> {}
+impl<'de, 'a, 's> Trait<'de> for UnitVariantAccess<'a, 'de, 's> {}
+//~^ elidable_lifetime_names
diff --git a/src/tools/clippy/tests/ui/crashes/ice-15666.stderr b/src/tools/clippy/tests/ui/crashes/ice-15666.stderr
new file mode 100644
index 00000000000..b417c09b5c6
--- /dev/null
+++ b/src/tools/clippy/tests/ui/crashes/ice-15666.stderr
@@ -0,0 +1,16 @@
+error: the following explicit lifetimes could be elided: 'a, 's
+  --> tests/ui/crashes/ice-15666.rs:5:11
+   |
+LL | impl<'de, 'a, 's> Trait<'de> for UnitVariantAccess<'a, 'de, 's> {}
+   |           ^^  ^^                                   ^^       ^^
+   |
+   = note: `-D clippy::elidable-lifetime-names` implied by `-D warnings`
+   = help: to override `-D warnings` add `#[allow(clippy::elidable_lifetime_names)]`
+help: elide the lifetimes
+   |
+LL - impl<'de, 'a, 's> Trait<'de> for UnitVariantAccess<'a, 'de, 's> {}
+LL + impl<'de> Trait<'de> for UnitVariantAccess<'_, 'de, '_> {}
+   |
+
+error: aborting due to 1 previous error
+
diff --git a/src/tools/clippy/tests/ui/elidable_lifetime_names.fixed b/src/tools/clippy/tests/ui/elidable_lifetime_names.fixed
index abeee5c4cef..a6c4cb7a36a 100644
--- a/src/tools/clippy/tests/ui/elidable_lifetime_names.fixed
+++ b/src/tools/clippy/tests/ui/elidable_lifetime_names.fixed
@@ -192,3 +192,85 @@ mod issue13923 {
         x.b
     }
 }
+
+fn issue15666_original() {
+    struct UnitVariantAccess<'a, 'b, 's>(&'a &'b &'s ());
+
+    trait Trait<'de> {}
+
+    //~v elidable_lifetime_names
+    impl<'de> Trait<'de> for UnitVariantAccess<'_, 'de, '_> {}
+    //        ^^  ^^                                   ^^       ^^
+}
+
+#[allow(clippy::upper_case_acronyms)]
+fn issue15666() {
+    struct S1<'a>(&'a ());
+    struct S2<'a, 'b>(&'a &'b ());
+    struct S3<'a, 'b, 'c>(&'a &'b &'c ());
+
+    trait T {}
+    trait TA<'a> {}
+    trait TB<'b> {}
+    trait TC<'c> {}
+    trait TAB<'a, 'b> {}
+    trait TAC<'a, 'c> {}
+    trait TBC<'b, 'c> {}
+    trait TABC<'a, 'b, 'c> {}
+
+    // 1 lifetime
+
+    impl<'a> TA<'a> for S1<'a> {}
+
+    //~v elidable_lifetime_names
+    impl T for S1<'_> {}
+    //   ^^
+
+    // 2 lifetimes
+
+    impl<'a, 'b> TAB<'a, 'b> for S2<'a, 'b> {}
+
+    //~v elidable_lifetime_names
+    impl<'a> TA<'a> for S2<'a, '_> {}
+    //       ^^
+
+    //~v elidable_lifetime_names
+    impl<'b> TB<'b> for S2<'_, 'b> {}
+    //   ^^
+
+    //~v elidable_lifetime_names
+    impl T for S2<'_, '_> {}
+    //   ^^  ^^
+
+    // 3 lifetimes
+
+    impl<'a, 'b, 'c> TABC<'a, 'b, 'c> for S3<'a, 'b, 'c> {}
+
+    //~v elidable_lifetime_names
+    impl<'a, 'b> TAB<'a, 'b> for S3<'a, 'b, '_> {}
+    //           ^^
+
+    //~v elidable_lifetime_names
+    impl<'a, 'c> TAC<'a, 'c> for S3<'a, '_, 'c> {}
+    //       ^^
+
+    //~v elidable_lifetime_names
+    impl<'a> TA<'a> for S3<'a, '_, '_> {}
+    //       ^^  ^^
+
+    //~v elidable_lifetime_names
+    impl<'b, 'c> TBC<'b, 'c> for S3<'_, 'b, 'c> {}
+    //   ^^
+
+    //~v elidable_lifetime_names
+    impl<'b> TB<'b> for S3<'_, 'b, '_> {}
+    //   ^^      ^^
+
+    //~v elidable_lifetime_names
+    impl<'c> TC<'c> for S3<'_, '_, 'c> {}
+    //   ^^  ^^
+
+    //~v elidable_lifetime_names
+    impl T for S3<'_, '_, '_> {}
+    //   ^^  ^^  ^^
+}
diff --git a/src/tools/clippy/tests/ui/elidable_lifetime_names.rs b/src/tools/clippy/tests/ui/elidable_lifetime_names.rs
index fae3577a8e9..e08056b2fb5 100644
--- a/src/tools/clippy/tests/ui/elidable_lifetime_names.rs
+++ b/src/tools/clippy/tests/ui/elidable_lifetime_names.rs
@@ -192,3 +192,85 @@ mod issue13923 {
         x.b
     }
 }
+
+fn issue15666_original() {
+    struct UnitVariantAccess<'a, 'b, 's>(&'a &'b &'s ());
+
+    trait Trait<'de> {}
+
+    //~v elidable_lifetime_names
+    impl<'de, 'a, 's> Trait<'de> for UnitVariantAccess<'a, 'de, 's> {}
+    //        ^^  ^^                                   ^^       ^^
+}
+
+#[allow(clippy::upper_case_acronyms)]
+fn issue15666() {
+    struct S1<'a>(&'a ());
+    struct S2<'a, 'b>(&'a &'b ());
+    struct S3<'a, 'b, 'c>(&'a &'b &'c ());
+
+    trait T {}
+    trait TA<'a> {}
+    trait TB<'b> {}
+    trait TC<'c> {}
+    trait TAB<'a, 'b> {}
+    trait TAC<'a, 'c> {}
+    trait TBC<'b, 'c> {}
+    trait TABC<'a, 'b, 'c> {}
+
+    // 1 lifetime
+
+    impl<'a> TA<'a> for S1<'a> {}
+
+    //~v elidable_lifetime_names
+    impl<'a> T for S1<'a> {}
+    //   ^^
+
+    // 2 lifetimes
+
+    impl<'a, 'b> TAB<'a, 'b> for S2<'a, 'b> {}
+
+    //~v elidable_lifetime_names
+    impl<'a, 'b> TA<'a> for S2<'a, 'b> {}
+    //       ^^
+
+    //~v elidable_lifetime_names
+    impl<'a, 'b> TB<'b> for S2<'a, 'b> {}
+    //   ^^
+
+    //~v elidable_lifetime_names
+    impl<'a, 'b> T for S2<'a, 'b> {}
+    //   ^^  ^^
+
+    // 3 lifetimes
+
+    impl<'a, 'b, 'c> TABC<'a, 'b, 'c> for S3<'a, 'b, 'c> {}
+
+    //~v elidable_lifetime_names
+    impl<'a, 'b, 'c> TAB<'a, 'b> for S3<'a, 'b, 'c> {}
+    //           ^^
+
+    //~v elidable_lifetime_names
+    impl<'a, 'b, 'c> TAC<'a, 'c> for S3<'a, 'b, 'c> {}
+    //       ^^
+
+    //~v elidable_lifetime_names
+    impl<'a, 'b, 'c> TA<'a> for S3<'a, 'b, 'c> {}
+    //       ^^  ^^
+
+    //~v elidable_lifetime_names
+    impl<'a, 'b, 'c> TBC<'b, 'c> for S3<'a, 'b, 'c> {}
+    //   ^^
+
+    //~v elidable_lifetime_names
+    impl<'a, 'b, 'c> TB<'b> for S3<'a, 'b, 'c> {}
+    //   ^^      ^^
+
+    //~v elidable_lifetime_names
+    impl<'a, 'b, 'c> TC<'c> for S3<'a, 'b, 'c> {}
+    //   ^^  ^^
+
+    //~v elidable_lifetime_names
+    impl<'a, 'b, 'c> T for S3<'a, 'b, 'c> {}
+    //   ^^  ^^  ^^
+}
diff --git a/src/tools/clippy/tests/ui/elidable_lifetime_names.stderr b/src/tools/clippy/tests/ui/elidable_lifetime_names.stderr
index a60dfc69756..03fe383b8f6 100644
--- a/src/tools/clippy/tests/ui/elidable_lifetime_names.stderr
+++ b/src/tools/clippy/tests/ui/elidable_lifetime_names.stderr
@@ -158,5 +158,149 @@ LL |             o: &'t str,
 LL ~         ) -> Content<'t, '_> {
    |
 
-error: aborting due to 12 previous errors
+error: the following explicit lifetimes could be elided: 'a, 's
+  --> tests/ui/elidable_lifetime_names.rs:202:15
+   |
+LL |     impl<'de, 'a, 's> Trait<'de> for UnitVariantAccess<'a, 'de, 's> {}
+   |               ^^  ^^                                   ^^       ^^
+   |
+help: elide the lifetimes
+   |
+LL -     impl<'de, 'a, 's> Trait<'de> for UnitVariantAccess<'a, 'de, 's> {}
+LL +     impl<'de> Trait<'de> for UnitVariantAccess<'_, 'de, '_> {}
+   |
+
+error: the following explicit lifetimes could be elided: 'a
+  --> tests/ui/elidable_lifetime_names.rs:226:10
+   |
+LL |     impl<'a> T for S1<'a> {}
+   |          ^^           ^^
+   |
+help: elide the lifetimes
+   |
+LL -     impl<'a> T for S1<'a> {}
+LL +     impl T for S1<'_> {}
+   |
+
+error: the following explicit lifetimes could be elided: 'b
+  --> tests/ui/elidable_lifetime_names.rs:234:14
+   |
+LL |     impl<'a, 'b> TA<'a> for S2<'a, 'b> {}
+   |              ^^                    ^^
+   |
+help: elide the lifetimes
+   |
+LL -     impl<'a, 'b> TA<'a> for S2<'a, 'b> {}
+LL +     impl<'a> TA<'a> for S2<'a, '_> {}
+   |
+
+error: the following explicit lifetimes could be elided: 'a
+  --> tests/ui/elidable_lifetime_names.rs:238:10
+   |
+LL |     impl<'a, 'b> TB<'b> for S2<'a, 'b> {}
+   |          ^^                    ^^
+   |
+help: elide the lifetimes
+   |
+LL -     impl<'a, 'b> TB<'b> for S2<'a, 'b> {}
+LL +     impl<'b> TB<'b> for S2<'_, 'b> {}
+   |
+
+error: the following explicit lifetimes could be elided: 'a, 'b
+  --> tests/ui/elidable_lifetime_names.rs:242:10
+   |
+LL |     impl<'a, 'b> T for S2<'a, 'b> {}
+   |          ^^  ^^           ^^  ^^
+   |
+help: elide the lifetimes
+   |
+LL -     impl<'a, 'b> T for S2<'a, 'b> {}
+LL +     impl T for S2<'_, '_> {}
+   |
+
+error: the following explicit lifetimes could be elided: 'c
+  --> tests/ui/elidable_lifetime_names.rs:250:18
+   |
+LL |     impl<'a, 'b, 'c> TAB<'a, 'b> for S3<'a, 'b, 'c> {}
+   |                  ^^                             ^^
+   |
+help: elide the lifetimes
+   |
+LL -     impl<'a, 'b, 'c> TAB<'a, 'b> for S3<'a, 'b, 'c> {}
+LL +     impl<'a, 'b> TAB<'a, 'b> for S3<'a, 'b, '_> {}
+   |
+
+error: the following explicit lifetimes could be elided: 'b
+  --> tests/ui/elidable_lifetime_names.rs:254:14
+   |
+LL |     impl<'a, 'b, 'c> TAC<'a, 'c> for S3<'a, 'b, 'c> {}
+   |              ^^                             ^^
+   |
+help: elide the lifetimes
+   |
+LL -     impl<'a, 'b, 'c> TAC<'a, 'c> for S3<'a, 'b, 'c> {}
+LL +     impl<'a, 'c> TAC<'a, 'c> for S3<'a, '_, 'c> {}
+   |
+
+error: the following explicit lifetimes could be elided: 'b, 'c
+  --> tests/ui/elidable_lifetime_names.rs:258:14
+   |
+LL |     impl<'a, 'b, 'c> TA<'a> for S3<'a, 'b, 'c> {}
+   |              ^^  ^^                    ^^  ^^
+   |
+help: elide the lifetimes
+   |
+LL -     impl<'a, 'b, 'c> TA<'a> for S3<'a, 'b, 'c> {}
+LL +     impl<'a> TA<'a> for S3<'a, '_, '_> {}
+   |
+
+error: the following explicit lifetimes could be elided: 'a
+  --> tests/ui/elidable_lifetime_names.rs:262:10
+   |
+LL |     impl<'a, 'b, 'c> TBC<'b, 'c> for S3<'a, 'b, 'c> {}
+   |          ^^                             ^^
+   |
+help: elide the lifetimes
+   |
+LL -     impl<'a, 'b, 'c> TBC<'b, 'c> for S3<'a, 'b, 'c> {}
+LL +     impl<'b, 'c> TBC<'b, 'c> for S3<'_, 'b, 'c> {}
+   |
+
+error: the following explicit lifetimes could be elided: 'a, 'c
+  --> tests/ui/elidable_lifetime_names.rs:266:10
+   |
+LL |     impl<'a, 'b, 'c> TB<'b> for S3<'a, 'b, 'c> {}
+   |          ^^      ^^                ^^      ^^
+   |
+help: elide the lifetimes
+   |
+LL -     impl<'a, 'b, 'c> TB<'b> for S3<'a, 'b, 'c> {}
+LL +     impl<'b> TB<'b> for S3<'_, 'b, '_> {}
+   |
+
+error: the following explicit lifetimes could be elided: 'a, 'b
+  --> tests/ui/elidable_lifetime_names.rs:270:10
+   |
+LL |     impl<'a, 'b, 'c> TC<'c> for S3<'a, 'b, 'c> {}
+   |          ^^  ^^                    ^^  ^^
+   |
+help: elide the lifetimes
+   |
+LL -     impl<'a, 'b, 'c> TC<'c> for S3<'a, 'b, 'c> {}
+LL +     impl<'c> TC<'c> for S3<'_, '_, 'c> {}
+   |
+
+error: the following explicit lifetimes could be elided: 'a, 'b, 'c
+  --> tests/ui/elidable_lifetime_names.rs:274:10
+   |
+LL |     impl<'a, 'b, 'c> T for S3<'a, 'b, 'c> {}
+   |          ^^  ^^  ^^           ^^  ^^  ^^
+   |
+help: elide the lifetimes
+   |
+LL -     impl<'a, 'b, 'c> T for S3<'a, 'b, 'c> {}
+LL +     impl T for S3<'_, '_, '_> {}
+   |
+
+error: aborting due to 24 previous errors
 
diff --git a/src/tools/clippy/tests/ui/eta.fixed b/src/tools/clippy/tests/ui/eta.fixed
index 6944a979c05..107318e5323 100644
--- a/src/tools/clippy/tests/ui/eta.fixed
+++ b/src/tools/clippy/tests/ui/eta.fixed
@@ -635,3 +635,11 @@ fn issue8817() {
         //~| HELP: replace the closure with the tuple variant itself
         .unwrap(); // just for nicer formatting
 }
+
+async fn issue13892<'a, T, F>(maybe: Option<&'a T>, visitor: F)
+where
+    F: AsyncFn(&'a T),
+    T: 'a,
+{
+    maybe.map(|x| visitor(x));
+}
diff --git a/src/tools/clippy/tests/ui/eta.rs b/src/tools/clippy/tests/ui/eta.rs
index 5bcc1cb26fd..b85e8e75153 100644
--- a/src/tools/clippy/tests/ui/eta.rs
+++ b/src/tools/clippy/tests/ui/eta.rs
@@ -635,3 +635,11 @@ fn issue8817() {
         //~| HELP: replace the closure with the tuple variant itself
         .unwrap(); // just for nicer formatting
 }
+
+async fn issue13892<'a, T, F>(maybe: Option<&'a T>, visitor: F)
+where
+    F: AsyncFn(&'a T),
+    T: 'a,
+{
+    maybe.map(|x| visitor(x));
+}
diff --git a/src/tools/clippy/tests/ui/invalid_upcast_comparisons.rs b/src/tools/clippy/tests/ui/invalid_upcast_comparisons.rs
index 4f3194869f4..88ecca65e15 100644
--- a/src/tools/clippy/tests/ui/invalid_upcast_comparisons.rs
+++ b/src/tools/clippy/tests/ui/invalid_upcast_comparisons.rs
@@ -133,3 +133,15 @@ fn main() {
 
     -5 == (u32 as i32);
 }
+
+fn issue15662() {
+    macro_rules! add_one {
+        ($x:expr) => {
+            $x + 1
+        };
+    }
+
+    let x: u8 = 1;
+    (add_one!(x) as u32) > 300;
+    //~^ invalid_upcast_comparisons
+}
diff --git a/src/tools/clippy/tests/ui/invalid_upcast_comparisons.stderr b/src/tools/clippy/tests/ui/invalid_upcast_comparisons.stderr
index ef36f18eabc..cc042a7c4b0 100644
--- a/src/tools/clippy/tests/ui/invalid_upcast_comparisons.stderr
+++ b/src/tools/clippy/tests/ui/invalid_upcast_comparisons.stderr
@@ -163,5 +163,11 @@ error: because of the numeric bounds on `u8` prior to casting, this expression i
 LL |     -5 >= (u8 as i32);
    |     ^^^^^^^^^^^^^^^^^
 
-error: aborting due to 27 previous errors
+error: because of the numeric bounds on `add_one!(x)` prior to casting, this expression is always false
+  --> tests/ui/invalid_upcast_comparisons.rs:145:5
+   |
+LL |     (add_one!(x) as u32) > 300;
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 28 previous errors
 
diff --git a/src/tools/clippy/tests/ui/iter_overeager_cloned.fixed b/src/tools/clippy/tests/ui/iter_overeager_cloned.fixed
index b0e548f1790..4171f19469a 100644
--- a/src/tools/clippy/tests/ui/iter_overeager_cloned.fixed
+++ b/src/tools/clippy/tests/ui/iter_overeager_cloned.fixed
@@ -1,4 +1,4 @@
-#![warn(clippy::iter_overeager_cloned, clippy::redundant_clone, clippy::filter_next)]
+#![warn(clippy::iter_overeager_cloned, clippy::redundant_iter_cloned, clippy::filter_next)]
 #![allow(
     dead_code,
     clippy::let_unit_value,
@@ -16,7 +16,7 @@ fn main() {
     //~^ iter_overeager_cloned
 
     let _: usize = vec.iter().filter(|x| x == &"2").count();
-    //~^ redundant_clone
+    //~^ redundant_iter_cloned
 
     let _: Vec<_> = vec.iter().take(2).cloned().collect();
     //~^ iter_overeager_cloned
@@ -77,19 +77,19 @@ fn main() {
     }
 
     let _ = vec.iter().map(|x| x.len());
-    //~^ redundant_clone
+    //~^ redundant_iter_cloned
 
     // This would fail if changed.
     let _ = vec.iter().cloned().map(|x| x + "2");
 
     let _ = vec.iter().for_each(|x| assert!(!x.is_empty()));
-    //~^ redundant_clone
+    //~^ redundant_iter_cloned
 
     let _ = vec.iter().all(|x| x.len() == 1);
-    //~^ redundant_clone
+    //~^ redundant_iter_cloned
 
     let _ = vec.iter().any(|x| x.len() == 1);
-    //~^ redundant_clone
+    //~^ redundant_iter_cloned
 
     // Should probably stay as it is.
     let _ = [0, 1, 2, 3, 4].iter().cloned().take(10);
diff --git a/src/tools/clippy/tests/ui/iter_overeager_cloned.rs b/src/tools/clippy/tests/ui/iter_overeager_cloned.rs
index cedf62a6b47..fe6aba24dd3 100644
--- a/src/tools/clippy/tests/ui/iter_overeager_cloned.rs
+++ b/src/tools/clippy/tests/ui/iter_overeager_cloned.rs
@@ -1,4 +1,4 @@
-#![warn(clippy::iter_overeager_cloned, clippy::redundant_clone, clippy::filter_next)]
+#![warn(clippy::iter_overeager_cloned, clippy::redundant_iter_cloned, clippy::filter_next)]
 #![allow(
     dead_code,
     clippy::let_unit_value,
@@ -16,7 +16,7 @@ fn main() {
     //~^ iter_overeager_cloned
 
     let _: usize = vec.iter().filter(|x| x == &"2").cloned().count();
-    //~^ redundant_clone
+    //~^ redundant_iter_cloned
 
     let _: Vec<_> = vec.iter().cloned().take(2).collect();
     //~^ iter_overeager_cloned
@@ -78,19 +78,19 @@ fn main() {
     }
 
     let _ = vec.iter().cloned().map(|x| x.len());
-    //~^ redundant_clone
+    //~^ redundant_iter_cloned
 
     // This would fail if changed.
     let _ = vec.iter().cloned().map(|x| x + "2");
 
     let _ = vec.iter().cloned().for_each(|x| assert!(!x.is_empty()));
-    //~^ redundant_clone
+    //~^ redundant_iter_cloned
 
     let _ = vec.iter().cloned().all(|x| x.len() == 1);
-    //~^ redundant_clone
+    //~^ redundant_iter_cloned
 
     let _ = vec.iter().cloned().any(|x| x.len() == 1);
-    //~^ redundant_clone
+    //~^ redundant_iter_cloned
 
     // Should probably stay as it is.
     let _ = [0, 1, 2, 3, 4].iter().cloned().take(10);
diff --git a/src/tools/clippy/tests/ui/iter_overeager_cloned.stderr b/src/tools/clippy/tests/ui/iter_overeager_cloned.stderr
index 1616dec95b7..f234d19e4aa 100644
--- a/src/tools/clippy/tests/ui/iter_overeager_cloned.stderr
+++ b/src/tools/clippy/tests/ui/iter_overeager_cloned.stderr
@@ -25,8 +25,8 @@ LL |     let _: usize = vec.iter().filter(|x| x == &"2").cloned().count();
    |                                                    |
    |                                                    help: try: `.count()`
    |
-   = note: `-D clippy::redundant-clone` implied by `-D warnings`
-   = help: to override `-D warnings` add `#[allow(clippy::redundant_clone)]`
+   = note: `-D clippy::redundant-iter-cloned` implied by `-D warnings`
+   = help: to override `-D warnings` add `#[allow(clippy::redundant_iter_cloned)]`
 
 error: unnecessarily eager cloning of iterator items
   --> tests/ui/iter_overeager_cloned.rs:21:21
diff --git a/src/tools/clippy/tests/ui/match_as_ref.fixed b/src/tools/clippy/tests/ui/match_as_ref.fixed
index 8c07076af4a..a39f0c9299b 100644
--- a/src/tools/clippy/tests/ui/match_as_ref.fixed
+++ b/src/tools/clippy/tests/ui/match_as_ref.fixed
@@ -41,3 +41,33 @@ fn main() {
         None => None,
     };
 }
+
+mod issue15691 {
+    use std::ops::{Deref, DerefMut};
+
+    struct A(B);
+    struct B;
+
+    impl Deref for A {
+        type Target = B;
+        fn deref(&self) -> &Self::Target {
+            &self.0
+        }
+    }
+
+    impl DerefMut for A {
+        fn deref_mut(&mut self) -> &mut Self::Target {
+            &mut self.0
+        }
+    }
+
+    fn func() {
+        let mut a = Some(A(B));
+        let mut b = Some(B);
+        // Do not lint, we don't have `None => None`
+        let _ = match b {
+            Some(ref mut x) => Some(x),
+            None => a.as_deref_mut(),
+        };
+    }
+}
diff --git a/src/tools/clippy/tests/ui/match_as_ref.rs b/src/tools/clippy/tests/ui/match_as_ref.rs
index 3a5b1227331..04992816790 100644
--- a/src/tools/clippy/tests/ui/match_as_ref.rs
+++ b/src/tools/clippy/tests/ui/match_as_ref.rs
@@ -53,3 +53,33 @@ fn main() {
         None => None,
     };
 }
+
+mod issue15691 {
+    use std::ops::{Deref, DerefMut};
+
+    struct A(B);
+    struct B;
+
+    impl Deref for A {
+        type Target = B;
+        fn deref(&self) -> &Self::Target {
+            &self.0
+        }
+    }
+
+    impl DerefMut for A {
+        fn deref_mut(&mut self) -> &mut Self::Target {
+            &mut self.0
+        }
+    }
+
+    fn func() {
+        let mut a = Some(A(B));
+        let mut b = Some(B);
+        // Do not lint, we don't have `None => None`
+        let _ = match b {
+            Some(ref mut x) => Some(x),
+            None => a.as_deref_mut(),
+        };
+    }
+}
diff --git a/src/tools/clippy/tests/ui/multiple_unsafe_ops_per_block.rs b/src/tools/clippy/tests/ui/multiple_unsafe_ops_per_block.rs
index 016fd89a7b7..132673d5164 100644
--- a/src/tools/clippy/tests/ui/multiple_unsafe_ops_per_block.rs
+++ b/src/tools/clippy/tests/ui/multiple_unsafe_ops_per_block.rs
@@ -1,10 +1,10 @@
 //@needs-asm-support
 //@aux-build:proc_macros.rs
-#![allow(unused)]
-#![allow(deref_nullptr)]
-#![allow(clippy::unnecessary_operation)]
-#![allow(dropping_copy_types)]
-#![allow(clippy::assign_op_pattern)]
+#![expect(
+    dropping_copy_types,
+    clippy::unnecessary_operation,
+    clippy::unnecessary_literal_unwrap
+)]
 #![warn(clippy::multiple_unsafe_ops_per_block)]
 
 extern crate proc_macros;
@@ -105,17 +105,17 @@ fn correct3() {
     }
 }
 
-// tests from the issue (https://github.com/rust-lang/rust-clippy/issues/10064)
-
-unsafe fn read_char_bad(ptr: *const u8) -> char {
-    unsafe { char::from_u32_unchecked(*ptr.cast::<u32>()) }
-    //~^ multiple_unsafe_ops_per_block
-}
+fn issue10064() {
+    unsafe fn read_char_bad(ptr: *const u8) -> char {
+        unsafe { char::from_u32_unchecked(*ptr.cast::<u32>()) }
+        //~^ multiple_unsafe_ops_per_block
+    }
 
-// no lint
-unsafe fn read_char_good(ptr: *const u8) -> char {
-    let int_value = unsafe { *ptr.cast::<u32>() };
-    unsafe { core::char::from_u32_unchecked(int_value) }
+    // no lint
+    unsafe fn read_char_good(ptr: *const u8) -> char {
+        let int_value = unsafe { *ptr.cast::<u32>() };
+        unsafe { core::char::from_u32_unchecked(int_value) }
+    }
 }
 
 // no lint
@@ -126,42 +126,87 @@ fn issue10259() {
     });
 }
 
-fn _fn_ptr(x: unsafe fn()) {
-    unsafe {
-        //~^ multiple_unsafe_ops_per_block
-        x();
-        x();
+fn issue10367() {
+    fn fn_ptr(x: unsafe fn()) {
+        unsafe {
+            //~^ multiple_unsafe_ops_per_block
+            x();
+            x();
+        }
     }
-}
 
-fn _assoc_const() {
-    trait X {
-        const X: unsafe fn();
+    fn assoc_const() {
+        trait X {
+            const X: unsafe fn();
+        }
+        fn _f<T: X>() {
+            unsafe {
+                //~^ multiple_unsafe_ops_per_block
+                T::X();
+                T::X();
+            }
+        }
     }
-    fn _f<T: X>() {
+
+    fn field_fn_ptr(x: unsafe fn()) {
+        struct X(unsafe fn());
+        let x = X(x);
         unsafe {
             //~^ multiple_unsafe_ops_per_block
-            T::X();
-            T::X();
+            x.0();
+            x.0();
         }
     }
 }
 
-fn _field_fn_ptr(x: unsafe fn()) {
-    struct X(unsafe fn());
-    let x = X(x);
+// await expands to an unsafe block with several operations, but this is fine.
+async fn issue11312() {
+    async fn helper() {}
+
+    helper().await;
+}
+
+async fn issue13879() {
+    async fn foo() {}
+
+    // no lint: nothing unsafe beyond the `await` which we ignore
+    unsafe {
+        foo().await;
+    }
+
+    // no lint: only one unsafe call beyond the `await`
+    unsafe {
+        not_very_safe();
+        foo().await;
+    }
+
+    // lint: two unsafe calls beyond the `await`
     unsafe {
         //~^ multiple_unsafe_ops_per_block
-        x.0();
-        x.0();
+        not_very_safe();
+        STATIC += 1;
+        foo().await;
     }
-}
 
-// await expands to an unsafe block with several operations, but this is fine.: #11312
-async fn await_desugaring_silent() {
-    async fn helper() {}
+    async unsafe fn foo_unchecked() {}
 
-    helper().await;
+    // no lint: only one unsafe call in the `await`ed expr
+    unsafe {
+        foo_unchecked().await;
+    }
+
+    // lint: one unsafe call in the `await`ed expr, and one outside
+    unsafe {
+        //~^ multiple_unsafe_ops_per_block
+        not_very_safe();
+        foo_unchecked().await;
+    }
+
+    // lint: two unsafe calls in the `await`ed expr
+    unsafe {
+        //~^ multiple_unsafe_ops_per_block
+        Some(foo_unchecked()).unwrap_unchecked().await;
+    }
 }
 
 fn main() {}
diff --git a/src/tools/clippy/tests/ui/multiple_unsafe_ops_per_block.stderr b/src/tools/clippy/tests/ui/multiple_unsafe_ops_per_block.stderr
index 3130cecc252..922a464c6b6 100644
--- a/src/tools/clippy/tests/ui/multiple_unsafe_ops_per_block.stderr
+++ b/src/tools/clippy/tests/ui/multiple_unsafe_ops_per_block.stderr
@@ -113,84 +113,147 @@ LL |         asm!("nop");
    |         ^^^^^^^^^^^
 
 error: this `unsafe` block contains 2 unsafe operations, expected only one
-  --> tests/ui/multiple_unsafe_ops_per_block.rs:111:5
+  --> tests/ui/multiple_unsafe_ops_per_block.rs:110:9
    |
-LL |     unsafe { char::from_u32_unchecked(*ptr.cast::<u32>()) }
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL |         unsafe { char::from_u32_unchecked(*ptr.cast::<u32>()) }
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
 note: unsafe function call occurs here
-  --> tests/ui/multiple_unsafe_ops_per_block.rs:111:14
+  --> tests/ui/multiple_unsafe_ops_per_block.rs:110:18
    |
-LL |     unsafe { char::from_u32_unchecked(*ptr.cast::<u32>()) }
-   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL |         unsafe { char::from_u32_unchecked(*ptr.cast::<u32>()) }
+   |                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 note: raw pointer dereference occurs here
-  --> tests/ui/multiple_unsafe_ops_per_block.rs:111:39
+  --> tests/ui/multiple_unsafe_ops_per_block.rs:110:43
    |
-LL |     unsafe { char::from_u32_unchecked(*ptr.cast::<u32>()) }
-   |                                       ^^^^^^^^^^^^^^^^^^
+LL |         unsafe { char::from_u32_unchecked(*ptr.cast::<u32>()) }
+   |                                           ^^^^^^^^^^^^^^^^^^
 
 error: this `unsafe` block contains 2 unsafe operations, expected only one
-  --> tests/ui/multiple_unsafe_ops_per_block.rs:130:5
+  --> tests/ui/multiple_unsafe_ops_per_block.rs:131:9
    |
-LL | /     unsafe {
+LL | /         unsafe {
 LL | |
-LL | |         x();
-LL | |         x();
-LL | |     }
-   | |_____^
+LL | |             x();
+LL | |             x();
+LL | |         }
+   | |_________^
    |
 note: unsafe function call occurs here
-  --> tests/ui/multiple_unsafe_ops_per_block.rs:132:9
+  --> tests/ui/multiple_unsafe_ops_per_block.rs:133:13
    |
-LL |         x();
-   |         ^^^
+LL |             x();
+   |             ^^^
 note: unsafe function call occurs here
-  --> tests/ui/multiple_unsafe_ops_per_block.rs:133:9
+  --> tests/ui/multiple_unsafe_ops_per_block.rs:134:13
    |
-LL |         x();
-   |         ^^^
+LL |             x();
+   |             ^^^
 
 error: this `unsafe` block contains 2 unsafe operations, expected only one
-  --> tests/ui/multiple_unsafe_ops_per_block.rs:142:9
+  --> tests/ui/multiple_unsafe_ops_per_block.rs:143:13
+   |
+LL | /             unsafe {
+LL | |
+LL | |                 T::X();
+LL | |                 T::X();
+LL | |             }
+   | |_____________^
+   |
+note: unsafe function call occurs here
+  --> tests/ui/multiple_unsafe_ops_per_block.rs:145:17
+   |
+LL |                 T::X();
+   |                 ^^^^^^
+note: unsafe function call occurs here
+  --> tests/ui/multiple_unsafe_ops_per_block.rs:146:17
+   |
+LL |                 T::X();
+   |                 ^^^^^^
+
+error: this `unsafe` block contains 2 unsafe operations, expected only one
+  --> tests/ui/multiple_unsafe_ops_per_block.rs:154:9
    |
 LL | /         unsafe {
 LL | |
-LL | |             T::X();
-LL | |             T::X();
+LL | |             x.0();
+LL | |             x.0();
 LL | |         }
    | |_________^
    |
 note: unsafe function call occurs here
-  --> tests/ui/multiple_unsafe_ops_per_block.rs:144:13
+  --> tests/ui/multiple_unsafe_ops_per_block.rs:156:13
    |
-LL |             T::X();
-   |             ^^^^^^
+LL |             x.0();
+   |             ^^^^^
 note: unsafe function call occurs here
-  --> tests/ui/multiple_unsafe_ops_per_block.rs:145:13
+  --> tests/ui/multiple_unsafe_ops_per_block.rs:157:13
    |
-LL |             T::X();
-   |             ^^^^^^
+LL |             x.0();
+   |             ^^^^^
 
 error: this `unsafe` block contains 2 unsafe operations, expected only one
-  --> tests/ui/multiple_unsafe_ops_per_block.rs:153:5
+  --> tests/ui/multiple_unsafe_ops_per_block.rs:184:5
    |
 LL | /     unsafe {
 LL | |
-LL | |         x.0();
-LL | |         x.0();
+LL | |         not_very_safe();
+LL | |         STATIC += 1;
+LL | |         foo().await;
 LL | |     }
    | |_____^
    |
 note: unsafe function call occurs here
-  --> tests/ui/multiple_unsafe_ops_per_block.rs:155:9
+  --> tests/ui/multiple_unsafe_ops_per_block.rs:186:9
+   |
+LL |         not_very_safe();
+   |         ^^^^^^^^^^^^^^^
+note: modification of a mutable static occurs here
+  --> tests/ui/multiple_unsafe_ops_per_block.rs:187:9
+   |
+LL |         STATIC += 1;
+   |         ^^^^^^^^^^^
+
+error: this `unsafe` block contains 2 unsafe operations, expected only one
+  --> tests/ui/multiple_unsafe_ops_per_block.rs:199:5
+   |
+LL | /     unsafe {
+LL | |
+LL | |         not_very_safe();
+LL | |         foo_unchecked().await;
+LL | |     }
+   | |_____^
+   |
+note: unsafe function call occurs here
+  --> tests/ui/multiple_unsafe_ops_per_block.rs:201:9
+   |
+LL |         not_very_safe();
+   |         ^^^^^^^^^^^^^^^
+note: unsafe function call occurs here
+  --> tests/ui/multiple_unsafe_ops_per_block.rs:202:9
+   |
+LL |         foo_unchecked().await;
+   |         ^^^^^^^^^^^^^^^
+
+error: this `unsafe` block contains 2 unsafe operations, expected only one
+  --> tests/ui/multiple_unsafe_ops_per_block.rs:206:5
+   |
+LL | /     unsafe {
+LL | |
+LL | |         Some(foo_unchecked()).unwrap_unchecked().await;
+LL | |     }
+   | |_____^
+   |
+note: unsafe method call occurs here
+  --> tests/ui/multiple_unsafe_ops_per_block.rs:208:9
    |
-LL |         x.0();
-   |         ^^^^^
+LL |         Some(foo_unchecked()).unwrap_unchecked().await;
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 note: unsafe function call occurs here
-  --> tests/ui/multiple_unsafe_ops_per_block.rs:156:9
+  --> tests/ui/multiple_unsafe_ops_per_block.rs:208:14
    |
-LL |         x.0();
-   |         ^^^^^
+LL |         Some(foo_unchecked()).unwrap_unchecked().await;
+   |              ^^^^^^^^^^^^^^^
 
-error: aborting due to 8 previous errors
+error: aborting due to 11 previous errors
 
diff --git a/src/tools/clippy/tests/ui/needless_return.fixed b/src/tools/clippy/tests/ui/needless_return.fixed
index d571b97f519..f5f8bb21e81 100644
--- a/src/tools/clippy/tests/ui/needless_return.fixed
+++ b/src/tools/clippy/tests/ui/needless_return.fixed
@@ -517,3 +517,10 @@ mod else_ifs {
         }
     }
 }
+
+fn issue14474() -> u64 {
+    return 456;
+
+    #[cfg(false)]
+    123
+}
diff --git a/src/tools/clippy/tests/ui/needless_return.rs b/src/tools/clippy/tests/ui/needless_return.rs
index 2e4348ea338..495516c1c2e 100644
--- a/src/tools/clippy/tests/ui/needless_return.rs
+++ b/src/tools/clippy/tests/ui/needless_return.rs
@@ -526,3 +526,10 @@ mod else_ifs {
         }
     }
 }
+
+fn issue14474() -> u64 {
+    return 456;
+
+    #[cfg(false)]
+    123
+}
diff --git a/src/tools/clippy/tests/ui/never_loop.rs b/src/tools/clippy/tests/ui/never_loop.rs
index 48d4b8ad151..01db64a446c 100644
--- a/src/tools/clippy/tests/ui/never_loop.rs
+++ b/src/tools/clippy/tests/ui/never_loop.rs
@@ -498,3 +498,27 @@ fn issue15059() {
         ()
     }
 }
+
+fn issue15350() {
+    'bar: for _ in 0..100 {
+        //~^ never_loop
+        loop {
+            //~^ never_loop
+            println!("This will still run");
+            break 'bar;
+        }
+    }
+
+    'foo: for _ in 0..100 {
+        //~^ never_loop
+        loop {
+            //~^ never_loop
+            println!("This will still run");
+            loop {
+                //~^ never_loop
+                println!("This will still run");
+                break 'foo;
+            }
+        }
+    }
+}
diff --git a/src/tools/clippy/tests/ui/never_loop.stderr b/src/tools/clippy/tests/ui/never_loop.stderr
index 54b463266a3..4fda06cff4a 100644
--- a/src/tools/clippy/tests/ui/never_loop.stderr
+++ b/src/tools/clippy/tests/ui/never_loop.stderr
@@ -193,6 +193,19 @@ LL | |         return;
 LL | |     }
    | |_____^
    |
+help: this code is unreachable. Consider moving the reachable parts out
+  --> tests/ui/never_loop.rs:436:9
+   |
+LL | /         loop {
+LL | |
+LL | |             break 'outer;
+LL | |         }
+   | |_________^
+help: this code is unreachable. Consider moving the reachable parts out
+  --> tests/ui/never_loop.rs:440:9
+   |
+LL |         return;
+   |         ^^^^^^^
 help: if you need the first element of the iterator, try writing
    |
 LL -     'outer: for v in 0..10 {
@@ -297,5 +310,87 @@ LL ~
 LL ~         
    |
 
-error: aborting due to 24 previous errors
+error: this loop never actually loops
+  --> tests/ui/never_loop.rs:503:5
+   |
+LL | /     'bar: for _ in 0..100 {
+LL | |
+LL | |         loop {
+...  |
+LL | |     }
+   | |_____^
+   |
+help: this code is unreachable. Consider moving the reachable parts out
+  --> tests/ui/never_loop.rs:505:9
+   |
+LL | /         loop {
+LL | |
+LL | |             println!("This will still run");
+LL | |             break 'bar;
+LL | |         }
+   | |_________^
+help: if you need the first element of the iterator, try writing
+   |
+LL -     'bar: for _ in 0..100 {
+LL +     if let Some(_) = (0..100).next() {
+   |
+
+error: this loop never actually loops
+  --> tests/ui/never_loop.rs:505:9
+   |
+LL | /         loop {
+LL | |
+LL | |             println!("This will still run");
+LL | |             break 'bar;
+LL | |         }
+   | |_________^
+
+error: this loop never actually loops
+  --> tests/ui/never_loop.rs:512:5
+   |
+LL | /     'foo: for _ in 0..100 {
+LL | |
+LL | |         loop {
+...  |
+LL | |     }
+   | |_____^
+   |
+help: this code is unreachable. Consider moving the reachable parts out
+  --> tests/ui/never_loop.rs:514:9
+   |
+LL | /         loop {
+LL | |
+LL | |             println!("This will still run");
+LL | |             loop {
+...  |
+LL | |         }
+   | |_________^
+help: if you need the first element of the iterator, try writing
+   |
+LL -     'foo: for _ in 0..100 {
+LL +     if let Some(_) = (0..100).next() {
+   |
+
+error: this loop never actually loops
+  --> tests/ui/never_loop.rs:514:9
+   |
+LL | /         loop {
+LL | |
+LL | |             println!("This will still run");
+LL | |             loop {
+...  |
+LL | |         }
+   | |_________^
+
+error: this loop never actually loops
+  --> tests/ui/never_loop.rs:517:13
+   |
+LL | /             loop {
+LL | |
+LL | |                 println!("This will still run");
+LL | |                 break 'foo;
+LL | |             }
+   | |_____________^
+
+error: aborting due to 29 previous errors
 
diff --git a/src/tools/clippy/tests/ui/option_if_let_else.fixed b/src/tools/clippy/tests/ui/option_if_let_else.fixed
index 0f86de5646c..6ce067f5c24 100644
--- a/src/tools/clippy/tests/ui/option_if_let_else.fixed
+++ b/src/tools/clippy/tests/ui/option_if_let_else.fixed
@@ -125,6 +125,16 @@ fn complex_subpat() -> DummyEnum {
     DummyEnum::Two
 }
 
+// #10335
+pub fn test_result_err_ignored_1(r: Result<&[u8], &[u8]>) -> Vec<u8> {
+    r.map_or_else(|_| Vec::new(), |s| s.to_owned())
+}
+
+// #10335
+pub fn test_result_err_ignored_2(r: Result<&[u8], &[u8]>) -> Vec<u8> {
+    r.map_or_else(|_| Vec::new(), |s| s.to_owned())
+}
+
 fn main() {
     let optional = Some(5);
     let _ = optional.map_or(5, |x| x + 2);
diff --git a/src/tools/clippy/tests/ui/option_if_let_else.rs b/src/tools/clippy/tests/ui/option_if_let_else.rs
index 7aabd778f87..096d3aabf28 100644
--- a/src/tools/clippy/tests/ui/option_if_let_else.rs
+++ b/src/tools/clippy/tests/ui/option_if_let_else.rs
@@ -152,6 +152,22 @@ fn complex_subpat() -> DummyEnum {
     DummyEnum::Two
 }
 
+// #10335
+pub fn test_result_err_ignored_1(r: Result<&[u8], &[u8]>) -> Vec<u8> {
+    match r {
+        //~^ option_if_let_else
+        Ok(s) => s.to_owned(),
+        Err(_) => Vec::new(),
+    }
+}
+
+// #10335
+pub fn test_result_err_ignored_2(r: Result<&[u8], &[u8]>) -> Vec<u8> {
+    if let Ok(s) = r { s.to_owned() }
+    //~^ option_if_let_else
+    else { Vec::new() }
+}
+
 fn main() {
     let optional = Some(5);
     let _ = if let Some(x) = optional { x + 2 } else { 5 };
diff --git a/src/tools/clippy/tests/ui/option_if_let_else.stderr b/src/tools/clippy/tests/ui/option_if_let_else.stderr
index 2e2fe6f2049..21a80ae038d 100644
--- a/src/tools/clippy/tests/ui/option_if_let_else.stderr
+++ b/src/tools/clippy/tests/ui/option_if_let_else.stderr
@@ -188,14 +188,32 @@ LL +         true
 LL +     })
    |
 
+error: use Option::map_or_else instead of an if let/else
+  --> tests/ui/option_if_let_else.rs:157:5
+   |
+LL | /     match r {
+LL | |
+LL | |         Ok(s) => s.to_owned(),
+LL | |         Err(_) => Vec::new(),
+LL | |     }
+   | |_____^ help: try: `r.map_or_else(|_| Vec::new(), |s| s.to_owned())`
+
+error: use Option::map_or_else instead of an if let/else
+  --> tests/ui/option_if_let_else.rs:166:5
+   |
+LL | /     if let Ok(s) = r { s.to_owned() }
+LL | |
+LL | |     else { Vec::new() }
+   | |_______________________^ help: try: `r.map_or_else(|_| Vec::new(), |s| s.to_owned())`
+
 error: use Option::map_or instead of an if let/else
-  --> tests/ui/option_if_let_else.rs:157:13
+  --> tests/ui/option_if_let_else.rs:173:13
    |
 LL |     let _ = if let Some(x) = optional { x + 2 } else { 5 };
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `optional.map_or(5, |x| x + 2)`
 
 error: use Option::map_or instead of an if let/else
-  --> tests/ui/option_if_let_else.rs:168:13
+  --> tests/ui/option_if_let_else.rs:184:13
    |
 LL |       let _ = if let Some(x) = Some(0) {
    |  _____________^
@@ -217,13 +235,13 @@ LL ~         });
    |
 
 error: use Option::map_or instead of an if let/else
-  --> tests/ui/option_if_let_else.rs:197:13
+  --> tests/ui/option_if_let_else.rs:213:13
    |
 LL |     let _ = if let Some(x) = Some(0) { s.len() + x } else { s.len() };
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Some(0).map_or(s.len(), |x| s.len() + x)`
 
 error: use Option::map_or instead of an if let/else
-  --> tests/ui/option_if_let_else.rs:202:13
+  --> tests/ui/option_if_let_else.rs:218:13
    |
 LL |       let _ = if let Some(x) = Some(0) {
    |  _____________^
@@ -245,7 +263,7 @@ LL ~     });
    |
 
 error: use Option::map_or instead of an if let/else
-  --> tests/ui/option_if_let_else.rs:242:13
+  --> tests/ui/option_if_let_else.rs:258:13
    |
 LL |       let _ = match s {
    |  _____________^
@@ -256,7 +274,7 @@ LL | |     };
    | |_____^ help: try: `s.map_or(1, |string| string.len())`
 
 error: use Option::map_or instead of an if let/else
-  --> tests/ui/option_if_let_else.rs:247:13
+  --> tests/ui/option_if_let_else.rs:263:13
    |
 LL |       let _ = match Some(10) {
    |  _____________^
@@ -267,7 +285,7 @@ LL | |     };
    | |_____^ help: try: `Some(10).map_or(5, |a| a + 1)`
 
 error: use Option::map_or instead of an if let/else
-  --> tests/ui/option_if_let_else.rs:254:13
+  --> tests/ui/option_if_let_else.rs:270:13
    |
 LL |       let _ = match res {
    |  _____________^
@@ -278,7 +296,7 @@ LL | |     };
    | |_____^ help: try: `res.map_or(1, |a| a + 1)`
 
 error: use Option::map_or instead of an if let/else
-  --> tests/ui/option_if_let_else.rs:259:13
+  --> tests/ui/option_if_let_else.rs:275:13
    |
 LL |       let _ = match res {
    |  _____________^
@@ -289,13 +307,13 @@ LL | |     };
    | |_____^ help: try: `res.map_or(1, |a| a + 1)`
 
 error: use Option::map_or instead of an if let/else
-  --> tests/ui/option_if_let_else.rs:264:13
+  --> tests/ui/option_if_let_else.rs:280:13
    |
 LL |     let _ = if let Ok(a) = res { a + 1 } else { 5 };
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `res.map_or(5, |a| a + 1)`
 
 error: use Option::map_or instead of an if let/else
-  --> tests/ui/option_if_let_else.rs:282:17
+  --> tests/ui/option_if_let_else.rs:298:17
    |
 LL |           let _ = match initial {
    |  _________________^
@@ -306,7 +324,7 @@ LL | |         };
    | |_________^ help: try: `initial.as_ref().map_or(42, |value| do_something(value))`
 
 error: use Option::map_or instead of an if let/else
-  --> tests/ui/option_if_let_else.rs:290:17
+  --> tests/ui/option_if_let_else.rs:306:17
    |
 LL |           let _ = match initial {
    |  _________________^
@@ -317,7 +335,7 @@ LL | |         };
    | |_________^ help: try: `initial.as_mut().map_or(42, |value| do_something2(value))`
 
 error: use Option::map_or_else instead of an if let/else
-  --> tests/ui/option_if_let_else.rs:314:24
+  --> tests/ui/option_if_let_else.rs:330:24
    |
 LL |       let mut _hashmap = if let Some(hm) = &opt {
    |  ________________________^
@@ -329,19 +347,19 @@ LL | |     };
    | |_____^ help: try: `opt.as_ref().map_or_else(HashMap::new, |hm| hm.clone())`
 
 error: use Option::map_or_else instead of an if let/else
-  --> tests/ui/option_if_let_else.rs:321:19
+  --> tests/ui/option_if_let_else.rs:337:19
    |
 LL |     let mut _hm = if let Some(hm) = &opt { hm.clone() } else { new_map!() };
    |                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `opt.as_ref().map_or_else(|| new_map!(), |hm| hm.clone())`
 
 error: use Option::map_or instead of an if let/else
-  --> tests/ui/option_if_let_else.rs:372:22
+  --> tests/ui/option_if_let_else.rs:388:22
    |
 LL |     let _ = unsafe { if let Some(o) = *opt_raw_ptr { o } else { 1 } };
    |                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `(*opt_raw_ptr).map_or(1, |o| o)`
 
 error: use Option::map_or_else instead of an if let/else
-  --> tests/ui/option_if_let_else.rs:378:13
+  --> tests/ui/option_if_let_else.rs:394:13
    |
 LL |       let _ = match res {
    |  _____________^
@@ -351,5 +369,5 @@ LL | |         Err(_) => String::new(),
 LL | |     };
    | |_____^ help: try: `res.map_or_else(|_| String::new(), |s| s.clone())`
 
-error: aborting due to 27 previous errors
+error: aborting due to 29 previous errors
 
diff --git a/src/tools/clippy/tests/ui/or_fun_call.fixed b/src/tools/clippy/tests/ui/or_fun_call.fixed
index 0a8525a12f5..7a0be97017e 100644
--- a/src/tools/clippy/tests/ui/or_fun_call.fixed
+++ b/src/tools/clippy/tests/ui/or_fun_call.fixed
@@ -77,6 +77,22 @@ fn or_fun_call() {
     with_default_type.unwrap_or_default();
     //~^ unwrap_or_default
 
+    let with_default_literal = Some(1);
+    with_default_literal.unwrap_or(0);
+    // Do not lint because `.unwrap_or_default()` wouldn't be simpler
+
+    let with_default_literal = Some(1.0);
+    with_default_literal.unwrap_or(0.0);
+    // Do not lint because `.unwrap_or_default()` wouldn't be simpler
+
+    let with_default_literal = Some("foo");
+    with_default_literal.unwrap_or("");
+    // Do not lint because `.unwrap_or_default()` wouldn't be simpler
+
+    let with_default_vec_macro = Some(vec![1, 2, 3]);
+    with_default_vec_macro.unwrap_or(vec![]);
+    // Do not lint because `.unwrap_or_default()` wouldn't be simpler
+
     let self_default = None::<FakeDefault>;
     self_default.unwrap_or_else(<FakeDefault>::default);
     //~^ or_fun_call
diff --git a/src/tools/clippy/tests/ui/or_fun_call.rs b/src/tools/clippy/tests/ui/or_fun_call.rs
index b4f9b950a7f..724af606de9 100644
--- a/src/tools/clippy/tests/ui/or_fun_call.rs
+++ b/src/tools/clippy/tests/ui/or_fun_call.rs
@@ -77,6 +77,22 @@ fn or_fun_call() {
     with_default_type.unwrap_or(u64::default());
     //~^ unwrap_or_default
 
+    let with_default_literal = Some(1);
+    with_default_literal.unwrap_or(0);
+    // Do not lint because `.unwrap_or_default()` wouldn't be simpler
+
+    let with_default_literal = Some(1.0);
+    with_default_literal.unwrap_or(0.0);
+    // Do not lint because `.unwrap_or_default()` wouldn't be simpler
+
+    let with_default_literal = Some("foo");
+    with_default_literal.unwrap_or("");
+    // Do not lint because `.unwrap_or_default()` wouldn't be simpler
+
+    let with_default_vec_macro = Some(vec![1, 2, 3]);
+    with_default_vec_macro.unwrap_or(vec![]);
+    // Do not lint because `.unwrap_or_default()` wouldn't be simpler
+
     let self_default = None::<FakeDefault>;
     self_default.unwrap_or(<FakeDefault>::default());
     //~^ or_fun_call
@@ -86,7 +102,7 @@ fn or_fun_call() {
     //~^ unwrap_or_default
 
     let with_vec = Some(vec![1]);
-    with_vec.unwrap_or(vec![]);
+    with_vec.unwrap_or(Vec::new());
     //~^ unwrap_or_default
 
     let without_default = Some(Foo);
@@ -98,7 +114,7 @@ fn or_fun_call() {
     //~^ unwrap_or_default
 
     let mut map_vec = HashMap::<u64, Vec<i32>>::new();
-    map_vec.entry(42).or_insert(vec![]);
+    map_vec.entry(42).or_insert(Vec::new());
     //~^ unwrap_or_default
 
     let mut btree = BTreeMap::<u64, String>::new();
@@ -106,7 +122,7 @@ fn or_fun_call() {
     //~^ unwrap_or_default
 
     let mut btree_vec = BTreeMap::<u64, Vec<i32>>::new();
-    btree_vec.entry(42).or_insert(vec![]);
+    btree_vec.entry(42).or_insert(Vec::new());
     //~^ unwrap_or_default
 
     let stringy = Some(String::new());
diff --git a/src/tools/clippy/tests/ui/or_fun_call.stderr b/src/tools/clippy/tests/ui/or_fun_call.stderr
index 3e4df772668..40b25f91154 100644
--- a/src/tools/clippy/tests/ui/or_fun_call.stderr
+++ b/src/tools/clippy/tests/ui/or_fun_call.stderr
@@ -47,175 +47,175 @@ 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:81:18
+  --> tests/ui/or_fun_call.rs:97: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:85:18
+  --> tests/ui/or_fun_call.rs:101: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:89:14
+  --> tests/ui/or_fun_call.rs:105:14
    |
-LL |     with_vec.unwrap_or(vec![]);
-   |              ^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_default()`
+LL |     with_vec.unwrap_or(Vec::new());
+   |              ^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_default()`
 
 error: function call inside of `unwrap_or`
-  --> tests/ui/or_fun_call.rs:93:21
+  --> tests/ui/or_fun_call.rs:109: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:97:19
+  --> tests/ui/or_fun_call.rs:113: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:101:23
+  --> tests/ui/or_fun_call.rs:117:23
    |
-LL |     map_vec.entry(42).or_insert(vec![]);
-   |                       ^^^^^^^^^^^^^^^^^ help: try: `or_default()`
+LL |     map_vec.entry(42).or_insert(Vec::new());
+   |                       ^^^^^^^^^^^^^^^^^^^^^ help: try: `or_default()`
 
 error: use of `or_insert` to construct default value
-  --> tests/ui/or_fun_call.rs:105:21
+  --> tests/ui/or_fun_call.rs:121: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:109:25
+  --> tests/ui/or_fun_call.rs:125:25
    |
-LL |     btree_vec.entry(42).or_insert(vec![]);
-   |                         ^^^^^^^^^^^^^^^^^ help: try: `or_default()`
+LL |     btree_vec.entry(42).or_insert(Vec::new());
+   |                         ^^^^^^^^^^^^^^^^^^^^^ help: try: `or_default()`
 
 error: use of `unwrap_or` to construct default value
-  --> tests/ui/or_fun_call.rs:113:21
+  --> tests/ui/or_fun_call.rs:129: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:118:17
+  --> tests/ui/or_fun_call.rs:134: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:123:21
+  --> tests/ui/or_fun_call.rs:139: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:126:21
+  --> tests/ui/or_fun_call.rs:142: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:151:35
+  --> tests/ui/or_fun_call.rs:167: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:194:18
+  --> tests/ui/or_fun_call.rs:210: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:202:14
+  --> tests/ui/or_fun_call.rs:218: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:205:14
+  --> tests/ui/or_fun_call.rs:221: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:281:25
+  --> tests/ui/or_fun_call.rs:297: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:283:25
+  --> tests/ui/or_fun_call.rs:299:25
    |
 LL |         let _ = Some(4).map_or(g(), f);
    |                         ^^^^^^^^^^^^^^ help: try: `map_or_else(g, f)`
 
 error: function call inside of `map_or`
-  --> tests/ui/or_fun_call.rs:286:25
+  --> tests/ui/or_fun_call.rs:302:25
    |
 LL |         let _ = Some(4).map_or("asd".to_string().len() as i32, f);
    |                         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map_or_else(|| "asd".to_string().len() as i32, f)`
 
 error: use of `unwrap_or_else` to construct default value
-  --> tests/ui/or_fun_call.rs:317:18
+  --> tests/ui/or_fun_call.rs:333: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:321:28
+  --> tests/ui/or_fun_call.rs:337: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:325:27
+  --> tests/ui/or_fun_call.rs:341: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:329:22
+  --> tests/ui/or_fun_call.rs:345: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:333:23
+  --> tests/ui/or_fun_call.rs:349: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:337:25
+  --> tests/ui/or_fun_call.rs:353: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:341:25
+  --> tests/ui/or_fun_call.rs:357: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:383:17
+  --> tests/ui/or_fun_call.rs:399: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:388:17
+  --> tests/ui/or_fun_call.rs:404: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:393:17
+  --> tests/ui/or_fun_call.rs:409:17
    |
 LL |       let _ = opt.unwrap_or({
    |  _________________^
@@ -235,55 +235,55 @@ LL ~     });
    |
 
 error: function call inside of `map_or`
-  --> tests/ui/or_fun_call.rs:399:17
+  --> tests/ui/or_fun_call.rs:415: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:404:17
+  --> tests/ui/or_fun_call.rs:420: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:411:21
+  --> tests/ui/or_fun_call.rs:427:21
    |
 LL |     let _ = opt_foo.unwrap_or(Foo { val: String::default() });
    |                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_else(|| Foo { val: String::default() })`
 
 error: function call inside of `map_or`
-  --> tests/ui/or_fun_call.rs:426:19
+  --> tests/ui/or_fun_call.rs:442: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:428:19
+  --> tests/ui/or_fun_call.rs:444:19
    |
 LL |         let _ = x.map_or(g(), f);
    |                   ^^^^^^^^^^^^^^ help: try: `map_or_else(|_| g(), f)`
 
 error: function call inside of `map_or`
-  --> tests/ui/or_fun_call.rs:431:19
+  --> tests/ui/or_fun_call.rs:447:19
    |
 LL |         let _ = x.map_or("asd".to_string().len() as i32, f);
    |                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map_or_else(|_| "asd".to_string().len() as i32, f)`
 
 error: function call inside of `get_or_insert`
-  --> tests/ui/or_fun_call.rs:442:15
+  --> tests/ui/or_fun_call.rs:458:15
    |
 LL |     let _ = x.get_or_insert(g());
    |               ^^^^^^^^^^^^^^^^^^ help: try: `get_or_insert_with(g)`
 
 error: function call inside of `and`
-  --> tests/ui/or_fun_call.rs:452:15
+  --> tests/ui/or_fun_call.rs:468:15
    |
 LL |     let _ = x.and(g());
    |               ^^^^^^^^ help: try: `and_then(|_| g())`
 
 error: function call inside of `and`
-  --> tests/ui/or_fun_call.rs:462:15
+  --> tests/ui/or_fun_call.rs:478:15
    |
 LL |     let _ = x.and(g());
    |               ^^^^^^^^ help: try: `and_then(|_| g())`
diff --git a/src/tools/clippy/tests/ui/ptr_offset_with_cast.fixed b/src/tools/clippy/tests/ui/ptr_offset_with_cast.fixed
index 4fe9dcf46c3..42d1abeaa05 100644
--- a/src/tools/clippy/tests/ui/ptr_offset_with_cast.fixed
+++ b/src/tools/clippy/tests/ui/ptr_offset_with_cast.fixed
@@ -1,4 +1,4 @@
-#![allow(clippy::unnecessary_cast, clippy::useless_vec)]
+#![expect(clippy::unnecessary_cast, clippy::useless_vec, clippy::needless_borrow)]
 
 fn main() {
     let vec = vec![b'a', b'b', b'c'];
@@ -18,5 +18,25 @@ fn main() {
         //~^ ptr_offset_with_cast
         let _ = ptr.wrapping_offset(offset_isize as isize);
         let _ = ptr.wrapping_offset(offset_u8 as isize);
+
+        let _ = S.offset(offset_usize as isize);
+        let _ = S.wrapping_offset(offset_usize as isize);
+
+        let _ = (&ptr).add(offset_usize);
+        //~^ ptr_offset_with_cast
+        let _ = (&ptr).wrapping_add(offset_usize);
+        //~^ ptr_offset_with_cast
+    }
+}
+
+#[derive(Clone, Copy)]
+struct S;
+
+impl S {
+    fn offset(self, _: isize) -> Self {
+        self
+    }
+    fn wrapping_offset(self, _: isize) -> Self {
+        self
     }
 }
diff --git a/src/tools/clippy/tests/ui/ptr_offset_with_cast.rs b/src/tools/clippy/tests/ui/ptr_offset_with_cast.rs
index a1fb892733d..6d06a6af1fa 100644
--- a/src/tools/clippy/tests/ui/ptr_offset_with_cast.rs
+++ b/src/tools/clippy/tests/ui/ptr_offset_with_cast.rs
@@ -1,4 +1,4 @@
-#![allow(clippy::unnecessary_cast, clippy::useless_vec)]
+#![expect(clippy::unnecessary_cast, clippy::useless_vec, clippy::needless_borrow)]
 
 fn main() {
     let vec = vec![b'a', b'b', b'c'];
@@ -18,5 +18,25 @@ fn main() {
         //~^ ptr_offset_with_cast
         let _ = ptr.wrapping_offset(offset_isize as isize);
         let _ = ptr.wrapping_offset(offset_u8 as isize);
+
+        let _ = S.offset(offset_usize as isize);
+        let _ = S.wrapping_offset(offset_usize as isize);
+
+        let _ = (&ptr).offset(offset_usize as isize);
+        //~^ ptr_offset_with_cast
+        let _ = (&ptr).wrapping_offset(offset_usize as isize);
+        //~^ ptr_offset_with_cast
+    }
+}
+
+#[derive(Clone, Copy)]
+struct S;
+
+impl S {
+    fn offset(self, _: isize) -> Self {
+        self
+    }
+    fn wrapping_offset(self, _: isize) -> Self {
+        self
     }
 }
diff --git a/src/tools/clippy/tests/ui/ptr_offset_with_cast.stderr b/src/tools/clippy/tests/ui/ptr_offset_with_cast.stderr
index dcd5e027d18..022b3286c93 100644
--- a/src/tools/clippy/tests/ui/ptr_offset_with_cast.stderr
+++ b/src/tools/clippy/tests/ui/ptr_offset_with_cast.stderr
@@ -2,16 +2,51 @@ error: use of `offset` with a `usize` casted to an `isize`
   --> tests/ui/ptr_offset_with_cast.rs:12:17
    |
 LL |         let _ = ptr.offset(offset_usize as isize);
-   |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `ptr.add(offset_usize)`
+   |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
    = note: `-D clippy::ptr-offset-with-cast` implied by `-D warnings`
    = help: to override `-D warnings` add `#[allow(clippy::ptr_offset_with_cast)]`
+help: use `add` instead
+   |
+LL -         let _ = ptr.offset(offset_usize as isize);
+LL +         let _ = ptr.add(offset_usize);
+   |
 
 error: use of `wrapping_offset` with a `usize` casted to an `isize`
   --> tests/ui/ptr_offset_with_cast.rs:17:17
    |
 LL |         let _ = ptr.wrapping_offset(offset_usize as isize);
-   |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `ptr.wrapping_add(offset_usize)`
+   |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: use `wrapping_add` instead
+   |
+LL -         let _ = ptr.wrapping_offset(offset_usize as isize);
+LL +         let _ = ptr.wrapping_add(offset_usize);
+   |
+
+error: use of `offset` with a `usize` casted to an `isize`
+  --> tests/ui/ptr_offset_with_cast.rs:25:17
+   |
+LL |         let _ = (&ptr).offset(offset_usize as isize);
+   |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: use `add` instead
+   |
+LL -         let _ = (&ptr).offset(offset_usize as isize);
+LL +         let _ = (&ptr).add(offset_usize);
+   |
+
+error: use of `wrapping_offset` with a `usize` casted to an `isize`
+  --> tests/ui/ptr_offset_with_cast.rs:27:17
+   |
+LL |         let _ = (&ptr).wrapping_offset(offset_usize as isize);
+   |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: use `wrapping_add` instead
+   |
+LL -         let _ = (&ptr).wrapping_offset(offset_usize as isize);
+LL +         let _ = (&ptr).wrapping_add(offset_usize);
+   |
 
-error: aborting due to 2 previous errors
+error: aborting due to 4 previous errors
 
diff --git a/src/tools/clippy/tests/ui/question_mark.fixed b/src/tools/clippy/tests/ui/question_mark.fixed
index 8d6f5fbadca..ac81b324c20 100644
--- a/src/tools/clippy/tests/ui/question_mark.fixed
+++ b/src/tools/clippy/tests/ui/question_mark.fixed
@@ -1,6 +1,4 @@
 #![feature(try_blocks)]
-#![allow(unreachable_code)]
-#![allow(dead_code)]
 #![allow(clippy::unnecessary_wraps)]
 
 use std::sync::MutexGuard;
@@ -465,3 +463,15 @@ fn issue_13642(x: Option<i32>) -> Option<()> {
 
     None
 }
+
+fn issue_15679() -> Result<i32, String> {
+    let some_result: Result<i32, &'static str> = todo!();
+
+    some_result?;
+
+    some_result?;
+
+    some_result?;
+
+    Ok(0)
+}
diff --git a/src/tools/clippy/tests/ui/question_mark.rs b/src/tools/clippy/tests/ui/question_mark.rs
index f13eee29c11..b5866dac6b8 100644
--- a/src/tools/clippy/tests/ui/question_mark.rs
+++ b/src/tools/clippy/tests/ui/question_mark.rs
@@ -1,6 +1,4 @@
 #![feature(try_blocks)]
-#![allow(unreachable_code)]
-#![allow(dead_code)]
 #![allow(clippy::unnecessary_wraps)]
 
 use std::sync::MutexGuard;
@@ -561,3 +559,27 @@ fn issue_13642(x: Option<i32>) -> Option<()> {
 
     None
 }
+
+fn issue_15679() -> Result<i32, String> {
+    let some_result: Result<i32, &'static str> = todo!();
+
+    match some_result {
+        //~^ question_mark
+        Ok(val) => val,
+        Err(err) => return Err(err.into()),
+    };
+
+    match some_result {
+        //~^ question_mark
+        Ok(val) => val,
+        Err(err) => return Err(Into::into(err)),
+    };
+
+    match some_result {
+        //~^ question_mark
+        Ok(val) => val,
+        Err(err) => return Err(<&str as Into<String>>::into(err)),
+    };
+
+    Ok(0)
+}
diff --git a/src/tools/clippy/tests/ui/question_mark.stderr b/src/tools/clippy/tests/ui/question_mark.stderr
index d8ce4420aee..1ecd936292e 100644
--- a/src/tools/clippy/tests/ui/question_mark.stderr
+++ b/src/tools/clippy/tests/ui/question_mark.stderr
@@ -1,5 +1,5 @@
 error: this block may be rewritten with the `?` operator
-  --> tests/ui/question_mark.rs:9:5
+  --> tests/ui/question_mark.rs:7:5
    |
 LL | /     if a.is_none() {
 LL | |
@@ -11,7 +11,7 @@ LL | |     }
    = help: to override `-D warnings` add `#[allow(clippy::question_mark)]`
 
 error: this block may be rewritten with the `?` operator
-  --> tests/ui/question_mark.rs:55:9
+  --> tests/ui/question_mark.rs:53:9
    |
 LL | /         if (self.opt).is_none() {
 LL | |
@@ -20,7 +20,7 @@ LL | |         }
    | |_________^ help: replace it with: `(self.opt)?;`
 
 error: this block may be rewritten with the `?` operator
-  --> tests/ui/question_mark.rs:60:9
+  --> tests/ui/question_mark.rs:58:9
    |
 LL | /         if self.opt.is_none() {
 LL | |
@@ -29,7 +29,7 @@ LL | |         }
    | |_________^ help: replace it with: `self.opt?;`
 
 error: this block may be rewritten with the `?` operator
-  --> tests/ui/question_mark.rs:65:17
+  --> tests/ui/question_mark.rs:63:17
    |
 LL |           let _ = if self.opt.is_none() {
    |  _________________^
@@ -41,7 +41,7 @@ LL | |         };
    | |_________^ help: replace it with: `Some(self.opt?)`
 
 error: this block may be rewritten with the `?` operator
-  --> tests/ui/question_mark.rs:72:17
+  --> tests/ui/question_mark.rs:70:17
    |
 LL |           let _ = if let Some(x) = self.opt {
    |  _________________^
@@ -53,7 +53,7 @@ LL | |         };
    | |_________^ help: replace it with: `self.opt?`
 
 error: this block may be rewritten with the `?` operator
-  --> tests/ui/question_mark.rs:90:9
+  --> tests/ui/question_mark.rs:88:9
    |
 LL | /         if self.opt.is_none() {
 LL | |
@@ -62,7 +62,7 @@ LL | |         }
    | |_________^ help: replace it with: `self.opt.as_ref()?;`
 
 error: this block may be rewritten with the `?` operator
-  --> tests/ui/question_mark.rs:99:9
+  --> tests/ui/question_mark.rs:97:9
    |
 LL | /         if self.opt.is_none() {
 LL | |
@@ -71,7 +71,7 @@ LL | |         }
    | |_________^ help: replace it with: `self.opt.as_ref()?;`
 
 error: this block may be rewritten with the `?` operator
-  --> tests/ui/question_mark.rs:108:9
+  --> tests/ui/question_mark.rs:106:9
    |
 LL | /         if self.opt.is_none() {
 LL | |
@@ -80,7 +80,7 @@ LL | |         }
    | |_________^ help: replace it with: `self.opt.as_ref()?;`
 
 error: this block may be rewritten with the `?` operator
-  --> tests/ui/question_mark.rs:116:26
+  --> tests/ui/question_mark.rs:114:26
    |
 LL |           let v: &Vec<_> = if let Some(ref v) = self.opt {
    |  __________________________^
@@ -92,7 +92,7 @@ LL | |         };
    | |_________^ help: replace it with: `self.opt.as_ref()?`
 
 error: this block may be rewritten with the `?` operator
-  --> tests/ui/question_mark.rs:127:17
+  --> tests/ui/question_mark.rs:125:17
    |
 LL |           let v = if let Some(v) = self.opt {
    |  _________________^
@@ -104,7 +104,7 @@ LL | |         };
    | |_________^ help: replace it with: `self.opt?`
 
 error: this block may be rewritten with the `?` operator
-  --> tests/ui/question_mark.rs:149:5
+  --> tests/ui/question_mark.rs:147:5
    |
 LL | /     if f().is_none() {
 LL | |
@@ -113,7 +113,7 @@ LL | |     }
    | |_____^ help: replace it with: `f()?;`
 
 error: this `match` expression can be replaced with `?`
-  --> tests/ui/question_mark.rs:154:16
+  --> tests/ui/question_mark.rs:152:16
    |
 LL |       let _val = match f() {
    |  ________________^
@@ -124,7 +124,7 @@ LL | |     };
    | |_____^ help: try instead: `f()?`
 
 error: this `match` expression can be replaced with `?`
-  --> tests/ui/question_mark.rs:165:5
+  --> tests/ui/question_mark.rs:163:5
    |
 LL | /     match f() {
 LL | |
@@ -134,7 +134,7 @@ LL | |     };
    | |_____^ help: try instead: `f()?`
 
 error: this `match` expression can be replaced with `?`
-  --> tests/ui/question_mark.rs:171:5
+  --> tests/ui/question_mark.rs:169:5
    |
 LL | /     match opt_none!() {
 LL | |
@@ -144,13 +144,13 @@ LL | |     };
    | |_____^ help: try instead: `opt_none!()?`
 
 error: this block may be rewritten with the `?` operator
-  --> tests/ui/question_mark.rs:198:13
+  --> tests/ui/question_mark.rs:196:13
    |
 LL |     let _ = if let Ok(x) = x { x } else { return x };
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace it with: `x?`
 
 error: this block may be rewritten with the `?` operator
-  --> tests/ui/question_mark.rs:201:5
+  --> tests/ui/question_mark.rs:199:5
    |
 LL | /     if x.is_err() {
 LL | |
@@ -159,7 +159,7 @@ LL | |     }
    | |_____^ help: replace it with: `x?;`
 
 error: this `match` expression can be replaced with `?`
-  --> tests/ui/question_mark.rs:206:16
+  --> tests/ui/question_mark.rs:204:16
    |
 LL |       let _val = match func_returning_result() {
    |  ________________^
@@ -170,7 +170,7 @@ LL | |     };
    | |_____^ help: try instead: `func_returning_result()?`
 
 error: this `match` expression can be replaced with `?`
-  --> tests/ui/question_mark.rs:212:5
+  --> tests/ui/question_mark.rs:210:5
    |
 LL | /     match func_returning_result() {
 LL | |
@@ -180,7 +180,7 @@ LL | |     };
    | |_____^ help: try instead: `func_returning_result()?`
 
 error: this block may be rewritten with the `?` operator
-  --> tests/ui/question_mark.rs:304:5
+  --> tests/ui/question_mark.rs:302:5
    |
 LL | /     if let Err(err) = func_returning_result() {
 LL | |
@@ -189,7 +189,7 @@ LL | |     }
    | |_____^ help: replace it with: `func_returning_result()?;`
 
 error: this block may be rewritten with the `?` operator
-  --> tests/ui/question_mark.rs:312:5
+  --> tests/ui/question_mark.rs:310:5
    |
 LL | /     if let Err(err) = func_returning_result() {
 LL | |
@@ -198,7 +198,7 @@ LL | |     }
    | |_____^ help: replace it with: `func_returning_result()?;`
 
 error: this block may be rewritten with the `?` operator
-  --> tests/ui/question_mark.rs:395:13
+  --> tests/ui/question_mark.rs:393:13
    |
 LL | /             if a.is_none() {
 LL | |
@@ -208,7 +208,7 @@ LL | |             }
    | |_____________^ help: replace it with: `a?;`
 
 error: this `let...else` may be rewritten with the `?` operator
-  --> tests/ui/question_mark.rs:456:5
+  --> tests/ui/question_mark.rs:454:5
    |
 LL | /     let Some(v) = bar.foo.owned.clone() else {
 LL | |         return None;
@@ -216,7 +216,7 @@ LL | |     };
    | |______^ help: replace it with: `let v = bar.foo.owned.clone()?;`
 
 error: this `let...else` may be rewritten with the `?` operator
-  --> tests/ui/question_mark.rs:471:5
+  --> tests/ui/question_mark.rs:469:5
    |
 LL | /     let Some(ref x) = foo.opt_x else {
 LL | |         return None;
@@ -224,7 +224,7 @@ LL | |     };
    | |______^ help: replace it with: `let x = foo.opt_x.as_ref()?;`
 
 error: this `let...else` may be rewritten with the `?` operator
-  --> tests/ui/question_mark.rs:481:5
+  --> tests/ui/question_mark.rs:479:5
    |
 LL | /     let Some(ref mut x) = foo.opt_x else {
 LL | |         return None;
@@ -232,7 +232,7 @@ LL | |     };
    | |______^ help: replace it with: `let x = foo.opt_x.as_mut()?;`
 
 error: this `let...else` may be rewritten with the `?` operator
-  --> tests/ui/question_mark.rs:492:5
+  --> tests/ui/question_mark.rs:490:5
    |
 LL | /     let Some(ref x @ ref y) = foo.opt_x else {
 LL | |         return None;
@@ -240,7 +240,7 @@ LL | |     };
    | |______^ help: replace it with: `let x @ y = foo.opt_x.as_ref()?;`
 
 error: this `let...else` may be rewritten with the `?` operator
-  --> tests/ui/question_mark.rs:496:5
+  --> tests/ui/question_mark.rs:494:5
    |
 LL | /     let Some(ref x @ WrapperStructWithString(_)) = bar else {
 LL | |         return None;
@@ -248,7 +248,7 @@ LL | |     };
    | |______^ help: replace it with: `let x @ &WrapperStructWithString(_) = bar.as_ref()?;`
 
 error: this `let...else` may be rewritten with the `?` operator
-  --> tests/ui/question_mark.rs:500:5
+  --> tests/ui/question_mark.rs:498:5
    |
 LL | /     let Some(ref mut x @ WrapperStructWithString(_)) = bar else {
 LL | |         return None;
@@ -256,7 +256,7 @@ LL | |     };
    | |______^ help: replace it with: `let x @ &mut WrapperStructWithString(_) = bar.as_mut()?;`
 
 error: this block may be rewritten with the `?` operator
-  --> tests/ui/question_mark.rs:522:5
+  --> tests/ui/question_mark.rs:520:5
    |
 LL | /     if arg.is_none() {
 LL | |
@@ -265,7 +265,7 @@ LL | |     }
    | |_____^ help: replace it with: `arg?;`
 
 error: this `match` expression can be replaced with `?`
-  --> tests/ui/question_mark.rs:526:15
+  --> tests/ui/question_mark.rs:524:15
    |
 LL |       let val = match arg {
    |  _______________^
@@ -276,12 +276,42 @@ LL | |     };
    | |_____^ help: try instead: `arg?`
 
 error: this `let...else` may be rewritten with the `?` operator
-  --> tests/ui/question_mark.rs:536:5
+  --> tests/ui/question_mark.rs:534:5
    |
 LL | /     let Some(a) = *a else {
 LL | |         return None;
 LL | |     };
    | |______^ help: replace it with: `let a = (*a)?;`
 
-error: aborting due to 30 previous errors
+error: this `match` expression can be replaced with `?`
+  --> tests/ui/question_mark.rs:566:5
+   |
+LL | /     match some_result {
+LL | |
+LL | |         Ok(val) => val,
+LL | |         Err(err) => return Err(err.into()),
+LL | |     };
+   | |_____^ help: try instead: `some_result?`
+
+error: this `match` expression can be replaced with `?`
+  --> tests/ui/question_mark.rs:572:5
+   |
+LL | /     match some_result {
+LL | |
+LL | |         Ok(val) => val,
+LL | |         Err(err) => return Err(Into::into(err)),
+LL | |     };
+   | |_____^ help: try instead: `some_result?`
+
+error: this `match` expression can be replaced with `?`
+  --> tests/ui/question_mark.rs:578:5
+   |
+LL | /     match some_result {
+LL | |
+LL | |         Ok(val) => val,
+LL | |         Err(err) => return Err(<&str as Into<String>>::into(err)),
+LL | |     };
+   | |_____^ help: try instead: `some_result?`
+
+error: aborting due to 33 previous errors
 
diff --git a/src/tools/clippy/tests/ui/read_zero_byte_vec.rs b/src/tools/clippy/tests/ui/read_zero_byte_vec.rs
index 938d61b6860..720276cb554 100644
--- a/src/tools/clippy/tests/ui/read_zero_byte_vec.rs
+++ b/src/tools/clippy/tests/ui/read_zero_byte_vec.rs
@@ -120,3 +120,30 @@ fn allow_works<F: std::io::Read>(mut f: F) {
 }
 
 fn main() {}
+
+fn issue15575() -> usize {
+    use std::io::Read;
+    use std::net::TcpListener;
+
+    let listener = TcpListener::bind("127.0.0.1:9010").unwrap();
+    let mut stream_and_addr = listener.accept().unwrap();
+    let mut buf = Vec::with_capacity(32);
+    let num_bytes_received = stream_and_addr.0.read(&mut buf).unwrap();
+    //~^ read_zero_byte_vec
+
+    let cap = 1000;
+    let mut buf = Vec::with_capacity(cap);
+    let num_bytes_received = stream_and_addr.0.read(&mut buf).unwrap();
+    //~^ read_zero_byte_vec
+
+    let cap = 1000;
+    let mut buf = Vec::with_capacity(cap);
+    let num_bytes_received = { stream_and_addr.0.read(&mut buf) }.unwrap();
+    //~^ read_zero_byte_vec
+
+    use std::fs::File;
+    let mut f = File::open("foo.txt").unwrap();
+    let mut data = Vec::with_capacity(100);
+    f.read(&mut data).unwrap()
+    //~^ read_zero_byte_vec
+}
diff --git a/src/tools/clippy/tests/ui/read_zero_byte_vec.stderr b/src/tools/clippy/tests/ui/read_zero_byte_vec.stderr
index 8f255bc87ab..8dd74592e4c 100644
--- a/src/tools/clippy/tests/ui/read_zero_byte_vec.stderr
+++ b/src/tools/clippy/tests/ui/read_zero_byte_vec.stderr
@@ -2,16 +2,27 @@ error: reading zero byte data to `Vec`
   --> tests/ui/read_zero_byte_vec.rs:22:5
    |
 LL |     f.read_exact(&mut data).unwrap();
-   |     ^^^^^^^^^^^^^^^^^^^^^^^ help: try: `data.resize(20, 0); f.read_exact(&mut data)`
+   |     ^^^^^^^^^^^^^^^^^^^^^^^
    |
    = note: `-D clippy::read-zero-byte-vec` implied by `-D warnings`
    = help: to override `-D warnings` add `#[allow(clippy::read_zero_byte_vec)]`
+help: try
+   |
+LL ~     data.resize(20, 0);
+LL ~     f.read_exact(&mut data).unwrap();
+   |
 
 error: reading zero byte data to `Vec`
   --> tests/ui/read_zero_byte_vec.rs:28:5
    |
 LL |     f.read_exact(&mut data2)?;
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `data2.resize(cap, 0); f.read_exact(&mut data2)`
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: try
+   |
+LL ~     data2.resize(cap, 0);
+LL ~     f.read_exact(&mut data2)?;
+   |
 
 error: reading zero byte data to `Vec`
   --> tests/ui/read_zero_byte_vec.rs:33:5
@@ -67,5 +78,53 @@ error: reading zero byte data to `Vec`
 LL |     r.read_exact(&mut data2).await.unwrap();
    |     ^^^^^^^^^^^^^^^^^^^^^^^^
 
-error: aborting due to 11 previous errors
+error: reading zero byte data to `Vec`
+  --> tests/ui/read_zero_byte_vec.rs:131:30
+   |
+LL |     let num_bytes_received = stream_and_addr.0.read(&mut buf).unwrap();
+   |                              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: try
+   |
+LL ~     buf.resize(32, 0);
+LL ~     let num_bytes_received = stream_and_addr.0.read(&mut buf).unwrap();
+   |
+
+error: reading zero byte data to `Vec`
+  --> tests/ui/read_zero_byte_vec.rs:136:30
+   |
+LL |     let num_bytes_received = stream_and_addr.0.read(&mut buf).unwrap();
+   |                              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: try
+   |
+LL ~     buf.resize(cap, 0);
+LL ~     let num_bytes_received = stream_and_addr.0.read(&mut buf).unwrap();
+   |
+
+error: reading zero byte data to `Vec`
+  --> tests/ui/read_zero_byte_vec.rs:141:32
+   |
+LL |     let num_bytes_received = { stream_and_addr.0.read(&mut buf) }.unwrap();
+   |                                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: try
+   |
+LL ~     buf.resize(cap, 0);
+LL ~     let num_bytes_received = { stream_and_addr.0.read(&mut buf) }.unwrap();
+   |
+
+error: reading zero byte data to `Vec`
+  --> tests/ui/read_zero_byte_vec.rs:147:5
+   |
+LL |     f.read(&mut data).unwrap()
+   |     ^^^^^^^^^^^^^^^^^
+   |
+help: try
+   |
+LL ~     data.resize(100, 0);
+LL ~     f.read(&mut data).unwrap()
+   |
+
+error: aborting due to 15 previous errors
 
diff --git a/src/tools/clippy/tests/ui/ref_option/ref_option.all.fixed b/src/tools/clippy/tests/ui/ref_option/ref_option.all.fixed
deleted file mode 100644
index 4159e916f19..00000000000
--- a/src/tools/clippy/tests/ui/ref_option/ref_option.all.fixed
+++ /dev/null
@@ -1,79 +0,0 @@
-//@revisions: private all
-//@[private] rustc-env:CLIPPY_CONF_DIR=tests/ui/ref_option/private
-//@[all] rustc-env:CLIPPY_CONF_DIR=tests/ui/ref_option/all
-
-#![allow(unused, clippy::needless_lifetimes, clippy::borrowed_box)]
-#![warn(clippy::ref_option)]
-
-fn opt_u8(a: Option<&u8>) {}
-//~^ ref_option
-fn opt_gen<T>(a: Option<&T>) {}
-//~^ ref_option
-fn opt_string(a: std::option::Option<&String>) {}
-//~^ ref_option
-fn ret_string<'a>(p: &'a str) -> Option<&'a u8> {
-    //~^ ref_option
-    panic!()
-}
-fn ret_string_static() -> Option<&'static u8> {
-    //~^ ref_option
-    panic!()
-}
-fn mult_string(a: Option<&String>, b: Option<&Vec<u8>>) {}
-//~^ ref_option
-fn ret_box<'a>() -> Option<&'a Box<u8>> {
-    //~^ ref_option
-    panic!()
-}
-
-pub fn pub_opt_string(a: Option<&String>) {}
-//~[all]^ ref_option
-pub fn pub_mult_string(a: Option<&String>, b: Option<&Vec<u8>>) {}
-//~[all]^ ref_option
-
-pub trait PubTrait {
-    fn pub_trait_opt(&self, a: Option<&Vec<u8>>);
-    //~[all]^ ref_option
-    fn pub_trait_ret(&self) -> Option<&Vec<u8>>;
-    //~[all]^ ref_option
-}
-
-trait PrivateTrait {
-    fn trait_opt(&self, a: Option<&String>);
-    //~^ ref_option
-    fn trait_ret(&self) -> Option<&String>;
-    //~^ ref_option
-}
-
-pub struct PubStruct;
-
-impl PubStruct {
-    pub fn pub_opt_params(&self, a: Option<&()>) {}
-    //~[all]^ ref_option
-    pub fn pub_opt_ret(&self) -> Option<&String> {
-        //~[all]^ ref_option
-        panic!()
-    }
-
-    fn private_opt_params(&self, a: Option<&()>) {}
-    //~^ ref_option
-    fn private_opt_ret(&self) -> Option<&String> {
-        //~^ ref_option
-        panic!()
-    }
-}
-
-// valid, don't change
-fn mut_u8(a: &mut Option<u8>) {}
-pub fn pub_mut_u8(a: &mut Option<String>) {}
-
-// might be good to catch in the future
-fn mut_u8_ref(a: &mut &Option<u8>) {}
-pub fn pub_mut_u8_ref(a: &mut &Option<String>) {}
-fn lambdas() {
-    // Not handled for now, not sure if we should
-    let x = |a: &Option<String>| {};
-    let x = |a: &Option<String>| -> &Option<String> { panic!() };
-}
-
-fn main() {}
diff --git a/src/tools/clippy/tests/ui/ref_option/ref_option.private.fixed b/src/tools/clippy/tests/ui/ref_option/ref_option.private.fixed
deleted file mode 100644
index 3b158befb92..00000000000
--- a/src/tools/clippy/tests/ui/ref_option/ref_option.private.fixed
+++ /dev/null
@@ -1,79 +0,0 @@
-//@revisions: private all
-//@[private] rustc-env:CLIPPY_CONF_DIR=tests/ui/ref_option/private
-//@[all] rustc-env:CLIPPY_CONF_DIR=tests/ui/ref_option/all
-
-#![allow(unused, clippy::needless_lifetimes, clippy::borrowed_box)]
-#![warn(clippy::ref_option)]
-
-fn opt_u8(a: Option<&u8>) {}
-//~^ ref_option
-fn opt_gen<T>(a: Option<&T>) {}
-//~^ ref_option
-fn opt_string(a: std::option::Option<&String>) {}
-//~^ ref_option
-fn ret_string<'a>(p: &'a str) -> Option<&'a u8> {
-    //~^ ref_option
-    panic!()
-}
-fn ret_string_static() -> Option<&'static u8> {
-    //~^ ref_option
-    panic!()
-}
-fn mult_string(a: Option<&String>, b: Option<&Vec<u8>>) {}
-//~^ ref_option
-fn ret_box<'a>() -> Option<&'a Box<u8>> {
-    //~^ ref_option
-    panic!()
-}
-
-pub fn pub_opt_string(a: &Option<String>) {}
-//~[all]^ ref_option
-pub fn pub_mult_string(a: &Option<String>, b: &Option<Vec<u8>>) {}
-//~[all]^ ref_option
-
-pub trait PubTrait {
-    fn pub_trait_opt(&self, a: &Option<Vec<u8>>);
-    //~[all]^ ref_option
-    fn pub_trait_ret(&self) -> &Option<Vec<u8>>;
-    //~[all]^ ref_option
-}
-
-trait PrivateTrait {
-    fn trait_opt(&self, a: Option<&String>);
-    //~^ ref_option
-    fn trait_ret(&self) -> Option<&String>;
-    //~^ ref_option
-}
-
-pub struct PubStruct;
-
-impl PubStruct {
-    pub fn pub_opt_params(&self, a: &Option<()>) {}
-    //~[all]^ ref_option
-    pub fn pub_opt_ret(&self) -> &Option<String> {
-        //~[all]^ ref_option
-        panic!()
-    }
-
-    fn private_opt_params(&self, a: Option<&()>) {}
-    //~^ ref_option
-    fn private_opt_ret(&self) -> Option<&String> {
-        //~^ ref_option
-        panic!()
-    }
-}
-
-// valid, don't change
-fn mut_u8(a: &mut Option<u8>) {}
-pub fn pub_mut_u8(a: &mut Option<String>) {}
-
-// might be good to catch in the future
-fn mut_u8_ref(a: &mut &Option<u8>) {}
-pub fn pub_mut_u8_ref(a: &mut &Option<String>) {}
-fn lambdas() {
-    // Not handled for now, not sure if we should
-    let x = |a: &Option<String>| {};
-    let x = |a: &Option<String>| -> &Option<String> { panic!() };
-}
-
-fn main() {}
diff --git a/src/tools/clippy/tests/ui/ref_option/ref_option.rs b/src/tools/clippy/tests/ui/ref_option/ref_option.rs
deleted file mode 100644
index 35cd94174f8..00000000000
--- a/src/tools/clippy/tests/ui/ref_option/ref_option.rs
+++ /dev/null
@@ -1,79 +0,0 @@
-//@revisions: private all
-//@[private] rustc-env:CLIPPY_CONF_DIR=tests/ui/ref_option/private
-//@[all] rustc-env:CLIPPY_CONF_DIR=tests/ui/ref_option/all
-
-#![allow(unused, clippy::needless_lifetimes, clippy::borrowed_box)]
-#![warn(clippy::ref_option)]
-
-fn opt_u8(a: &Option<u8>) {}
-//~^ ref_option
-fn opt_gen<T>(a: &Option<T>) {}
-//~^ ref_option
-fn opt_string(a: &std::option::Option<String>) {}
-//~^ ref_option
-fn ret_string<'a>(p: &'a str) -> &'a Option<u8> {
-    //~^ ref_option
-    panic!()
-}
-fn ret_string_static() -> &'static Option<u8> {
-    //~^ ref_option
-    panic!()
-}
-fn mult_string(a: &Option<String>, b: &Option<Vec<u8>>) {}
-//~^ ref_option
-fn ret_box<'a>() -> &'a Option<Box<u8>> {
-    //~^ ref_option
-    panic!()
-}
-
-pub fn pub_opt_string(a: &Option<String>) {}
-//~[all]^ ref_option
-pub fn pub_mult_string(a: &Option<String>, b: &Option<Vec<u8>>) {}
-//~[all]^ ref_option
-
-pub trait PubTrait {
-    fn pub_trait_opt(&self, a: &Option<Vec<u8>>);
-    //~[all]^ ref_option
-    fn pub_trait_ret(&self) -> &Option<Vec<u8>>;
-    //~[all]^ ref_option
-}
-
-trait PrivateTrait {
-    fn trait_opt(&self, a: &Option<String>);
-    //~^ ref_option
-    fn trait_ret(&self) -> &Option<String>;
-    //~^ ref_option
-}
-
-pub struct PubStruct;
-
-impl PubStruct {
-    pub fn pub_opt_params(&self, a: &Option<()>) {}
-    //~[all]^ ref_option
-    pub fn pub_opt_ret(&self) -> &Option<String> {
-        //~[all]^ ref_option
-        panic!()
-    }
-
-    fn private_opt_params(&self, a: &Option<()>) {}
-    //~^ ref_option
-    fn private_opt_ret(&self) -> &Option<String> {
-        //~^ ref_option
-        panic!()
-    }
-}
-
-// valid, don't change
-fn mut_u8(a: &mut Option<u8>) {}
-pub fn pub_mut_u8(a: &mut Option<String>) {}
-
-// might be good to catch in the future
-fn mut_u8_ref(a: &mut &Option<u8>) {}
-pub fn pub_mut_u8_ref(a: &mut &Option<String>) {}
-fn lambdas() {
-    // Not handled for now, not sure if we should
-    let x = |a: &Option<String>| {};
-    let x = |a: &Option<String>| -> &Option<String> { panic!() };
-}
-
-fn main() {}
diff --git a/src/tools/clippy/tests/ui/ref_option/ref_option_traits.rs b/src/tools/clippy/tests/ui/ref_option/ref_option_traits.rs
deleted file mode 100644
index 4c773e84f8d..00000000000
--- a/src/tools/clippy/tests/ui/ref_option/ref_option_traits.rs
+++ /dev/null
@@ -1,40 +0,0 @@
-//@no-rustfix: fixes are only done to traits, not the impls
-//@revisions: private all
-//@[private] rustc-env:CLIPPY_CONF_DIR=tests/ui/ref_option/private
-//@[all] rustc-env:CLIPPY_CONF_DIR=tests/ui/ref_option/all
-
-#![warn(clippy::ref_option)]
-
-pub trait PubTrait {
-    fn pub_trait_opt(&self, a: &Option<Vec<u8>>);
-    //~[all]^ ref_option
-    fn pub_trait_ret(&self) -> &Option<Vec<u8>>;
-    //~[all]^ ref_option
-}
-
-trait PrivateTrait {
-    fn trait_opt(&self, a: &Option<String>);
-    //~^ ref_option
-    fn trait_ret(&self) -> &Option<String>;
-    //~^ ref_option
-}
-
-pub struct PubStruct;
-
-impl PubTrait for PubStruct {
-    fn pub_trait_opt(&self, a: &Option<Vec<u8>>) {}
-    fn pub_trait_ret(&self) -> &Option<Vec<u8>> {
-        panic!()
-    }
-}
-
-struct PrivateStruct;
-
-impl PrivateTrait for PrivateStruct {
-    fn trait_opt(&self, a: &Option<String>) {}
-    fn trait_ret(&self) -> &Option<String> {
-        panic!()
-    }
-}
-
-fn main() {}
diff --git a/src/tools/clippy/tests/ui/rest_pat_in_fully_bound_structs.fixed b/src/tools/clippy/tests/ui/rest_pat_in_fully_bound_structs.fixed
new file mode 100644
index 00000000000..ac200b3b19b
--- /dev/null
+++ b/src/tools/clippy/tests/ui/rest_pat_in_fully_bound_structs.fixed
@@ -0,0 +1,61 @@
+#![warn(clippy::rest_pat_in_fully_bound_structs)]
+#![allow(clippy::struct_field_names)]
+
+struct A {
+    a: i32,
+    b: i64,
+    c: &'static str,
+}
+
+macro_rules! foo {
+    ($param:expr) => {
+        match $param {
+            A { a: 0, b: 0, c: "", .. } => {},
+            _ => {},
+        }
+    };
+}
+
+fn main() {
+    let a_struct = A { a: 5, b: 42, c: "A" };
+
+    match a_struct {
+        A { a: 5, b: 42, c: "",  } => {}, // Lint
+        //~^ rest_pat_in_fully_bound_structs
+        A { a: 0, b: 0, c: "",  } => {}, // Lint
+        //~^ rest_pat_in_fully_bound_structs
+        _ => {},
+    }
+
+    match a_struct {
+        A { a: 5, b: 42, .. } => {},
+        A { a: 0, b: 0, c: "",  } => {}, // Lint
+        //~^ rest_pat_in_fully_bound_structs
+        _ => {},
+    }
+
+    // No lint
+    match a_struct {
+        A { a: 5, .. } => {},
+        A { a: 0, b: 0, .. } => {},
+        _ => {},
+    }
+
+    // No lint
+    foo!(a_struct);
+
+    #[non_exhaustive]
+    struct B {
+        a: u32,
+        b: u32,
+        c: u64,
+    }
+
+    let b_struct = B { a: 5, b: 42, c: 342 };
+
+    match b_struct {
+        B { a: 5, b: 42, .. } => {},
+        B { a: 0, b: 0, c: 128, .. } => {}, // No Lint
+        _ => {},
+    }
+}
diff --git a/src/tools/clippy/tests/ui/rest_pat_in_fully_bound_structs.stderr b/src/tools/clippy/tests/ui/rest_pat_in_fully_bound_structs.stderr
index d048933ddb7..8a2da302b9e 100644
--- a/src/tools/clippy/tests/ui/rest_pat_in_fully_bound_structs.stderr
+++ b/src/tools/clippy/tests/ui/rest_pat_in_fully_bound_structs.stderr
@@ -4,9 +4,13 @@ error: unnecessary use of `..` pattern in struct binding. All fields were alread
 LL |         A { a: 5, b: 42, c: "", .. } => {}, // Lint
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
-   = help: consider removing `..` from this binding
    = note: `-D clippy::rest-pat-in-fully-bound-structs` implied by `-D warnings`
    = help: to override `-D warnings` add `#[allow(clippy::rest_pat_in_fully_bound_structs)]`
+help: consider removing `..` from this binding
+   |
+LL -         A { a: 5, b: 42, c: "", .. } => {}, // Lint
+LL +         A { a: 5, b: 42, c: "",  } => {}, // Lint
+   |
 
 error: unnecessary use of `..` pattern in struct binding. All fields were already bound
   --> tests/ui/rest_pat_in_fully_bound_structs.rs:25:9
@@ -14,7 +18,11 @@ error: unnecessary use of `..` pattern in struct binding. All fields were alread
 LL |         A { a: 0, b: 0, c: "", .. } => {}, // Lint
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
-   = help: consider removing `..` from this binding
+help: consider removing `..` from this binding
+   |
+LL -         A { a: 0, b: 0, c: "", .. } => {}, // Lint
+LL +         A { a: 0, b: 0, c: "",  } => {}, // Lint
+   |
 
 error: unnecessary use of `..` pattern in struct binding. All fields were already bound
   --> tests/ui/rest_pat_in_fully_bound_structs.rs:32:9
@@ -22,7 +30,11 @@ error: unnecessary use of `..` pattern in struct binding. All fields were alread
 LL |         A { a: 0, b: 0, c: "", .. } => {}, // Lint
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
-   = help: consider removing `..` from this binding
+help: consider removing `..` from this binding
+   |
+LL -         A { a: 0, b: 0, c: "", .. } => {}, // Lint
+LL +         A { a: 0, b: 0, c: "",  } => {}, // Lint
+   |
 
 error: aborting due to 3 previous errors
 
diff --git a/src/tools/clippy/tests/ui/semicolon_inside_block.fixed b/src/tools/clippy/tests/ui/semicolon_inside_block.fixed
index 7308e78aae2..468f0a5b1e4 100644
--- a/src/tools/clippy/tests/ui/semicolon_inside_block.fixed
+++ b/src/tools/clippy/tests/ui/semicolon_inside_block.fixed
@@ -3,7 +3,8 @@
     clippy::unused_unit,
     clippy::unnecessary_operation,
     clippy::no_effect,
-    clippy::single_element_loop
+    clippy::single_element_loop,
+    clippy::double_parens
 )]
 #![warn(clippy::semicolon_inside_block)]
 
@@ -87,6 +88,20 @@ fn main() {
     unit_fn_block()
 }
 
+#[rustfmt::skip]
+fn issue15380() {
+    ( {0;0});
+
+    ({
+        0;
+        0
+    });
+
+    (({ 0 }))      ;
+
+    ( ( { 0 } ) ) ;
+}
+
 pub fn issue15388() {
     #[rustfmt::skip]
     {0; 0};
diff --git a/src/tools/clippy/tests/ui/semicolon_inside_block.rs b/src/tools/clippy/tests/ui/semicolon_inside_block.rs
index 467bf4d779f..101374af264 100644
--- a/src/tools/clippy/tests/ui/semicolon_inside_block.rs
+++ b/src/tools/clippy/tests/ui/semicolon_inside_block.rs
@@ -3,7 +3,8 @@
     clippy::unused_unit,
     clippy::unnecessary_operation,
     clippy::no_effect,
-    clippy::single_element_loop
+    clippy::single_element_loop,
+    clippy::double_parens
 )]
 #![warn(clippy::semicolon_inside_block)]
 
@@ -87,6 +88,20 @@ fn main() {
     unit_fn_block()
 }
 
+#[rustfmt::skip]
+fn issue15380() {
+    ( {0;0});
+
+    ({
+        0;
+        0
+    });
+
+    (({ 0 }))      ;
+
+    ( ( { 0 } ) ) ;
+}
+
 pub fn issue15388() {
     #[rustfmt::skip]
     {0; 0};
diff --git a/src/tools/clippy/tests/ui/semicolon_inside_block.stderr b/src/tools/clippy/tests/ui/semicolon_inside_block.stderr
index 23433f4e7ef..2046dd1c36b 100644
--- a/src/tools/clippy/tests/ui/semicolon_inside_block.stderr
+++ b/src/tools/clippy/tests/ui/semicolon_inside_block.stderr
@@ -1,5 +1,5 @@
 error: consider moving the `;` inside the block for consistent formatting
-  --> tests/ui/semicolon_inside_block.rs:38:5
+  --> tests/ui/semicolon_inside_block.rs:39:5
    |
 LL |     { unit_fn_block() };
    |     ^^^^^^^^^^^^^^^^^^^^
@@ -13,7 +13,7 @@ LL +     { unit_fn_block(); }
    |
 
 error: consider moving the `;` inside the block for consistent formatting
-  --> tests/ui/semicolon_inside_block.rs:40:5
+  --> tests/ui/semicolon_inside_block.rs:41:5
    |
 LL |     unsafe { unit_fn_block() };
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -25,7 +25,7 @@ LL +     unsafe { unit_fn_block(); }
    |
 
 error: consider moving the `;` inside the block for consistent formatting
-  --> tests/ui/semicolon_inside_block.rs:49:5
+  --> tests/ui/semicolon_inside_block.rs:50:5
    |
 LL | /     {
 LL | |
@@ -41,7 +41,7 @@ LL ~     }
    |
 
 error: consider moving the `;` inside the block for consistent formatting
-  --> tests/ui/semicolon_inside_block.rs:63:5
+  --> tests/ui/semicolon_inside_block.rs:64:5
    |
 LL |     { m!(()) };
    |     ^^^^^^^^^^^
diff --git a/src/tools/clippy/tests/ui/track-diagnostics-clippy.stderr b/src/tools/clippy/tests/ui/track-diagnostics-clippy.stderr
index d5533877b45..3ceb501463b 100644
--- a/src/tools/clippy/tests/ui/track-diagnostics-clippy.stderr
+++ b/src/tools/clippy/tests/ui/track-diagnostics-clippy.stderr
@@ -16,7 +16,7 @@ LL |         let d = 42;
 LL |         d
    |         ^
    |
-   = note: -Ztrack-diagnostics: created at clippy_lints/src/returns.rs:LL:CC
+   = note: -Ztrack-diagnostics: created at clippy_lints/src/returns/let_and_return.rs:LL:CC
    = note: `-D clippy::let-and-return` implied by `-D warnings`
    = help: to override `-D warnings` add `#[allow(clippy::let_and_return)]`
 help: return the expression directly
diff --git a/src/tools/clippy/tests/ui/transmute_ptr_to_ref.fixed b/src/tools/clippy/tests/ui/transmute_ptr_to_ref.fixed
index 61e3ac2fe88..c130575df96 100644
--- a/src/tools/clippy/tests/ui/transmute_ptr_to_ref.fixed
+++ b/src/tools/clippy/tests/ui/transmute_ptr_to_ref.fixed
@@ -5,7 +5,7 @@
     clippy::missing_transmute_annotations
 )]
 
-unsafe fn _ptr_to_ref<T, U>(p: *const T, m: *mut T, o: *const U, om: *mut U) {
+fn ptr_to_ref<T, U>(p: *const T, m: *mut T, o: *const U, om: *mut U) {
     unsafe {
         let _: &T = &*p;
         //~^ transmute_ptr_to_ref
@@ -37,7 +37,7 @@ unsafe fn _ptr_to_ref<T, U>(p: *const T, m: *mut T, o: *const U, om: *mut U) {
     }
 }
 
-fn _issue1231() {
+fn issue1231() {
     struct Foo<'a, T> {
         bar: &'a T,
     }
@@ -55,7 +55,7 @@ fn _issue1231() {
     //~^ transmute_ptr_to_ref
 }
 
-unsafe fn _issue8924<'a, 'b, 'c>(x: *const &'a u32, y: *const &'b u32) -> &'c &'b u32 {
+fn issue8924<'a, 'b, 'c>(x: *const &'a u32, y: *const &'b u32) -> &'c &'b u32 {
     unsafe {
         match 0 {
             0 => &*x.cast::<&u32>(),
@@ -71,7 +71,7 @@ unsafe fn _issue8924<'a, 'b, 'c>(x: *const &'a u32, y: *const &'b u32) -> &'c &'
 }
 
 #[clippy::msrv = "1.38"]
-unsafe fn _meets_msrv<'a, 'b, 'c>(x: *const &'a u32) -> &'c &'b u32 {
+fn meets_msrv<'a, 'b, 'c>(x: *const &'a u32) -> &'c &'b u32 {
     unsafe {
         let a = 0u32;
         let a = &a as *const u32;
@@ -89,7 +89,7 @@ unsafe fn _meets_msrv<'a, 'b, 'c>(x: *const &'a u32) -> &'c &'b u32 {
 }
 
 #[clippy::msrv = "1.37"]
-unsafe fn _under_msrv<'a, 'b, 'c>(x: *const &'a u32) -> &'c &'b u32 {
+fn under_msrv<'a, 'b, 'c>(x: *const &'a u32) -> &'c &'b u32 {
     unsafe {
         let a = 0u32;
         let a = &a as *const u32;
@@ -106,4 +106,33 @@ unsafe fn _under_msrv<'a, 'b, 'c>(x: *const &'a u32) -> &'c &'b u32 {
     }
 }
 
+// handle DSTs
+fn issue13357(ptr: *const [i32], s_ptr: *const &str, a_s_ptr: *const [&str]) {
+    unsafe {
+        // different types, without erased regions
+        let _ = &*(ptr as *const [u32]);
+        //~^ transmute_ptr_to_ref
+        let _: &[u32] = &*(ptr as *const [u32]);
+        //~^ transmute_ptr_to_ref
+
+        // different types, with erased regions
+        let _ = &*(a_s_ptr as *const [&[u8]]);
+        //~^ transmute_ptr_to_ref
+        let _: &[&[u8]] = &*(a_s_ptr as *const [&[u8]]);
+        //~^ transmute_ptr_to_ref
+
+        // same type, without erased regions
+        let _ = &*(ptr as *const [i32]);
+        //~^ transmute_ptr_to_ref
+        let _: &[i32] = &*ptr;
+        //~^ transmute_ptr_to_ref
+
+        // same type, with erased regions
+        let _ = &*(a_s_ptr as *const [&str]);
+        //~^ transmute_ptr_to_ref
+        let _: &[&str] = &*(a_s_ptr as *const [&str]);
+        //~^ transmute_ptr_to_ref
+    }
+}
+
 fn main() {}
diff --git a/src/tools/clippy/tests/ui/transmute_ptr_to_ref.rs b/src/tools/clippy/tests/ui/transmute_ptr_to_ref.rs
index 48e2f527b55..f79d54234a2 100644
--- a/src/tools/clippy/tests/ui/transmute_ptr_to_ref.rs
+++ b/src/tools/clippy/tests/ui/transmute_ptr_to_ref.rs
@@ -5,7 +5,7 @@
     clippy::missing_transmute_annotations
 )]
 
-unsafe fn _ptr_to_ref<T, U>(p: *const T, m: *mut T, o: *const U, om: *mut U) {
+fn ptr_to_ref<T, U>(p: *const T, m: *mut T, o: *const U, om: *mut U) {
     unsafe {
         let _: &T = std::mem::transmute(p);
         //~^ transmute_ptr_to_ref
@@ -37,7 +37,7 @@ unsafe fn _ptr_to_ref<T, U>(p: *const T, m: *mut T, o: *const U, om: *mut U) {
     }
 }
 
-fn _issue1231() {
+fn issue1231() {
     struct Foo<'a, T> {
         bar: &'a T,
     }
@@ -55,7 +55,7 @@ fn _issue1231() {
     //~^ transmute_ptr_to_ref
 }
 
-unsafe fn _issue8924<'a, 'b, 'c>(x: *const &'a u32, y: *const &'b u32) -> &'c &'b u32 {
+fn issue8924<'a, 'b, 'c>(x: *const &'a u32, y: *const &'b u32) -> &'c &'b u32 {
     unsafe {
         match 0 {
             0 => std::mem::transmute(x),
@@ -71,7 +71,7 @@ unsafe fn _issue8924<'a, 'b, 'c>(x: *const &'a u32, y: *const &'b u32) -> &'c &'
 }
 
 #[clippy::msrv = "1.38"]
-unsafe fn _meets_msrv<'a, 'b, 'c>(x: *const &'a u32) -> &'c &'b u32 {
+fn meets_msrv<'a, 'b, 'c>(x: *const &'a u32) -> &'c &'b u32 {
     unsafe {
         let a = 0u32;
         let a = &a as *const u32;
@@ -89,7 +89,7 @@ unsafe fn _meets_msrv<'a, 'b, 'c>(x: *const &'a u32) -> &'c &'b u32 {
 }
 
 #[clippy::msrv = "1.37"]
-unsafe fn _under_msrv<'a, 'b, 'c>(x: *const &'a u32) -> &'c &'b u32 {
+fn under_msrv<'a, 'b, 'c>(x: *const &'a u32) -> &'c &'b u32 {
     unsafe {
         let a = 0u32;
         let a = &a as *const u32;
@@ -106,4 +106,33 @@ unsafe fn _under_msrv<'a, 'b, 'c>(x: *const &'a u32) -> &'c &'b u32 {
     }
 }
 
+// handle DSTs
+fn issue13357(ptr: *const [i32], s_ptr: *const &str, a_s_ptr: *const [&str]) {
+    unsafe {
+        // different types, without erased regions
+        let _ = core::mem::transmute::<_, &[u32]>(ptr);
+        //~^ transmute_ptr_to_ref
+        let _: &[u32] = core::mem::transmute(ptr);
+        //~^ transmute_ptr_to_ref
+
+        // different types, with erased regions
+        let _ = core::mem::transmute::<_, &[&[u8]]>(a_s_ptr);
+        //~^ transmute_ptr_to_ref
+        let _: &[&[u8]] = core::mem::transmute(a_s_ptr);
+        //~^ transmute_ptr_to_ref
+
+        // same type, without erased regions
+        let _ = core::mem::transmute::<_, &[i32]>(ptr);
+        //~^ transmute_ptr_to_ref
+        let _: &[i32] = core::mem::transmute(ptr);
+        //~^ transmute_ptr_to_ref
+
+        // same type, with erased regions
+        let _ = core::mem::transmute::<_, &[&str]>(a_s_ptr);
+        //~^ transmute_ptr_to_ref
+        let _: &[&str] = core::mem::transmute(a_s_ptr);
+        //~^ transmute_ptr_to_ref
+    }
+}
+
 fn main() {}
diff --git a/src/tools/clippy/tests/ui/transmute_ptr_to_ref.stderr b/src/tools/clippy/tests/ui/transmute_ptr_to_ref.stderr
index 7685c345c86..3f404d295fe 100644
--- a/src/tools/clippy/tests/ui/transmute_ptr_to_ref.stderr
+++ b/src/tools/clippy/tests/ui/transmute_ptr_to_ref.stderr
@@ -43,13 +43,13 @@ error: transmute from a pointer type (`*mut U`) to a reference type (`&T`)
 LL |         let _: &T = std::mem::transmute(om);
    |                     ^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&*(om as *const T)`
 
-error: transmute from a pointer type (`*const i32`) to a reference type (`&_issue1231::Foo<'_, u8>`)
+error: transmute from a pointer type (`*const i32`) to a reference type (`&issue1231::Foo<'_, u8>`)
   --> tests/ui/transmute_ptr_to_ref.rs:46:32
    |
 LL |     let _: &Foo<u8> = unsafe { std::mem::transmute::<_, &Foo<_>>(raw) };
    |                                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&*raw.cast::<Foo<_>>()`
 
-error: transmute from a pointer type (`*const i32`) to a reference type (`&_issue1231::Foo<'_, &u8>`)
+error: transmute from a pointer type (`*const i32`) to a reference type (`&issue1231::Foo<'_, &u8>`)
   --> tests/ui/transmute_ptr_to_ref.rs:49:33
    |
 LL |     let _: &Foo<&u8> = unsafe { std::mem::transmute::<_, &Foo<&_>>(raw) };
@@ -133,5 +133,53 @@ error: transmute from a pointer type (`*const &u32`) to a reference type (`&&u32
 LL |             _ => std::mem::transmute::<_, &&'b u32>(x),
    |                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&*(x as *const () as *const &'b u32)`
 
-error: aborting due to 22 previous errors
+error: transmute from a pointer type (`*const [i32]`) to a reference type (`&[u32]`)
+  --> tests/ui/transmute_ptr_to_ref.rs:113:17
+   |
+LL |         let _ = core::mem::transmute::<_, &[u32]>(ptr);
+   |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&*(ptr as *const [u32])`
+
+error: transmute from a pointer type (`*const [i32]`) to a reference type (`&[u32]`)
+  --> tests/ui/transmute_ptr_to_ref.rs:115:25
+   |
+LL |         let _: &[u32] = core::mem::transmute(ptr);
+   |                         ^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&*(ptr as *const [u32])`
+
+error: transmute from a pointer type (`*const [&str]`) to a reference type (`&[&[u8]]`)
+  --> tests/ui/transmute_ptr_to_ref.rs:119:17
+   |
+LL |         let _ = core::mem::transmute::<_, &[&[u8]]>(a_s_ptr);
+   |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&*(a_s_ptr as *const [&[u8]])`
+
+error: transmute from a pointer type (`*const [&str]`) to a reference type (`&[&[u8]]`)
+  --> tests/ui/transmute_ptr_to_ref.rs:121:27
+   |
+LL |         let _: &[&[u8]] = core::mem::transmute(a_s_ptr);
+   |                           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&*(a_s_ptr as *const [&[u8]])`
+
+error: transmute from a pointer type (`*const [i32]`) to a reference type (`&[i32]`)
+  --> tests/ui/transmute_ptr_to_ref.rs:125:17
+   |
+LL |         let _ = core::mem::transmute::<_, &[i32]>(ptr);
+   |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&*(ptr as *const [i32])`
+
+error: transmute from a pointer type (`*const [i32]`) to a reference type (`&[i32]`)
+  --> tests/ui/transmute_ptr_to_ref.rs:127:25
+   |
+LL |         let _: &[i32] = core::mem::transmute(ptr);
+   |                         ^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&*ptr`
+
+error: transmute from a pointer type (`*const [&str]`) to a reference type (`&[&str]`)
+  --> tests/ui/transmute_ptr_to_ref.rs:131:17
+   |
+LL |         let _ = core::mem::transmute::<_, &[&str]>(a_s_ptr);
+   |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&*(a_s_ptr as *const [&str])`
+
+error: transmute from a pointer type (`*const [&str]`) to a reference type (`&[&str]`)
+  --> tests/ui/transmute_ptr_to_ref.rs:133:26
+   |
+LL |         let _: &[&str] = core::mem::transmute(a_s_ptr);
+   |                          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&*(a_s_ptr as *const [&str])`
+
+error: aborting due to 30 previous errors
 
diff --git a/src/tools/clippy/tests/ui/use_self.fixed b/src/tools/clippy/tests/ui/use_self.fixed
index cccb6bffabb..075e31d202b 100644
--- a/src/tools/clippy/tests/ui/use_self.fixed
+++ b/src/tools/clippy/tests/ui/use_self.fixed
@@ -530,8 +530,8 @@ mod issue7206 {
 
     impl<'a> S2<S<'a>> {
         fn new_again() -> Self {
-            Self::new()
-            //~^ use_self
+            S2::new()
+            // FIXME: ^Broken by PR #15611
         }
     }
 }
@@ -755,3 +755,17 @@ mod crash_check_13128 {
         }
     }
 }
+
+mod issue_13277 {
+    trait Foo {
+        type Item<'foo>;
+    }
+    struct Bar<'b> {
+        content: &'b str,
+    }
+    impl<'b> Foo for Option<Bar<'b>> {
+        // when checking whether `Option<Bar<'foo>>` has a lifetime, check not only the outer
+        // `Option<T>`, but also the inner `Bar<'foo>`
+        type Item<'foo> = Option<Bar<'foo>>;
+    }
+}
diff --git a/src/tools/clippy/tests/ui/use_self.rs b/src/tools/clippy/tests/ui/use_self.rs
index 09288677aa7..6fbba0bbc55 100644
--- a/src/tools/clippy/tests/ui/use_self.rs
+++ b/src/tools/clippy/tests/ui/use_self.rs
@@ -531,7 +531,7 @@ mod issue7206 {
     impl<'a> S2<S<'a>> {
         fn new_again() -> Self {
             S2::new()
-            //~^ use_self
+            // FIXME: ^Broken by PR #15611
         }
     }
 }
@@ -755,3 +755,17 @@ mod crash_check_13128 {
         }
     }
 }
+
+mod issue_13277 {
+    trait Foo {
+        type Item<'foo>;
+    }
+    struct Bar<'b> {
+        content: &'b str,
+    }
+    impl<'b> Foo for Option<Bar<'b>> {
+        // when checking whether `Option<Bar<'foo>>` has a lifetime, check not only the outer
+        // `Option<T>`, but also the inner `Bar<'foo>`
+        type Item<'foo> = Option<Bar<'foo>>;
+    }
+}
diff --git a/src/tools/clippy/tests/ui/use_self.stderr b/src/tools/clippy/tests/ui/use_self.stderr
index 781327696ac..5f65c53ea25 100644
--- a/src/tools/clippy/tests/ui/use_self.stderr
+++ b/src/tools/clippy/tests/ui/use_self.stderr
@@ -170,12 +170,6 @@ LL |             A::new::<submod::B>(submod::B {})
    |             ^ help: use the applicable keyword: `Self`
 
 error: unnecessary structure name repetition
-  --> tests/ui/use_self.rs:533:13
-   |
-LL |             S2::new()
-   |             ^^ help: use the applicable keyword: `Self`
-
-error: unnecessary structure name repetition
   --> tests/ui/use_self.rs:571:17
    |
 LL |                 Foo::Bar => unimplemented!(),
@@ -259,5 +253,5 @@ error: unnecessary structure name repetition
 LL |                 E::A => {},
    |                 ^ help: use the applicable keyword: `Self`
 
-error: aborting due to 43 previous errors
+error: aborting due to 42 previous errors
 
diff --git a/src/tools/clippy/tests/ui/useless_attribute.fixed b/src/tools/clippy/tests/ui/useless_attribute.fixed
index be4fb55ddfb..15070dd9c2c 100644
--- a/src/tools/clippy/tests/ui/useless_attribute.fixed
+++ b/src/tools/clippy/tests/ui/useless_attribute.fixed
@@ -158,3 +158,13 @@ pub mod redundant_imports_issue {
 
     empty!();
 }
+
+pub mod issue15636 {
+    pub mod f {
+        #[deprecated(since = "TBD")]
+        pub mod deprec {}
+    }
+
+    #[allow(deprecated_in_future)]
+    pub use f::deprec;
+}
diff --git a/src/tools/clippy/tests/ui/useless_attribute.rs b/src/tools/clippy/tests/ui/useless_attribute.rs
index 5a1bcf97a5b..3f530de7fd8 100644
--- a/src/tools/clippy/tests/ui/useless_attribute.rs
+++ b/src/tools/clippy/tests/ui/useless_attribute.rs
@@ -158,3 +158,13 @@ pub mod redundant_imports_issue {
 
     empty!();
 }
+
+pub mod issue15636 {
+    pub mod f {
+        #[deprecated(since = "TBD")]
+        pub mod deprec {}
+    }
+
+    #[allow(deprecated_in_future)]
+    pub use f::deprec;
+}
diff --git a/src/tools/enzyme b/src/tools/enzyme
-Subproject 58af4e9e6c047534ba059b12af17cecb8a2e9f9
+Subproject 09f4820b78e2d71b85a3278bbb41dc3a012e84d
diff --git a/src/tools/miri/src/clock.rs b/src/tools/miri/src/clock.rs
index 47608f873a4..dbbe741a071 100644
--- a/src/tools/miri/src/clock.rs
+++ b/src/tools/miri/src/clock.rs
@@ -46,7 +46,21 @@ impl Instant {
                 InstantKind::Virtual { nanoseconds: earlier },
             ) => {
                 let duration = nanoseconds.saturating_sub(earlier);
-                Duration::from_nanos_u128(duration)
+                cfg_select! {
+                    bootstrap => {
+                         // `Duration` does not provide a nice constructor from a `u128` of nanoseconds,
+                        // so we have to implement this ourselves.
+                        // It is possible for second to overflow because u64::MAX < (u128::MAX / 1e9).
+                        // It will be saturated to u64::MAX seconds if the value after division exceeds u64::MAX.
+                        let seconds = u64::try_from(duration / 1_000_000_000).unwrap_or(u64::MAX);
+                        // It is impossible for nanosecond to overflow because u32::MAX > 1e9.
+                        let nanosecond = u32::try_from(duration.wrapping_rem(1_000_000_000)).unwrap();
+                        Duration::new(seconds, nanosecond)
+                    }
+                    _ => {
+                        Duration::from_nanos_u128(duration)
+                    }
+                }
             }
             _ => panic!("all `Instant` must be of the same kind"),
         }
diff --git a/src/tools/miri/src/lib.rs b/src/tools/miri/src/lib.rs
index dbc2a99593d..7f5f25b9f66 100644
--- a/src/tools/miri/src/lib.rs
+++ b/src/tools/miri/src/lib.rs
@@ -18,7 +18,7 @@
 #![feature(derive_coerce_pointee)]
 #![feature(arbitrary_self_types)]
 #![feature(iter_advance_by)]
-#![feature(duration_from_nanos_u128)]
+#![cfg_attr(not(bootstrap), feature(duration_from_nanos_u128))]
 // Configure clippy and other lints
 #![allow(
     clippy::collapsible_else_if,
diff --git a/src/tools/tidy/Readme.md b/src/tools/tidy/Readme.md
new file mode 100644
index 00000000000..fc9dc6350e9
--- /dev/null
+++ b/src/tools/tidy/Readme.md
@@ -0,0 +1,112 @@
+# Tidy
+Tidy is the Rust project's custom internal linter and a crucial part of our testing and continuous integration (CI) infrastructure. It is designed to enforce a consistent style and formatting across the entire codebase, but its role extends beyond simple linting. Tidy also helps with infrastructure, policy, and documentation, ensuring the project remains organized, functional, and... tidy.
+
+This document will cover how to use tidy, the specific checks tidy performs, and using tidy directives to manage its behavior. By understanding and utilizing tidy, you can help us maintain the high standards of the Rust project.
+## Tidy Checks
+### Style and Code Quality
+These lints focus on enforcing consistent formatting, style, and general code health.
+* [`alphabetical`](https://doc.rust-lang.org/nightly/nightly-rustc/tidy/alphabetical/index.html): Checks that lists are sorted alphabetically
+* [`style`](https://doc.rust-lang.org/nightly/nightly-rustc/tidy/style/index.html): Check to enforce various stylistic guidelines on the Rust codebase.
+* [`filenames`](https://doc.rust-lang.org/nightly/nightly-rustc/tidy/filenames/index.html): Check to prevent invalid characters in file names.
+* [`pal`](https://doc.rust-lang.org/nightly/nightly-rustc/tidy/pal/index.html): Check to enforce rules about platform-specific code in std.
+* [`target_policy`](https://doc.rust-lang.org/nightly/nightly-rustc/tidy/target_policy/index.html): Check for target tier policy compliance.
+* [`error_codes`](https://doc.rust-lang.org/nightly/nightly-rustc/tidy/error_codes/index.html): Check to ensure error codes are properly documented and tested.
+
+### Infrastructure
+These checks focus on the integrity of the project's dependencies, internal tools, and documentation.
+* [`bins`](https://doc.rust-lang.org/nightly/nightly-rustc/tidy/bins/index.html): Prevent stray binaries from being checked into the source tree.
+* [`fluent_alphabetical`](https://doc.rust-lang.org/nightly/nightly-rustc/tidy/fluent_alphabetical/index.html) / [`fluent_period`](https://doc.rust-lang.org/nightly/nightly-rustc/tidy/fluent_period/index.html) / [`fluent_used`](https://doc.rust-lang.org/nightly/nightly-rustc/tidy/fluent_used/index.html): Various checks related to [Fluent](https://github.com/projectfluent) for localization and natural language translation.
+* [`deps`](https://doc.rust-lang.org/nightly/nightly-rustc/tidy/deps/index.html) / [`extdeps`](https://doc.rust-lang.org/nightly/nightly-rustc/tidy/extdeps/index.html): Check for valid licenses and sources for external dependencies.
+* [`gcc_submodule`](https://doc.rust-lang.org/nightly/nightly-rustc/tidy/gcc_submodule/index.html): Check that the `src/gcc` submodule version is valid.
+* [`triagebot`](https://doc.rust-lang.org/nightly/nightly-rustc/tidy/triagebot/index.html): Check to ensure paths mentioned in `triagebot.toml` exist in the project.
+* [`x_version`](https://doc.rust-lang.org/nightly/nightly-rustc/tidy/x_version/index.html): Validates the current version of the `x` tool.
+
+* [`edition`](https://doc.rust-lang.org/nightly/nightly-rustc/tidy/edition/index.html) / [`features`](https://doc.rust-lang.org/nightly/nightly-rustc/tidy/features/index.html): Check for a valid Rust edition and proper ordering of unstable features.
+* [`rustdoc_css_themes`](https://doc.rust-lang.org/nightly/nightly-rustc/tidy/rustdoc_css_themes/index.html) / [`rustdoc_templates`](https://doc.rust-lang.org/nightly/nightly-rustc/tidy/rustdoc_templates/index.html): Verify that Rust documentation templates and themes are correct.
+* [`unstable_book`](https://doc.rust-lang.org/nightly/nightly-rustc/tidy/unstable_book/index.html): Synchronizes the unstable book with unstable features.
+### Testing
+These checks ensure that tests are correctly structured, cleaned up, and free of common errors.
+* [`tests_placement`](https://doc.rust-lang.org/nightly/nightly-rustc/tidy/tests_placement/index.html) / [`unit_tests`](https://doc.rust-lang.org/nightly/nightly-rustc/tidy/unit_tests/index.html): Verify that tests are located in the correct directories and are not using improper attributes.
+* [`known_bug`](https://doc.rust-lang.org/nightly/nightly-rustc/tidy/known_bug/index.html) / [`unknown_revision`](https://doc.rust-lang.org/nightly/nightly-rustc/tidy/unknown_revision/index.html): Ensure that test directives and annotations are used correctly.
+* [`debug_artifacts`](https://doc.rust-lang.org/nightly/nightly-rustc/tidy/debug_artifacts/index.html) / [`mir_opt_tests`](https://doc.rust-lang.org/nightly/nightly-rustc/tidy/mir_opt_tests/index.html): Prevent unnecessary artifacts and stale files in test directories.
+* [`tests_revision_unpaired_stdout_stderr`](https://doc.rust-lang.org/nightly/nightly-rustc/tidy/tests_revision_unpaired_stdout_stderr/index.html) / [`ui_tests`](https://doc.rust-lang.org/nightly/nightly-rustc/tidy/ui_tests/index.html): Check for unpaired or stray test output files.
+* [`target_specific_tests`](https://doc.rust-lang.org/nightly/nightly-rustc/tidy/target_specific_tests/index.html): Check to ensure that all target specific tests (those that require a --target flag) also require the pre-requisite LLVM components to run.
+* [`rustdoc_gui_tests`](https://doc.rust-lang.org/nightly/nightly-rustc/tidy/rustdoc_gui_tests/index.html): Checks that rustdoc gui tests start with a small description
+* [`rustdoc_json`](https://doc.rust-lang.org/nightly/nightly-rustc/tidy/rustdoc_json/index.html): Verify that `FORMAT_VERSION` is in sync with `rust-json-types`.
+## Using Tidy
+
+Tidy is used in a number of different ways.
+* Every time `./x test` is used tidy will run automatically.
+
+* On every pull request, tidy will run automatically during CI checks.
+* Optionally, with the use of git-hooks, tidy can run locally on every push. This can be setup with `./x setup`. See the [rustc-dev-guide](https://rustc-dev-guide.rust-lang.org/building/suggested.html#installing-a-pre-push-hook) for more information.
+
+You can run tidy manually with:
+
+`./x test tidy`
+
+To first run the relevant formatter and then run tidy you can add `--bless`.
+
+`./x test tidy --bless`
+### Extra Checks
+[`extra_checks`](https://doc.rust-lang.org/nightly/nightly-rustc/tidy/extra_checks/index.html) are optional checks primarily focused on other file types and programming languages.
+
+Example usage:
+
+`./x test tidy --extra-checks=py,cpp,js,spellcheck`
+
+All options for `--extra-checks`:
+* `cpp`, `cpp:fmt`
+* `py`, `py:lint`, `py:fmt`
+* `js`, `js:lint`, `js:fmt`, `js:typecheck`
+* `shell`, `shell:lint`
+* `spellcheck`
+
+Default values for tidy's `extra-checks` can be set in `bootstrap.toml`. For example, `build.tidy-extra-checks = "js,py"`.
+
+Any argument without a suffix (eg. `py` or `js`) will include all possible checks. For example, `--extra-checks=js` is the same as `extra-checks=js:lint,js:fmt,js:typecheck`.
+
+Any argument can be prefixed with `auto:` to only run if relevant files are modified (eg. `--extra-checks=auto:py`).
+
+A specific configuration file or folder can be passed to tidy after a double dash (`--extra-checks=py -- foo.py`)
+
+## Tidy Directives
+
+Tidy directives are special comments that help tidy operate.
+
+Tidy directives can be used in the following types of comments:
+* `// `
+* `# `
+* `/* {...} */`
+* `<!-- {...} -->`
+
+You might find yourself needing to ignore a specific tidy style check and can do so with:
+* `ignore-tidy-cr`
+* `ignore-tidy-undocumented-unsafe`
+* `ignore-tidy-tab`
+* `ignore-tidy-linelength`
+* `ignore-tidy-filelength`
+
+* `ignore-tidy-end-whitespace`
+* `ignore-tidy-trailing-newlines`
+* `ignore-tidy-leading-newlines`
+* `ignore-tidy-copyright`
+* `ignore-tidy-dbg`
+* `ignore-tidy-odd-backticks`
+* `ignore-tidy-todo`
+
+Some checks, like `alphabetical`, require a tidy directive to use:
+```
+// tidy-alphabetical-start
+fn aaa() {}
+fn eee() {}
+fn z() {}
+// tidy-alphabetical-end
+```
+<!--ignore-tidy-todo-->While not exactly a tidy directive, // TODO will fail tidy and make sure you can't merge a PR with unfinished work.
+
+### Test Specific Directives
+
+`target-specific-tests` can be ignored with `// ignore-tidy-target-specific-tests`
+
+Tidy's `unknown_revision` check can be suppressed by adding the revision name to `//@ unused-revision-names:{revision}` or with `//@ unused-revision-names:*`.
diff --git a/src/tools/tidy/src/lib.rs b/src/tools/tidy/src/lib.rs
index 2a9c3963d2d..f7920e3205a 100644
--- a/src/tools/tidy/src/lib.rs
+++ b/src/tools/tidy/src/lib.rs
@@ -237,7 +237,7 @@ pub fn ensure_version_or_cargo_install(
     if !cargo_exit_code.success() {
         return Err(io::Error::other("cargo install failed"));
     }
-    let bin_path = tool_bin_dir.join(bin_name);
+    let bin_path = tool_bin_dir.join(bin_name).with_extension(env::consts::EXE_EXTENSION);
     assert!(
         matches!(bin_path.try_exists(), Ok(true)),
         "cargo install did not produce the expected binary"
diff --git a/src/tools/tidy/src/pal.rs b/src/tools/tidy/src/pal.rs
index 5b8b44429bb..991ad55809c 100644
--- a/src/tools/tidy/src/pal.rs
+++ b/src/tools/tidy/src/pal.rs
@@ -53,6 +53,7 @@ const EXCEPTION_PATHS: &[&str] = &[
     // core::ffi contains platform-specific type and linkage configuration
     "library/core/src/ffi/mod.rs",
     "library/core/src/ffi/primitives.rs",
+    "library/core/src/os", // Platform-specific public interfaces
     "library/std/src/sys", // Platform-specific code for std lives here.
     "library/std/src/os",  // Platform-specific public interfaces
     // Temporary `std` exceptions