about summary refs log tree commit diff
diff options
context:
space:
mode:
authorPhilipp Krones <hello@philkrones.com>2025-08-22 14:57:22 +0200
committerPhilipp Krones <hello@philkrones.com>2025-08-22 14:57:22 +0200
commit9a348e8da88967bdef72b450482f3d5f8eaf88ff (patch)
treed7ae0b563d98e281ab4ed33dee58386ebe9a6af1
parent831e291d3be4cacc4fe178424c4d6baa264d8b5a (diff)
parent877967959ae8da9814df4f2614971f4d784bf53f (diff)
downloadrust-9a348e8da88967bdef72b450482f3d5f8eaf88ff.tar.gz
rust-9a348e8da88967bdef72b450482f3d5f8eaf88ff.zip
Merge commit '877967959ae8da9814df4f2614971f4d784bf53f' into clippy-subtree-update
-rw-r--r--src/tools/clippy/.github/workflows/clippy_dev.yml2
-rw-r--r--src/tools/clippy/.github/workflows/clippy_mq.yml8
-rw-r--r--src/tools/clippy/.github/workflows/clippy_pr.yml2
-rw-r--r--src/tools/clippy/.github/workflows/deploy.yml4
-rw-r--r--src/tools/clippy/.github/workflows/feature_freeze.yml2
-rw-r--r--src/tools/clippy/.github/workflows/lintcheck.yml6
-rw-r--r--src/tools/clippy/.github/workflows/remark.yml2
-rw-r--r--src/tools/clippy/CONTRIBUTING.md12
-rw-r--r--src/tools/clippy/Cargo.toml11
-rw-r--r--src/tools/clippy/book/src/continuous_integration/github_actions.md2
-rw-r--r--src/tools/clippy/book/src/development/basics.md4
-rw-r--r--src/tools/clippy/book/src/development/common_tools_writing_lints.md2
-rw-r--r--src/tools/clippy/book/src/lint_configuration.md2
-rw-r--r--src/tools/clippy/clippy_config/src/conf.rs2
-rw-r--r--src/tools/clippy/clippy_dev/src/dogfood.rs49
-rw-r--r--src/tools/clippy/clippy_dev/src/lib.rs7
-rw-r--r--src/tools/clippy/clippy_dev/src/lint.rs56
-rw-r--r--src/tools/clippy/clippy_dev/src/main.rs11
-rw-r--r--src/tools/clippy/clippy_dev/src/serve.rs107
-rw-r--r--src/tools/clippy/clippy_dev/src/setup/git_hook.rs6
-rw-r--r--src/tools/clippy/clippy_dev/src/setup/mod.rs20
-rw-r--r--src/tools/clippy/clippy_dev/src/setup/toolchain.rs19
-rw-r--r--src/tools/clippy/clippy_dev/src/setup/vscode.rs6
-rw-r--r--src/tools/clippy/clippy_dev/src/utils.rs62
-rw-r--r--src/tools/clippy/clippy_lints/src/casts/borrow_as_ptr.rs9
-rw-r--r--src/tools/clippy/clippy_lints/src/casts/char_lit_as_u8.rs11
-rw-r--r--src/tools/clippy/clippy_lints/src/casts/mod.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/casts/ptr_as_ptr.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/cognitive_complexity.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/collapsible_if.rs22
-rw-r--r--src/tools/clippy/clippy_lints/src/declared_lints.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/dereference.rs11
-rw-r--r--src/tools/clippy/clippy_lints/src/doc/mod.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/eta_reduction.rs6
-rw-r--r--src/tools/clippy/clippy_lints/src/from_str_radix_10.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/functions/duplicate_underscore_argument.rs34
-rw-r--r--src/tools/clippy/clippy_lints/src/functions/mod.rs39
-rw-r--r--src/tools/clippy/clippy_lints/src/functions/renamed_function_params.rs21
-rw-r--r--src/tools/clippy/clippy_lints/src/functions/result.rs6
-rw-r--r--src/tools/clippy/clippy_lints/src/functions/too_many_lines.rs6
-rw-r--r--src/tools/clippy/clippy_lints/src/len_zero.rs41
-rw-r--r--src/tools/clippy/clippy_lints/src/lib.rs3
-rw-r--r--src/tools/clippy/clippy_lints/src/loops/infinite_loop.rs48
-rw-r--r--src/tools/clippy/clippy_lints/src/manual_let_else.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/matches/match_bool.rs6
-rw-r--r--src/tools/clippy/clippy_lints/src/matches/match_ref_pats.rs5
-rw-r--r--src/tools/clippy/clippy_lints/src/matches/match_str_case_mismatch.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/double_ended_iterator_last.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/expect_fun_call.rs75
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/filter_map.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/filter_next.rs18
-rw-r--r--src/tools/clippy/clippy_lints/src/misc_early/mod.rs57
-rw-r--r--src/tools/clippy/clippy_lints/src/mixed_read_write_in_expression.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/needless_bool.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/needless_borrows_for_generic_args.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/no_effect.rs3
-rw-r--r--src/tools/clippy/clippy_lints/src/non_copy_const.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/non_expressive_names.rs5
-rw-r--r--src/tools/clippy/clippy_lints/src/only_used_in_recursion.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/operators/arithmetic_side_effects.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/operators/numeric_arithmetic.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/pass_by_ref_or_value.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/ptr.rs61
-rw-r--r--src/tools/clippy/clippy_lints/src/raw_strings.rs10
-rw-r--r--src/tools/clippy/clippy_lints/src/redundant_pub_crate.rs3
-rw-r--r--src/tools/clippy/clippy_lints/src/reference.rs141
-rw-r--r--src/tools/clippy/clippy_lints/src/swap.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/transmute/eager_transmute.rs8
-rw-r--r--src/tools/clippy/clippy_lints/src/transmute/mod.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/undocumented_unsafe_blocks.rs194
-rw-r--r--src/tools/clippy/clippy_lints/src/unnecessary_box_returns.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/unnecessary_semicolon.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/unnested_or_patterns.rs8
-rw-r--r--src/tools/clippy/clippy_lints/src/unwrap.rs72
-rw-r--r--src/tools/clippy/clippy_lints/src/zero_sized_map_values.rs3
-rw-r--r--src/tools/clippy/clippy_lints_internal/src/derive_deserialize_allowing_unknown.rs15
-rw-r--r--src/tools/clippy/clippy_test_deps/Cargo.lock4
-rw-r--r--src/tools/clippy/clippy_utils/README.md2
-rw-r--r--src/tools/clippy/clippy_utils/src/ast_utils/mod.rs55
-rw-r--r--src/tools/clippy/clippy_utils/src/check_proc_macro.rs9
-rw-r--r--src/tools/clippy/clippy_utils/src/diagnostics.rs15
-rw-r--r--src/tools/clippy/clippy_utils/src/hir_utils.rs2
-rw-r--r--src/tools/clippy/clippy_utils/src/lib.rs17
-rw-r--r--src/tools/clippy/clippy_utils/src/msrvs.rs36
-rw-r--r--src/tools/clippy/clippy_utils/src/ty/mod.rs12
-rw-r--r--src/tools/clippy/rust-toolchain.toml2
-rw-r--r--src/tools/clippy/tests/ui-cargo/undocumented_unsafe_blocks/fail/Cargo.stderr26
-rw-r--r--src/tools/clippy/tests/ui-cargo/undocumented_unsafe_blocks/fail/Cargo.toml12
-rw-r--r--src/tools/clippy/tests/ui-cargo/undocumented_unsafe_blocks/fail/src/main.rs7
-rw-r--r--src/tools/clippy/tests/ui-toml/functions_maxlines/test.stderr35
-rw-r--r--src/tools/clippy/tests/ui/as_ptr_cast_mut.fixed38
-rw-r--r--src/tools/clippy/tests/ui/as_ptr_cast_mut.rs4
-rw-r--r--src/tools/clippy/tests/ui/as_ptr_cast_mut.stderr10
-rw-r--r--src/tools/clippy/tests/ui/as_ptr_cast_mut_unfixable.rs16
-rw-r--r--src/tools/clippy/tests/ui/as_ptr_cast_mut_unfixable.stderr11
-rw-r--r--src/tools/clippy/tests/ui/borrow_as_ptr.fixed12
-rw-r--r--src/tools/clippy/tests/ui/borrow_as_ptr.rs12
-rw-r--r--src/tools/clippy/tests/ui/borrow_as_ptr.stderr14
-rw-r--r--src/tools/clippy/tests/ui/char_lit_as_u8.fixed (renamed from src/tools/clippy/tests/ui/char_lit_as_u8_suggestions.fixed)0
-rw-r--r--src/tools/clippy/tests/ui/char_lit_as_u8.rs9
-rw-r--r--src/tools/clippy/tests/ui/char_lit_as_u8.stderr32
-rw-r--r--src/tools/clippy/tests/ui/char_lit_as_u8_suggestions.rs12
-rw-r--r--src/tools/clippy/tests/ui/char_lit_as_u8_suggestions.stderr36
-rw-r--r--src/tools/clippy/tests/ui/char_lit_as_u8_unfixable.rs8
-rw-r--r--src/tools/clippy/tests/ui/char_lit_as_u8_unfixable.stderr12
-rw-r--r--src/tools/clippy/tests/ui/deref_addrof.fixed88
-rw-r--r--src/tools/clippy/tests/ui/deref_addrof.rs88
-rw-r--r--src/tools/clippy/tests/ui/deref_addrof.stderr56
-rw-r--r--src/tools/clippy/tests/ui/doc/doc-fixable.fixed2
-rw-r--r--src/tools/clippy/tests/ui/doc/doc-fixable.rs2
-rw-r--r--src/tools/clippy/tests/ui/double_ended_iterator_last.fixed11
-rw-r--r--src/tools/clippy/tests/ui/double_ended_iterator_last.rs11
-rw-r--r--src/tools/clippy/tests/ui/double_ended_iterator_last.stderr17
-rw-r--r--src/tools/clippy/tests/ui/double_ended_iterator_last_unfixable.rs39
-rw-r--r--src/tools/clippy/tests/ui/double_ended_iterator_last_unfixable.stderr19
-rw-r--r--src/tools/clippy/tests/ui/eta.fixed29
-rw-r--r--src/tools/clippy/tests/ui/eta.rs29
-rw-r--r--src/tools/clippy/tests/ui/eta.stderr96
-rw-r--r--src/tools/clippy/tests/ui/from_str_radix_10.fixed10
-rw-r--r--src/tools/clippy/tests/ui/from_str_radix_10.rs10
-rw-r--r--src/tools/clippy/tests/ui/from_str_radix_10.stderr14
-rw-r--r--src/tools/clippy/tests/ui/functions_maxlines.rs115
-rw-r--r--src/tools/clippy/tests/ui/functions_maxlines.stderr22
-rw-r--r--src/tools/clippy/tests/ui/infinite_loops.rs71
-rw-r--r--src/tools/clippy/tests/ui/infinite_loops.stderr24
-rw-r--r--src/tools/clippy/tests/ui/match_bool.fixed13
-rw-r--r--src/tools/clippy/tests/ui/match_bool.rs13
-rw-r--r--src/tools/clippy/tests/ui/match_ref_pats.fixed36
-rw-r--r--src/tools/clippy/tests/ui/match_ref_pats.rs36
-rw-r--r--src/tools/clippy/tests/ui/match_ref_pats.stderr10
-rw-r--r--src/tools/clippy/tests/ui/ptr_as_ptr.fixed8
-rw-r--r--src/tools/clippy/tests/ui/ptr_as_ptr.rs6
-rw-r--r--src/tools/clippy/tests/ui/ptr_as_ptr.stderr64
-rw-r--r--src/tools/clippy/tests/ui/similar_names.rs4
-rw-r--r--src/tools/clippy/tests/ui/similar_names.stderr4
-rw-r--r--src/tools/clippy/tests/ui/unnecessary_operation.fixed10
-rw-r--r--src/tools/clippy/tests/ui/unnecessary_operation.stderr10
-rw-r--r--src/tools/clippy/tests/ui/unnecessary_semicolon.edition2021.fixed9
-rw-r--r--src/tools/clippy/tests/ui/unnecessary_semicolon.edition2024.fixed9
-rw-r--r--src/tools/clippy/tests/ui/unnecessary_semicolon.rs9
-rw-r--r--src/tools/clippy/tests/ui/zero_sized_hashmap_values.rs8
-rw-r--r--src/tools/clippy/tests/ui/zero_sized_hashmap_values.stderr6
142 files changed, 1823 insertions, 1050 deletions
diff --git a/src/tools/clippy/.github/workflows/clippy_dev.yml b/src/tools/clippy/.github/workflows/clippy_dev.yml
index d6534fbaff9..d530eb6c73a 100644
--- a/src/tools/clippy/.github/workflows/clippy_dev.yml
+++ b/src/tools/clippy/.github/workflows/clippy_dev.yml
@@ -16,7 +16,7 @@ jobs:
     steps:
     # Setup
     - name: Checkout
-      uses: actions/checkout@v4
+      uses: actions/checkout@v5
       with:
         # Unsetting this would make so that any malicious package could get our Github Token
         persist-credentials: false
diff --git a/src/tools/clippy/.github/workflows/clippy_mq.yml b/src/tools/clippy/.github/workflows/clippy_mq.yml
index 07d5a08304e..0bcb7135935 100644
--- a/src/tools/clippy/.github/workflows/clippy_mq.yml
+++ b/src/tools/clippy/.github/workflows/clippy_mq.yml
@@ -36,7 +36,7 @@ jobs:
     steps:
     # Setup
     - name: Checkout
-      uses: actions/checkout@v4
+      uses: actions/checkout@v5
       with:
         persist-credentials: false
 
@@ -96,7 +96,7 @@ jobs:
     steps:
      # Setup
     - name: Checkout
-      uses: actions/checkout@v4
+      uses: actions/checkout@v5
       with:
         persist-credentials: false
 
@@ -114,7 +114,7 @@ jobs:
     steps:
     # Setup
     - name: Checkout
-      uses: actions/checkout@v4
+      uses: actions/checkout@v5
       with:
         persist-credentials: false
 
@@ -170,7 +170,7 @@ jobs:
     steps:
     # Setup
     - name: Checkout
-      uses: actions/checkout@v4
+      uses: actions/checkout@v5
       with:
         persist-credentials: false
 
diff --git a/src/tools/clippy/.github/workflows/clippy_pr.yml b/src/tools/clippy/.github/workflows/clippy_pr.yml
index 880ebd6e5d5..d91c638a8fb 100644
--- a/src/tools/clippy/.github/workflows/clippy_pr.yml
+++ b/src/tools/clippy/.github/workflows/clippy_pr.yml
@@ -24,7 +24,7 @@ jobs:
     steps:
     # Setup
     - name: Checkout
-      uses: actions/checkout@v4
+      uses: actions/checkout@v5
       with:
         # Unsetting this would make so that any malicious package could get our Github Token
         persist-credentials: false
diff --git a/src/tools/clippy/.github/workflows/deploy.yml b/src/tools/clippy/.github/workflows/deploy.yml
index ede19c11257..48c5bd36dbc 100644
--- a/src/tools/clippy/.github/workflows/deploy.yml
+++ b/src/tools/clippy/.github/workflows/deploy.yml
@@ -25,13 +25,13 @@ jobs:
     steps:
     # Setup
     - name: Checkout
-      uses: actions/checkout@v4
+      uses: actions/checkout@v5
       with:
         # Unsetting this would make so that any malicious package could get our Github Token
         persist-credentials: false
 
     - name: Checkout
-      uses: actions/checkout@v4
+      uses: actions/checkout@v5
       with:
         ref: ${{ env.TARGET_BRANCH }}
         path: 'out'
diff --git a/src/tools/clippy/.github/workflows/feature_freeze.yml b/src/tools/clippy/.github/workflows/feature_freeze.yml
index ec59be3e7f6..5b139e76700 100644
--- a/src/tools/clippy/.github/workflows/feature_freeze.yml
+++ b/src/tools/clippy/.github/workflows/feature_freeze.yml
@@ -16,7 +16,7 @@ jobs:
     permissions:
       pull-requests: write
 
-    # Do not in any case add code that runs anything coming from the  the content
+    # 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:
diff --git a/src/tools/clippy/.github/workflows/lintcheck.yml b/src/tools/clippy/.github/workflows/lintcheck.yml
index 003d0395739..390d6a0f747 100644
--- a/src/tools/clippy/.github/workflows/lintcheck.yml
+++ b/src/tools/clippy/.github/workflows/lintcheck.yml
@@ -24,7 +24,7 @@ jobs:
 
     steps:
     - name: Checkout
-      uses: actions/checkout@v4
+      uses: actions/checkout@v5
       with:
         fetch-depth: 2
         # Unsetting this would make so that any malicious package could get our Github Token
@@ -80,7 +80,7 @@ jobs:
 
     steps:
     - name: Checkout
-      uses: actions/checkout@v4
+      uses: actions/checkout@v5
       with:
         # Unsetting this would make so that any malicious package could get our Github Token
         persist-credentials: false
@@ -113,7 +113,7 @@ jobs:
 
     steps:
     - name: Checkout
-      uses: actions/checkout@v4
+      uses: actions/checkout@v5
       with:
         # Unsetting this would make so that any malicious package could get our Github Token
         persist-credentials: false
diff --git a/src/tools/clippy/.github/workflows/remark.yml b/src/tools/clippy/.github/workflows/remark.yml
index 7e7e26818c0..c9d350ee0b3 100644
--- a/src/tools/clippy/.github/workflows/remark.yml
+++ b/src/tools/clippy/.github/workflows/remark.yml
@@ -11,7 +11,7 @@ jobs:
     steps:
     # Setup
     - name: Checkout
-      uses: actions/checkout@v4
+      uses: actions/checkout@v5
       with:
         # Unsetting this would make so that any malicious package could get our Github Token
         persist-credentials: false
diff --git a/src/tools/clippy/CONTRIBUTING.md b/src/tools/clippy/CONTRIBUTING.md
index 42ed624ec21..f7f0a1ce249 100644
--- a/src/tools/clippy/CONTRIBUTING.md
+++ b/src/tools/clippy/CONTRIBUTING.md
@@ -17,7 +17,7 @@ All contributors are expected to follow the [Rust Code of Conduct].
   - [High level approach](#high-level-approach)
   - [Finding something to fix/improve](#finding-something-to-fiximprove)
   - [Getting code-completion for rustc internals to work](#getting-code-completion-for-rustc-internals-to-work)
-    - [IntelliJ Rust](#intellij-rust)
+    - [RustRover](#rustrover)
     - [Rust Analyzer](#rust-analyzer)
   - [How Clippy works](#how-clippy-works)
   - [Issue and PR triage](#issue-and-pr-triage)
@@ -92,22 +92,22 @@ an AST expression).
 
 ## Getting code-completion for rustc internals to work
 
-### IntelliJ Rust
-Unfortunately, [`IntelliJ Rust`][IntelliJ_rust_homepage] does not (yet?) understand how Clippy uses compiler-internals
+### RustRover
+Unfortunately, [`RustRover`][RustRover_homepage] does not (yet?) understand how Clippy uses compiler-internals
 using `extern crate` and it also needs to be able to read the source files of the rustc-compiler which are not
 available via a `rustup` component at the time of writing.
 To work around this, you need to have a copy of the [rustc-repo][rustc_repo] available which can be obtained via
 `git clone https://github.com/rust-lang/rust/`.
 Then you can run a `cargo dev` command to automatically make Clippy use the rustc-repo via path-dependencies
-which `IntelliJ Rust` will be able to understand.
+which `RustRover` will be able to understand.
 Run `cargo dev setup intellij --repo-path <repo-path>` where `<repo-path>` is a path to the rustc repo
 you just cloned.
 The command will add path-dependencies pointing towards rustc-crates inside the rustc repo to
-Clippy's `Cargo.toml`s and should allow `IntelliJ Rust` to understand most of the types that Clippy uses.
+Clippy's `Cargo.toml`s and should allow `RustRover` to understand most of the types that Clippy uses.
 Just make sure to remove the dependencies again before finally making a pull request!
 
 [rustc_repo]: https://github.com/rust-lang/rust/
-[IntelliJ_rust_homepage]: https://intellij-rust.github.io/
+[RustRover_homepage]: https://www.jetbrains.com/rust/
 
 ### Rust Analyzer
 For [`rust-analyzer`][ra_homepage] to work correctly make sure that in the `rust-analyzer` configuration you set
diff --git a/src/tools/clippy/Cargo.toml b/src/tools/clippy/Cargo.toml
index daf1c98cdc9..2add525b7e8 100644
--- a/src/tools/clippy/Cargo.toml
+++ b/src/tools/clippy/Cargo.toml
@@ -64,3 +64,14 @@ harness = false
 [[test]]
 name = "dogfood"
 harness = false
+
+# quine-mc_cluskey makes up a significant part of the runtime in dogfood
+# due to the number of conditions in the clippy_lints crate
+# and enabling optimizations for that specific dependency helps a bit
+# without increasing total build times.
+[profile.dev.package.quine-mc_cluskey]
+opt-level = 3
+
+[lints.rust.unexpected_cfgs]
+level = "warn"
+check-cfg = ['cfg(bootstrap)']
diff --git a/src/tools/clippy/book/src/continuous_integration/github_actions.md b/src/tools/clippy/book/src/continuous_integration/github_actions.md
index b588c8f0f02..62d32446d92 100644
--- a/src/tools/clippy/book/src/continuous_integration/github_actions.md
+++ b/src/tools/clippy/book/src/continuous_integration/github_actions.md
@@ -15,7 +15,7 @@ jobs:
   clippy_check:
     runs-on: ubuntu-latest
     steps:
-      - uses: actions/checkout@v4
+      - uses: actions/checkout@v5
       - name: Run Clippy
         run: cargo clippy --all-targets --all-features
 ```
diff --git a/src/tools/clippy/book/src/development/basics.md b/src/tools/clippy/book/src/development/basics.md
index fc405249bcf..19f626ab804 100644
--- a/src/tools/clippy/book/src/development/basics.md
+++ b/src/tools/clippy/book/src/development/basics.md
@@ -95,7 +95,7 @@ cargo dev new_lint
 cargo dev deprecate
 # automatically formatting all code before each commit
 cargo dev setup git-hook
-# (experimental) Setup Clippy to work with IntelliJ-Rust
+# (experimental) Setup Clippy to work with RustRover
 cargo dev setup intellij
 # runs the `dogfood` tests
 cargo dev dogfood
@@ -103,7 +103,7 @@ cargo dev dogfood
 
 More about [intellij] command usage and reasons.
 
-[intellij]: https://github.com/rust-lang/rust-clippy/blob/master/CONTRIBUTING.md#intellij-rust
+[intellij]: https://github.com/rust-lang/rust-clippy/blob/master/CONTRIBUTING.md#rustrover
 
 ## lintcheck
 
diff --git a/src/tools/clippy/book/src/development/common_tools_writing_lints.md b/src/tools/clippy/book/src/development/common_tools_writing_lints.md
index e23b32039c9..3bec3ce33af 100644
--- a/src/tools/clippy/book/src/development/common_tools_writing_lints.md
+++ b/src/tools/clippy/book/src/development/common_tools_writing_lints.md
@@ -141,7 +141,7 @@ impl LateLintPass<'_> for MyStructLint {
             // we are looking for the `DefId` of `Drop` trait in lang items
             .drop_trait()
             // then we use it with our type `ty` by calling `implements_trait` from Clippy's utils
-            .map_or(false, |id| implements_trait(cx, ty, id, &[])) {
+            .is_some_and(|id| implements_trait(cx, ty, id, &[])) {
                 // `expr` implements `Drop` trait
             }
     }
diff --git a/src/tools/clippy/book/src/lint_configuration.md b/src/tools/clippy/book/src/lint_configuration.md
index 7f16f3a9810..05590ff7b1c 100644
--- a/src/tools/clippy/book/src/lint_configuration.md
+++ b/src/tools/clippy/book/src/lint_configuration.md
@@ -555,7 +555,7 @@ default configuration of Clippy. By default, any configuration will replace the
 * `doc-valid-idents = ["ClipPy"]` would replace the default list with `["ClipPy"]`.
 * `doc-valid-idents = ["ClipPy", ".."]` would append `ClipPy` to the default list.
 
-**Default Value:** `["KiB", "MiB", "GiB", "TiB", "PiB", "EiB", "MHz", "GHz", "THz", "AccessKit", "CoAP", "CoreFoundation", "CoreGraphics", "CoreText", "DevOps", "Direct2D", "Direct3D", "DirectWrite", "DirectX", "ECMAScript", "GPLv2", "GPLv3", "GitHub", "GitLab", "IPv4", "IPv6", "ClojureScript", "CoffeeScript", "JavaScript", "PostScript", "PureScript", "TypeScript", "WebAssembly", "NaN", "NaNs", "OAuth", "GraphQL", "OCaml", "OpenAL", "OpenDNS", "OpenGL", "OpenMP", "OpenSSH", "OpenSSL", "OpenStreetMap", "OpenTelemetry", "OpenType", "WebGL", "WebGL2", "WebGPU", "WebRTC", "WebSocket", "WebTransport", "WebP", "OpenExr", "YCbCr", "sRGB", "TensorFlow", "TrueType", "iOS", "macOS", "FreeBSD", "NetBSD", "OpenBSD", "NixOS", "TeX", "LaTeX", "BibTeX", "BibLaTeX", "MinGW", "CamelCase"]`
+**Default Value:** `["KiB", "MiB", "GiB", "TiB", "PiB", "EiB", "MHz", "GHz", "THz", "AccessKit", "CoAP", "CoreFoundation", "CoreGraphics", "CoreText", "DevOps", "Direct2D", "Direct3D", "DirectWrite", "DirectX", "ECMAScript", "GPLv2", "GPLv3", "GitHub", "GitLab", "IPv4", "IPv6", "ClojureScript", "CoffeeScript", "JavaScript", "PostScript", "PureScript", "TypeScript", "PowerPC", "WebAssembly", "NaN", "NaNs", "OAuth", "GraphQL", "OCaml", "OpenAL", "OpenDNS", "OpenGL", "OpenMP", "OpenSSH", "OpenSSL", "OpenStreetMap", "OpenTelemetry", "OpenType", "WebGL", "WebGL2", "WebGPU", "WebRTC", "WebSocket", "WebTransport", "WebP", "OpenExr", "YCbCr", "sRGB", "TensorFlow", "TrueType", "iOS", "macOS", "FreeBSD", "NetBSD", "OpenBSD", "NixOS", "TeX", "LaTeX", "BibTeX", "BibLaTeX", "MinGW", "CamelCase"]`
 
 ---
 **Affected lints:**
diff --git a/src/tools/clippy/clippy_config/src/conf.rs b/src/tools/clippy/clippy_config/src/conf.rs
index 8167d75583e..2ad3f2efcdd 100644
--- a/src/tools/clippy/clippy_config/src/conf.rs
+++ b/src/tools/clippy/clippy_config/src/conf.rs
@@ -34,7 +34,7 @@ const DEFAULT_DOC_VALID_IDENTS: &[&str] = &[
     "GitHub", "GitLab",
     "IPv4", "IPv6",
     "ClojureScript", "CoffeeScript", "JavaScript", "PostScript", "PureScript", "TypeScript",
-    "WebAssembly",
+    "PowerPC", "WebAssembly",
     "NaN", "NaNs",
     "OAuth", "GraphQL",
     "OCaml",
diff --git a/src/tools/clippy/clippy_dev/src/dogfood.rs b/src/tools/clippy/clippy_dev/src/dogfood.rs
index 7e9d92458d0..d0fca952b93 100644
--- a/src/tools/clippy/clippy_dev/src/dogfood.rs
+++ b/src/tools/clippy/clippy_dev/src/dogfood.rs
@@ -1,35 +1,28 @@
-use crate::utils::exit_if_err;
-use std::process::Command;
+use crate::utils::{cargo_cmd, run_exit_on_err};
+use itertools::Itertools;
 
 /// # Panics
 ///
 /// Panics if unable to run the dogfood test
 #[allow(clippy::fn_params_excessive_bools)]
 pub fn dogfood(fix: bool, allow_dirty: bool, allow_staged: bool, allow_no_vcs: bool) {
-    let mut cmd = Command::new("cargo");
-
-    cmd.args(["test", "--test", "dogfood"])
-        .args(["--features", "internal"])
-        .args(["--", "dogfood_clippy", "--nocapture"]);
-
-    let mut dogfood_args = Vec::new();
-    if fix {
-        dogfood_args.push("--fix");
-    }
-
-    if allow_dirty {
-        dogfood_args.push("--allow-dirty");
-    }
-
-    if allow_staged {
-        dogfood_args.push("--allow-staged");
-    }
-
-    if allow_no_vcs {
-        dogfood_args.push("--allow-no-vcs");
-    }
-
-    cmd.env("__CLIPPY_DOGFOOD_ARGS", dogfood_args.join(" "));
-
-    exit_if_err(cmd.status());
+    run_exit_on_err(
+        "cargo test",
+        cargo_cmd()
+            .args(["test", "--test", "dogfood"])
+            .args(["--features", "internal"])
+            .args(["--", "dogfood_clippy", "--nocapture"])
+            .env(
+                "__CLIPPY_DOGFOOD_ARGS",
+                [
+                    if fix { "--fix" } else { "" },
+                    if allow_dirty { "--allow-dirty" } else { "" },
+                    if allow_staged { "--allow-staged" } else { "" },
+                    if allow_no_vcs { "--allow-no-vcs" } else { "" },
+                ]
+                .iter()
+                .filter(|x| !x.is_empty())
+                .join(" "),
+            ),
+    );
 }
diff --git a/src/tools/clippy/clippy_dev/src/lib.rs b/src/tools/clippy/clippy_dev/src/lib.rs
index 40aadf4589a..16f413e0c86 100644
--- a/src/tools/clippy/clippy_dev/src/lib.rs
+++ b/src/tools/clippy/clippy_dev/src/lib.rs
@@ -15,8 +15,7 @@
 )]
 #![allow(clippy::missing_panics_doc)]
 
-// The `rustc_driver` crate seems to be required in order to use the `rust_lexer` crate.
-#[allow(unused_extern_crates)]
+#[expect(unused_extern_crates, reason = "required to link to rustc crates")]
 extern crate rustc_driver;
 extern crate rustc_lexer;
 extern crate rustc_literal_escaper;
@@ -32,4 +31,6 @@ pub mod serve;
 pub mod setup;
 pub mod sync;
 pub mod update_lints;
-pub mod utils;
+
+mod utils;
+pub use utils::{ClippyInfo, UpdateMode};
diff --git a/src/tools/clippy/clippy_dev/src/lint.rs b/src/tools/clippy/clippy_dev/src/lint.rs
index 0d66f167a38..2d9f563cdae 100644
--- a/src/tools/clippy/clippy_dev/src/lint.rs
+++ b/src/tools/clippy/clippy_dev/src/lint.rs
@@ -1,19 +1,18 @@
-use crate::utils::{cargo_clippy_path, exit_if_err};
-use std::process::{self, Command};
+use crate::utils::{ErrAction, cargo_cmd, expect_action, run_exit_on_err};
+use std::process::Command;
 use std::{env, fs};
 
-pub fn run<'a>(path: &str, edition: &str, args: impl Iterator<Item = &'a String>) {
-    let is_file = match fs::metadata(path) {
-        Ok(metadata) => metadata.is_file(),
-        Err(e) => {
-            eprintln!("Failed to read {path}: {e:?}");
-            process::exit(1);
-        },
-    };
+#[cfg(not(windows))]
+static CARGO_CLIPPY_EXE: &str = "cargo-clippy";
+#[cfg(windows)]
+static CARGO_CLIPPY_EXE: &str = "cargo-clippy.exe";
 
+pub fn run<'a>(path: &str, edition: &str, args: impl Iterator<Item = &'a String>) {
+    let is_file = expect_action(fs::metadata(path), ErrAction::Read, path).is_file();
     if is_file {
-        exit_if_err(
-            Command::new(env::var("CARGO").unwrap_or_else(|_| "cargo".into()))
+        run_exit_on_err(
+            "cargo run",
+            cargo_cmd()
                 .args(["run", "--bin", "clippy-driver", "--"])
                 .args(["-L", "./target/debug"])
                 .args(["-Z", "no-codegen"])
@@ -21,24 +20,25 @@ pub fn run<'a>(path: &str, edition: &str, args: impl Iterator<Item = &'a String>
                 .arg(path)
                 .args(args)
                 // Prevent rustc from creating `rustc-ice-*` files the console output is enough.
-                .env("RUSTC_ICE", "0")
-                .status(),
+                .env("RUSTC_ICE", "0"),
         );
     } else {
-        exit_if_err(
-            Command::new(env::var("CARGO").unwrap_or_else(|_| "cargo".into()))
-                .arg("build")
-                .status(),
-        );
-
-        let status = Command::new(cargo_clippy_path())
-            .arg("clippy")
-            .args(args)
-            // Prevent rustc from creating `rustc-ice-*` files the console output is enough.
-            .env("RUSTC_ICE", "0")
-            .current_dir(path)
-            .status();
+        // Ideally this would just be `cargo run`, but the working directory needs to be
+        // set to clippy's directory when building, and the target project's directory
+        // when running clippy. `cargo` can only set a single working directory for both
+        // when using `run`.
+        run_exit_on_err("cargo build", cargo_cmd().arg("build"));
 
-        exit_if_err(status);
+        let mut exe = env::current_exe().expect("failed to get current executable name");
+        exe.set_file_name(CARGO_CLIPPY_EXE);
+        run_exit_on_err(
+            "cargo clippy",
+            Command::new(exe)
+                .arg("clippy")
+                .args(args)
+                // Prevent rustc from creating `rustc-ice-*` files the console output is enough.
+                .env("RUSTC_ICE", "0")
+                .current_dir(path),
+        );
     }
 }
diff --git a/src/tools/clippy/clippy_dev/src/main.rs b/src/tools/clippy/clippy_dev/src/main.rs
index 26aa269fb63..5fef231f6ca 100644
--- a/src/tools/clippy/clippy_dev/src/main.rs
+++ b/src/tools/clippy/clippy_dev/src/main.rs
@@ -4,14 +4,15 @@
 
 use clap::{Args, Parser, Subcommand};
 use clippy_dev::{
-    deprecate_lint, dogfood, fmt, lint, new_lint, release, rename_lint, serve, setup, sync, update_lints, utils,
+    ClippyInfo, UpdateMode, deprecate_lint, dogfood, fmt, lint, new_lint, release, rename_lint, serve, setup, sync,
+    update_lints,
 };
 use std::convert::Infallible;
 use std::env;
 
 fn main() {
     let dev = Dev::parse();
-    let clippy = utils::ClippyInfo::search_for_manifest();
+    let clippy = ClippyInfo::search_for_manifest();
     if let Err(e) = env::set_current_dir(&clippy.path) {
         panic!("error setting current directory to `{}`: {e}", clippy.path.display());
     }
@@ -26,8 +27,8 @@ fn main() {
             allow_staged,
             allow_no_vcs,
         } => dogfood::dogfood(fix, allow_dirty, allow_staged, allow_no_vcs),
-        DevCommand::Fmt { check } => fmt::run(utils::UpdateMode::from_check(check)),
-        DevCommand::UpdateLints { check } => update_lints::update(utils::UpdateMode::from_check(check)),
+        DevCommand::Fmt { check } => fmt::run(UpdateMode::from_check(check)),
+        DevCommand::UpdateLints { check } => update_lints::update(UpdateMode::from_check(check)),
         DevCommand::NewLint {
             pass,
             name,
@@ -35,7 +36,7 @@ fn main() {
             r#type,
             msrv,
         } => match new_lint::create(clippy.version, pass, &name, &category, r#type.as_deref(), msrv) {
-            Ok(()) => update_lints::update(utils::UpdateMode::Change),
+            Ok(()) => update_lints::update(UpdateMode::Change),
             Err(e) => eprintln!("Unable to create lint: {e}"),
         },
         DevCommand::Setup(SetupCommand { subcommand }) => match subcommand {
diff --git a/src/tools/clippy/clippy_dev/src/serve.rs b/src/tools/clippy/clippy_dev/src/serve.rs
index 498ffeba9d6..d9e01813381 100644
--- a/src/tools/clippy/clippy_dev/src/serve.rs
+++ b/src/tools/clippy/clippy_dev/src/serve.rs
@@ -1,7 +1,11 @@
+use crate::utils::{ErrAction, cargo_cmd, expect_action};
+use core::fmt::Display;
+use core::mem;
 use std::path::Path;
 use std::process::Command;
 use std::time::{Duration, SystemTime};
-use std::{env, thread};
+use std::{fs, thread};
+use walkdir::WalkDir;
 
 #[cfg(windows)]
 const PYTHON: &str = "python";
@@ -18,56 +22,83 @@ pub fn run(port: u16, lint: Option<String>) -> ! {
         Some(lint) => format!("http://localhost:{port}/#{lint}"),
     });
 
+    let mut last_update = mtime("util/gh-pages/index.html");
     loop {
-        let index_time = mtime("util/gh-pages/index.html");
-        let times = [
-            "clippy_lints/src",
-            "util/gh-pages/index_template.html",
-            "tests/compile-test.rs",
-        ]
-        .map(mtime);
-
-        if times.iter().any(|&time| index_time < time) {
-            Command::new(env::var("CARGO").unwrap_or_else(|_| "cargo".into()))
-                .arg("collect-metadata")
-                .spawn()
-                .unwrap()
-                .wait()
-                .unwrap();
+        if is_metadata_outdated(mem::replace(&mut last_update, SystemTime::now())) {
+            // Ignore the command result; we'll fall back to displaying the old metadata.
+            let _ = expect_action(
+                cargo_cmd().arg("collect-metadata").status(),
+                ErrAction::Run,
+                "cargo collect-metadata",
+            );
+            last_update = SystemTime::now();
         }
+
+        // Only start the web server the first time around.
         if let Some(url) = url.take() {
             thread::spawn(move || {
-                let mut child = Command::new(PYTHON)
-                    .arg("-m")
-                    .arg("http.server")
-                    .arg(port.to_string())
-                    .current_dir("util/gh-pages")
-                    .spawn()
-                    .unwrap();
+                let mut child = expect_action(
+                    Command::new(PYTHON)
+                        .args(["-m", "http.server", port.to_string().as_str()])
+                        .current_dir("util/gh-pages")
+                        .spawn(),
+                    ErrAction::Run,
+                    "python -m http.server",
+                );
                 // Give some time for python to start
                 thread::sleep(Duration::from_millis(500));
                 // Launch browser after first export.py has completed and http.server is up
                 let _result = opener::open(url);
-                child.wait().unwrap();
+                expect_action(child.wait(), ErrAction::Run, "python -m http.server");
             });
         }
+
+        // Delay to avoid updating the metadata too aggressively.
         thread::sleep(Duration::from_millis(1000));
     }
 }
 
-fn mtime(path: impl AsRef<Path>) -> SystemTime {
-    let path = path.as_ref();
-    if path.is_dir() {
-        path.read_dir()
-            .into_iter()
-            .flatten()
-            .flatten()
-            .map(|entry| mtime(entry.path()))
-            .max()
-            .unwrap_or(SystemTime::UNIX_EPOCH)
-    } else {
-        path.metadata()
-            .and_then(|metadata| metadata.modified())
-            .unwrap_or(SystemTime::UNIX_EPOCH)
+fn log_err_and_continue<T>(res: Result<T, impl Display>, path: &Path) -> Option<T> {
+    match res {
+        Ok(x) => Some(x),
+        Err(ref e) => {
+            eprintln!("error reading `{}`: {e}", path.display());
+            None
+        },
     }
 }
+
+fn mtime(path: &str) -> SystemTime {
+    log_err_and_continue(fs::metadata(path), path.as_ref())
+        .and_then(|metadata| log_err_and_continue(metadata.modified(), path.as_ref()))
+        .unwrap_or(SystemTime::UNIX_EPOCH)
+}
+
+fn is_metadata_outdated(time: SystemTime) -> bool {
+    // Ignore all IO errors here. We don't want to stop them from hosting the server.
+    if time < mtime("util/gh-pages/index_template.html") || time < mtime("tests/compile-test.rs") {
+        return true;
+    }
+    let Some(dir) = log_err_and_continue(fs::read_dir("."), ".".as_ref()) else {
+        return false;
+    };
+    dir.map_while(|e| log_err_and_continue(e, ".".as_ref())).any(|e| {
+        let name = e.file_name();
+        let name_bytes = name.as_encoded_bytes();
+        if (name_bytes.starts_with(b"clippy_lints") && name_bytes != b"clippy_lints_internal")
+            || name_bytes == b"clippy_config"
+        {
+            WalkDir::new(&name)
+                .into_iter()
+                .map_while(|e| log_err_and_continue(e, name.as_ref()))
+                .filter(|e| e.file_type().is_file())
+                .filter_map(|e| {
+                    log_err_and_continue(e.metadata(), e.path())
+                        .and_then(|m| log_err_and_continue(m.modified(), e.path()))
+                })
+                .any(|ftime| time < ftime)
+        } else {
+            false
+        }
+    })
+}
diff --git a/src/tools/clippy/clippy_dev/src/setup/git_hook.rs b/src/tools/clippy/clippy_dev/src/setup/git_hook.rs
index c7c53bc69d0..c5a1e8264c7 100644
--- a/src/tools/clippy/clippy_dev/src/setup/git_hook.rs
+++ b/src/tools/clippy/clippy_dev/src/setup/git_hook.rs
@@ -1,8 +1,6 @@
 use std::fs;
 use std::path::Path;
 
-use super::verify_inside_clippy_dir;
-
 /// Rusts setup uses `git rev-parse --git-common-dir` to get the root directory of the repo.
 /// I've decided against this for the sake of simplicity and to make sure that it doesn't install
 /// the hook if `clippy_dev` would be used in the rust tree. The hook also references this tool
@@ -35,10 +33,6 @@ pub fn install_hook(force_override: bool) {
 }
 
 fn check_precondition(force_override: bool) -> bool {
-    if !verify_inside_clippy_dir() {
-        return false;
-    }
-
     // Make sure that we can find the git repository
     let git_path = Path::new(REPO_GIT_DIR);
     if !git_path.exists() || !git_path.is_dir() {
diff --git a/src/tools/clippy/clippy_dev/src/setup/mod.rs b/src/tools/clippy/clippy_dev/src/setup/mod.rs
index b0d31814639..5e938fff126 100644
--- a/src/tools/clippy/clippy_dev/src/setup/mod.rs
+++ b/src/tools/clippy/clippy_dev/src/setup/mod.rs
@@ -2,23 +2,3 @@ pub mod git_hook;
 pub mod intellij;
 pub mod toolchain;
 pub mod vscode;
-
-use std::path::Path;
-
-const CLIPPY_DEV_DIR: &str = "clippy_dev";
-
-/// This function verifies that the tool is being executed in the clippy directory.
-/// This is useful to ensure that setups only modify Clippy's resources. The verification
-/// is done by checking that `clippy_dev` is a sub directory of the current directory.
-///
-/// It will print an error message and return `false` if the directory could not be
-/// verified.
-fn verify_inside_clippy_dir() -> bool {
-    let path = Path::new(CLIPPY_DEV_DIR);
-    if path.exists() && path.is_dir() {
-        true
-    } else {
-        eprintln!("error: unable to verify that the working directory is clippy's directory");
-        false
-    }
-}
diff --git a/src/tools/clippy/clippy_dev/src/setup/toolchain.rs b/src/tools/clippy/clippy_dev/src/setup/toolchain.rs
index ecd80215f7e..c64ae4ef3c3 100644
--- a/src/tools/clippy/clippy_dev/src/setup/toolchain.rs
+++ b/src/tools/clippy/clippy_dev/src/setup/toolchain.rs
@@ -1,20 +1,12 @@
+use crate::utils::{cargo_cmd, run_exit_on_err};
 use std::env::consts::EXE_SUFFIX;
 use std::env::current_dir;
 use std::ffi::OsStr;
 use std::fs;
 use std::path::{Path, PathBuf};
-use std::process::Command;
 use walkdir::WalkDir;
 
-use crate::utils::exit_if_err;
-
-use super::verify_inside_clippy_dir;
-
 pub fn create(standalone: bool, force: bool, release: bool, name: &str) {
-    if !verify_inside_clippy_dir() {
-        return;
-    }
-
     let rustup_home = std::env::var("RUSTUP_HOME").unwrap();
     let toolchain = std::env::var("RUSTUP_TOOLCHAIN").unwrap();
 
@@ -51,11 +43,10 @@ pub fn create(standalone: bool, force: bool, release: bool, name: &str) {
         }
     }
 
-    let status = Command::new("cargo")
-        .arg("build")
-        .args(release.then_some("--release"))
-        .status();
-    exit_if_err(status);
+    run_exit_on_err(
+        "cargo build",
+        cargo_cmd().arg("build").args(release.then_some("--release")),
+    );
 
     install_bin("cargo-clippy", &dest, standalone, release);
     install_bin("clippy-driver", &dest, standalone, release);
diff --git a/src/tools/clippy/clippy_dev/src/setup/vscode.rs b/src/tools/clippy/clippy_dev/src/setup/vscode.rs
index a37c873eed4..a24aef65991 100644
--- a/src/tools/clippy/clippy_dev/src/setup/vscode.rs
+++ b/src/tools/clippy/clippy_dev/src/setup/vscode.rs
@@ -1,8 +1,6 @@
 use std::fs;
 use std::path::Path;
 
-use super::verify_inside_clippy_dir;
-
 const VSCODE_DIR: &str = ".vscode";
 const TASK_SOURCE_FILE: &str = "util/etc/vscode-tasks.json";
 const TASK_TARGET_FILE: &str = ".vscode/tasks.json";
@@ -22,10 +20,6 @@ pub fn install_tasks(force_override: bool) {
 }
 
 fn check_install_precondition(force_override: bool) -> bool {
-    if !verify_inside_clippy_dir() {
-        return false;
-    }
-
     let vs_dir_path = Path::new(VSCODE_DIR);
     if vs_dir_path.exists() {
         // verify the target will be valid
diff --git a/src/tools/clippy/clippy_dev/src/utils.rs b/src/tools/clippy/clippy_dev/src/utils.rs
index 89962a11034..057951d0e33 100644
--- a/src/tools/clippy/clippy_dev/src/utils.rs
+++ b/src/tools/clippy/clippy_dev/src/utils.rs
@@ -8,15 +8,10 @@ use std::ffi::OsStr;
 use std::fs::{self, OpenOptions};
 use std::io::{self, Read as _, Seek as _, SeekFrom, Write};
 use std::path::{Path, PathBuf};
-use std::process::{self, Command, ExitStatus, Stdio};
+use std::process::{self, Command, Stdio};
 use std::{env, thread};
 use walkdir::WalkDir;
 
-#[cfg(not(windows))]
-static CARGO_CLIPPY_EXE: &str = "cargo-clippy";
-#[cfg(windows)]
-static CARGO_CLIPPY_EXE: &str = "cargo-clippy.exe";
-
 #[derive(Clone, Copy)]
 pub enum ErrAction {
     Open,
@@ -118,16 +113,14 @@ impl<'a> File<'a> {
     }
 }
 
-/// Returns the path to the `cargo-clippy` binary
-///
-/// # Panics
-///
-/// Panics if the path of current executable could not be retrieved.
+/// Creates a `Command` for running cargo.
 #[must_use]
-pub fn cargo_clippy_path() -> PathBuf {
-    let mut path = env::current_exe().expect("failed to get current executable name");
-    path.set_file_name(CARGO_CLIPPY_EXE);
-    path
+pub fn cargo_cmd() -> Command {
+    if let Some(path) = env::var_os("CARGO") {
+        Command::new(path)
+    } else {
+        Command::new("cargo")
+    }
 }
 
 #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
@@ -288,19 +281,6 @@ impl ClippyInfo {
     }
 }
 
-/// # Panics
-/// Panics if given command result was failed.
-pub fn exit_if_err(status: io::Result<ExitStatus>) {
-    match status.expect("failed to run command").code() {
-        Some(0) => {},
-        Some(n) => process::exit(n),
-        None => {
-            eprintln!("Killed by signal");
-            process::exit(1);
-        },
-    }
-}
-
 #[derive(Clone, Copy)]
 pub enum UpdateStatus {
     Unchanged,
@@ -341,6 +321,7 @@ pub struct FileUpdater {
     dst_buf: String,
 }
 impl FileUpdater {
+    #[track_caller]
     fn update_file_checked_inner(
         &mut self,
         tool: &str,
@@ -364,6 +345,7 @@ impl FileUpdater {
         }
     }
 
+    #[track_caller]
     fn update_file_inner(&mut self, path: &Path, update: &mut dyn FnMut(&Path, &str, &mut String) -> UpdateStatus) {
         let mut file = File::open(path, OpenOptions::new().read(true).write(true));
         file.read_to_cleared_string(&mut self.src_buf);
@@ -373,6 +355,7 @@ impl FileUpdater {
         }
     }
 
+    #[track_caller]
     pub fn update_file_checked(
         &mut self,
         tool: &str,
@@ -383,6 +366,7 @@ impl FileUpdater {
         self.update_file_checked_inner(tool, mode, path.as_ref(), update);
     }
 
+    #[track_caller]
     pub fn update_file(
         &mut self,
         path: impl AsRef<Path>,
@@ -450,7 +434,6 @@ pub enum Token<'a> {
     OpenParen,
     Pound,
     Semi,
-    Slash,
 }
 
 pub struct RustSearcher<'txt> {
@@ -528,7 +511,6 @@ impl<'txt> RustSearcher<'txt> {
                 | (Token::OpenParen, lexer::TokenKind::OpenParen)
                 | (Token::Pound, lexer::TokenKind::Pound)
                 | (Token::Semi, lexer::TokenKind::Semi)
-                | (Token::Slash, lexer::TokenKind::Slash)
                 | (
                     Token::LitStr,
                     lexer::TokenKind::Literal {
@@ -601,7 +583,7 @@ impl<'txt> RustSearcher<'txt> {
     }
 }
 
-#[expect(clippy::must_use_candidate)]
+#[track_caller]
 pub fn try_rename_file(old_name: &Path, new_name: &Path) -> bool {
     match OpenOptions::new().create_new(true).write(true).open(new_name) {
         Ok(file) => drop(file),
@@ -623,7 +605,7 @@ pub fn try_rename_file(old_name: &Path, new_name: &Path) -> bool {
     }
 }
 
-#[expect(clippy::must_use_candidate)]
+#[track_caller]
 pub fn try_rename_dir(old_name: &Path, new_name: &Path) -> bool {
     match fs::create_dir(new_name) {
         Ok(()) => {},
@@ -649,10 +631,19 @@ pub fn try_rename_dir(old_name: &Path, new_name: &Path) -> bool {
     }
 }
 
-pub fn write_file(path: &Path, contents: &str) {
-    expect_action(fs::write(path, contents), ErrAction::Write, path);
+#[track_caller]
+pub fn run_exit_on_err(path: &(impl AsRef<Path> + ?Sized), cmd: &mut Command) {
+    match expect_action(cmd.status(), ErrAction::Run, path.as_ref()).code() {
+        Some(0) => {},
+        Some(n) => process::exit(n),
+        None => {
+            eprintln!("{} killed by signal", path.as_ref().display());
+            process::exit(1);
+        },
+    }
 }
 
+#[track_caller]
 #[must_use]
 pub fn run_with_output(path: &(impl AsRef<Path> + ?Sized), cmd: &mut Command) -> Vec<u8> {
     fn f(path: &Path, cmd: &mut Command) -> Vec<u8> {
@@ -738,7 +729,7 @@ pub fn split_args_for_threads(
     }
 }
 
-#[expect(clippy::must_use_candidate)]
+#[track_caller]
 pub fn delete_file_if_exists(path: &Path) -> bool {
     match fs::remove_file(path) {
         Ok(()) => true,
@@ -747,6 +738,7 @@ pub fn delete_file_if_exists(path: &Path) -> bool {
     }
 }
 
+#[track_caller]
 pub fn delete_dir_if_exists(path: &Path) {
     match fs::remove_dir_all(path) {
         Ok(()) => {},
diff --git a/src/tools/clippy/clippy_lints/src/casts/borrow_as_ptr.rs b/src/tools/clippy/clippy_lints/src/casts/borrow_as_ptr.rs
index e3b125a8d5b..eb75d5576f5 100644
--- a/src/tools/clippy/clippy_lints/src/casts/borrow_as_ptr.rs
+++ b/src/tools/clippy/clippy_lints/src/casts/borrow_as_ptr.rs
@@ -2,7 +2,7 @@ use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_and_then};
 use clippy_utils::msrvs::Msrv;
 use clippy_utils::source::{snippet_with_applicability, snippet_with_context};
 use clippy_utils::sugg::has_enclosing_paren;
-use clippy_utils::{get_parent_expr, is_expr_temporary_value, is_lint_allowed, msrvs, std_or_core};
+use clippy_utils::{get_parent_expr, is_expr_temporary_value, is_from_proc_macro, is_lint_allowed, msrvs, std_or_core};
 use rustc_errors::Applicability;
 use rustc_hir::{BorrowKind, Expr, ExprKind, Mutability, Ty, TyKind};
 use rustc_lint::LateContext;
@@ -22,13 +22,12 @@ pub(super) fn check<'tcx>(
         && !matches!(target.ty.kind, TyKind::TraitObject(..))
         && let ExprKind::AddrOf(BorrowKind::Ref, mutability, e) = cast_expr.kind
         && !is_lint_allowed(cx, BORROW_AS_PTR, expr.hir_id)
+        // Fix #9884
+        && !is_expr_temporary_value(cx, e)
+        && !is_from_proc_macro(cx, expr)
     {
         let mut app = Applicability::MachineApplicable;
         let snip = snippet_with_context(cx, e.span, cast_expr.span.ctxt(), "..", &mut app).0;
-        // Fix #9884
-        if is_expr_temporary_value(cx, e) {
-            return false;
-        }
 
         let (suggestion, span) = if msrv.meets(cx, msrvs::RAW_REF_OP) {
             // Make sure that the span to be replaced doesn't include parentheses, that could break the
diff --git a/src/tools/clippy/clippy_lints/src/casts/char_lit_as_u8.rs b/src/tools/clippy/clippy_lints/src/casts/char_lit_as_u8.rs
index a7d3868f76c..964eaf2a0a2 100644
--- a/src/tools/clippy/clippy_lints/src/casts/char_lit_as_u8.rs
+++ b/src/tools/clippy/clippy_lints/src/casts/char_lit_as_u8.rs
@@ -4,18 +4,17 @@ use rustc_ast::LitKind;
 use rustc_errors::Applicability;
 use rustc_hir::{Expr, ExprKind};
 use rustc_lint::LateContext;
-use rustc_middle::ty::{self, UintTy};
+use rustc_middle::ty::{self, Ty, UintTy};
 
 use super::CHAR_LIT_AS_U8;
 
-pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>) {
-    if let ExprKind::Cast(e, _) = &expr.kind
-        && let ExprKind::Lit(l) = &e.kind
+pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, cast_from_expr: &Expr<'_>, cast_to: Ty<'_>) {
+    if let ExprKind::Lit(l) = &cast_from_expr.kind
         && let LitKind::Char(c) = l.node
-        && ty::Uint(UintTy::U8) == *cx.typeck_results().expr_ty(expr).kind()
+        && ty::Uint(UintTy::U8) == *cast_to.kind()
     {
         let mut applicability = Applicability::MachineApplicable;
-        let snippet = snippet_with_applicability(cx, e.span, "'x'", &mut applicability);
+        let snippet = snippet_with_applicability(cx, cast_from_expr.span, "'x'", &mut applicability);
 
         span_lint_and_then(
             cx,
diff --git a/src/tools/clippy/clippy_lints/src/casts/mod.rs b/src/tools/clippy/clippy_lints/src/casts/mod.rs
index dcc439a272c..e25df9dd249 100644
--- a/src/tools/clippy/clippy_lints/src/casts/mod.rs
+++ b/src/tools/clippy/clippy_lints/src/casts/mod.rs
@@ -871,6 +871,7 @@ impl<'tcx> LateLintPass<'tcx> for Casts {
             if !expr.span.from_expansion() && unnecessary_cast::check(cx, expr, cast_from_expr, cast_from, cast_to) {
                 return;
             }
+            char_lit_as_u8::check(cx, expr, cast_from_expr, cast_to);
             cast_slice_from_raw_parts::check(cx, expr, cast_from_expr, cast_to, self.msrv);
             ptr_cast_constness::check(cx, expr, cast_from_expr, cast_from, cast_to, self.msrv);
             as_ptr_cast_mut::check(cx, expr, cast_from_expr, cast_to);
@@ -911,7 +912,6 @@ impl<'tcx> LateLintPass<'tcx> for Casts {
             borrow_as_ptr::check_implicit_cast(cx, expr);
         }
         cast_ptr_alignment::check(cx, expr);
-        char_lit_as_u8::check(cx, expr);
         ptr_as_ptr::check(cx, expr, self.msrv);
         cast_slice_different_sizes::check(cx, expr, self.msrv);
         ptr_cast_constness::check_null_ptr_cast_method(cx, expr);
diff --git a/src/tools/clippy/clippy_lints/src/casts/ptr_as_ptr.rs b/src/tools/clippy/clippy_lints/src/casts/ptr_as_ptr.rs
index ee0f3fa81c6..89075409098 100644
--- a/src/tools/clippy/clippy_lints/src/casts/ptr_as_ptr.rs
+++ b/src/tools/clippy/clippy_lints/src/casts/ptr_as_ptr.rs
@@ -1,4 +1,5 @@
 use clippy_utils::diagnostics::span_lint_and_sugg;
+use clippy_utils::is_from_proc_macro;
 use clippy_utils::msrvs::{self, Msrv};
 use clippy_utils::source::snippet_with_applicability;
 use clippy_utils::sugg::Sugg;
@@ -25,7 +26,7 @@ impl OmitFollowedCastReason<'_> {
     }
 }
 
-pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, msrv: Msrv) {
+pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'tcx>, msrv: Msrv) {
     if let ExprKind::Cast(cast_expr, cast_to_hir_ty) = expr.kind
         && let (cast_from, cast_to) = (cx.typeck_results().expr_ty(cast_expr), cx.typeck_results().expr_ty(expr))
         && let ty::RawPtr(_, from_mutbl) = cast_from.kind()
@@ -36,6 +37,7 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, msrv: Msrv) {
         // as explained here: https://github.com/rust-lang/rust/issues/60602.
         && to_pointee_ty.is_sized(cx.tcx, cx.typing_env())
         && msrv.meets(cx, msrvs::POINTER_CAST)
+        && !is_from_proc_macro(cx, expr)
     {
         let mut app = Applicability::MachineApplicable;
         let turbofish = match &cast_to_hir_ty.kind {
diff --git a/src/tools/clippy/clippy_lints/src/cognitive_complexity.rs b/src/tools/clippy/clippy_lints/src/cognitive_complexity.rs
index 8f1c0296524..8f95c63a854 100644
--- a/src/tools/clippy/clippy_lints/src/cognitive_complexity.rs
+++ b/src/tools/clippy/clippy_lints/src/cognitive_complexity.rs
@@ -56,7 +56,7 @@ impl_lint_pass!(CognitiveComplexity => [COGNITIVE_COMPLEXITY]);
 
 impl CognitiveComplexity {
     fn check<'tcx>(
-        &mut self,
+        &self,
         cx: &LateContext<'tcx>,
         kind: FnKind<'tcx>,
         decl: &'tcx FnDecl<'_>,
diff --git a/src/tools/clippy/clippy_lints/src/collapsible_if.rs b/src/tools/clippy/clippy_lints/src/collapsible_if.rs
index e3103e2d301..ad610fbd8d2 100644
--- a/src/tools/clippy/clippy_lints/src/collapsible_if.rs
+++ b/src/tools/clippy/clippy_lints/src/collapsible_if.rs
@@ -5,7 +5,7 @@ use clippy_utils::source::{IntoSpan as _, SpanRangeExt, snippet, snippet_block_w
 use clippy_utils::{span_contains_non_whitespace, tokenize_with_text};
 use rustc_ast::BinOpKind;
 use rustc_errors::Applicability;
-use rustc_hir::{Block, Expr, ExprKind, Stmt, StmtKind};
+use rustc_hir::{Block, Expr, ExprKind, StmtKind};
 use rustc_lexer::TokenKind;
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_session::impl_lint_pass;
@@ -141,11 +141,7 @@ impl CollapsibleIf {
 
                     // Prevent "elseif"
                     // Check that the "else" is followed by whitespace
-                    let requires_space = if let Some(c) = snippet(cx, up_to_else, "..").chars().last() {
-                        !c.is_whitespace()
-                    } else {
-                        false
-                    };
+                    let requires_space = snippet(cx, up_to_else, "..").ends_with(|c: char| !c.is_whitespace());
                     let mut applicability = Applicability::MachineApplicable;
                     diag.span_suggestion(
                         else_block.span,
@@ -173,8 +169,7 @@ impl CollapsibleIf {
             && cx.tcx.hir_attrs(inner.hir_id).is_empty()
             && let ExprKind::If(check_inner, _, None) = &inner.kind
             && self.eligible_condition(cx, check_inner)
-            && let ctxt = expr.span.ctxt()
-            && inner.span.ctxt() == ctxt
+            && expr.span.eq_ctxt(inner.span)
             && !block_starts_with_significant_tokens(cx, then, inner, self.lint_commented_code)
         {
             span_lint_and_then(
@@ -262,14 +257,9 @@ fn block_starts_with_significant_tokens(
 /// If `block` is a block with either one expression or a statement containing an expression,
 /// return the expression. We don't peel blocks recursively, as extra blocks might be intentional.
 fn expr_block<'tcx>(block: &Block<'tcx>) -> Option<&'tcx Expr<'tcx>> {
-    match block.stmts {
-        [] => block.expr,
-        [
-            Stmt {
-                kind: StmtKind::Semi(expr),
-                ..
-            },
-        ] if block.expr.is_none() => Some(expr),
+    match (block.stmts, block.expr) {
+        ([], expr) => expr,
+        ([stmt], None) if let StmtKind::Semi(expr) = stmt.kind => Some(expr),
         _ => None,
     }
 }
diff --git a/src/tools/clippy/clippy_lints/src/declared_lints.rs b/src/tools/clippy/clippy_lints/src/declared_lints.rs
index e1cb08e361c..e67e8d9070f 100644
--- a/src/tools/clippy/clippy_lints/src/declared_lints.rs
+++ b/src/tools/clippy/clippy_lints/src/declared_lints.rs
@@ -187,6 +187,7 @@ pub static LINTS: &[&::declare_clippy_lint::LintInfo] = &[
     crate::from_raw_with_void_ptr::FROM_RAW_WITH_VOID_PTR_INFO,
     crate::from_str_radix_10::FROM_STR_RADIX_10_INFO,
     crate::functions::DOUBLE_MUST_USE_INFO,
+    crate::functions::DUPLICATE_UNDERSCORE_ARGUMENT_INFO,
     crate::functions::IMPL_TRAIT_IN_PARAMS_INFO,
     crate::functions::MISNAMED_GETTERS_INFO,
     crate::functions::MUST_USE_CANDIDATE_INFO,
@@ -505,7 +506,6 @@ pub static LINTS: &[&::declare_clippy_lint::LintInfo] = &[
     crate::misc::USED_UNDERSCORE_BINDING_INFO,
     crate::misc::USED_UNDERSCORE_ITEMS_INFO,
     crate::misc_early::BUILTIN_TYPE_SHADOW_INFO,
-    crate::misc_early::DUPLICATE_UNDERSCORE_ARGUMENT_INFO,
     crate::misc_early::MIXED_CASE_HEX_LITERALS_INFO,
     crate::misc_early::REDUNDANT_AT_REST_PATTERN_INFO,
     crate::misc_early::REDUNDANT_PATTERN_INFO,
diff --git a/src/tools/clippy/clippy_lints/src/dereference.rs b/src/tools/clippy/clippy_lints/src/dereference.rs
index 995a1209595..9aa2f3cf0a5 100644
--- a/src/tools/clippy/clippy_lints/src/dereference.rs
+++ b/src/tools/clippy/clippy_lints/src/dereference.rs
@@ -1,12 +1,11 @@
 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::{implements_trait, is_manually_drop};
+use clippy_utils::ty::{adjust_derefs_manually_drop, implements_trait, is_manually_drop};
 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 core::mem;
 use rustc_ast::util::parser::ExprPrecedence;
 use rustc_data_structures::fx::FxIndexMap;
 use rustc_errors::Applicability;
@@ -707,14 +706,6 @@ fn try_parse_ref_op<'tcx>(
     ))
 }
 
-// Checks if the adjustments contains a deref of `ManuallyDrop<_>`
-fn adjust_derefs_manually_drop<'tcx>(adjustments: &'tcx [Adjustment<'tcx>], mut ty: Ty<'tcx>) -> bool {
-    adjustments.iter().any(|a| {
-        let ty = mem::replace(&mut ty, a.target);
-        matches!(a.kind, Adjust::Deref(Some(ref op)) if op.mutbl == Mutability::Mut) && is_manually_drop(ty)
-    })
-}
-
 // Checks whether the type for a deref call actually changed the type, not just the mutability of
 // the reference.
 fn deref_method_same_type<'tcx>(result_ty: Ty<'tcx>, arg_ty: Ty<'tcx>) -> bool {
diff --git a/src/tools/clippy/clippy_lints/src/doc/mod.rs b/src/tools/clippy/clippy_lints/src/doc/mod.rs
index d27d68d3866..eca3bc390d7 100644
--- a/src/tools/clippy/clippy_lints/src/doc/mod.rs
+++ b/src/tools/clippy/clippy_lints/src/doc/mod.rs
@@ -1139,12 +1139,12 @@ fn check_doc<'a, Events: Iterator<Item = (pulldown_cmark::Event<'a>, Range<usize
                         None,
                         "a backtick may be missing a pair",
                     );
+                    text_to_check.clear();
                 } else {
-                    for (text, range, assoc_code_level) in text_to_check {
+                    for (text, range, assoc_code_level) in text_to_check.drain(..) {
                         markdown::check(cx, valid_idents, &text, &fragments, range, assoc_code_level, blockquote_level);
                     }
                 }
-                text_to_check = Vec::new();
             },
             Start(FootnoteDefinition(..)) => in_footnote_definition = true,
             End(TagEnd::FootnoteDefinition) => in_footnote_definition = false,
diff --git a/src/tools/clippy/clippy_lints/src/eta_reduction.rs b/src/tools/clippy/clippy_lints/src/eta_reduction.rs
index e467246741c..0eefc2f6109 100644
--- a/src/tools/clippy/clippy_lints/src/eta_reduction.rs
+++ b/src/tools/clippy/clippy_lints/src/eta_reduction.rs
@@ -231,9 +231,13 @@ fn check_closure<'tcx>(cx: &LateContext<'tcx>, outer_receiver: Option<&Expr<'tcx
                                     _ => (),
                                 }
                             }
+                            let replace_with = match callee_ty_adjusted.kind() {
+                                ty::FnDef(def, _) => cx.tcx.def_descr(*def),
+                                _ => "function",
+                            };
                             diag.span_suggestion(
                                 expr.span,
-                                "replace the closure with the function itself",
+                                format!("replace the closure with the {replace_with} itself"),
                                 snippet,
                                 Applicability::MachineApplicable,
                             );
diff --git a/src/tools/clippy/clippy_lints/src/from_str_radix_10.rs b/src/tools/clippy/clippy_lints/src/from_str_radix_10.rs
index b816963cc82..d5873b3f85a 100644
--- a/src/tools/clippy/clippy_lints/src/from_str_radix_10.rs
+++ b/src/tools/clippy/clippy_lints/src/from_str_radix_10.rs
@@ -1,6 +1,6 @@
 use clippy_utils::diagnostics::span_lint_and_sugg;
 use clippy_utils::sugg::Sugg;
-use clippy_utils::ty::{is_type_diagnostic_item, is_type_lang_item};
+use clippy_utils::ty::is_type_lang_item;
 use clippy_utils::{is_in_const_context, is_integer_literal, sym};
 use rustc_errors::Applicability;
 use rustc_hir::{Expr, ExprKind, LangItem, PrimTy, QPath, TyKind, def};
@@ -89,5 +89,5 @@ impl<'tcx> LateLintPass<'tcx> for FromStrRadix10 {
 
 /// Checks if a Ty is `String` or `&str`
 fn is_ty_stringish(cx: &LateContext<'_>, ty: Ty<'_>) -> bool {
-    is_type_lang_item(cx, ty, LangItem::String) || is_type_diagnostic_item(cx, ty, sym::str)
+    is_type_lang_item(cx, ty, LangItem::String) || ty.peel_refs().is_str()
 }
diff --git a/src/tools/clippy/clippy_lints/src/functions/duplicate_underscore_argument.rs b/src/tools/clippy/clippy_lints/src/functions/duplicate_underscore_argument.rs
new file mode 100644
index 00000000000..b15d1b1bb79
--- /dev/null
+++ b/src/tools/clippy/clippy_lints/src/functions/duplicate_underscore_argument.rs
@@ -0,0 +1,34 @@
+use clippy_utils::diagnostics::span_lint;
+use rustc_ast::PatKind;
+use rustc_ast::visit::FnKind;
+use rustc_data_structures::fx::FxHashMap;
+use rustc_lint::EarlyContext;
+use rustc_span::Span;
+
+use super::DUPLICATE_UNDERSCORE_ARGUMENT;
+
+pub(super) fn check(cx: &EarlyContext<'_>, fn_kind: FnKind<'_>) {
+    let mut registered_names: FxHashMap<String, Span> = FxHashMap::default();
+
+    for arg in &fn_kind.decl().inputs {
+        if let PatKind::Ident(_, ident, None) = arg.pat.kind {
+            let arg_name = ident.to_string();
+
+            if let Some(arg_name) = arg_name.strip_prefix('_') {
+                if let Some(correspondence) = registered_names.get(arg_name) {
+                    span_lint(
+                        cx,
+                        DUPLICATE_UNDERSCORE_ARGUMENT,
+                        *correspondence,
+                        format!(
+                            "`{arg_name}` already exists, having another argument having almost the same \
+                                 name makes code comprehension and documentation more difficult"
+                        ),
+                    );
+                }
+            } else {
+                registered_names.insert(arg_name, arg.pat.span);
+            }
+        }
+    }
+}
diff --git a/src/tools/clippy/clippy_lints/src/functions/mod.rs b/src/tools/clippy/clippy_lints/src/functions/mod.rs
index 6051dc9479b..ca5ea901814 100644
--- a/src/tools/clippy/clippy_lints/src/functions/mod.rs
+++ b/src/tools/clippy/clippy_lints/src/functions/mod.rs
@@ -1,3 +1,4 @@
+mod duplicate_underscore_argument;
 mod impl_trait_in_params;
 mod misnamed_getters;
 mod must_use;
@@ -11,16 +12,40 @@ mod too_many_lines;
 use clippy_config::Conf;
 use clippy_utils::msrvs::Msrv;
 use clippy_utils::paths::{PathNS, lookup_path_str};
+use rustc_ast::{self as ast, visit};
 use rustc_hir as hir;
 use rustc_hir::intravisit;
-use rustc_lint::{LateContext, LateLintPass};
+use rustc_lint::{EarlyContext, EarlyLintPass, LateContext, LateLintPass};
 use rustc_middle::ty::TyCtxt;
-use rustc_session::impl_lint_pass;
+use rustc_session::{declare_lint_pass, impl_lint_pass};
 use rustc_span::Span;
 use rustc_span::def_id::{DefIdSet, LocalDefId};
 
 declare_clippy_lint! {
     /// ### What it does
+    /// Checks for function arguments having the similar names
+    /// differing by an underscore.
+    ///
+    /// ### Why is this bad?
+    /// It affects code readability.
+    ///
+    /// ### Example
+    /// ```no_run
+    /// fn foo(a: i32, _a: i32) {}
+    /// ```
+    ///
+    /// Use instead:
+    /// ```no_run
+    /// fn bar(a: i32, _b: i32) {}
+    /// ```
+    #[clippy::version = "pre 1.29.0"]
+    pub DUPLICATE_UNDERSCORE_ARGUMENT,
+    style,
+    "function arguments having names which only differ by an underscore"
+}
+
+declare_clippy_lint! {
+    /// ### What it does
     /// Checks for functions with too many parameters.
     ///
     /// ### Why is this bad?
@@ -448,6 +473,14 @@ declare_clippy_lint! {
     "function signature uses `&Option<T>` instead of `Option<&T>`"
 }
 
+declare_lint_pass!(EarlyFunctions => [DUPLICATE_UNDERSCORE_ARGUMENT]);
+
+impl EarlyLintPass for EarlyFunctions {
+    fn check_fn(&mut self, cx: &EarlyContext<'_>, fn_kind: visit::FnKind<'_>, _: Span, _: ast::NodeId) {
+        duplicate_underscore_argument::check(cx, fn_kind);
+    }
+}
+
 pub struct Functions {
     too_many_arguments_threshold: u64,
     too_many_lines_threshold: u64,
@@ -503,7 +536,7 @@ impl<'tcx> LateLintPass<'tcx> for Functions {
     ) {
         let hir_id = cx.tcx.local_def_id_to_hir_id(def_id);
         too_many_arguments::check_fn(cx, kind, decl, span, hir_id, self.too_many_arguments_threshold);
-        too_many_lines::check_fn(cx, kind, span, body, self.too_many_lines_threshold);
+        too_many_lines::check_fn(cx, kind, body, span, def_id, self.too_many_lines_threshold);
         not_unsafe_ptr_arg_deref::check_fn(cx, kind, decl, body, def_id);
         misnamed_getters::check_fn(cx, kind, decl, body, span);
         impl_trait_in_params::check_fn(cx, &kind, body, hir_id);
diff --git a/src/tools/clippy/clippy_lints/src/functions/renamed_function_params.rs b/src/tools/clippy/clippy_lints/src/functions/renamed_function_params.rs
index 0a7c6e9d5f8..f8e8f5544b9 100644
--- a/src/tools/clippy/clippy_lints/src/functions/renamed_function_params.rs
+++ b/src/tools/clippy/clippy_lints/src/functions/renamed_function_params.rs
@@ -6,6 +6,7 @@ use rustc_hir::{Impl, ImplItem, ImplItemKind, ItemKind, Node, TraitRef};
 use rustc_lint::LateContext;
 use rustc_span::Span;
 use rustc_span::symbol::{Ident, kw};
+use std::iter;
 
 use super::RENAMED_FUNCTION_PARAMS;
 
@@ -58,16 +59,11 @@ impl RenamedFnArgs {
         let mut renamed: Vec<(Span, String)> = vec![];
 
         debug_assert!(default_idents.size_hint() == current_idents.size_hint());
-        while let (Some(default_ident), Some(current_ident)) = (default_idents.next(), current_idents.next()) {
+        for (default_ident, current_ident) in iter::zip(default_idents, current_idents) {
             let has_name_to_check = |ident: Option<Ident>| {
-                if let Some(ident) = ident
-                    && ident.name != kw::Underscore
-                    && !ident.name.as_str().starts_with('_')
-                {
-                    Some(ident)
-                } else {
-                    None
-                }
+                ident
+                    .filter(|ident| ident.name != kw::Underscore)
+                    .filter(|ident| !ident.name.as_str().starts_with('_'))
             };
 
             if let Some(default_ident) = has_name_to_check(default_ident)
@@ -97,8 +93,7 @@ fn trait_item_def_id_of_impl(cx: &LateContext<'_>, target: OwnerId) -> Option<De
 }
 
 fn is_from_ignored_trait(of_trait: &TraitRef<'_>, ignored_traits: &DefIdSet) -> bool {
-    let Some(trait_did) = of_trait.trait_def_id() else {
-        return false;
-    };
-    ignored_traits.contains(&trait_did)
+    of_trait
+        .trait_def_id()
+        .is_some_and(|trait_did| ignored_traits.contains(&trait_did))
 }
diff --git a/src/tools/clippy/clippy_lints/src/functions/result.rs b/src/tools/clippy/clippy_lints/src/functions/result.rs
index bb98ae82611..1f2fce687ed 100644
--- a/src/tools/clippy/clippy_lints/src/functions/result.rs
+++ b/src/tools/clippy/clippy_lints/src/functions/result.rs
@@ -97,11 +97,7 @@ fn check_result_unit_err(cx: &LateContext<'_>, err_ty: Ty<'_>, fn_header_span: S
 
 fn check_result_large_err<'tcx>(cx: &LateContext<'tcx>, err_ty: Ty<'tcx>, hir_ty_span: Span, large_err_threshold: u64) {
     if let ty::Adt(adt, subst) = err_ty.kind()
-        && let Some(local_def_id) = err_ty
-            .ty_adt_def()
-            .expect("already checked this is adt")
-            .did()
-            .as_local()
+        && let Some(local_def_id) = adt.did().as_local()
         && let hir::Node::Item(item) = cx.tcx.hir_node_by_def_id(local_def_id)
         && let hir::ItemKind::Enum(_, _, ref def) = item.kind
     {
diff --git a/src/tools/clippy/clippy_lints/src/functions/too_many_lines.rs b/src/tools/clippy/clippy_lints/src/functions/too_many_lines.rs
index 4f90d9655b4..33eede8e65a 100644
--- a/src/tools/clippy/clippy_lints/src/functions/too_many_lines.rs
+++ b/src/tools/clippy/clippy_lints/src/functions/too_many_lines.rs
@@ -1,6 +1,7 @@
 use clippy_utils::diagnostics::span_lint;
 use clippy_utils::source::SpanRangeExt;
 use rustc_hir as hir;
+use rustc_hir::def_id::LocalDefId;
 use rustc_hir::intravisit::FnKind;
 use rustc_lint::{LateContext, LintContext};
 use rustc_span::Span;
@@ -10,8 +11,9 @@ use super::TOO_MANY_LINES;
 pub(super) fn check_fn(
     cx: &LateContext<'_>,
     kind: FnKind<'_>,
-    span: Span,
     body: &hir::Body<'_>,
+    span: Span,
+    def_id: LocalDefId,
     too_many_lines_threshold: u64,
 ) {
     // Closures must be contained in a parent body, which will be checked for `too_many_lines`.
@@ -74,7 +76,7 @@ pub(super) fn check_fn(
         span_lint(
             cx,
             TOO_MANY_LINES,
-            span,
+            cx.tcx.def_span(def_id),
             format!("this function has too many lines ({line_count}/{too_many_lines_threshold})"),
         );
     }
diff --git a/src/tools/clippy/clippy_lints/src/len_zero.rs b/src/tools/clippy/clippy_lints/src/len_zero.rs
index 6beddc1be14..57deb011f2b 100644
--- a/src/tools/clippy/clippy_lints/src/len_zero.rs
+++ b/src/tools/clippy/clippy_lints/src/len_zero.rs
@@ -176,12 +176,11 @@ impl<'tcx> LateLintPass<'tcx> for LenZero {
         if let ExprKind::Let(lt) = expr.kind
             && match lt.pat.kind {
                 PatKind::Slice([], None, []) => true,
-                PatKind::Expr(lit) => match lit.kind {
-                    PatExprKind::Lit { lit, .. } => match lit.node {
-                        LitKind::Str(lit, _) => lit.as_str().is_empty(),
-                        _ => false,
-                    },
-                    _ => false,
+                PatKind::Expr(lit)
+                    if let PatExprKind::Lit { lit, .. } = lit.kind
+                        && let LitKind::Str(lit, _) = lit.node =>
+                {
+                    lit.as_str().is_empty()
                 },
                 _ => false,
             }
@@ -336,33 +335,23 @@ fn extract_future_output<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> Option<&
 }
 
 fn is_first_generic_integral<'tcx>(segment: &'tcx PathSegment<'tcx>) -> bool {
-    if let Some(generic_args) = segment.args {
-        if generic_args.args.is_empty() {
-            return false;
-        }
-        let arg = &generic_args.args[0];
-        if let GenericArg::Type(rustc_hir::Ty {
-            kind: TyKind::Path(QPath::Resolved(_, path)),
-            ..
-        }) = arg
-        {
-            let segments = &path.segments;
-            let segment = &segments[0];
-            let res = &segment.res;
-            if matches!(res, Res::PrimTy(PrimTy::Uint(_))) || matches!(res, Res::PrimTy(PrimTy::Int(_))) {
-                return true;
-            }
-        }
+    if let Some(generic_args) = segment.args
+        && let [GenericArg::Type(ty), ..] = &generic_args.args
+        && let TyKind::Path(QPath::Resolved(_, path)) = ty.kind
+        && let [segment, ..] = &path.segments
+        && matches!(segment.res, Res::PrimTy(PrimTy::Uint(_) | PrimTy::Int(_)))
+    {
+        true
+    } else {
+        false
     }
-
-    false
 }
 
 fn parse_len_output<'tcx>(cx: &LateContext<'tcx>, sig: FnSig<'tcx>) -> Option<LenOutput> {
     if let Some(segment) = extract_future_output(cx, sig.output()) {
         let res = segment.res;
 
-        if matches!(res, Res::PrimTy(PrimTy::Uint(_))) || matches!(res, Res::PrimTy(PrimTy::Int(_))) {
+        if matches!(res, Res::PrimTy(PrimTy::Uint(_) | PrimTy::Int(_))) {
             return Some(LenOutput::Integral);
         }
 
diff --git a/src/tools/clippy/clippy_lints/src/lib.rs b/src/tools/clippy/clippy_lints/src/lib.rs
index 844bc1b0e39..d468993e744 100644
--- a/src/tools/clippy/clippy_lints/src/lib.rs
+++ b/src/tools/clippy/clippy_lints/src/lib.rs
@@ -556,6 +556,7 @@ pub fn register_lint_passes(store: &mut rustc_lint::LintStore, conf: &'static Co
     store.register_late_pass(|_| Box::new(panicking_overflow_checks::PanickingOverflowChecks));
     store.register_late_pass(|_| Box::<new_without_default::NewWithoutDefault>::default());
     store.register_late_pass(move |_| Box::new(disallowed_names::DisallowedNames::new(conf)));
+    store.register_early_pass(|| Box::new(functions::EarlyFunctions));
     store.register_late_pass(move |tcx| Box::new(functions::Functions::new(tcx, conf)));
     store.register_late_pass(move |_| Box::new(doc::Documentation::new(conf)));
     store.register_early_pass(move || Box::new(doc::Documentation::new(conf)));
@@ -600,7 +601,7 @@ pub fn register_lint_passes(store: &mut rustc_lint::LintStore, conf: &'static Co
     store.register_late_pass(move |_| Box::new(trait_bounds::TraitBounds::new(conf)));
     store.register_late_pass(|_| Box::new(comparison_chain::ComparisonChain));
     store.register_late_pass(move |tcx| Box::new(mut_key::MutableKeyType::new(tcx, conf)));
-    store.register_early_pass(|| Box::new(reference::DerefAddrOf));
+    store.register_late_pass(|_| Box::new(reference::DerefAddrOf));
     store.register_early_pass(|| Box::new(double_parens::DoubleParens));
     let format_args = format_args_storage.clone();
     store.register_late_pass(move |_| Box::new(format_impl::FormatImpl::new(format_args.clone())));
diff --git a/src/tools/clippy/clippy_lints/src/loops/infinite_loop.rs b/src/tools/clippy/clippy_lints/src/loops/infinite_loop.rs
index 797ff1f3986..a71e6963f8c 100644
--- a/src/tools/clippy/clippy_lints/src/loops/infinite_loop.rs
+++ b/src/tools/clippy/clippy_lints/src/loops/infinite_loop.rs
@@ -1,10 +1,11 @@
 use clippy_utils::diagnostics::span_lint_and_then;
 use clippy_utils::{fn_def_id, is_from_proc_macro, is_lint_allowed};
 use hir::intravisit::{Visitor, walk_expr};
-use hir::{Expr, ExprKind, FnRetTy, FnSig, Node, TyKind};
 use rustc_ast::Label;
 use rustc_errors::Applicability;
-use rustc_hir as hir;
+use rustc_hir::{
+    self as hir, Closure, ClosureKind, CoroutineDesugaring, CoroutineKind, Expr, ExprKind, FnRetTy, FnSig, Node, TyKind,
+};
 use rustc_lint::{LateContext, LintContext};
 use rustc_span::sym;
 
@@ -29,6 +30,10 @@ pub(super) fn check<'tcx>(
         return;
     }
 
+    if is_inside_unawaited_async_block(cx, expr) {
+        return;
+    }
+
     if expr.span.in_external_macro(cx.sess().source_map()) || is_from_proc_macro(cx, expr) {
         return;
     }
@@ -60,6 +65,39 @@ pub(super) fn check<'tcx>(
     }
 }
 
+/// Check if the given expression is inside an async block that is not being awaited.
+/// This helps avoid false positives when async blocks are spawned or assigned to variables.
+fn is_inside_unawaited_async_block(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
+    let current_hir_id = expr.hir_id;
+    for (_, parent_node) in cx.tcx.hir_parent_iter(current_hir_id) {
+        if let Node::Expr(Expr {
+            kind:
+                ExprKind::Closure(Closure {
+                    kind: ClosureKind::Coroutine(CoroutineKind::Desugared(CoroutineDesugaring::Async, _)),
+                    ..
+                }),
+            ..
+        }) = parent_node
+        {
+            return !is_async_block_awaited(cx, expr);
+        }
+    }
+    false
+}
+
+fn is_async_block_awaited(cx: &LateContext<'_>, async_expr: &Expr<'_>) -> bool {
+    for (_, parent_node) in cx.tcx.hir_parent_iter(async_expr.hir_id) {
+        if let Node::Expr(Expr {
+            kind: ExprKind::Match(_, _, hir::MatchSource::AwaitDesugar),
+            ..
+        }) = parent_node
+        {
+            return true;
+        }
+    }
+    false
+}
+
 fn get_parent_fn_ret_ty<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'_>) -> Option<FnRetTy<'tcx>> {
     for (_, parent_node) in cx.tcx.hir_parent_iter(expr.hir_id) {
         match parent_node {
@@ -67,8 +105,8 @@ fn get_parent_fn_ret_ty<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'_>) -> Option
             // This is because we still need to backtrack one parent node to get the `OpaqueDef` ty.
             Node::Expr(Expr {
                 kind:
-                    ExprKind::Closure(hir::Closure {
-                        kind: hir::ClosureKind::Coroutine(_),
+                    ExprKind::Closure(Closure {
+                        kind: ClosureKind::Coroutine(_),
                         ..
                     }),
                 ..
@@ -90,7 +128,7 @@ fn get_parent_fn_ret_ty<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'_>) -> Option
                 ..
             })
             | Node::Expr(Expr {
-                kind: ExprKind::Closure(hir::Closure { fn_decl: decl, .. }),
+                kind: ExprKind::Closure(Closure { fn_decl: decl, .. }),
                 ..
             }) => return Some(decl.output),
             _ => (),
diff --git a/src/tools/clippy/clippy_lints/src/manual_let_else.rs b/src/tools/clippy/clippy_lints/src/manual_let_else.rs
index 1f9a943f13d..5a7967bbf94 100644
--- a/src/tools/clippy/clippy_lints/src/manual_let_else.rs
+++ b/src/tools/clippy/clippy_lints/src/manual_let_else.rs
@@ -49,7 +49,7 @@ declare_clippy_lint! {
 }
 
 impl<'tcx> QuestionMark {
-    pub(crate) fn check_manual_let_else(&mut self, cx: &LateContext<'tcx>, stmt: &'tcx Stmt<'tcx>) {
+    pub(crate) fn check_manual_let_else(&self, cx: &LateContext<'tcx>, stmt: &'tcx Stmt<'tcx>) {
         if let StmtKind::Let(local) = stmt.kind
             && let Some(init) = local.init
             && local.els.is_none()
diff --git a/src/tools/clippy/clippy_lints/src/matches/match_bool.rs b/src/tools/clippy/clippy_lints/src/matches/match_bool.rs
index b90cf6357c5..a2c8741f4f7 100644
--- a/src/tools/clippy/clippy_lints/src/matches/match_bool.rs
+++ b/src/tools/clippy/clippy_lints/src/matches/match_bool.rs
@@ -12,7 +12,11 @@ use super::MATCH_BOOL;
 
 pub(crate) fn check(cx: &LateContext<'_>, scrutinee: &Expr<'_>, arms: &[Arm<'_>], expr: &Expr<'_>) {
     // Type of expression is `bool`.
-    if *cx.typeck_results().expr_ty(scrutinee).kind() == ty::Bool {
+    if *cx.typeck_results().expr_ty(scrutinee).kind() == ty::Bool
+        && arms
+            .iter()
+            .all(|arm| arm.pat.walk_short(|p| !matches!(p.kind, PatKind::Binding(..))))
+    {
         span_lint_and_then(
             cx,
             MATCH_BOOL,
diff --git a/src/tools/clippy/clippy_lints/src/matches/match_ref_pats.rs b/src/tools/clippy/clippy_lints/src/matches/match_ref_pats.rs
index 5445ee1f042..5934ec40993 100644
--- a/src/tools/clippy/clippy_lints/src/matches/match_ref_pats.rs
+++ b/src/tools/clippy/clippy_lints/src/matches/match_ref_pats.rs
@@ -17,6 +17,11 @@ where
         return;
     }
 
+    // `!` cannot be deref-ed
+    if cx.typeck_results().expr_ty(scrutinee).is_never() {
+        return;
+    }
+
     let (first_sugg, msg, title);
     let ctxt = expr.span.ctxt();
     let mut app = Applicability::Unspecified;
diff --git a/src/tools/clippy/clippy_lints/src/matches/match_str_case_mismatch.rs b/src/tools/clippy/clippy_lints/src/matches/match_str_case_mismatch.rs
index 8b4c1700051..eb8b16e1561 100644
--- a/src/tools/clippy/clippy_lints/src/matches/match_str_case_mismatch.rs
+++ b/src/tools/clippy/clippy_lints/src/matches/match_str_case_mismatch.rs
@@ -54,7 +54,7 @@ impl<'tcx> Visitor<'tcx> for MatchExprVisitor<'_, 'tcx> {
 }
 
 impl MatchExprVisitor<'_, '_> {
-    fn case_altered(&mut self, segment_ident: Symbol, receiver: &Expr<'_>) -> ControlFlow<CaseMethod> {
+    fn case_altered(&self, segment_ident: Symbol, receiver: &Expr<'_>) -> ControlFlow<CaseMethod> {
         if let Some(case_method) = get_case_method(segment_ident) {
             let ty = self.cx.typeck_results().expr_ty(receiver).peel_refs();
 
diff --git a/src/tools/clippy/clippy_lints/src/methods/double_ended_iterator_last.rs b/src/tools/clippy/clippy_lints/src/methods/double_ended_iterator_last.rs
index 6d841853fbe..578865c3291 100644
--- a/src/tools/clippy/clippy_lints/src/methods/double_ended_iterator_last.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/double_ended_iterator_last.rs
@@ -1,6 +1,6 @@
 use clippy_utils::diagnostics::span_lint_and_then;
 use clippy_utils::ty::{has_non_owning_mutable_access, implements_trait};
-use clippy_utils::{is_mutable, is_trait_method, path_to_local, sym};
+use clippy_utils::{is_mutable, is_trait_method, path_to_local_with_projections, sym};
 use rustc_errors::Applicability;
 use rustc_hir::{Expr, Node, PatKind};
 use rustc_lint::LateContext;
@@ -37,7 +37,7 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &'_ Expr<'_>, self_expr: &'_ Exp
         // TODO: Change this to lint only when the referred iterator is not used later. If it is used later,
         // changing to `next_back()` may change its behavior.
         if !(is_mutable(cx, self_expr) || self_type.is_ref()) {
-            if let Some(hir_id) = path_to_local(self_expr)
+            if let Some(hir_id) = path_to_local_with_projections(self_expr)
                 && let Node::Pat(pat) = cx.tcx.hir_node(hir_id)
                 && let PatKind::Binding(_, _, ident, _) = pat.kind
             {
diff --git a/src/tools/clippy/clippy_lints/src/methods/expect_fun_call.rs b/src/tools/clippy/clippy_lints/src/methods/expect_fun_call.rs
index 6e5da5bda8c..818e26f8aa1 100644
--- a/src/tools/clippy/clippy_lints/src/methods/expect_fun_call.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/expect_fun_call.rs
@@ -15,7 +15,6 @@ use std::ops::ControlFlow;
 use super::EXPECT_FUN_CALL;
 
 /// Checks for the `EXPECT_FUN_CALL` lint.
-#[allow(clippy::too_many_lines)]
 pub(super) fn check<'tcx>(
     cx: &LateContext<'tcx>,
     format_args_storage: &FormatArgsStorage,
@@ -25,43 +24,6 @@ pub(super) fn check<'tcx>(
     receiver: &'tcx hir::Expr<'tcx>,
     args: &'tcx [hir::Expr<'tcx>],
 ) {
-    // Strip `{}`, `&`, `as_ref()` and `as_str()` off `arg` until we're left with either a `String` or
-    // `&str`
-    fn get_arg_root<'a>(cx: &LateContext<'_>, arg: &'a hir::Expr<'a>) -> &'a hir::Expr<'a> {
-        let mut arg_root = peel_blocks(arg);
-        loop {
-            arg_root = match &arg_root.kind {
-                hir::ExprKind::AddrOf(hir::BorrowKind::Ref, _, expr) => expr,
-                hir::ExprKind::MethodCall(method_name, receiver, [], ..) => {
-                    if (method_name.ident.name == sym::as_str || method_name.ident.name == sym::as_ref) && {
-                        let arg_type = cx.typeck_results().expr_ty(receiver);
-                        let base_type = arg_type.peel_refs();
-                        base_type.is_str() || is_type_lang_item(cx, base_type, hir::LangItem::String)
-                    } {
-                        receiver
-                    } else {
-                        break;
-                    }
-                },
-                _ => break,
-            };
-        }
-        arg_root
-    }
-
-    fn contains_call<'a>(cx: &LateContext<'a>, arg: &'a hir::Expr<'a>) -> bool {
-        for_each_expr(cx, arg, |expr| {
-            if matches!(expr.kind, hir::ExprKind::MethodCall { .. } | hir::ExprKind::Call { .. })
-                && !is_inside_always_const_context(cx.tcx, expr.hir_id)
-            {
-                ControlFlow::Break(())
-            } else {
-                ControlFlow::Continue(())
-            }
-        })
-        .is_some()
-    }
-
     if name == sym::expect
         && let [arg] = args
         && let arg_root = get_arg_root(cx, arg)
@@ -114,3 +76,40 @@ pub(super) fn check<'tcx>(
         );
     }
 }
+
+/// Strip `{}`, `&`, `as_ref()` and `as_str()` off `arg` until we're left with either a `String` or
+/// `&str`
+fn get_arg_root<'a>(cx: &LateContext<'_>, arg: &'a hir::Expr<'a>) -> &'a hir::Expr<'a> {
+    let mut arg_root = peel_blocks(arg);
+    loop {
+        arg_root = match &arg_root.kind {
+            hir::ExprKind::AddrOf(hir::BorrowKind::Ref, _, expr) => expr,
+            hir::ExprKind::MethodCall(method_name, receiver, [], ..) => {
+                if (method_name.ident.name == sym::as_str || method_name.ident.name == sym::as_ref) && {
+                    let arg_type = cx.typeck_results().expr_ty(receiver);
+                    let base_type = arg_type.peel_refs();
+                    base_type.is_str() || is_type_lang_item(cx, base_type, hir::LangItem::String)
+                } {
+                    receiver
+                } else {
+                    break;
+                }
+            },
+            _ => break,
+        };
+    }
+    arg_root
+}
+
+fn contains_call<'a>(cx: &LateContext<'a>, arg: &'a hir::Expr<'a>) -> bool {
+    for_each_expr(cx, arg, |expr| {
+        if matches!(expr.kind, hir::ExprKind::MethodCall { .. } | hir::ExprKind::Call { .. })
+            && !is_inside_always_const_context(cx.tcx, expr.hir_id)
+        {
+            ControlFlow::Break(())
+        } else {
+            ControlFlow::Continue(())
+        }
+    })
+    .is_some()
+}
diff --git a/src/tools/clippy/clippy_lints/src/methods/filter_map.rs b/src/tools/clippy/clippy_lints/src/methods/filter_map.rs
index 4dd54cf1974..5b8457bdd16 100644
--- a/src/tools/clippy/clippy_lints/src/methods/filter_map.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/filter_map.rs
@@ -106,7 +106,7 @@ enum CheckResult<'tcx> {
 
 impl<'tcx> OffendingFilterExpr<'tcx> {
     pub fn check_map_call(
-        &mut self,
+        &self,
         cx: &LateContext<'tcx>,
         map_body: &'tcx Body<'tcx>,
         map_param_id: HirId,
@@ -413,7 +413,7 @@ fn is_find_or_filter<'a>(
         }
 
         && let PatKind::Binding(_, filter_param_id, _, None) = filter_pat.kind
-        && let Some(mut offending_expr) = OffendingFilterExpr::hir(cx, filter_body.value, filter_param_id)
+        && let Some(offending_expr) = OffendingFilterExpr::hir(cx, filter_body.value, filter_param_id)
 
         && let ExprKind::Closure(&Closure { body: map_body_id, .. }) = map_arg.kind
         && let map_body = cx.tcx.hir_body(map_body_id)
diff --git a/src/tools/clippy/clippy_lints/src/methods/filter_next.rs b/src/tools/clippy/clippy_lints/src/methods/filter_next.rs
index 6c1a14fc882..72f83b245a0 100644
--- a/src/tools/clippy/clippy_lints/src/methods/filter_next.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/filter_next.rs
@@ -1,4 +1,5 @@
 use clippy_utils::diagnostics::{span_lint, span_lint_and_then};
+use clippy_utils::path_to_local_with_projections;
 use clippy_utils::source::snippet;
 use clippy_utils::ty::implements_trait;
 use rustc_ast::{BindingMode, Mutability};
@@ -9,21 +10,6 @@ use rustc_span::sym;
 
 use super::FILTER_NEXT;
 
-fn path_to_local(expr: &hir::Expr<'_>) -> Option<hir::HirId> {
-    match expr.kind {
-        hir::ExprKind::Field(f, _) => path_to_local(f),
-        hir::ExprKind::Index(recv, _, _) => path_to_local(recv),
-        hir::ExprKind::Path(hir::QPath::Resolved(
-            _,
-            hir::Path {
-                res: rustc_hir::def::Res::Local(local),
-                ..
-            },
-        )) => Some(*local),
-        _ => None,
-    }
-}
-
 /// lint use of `filter().next()` for `Iterators`
 pub(super) fn check<'tcx>(
     cx: &LateContext<'tcx>,
@@ -44,7 +30,7 @@ pub(super) fn check<'tcx>(
             let iter_snippet = snippet(cx, recv.span, "..");
             // add note if not multi-line
             span_lint_and_then(cx, FILTER_NEXT, expr.span, msg, |diag| {
-                let (applicability, pat) = if let Some(id) = path_to_local(recv)
+                let (applicability, pat) = if let Some(id) = path_to_local_with_projections(recv)
                     && let hir::Node::Pat(pat) = cx.tcx.hir_node(id)
                     && let hir::PatKind::Binding(BindingMode(_, Mutability::Not), _, ident, _) = pat.kind
                 {
diff --git a/src/tools/clippy/clippy_lints/src/misc_early/mod.rs b/src/tools/clippy/clippy_lints/src/misc_early/mod.rs
index f880f1f329f..f988323a8c1 100644
--- a/src/tools/clippy/clippy_lints/src/misc_early/mod.rs
+++ b/src/tools/clippy/clippy_lints/src/misc_early/mod.rs
@@ -7,12 +7,9 @@ mod unneeded_field_pattern;
 mod unneeded_wildcard_pattern;
 mod zero_prefixed_literal;
 
-use clippy_utils::diagnostics::span_lint;
 use clippy_utils::source::snippet_opt;
-use rustc_ast::ast::{Expr, ExprKind, Generics, LitFloatType, LitIntType, LitKind, NodeId, Pat, PatKind};
+use rustc_ast::ast::{Expr, ExprKind, Generics, LitFloatType, LitIntType, LitKind, Pat};
 use rustc_ast::token;
-use rustc_ast::visit::FnKind;
-use rustc_data_structures::fx::FxHashMap;
 use rustc_lint::{EarlyContext, EarlyLintPass, LintContext};
 use rustc_session::declare_lint_pass;
 use rustc_span::Span;
@@ -62,29 +59,6 @@ declare_clippy_lint! {
 
 declare_clippy_lint! {
     /// ### What it does
-    /// Checks for function arguments having the similar names
-    /// differing by an underscore.
-    ///
-    /// ### Why is this bad?
-    /// It affects code readability.
-    ///
-    /// ### Example
-    /// ```no_run
-    /// fn foo(a: i32, _a: i32) {}
-    /// ```
-    ///
-    /// Use instead:
-    /// ```no_run
-    /// fn bar(a: i32, _b: i32) {}
-    /// ```
-    #[clippy::version = "pre 1.29.0"]
-    pub DUPLICATE_UNDERSCORE_ARGUMENT,
-    style,
-    "function arguments having names which only differ by an underscore"
-}
-
-declare_clippy_lint! {
-    /// ### What it does
     /// Warns on hexadecimal literals with mixed-case letter
     /// digits.
     ///
@@ -330,7 +304,6 @@ declare_clippy_lint! {
 
 declare_lint_pass!(MiscEarlyLints => [
     UNNEEDED_FIELD_PATTERN,
-    DUPLICATE_UNDERSCORE_ARGUMENT,
     MIXED_CASE_HEX_LITERALS,
     UNSEPARATED_LITERAL_SUFFIX,
     SEPARATED_LITERAL_SUFFIX,
@@ -359,32 +332,6 @@ impl EarlyLintPass for MiscEarlyLints {
         unneeded_wildcard_pattern::check(cx, pat);
     }
 
-    fn check_fn(&mut self, cx: &EarlyContext<'_>, fn_kind: FnKind<'_>, _: Span, _: NodeId) {
-        let mut registered_names: FxHashMap<String, Span> = FxHashMap::default();
-
-        for arg in &fn_kind.decl().inputs {
-            if let PatKind::Ident(_, ident, None) = arg.pat.kind {
-                let arg_name = ident.to_string();
-
-                if let Some(arg_name) = arg_name.strip_prefix('_') {
-                    if let Some(correspondence) = registered_names.get(arg_name) {
-                        span_lint(
-                            cx,
-                            DUPLICATE_UNDERSCORE_ARGUMENT,
-                            *correspondence,
-                            format!(
-                                "`{arg_name}` already exists, having another argument having almost the same \
-                                 name makes code comprehension and documentation more difficult"
-                            ),
-                        );
-                    }
-                } else {
-                    registered_names.insert(arg_name, arg.pat.span);
-                }
-            }
-        }
-    }
-
     fn check_expr(&mut self, cx: &EarlyContext<'_>, expr: &Expr) {
         if expr.span.in_external_macro(cx.sess().source_map()) {
             return;
@@ -404,7 +351,7 @@ impl MiscEarlyLints {
         // See <https://github.com/rust-lang/rust-clippy/issues/4507> for a regression.
         // FIXME: Find a better way to detect those cases.
         let lit_snip = match snippet_opt(cx, span) {
-            Some(snip) if snip.chars().next().is_some_and(|c| c.is_ascii_digit()) => snip,
+            Some(snip) if snip.starts_with(|c: char| c.is_ascii_digit()) => snip,
             _ => return,
         };
 
diff --git a/src/tools/clippy/clippy_lints/src/mixed_read_write_in_expression.rs b/src/tools/clippy/clippy_lints/src/mixed_read_write_in_expression.rs
index a489c0a4a5a..3b44d4b60d3 100644
--- a/src/tools/clippy/clippy_lints/src/mixed_read_write_in_expression.rs
+++ b/src/tools/clippy/clippy_lints/src/mixed_read_write_in_expression.rs
@@ -134,7 +134,7 @@ impl<'tcx> DivergenceVisitor<'_, 'tcx> {
         }
     }
 
-    fn report_diverging_sub_expr(&mut self, e: &Expr<'_>) {
+    fn report_diverging_sub_expr(&self, e: &Expr<'_>) {
         if let Some(macro_call) = root_macro_call_first_node(self.cx, e)
             && self.cx.tcx.is_diagnostic_item(sym::todo_macro, macro_call.def_id)
         {
diff --git a/src/tools/clippy/clippy_lints/src/needless_bool.rs b/src/tools/clippy/clippy_lints/src/needless_bool.rs
index fa5afcc0087..6ae26156bc4 100644
--- a/src/tools/clippy/clippy_lints/src/needless_bool.rs
+++ b/src/tools/clippy/clippy_lints/src/needless_bool.rs
@@ -166,7 +166,9 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessBool {
                     applicability,
                 );
             };
-            if let Some((a, b)) = fetch_bool_block(then).and_then(|a| Some((a, fetch_bool_block(else_expr)?))) {
+            if let Some(a) = fetch_bool_block(then)
+                && let Some(b) = fetch_bool_block(else_expr)
+            {
                 match (a, b) {
                     (RetBool(true), RetBool(true)) | (Bool(true), Bool(true)) => {
                         span_lint(
diff --git a/src/tools/clippy/clippy_lints/src/needless_borrows_for_generic_args.rs b/src/tools/clippy/clippy_lints/src/needless_borrows_for_generic_args.rs
index 120a4b98a65..c7c4976aeb7 100644
--- a/src/tools/clippy/clippy_lints/src/needless_borrows_for_generic_args.rs
+++ b/src/tools/clippy/clippy_lints/src/needless_borrows_for_generic_args.rs
@@ -59,7 +59,7 @@ declare_clippy_lint! {
 
 pub struct NeedlessBorrowsForGenericArgs<'tcx> {
     /// Stack of (body owner, `PossibleBorrowerMap`) pairs. Used by
-    /// `needless_borrow_impl_arg_position` to determine when a borrowed expression can instead
+    /// [`needless_borrow_count`] to determine when a borrowed expression can instead
     /// be moved.
     possible_borrowers: Vec<(LocalDefId, PossibleBorrowerMap<'tcx, 'tcx>)>,
 
diff --git a/src/tools/clippy/clippy_lints/src/no_effect.rs b/src/tools/clippy/clippy_lints/src/no_effect.rs
index 72e6503e7e4..0d6666eed45 100644
--- a/src/tools/clippy/clippy_lints/src/no_effect.rs
+++ b/src/tools/clippy/clippy_lints/src/no_effect.rs
@@ -305,11 +305,12 @@ fn check_unnecessary_operation(cx: &LateContext<'_>, stmt: &Stmt<'_>) {
             for e in reduced {
                 if let Some(snip) = e.span.get_source_text(cx) {
                     snippet.push_str(&snip);
-                    snippet.push(';');
+                    snippet.push_str("; ");
                 } else {
                     return;
                 }
             }
+            snippet.pop(); // remove the last space
             span_lint_hir_and_then(
                 cx,
                 UNNECESSARY_OPERATION,
diff --git a/src/tools/clippy/clippy_lints/src/non_copy_const.rs b/src/tools/clippy/clippy_lints/src/non_copy_const.rs
index 8a5a6f4a4dc..2fffc4244a7 100644
--- a/src/tools/clippy/clippy_lints/src/non_copy_const.rs
+++ b/src/tools/clippy/clippy_lints/src/non_copy_const.rs
@@ -92,7 +92,7 @@ declare_clippy_lint! {
     /// ```
     #[clippy::version = "pre 1.29.0"]
     pub DECLARE_INTERIOR_MUTABLE_CONST,
-    style,
+    suspicious,
     "declaring `const` with interior mutability"
 }
 
diff --git a/src/tools/clippy/clippy_lints/src/non_expressive_names.rs b/src/tools/clippy/clippy_lints/src/non_expressive_names.rs
index c5873589b26..1961ac1516d 100644
--- a/src/tools/clippy/clippy_lints/src/non_expressive_names.rs
+++ b/src/tools/clippy/clippy_lints/src/non_expressive_names.rs
@@ -248,6 +248,11 @@ impl SimilarNamesNameVisitor<'_, '_, '_> {
                 continue;
             }
 
+            // Skip similarity check if both names are exactly 3 characters
+            if count == 3 && existing_name.len == 3 {
+                continue;
+            }
+
             let dissimilar = match existing_name.len.cmp(&count) {
                 Ordering::Greater => existing_name.len - count != 1 || levenstein_not_1(interned_name, existing_str),
                 Ordering::Less => count - existing_name.len != 1 || levenstein_not_1(existing_str, interned_name),
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 ba8f6354d97..a42763172f5 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
@@ -173,7 +173,7 @@ impl Params {
     }
 
     /// Sets the `apply_lint` flag on each parameter.
-    fn flag_for_linting(&mut self) {
+    fn flag_for_linting(&self) {
         // Stores the list of parameters currently being resolved. Needed to avoid cycles.
         let mut eval_stack = Vec::new();
         for param in &self.params {
diff --git a/src/tools/clippy/clippy_lints/src/operators/arithmetic_side_effects.rs b/src/tools/clippy/clippy_lints/src/operators/arithmetic_side_effects.rs
index 466beb04b07..ea5b81aec31 100644
--- a/src/tools/clippy/clippy_lints/src/operators/arithmetic_side_effects.rs
+++ b/src/tools/clippy/clippy_lints/src/operators/arithmetic_side_effects.rs
@@ -325,7 +325,7 @@ impl ArithmeticSideEffects {
         self.issue_lint(cx, expr);
     }
 
-    fn should_skip_expr<'tcx>(&mut self, cx: &LateContext<'tcx>, expr: &hir::Expr<'tcx>) -> bool {
+    fn should_skip_expr<'tcx>(&self, cx: &LateContext<'tcx>, expr: &hir::Expr<'tcx>) -> bool {
         is_lint_allowed(cx, ARITHMETIC_SIDE_EFFECTS, expr.hir_id)
             || self.expr_span.is_some()
             || self.const_span.is_some_and(|sp| sp.contains(expr.span))
diff --git a/src/tools/clippy/clippy_lints/src/operators/numeric_arithmetic.rs b/src/tools/clippy/clippy_lints/src/operators/numeric_arithmetic.rs
index e6be536ca0f..9b1b063c473 100644
--- a/src/tools/clippy/clippy_lints/src/operators/numeric_arithmetic.rs
+++ b/src/tools/clippy/clippy_lints/src/operators/numeric_arithmetic.rs
@@ -13,7 +13,7 @@ pub struct Context {
     const_span: Option<Span>,
 }
 impl Context {
-    fn skip_expr(&mut self, e: &hir::Expr<'_>) -> bool {
+    fn skip_expr(&self, e: &hir::Expr<'_>) -> bool {
         self.expr_id.is_some() || self.const_span.is_some_and(|span| span.contains(e.span))
     }
 
diff --git a/src/tools/clippy/clippy_lints/src/pass_by_ref_or_value.rs b/src/tools/clippy/clippy_lints/src/pass_by_ref_or_value.rs
index d7b4a03aa53..1b1e77bbea8 100644
--- a/src/tools/clippy/clippy_lints/src/pass_by_ref_or_value.rs
+++ b/src/tools/clippy/clippy_lints/src/pass_by_ref_or_value.rs
@@ -120,7 +120,7 @@ impl PassByRefOrValue {
         }
     }
 
-    fn check_poly_fn(&mut self, cx: &LateContext<'_>, def_id: LocalDefId, decl: &FnDecl<'_>, span: Option<Span>) {
+    fn check_poly_fn(&self, cx: &LateContext<'_>, def_id: LocalDefId, decl: &FnDecl<'_>, span: Option<Span>) {
         if self.avoid_breaking_exported_api && cx.effective_visibilities.is_exported(def_id) {
             return;
         }
diff --git a/src/tools/clippy/clippy_lints/src/ptr.rs b/src/tools/clippy/clippy_lints/src/ptr.rs
index b3058c51afd..9eed46460a6 100644
--- a/src/tools/clippy/clippy_lints/src/ptr.rs
+++ b/src/tools/clippy/clippy_lints/src/ptr.rs
@@ -237,7 +237,7 @@ impl<'tcx> LateLintPass<'tcx> for Ptr {
             .collect();
         let results = check_ptr_arg_usage(cx, body, &lint_args);
 
-        for (result, args) in results.iter().zip(lint_args.iter()).filter(|(r, _)| !r.skip) {
+        for (result, args) in iter::zip(&results, &lint_args).filter(|(r, _)| !r.skip) {
             span_lint_hir_and_then(cx, PTR_ARG, args.emission_id, args.span, args.build_msg(), |diag| {
                 diag.multipart_suggestion(
                     "change this to",
@@ -386,7 +386,6 @@ impl<'tcx> DerefTy<'tcx> {
     }
 }
 
-#[expect(clippy::too_many_lines)]
 fn check_fn_args<'cx, 'tcx: 'cx>(
     cx: &'cx LateContext<'tcx>,
     fn_sig: ty::FnSig<'tcx>,
@@ -413,13 +412,13 @@ fn check_fn_args<'cx, 'tcx: 'cx>(
                     Some(sym::Vec) => (
                         [(sym::clone, ".to_owned()")].as_slice(),
                         DerefTy::Slice(
-                            name.args.and_then(|args| args.args.first()).and_then(|arg| {
-                                if let GenericArg::Type(ty) = arg {
-                                    Some(ty.span)
-                                } else {
-                                    None
-                                }
-                            }),
+                            if let Some(name_args) = name.args
+                                && let [GenericArg::Type(ty), ..] = name_args.args
+                            {
+                                Some(ty.span)
+                            } else {
+                                None
+                            },
                             args.type_at(0),
                         ),
                     ),
@@ -432,33 +431,29 @@ fn check_fn_args<'cx, 'tcx: 'cx>(
                         DerefTy::Path,
                     ),
                     Some(sym::Cow) if mutability == Mutability::Not => {
-                        if let Some((lifetime, ty)) = name.args.and_then(|args| {
-                            if let [GenericArg::Lifetime(lifetime), ty] = args.args {
-                                return Some((lifetime, ty));
-                            }
-                            None
-                        }) {
+                        if let Some(name_args) = name.args
+                            && let [GenericArg::Lifetime(lifetime), ty] = name_args.args
+                        {
                             if let LifetimeKind::Param(param_def_id) = lifetime.kind
                                 && !lifetime.is_anonymous()
                                 && fn_sig
                                     .output()
                                     .walk()
-                                    .filter_map(|arg| {
-                                        arg.as_region().and_then(|lifetime| match lifetime.kind() {
-                                            ty::ReEarlyParam(r) => Some(
-                                                cx.tcx
-                                                    .generics_of(cx.tcx.parent(param_def_id.to_def_id()))
-                                                    .region_param(r, cx.tcx)
-                                                    .def_id,
-                                            ),
-                                            ty::ReBound(_, r) => r.kind.get_id(),
-                                            ty::ReLateParam(r) => r.kind.get_id(),
-                                            ty::ReStatic
-                                            | ty::ReVar(_)
-                                            | ty::RePlaceholder(_)
-                                            | ty::ReErased
-                                            | ty::ReError(_) => None,
-                                        })
+                                    .filter_map(ty::GenericArg::as_region)
+                                    .filter_map(|lifetime| match lifetime.kind() {
+                                        ty::ReEarlyParam(r) => Some(
+                                            cx.tcx
+                                                .generics_of(cx.tcx.parent(param_def_id.to_def_id()))
+                                                .region_param(r, cx.tcx)
+                                                .def_id,
+                                        ),
+                                        ty::ReBound(_, r) => r.kind.get_id(),
+                                        ty::ReLateParam(r) => r.kind.get_id(),
+                                        ty::ReStatic
+                                        | ty::ReVar(_)
+                                        | ty::RePlaceholder(_)
+                                        | ty::ReErased
+                                        | ty::ReError(_) => None,
                                     })
                                     .any(|def_id| def_id.as_local().is_some_and(|def_id| def_id == param_def_id))
                             {
@@ -627,12 +622,16 @@ fn check_ptr_arg_usage<'tcx>(cx: &LateContext<'tcx>, body: &Body<'tcx>, args: &[
                         }
                     }
 
+                    // If the expression's type gets adjusted down to the deref type, we might as
+                    // well have started with that deref type -- the lint should fire
                     let deref_ty = args.deref_ty.ty(self.cx);
                     let adjusted_ty = self.cx.typeck_results().expr_ty_adjusted(e).peel_refs();
                     if adjusted_ty == deref_ty {
                         return;
                     }
 
+                    // If the expression's type is constrained by `dyn Trait`, see if the deref
+                    // type implements the trait(s) as well, and if so, the lint should fire
                     if let ty::Dynamic(preds, ..) = adjusted_ty.kind()
                         && matches_preds(self.cx, deref_ty, preds)
                     {
diff --git a/src/tools/clippy/clippy_lints/src/raw_strings.rs b/src/tools/clippy/clippy_lints/src/raw_strings.rs
index 6a79cae32a5..943e662479e 100644
--- a/src/tools/clippy/clippy_lints/src/raw_strings.rs
+++ b/src/tools/clippy/clippy_lints/src/raw_strings.rs
@@ -103,15 +103,7 @@ impl EarlyLintPass for RawStrings {
 }
 
 impl RawStrings {
-    fn check_raw_string(
-        &mut self,
-        cx: &EarlyContext<'_>,
-        str: &str,
-        lit_span: Span,
-        prefix: &str,
-        max: u8,
-        descr: &str,
-    ) {
+    fn check_raw_string(&self, cx: &EarlyContext<'_>, str: &str, lit_span: Span, prefix: &str, max: u8, descr: &str) {
         if !str.contains(['\\', '"']) {
             span_lint_and_then(
                 cx,
diff --git a/src/tools/clippy/clippy_lints/src/redundant_pub_crate.rs b/src/tools/clippy/clippy_lints/src/redundant_pub_crate.rs
index 902e8af7ec4..0c1c664f111 100644
--- a/src/tools/clippy/clippy_lints/src/redundant_pub_crate.rs
+++ b/src/tools/clippy/clippy_lints/src/redundant_pub_crate.rs
@@ -88,8 +88,7 @@ impl<'tcx> LateLintPass<'tcx> for RedundantPubCrate {
 // We ignore macro exports. And `ListStem` uses, which aren't interesting.
 fn is_ignorable_export<'tcx>(item: &'tcx Item<'tcx>) -> bool {
     if let ItemKind::Use(path, kind) = item.kind {
-        let ignore = matches!(path.res.macro_ns, Some(Res::Def(DefKind::Macro(_), _)))
-            || kind == UseKind::ListStem;
+        let ignore = matches!(path.res.macro_ns, Some(Res::Def(DefKind::Macro(_), _))) || kind == UseKind::ListStem;
         if ignore {
             return true;
         }
diff --git a/src/tools/clippy/clippy_lints/src/reference.rs b/src/tools/clippy/clippy_lints/src/reference.rs
index 4bff37216ed..3bbcad12a31 100644
--- a/src/tools/clippy/clippy_lints/src/reference.rs
+++ b/src/tools/clippy/clippy_lints/src/reference.rs
@@ -1,10 +1,11 @@
 use clippy_utils::diagnostics::span_lint_and_sugg;
-use clippy_utils::source::{SpanRangeExt, snippet_with_applicability};
-use rustc_ast::ast::{Expr, ExprKind, Mutability, UnOp};
+use clippy_utils::source::snippet;
+use clippy_utils::sugg::{Sugg, has_enclosing_paren};
+use clippy_utils::ty::adjust_derefs_manually_drop;
 use rustc_errors::Applicability;
-use rustc_lint::{EarlyContext, EarlyLintPass};
+use rustc_hir::{Expr, ExprKind, HirId, Node, UnOp};
+use rustc_lint::{LateContext, LateLintPass};
 use rustc_session::declare_lint_pass;
-use rustc_span::{BytePos, Span};
 
 declare_clippy_lint! {
     /// ### What it does
@@ -37,17 +38,12 @@ declare_clippy_lint! {
 
 declare_lint_pass!(DerefAddrOf => [DEREF_ADDROF]);
 
-fn without_parens(mut e: &Expr) -> &Expr {
-    while let ExprKind::Paren(ref child_e) = e.kind {
-        e = child_e;
-    }
-    e
-}
-
-impl EarlyLintPass for DerefAddrOf {
-    fn check_expr(&mut self, cx: &EarlyContext<'_>, e: &Expr) {
-        if let ExprKind::Unary(UnOp::Deref, ref deref_target) = e.kind
-            && let ExprKind::AddrOf(_, ref mutability, ref addrof_target) = without_parens(deref_target).kind
+impl LateLintPass<'_> for DerefAddrOf {
+    fn check_expr(&mut self, cx: &LateContext<'_>, e: &Expr<'_>) {
+        if !e.span.from_expansion()
+            && let ExprKind::Unary(UnOp::Deref, deref_target) = e.kind
+            && !deref_target.span.from_expansion()
+            && let ExprKind::AddrOf(_, _, addrof_target) = deref_target.kind
             // NOTE(tesuji): `*&` forces rustc to const-promote the array to `.rodata` section.
             // See #12854 for details.
             && !matches!(addrof_target.kind, ExprKind::Array(_))
@@ -55,57 +51,82 @@ impl EarlyLintPass for DerefAddrOf {
             && !addrof_target.span.from_expansion()
         {
             let mut applicability = Applicability::MachineApplicable;
-            let sugg = if e.span.from_expansion() {
-                if let Some(macro_source) = e.span.get_source_text(cx) {
-                    // Remove leading whitespace from the given span
-                    // e.g: ` $visitor` turns into `$visitor`
-                    let trim_leading_whitespaces = |span: Span| {
-                        span.get_source_text(cx)
-                            .and_then(|snip| {
-                                #[expect(clippy::cast_possible_truncation)]
-                                snip.find(|c: char| !c.is_whitespace())
-                                    .map(|pos| span.lo() + BytePos(pos as u32))
-                            })
-                            .map_or(span, |start_no_whitespace| e.span.with_lo(start_no_whitespace))
-                    };
+            let mut sugg = || Sugg::hir_with_applicability(cx, addrof_target, "_", &mut applicability);
 
-                    let mut generate_snippet = |pattern: &str| {
-                        #[expect(clippy::cast_possible_truncation)]
-                        macro_source.rfind(pattern).map(|pattern_pos| {
-                            let rpos = pattern_pos + pattern.len();
-                            let span_after_ref = e.span.with_lo(BytePos(e.span.lo().0 + rpos as u32));
-                            let span = trim_leading_whitespaces(span_after_ref);
-                            snippet_with_applicability(cx, span, "_", &mut applicability)
-                        })
-                    };
+            // If this expression is an explicit `DerefMut` of a `ManuallyDrop` reached through a
+            // union, we may remove the reference if we are at the point where the implicit
+            // dereference would take place. Otherwise, we should not lint.
+            let sugg = match is_manually_drop_through_union(cx, e.hir_id, addrof_target) {
+                ManuallyDropThroughUnion::Directly => sugg().deref(),
+                ManuallyDropThroughUnion::Indirect => return,
+                ManuallyDropThroughUnion::No => sugg(),
+            };
+
+            let sugg = if has_enclosing_paren(snippet(cx, e.span, "")) {
+                sugg.maybe_paren()
+            } else {
+                sugg
+            };
+
+            span_lint_and_sugg(
+                cx,
+                DEREF_ADDROF,
+                e.span,
+                "immediately dereferencing a reference",
+                "try",
+                sugg.to_string(),
+                applicability,
+            );
+        }
+    }
+}
+
+/// Is this a `ManuallyDrop` reached through a union, and when is `DerefMut` called on it?
+enum ManuallyDropThroughUnion {
+    /// `ManuallyDrop` reached through a union and immediately explicitely dereferenced
+    Directly,
+    /// `ManuallyDrop` reached through a union, and dereferenced later on
+    Indirect,
+    /// Any other situation
+    No,
+}
 
-                    if *mutability == Mutability::Mut {
-                        generate_snippet("mut")
+/// Check if `addrof_target` is part of an access to a `ManuallyDrop` entity reached through a
+/// union, and when it is dereferenced using `DerefMut` starting from `expr_id` and going up.
+fn is_manually_drop_through_union(
+    cx: &LateContext<'_>,
+    expr_id: HirId,
+    addrof_target: &Expr<'_>,
+) -> ManuallyDropThroughUnion {
+    if is_reached_through_union(cx, addrof_target) {
+        let typeck = cx.typeck_results();
+        for (idx, id) in std::iter::once(expr_id)
+            .chain(cx.tcx.hir_parent_id_iter(expr_id))
+            .enumerate()
+        {
+            if let Node::Expr(expr) = cx.tcx.hir_node(id) {
+                if adjust_derefs_manually_drop(typeck.expr_adjustments(expr), typeck.expr_ty(expr)) {
+                    return if idx == 0 {
+                        ManuallyDropThroughUnion::Directly
                     } else {
-                        generate_snippet("&")
-                    }
-                } else {
-                    Some(snippet_with_applicability(cx, e.span, "_", &mut applicability))
+                        ManuallyDropThroughUnion::Indirect
+                    };
                 }
             } else {
-                Some(snippet_with_applicability(
-                    cx,
-                    addrof_target.span,
-                    "_",
-                    &mut applicability,
-                ))
-            };
-            if let Some(sugg) = sugg {
-                span_lint_and_sugg(
-                    cx,
-                    DEREF_ADDROF,
-                    e.span,
-                    "immediately dereferencing a reference",
-                    "try",
-                    sugg.to_string(),
-                    applicability,
-                );
+                break;
             }
         }
     }
+    ManuallyDropThroughUnion::No
+}
+
+/// Checks whether `expr` denotes an object reached through a union
+fn is_reached_through_union(cx: &LateContext<'_>, mut expr: &Expr<'_>) -> bool {
+    while let ExprKind::Field(parent, _) | ExprKind::Index(parent, _, _) = expr.kind {
+        if cx.typeck_results().expr_ty_adjusted(parent).is_union() {
+            return true;
+        }
+        expr = parent;
+    }
+    false
 }
diff --git a/src/tools/clippy/clippy_lints/src/swap.rs b/src/tools/clippy/clippy_lints/src/swap.rs
index 5ecbb56925e..76ab3cdae22 100644
--- a/src/tools/clippy/clippy_lints/src/swap.rs
+++ b/src/tools/clippy/clippy_lints/src/swap.rs
@@ -380,7 +380,7 @@ impl<'tcx> IndexBinding<'_, 'tcx> {
         }
     }
 
-    fn is_used_other_than_swapping(&mut self, idx_ident: Ident) -> bool {
+    fn is_used_other_than_swapping(&self, idx_ident: Ident) -> bool {
         if Self::is_used_slice_indexed(self.swap1_idx, idx_ident)
             || Self::is_used_slice_indexed(self.swap2_idx, idx_ident)
         {
@@ -389,7 +389,7 @@ impl<'tcx> IndexBinding<'_, 'tcx> {
         self.is_used_after_swap(idx_ident)
     }
 
-    fn is_used_after_swap(&mut self, idx_ident: Ident) -> bool {
+    fn is_used_after_swap(&self, idx_ident: Ident) -> bool {
         let mut v = IndexBindingVisitor {
             idx: idx_ident,
             suggest_span: self.suggest_span,
diff --git a/src/tools/clippy/clippy_lints/src/transmute/eager_transmute.rs b/src/tools/clippy/clippy_lints/src/transmute/eager_transmute.rs
index 535c044f49e..97e68b3df94 100644
--- a/src/tools/clippy/clippy_lints/src/transmute/eager_transmute.rs
+++ b/src/tools/clippy/clippy_lints/src/transmute/eager_transmute.rs
@@ -1,5 +1,5 @@
 use clippy_utils::diagnostics::span_lint_and_then;
-use clippy_utils::{eq_expr_value, path_to_local, sym};
+use clippy_utils::{eq_expr_value, path_to_local_with_projections, sym};
 use rustc_abi::WrappingRange;
 use rustc_errors::Applicability;
 use rustc_hir::{Expr, ExprKind, Node};
@@ -63,11 +63,7 @@ fn binops_with_local(cx: &LateContext<'_>, local_expr: &Expr<'_>, expr: &Expr<'_
 /// Checks if an expression is a path to a local variable (with optional projections), e.g.
 /// `x.field[0].field2` would return true.
 fn is_local_with_projections(expr: &Expr<'_>) -> bool {
-    match expr.kind {
-        ExprKind::Path(_) => path_to_local(expr).is_some(),
-        ExprKind::Field(expr, _) | ExprKind::Index(expr, ..) => is_local_with_projections(expr),
-        _ => false,
-    }
+    path_to_local_with_projections(expr).is_some()
 }
 
 pub(super) fn check<'tcx>(
diff --git a/src/tools/clippy/clippy_lints/src/transmute/mod.rs b/src/tools/clippy/clippy_lints/src/transmute/mod.rs
index d5112e2c3f9..1c7bb4314dd 100644
--- a/src/tools/clippy/clippy_lints/src/transmute/mod.rs
+++ b/src/tools/clippy/clippy_lints/src/transmute/mod.rs
@@ -105,7 +105,7 @@ declare_clippy_lint! {
     /// ```
     #[clippy::version = "pre 1.29.0"]
     pub CROSSPOINTER_TRANSMUTE,
-    complexity,
+    suspicious,
     "transmutes that have to or from types that are a pointer to the other"
 }
 
diff --git a/src/tools/clippy/clippy_lints/src/undocumented_unsafe_blocks.rs b/src/tools/clippy/clippy_lints/src/undocumented_unsafe_blocks.rs
index 1c52de52619..ba0d4de5f3b 100644
--- a/src/tools/clippy/clippy_lints/src/undocumented_unsafe_blocks.rs
+++ b/src/tools/clippy/clippy_lints/src/undocumented_unsafe_blocks.rs
@@ -202,79 +202,41 @@ impl<'tcx> LateLintPass<'tcx> for UndocumentedUnsafeBlocks {
         };
 
         let item_has_safety_comment = item_has_safety_comment(cx, item);
-        match (&item.kind, item_has_safety_comment) {
-            // lint unsafe impl without safety comment
-            (ItemKind::Impl(Impl { of_trait: Some(of_trait), .. }), HasSafetyComment::No) if of_trait.safety.is_unsafe() => {
-                if !is_lint_allowed(cx, UNDOCUMENTED_UNSAFE_BLOCKS, item.hir_id())
-                    && !is_unsafe_from_proc_macro(cx, item.span)
-                {
-                    let source_map = cx.tcx.sess.source_map();
-                    let span = if source_map.is_multiline(item.span) {
-                        source_map.span_until_char(item.span, '\n')
-                    } else {
-                        item.span
-                    };
-
-                    #[expect(clippy::collapsible_span_lint_calls, reason = "rust-clippy#7797")]
-                    span_lint_and_then(
-                        cx,
-                        UNDOCUMENTED_UNSAFE_BLOCKS,
-                        span,
-                        "unsafe impl missing a safety comment",
-                        |diag| {
-                            diag.help("consider adding a safety comment on the preceding line");
-                        },
-                    );
-                }
-            },
-            // lint safe impl with unnecessary safety comment
-            (ItemKind::Impl(Impl { of_trait: Some(of_trait), .. }), HasSafetyComment::Yes(pos)) if of_trait.safety.is_safe() => {
-                if !is_lint_allowed(cx, UNNECESSARY_SAFETY_COMMENT, item.hir_id()) {
-                    let (span, help_span) = mk_spans(pos);
-
-                    span_lint_and_then(
-                        cx,
-                        UNNECESSARY_SAFETY_COMMENT,
-                        span,
-                        "impl has unnecessary safety comment",
-                        |diag| {
-                            diag.span_help(help_span, "consider removing the safety comment");
-                        },
-                    );
-                }
-            },
-            (ItemKind::Impl(_), _) => {},
-            // const and static items only need a safety comment if their body is an unsafe block, lint otherwise
-            (&ItemKind::Const(.., body) | &ItemKind::Static(.., body), HasSafetyComment::Yes(pos)) => {
-                if !is_lint_allowed(cx, UNNECESSARY_SAFETY_COMMENT, body.hir_id) {
-                    let body = cx.tcx.hir_body(body);
-                    if !matches!(
-                        body.value.kind, hir::ExprKind::Block(block, _)
-                        if block.rules == BlockCheckMode::UnsafeBlock(UnsafeSource::UserProvided)
-                    ) {
-                        let (span, help_span) = mk_spans(pos);
-
-                        span_lint_and_then(
-                            cx,
-                            UNNECESSARY_SAFETY_COMMENT,
-                            span,
-                            format!(
-                                "{} has unnecessary safety comment",
-                                cx.tcx.def_descr(item.owner_id.to_def_id()),
-                            ),
-                            |diag| {
-                                diag.span_help(help_span, "consider removing the safety comment");
-                            },
-                        );
-                    }
-                }
-            },
-            // Aside from unsafe impls and consts/statics with an unsafe block, items in general
-            // do not have safety invariants that need to be documented, so lint those.
-            (_, HasSafetyComment::Yes(pos)) => {
-                if !is_lint_allowed(cx, UNNECESSARY_SAFETY_COMMENT, item.hir_id()) {
-                    let (span, help_span) = mk_spans(pos);
+        match item_has_safety_comment {
+            HasSafetyComment::Yes(pos) => check_has_safety_comment(cx, item, mk_spans(pos)),
+            HasSafetyComment::No => check_has_no_safety_comment(cx, item),
+            HasSafetyComment::Maybe => {},
+        }
+    }
+}
 
+fn check_has_safety_comment(cx: &LateContext<'_>, item: &hir::Item<'_>, (span, help_span): (Span, Span)) {
+    match &item.kind {
+        ItemKind::Impl(Impl {
+            of_trait: Some(of_trait),
+            ..
+        }) if of_trait.safety.is_safe() => {
+            if !is_lint_allowed(cx, UNNECESSARY_SAFETY_COMMENT, item.hir_id()) {
+                span_lint_and_then(
+                    cx,
+                    UNNECESSARY_SAFETY_COMMENT,
+                    span,
+                    "impl has unnecessary safety comment",
+                    |diag| {
+                        diag.span_help(help_span, "consider removing the safety comment");
+                    },
+                );
+            }
+        },
+        ItemKind::Impl(_) => {},
+        // const and static items only need a safety comment if their body is an unsafe block, lint otherwise
+        &ItemKind::Const(.., body) | &ItemKind::Static(.., body) => {
+            if !is_lint_allowed(cx, UNNECESSARY_SAFETY_COMMENT, body.hir_id) {
+                let body = cx.tcx.hir_body(body);
+                if !matches!(
+                    body.value.kind, hir::ExprKind::Block(block, _)
+                    if block.rules == BlockCheckMode::UnsafeBlock(UnsafeSource::UserProvided)
+                ) {
                     span_lint_and_then(
                         cx,
                         UNNECESSARY_SAFETY_COMMENT,
@@ -288,12 +250,56 @@ impl<'tcx> LateLintPass<'tcx> for UndocumentedUnsafeBlocks {
                         },
                     );
                 }
-            },
-            _ => (),
-        }
+            }
+        },
+        // Aside from unsafe impls and consts/statics with an unsafe block, items in general
+        // do not have safety invariants that need to be documented, so lint those.
+        _ => {
+            if !is_lint_allowed(cx, UNNECESSARY_SAFETY_COMMENT, item.hir_id()) {
+                span_lint_and_then(
+                    cx,
+                    UNNECESSARY_SAFETY_COMMENT,
+                    span,
+                    format!(
+                        "{} has unnecessary safety comment",
+                        cx.tcx.def_descr(item.owner_id.to_def_id()),
+                    ),
+                    |diag| {
+                        diag.span_help(help_span, "consider removing the safety comment");
+                    },
+                );
+            }
+        },
     }
 }
+fn check_has_no_safety_comment(cx: &LateContext<'_>, item: &hir::Item<'_>) {
+    if let ItemKind::Impl(Impl {
+        of_trait: Some(of_trait),
+        ..
+    }) = item.kind
+        && of_trait.safety.is_unsafe()
+        && !is_lint_allowed(cx, UNDOCUMENTED_UNSAFE_BLOCKS, item.hir_id())
+        && !is_unsafe_from_proc_macro(cx, item.span)
+    {
+        let source_map = cx.tcx.sess.source_map();
+        let span = if source_map.is_multiline(item.span) {
+            source_map.span_until_char(item.span, '\n')
+        } else {
+            item.span
+        };
 
+        #[expect(clippy::collapsible_span_lint_calls, reason = "rust-clippy#7797")]
+        span_lint_and_then(
+            cx,
+            UNDOCUMENTED_UNSAFE_BLOCKS,
+            span,
+            "unsafe impl missing a safety comment",
+            |diag| {
+                diag.help("consider adding a safety comment on the preceding line");
+            },
+        );
+    }
+}
 fn expr_has_unnecessary_safety_comment<'tcx>(
     cx: &LateContext<'tcx>,
     expr: &'tcx hir::Expr<'tcx>,
@@ -505,7 +511,8 @@ fn item_has_safety_comment(cx: &LateContext<'_>, item: &hir::Item<'_>) -> HasSaf
         },
         Node::Stmt(stmt) => {
             if let Node::Block(block) = cx.tcx.parent_hir_node(stmt.hir_id) {
-                walk_span_to_context(block.span, SyntaxContext::root()).map(Span::lo)
+                walk_span_to_context(block.span, SyntaxContext::root())
+                    .map(|sp| CommentStartBeforeItem::Offset(sp.lo()))
             } else {
                 // Problem getting the parent node. Pretend a comment was found.
                 return HasSafetyComment::Maybe;
@@ -518,10 +525,12 @@ fn item_has_safety_comment(cx: &LateContext<'_>, item: &hir::Item<'_>) -> HasSaf
     };
 
     let source_map = cx.sess().source_map();
+    // If the comment is in the first line of the file, there is no preceding line
     if let Some(comment_start) = comment_start
         && let Ok(unsafe_line) = source_map.lookup_line(item.span.lo())
-        && let Ok(comment_start_line) = source_map.lookup_line(comment_start)
-        && Arc::ptr_eq(&unsafe_line.sf, &comment_start_line.sf)
+        && let Ok(comment_start_line) = source_map.lookup_line(comment_start.into())
+        && let include_first_line_of_file = matches!(comment_start, CommentStartBeforeItem::Start)
+        && (include_first_line_of_file || Arc::ptr_eq(&unsafe_line.sf, &comment_start_line.sf))
         && let Some(src) = unsafe_line.sf.src.as_deref()
     {
         return if comment_start_line.line >= unsafe_line.line {
@@ -529,7 +538,8 @@ fn item_has_safety_comment(cx: &LateContext<'_>, item: &hir::Item<'_>) -> HasSaf
         } else {
             match text_has_safety_comment(
                 src,
-                &unsafe_line.sf.lines()[comment_start_line.line + 1..=unsafe_line.line],
+                &unsafe_line.sf.lines()
+                    [(comment_start_line.line + usize::from(!include_first_line_of_file))..=unsafe_line.line],
                 unsafe_line.sf.start_pos,
             ) {
                 Some(b) => HasSafetyComment::Yes(b),
@@ -592,12 +602,27 @@ fn stmt_has_safety_comment(
     HasSafetyComment::Maybe
 }
 
+#[derive(Clone, Copy, Debug)]
+enum CommentStartBeforeItem {
+    Offset(BytePos),
+    Start,
+}
+
+impl From<CommentStartBeforeItem> for BytePos {
+    fn from(value: CommentStartBeforeItem) -> Self {
+        match value {
+            CommentStartBeforeItem::Offset(loc) => loc,
+            CommentStartBeforeItem::Start => BytePos(0),
+        }
+    }
+}
+
 fn comment_start_before_item_in_mod(
     cx: &LateContext<'_>,
     parent_mod: &hir::Mod<'_>,
     parent_mod_span: Span,
     item: &hir::Item<'_>,
-) -> Option<BytePos> {
+) -> Option<CommentStartBeforeItem> {
     parent_mod.item_ids.iter().enumerate().find_map(|(idx, item_id)| {
         if *item_id == item.item_id() {
             if idx == 0 {
@@ -605,15 +630,18 @@ fn comment_start_before_item_in_mod(
                 // ^------------------------------------------^ returns the start of this span
                 // ^---------------------^ finally checks comments in this range
                 if let Some(sp) = walk_span_to_context(parent_mod_span, SyntaxContext::root()) {
-                    return Some(sp.lo());
+                    return Some(CommentStartBeforeItem::Offset(sp.lo()));
                 }
             } else {
                 // some_item /* comment */ unsafe impl T {}
                 // ^-------^ returns the end of this span
                 //         ^---------------^ finally checks comments in this range
                 let prev_item = cx.tcx.hir_item(parent_mod.item_ids[idx - 1]);
+                if prev_item.span.is_dummy() {
+                    return Some(CommentStartBeforeItem::Start);
+                }
                 if let Some(sp) = walk_span_to_context(prev_item.span, SyntaxContext::root()) {
-                    return Some(sp.hi());
+                    return Some(CommentStartBeforeItem::Offset(sp.hi()));
                 }
             }
         }
@@ -668,7 +696,7 @@ fn get_body_search_span(cx: &LateContext<'_>) -> Option<Span> {
             }) => {
                 return maybe_mod_item
                     .and_then(|item| comment_start_before_item_in_mod(cx, mod_, *span, &item))
-                    .map(|comment_start| mod_.spans.inner_span.with_lo(comment_start))
+                    .map(|comment_start| mod_.spans.inner_span.with_lo(comment_start.into()))
                     .or(Some(*span));
             },
             node if let Some((span, _)) = span_and_hid_of_item_alike_node(&node)
diff --git a/src/tools/clippy/clippy_lints/src/unnecessary_box_returns.rs b/src/tools/clippy/clippy_lints/src/unnecessary_box_returns.rs
index 2b7d3dc0c90..6e3e41f08ee 100644
--- a/src/tools/clippy/clippy_lints/src/unnecessary_box_returns.rs
+++ b/src/tools/clippy/clippy_lints/src/unnecessary_box_returns.rs
@@ -55,7 +55,7 @@ impl UnnecessaryBoxReturns {
         }
     }
 
-    fn check_fn_item(&mut self, cx: &LateContext<'_>, decl: &FnDecl<'_>, def_id: LocalDefId, name: Symbol) {
+    fn check_fn_item(&self, cx: &LateContext<'_>, decl: &FnDecl<'_>, def_id: LocalDefId, name: Symbol) {
         // we don't want to tell someone to break an exported function if they ask us not to
         if self.avoid_breaking_exported_api && cx.effective_visibilities.is_exported(def_id) {
             return;
diff --git a/src/tools/clippy/clippy_lints/src/unnecessary_semicolon.rs b/src/tools/clippy/clippy_lints/src/unnecessary_semicolon.rs
index f1d1a76d0c2..76e24b6bf80 100644
--- a/src/tools/clippy/clippy_lints/src/unnecessary_semicolon.rs
+++ b/src/tools/clippy/clippy_lints/src/unnecessary_semicolon.rs
@@ -86,7 +86,9 @@ impl<'tcx> LateLintPass<'tcx> for UnnecessarySemicolon {
                 expr.kind,
                 ExprKind::If(..) | ExprKind::Match(_, _, MatchSource::Normal | MatchSource::Postfix)
             )
-            && cx.typeck_results().expr_ty(expr) == cx.tcx.types.unit
+            && cx.typeck_results().expr_ty(expr).is_unit()
+            // if a stmt has attrs, then turning it into an expr will break the code, since attrs aren't allowed on exprs
+            && cx.tcx.hir_attrs(stmt.hir_id).is_empty()
         {
             if let Some(block_is_unit) = self.is_last_in_block(stmt) {
                 if cx.tcx.sess.edition() <= Edition2021 && leaks_droppable_temporary_with_limited_lifetime(cx, expr) {
diff --git a/src/tools/clippy/clippy_lints/src/unnested_or_patterns.rs b/src/tools/clippy/clippy_lints/src/unnested_or_patterns.rs
index e9ad578da2f..8b278d98a30 100644
--- a/src/tools/clippy/clippy_lints/src/unnested_or_patterns.rs
+++ b/src/tools/clippy/clippy_lints/src/unnested_or_patterns.rs
@@ -284,14 +284,14 @@ fn transform_with_focus_on_idx(alternatives: &mut ThinVec<Box<Pat>>, focus_idx:
             |k, ps1, idx| matches!(
                 k,
                 TupleStruct(qself2, path2, ps2)
-                    if eq_maybe_qself(qself1.as_ref(), qself2.as_ref())
+                    if eq_maybe_qself(qself1.as_deref(), qself2.as_deref())
                        && eq_path(path1, path2) && eq_pre_post(ps1, ps2, idx)
             ),
             |k| always_pat!(k, TupleStruct(_, _, ps) => ps),
         ),
         // Transform a record pattern `S { fp_0, ..., fp_n }`.
         Struct(qself1, path1, fps1, rest1) => {
-            extend_with_struct_pat(qself1.as_ref(), path1, fps1, *rest1, start, alternatives)
+            extend_with_struct_pat(qself1.as_deref(), path1, fps1, *rest1, start, alternatives)
         },
     };
 
@@ -304,7 +304,7 @@ fn transform_with_focus_on_idx(alternatives: &mut ThinVec<Box<Pat>>, focus_idx:
 /// So when we fixate on some `ident_k: pat_k`, we try to find `ident_k` in the other pattern
 /// and check that all `fp_i` where `i ∈ ((0...n) \ k)` between two patterns are equal.
 fn extend_with_struct_pat(
-    qself1: Option<&Box<ast::QSelf>>,
+    qself1: Option<&ast::QSelf>,
     path1: &ast::Path,
     fps1: &mut [ast::PatField],
     rest1: ast::PatFieldsRest,
@@ -319,7 +319,7 @@ fn extend_with_struct_pat(
             |k| {
                 matches!(k, Struct(qself2, path2, fps2, rest2)
                 if rest1 == *rest2 // If one struct pattern has `..` so must the other.
-                && eq_maybe_qself(qself1, qself2.as_ref())
+                && eq_maybe_qself(qself1, qself2.as_deref())
                 && eq_path(path1, path2)
                 && fps1.len() == fps2.len()
                 && fps1.iter().enumerate().all(|(idx_1, fp1)| {
diff --git a/src/tools/clippy/clippy_lints/src/unwrap.rs b/src/tools/clippy/clippy_lints/src/unwrap.rs
index c641d4e55b9..490da4f1e03 100644
--- a/src/tools/clippy/clippy_lints/src/unwrap.rs
+++ b/src/tools/clippy/clippy_lints/src/unwrap.rs
@@ -141,43 +141,45 @@ fn collect_unwrap_info<'tcx>(
         is_type_diagnostic_item(cx, ty, sym::Result) && matches!(method_name, sym::is_err | sym::is_ok)
     }
 
-    if let ExprKind::Binary(op, left, right) = &expr.kind {
-        match (invert, op.node) {
-            (false, BinOpKind::And | BinOpKind::BitAnd) | (true, BinOpKind::Or | BinOpKind::BitOr) => {
-                let mut unwrap_info = collect_unwrap_info(cx, if_expr, left, branch, invert, false);
-                unwrap_info.append(&mut collect_unwrap_info(cx, if_expr, right, branch, invert, false));
-                return unwrap_info;
-            },
-            _ => (),
-        }
-    } else if let ExprKind::Unary(UnOp::Not, expr) = &expr.kind {
-        return collect_unwrap_info(cx, if_expr, expr, branch, !invert, false);
-    } else if let ExprKind::MethodCall(method_name, receiver, [], _) = &expr.kind
-        && let Some(local_id) = path_to_local(receiver)
-        && let ty = cx.typeck_results().expr_ty(receiver)
-        && let name = method_name.ident.name
-        && (is_relevant_option_call(cx, ty, name) || is_relevant_result_call(cx, ty, name))
-    {
-        let unwrappable = matches!(name, sym::is_some | sym::is_ok);
-        let safe_to_unwrap = unwrappable != invert;
-        let kind = if is_type_diagnostic_item(cx, ty, sym::Option) {
-            UnwrappableKind::Option
-        } else {
-            UnwrappableKind::Result
-        };
+    match expr.kind {
+        ExprKind::Binary(op, left, right)
+            if matches!(
+                (invert, op.node),
+                (false, BinOpKind::And | BinOpKind::BitAnd) | (true, BinOpKind::Or | BinOpKind::BitOr)
+            ) =>
+        {
+            let mut unwrap_info = collect_unwrap_info(cx, if_expr, left, branch, invert, false);
+            unwrap_info.extend(collect_unwrap_info(cx, if_expr, right, branch, invert, false));
+            unwrap_info
+        },
+        ExprKind::Unary(UnOp::Not, expr) => collect_unwrap_info(cx, if_expr, expr, branch, !invert, false),
+        ExprKind::MethodCall(method_name, receiver, [], _)
+            if let Some(local_id) = path_to_local(receiver)
+                && let ty = cx.typeck_results().expr_ty(receiver)
+                && let name = method_name.ident.name
+                && (is_relevant_option_call(cx, ty, name) || is_relevant_result_call(cx, ty, name)) =>
+        {
+            let unwrappable = matches!(name, sym::is_some | sym::is_ok);
+            let safe_to_unwrap = unwrappable != invert;
+            let kind = if is_type_diagnostic_item(cx, ty, sym::Option) {
+                UnwrappableKind::Option
+            } else {
+                UnwrappableKind::Result
+            };
 
-        return vec![UnwrapInfo {
-            local_id,
-            if_expr,
-            check: expr,
-            check_name: name,
-            branch,
-            safe_to_unwrap,
-            kind,
-            is_entire_condition,
-        }];
+            vec![UnwrapInfo {
+                local_id,
+                if_expr,
+                check: expr,
+                check_name: name,
+                branch,
+                safe_to_unwrap,
+                kind,
+                is_entire_condition,
+            }]
+        },
+        _ => vec![],
     }
-    Vec::new()
 }
 
 /// A HIR visitor delegate that checks if a local variable of type `Option` or `Result` is mutated,
diff --git a/src/tools/clippy/clippy_lints/src/zero_sized_map_values.rs b/src/tools/clippy/clippy_lints/src/zero_sized_map_values.rs
index 1550872bca2..f1572fd65bb 100644
--- a/src/tools/clippy/clippy_lints/src/zero_sized_map_values.rs
+++ b/src/tools/clippy/clippy_lints/src/zero_sized_map_values.rs
@@ -56,6 +56,9 @@ impl LateLintPass<'_> for ZeroSizedMapValues {
             // cannot check if it is `Sized` or not, such as an incomplete associated type in a
             // type alias. See an example in `issue14822()` of `tests/ui/zero_sized_hashmap_values.rs`.
             && !ty.has_non_region_param()
+            // Ensure that no region escapes to avoid an assertion error when computing the layout.
+            // See an example in `issue15429()` of `tests/ui/zero_sized_hashmap_values.rs`.
+            && !ty.has_escaping_bound_vars()
             && let Ok(layout) = cx.layout_of(ty)
             && layout.is_zst()
         {
diff --git a/src/tools/clippy/clippy_lints_internal/src/derive_deserialize_allowing_unknown.rs b/src/tools/clippy/clippy_lints_internal/src/derive_deserialize_allowing_unknown.rs
index 5e6a40ac2eb..0fd1e11b033 100644
--- a/src/tools/clippy/clippy_lints_internal/src/derive_deserialize_allowing_unknown.rs
+++ b/src/tools/clippy/clippy_lints_internal/src/derive_deserialize_allowing_unknown.rs
@@ -6,7 +6,8 @@ use rustc_hir::attrs::AttributeKind;
 use rustc_hir::def::Res;
 use rustc_hir::def_id::LocalDefId;
 use rustc_hir::{
-    AttrArgs, AttrItem, AttrPath, Attribute, HirId, Impl, Item, ItemKind, Path, QPath, TraitRef, Ty, TyKind, find_attr,
+    AttrArgs, AttrItem, AttrPath, Attribute, HirId, Impl, Item, ItemKind, Path, QPath, TraitImplHeader, TraitRef, Ty,
+    TyKind, find_attr,
 };
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_lint_defs::declare_tool_lint;
@@ -56,10 +57,14 @@ impl<'tcx> LateLintPass<'tcx> for DeriveDeserializeAllowingUnknown {
         // Is this an `impl` (of a certain form)?
         let ItemKind::Impl(Impl {
             of_trait:
-                Some(TraitRef {
-                    path:
-                        Path {
-                            res: Res::Def(_, trait_def_id),
+                Some(TraitImplHeader {
+                    trait_ref:
+                        TraitRef {
+                            path:
+                                Path {
+                                    res: Res::Def(_, trait_def_id),
+                                    ..
+                                },
                             ..
                         },
                     ..
diff --git a/src/tools/clippy/clippy_test_deps/Cargo.lock b/src/tools/clippy/clippy_test_deps/Cargo.lock
index 2f987c0137c..b22cf9d107d 100644
--- a/src/tools/clippy/clippy_test_deps/Cargo.lock
+++ b/src/tools/clippy/clippy_test_deps/Cargo.lock
@@ -377,9 +377,9 @@ dependencies = [
 
 [[package]]
 name = "slab"
-version = "0.4.10"
+version = "0.4.11"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "04dc19736151f35336d325007ac991178d504a119863a2fcb3758cdb5e52c50d"
+checksum = "7a2ae44ef20feb57a68b23d846850f861394c2e02dc425a50098ae8c90267589"
 
 [[package]]
 name = "smallvec"
diff --git a/src/tools/clippy/clippy_utils/README.md b/src/tools/clippy/clippy_utils/README.md
index 6d8dd92d55d..2dfe28953d0 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-08-07
+nightly-2025-08-22
 ```
 <!-- end autogenerated nightly -->
 
diff --git a/src/tools/clippy/clippy_utils/src/ast_utils/mod.rs b/src/tools/clippy/clippy_utils/src/ast_utils/mod.rs
index d80a9d9dd07..40c00568a3b 100644
--- a/src/tools/clippy/clippy_utils/src/ast_utils/mod.rs
+++ b/src/tools/clippy/clippy_utils/src/ast_utils/mod.rs
@@ -41,21 +41,23 @@ pub fn eq_pat(l: &Pat, r: &Pat) -> bool {
             b1 == b2 && eq_id(*i1, *i2) && both(s1.as_deref(), s2.as_deref(), eq_pat)
         },
         (Range(lf, lt, le), Range(rf, rt, re)) => {
-            eq_expr_opt(lf.as_ref(), rf.as_ref())
-                && eq_expr_opt(lt.as_ref(), rt.as_ref())
+            eq_expr_opt(lf.as_deref(), rf.as_deref())
+                && eq_expr_opt(lt.as_deref(), rt.as_deref())
                 && eq_range_end(&le.node, &re.node)
         },
         (Box(l), Box(r))
         | (Ref(l, Mutability::Not), Ref(r, Mutability::Not))
         | (Ref(l, Mutability::Mut), Ref(r, Mutability::Mut)) => eq_pat(l, r),
         (Tuple(l), Tuple(r)) | (Slice(l), Slice(r)) => over(l, r, |l, r| eq_pat(l, r)),
-        (Path(lq, lp), Path(rq, rp)) => both(lq.as_ref(), rq.as_ref(), eq_qself) && eq_path(lp, rp),
+        (Path(lq, lp), Path(rq, rp)) => both(lq.as_deref(), rq.as_deref(), eq_qself) && eq_path(lp, rp),
         (TupleStruct(lqself, lp, lfs), TupleStruct(rqself, rp, rfs)) => {
-            eq_maybe_qself(lqself.as_ref(), rqself.as_ref()) && eq_path(lp, rp) && over(lfs, rfs, |l, r| eq_pat(l, r))
+            eq_maybe_qself(lqself.as_deref(), rqself.as_deref())
+                && eq_path(lp, rp)
+                && over(lfs, rfs, |l, r| eq_pat(l, r))
         },
         (Struct(lqself, lp, lfs, lr), Struct(rqself, rp, rfs, rr)) => {
             lr == rr
-                && eq_maybe_qself(lqself.as_ref(), rqself.as_ref())
+                && eq_maybe_qself(lqself.as_deref(), rqself.as_deref())
                 && eq_path(lp, rp)
                 && unordered_over(lfs, rfs, eq_field_pat)
         },
@@ -82,11 +84,11 @@ pub fn eq_field_pat(l: &PatField, r: &PatField) -> bool {
         && over(&l.attrs, &r.attrs, eq_attr)
 }
 
-pub fn eq_qself(l: &Box<QSelf>, r: &Box<QSelf>) -> bool {
+pub fn eq_qself(l: &QSelf, r: &QSelf) -> bool {
     l.position == r.position && eq_ty(&l.ty, &r.ty)
 }
 
-pub fn eq_maybe_qself(l: Option<&Box<QSelf>>, r: Option<&Box<QSelf>>) -> bool {
+pub fn eq_maybe_qself(l: Option<&QSelf>, r: Option<&QSelf>) -> bool {
     match (l, r) {
         (Some(l), Some(r)) => eq_qself(l, r),
         (None, None) => true,
@@ -129,8 +131,8 @@ pub fn eq_generic_arg(l: &GenericArg, r: &GenericArg) -> bool {
     }
 }
 
-pub fn eq_expr_opt(l: Option<&Box<Expr>>, r: Option<&Box<Expr>>) -> bool {
-    both(l, r, |l, r| eq_expr(l, r))
+pub fn eq_expr_opt(l: Option<&Expr>, r: Option<&Expr>) -> bool {
+    both(l, r, eq_expr)
 }
 
 pub fn eq_struct_rest(l: &StructRest, r: &StructRest) -> bool {
@@ -177,7 +179,7 @@ pub fn eq_expr(l: &Expr, r: &Expr) -> bool {
         (Cast(l, lt), Cast(r, rt)) | (Type(l, lt), Type(r, rt)) => eq_expr(l, r) && eq_ty(lt, rt),
         (Let(lp, le, _, _), Let(rp, re, _, _)) => eq_pat(lp, rp) && eq_expr(le, re),
         (If(lc, lt, le), If(rc, rt, re)) => {
-            eq_expr(lc, rc) && eq_block(lt, rt) && eq_expr_opt(le.as_ref(), re.as_ref())
+            eq_expr(lc, rc) && eq_block(lt, rt) && eq_expr_opt(le.as_deref(), re.as_deref())
         },
         (While(lc, lt, ll), While(rc, rt, rl)) => {
             eq_label(ll.as_ref(), rl.as_ref()) && eq_expr(lc, rc) && eq_block(lt, rt)
@@ -201,9 +203,11 @@ pub fn eq_expr(l: &Expr, r: &Expr) -> bool {
         (Loop(lt, ll, _), Loop(rt, rl, _)) => eq_label(ll.as_ref(), rl.as_ref()) && eq_block(lt, rt),
         (Block(lb, ll), Block(rb, rl)) => eq_label(ll.as_ref(), rl.as_ref()) && eq_block(lb, rb),
         (TryBlock(l), TryBlock(r)) => eq_block(l, r),
-        (Yield(l), Yield(r)) => eq_expr_opt(l.expr(), r.expr()) && l.same_kind(r),
-        (Ret(l), Ret(r)) => eq_expr_opt(l.as_ref(), r.as_ref()),
-        (Break(ll, le), Break(rl, re)) => eq_label(ll.as_ref(), rl.as_ref()) && eq_expr_opt(le.as_ref(), re.as_ref()),
+        (Yield(l), Yield(r)) => eq_expr_opt(l.expr().map(Box::as_ref), r.expr().map(Box::as_ref)) && l.same_kind(r),
+        (Ret(l), Ret(r)) => eq_expr_opt(l.as_deref(), r.as_deref()),
+        (Break(ll, le), Break(rl, re)) => {
+            eq_label(ll.as_ref(), rl.as_ref()) && eq_expr_opt(le.as_deref(), re.as_deref())
+        },
         (Continue(ll), Continue(rl)) => eq_label(ll.as_ref(), rl.as_ref()),
         (Assign(l1, l2, _), Assign(r1, r2, _)) | (Index(l1, l2, _), Index(r1, r2, _)) => {
             eq_expr(l1, r1) && eq_expr(l2, r2)
@@ -240,13 +244,13 @@ pub fn eq_expr(l: &Expr, r: &Expr) -> bool {
         },
         (Gen(lc, lb, lk, _), Gen(rc, rb, rk, _)) => lc == rc && eq_block(lb, rb) && lk == rk,
         (Range(lf, lt, ll), Range(rf, rt, rl)) => {
-            ll == rl && eq_expr_opt(lf.as_ref(), rf.as_ref()) && eq_expr_opt(lt.as_ref(), rt.as_ref())
+            ll == rl && eq_expr_opt(lf.as_deref(), rf.as_deref()) && eq_expr_opt(lt.as_deref(), rt.as_deref())
         },
         (AddrOf(lbk, lm, le), AddrOf(rbk, rm, re)) => lbk == rbk && lm == rm && eq_expr(le, re),
-        (Path(lq, lp), Path(rq, rp)) => both(lq.as_ref(), rq.as_ref(), eq_qself) && eq_path(lp, rp),
+        (Path(lq, lp), Path(rq, rp)) => both(lq.as_deref(), rq.as_deref(), eq_qself) && eq_path(lp, rp),
         (MacCall(l), MacCall(r)) => eq_mac_call(l, r),
         (Struct(lse), Struct(rse)) => {
-            eq_maybe_qself(lse.qself.as_ref(), rse.qself.as_ref())
+            eq_maybe_qself(lse.qself.as_deref(), rse.qself.as_deref())
                 && eq_path(&lse.path, &rse.path)
                 && eq_struct_rest(&lse.rest, &rse.rest)
                 && unordered_over(&lse.fields, &rse.fields, eq_field)
@@ -278,8 +282,8 @@ pub fn eq_field(l: &ExprField, r: &ExprField) -> bool {
 pub fn eq_arm(l: &Arm, r: &Arm) -> bool {
     l.is_placeholder == r.is_placeholder
         && eq_pat(&l.pat, &r.pat)
-        && eq_expr_opt(l.body.as_ref(), r.body.as_ref())
-        && eq_expr_opt(l.guard.as_ref(), r.guard.as_ref())
+        && eq_expr_opt(l.body.as_deref(), r.body.as_deref())
+        && eq_expr_opt(l.guard.as_deref(), r.guard.as_deref())
         && over(&l.attrs, &r.attrs, eq_attr)
 }
 
@@ -324,7 +328,7 @@ pub fn eq_item<K>(l: &Item<K>, r: &Item<K>, mut eq_kind: impl FnMut(&K, &K) -> b
     over(&l.attrs, &r.attrs, eq_attr) && eq_vis(&l.vis, &r.vis) && eq_kind(&l.kind, &r.kind)
 }
 
-#[expect(clippy::similar_names, clippy::too_many_lines)] // Just a big match statement
+#[expect(clippy::too_many_lines)] // Just a big match statement
 pub fn eq_item_kind(l: &ItemKind, r: &ItemKind) -> bool {
     use ItemKind::*;
     match (l, r) {
@@ -347,7 +351,7 @@ pub fn eq_item_kind(l: &ItemKind, r: &ItemKind) -> bool {
                 safety: rs,
                 define_opaque: _,
             }),
-        ) => eq_id(*li, *ri) && lm == rm && ls == rs && eq_ty(lt, rt) && eq_expr_opt(le.as_ref(), re.as_ref()),
+        ) => eq_id(*li, *ri) && lm == rm && ls == rs && eq_ty(lt, rt) && eq_expr_opt(le.as_deref(), re.as_deref()),
         (
             Const(box ConstItem {
                 defaultness: ld,
@@ -370,7 +374,7 @@ pub fn eq_item_kind(l: &ItemKind, r: &ItemKind) -> bool {
                 && eq_id(*li, *ri)
                 && eq_generics(lg, rg)
                 && eq_ty(lt, rt)
-                && eq_expr_opt(le.as_ref(), re.as_ref())
+                && eq_expr_opt(le.as_deref(), re.as_deref())
         },
         (
             Fn(box ast::Fn {
@@ -525,7 +529,7 @@ pub fn eq_foreign_item_kind(l: &ForeignItemKind, r: &ForeignItemKind) -> bool {
                 safety: rs,
                 define_opaque: _,
             }),
-        ) => eq_id(*li, *ri) && eq_ty(lt, rt) && lm == rm && eq_expr_opt(le.as_ref(), re.as_ref()) && ls == rs,
+        ) => eq_id(*li, *ri) && eq_ty(lt, rt) && lm == rm && eq_expr_opt(le.as_deref(), re.as_deref()) && ls == rs,
         (
             Fn(box ast::Fn {
                 defaultness: ld,
@@ -607,7 +611,7 @@ pub fn eq_assoc_item_kind(l: &AssocItemKind, r: &AssocItemKind) -> bool {
                 && eq_id(*li, *ri)
                 && eq_generics(lg, rg)
                 && eq_ty(lt, rt)
-                && eq_expr_opt(le.as_ref(), re.as_ref())
+                && eq_expr_opt(le.as_deref(), re.as_deref())
         },
         (
             Fn(box ast::Fn {
@@ -723,7 +727,8 @@ pub fn eq_fn_header(l: &FnHeader, r: &FnHeader) -> bool {
 pub fn eq_opt_fn_contract(l: &Option<Box<FnContract>>, r: &Option<Box<FnContract>>) -> bool {
     match (l, r) {
         (Some(l), Some(r)) => {
-            eq_expr_opt(l.requires.as_ref(), r.requires.as_ref()) && eq_expr_opt(l.ensures.as_ref(), r.ensures.as_ref())
+            eq_expr_opt(l.requires.as_deref(), r.requires.as_deref())
+                && eq_expr_opt(l.ensures.as_deref(), r.ensures.as_deref())
         },
         (None, None) => true,
         (Some(_), None) | (None, Some(_)) => false,
@@ -841,7 +846,7 @@ pub fn eq_ty(l: &Ty, r: &Ty) -> bool {
                 && eq_fn_decl(&l.decl, &r.decl)
         },
         (Tup(l), Tup(r)) => over(l, r, |l, r| eq_ty(l, r)),
-        (Path(lq, lp), Path(rq, rp)) => both(lq.as_ref(), rq.as_ref(), eq_qself) && eq_path(lp, rp),
+        (Path(lq, lp), Path(rq, rp)) => both(lq.as_deref(), rq.as_deref(), eq_qself) && eq_path(lp, rp),
         (TraitObject(lg, ls), TraitObject(rg, rs)) => ls == rs && over(lg, rg, eq_generic_bound),
         (ImplTrait(_, lg), ImplTrait(_, rg)) => over(lg, rg, eq_generic_bound),
         (Typeof(l), Typeof(r)) => eq_expr(&l.value, &r.value),
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 e0c1b9d445a..c4a759e919b 100644
--- a/src/tools/clippy/clippy_utils/src/check_proc_macro.rs
+++ b/src/tools/clippy/clippy_utils/src/check_proc_macro.rs
@@ -19,8 +19,8 @@ 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, ImplItemKind, TraitImplHeader, IsAuto, Item, ItemKind, Lit, LoopSource, MatchSource, MutTy, Node, Path,
-    QPath, Safety, TraitItem, TraitItemKind, Ty, TyKind, UnOp, UnsafeSource, Variant, VariantData, YieldSource,
+    ImplItem, 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;
@@ -254,7 +254,10 @@ fn item_search_pat(item: &Item<'_>) -> (Pat, Pat) {
         ItemKind::Union(..) => (Pat::Str("union"), Pat::Str("}")),
         ItemKind::Trait(_, _, Safety::Unsafe, ..)
         | ItemKind::Impl(Impl {
-            of_trait: Some(TraitImplHeader { safety: Safety::Unsafe, .. }), ..
+            of_trait: Some(TraitImplHeader {
+                safety: Safety::Unsafe, ..
+            }),
+            ..
         }) => (Pat::Str("unsafe"), Pat::Str("}")),
         ItemKind::Trait(_, IsAuto::Yes, ..) => (Pat::Str("auto"), Pat::Str("}")),
         ItemKind::Trait(..) => (Pat::Str("trait"), Pat::Str("}")),
diff --git a/src/tools/clippy/clippy_utils/src/diagnostics.rs b/src/tools/clippy/clippy_utils/src/diagnostics.rs
index 625e1eead21..8a19039a7fe 100644
--- a/src/tools/clippy/clippy_utils/src/diagnostics.rs
+++ b/src/tools/clippy/clippy_utils/src/diagnostics.rs
@@ -22,13 +22,14 @@ fn docs_link(diag: &mut Diag<'_, ()>, lint: &'static Lint) {
     {
         diag.help(format!(
             "for further information visit https://rust-lang.github.io/rust-clippy/{}/index.html#{lint}",
-            &option_env!("RUST_RELEASE_NUM").map_or_else(
-                || "master".to_string(),
-                |n| {
-                    // extract just major + minor version and ignore patch versions
-                    format!("rust-{}", n.rsplit_once('.').unwrap().1)
-                }
-            )
+            match option_env!("CFG_RELEASE_CHANNEL") {
+                // Clippy version is 0.1.xx
+                //
+                // Always use .0 because we do not generate separate lint doc pages for rust patch releases
+                Some("stable") => concat!("rust-1.", env!("CARGO_PKG_VERSION_PATCH"), ".0"),
+                Some("beta") => "beta",
+                _ => "master",
+            }
         ));
     }
 }
diff --git a/src/tools/clippy/clippy_utils/src/hir_utils.rs b/src/tools/clippy/clippy_utils/src/hir_utils.rs
index f0d7fb89c44..8160443f413 100644
--- a/src/tools/clippy/clippy_utils/src/hir_utils.rs
+++ b/src/tools/clippy/clippy_utils/src/hir_utils.rs
@@ -258,7 +258,7 @@ impl HirEqInterExpr<'_, '_, '_> {
         })
     }
 
-    fn should_ignore(&mut self, expr: &Expr<'_>) -> bool {
+    fn should_ignore(&self, expr: &Expr<'_>) -> bool {
         macro_backtrace(expr.span).last().is_some_and(|macro_call| {
             matches!(
                 self.inner.cx.tcx.get_diagnostic_name(macro_call.def_id),
diff --git a/src/tools/clippy/clippy_utils/src/lib.rs b/src/tools/clippy/clippy_utils/src/lib.rs
index fcc120656e3..8533fa85541 100644
--- a/src/tools/clippy/clippy_utils/src/lib.rs
+++ b/src/tools/clippy/clippy_utils/src/lib.rs
@@ -460,6 +460,23 @@ pub fn path_to_local_id(expr: &Expr<'_>, id: HirId) -> bool {
     path_to_local(expr) == Some(id)
 }
 
+/// If the expression is a path to a local (with optional projections),
+/// returns the canonical `HirId` of the local.
+///
+/// For example, `x.field[0].field2` would return the `HirId` of `x`.
+pub fn path_to_local_with_projections(expr: &Expr<'_>) -> Option<HirId> {
+    match expr.kind {
+        ExprKind::Field(recv, _) | ExprKind::Index(recv, _, _) => path_to_local_with_projections(recv),
+        ExprKind::Path(QPath::Resolved(
+            _,
+            Path {
+                res: Res::Local(local), ..
+            },
+        )) => Some(*local),
+        _ => None,
+    }
+}
+
 pub trait MaybePath<'hir> {
     fn hir_id(&self) -> HirId;
     fn qpath_opt(&self) -> Option<&QPath<'hir>>;
diff --git a/src/tools/clippy/clippy_utils/src/msrvs.rs b/src/tools/clippy/clippy_utils/src/msrvs.rs
index 89a83e2c48f..896d607fbcd 100644
--- a/src/tools/clippy/clippy_utils/src/msrvs.rs
+++ b/src/tools/clippy/clippy_utils/src/msrvs.rs
@@ -189,25 +189,25 @@ impl MsrvStack {
 fn parse_attrs(sess: &Session, attrs: &[impl AttributeExt]) -> Option<RustcVersion> {
     let mut msrv_attrs = attrs.iter().filter(|attr| attr.path_matches(&[sym::clippy, sym::msrv]));
 
-    if let Some(msrv_attr) = msrv_attrs.next() {
-        if let Some(duplicate) = msrv_attrs.next_back() {
-            sess.dcx()
-                .struct_span_err(duplicate.span(), "`clippy::msrv` is defined multiple times")
-                .with_span_note(msrv_attr.span(), "first definition found here")
-                .emit();
-        }
-
-        if let Some(msrv) = msrv_attr.value_str() {
-            if let Some(version) = parse_version(msrv) {
-                return Some(version);
-            }
+    let msrv_attr = msrv_attrs.next()?;
 
-            sess.dcx()
-                .span_err(msrv_attr.span(), format!("`{msrv}` is not a valid Rust version"));
-        } else {
-            sess.dcx().span_err(msrv_attr.span(), "bad clippy attribute");
-        }
+    if let Some(duplicate) = msrv_attrs.next_back() {
+        sess.dcx()
+            .struct_span_err(duplicate.span(), "`clippy::msrv` is defined multiple times")
+            .with_span_note(msrv_attr.span(), "first definition found here")
+            .emit();
     }
 
-    None
+    let Some(msrv) = msrv_attr.value_str() else {
+        sess.dcx().span_err(msrv_attr.span(), "bad clippy attribute");
+        return None;
+    };
+
+    let Some(version) = parse_version(msrv) else {
+        sess.dcx()
+            .span_err(msrv_attr.span(), format!("`{msrv}` is not a valid Rust version"));
+        return None;
+    };
+
+    Some(version)
 }
diff --git a/src/tools/clippy/clippy_utils/src/ty/mod.rs b/src/tools/clippy/clippy_utils/src/ty/mod.rs
index d79773f8321..fafc1d07e51 100644
--- a/src/tools/clippy/clippy_utils/src/ty/mod.rs
+++ b/src/tools/clippy/clippy_utils/src/ty/mod.rs
@@ -18,6 +18,7 @@ use rustc_lint::LateContext;
 use rustc_middle::mir::ConstValue;
 use rustc_middle::mir::interpret::Scalar;
 use rustc_middle::traits::EvaluationResult;
+use rustc_middle::ty::adjustment::{Adjust, Adjustment};
 use rustc_middle::ty::layout::ValidityRequirement;
 use rustc_middle::ty::{
     self, AdtDef, AliasTy, AssocItem, AssocTag, Binder, BoundRegion, FnSig, GenericArg, GenericArgKind, GenericArgsRef,
@@ -31,7 +32,7 @@ use rustc_trait_selection::traits::query::normalize::QueryNormalizeExt;
 use rustc_trait_selection::traits::{Obligation, ObligationCause};
 use std::assert_matches::debug_assert_matches;
 use std::collections::hash_map::Entry;
-use std::iter;
+use std::{iter, mem};
 
 use crate::path_res;
 use crate::paths::{PathNS, lookup_path_str};
@@ -1382,7 +1383,6 @@ pub fn is_slice_like<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool {
         || matches!(ty.kind(), ty::Adt(adt_def, _) if cx.tcx.is_diagnostic_item(sym::Vec, adt_def.did()))
 }
 
-/// Gets the index of a field by name.
 pub fn get_field_idx_by_name(ty: Ty<'_>, name: Symbol) -> Option<usize> {
     match *ty.kind() {
         ty::Adt(def, _) if def.is_union() || def.is_struct() => {
@@ -1392,3 +1392,11 @@ pub fn get_field_idx_by_name(ty: Ty<'_>, name: Symbol) -> Option<usize> {
         _ => None,
     }
 }
+
+/// Checks if the adjustments contain a mutable dereference of a `ManuallyDrop<_>`.
+pub fn adjust_derefs_manually_drop<'tcx>(adjustments: &'tcx [Adjustment<'tcx>], mut ty: Ty<'tcx>) -> bool {
+    adjustments.iter().any(|a| {
+        let ty = mem::replace(&mut ty, a.target);
+        matches!(a.kind, Adjust::Deref(Some(op)) if op.mutbl == Mutability::Mut) && is_manually_drop(ty)
+    })
+}
diff --git a/src/tools/clippy/rust-toolchain.toml b/src/tools/clippy/rust-toolchain.toml
index ac51ec2d61b..5497e77e8ad 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-08-07"
+channel = "nightly-2025-08-22"
 # end autogenerated nightly
 components = ["cargo", "llvm-tools", "rust-src", "rust-std", "rustc", "rustc-dev", "rustfmt"]
 profile = "minimal"
diff --git a/src/tools/clippy/tests/ui-cargo/undocumented_unsafe_blocks/fail/Cargo.stderr b/src/tools/clippy/tests/ui-cargo/undocumented_unsafe_blocks/fail/Cargo.stderr
new file mode 100644
index 00000000000..59a7146ac90
--- /dev/null
+++ b/src/tools/clippy/tests/ui-cargo/undocumented_unsafe_blocks/fail/Cargo.stderr
@@ -0,0 +1,26 @@
+error: module has unnecessary safety comment
+ --> src/main.rs:2:1
+  |
+2 | mod x {}
+  | ^^^^^^^^
+  |
+help: consider removing the safety comment
+ --> src/main.rs:1:1
+  |
+1 | // SAFETY: ...
+  | ^^^^^^^^^^^^^^
+  = note: requested on the command line with `-D clippy::unnecessary-safety-comment`
+
+error: module has unnecessary safety comment
+ --> src/main.rs:5:1
+  |
+5 | mod y {}
+  | ^^^^^^^^
+  |
+help: consider removing the safety comment
+ --> src/main.rs:4:1
+  |
+4 | // SAFETY: ...
+  | ^^^^^^^^^^^^^^
+
+error: could not compile `undocumented_unsafe_blocks` (bin "undocumented_unsafe_blocks") due to 2 previous errors
diff --git a/src/tools/clippy/tests/ui-cargo/undocumented_unsafe_blocks/fail/Cargo.toml b/src/tools/clippy/tests/ui-cargo/undocumented_unsafe_blocks/fail/Cargo.toml
new file mode 100644
index 00000000000..36bb3472df0
--- /dev/null
+++ b/src/tools/clippy/tests/ui-cargo/undocumented_unsafe_blocks/fail/Cargo.toml
@@ -0,0 +1,12 @@
+# Reproducing #14553 requires the `# Safety` comment to be in the first line of 
+# the file. Since `unnecessary_safety_comment` is not enabled by default, we
+# will set it up here.
+
+[package]
+name = "undocumented_unsafe_blocks"
+edition = "2024"
+publish = false
+version = "0.1.0"
+
+[lints.clippy]
+unnecessary_safety_comment = "deny"
diff --git a/src/tools/clippy/tests/ui-cargo/undocumented_unsafe_blocks/fail/src/main.rs b/src/tools/clippy/tests/ui-cargo/undocumented_unsafe_blocks/fail/src/main.rs
new file mode 100644
index 00000000000..5cafcff99dd
--- /dev/null
+++ b/src/tools/clippy/tests/ui-cargo/undocumented_unsafe_blocks/fail/src/main.rs
@@ -0,0 +1,7 @@
+// SAFETY: ...
+mod x {}
+
+// SAFETY: ...
+mod y {}
+
+fn main() {}
diff --git a/src/tools/clippy/tests/ui-toml/functions_maxlines/test.stderr b/src/tools/clippy/tests/ui-toml/functions_maxlines/test.stderr
index 14a49cb76c1..e856963c87d 100644
--- a/src/tools/clippy/tests/ui-toml/functions_maxlines/test.stderr
+++ b/src/tools/clippy/tests/ui-toml/functions_maxlines/test.stderr
@@ -1,12 +1,8 @@
 error: this function has too many lines (2/1)
   --> tests/ui-toml/functions_maxlines/test.rs:19:1
    |
-LL | / fn too_many_lines() {
-LL | |
-LL | |     println!("This is bad.");
-LL | |     println!("This is bad.");
-LL | | }
-   | |_^
+LL | fn too_many_lines() {
+   | ^^^^^^^^^^^^^^^^^^^
    |
    = note: `-D clippy::too-many-lines` implied by `-D warnings`
    = help: to override `-D warnings` add `#[allow(clippy::too_many_lines)]`
@@ -14,35 +10,20 @@ LL | | }
 error: this function has too many lines (4/1)
   --> tests/ui-toml/functions_maxlines/test.rs:26:1
    |
-LL | / async fn async_too_many_lines() {
-LL | |
-LL | |     println!("This is bad.");
-LL | |     println!("This is bad.");
-LL | | }
-   | |_^
+LL | async fn async_too_many_lines() {
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: this function has too many lines (4/1)
   --> tests/ui-toml/functions_maxlines/test.rs:33:1
    |
-LL | / fn closure_too_many_lines() {
-LL | |
-LL | |     let _ = {
-LL | |         println!("This is bad.");
-LL | |         println!("This is bad.");
-LL | |     };
-LL | | }
-   | |_^
+LL | fn closure_too_many_lines() {
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: this function has too many lines (2/1)
   --> tests/ui-toml/functions_maxlines/test.rs:56:1
    |
-LL | / fn comment_before_code() {
-LL | |
-LL | |     let _ = "test";
-LL | |     /* This comment extends to the front of
-LL | |     the code but this line should still count. */ let _ = 5;
-LL | | }
-   | |_^
+LL | fn comment_before_code() {
+   | ^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: aborting due to 4 previous errors
 
diff --git a/src/tools/clippy/tests/ui/as_ptr_cast_mut.fixed b/src/tools/clippy/tests/ui/as_ptr_cast_mut.fixed
new file mode 100644
index 00000000000..fe9c5dca5ba
--- /dev/null
+++ b/src/tools/clippy/tests/ui/as_ptr_cast_mut.fixed
@@ -0,0 +1,38 @@
+#![allow(unused)]
+#![warn(clippy::as_ptr_cast_mut)]
+#![allow(clippy::wrong_self_convention, clippy::unnecessary_cast)]
+
+struct MutPtrWrapper(Vec<u8>);
+impl MutPtrWrapper {
+    fn as_ptr(&mut self) -> *const u8 {
+        self.0.as_mut_ptr() as *const u8
+    }
+}
+
+struct Covariant<T>(*const T);
+impl<T> Covariant<T> {
+    fn as_ptr(self) -> *const T {
+        self.0
+    }
+}
+
+fn main() {
+    let mut string = String::new();
+    let _ = string.as_mut_ptr();
+    //~^ as_ptr_cast_mut
+
+    let _ = string.as_ptr() as *const i8;
+    let _ = string.as_mut_ptr();
+    let _ = string.as_mut_ptr() as *mut u8;
+    let _ = string.as_mut_ptr() as *const u8;
+
+    let nn = std::ptr::NonNull::new(4 as *mut u8).unwrap();
+    let _ = nn.as_ptr() as *mut u8;
+
+    let mut wrap = MutPtrWrapper(Vec::new());
+    let _ = wrap.as_ptr() as *mut u8;
+
+    let mut local = 4;
+    let ref_with_write_perm = Covariant(std::ptr::addr_of_mut!(local) as *const _);
+    let _ = ref_with_write_perm.as_ptr() as *mut u8;
+}
diff --git a/src/tools/clippy/tests/ui/as_ptr_cast_mut.rs b/src/tools/clippy/tests/ui/as_ptr_cast_mut.rs
index baf7279adc4..3f22c2058d0 100644
--- a/src/tools/clippy/tests/ui/as_ptr_cast_mut.rs
+++ b/src/tools/clippy/tests/ui/as_ptr_cast_mut.rs
@@ -1,7 +1,6 @@
 #![allow(unused)]
 #![warn(clippy::as_ptr_cast_mut)]
 #![allow(clippy::wrong_self_convention, clippy::unnecessary_cast)]
-//@no-rustfix: incorrect suggestion
 
 struct MutPtrWrapper(Vec<u8>);
 impl MutPtrWrapper {
@@ -22,9 +21,6 @@ fn main() {
     let _ = string.as_ptr() as *mut u8;
     //~^ as_ptr_cast_mut
 
-    let _: *mut i8 = string.as_ptr() as *mut _;
-    //~^ as_ptr_cast_mut
-
     let _ = string.as_ptr() as *const i8;
     let _ = string.as_mut_ptr();
     let _ = string.as_mut_ptr() as *mut u8;
diff --git a/src/tools/clippy/tests/ui/as_ptr_cast_mut.stderr b/src/tools/clippy/tests/ui/as_ptr_cast_mut.stderr
index b3fc223ccdb..fa9fb23e2d0 100644
--- a/src/tools/clippy/tests/ui/as_ptr_cast_mut.stderr
+++ b/src/tools/clippy/tests/ui/as_ptr_cast_mut.stderr
@@ -1,5 +1,5 @@
 error: casting the result of `as_ptr` to *mut u8
-  --> tests/ui/as_ptr_cast_mut.rs:22:13
+  --> tests/ui/as_ptr_cast_mut.rs:21:13
    |
 LL |     let _ = string.as_ptr() as *mut u8;
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `string.as_mut_ptr()`
@@ -7,11 +7,5 @@ LL |     let _ = string.as_ptr() as *mut u8;
    = note: `-D clippy::as-ptr-cast-mut` implied by `-D warnings`
    = help: to override `-D warnings` add `#[allow(clippy::as_ptr_cast_mut)]`
 
-error: casting the result of `as_ptr` to *mut i8
-  --> tests/ui/as_ptr_cast_mut.rs:25:22
-   |
-LL |     let _: *mut i8 = string.as_ptr() as *mut _;
-   |                      ^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `string.as_mut_ptr()`
-
-error: aborting due to 2 previous errors
+error: aborting due to 1 previous error
 
diff --git a/src/tools/clippy/tests/ui/as_ptr_cast_mut_unfixable.rs b/src/tools/clippy/tests/ui/as_ptr_cast_mut_unfixable.rs
new file mode 100644
index 00000000000..a8f6b06bd4f
--- /dev/null
+++ b/src/tools/clippy/tests/ui/as_ptr_cast_mut_unfixable.rs
@@ -0,0 +1,16 @@
+//@no-rustfix
+#![allow(unused)]
+#![warn(clippy::as_ptr_cast_mut)]
+
+fn main() {
+    let mut string = String::new();
+
+    // the `*mut _` is actually necessary since it does two things at once:
+    // - changes the mutability (caught by the lint)
+    // - changes the type
+    //
+    // and so replacing this with `as_mut_ptr` removes the second thing,
+    // resulting in a type mismatch
+    let _: *mut i8 = string.as_ptr() as *mut _;
+    //~^ as_ptr_cast_mut
+}
diff --git a/src/tools/clippy/tests/ui/as_ptr_cast_mut_unfixable.stderr b/src/tools/clippy/tests/ui/as_ptr_cast_mut_unfixable.stderr
new file mode 100644
index 00000000000..c5bcad6f4df
--- /dev/null
+++ b/src/tools/clippy/tests/ui/as_ptr_cast_mut_unfixable.stderr
@@ -0,0 +1,11 @@
+error: casting the result of `as_ptr` to *mut i8
+  --> tests/ui/as_ptr_cast_mut_unfixable.rs:14:22
+   |
+LL |     let _: *mut i8 = string.as_ptr() as *mut _;
+   |                      ^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `string.as_mut_ptr()`
+   |
+   = note: `-D clippy::as-ptr-cast-mut` implied by `-D warnings`
+   = help: to override `-D warnings` add `#[allow(clippy::as_ptr_cast_mut)]`
+
+error: aborting due to 1 previous error
+
diff --git a/src/tools/clippy/tests/ui/borrow_as_ptr.fixed b/src/tools/clippy/tests/ui/borrow_as_ptr.fixed
index 3f6e5245b87..bfe826508f3 100644
--- a/src/tools/clippy/tests/ui/borrow_as_ptr.fixed
+++ b/src/tools/clippy/tests/ui/borrow_as_ptr.fixed
@@ -1,6 +1,9 @@
+//@aux-build:proc_macros.rs
 #![warn(clippy::borrow_as_ptr)]
 #![allow(clippy::useless_vec)]
 
+extern crate proc_macros;
+
 fn a() -> i32 {
     0
 }
@@ -53,3 +56,12 @@ fn issue_15141() {
     // Don't lint cast to dyn trait pointers
     let b = &a as *const dyn std::any::Any;
 }
+
+fn issue15389() {
+    proc_macros::with_span! {
+        span
+        let var = 0u32;
+        // Don't lint in proc-macros
+        let _ = &var as *const u32;
+    };
+}
diff --git a/src/tools/clippy/tests/ui/borrow_as_ptr.rs b/src/tools/clippy/tests/ui/borrow_as_ptr.rs
index 20f4f40e001..ce248f157c6 100644
--- a/src/tools/clippy/tests/ui/borrow_as_ptr.rs
+++ b/src/tools/clippy/tests/ui/borrow_as_ptr.rs
@@ -1,6 +1,9 @@
+//@aux-build:proc_macros.rs
 #![warn(clippy::borrow_as_ptr)]
 #![allow(clippy::useless_vec)]
 
+extern crate proc_macros;
+
 fn a() -> i32 {
     0
 }
@@ -53,3 +56,12 @@ fn issue_15141() {
     // Don't lint cast to dyn trait pointers
     let b = &a as *const dyn std::any::Any;
 }
+
+fn issue15389() {
+    proc_macros::with_span! {
+        span
+        let var = 0u32;
+        // Don't lint in proc-macros
+        let _ = &var as *const u32;
+    };
+}
diff --git a/src/tools/clippy/tests/ui/borrow_as_ptr.stderr b/src/tools/clippy/tests/ui/borrow_as_ptr.stderr
index b1fcce49403..b371b477a50 100644
--- a/src/tools/clippy/tests/ui/borrow_as_ptr.stderr
+++ b/src/tools/clippy/tests/ui/borrow_as_ptr.stderr
@@ -1,5 +1,5 @@
 error: borrow as raw pointer
-  --> tests/ui/borrow_as_ptr.rs:11:14
+  --> tests/ui/borrow_as_ptr.rs:14:14
    |
 LL |     let _p = &val as *const i32;
    |              ^^^^^^^^^^^^^^^^^^ help: try: `std::ptr::addr_of!(val)`
@@ -8,25 +8,25 @@ LL |     let _p = &val as *const i32;
    = help: to override `-D warnings` add `#[allow(clippy::borrow_as_ptr)]`
 
 error: borrow as raw pointer
-  --> tests/ui/borrow_as_ptr.rs:19:18
+  --> tests/ui/borrow_as_ptr.rs:22:18
    |
 LL |     let _p_mut = &mut val_mut as *mut i32;
    |                  ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `std::ptr::addr_of_mut!(val_mut)`
 
 error: borrow as raw pointer
-  --> tests/ui/borrow_as_ptr.rs:23:16
+  --> tests/ui/borrow_as_ptr.rs:26:16
    |
 LL |     let _raw = (&mut x[1] as *mut i32).wrapping_offset(-1);
    |                ^^^^^^^^^^^^^^^^^^^^^^^ help: try: `std::ptr::addr_of_mut!(x[1])`
 
 error: borrow as raw pointer
-  --> tests/ui/borrow_as_ptr.rs:29:17
+  --> tests/ui/borrow_as_ptr.rs:32:17
    |
 LL |     let _raw = (&mut x[1] as *mut i32).wrapping_offset(-1);
    |                 ^^^^^^^^^^^^^^^^^^^^^ help: try: `&raw mut x[1]`
 
 error: implicit borrow as raw pointer
-  --> tests/ui/borrow_as_ptr.rs:35:25
+  --> tests/ui/borrow_as_ptr.rs:38:25
    |
 LL |     let p: *const i32 = &val;
    |                         ^^^^
@@ -37,7 +37,7 @@ LL |     let p: *const i32 = &raw const val;
    |                          +++++++++
 
 error: implicit borrow as raw pointer
-  --> tests/ui/borrow_as_ptr.rs:39:23
+  --> tests/ui/borrow_as_ptr.rs:42:23
    |
 LL |     let p: *mut i32 = &mut val;
    |                       ^^^^^^^^
@@ -48,7 +48,7 @@ LL |     let p: *mut i32 = &raw mut val;
    |                        +++
 
 error: implicit borrow as raw pointer
-  --> tests/ui/borrow_as_ptr.rs:44:19
+  --> tests/ui/borrow_as_ptr.rs:47:19
    |
 LL |     core::ptr::eq(&val, &1);
    |                   ^^^^
diff --git a/src/tools/clippy/tests/ui/char_lit_as_u8_suggestions.fixed b/src/tools/clippy/tests/ui/char_lit_as_u8.fixed
index 64aacedfd36..64aacedfd36 100644
--- a/src/tools/clippy/tests/ui/char_lit_as_u8_suggestions.fixed
+++ b/src/tools/clippy/tests/ui/char_lit_as_u8.fixed
diff --git a/src/tools/clippy/tests/ui/char_lit_as_u8.rs b/src/tools/clippy/tests/ui/char_lit_as_u8.rs
index c8774c7f309..a8f39e27605 100644
--- a/src/tools/clippy/tests/ui/char_lit_as_u8.rs
+++ b/src/tools/clippy/tests/ui/char_lit_as_u8.rs
@@ -1,7 +1,12 @@
 #![warn(clippy::char_lit_as_u8)]
 
 fn main() {
-    // no suggestion, since a byte literal won't work.
-    let _ = '❤' as u8;
+    let _ = 'a' as u8;
+    //~^ char_lit_as_u8
+    let _ = '\n' as u8;
+    //~^ char_lit_as_u8
+    let _ = '\0' as u8;
+    //~^ char_lit_as_u8
+    let _ = '\x01' as u8;
     //~^ char_lit_as_u8
 }
diff --git a/src/tools/clippy/tests/ui/char_lit_as_u8.stderr b/src/tools/clippy/tests/ui/char_lit_as_u8.stderr
index ec02f1341c0..9bcded7b0ff 100644
--- a/src/tools/clippy/tests/ui/char_lit_as_u8.stderr
+++ b/src/tools/clippy/tests/ui/char_lit_as_u8.stderr
@@ -1,12 +1,36 @@
 error: casting a character literal to `u8` truncates
-  --> tests/ui/char_lit_as_u8.rs:5:13
+  --> tests/ui/char_lit_as_u8.rs:4:13
    |
-LL |     let _ = '❤' as u8;
-   |             ^^^^^^^^^
+LL |     let _ = 'a' as u8;
+   |             ^^^^^^^^^ help: use a byte literal instead: `b'a'`
    |
    = note: `char` is four bytes wide, but `u8` is a single byte
    = note: `-D clippy::char-lit-as-u8` implied by `-D warnings`
    = help: to override `-D warnings` add `#[allow(clippy::char_lit_as_u8)]`
 
-error: aborting due to 1 previous error
+error: casting a character literal to `u8` truncates
+  --> tests/ui/char_lit_as_u8.rs:6:13
+   |
+LL |     let _ = '\n' as u8;
+   |             ^^^^^^^^^^ help: use a byte literal instead: `b'\n'`
+   |
+   = note: `char` is four bytes wide, but `u8` is a single byte
+
+error: casting a character literal to `u8` truncates
+  --> tests/ui/char_lit_as_u8.rs:8:13
+   |
+LL |     let _ = '\0' as u8;
+   |             ^^^^^^^^^^ help: use a byte literal instead: `b'\0'`
+   |
+   = note: `char` is four bytes wide, but `u8` is a single byte
+
+error: casting a character literal to `u8` truncates
+  --> tests/ui/char_lit_as_u8.rs:10:13
+   |
+LL |     let _ = '\x01' as u8;
+   |             ^^^^^^^^^^^^ help: use a byte literal instead: `b'\x01'`
+   |
+   = note: `char` is four bytes wide, but `u8` is a single byte
+
+error: aborting due to 4 previous errors
 
diff --git a/src/tools/clippy/tests/ui/char_lit_as_u8_suggestions.rs b/src/tools/clippy/tests/ui/char_lit_as_u8_suggestions.rs
deleted file mode 100644
index a8f39e27605..00000000000
--- a/src/tools/clippy/tests/ui/char_lit_as_u8_suggestions.rs
+++ /dev/null
@@ -1,12 +0,0 @@
-#![warn(clippy::char_lit_as_u8)]
-
-fn main() {
-    let _ = 'a' as u8;
-    //~^ char_lit_as_u8
-    let _ = '\n' as u8;
-    //~^ char_lit_as_u8
-    let _ = '\0' as u8;
-    //~^ char_lit_as_u8
-    let _ = '\x01' as u8;
-    //~^ char_lit_as_u8
-}
diff --git a/src/tools/clippy/tests/ui/char_lit_as_u8_suggestions.stderr b/src/tools/clippy/tests/ui/char_lit_as_u8_suggestions.stderr
deleted file mode 100644
index 158dfd6bed2..00000000000
--- a/src/tools/clippy/tests/ui/char_lit_as_u8_suggestions.stderr
+++ /dev/null
@@ -1,36 +0,0 @@
-error: casting a character literal to `u8` truncates
-  --> tests/ui/char_lit_as_u8_suggestions.rs:4:13
-   |
-LL |     let _ = 'a' as u8;
-   |             ^^^^^^^^^ help: use a byte literal instead: `b'a'`
-   |
-   = note: `char` is four bytes wide, but `u8` is a single byte
-   = note: `-D clippy::char-lit-as-u8` implied by `-D warnings`
-   = help: to override `-D warnings` add `#[allow(clippy::char_lit_as_u8)]`
-
-error: casting a character literal to `u8` truncates
-  --> tests/ui/char_lit_as_u8_suggestions.rs:6:13
-   |
-LL |     let _ = '\n' as u8;
-   |             ^^^^^^^^^^ help: use a byte literal instead: `b'\n'`
-   |
-   = note: `char` is four bytes wide, but `u8` is a single byte
-
-error: casting a character literal to `u8` truncates
-  --> tests/ui/char_lit_as_u8_suggestions.rs:8:13
-   |
-LL |     let _ = '\0' as u8;
-   |             ^^^^^^^^^^ help: use a byte literal instead: `b'\0'`
-   |
-   = note: `char` is four bytes wide, but `u8` is a single byte
-
-error: casting a character literal to `u8` truncates
-  --> tests/ui/char_lit_as_u8_suggestions.rs:10:13
-   |
-LL |     let _ = '\x01' as u8;
-   |             ^^^^^^^^^^^^ help: use a byte literal instead: `b'\x01'`
-   |
-   = note: `char` is four bytes wide, but `u8` is a single byte
-
-error: aborting due to 4 previous errors
-
diff --git a/src/tools/clippy/tests/ui/char_lit_as_u8_unfixable.rs b/src/tools/clippy/tests/ui/char_lit_as_u8_unfixable.rs
new file mode 100644
index 00000000000..e5c094f158e
--- /dev/null
+++ b/src/tools/clippy/tests/ui/char_lit_as_u8_unfixable.rs
@@ -0,0 +1,8 @@
+//@no-rustfix
+#![warn(clippy::char_lit_as_u8)]
+
+fn main() {
+    // no suggestion, since a byte literal won't work.
+    let _ = '❤' as u8;
+    //~^ char_lit_as_u8
+}
diff --git a/src/tools/clippy/tests/ui/char_lit_as_u8_unfixable.stderr b/src/tools/clippy/tests/ui/char_lit_as_u8_unfixable.stderr
new file mode 100644
index 00000000000..49e555ae638
--- /dev/null
+++ b/src/tools/clippy/tests/ui/char_lit_as_u8_unfixable.stderr
@@ -0,0 +1,12 @@
+error: casting a character literal to `u8` truncates
+  --> tests/ui/char_lit_as_u8_unfixable.rs:6:13
+   |
+LL |     let _ = '❤' as u8;
+   |             ^^^^^^^^^
+   |
+   = note: `char` is four bytes wide, but `u8` is a single byte
+   = note: `-D clippy::char-lit-as-u8` implied by `-D warnings`
+   = help: to override `-D warnings` add `#[allow(clippy::char_lit_as_u8)]`
+
+error: aborting due to 1 previous error
+
diff --git a/src/tools/clippy/tests/ui/deref_addrof.fixed b/src/tools/clippy/tests/ui/deref_addrof.fixed
index 35dbd790e89..ffe7f7d1440 100644
--- a/src/tools/clippy/tests/ui/deref_addrof.fixed
+++ b/src/tools/clippy/tests/ui/deref_addrof.fixed
@@ -1,11 +1,11 @@
-//@aux-build:proc_macros.rs
-
-#![allow(clippy::return_self_not_must_use, clippy::useless_vec)]
+#![allow(
+    dangerous_implicit_autorefs,
+    clippy::explicit_auto_deref,
+    clippy::return_self_not_must_use,
+    clippy::useless_vec
+)]
 #![warn(clippy::deref_addrof)]
 
-extern crate proc_macros;
-use proc_macros::inline_macros;
-
 fn get_number() -> usize {
     10
 }
@@ -56,19 +56,75 @@ fn main() {
     //~^ deref_addrof
     // do NOT lint for array as semantic differences with/out `*&`.
     let _arr = *&[0, 1, 2, 3, 4];
+
+    // Do not lint when text comes from macro
+    macro_rules! mac {
+        (dr) => {
+            *&0
+        };
+        (dr $e:expr) => {
+            *&$e
+        };
+        (r $e:expr) => {
+            &$e
+        };
+    }
+    let b = mac!(dr);
+    let b = mac!(dr a);
+    let b = *mac!(r a);
 }
 
-#[derive(Copy, Clone)]
-pub struct S;
-#[inline_macros]
-impl S {
-    pub fn f(&self) -> &Self {
-        inline!($(@expr self))
-        //~^ deref_addrof
+fn issue14386() {
+    use std::mem::ManuallyDrop;
+
+    #[derive(Copy, Clone)]
+    struct Data {
+        num: u64,
     }
-    #[allow(unused_mut)] // mut will be unused, once the macro is fixed
-    pub fn f_mut(mut self) -> Self {
-        inline!($(@expr self))
+
+    #[derive(Clone, Copy)]
+    struct M {
+        md: ManuallyDrop<[u8; 4]>,
+    }
+
+    union DataWithPadding<'lt> {
+        data: ManuallyDrop<Data>,
+        prim: ManuallyDrop<u64>,
+        padding: [u8; size_of::<Data>()],
+        tup: (ManuallyDrop<Data>, ()),
+        indirect: M,
+        indirect_arr: [M; 2],
+        indirect_ref: &'lt mut M,
+    }
+
+    let mut a = DataWithPadding {
+        padding: [0; size_of::<DataWithPadding>()],
+    };
+    unsafe {
+        a.padding = [1; size_of::<DataWithPadding>()];
         //~^ deref_addrof
+        a.tup.1 = ();
+        //~^ deref_addrof
+        *a.prim = 0;
+        //~^ deref_addrof
+
+        (*a.data).num = 42;
+        //~^ deref_addrof
+        (*a.indirect.md)[3] = 1;
+        //~^ deref_addrof
+        (*a.indirect_arr[1].md)[3] = 1;
+        //~^ deref_addrof
+        (*a.indirect_ref.md)[3] = 1;
+        //~^ deref_addrof
+
+        // Check that raw pointers are properly considered as well
+        *a.prim = 0;
+        //~^ deref_addrof
+        (*a.data).num = 42;
+        //~^ deref_addrof
+
+        // Do not lint, as the dereference happens later, we cannot
+        // just remove `&mut`
+        (*&mut a.tup).0.num = 42;
     }
 }
diff --git a/src/tools/clippy/tests/ui/deref_addrof.rs b/src/tools/clippy/tests/ui/deref_addrof.rs
index 96d1b92ef7b..bc253716aff 100644
--- a/src/tools/clippy/tests/ui/deref_addrof.rs
+++ b/src/tools/clippy/tests/ui/deref_addrof.rs
@@ -1,11 +1,11 @@
-//@aux-build:proc_macros.rs
-
-#![allow(clippy::return_self_not_must_use, clippy::useless_vec)]
+#![allow(
+    dangerous_implicit_autorefs,
+    clippy::explicit_auto_deref,
+    clippy::return_self_not_must_use,
+    clippy::useless_vec
+)]
 #![warn(clippy::deref_addrof)]
 
-extern crate proc_macros;
-use proc_macros::inline_macros;
-
 fn get_number() -> usize {
     10
 }
@@ -56,19 +56,75 @@ fn main() {
     //~^ deref_addrof
     // do NOT lint for array as semantic differences with/out `*&`.
     let _arr = *&[0, 1, 2, 3, 4];
+
+    // Do not lint when text comes from macro
+    macro_rules! mac {
+        (dr) => {
+            *&0
+        };
+        (dr $e:expr) => {
+            *&$e
+        };
+        (r $e:expr) => {
+            &$e
+        };
+    }
+    let b = mac!(dr);
+    let b = mac!(dr a);
+    let b = *mac!(r a);
 }
 
-#[derive(Copy, Clone)]
-pub struct S;
-#[inline_macros]
-impl S {
-    pub fn f(&self) -> &Self {
-        inline!(*& $(@expr self))
-        //~^ deref_addrof
+fn issue14386() {
+    use std::mem::ManuallyDrop;
+
+    #[derive(Copy, Clone)]
+    struct Data {
+        num: u64,
     }
-    #[allow(unused_mut)] // mut will be unused, once the macro is fixed
-    pub fn f_mut(mut self) -> Self {
-        inline!(*&mut $(@expr self))
+
+    #[derive(Clone, Copy)]
+    struct M {
+        md: ManuallyDrop<[u8; 4]>,
+    }
+
+    union DataWithPadding<'lt> {
+        data: ManuallyDrop<Data>,
+        prim: ManuallyDrop<u64>,
+        padding: [u8; size_of::<Data>()],
+        tup: (ManuallyDrop<Data>, ()),
+        indirect: M,
+        indirect_arr: [M; 2],
+        indirect_ref: &'lt mut M,
+    }
+
+    let mut a = DataWithPadding {
+        padding: [0; size_of::<DataWithPadding>()],
+    };
+    unsafe {
+        (*&mut a.padding) = [1; size_of::<DataWithPadding>()];
         //~^ deref_addrof
+        (*&mut a.tup).1 = ();
+        //~^ deref_addrof
+        **&mut a.prim = 0;
+        //~^ deref_addrof
+
+        (*&mut a.data).num = 42;
+        //~^ deref_addrof
+        (*&mut a.indirect.md)[3] = 1;
+        //~^ deref_addrof
+        (*&mut a.indirect_arr[1].md)[3] = 1;
+        //~^ deref_addrof
+        (*&mut a.indirect_ref.md)[3] = 1;
+        //~^ deref_addrof
+
+        // Check that raw pointers are properly considered as well
+        **&raw mut a.prim = 0;
+        //~^ deref_addrof
+        (*&raw mut a.data).num = 42;
+        //~^ deref_addrof
+
+        // Do not lint, as the dereference happens later, we cannot
+        // just remove `&mut`
+        (*&mut a.tup).0.num = 42;
     }
 }
diff --git a/src/tools/clippy/tests/ui/deref_addrof.stderr b/src/tools/clippy/tests/ui/deref_addrof.stderr
index 81414b625b2..65dd904a8f7 100644
--- a/src/tools/clippy/tests/ui/deref_addrof.stderr
+++ b/src/tools/clippy/tests/ui/deref_addrof.stderr
@@ -56,20 +56,58 @@ LL |     let _repeat = *&[0; 64];
    |                   ^^^^^^^^^ help: try: `[0; 64]`
 
 error: immediately dereferencing a reference
-  --> tests/ui/deref_addrof.rs:66:17
+  --> tests/ui/deref_addrof.rs:104:9
    |
-LL |         inline!(*& $(@expr self))
-   |                 ^^^^^^^^^^^^^^^^ help: try: `$(@expr self)`
+LL |         (*&mut a.padding) = [1; size_of::<DataWithPadding>()];
+   |         ^^^^^^^^^^^^^^^^^ help: try: `a.padding`
+
+error: immediately dereferencing a reference
+  --> tests/ui/deref_addrof.rs:106:9
+   |
+LL |         (*&mut a.tup).1 = ();
+   |         ^^^^^^^^^^^^^ help: try: `a.tup`
+
+error: immediately dereferencing a reference
+  --> tests/ui/deref_addrof.rs:108:10
    |
-   = note: this error originates in the macro `__inline_mac_impl` (in Nightly builds, run with -Z macro-backtrace for more info)
+LL |         **&mut a.prim = 0;
+   |          ^^^^^^^^^^^^ help: try: `a.prim`
 
 error: immediately dereferencing a reference
-  --> tests/ui/deref_addrof.rs:71:17
+  --> tests/ui/deref_addrof.rs:111:9
    |
-LL |         inline!(*&mut $(@expr self))
-   |                 ^^^^^^^^^^^^^^^^^^^ help: try: `$(@expr self)`
+LL |         (*&mut a.data).num = 42;
+   |         ^^^^^^^^^^^^^^ help: try: `(*a.data)`
+
+error: immediately dereferencing a reference
+  --> tests/ui/deref_addrof.rs:113:9
+   |
+LL |         (*&mut a.indirect.md)[3] = 1;
+   |         ^^^^^^^^^^^^^^^^^^^^^ help: try: `(*a.indirect.md)`
+
+error: immediately dereferencing a reference
+  --> tests/ui/deref_addrof.rs:115:9
+   |
+LL |         (*&mut a.indirect_arr[1].md)[3] = 1;
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `(*a.indirect_arr[1].md)`
+
+error: immediately dereferencing a reference
+  --> tests/ui/deref_addrof.rs:117:9
+   |
+LL |         (*&mut a.indirect_ref.md)[3] = 1;
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `(*a.indirect_ref.md)`
+
+error: immediately dereferencing a reference
+  --> tests/ui/deref_addrof.rs:121:10
+   |
+LL |         **&raw mut a.prim = 0;
+   |          ^^^^^^^^^^^^^^^^ help: try: `a.prim`
+
+error: immediately dereferencing a reference
+  --> tests/ui/deref_addrof.rs:123:9
    |
-   = note: this error originates in the macro `__inline_mac_impl` (in Nightly builds, run with -Z macro-backtrace for more info)
+LL |         (*&raw mut a.data).num = 42;
+   |         ^^^^^^^^^^^^^^^^^^ help: try: `(*a.data)`
 
-error: aborting due to 11 previous errors
+error: aborting due to 18 previous errors
 
diff --git a/src/tools/clippy/tests/ui/doc/doc-fixable.fixed b/src/tools/clippy/tests/ui/doc/doc-fixable.fixed
index bbbd5973036..423a73734da 100644
--- a/src/tools/clippy/tests/ui/doc/doc-fixable.fixed
+++ b/src/tools/clippy/tests/ui/doc/doc-fixable.fixed
@@ -74,7 +74,7 @@ fn test_units() {
 /// GitHub GitLab
 /// IPv4 IPv6
 /// ClojureScript CoffeeScript JavaScript PostScript PureScript TypeScript
-/// WebAssembly
+/// PowerPC WebAssembly
 /// NaN NaNs
 /// OAuth GraphQL
 /// OCaml
diff --git a/src/tools/clippy/tests/ui/doc/doc-fixable.rs b/src/tools/clippy/tests/ui/doc/doc-fixable.rs
index 1077d3580d3..8deffb4210e 100644
--- a/src/tools/clippy/tests/ui/doc/doc-fixable.rs
+++ b/src/tools/clippy/tests/ui/doc/doc-fixable.rs
@@ -74,7 +74,7 @@ fn test_units() {
 /// GitHub GitLab
 /// IPv4 IPv6
 /// ClojureScript CoffeeScript JavaScript PostScript PureScript TypeScript
-/// WebAssembly
+/// PowerPC WebAssembly
 /// NaN NaNs
 /// OAuth GraphQL
 /// OCaml
diff --git a/src/tools/clippy/tests/ui/double_ended_iterator_last.fixed b/src/tools/clippy/tests/ui/double_ended_iterator_last.fixed
index be31ee5fb48..180a513d0f8 100644
--- a/src/tools/clippy/tests/ui/double_ended_iterator_last.fixed
+++ b/src/tools/clippy/tests/ui/double_ended_iterator_last.fixed
@@ -81,6 +81,11 @@ fn issue_14139() {
     let (subindex, _) = (index.by_ref().take(3), 42);
     let _ = subindex.last();
     let _ = index.next();
+
+    let mut index = [true, true, false, false, false, true].iter();
+    let subindex = (index.by_ref().take(3), 42);
+    let _ = subindex.0.last();
+    let _ = index.next();
 }
 
 fn drop_order() {
@@ -108,6 +113,12 @@ fn drop_order() {
     let mut v = DropDeIterator(v.into_iter());
     println!("Last element is {}", v.next_back().unwrap().0);
     //~^ ERROR: called `Iterator::last` on a `DoubleEndedIterator`
+
+    let v = vec![S("four"), S("five"), S("six")];
+    let mut v = (DropDeIterator(v.into_iter()), 42);
+    println!("Last element is {}", v.0.next_back().unwrap().0);
+    //~^ ERROR: called `Iterator::last` on a `DoubleEndedIterator`
+
     println!("Done");
 }
 
diff --git a/src/tools/clippy/tests/ui/double_ended_iterator_last.rs b/src/tools/clippy/tests/ui/double_ended_iterator_last.rs
index 30864e15bce..3dd72cfeaac 100644
--- a/src/tools/clippy/tests/ui/double_ended_iterator_last.rs
+++ b/src/tools/clippy/tests/ui/double_ended_iterator_last.rs
@@ -81,6 +81,11 @@ fn issue_14139() {
     let (subindex, _) = (index.by_ref().take(3), 42);
     let _ = subindex.last();
     let _ = index.next();
+
+    let mut index = [true, true, false, false, false, true].iter();
+    let subindex = (index.by_ref().take(3), 42);
+    let _ = subindex.0.last();
+    let _ = index.next();
 }
 
 fn drop_order() {
@@ -108,6 +113,12 @@ fn drop_order() {
     let v = DropDeIterator(v.into_iter());
     println!("Last element is {}", v.last().unwrap().0);
     //~^ ERROR: called `Iterator::last` on a `DoubleEndedIterator`
+
+    let v = vec![S("four"), S("five"), S("six")];
+    let v = (DropDeIterator(v.into_iter()), 42);
+    println!("Last element is {}", v.0.last().unwrap().0);
+    //~^ ERROR: called `Iterator::last` on a `DoubleEndedIterator`
+
     println!("Done");
 }
 
diff --git a/src/tools/clippy/tests/ui/double_ended_iterator_last.stderr b/src/tools/clippy/tests/ui/double_ended_iterator_last.stderr
index 72a6ead47a9..0f0056be376 100644
--- a/src/tools/clippy/tests/ui/double_ended_iterator_last.stderr
+++ b/src/tools/clippy/tests/ui/double_ended_iterator_last.stderr
@@ -18,7 +18,7 @@ LL |     let _ = DeIterator.last();
    |                        help: try: `next_back()`
 
 error: called `Iterator::last` on a `DoubleEndedIterator`; this will needlessly iterate the entire iterator
-  --> tests/ui/double_ended_iterator_last.rs:109:36
+  --> tests/ui/double_ended_iterator_last.rs:114:36
    |
 LL |     println!("Last element is {}", v.last().unwrap().0);
    |                                    ^^^^^^^^
@@ -30,5 +30,18 @@ LL ~     let mut v = DropDeIterator(v.into_iter());
 LL ~     println!("Last element is {}", v.next_back().unwrap().0);
    |
 
-error: aborting due to 3 previous errors
+error: called `Iterator::last` on a `DoubleEndedIterator`; this will needlessly iterate the entire iterator
+  --> tests/ui/double_ended_iterator_last.rs:119:36
+   |
+LL |     println!("Last element is {}", v.0.last().unwrap().0);
+   |                                    ^^^^^^^^^^
+   |
+   = note: this change will alter drop order which may be undesirable
+help: try
+   |
+LL ~     let mut v = (DropDeIterator(v.into_iter()), 42);
+LL ~     println!("Last element is {}", v.0.next_back().unwrap().0);
+   |
+
+error: aborting due to 4 previous errors
 
diff --git a/src/tools/clippy/tests/ui/double_ended_iterator_last_unfixable.rs b/src/tools/clippy/tests/ui/double_ended_iterator_last_unfixable.rs
deleted file mode 100644
index 73f62ac1246..00000000000
--- a/src/tools/clippy/tests/ui/double_ended_iterator_last_unfixable.rs
+++ /dev/null
@@ -1,39 +0,0 @@
-//@no-rustfix: requires manual changes
-#![warn(clippy::double_ended_iterator_last)]
-
-// Should not be linted because applying the lint would move the original iterator. This can only be
-// linted if the iterator is used thereafter.
-fn main() {
-    let mut index = [true, true, false, false, false, true].iter();
-    let subindex = (index.by_ref().take(3), 42);
-    let _ = subindex.0.last();
-    let _ = index.next();
-}
-
-fn drop_order() {
-    struct DropDeIterator(std::vec::IntoIter<S>);
-    impl Iterator for DropDeIterator {
-        type Item = S;
-        fn next(&mut self) -> Option<Self::Item> {
-            self.0.next()
-        }
-    }
-    impl DoubleEndedIterator for DropDeIterator {
-        fn next_back(&mut self) -> Option<Self::Item> {
-            self.0.next_back()
-        }
-    }
-
-    struct S(&'static str);
-    impl std::ops::Drop for S {
-        fn drop(&mut self) {
-            println!("Dropping {}", self.0);
-        }
-    }
-
-    let v = vec![S("one"), S("two"), S("three")];
-    let v = (DropDeIterator(v.into_iter()), 42);
-    println!("Last element is {}", v.0.last().unwrap().0);
-    //~^ ERROR: called `Iterator::last` on a `DoubleEndedIterator`
-    println!("Done");
-}
diff --git a/src/tools/clippy/tests/ui/double_ended_iterator_last_unfixable.stderr b/src/tools/clippy/tests/ui/double_ended_iterator_last_unfixable.stderr
deleted file mode 100644
index e330a22a354..00000000000
--- a/src/tools/clippy/tests/ui/double_ended_iterator_last_unfixable.stderr
+++ /dev/null
@@ -1,19 +0,0 @@
-error: called `Iterator::last` on a `DoubleEndedIterator`; this will needlessly iterate the entire iterator
-  --> tests/ui/double_ended_iterator_last_unfixable.rs:36:36
-   |
-LL |     println!("Last element is {}", v.0.last().unwrap().0);
-   |                                    ^^^^------
-   |                                        |
-   |                                        help: try: `next_back()`
-   |
-   = note: this change will alter drop order which may be undesirable
-note: this must be made mutable to use `.next_back()`
-  --> tests/ui/double_ended_iterator_last_unfixable.rs:36:36
-   |
-LL |     println!("Last element is {}", v.0.last().unwrap().0);
-   |                                    ^^^
-   = note: `-D clippy::double-ended-iterator-last` implied by `-D warnings`
-   = help: to override `-D warnings` add `#[allow(clippy::double_ended_iterator_last)]`
-
-error: aborting due to 1 previous error
-
diff --git a/src/tools/clippy/tests/ui/eta.fixed b/src/tools/clippy/tests/ui/eta.fixed
index c93b83f53ec..3d2b41b8fb8 100644
--- a/src/tools/clippy/tests/ui/eta.fixed
+++ b/src/tools/clippy/tests/ui/eta.fixed
@@ -1,3 +1,6 @@
+// we have some HELP annotations -- don't complain about them not being present everywhere
+//@require-annotations-for-level: ERROR
+
 #![warn(clippy::redundant_closure, clippy::redundant_closure_for_method_calls)]
 #![allow(unused)]
 #![allow(
@@ -561,3 +564,29 @@ fn issue_14789() {
         std::convert::identity,
     );
 }
+
+fn issue8817() {
+    fn f(_: u32) -> u32 {
+        todo!()
+    }
+    let g = |_: u32| -> u32 { todo!() };
+    struct S(u32);
+    enum MyError {
+        A(S),
+    }
+
+    Some(5)
+        .map(f)
+        //~^ redundant_closure
+        //~| HELP: replace the closure with the function itself
+        .map(g)
+        //~^ redundant_closure
+        //~| HELP: replace the closure with the function itself
+        .map(S)
+        //~^ redundant_closure
+        //~| HELP: replace the closure with the tuple struct itself
+        .map(MyError::A)
+        //~^ redundant_closure
+        //~| HELP: replace the closure with the tuple variant itself
+        .unwrap(); // just for nicer formatting
+}
diff --git a/src/tools/clippy/tests/ui/eta.rs b/src/tools/clippy/tests/ui/eta.rs
index 273c8b21f4a..79d1103410d 100644
--- a/src/tools/clippy/tests/ui/eta.rs
+++ b/src/tools/clippy/tests/ui/eta.rs
@@ -1,3 +1,6 @@
+// we have some HELP annotations -- don't complain about them not being present everywhere
+//@require-annotations-for-level: ERROR
+
 #![warn(clippy::redundant_closure, clippy::redundant_closure_for_method_calls)]
 #![allow(unused)]
 #![allow(
@@ -561,3 +564,29 @@ fn issue_14789() {
         std::convert::identity,
     );
 }
+
+fn issue8817() {
+    fn f(_: u32) -> u32 {
+        todo!()
+    }
+    let g = |_: u32| -> u32 { todo!() };
+    struct S(u32);
+    enum MyError {
+        A(S),
+    }
+
+    Some(5)
+        .map(|n| f(n))
+        //~^ redundant_closure
+        //~| HELP: replace the closure with the function itself
+        .map(|n| g(n))
+        //~^ redundant_closure
+        //~| HELP: replace the closure with the function itself
+        .map(|n| S(n))
+        //~^ redundant_closure
+        //~| HELP: replace the closure with the tuple struct itself
+        .map(|n| MyError::A(n))
+        //~^ redundant_closure
+        //~| HELP: replace the closure with the tuple variant itself
+        .unwrap(); // just for nicer formatting
+}
diff --git a/src/tools/clippy/tests/ui/eta.stderr b/src/tools/clippy/tests/ui/eta.stderr
index 8bc08add2fa..aa32ed1a38e 100644
--- a/src/tools/clippy/tests/ui/eta.stderr
+++ b/src/tools/clippy/tests/ui/eta.stderr
@@ -1,5 +1,5 @@
 error: redundant closure
-  --> tests/ui/eta.rs:31:27
+  --> tests/ui/eta.rs:34:27
    |
 LL |     let a = Some(1u8).map(|a| foo(a));
    |                           ^^^^^^^^^^ help: replace the closure with the function itself: `foo`
@@ -8,31 +8,31 @@ LL |     let a = Some(1u8).map(|a| foo(a));
    = help: to override `-D warnings` add `#[allow(clippy::redundant_closure)]`
 
 error: redundant closure
-  --> tests/ui/eta.rs:36:40
+  --> tests/ui/eta.rs:39:40
    |
 LL |     let _: Option<Vec<u8>> = true.then(|| vec![]); // special case vec!
    |                                        ^^^^^^^^^ help: replace the closure with `Vec::new`: `std::vec::Vec::new`
 
 error: redundant closure
-  --> tests/ui/eta.rs:39:35
+  --> tests/ui/eta.rs:42:35
    |
 LL |     let d = Some(1u8).map(|a| foo((|b| foo2(b))(a))); //is adjusted?
    |                                   ^^^^^^^^^^^^^ help: replace the closure with the function itself: `foo2`
 
 error: redundant closure
-  --> tests/ui/eta.rs:42:26
+  --> tests/ui/eta.rs:45:26
    |
 LL |     all(&[1, 2, 3], &&2, |x, y| below(x, y)); //is adjusted
    |                          ^^^^^^^^^^^^^^^^^^ help: replace the closure with the function itself: `below`
 
 error: redundant closure
-  --> tests/ui/eta.rs:51:27
+  --> tests/ui/eta.rs:54:27
    |
 LL |     let e = Some(1u8).map(|a| generic(a));
    |                           ^^^^^^^^^^^^^^ help: replace the closure with the function itself: `generic`
 
 error: redundant closure
-  --> tests/ui/eta.rs:104:51
+  --> tests/ui/eta.rs:107:51
    |
 LL |     let e = Some(TestStruct { some_ref: &i }).map(|a| a.foo());
    |                                                   ^^^^^^^^^^^ help: replace the closure with the method itself: `TestStruct::foo`
@@ -41,178 +41,202 @@ LL |     let e = Some(TestStruct { some_ref: &i }).map(|a| a.foo());
    = help: to override `-D warnings` add `#[allow(clippy::redundant_closure_for_method_calls)]`
 
 error: redundant closure
-  --> tests/ui/eta.rs:106:51
+  --> tests/ui/eta.rs:109:51
    |
 LL |     let e = Some(TestStruct { some_ref: &i }).map(|a| a.trait_foo());
    |                                                   ^^^^^^^^^^^^^^^^^ help: replace the closure with the method itself: `TestTrait::trait_foo`
 
 error: redundant closure
-  --> tests/ui/eta.rs:109:42
+  --> tests/ui/eta.rs:112:42
    |
 LL |     let e = Some(&mut vec![1, 2, 3]).map(|v| v.clear());
    |                                          ^^^^^^^^^^^^^ help: replace the closure with the method itself: `std::vec::Vec::clear`
 
 error: redundant closure
-  --> tests/ui/eta.rs:114:29
+  --> tests/ui/eta.rs:117:29
    |
 LL |     let e = Some("str").map(|s| s.to_string());
    |                             ^^^^^^^^^^^^^^^^^ help: replace the closure with the method itself: `std::string::ToString::to_string`
 
 error: redundant closure
-  --> tests/ui/eta.rs:116:27
+  --> tests/ui/eta.rs:119:27
    |
 LL |     let e = Some('a').map(|s| s.to_uppercase());
    |                           ^^^^^^^^^^^^^^^^^^^^ help: replace the closure with the method itself: `char::to_uppercase`
 
 error: redundant closure
-  --> tests/ui/eta.rs:119:65
+  --> tests/ui/eta.rs:122:65
    |
 LL |     let e: std::vec::Vec<char> = vec!['a', 'b', 'c'].iter().map(|c| c.to_ascii_uppercase()).collect();
    |                                                                 ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace the closure with the method itself: `char::to_ascii_uppercase`
 
 error: redundant closure
-  --> tests/ui/eta.rs:136:23
+  --> tests/ui/eta.rs:139:23
    |
 LL |         let _ = x.map(|x| x.parse::<i16>());
    |                       ^^^^^^^^^^^^^^^^^^^^ help: replace the closure with the method itself: `str::parse::<i16>`
 
 error: redundant closure
-  --> tests/ui/eta.rs:189:22
+  --> tests/ui/eta.rs:192:22
    |
 LL |     requires_fn_once(|| x());
    |                      ^^^^^^ help: replace the closure with the function itself: `x`
 
 error: redundant closure
-  --> tests/ui/eta.rs:197:27
+  --> tests/ui/eta.rs:200:27
    |
 LL |     let a = Some(1u8).map(|a| foo_ptr(a));
    |                           ^^^^^^^^^^^^^^ help: replace the closure with the function itself: `foo_ptr`
 
 error: redundant closure
-  --> tests/ui/eta.rs:203:27
+  --> tests/ui/eta.rs:206:27
    |
 LL |     let a = Some(1u8).map(|a| closure(a));
    |                           ^^^^^^^^^^^^^^ help: replace the closure with the function itself: `closure`
 
 error: redundant closure
-  --> tests/ui/eta.rs:236:28
+  --> tests/ui/eta.rs:239:28
    |
 LL |     x.into_iter().for_each(|x| add_to_res(x));
    |                            ^^^^^^^^^^^^^^^^^ help: replace the closure with the function itself: `&mut add_to_res`
 
 error: redundant closure
-  --> tests/ui/eta.rs:238:28
+  --> tests/ui/eta.rs:241:28
    |
 LL |     y.into_iter().for_each(|x| add_to_res(x));
    |                            ^^^^^^^^^^^^^^^^^ help: replace the closure with the function itself: `&mut add_to_res`
 
 error: redundant closure
-  --> tests/ui/eta.rs:240:28
+  --> tests/ui/eta.rs:243:28
    |
 LL |     z.into_iter().for_each(|x| add_to_res(x));
    |                            ^^^^^^^^^^^^^^^^^ help: replace the closure with the function itself: `add_to_res`
 
 error: redundant closure
-  --> tests/ui/eta.rs:248:21
+  --> tests/ui/eta.rs:251:21
    |
 LL |         Some(1).map(|n| closure(n));
    |                     ^^^^^^^^^^^^^^ help: replace the closure with the function itself: `&mut closure`
 
 error: redundant closure
-  --> tests/ui/eta.rs:253:21
+  --> tests/ui/eta.rs:256:21
    |
 LL |         Some(1).map(|n| in_loop(n));
    |                     ^^^^^^^^^^^^^^ help: replace the closure with the function itself: `in_loop`
 
 error: redundant closure
-  --> tests/ui/eta.rs:347:18
+  --> tests/ui/eta.rs:350:18
    |
 LL |     takes_fn_mut(|| f());
    |                  ^^^^^^ help: replace the closure with the function itself: `&mut f`
 
 error: redundant closure
-  --> tests/ui/eta.rs:351:19
+  --> tests/ui/eta.rs:354:19
    |
 LL |     takes_fn_once(|| f());
    |                   ^^^^^^ help: replace the closure with the function itself: `&mut f`
 
 error: redundant closure
-  --> tests/ui/eta.rs:356:26
+  --> tests/ui/eta.rs:359:26
    |
 LL |     move || takes_fn_mut(|| f_used_once())
    |                          ^^^^^^^^^^^^^^^^ help: replace the closure with the function itself: `&mut f_used_once`
 
 error: redundant closure
-  --> tests/ui/eta.rs:369:19
+  --> tests/ui/eta.rs:372:19
    |
 LL |     array_opt.map(|a| a.as_slice());
    |                   ^^^^^^^^^^^^^^^^ help: replace the closure with the method itself: `<[u8; 3]>::as_slice`
 
 error: redundant closure
-  --> tests/ui/eta.rs:373:19
+  --> tests/ui/eta.rs:376:19
    |
 LL |     slice_opt.map(|s| s.len());
    |                   ^^^^^^^^^^^ help: replace the closure with the method itself: `<[u8]>::len`
 
 error: redundant closure
-  --> tests/ui/eta.rs:377:17
+  --> tests/ui/eta.rs:380:17
    |
 LL |     ptr_opt.map(|p| p.is_null());
    |                 ^^^^^^^^^^^^^^^ help: replace the closure with the method itself: `<*const usize>::is_null`
 
 error: redundant closure
-  --> tests/ui/eta.rs:382:17
+  --> tests/ui/eta.rs:385:17
    |
 LL |     dyn_opt.map(|d| d.method_on_dyn());
    |                 ^^^^^^^^^^^^^^^^^^^^^ help: replace the closure with the method itself: `<dyn TestTrait>::method_on_dyn`
 
 error: redundant closure
-  --> tests/ui/eta.rs:443:19
+  --> tests/ui/eta.rs:446:19
    |
 LL |     let _ = f(&0, |x, y| f2(x, y));
    |                   ^^^^^^^^^^^^^^^ help: replace the closure with the function itself: `f2`
 
 error: redundant closure
-  --> tests/ui/eta.rs:472:22
+  --> tests/ui/eta.rs:475:22
    |
 LL |             test.map(|t| t.method())
    |                      ^^^^^^^^^^^^^^ help: replace the closure with the method itself: `Test::method`
 
 error: redundant closure
-  --> tests/ui/eta.rs:477:22
+  --> tests/ui/eta.rs:480:22
    |
 LL |             test.map(|t| t.method())
    |                      ^^^^^^^^^^^^^^ help: replace the closure with the method itself: `super::Outer::method`
 
 error: redundant closure
-  --> tests/ui/eta.rs:491:18
+  --> tests/ui/eta.rs:494:18
    |
 LL |         test.map(|t| t.method())
    |                  ^^^^^^^^^^^^^^ help: replace the closure with the method itself: `test_mod::Test::method`
 
 error: redundant closure
-  --> tests/ui/eta.rs:499:30
+  --> tests/ui/eta.rs:502:30
    |
 LL |                     test.map(|t| t.method())
    |                              ^^^^^^^^^^^^^^ help: replace the closure with the method itself: `crate::issue_10854::d::Test::method`
 
 error: redundant closure
-  --> tests/ui/eta.rs:519:38
+  --> tests/ui/eta.rs:522:38
    |
 LL |         let x = Box::new(|| None.map(|x| f(x)));
    |                                      ^^^^^^^^ help: replace the closure with the function itself: `&f`
 
 error: redundant closure
-  --> tests/ui/eta.rs:524:38
+  --> tests/ui/eta.rs:527:38
    |
 LL |         let x = Box::new(|| None.map(|x| f(x)));
    |                                      ^^^^^^^^ help: replace the closure with the function itself: `f`
 
 error: redundant closure
-  --> tests/ui/eta.rs:542:35
+  --> tests/ui/eta.rs:545:35
    |
 LL |         let _field = bind.or_else(|| get_default()).unwrap();
    |                                   ^^^^^^^^^^^^^^^^ help: replace the closure with the function itself: `get_default`
 
-error: aborting due to 35 previous errors
+error: redundant closure
+  --> tests/ui/eta.rs:588:14
+   |
+LL |         .map(|n| MyError::A(n))
+   |              ^^^^^^^^^^^^^^^^^ help: replace the closure with the tuple variant itself: `MyError::A`
+
+error: redundant closure
+  --> tests/ui/eta.rs:585:14
+   |
+LL |         .map(|n| S(n))
+   |              ^^^^^^^^ help: replace the closure with the tuple struct itself: `S`
+
+error: redundant closure
+  --> tests/ui/eta.rs:582:14
+   |
+LL |         .map(|n| g(n))
+   |              ^^^^^^^^ help: replace the closure with the function itself: `g`
+
+error: redundant closure
+  --> tests/ui/eta.rs:579:14
+   |
+LL |         .map(|n| f(n))
+   |              ^^^^^^^^ help: replace the closure with the function itself: `f`
+
+error: aborting due to 39 previous errors
 
diff --git a/src/tools/clippy/tests/ui/from_str_radix_10.fixed b/src/tools/clippy/tests/ui/from_str_radix_10.fixed
index 4b8fd778685..47d24167e56 100644
--- a/src/tools/clippy/tests/ui/from_str_radix_10.fixed
+++ b/src/tools/clippy/tests/ui/from_str_radix_10.fixed
@@ -74,3 +74,13 @@ fn issue_12731() {
         let _ = u32::from_str_radix("123", 10);
     }
 }
+
+fn fix_str_ref_check() {
+    #![allow(clippy::needless_borrow)]
+    let s = "1";
+    let _ = s.parse::<u32>().unwrap();
+    //~^ from_str_radix_10
+    let s_ref = &s;
+    let _ = s_ref.parse::<u32>().unwrap();
+    //~^ from_str_radix_10
+}
diff --git a/src/tools/clippy/tests/ui/from_str_radix_10.rs b/src/tools/clippy/tests/ui/from_str_radix_10.rs
index 89002b11a99..952e19b57a0 100644
--- a/src/tools/clippy/tests/ui/from_str_radix_10.rs
+++ b/src/tools/clippy/tests/ui/from_str_radix_10.rs
@@ -74,3 +74,13 @@ fn issue_12731() {
         let _ = u32::from_str_radix("123", 10);
     }
 }
+
+fn fix_str_ref_check() {
+    #![allow(clippy::needless_borrow)]
+    let s = "1";
+    let _ = u32::from_str_radix(&s, 10).unwrap();
+    //~^ from_str_radix_10
+    let s_ref = &s;
+    let _ = u32::from_str_radix(&s_ref, 10).unwrap();
+    //~^ from_str_radix_10
+}
diff --git a/src/tools/clippy/tests/ui/from_str_radix_10.stderr b/src/tools/clippy/tests/ui/from_str_radix_10.stderr
index c693e8f50ff..d4e6c3657f2 100644
--- a/src/tools/clippy/tests/ui/from_str_radix_10.stderr
+++ b/src/tools/clippy/tests/ui/from_str_radix_10.stderr
@@ -49,5 +49,17 @@ error: this call to `from_str_radix` can be replaced with a call to `str::parse`
 LL |     i32::from_str_radix(&stringier, 10)?;
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `stringier.parse::<i32>()`
 
-error: aborting due to 8 previous errors
+error: this call to `from_str_radix` can be replaced with a call to `str::parse`
+  --> tests/ui/from_str_radix_10.rs:81:13
+   |
+LL |     let _ = u32::from_str_radix(&s, 10).unwrap();
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `s.parse::<u32>()`
+
+error: this call to `from_str_radix` can be replaced with a call to `str::parse`
+  --> tests/ui/from_str_radix_10.rs:84:13
+   |
+LL |     let _ = u32::from_str_radix(&s_ref, 10).unwrap();
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `s_ref.parse::<u32>()`
+
+error: aborting due to 10 previous errors
 
diff --git a/src/tools/clippy/tests/ui/functions_maxlines.rs b/src/tools/clippy/tests/ui/functions_maxlines.rs
index e0990dadaaa..b0714552461 100644
--- a/src/tools/clippy/tests/ui/functions_maxlines.rs
+++ b/src/tools/clippy/tests/ui/functions_maxlines.rs
@@ -1,3 +1,4 @@
+#![allow(clippy::unused_unit, clippy::missing_safety_doc)]
 #![warn(clippy::too_many_lines)]
 
 fn good_lines() {
@@ -55,7 +56,8 @@ fn good_lines() {
     println!("This is good.");
 }
 
-fn bad_lines() {
+#[allow(unused)] // the attr shouldn't get included in the highlight
+pub async unsafe extern "Rust" fn bad_lines() -> () {
     //~^ too_many_lines
 
     println!("Dont get confused by braces: {{}}");
@@ -162,4 +164,115 @@ fn bad_lines() {
     println!("This is bad.");
 }
 
+struct Foo;
+impl Foo {
+    #[allow(unused)] // the attr shouldn't get included in the highlight
+    pub async unsafe extern "Rust" fn bad_lines() -> () {
+        //~^ too_many_lines
+
+        println!("Dont get confused by braces: {{}}");
+        println!("This is bad.");
+        println!("This is bad.");
+        println!("This is bad.");
+        println!("This is bad.");
+        println!("This is bad.");
+        println!("This is bad.");
+        println!("This is bad.");
+        println!("This is bad.");
+        println!("This is bad.");
+        println!("This is bad.");
+        println!("This is bad.");
+        println!("This is bad.");
+        println!("This is bad.");
+        println!("This is bad.");
+        println!("This is bad.");
+        println!("This is bad.");
+        println!("This is bad.");
+        println!("This is bad.");
+        println!("This is bad.");
+        println!("This is bad.");
+        println!("This is bad.");
+        println!("This is bad.");
+        println!("This is bad.");
+        println!("This is bad.");
+        println!("This is bad.");
+        println!("This is bad.");
+        println!("This is bad.");
+        println!("This is bad.");
+        println!("This is bad.");
+        println!("This is bad.");
+        println!("This is bad.");
+        println!("This is bad.");
+        println!("This is bad.");
+        println!("This is bad.");
+        println!("This is bad.");
+        println!("This is bad.");
+        println!("This is bad.");
+        println!("This is bad.");
+        println!("This is bad.");
+        println!("This is bad.");
+        println!("This is bad.");
+        println!("This is bad.");
+        println!("This is bad.");
+        println!("This is bad.");
+        println!("This is bad.");
+        println!("This is bad.");
+        println!("This is bad.");
+        println!("This is bad.");
+        println!("This is bad.");
+        println!("This is bad.");
+        println!("This is bad.");
+        println!("This is bad.");
+        println!("This is bad.");
+        println!("This is bad.");
+        println!("This is bad.");
+        println!("This is bad.");
+        println!("This is bad.");
+        println!("This is bad.");
+        println!("This is bad.");
+        println!("This is bad.");
+        println!("This is bad.");
+        println!("This is bad.");
+        println!("This is bad.");
+        println!("This is bad.");
+        println!("This is bad.");
+        println!("This is bad.");
+        println!("This is bad.");
+        println!("This is bad.");
+        println!("This is bad.");
+        println!("This is bad.");
+        println!("This is bad.");
+        println!("This is bad.");
+        println!("This is bad.");
+        println!("This is bad.");
+        println!("This is bad.");
+        println!("This is bad.");
+        println!("This is bad.");
+        println!("This is bad.");
+        println!("This is bad.");
+        println!("This is bad.");
+        println!("This is bad.");
+        println!("This is bad.");
+        println!("This is bad.");
+        println!("This is bad.");
+        println!("This is bad.");
+        println!("This is bad.");
+        println!("This is bad.");
+        println!("This is bad.");
+        println!("This is bad.");
+        println!("This is bad.");
+        println!("This is bad.");
+        println!("This is bad.");
+        println!("This is bad.");
+        println!("This is bad.");
+        println!("This is bad.");
+        println!("This is bad.");
+        println!("This is bad.");
+        println!("This is bad.");
+        println!("This is bad.");
+        println!("This is bad.");
+        println!("This is bad.");
+    }
+}
+
 fn main() {}
diff --git a/src/tools/clippy/tests/ui/functions_maxlines.stderr b/src/tools/clippy/tests/ui/functions_maxlines.stderr
index f42a2b2a22a..4c3faf45c47 100644
--- a/src/tools/clippy/tests/ui/functions_maxlines.stderr
+++ b/src/tools/clippy/tests/ui/functions_maxlines.stderr
@@ -1,17 +1,17 @@
-error: this function has too many lines (102/100)
-  --> tests/ui/functions_maxlines.rs:58:1
+error: this function has too many lines (104/100)
+  --> tests/ui/functions_maxlines.rs:60:1
    |
-LL | / fn bad_lines() {
-LL | |
-LL | |
-LL | |     println!("Dont get confused by braces: {{}}");
-...  |
-LL | |     println!("This is bad.");
-LL | | }
-   | |_^
+LL | pub async unsafe extern "Rust" fn bad_lines() -> () {
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
    = note: `-D clippy::too-many-lines` implied by `-D warnings`
    = help: to override `-D warnings` add `#[allow(clippy::too_many_lines)]`
 
-error: aborting due to 1 previous error
+error: this function has too many lines (104/100)
+  --> tests/ui/functions_maxlines.rs:170:5
+   |
+LL |     pub async unsafe extern "Rust" fn bad_lines() -> () {
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 2 previous errors
 
diff --git a/src/tools/clippy/tests/ui/infinite_loops.rs b/src/tools/clippy/tests/ui/infinite_loops.rs
index fcd1f795fff..9b8c3933197 100644
--- a/src/tools/clippy/tests/ui/infinite_loops.rs
+++ b/src/tools/clippy/tests/ui/infinite_loops.rs
@@ -450,4 +450,75 @@ mod issue_12338 {
     }
 }
 
+#[allow(clippy::let_underscore_future, clippy::empty_loop)]
+mod issue_14000 {
+    use super::do_something;
+
+    async fn foo() {
+        let _ = async move {
+            loop {
+                //~^ infinite_loop
+                do_something();
+            }
+        }
+        .await;
+        let _ = async move {
+            loop {
+                //~^ infinite_loop
+                continue;
+            }
+        }
+        .await;
+    }
+
+    fn bar() {
+        let _ = async move {
+            loop {
+                do_something();
+            }
+        };
+
+        let _ = async move {
+            loop {
+                continue;
+            }
+        };
+    }
+}
+
+#[allow(clippy::let_underscore_future)]
+mod tokio_spawn_test {
+    use super::do_something;
+
+    fn install_ticker() {
+        // This should NOT trigger the lint because the async block is spawned, not awaited
+        std::thread::spawn(move || {
+            async move {
+                loop {
+                    // This loop should not trigger infinite_loop lint
+                    do_something();
+                }
+            }
+        });
+    }
+
+    fn spawn_async_block() {
+        // This should NOT trigger the lint because the async block is not awaited
+        let _handle = async move {
+            loop {
+                do_something();
+            }
+        };
+    }
+
+    fn await_async_block() {
+        // This SHOULD trigger the lint because the async block is awaited
+        let _ = async move {
+            loop {
+                do_something();
+            }
+        };
+    }
+}
+
 fn main() {}
diff --git a/src/tools/clippy/tests/ui/infinite_loops.stderr b/src/tools/clippy/tests/ui/infinite_loops.stderr
index 4d02636ef4a..4c6b6f725f1 100644
--- a/src/tools/clippy/tests/ui/infinite_loops.stderr
+++ b/src/tools/clippy/tests/ui/infinite_loops.stderr
@@ -311,5 +311,27 @@ help: if this is intentional, consider specifying `!` as function return
 LL | fn continue_outer() -> ! {
    |                     ++++
 
-error: aborting due to 21 previous errors
+error: infinite loop detected
+  --> tests/ui/infinite_loops.rs:459:13
+   |
+LL | /             loop {
+LL | |
+LL | |                 do_something();
+LL | |             }
+   | |_____________^
+   |
+   = help: if this is not intended, try adding a `break` or `return` condition in the loop
+
+error: infinite loop detected
+  --> tests/ui/infinite_loops.rs:466:13
+   |
+LL | /             loop {
+LL | |
+LL | |                 continue;
+LL | |             }
+   | |_____________^
+   |
+   = help: if this is not intended, try adding a `break` or `return` condition in the loop
+
+error: aborting due to 23 previous errors
 
diff --git a/src/tools/clippy/tests/ui/match_bool.fixed b/src/tools/clippy/tests/ui/match_bool.fixed
index 1dfb82db120..876ae935afd 100644
--- a/src/tools/clippy/tests/ui/match_bool.fixed
+++ b/src/tools/clippy/tests/ui/match_bool.fixed
@@ -61,4 +61,17 @@ fn issue14099() {
     } }
 }
 
+fn issue15351() {
+    let mut d = false;
+    match d {
+        false => println!("foo"),
+        ref mut d => *d = false,
+    }
+
+    match d {
+        false => println!("foo"),
+        e => println!("{e}"),
+    }
+}
+
 fn main() {}
diff --git a/src/tools/clippy/tests/ui/match_bool.rs b/src/tools/clippy/tests/ui/match_bool.rs
index 719b4e51eb6..a134ad8346e 100644
--- a/src/tools/clippy/tests/ui/match_bool.rs
+++ b/src/tools/clippy/tests/ui/match_bool.rs
@@ -113,4 +113,17 @@ fn issue14099() {
     }
 }
 
+fn issue15351() {
+    let mut d = false;
+    match d {
+        false => println!("foo"),
+        ref mut d => *d = false,
+    }
+
+    match d {
+        false => println!("foo"),
+        e => println!("{e}"),
+    }
+}
+
 fn main() {}
diff --git a/src/tools/clippy/tests/ui/match_ref_pats.fixed b/src/tools/clippy/tests/ui/match_ref_pats.fixed
index 8add3da0c99..f727546838b 100644
--- a/src/tools/clippy/tests/ui/match_ref_pats.fixed
+++ b/src/tools/clippy/tests/ui/match_ref_pats.fixed
@@ -1,6 +1,12 @@
 #![warn(clippy::match_ref_pats)]
 #![allow(dead_code, unused_variables)]
-#![allow(clippy::enum_variant_names, clippy::equatable_if_let, clippy::uninlined_format_args)]
+#![allow(
+    clippy::enum_variant_names,
+    clippy::equatable_if_let,
+    clippy::uninlined_format_args,
+    clippy::empty_loop,
+    clippy::diverging_sub_expression
+)]
 
 fn ref_pats() {
     {
@@ -120,4 +126,32 @@ mod issue_7740 {
     }
 }
 
+mod issue15378 {
+    fn never_in_match() {
+        match unimplemented!() {
+            &_ => {},
+            &&&42 => {
+                todo!()
+            },
+            _ => {},
+        }
+
+        match panic!() {
+            &_ => {},
+            &&&42 => {
+                todo!()
+            },
+            _ => {},
+        }
+
+        match loop {} {
+            &_ => {},
+            &&&42 => {
+                todo!()
+            },
+            _ => {},
+        }
+    }
+}
+
 fn main() {}
diff --git a/src/tools/clippy/tests/ui/match_ref_pats.rs b/src/tools/clippy/tests/ui/match_ref_pats.rs
index 07889b0dfc2..eca4d584acd 100644
--- a/src/tools/clippy/tests/ui/match_ref_pats.rs
+++ b/src/tools/clippy/tests/ui/match_ref_pats.rs
@@ -1,6 +1,12 @@
 #![warn(clippy::match_ref_pats)]
 #![allow(dead_code, unused_variables)]
-#![allow(clippy::enum_variant_names, clippy::equatable_if_let, clippy::uninlined_format_args)]
+#![allow(
+    clippy::enum_variant_names,
+    clippy::equatable_if_let,
+    clippy::uninlined_format_args,
+    clippy::empty_loop,
+    clippy::diverging_sub_expression
+)]
 
 fn ref_pats() {
     {
@@ -120,4 +126,32 @@ mod issue_7740 {
     }
 }
 
+mod issue15378 {
+    fn never_in_match() {
+        match unimplemented!() {
+            &_ => {},
+            &&&42 => {
+                todo!()
+            },
+            _ => {},
+        }
+
+        match panic!() {
+            &_ => {},
+            &&&42 => {
+                todo!()
+            },
+            _ => {},
+        }
+
+        match loop {} {
+            &_ => {},
+            &&&42 => {
+                todo!()
+            },
+            _ => {},
+        }
+    }
+}
+
 fn main() {}
diff --git a/src/tools/clippy/tests/ui/match_ref_pats.stderr b/src/tools/clippy/tests/ui/match_ref_pats.stderr
index f81b290b32c..ecb08e6972d 100644
--- a/src/tools/clippy/tests/ui/match_ref_pats.stderr
+++ b/src/tools/clippy/tests/ui/match_ref_pats.stderr
@@ -1,5 +1,5 @@
 error: you don't need to add `&` to all patterns
-  --> tests/ui/match_ref_pats.rs:8:9
+  --> tests/ui/match_ref_pats.rs:14:9
    |
 LL | /         match v {
 LL | |
@@ -19,7 +19,7 @@ LL ~             None => println!("none"),
    |
 
 error: you don't need to add `&` to both the expression and the patterns
-  --> tests/ui/match_ref_pats.rs:26:5
+  --> tests/ui/match_ref_pats.rs:32:5
    |
 LL | /     match &w {
 LL | |
@@ -37,7 +37,7 @@ LL ~         None => println!("none"),
    |
 
 error: redundant pattern matching, consider using `is_none()`
-  --> tests/ui/match_ref_pats.rs:39:12
+  --> tests/ui/match_ref_pats.rs:45:12
    |
 LL |     if let &None = a {
    |     -------^^^^^---- help: try: `if a.is_none()`
@@ -46,13 +46,13 @@ LL |     if let &None = a {
    = help: to override `-D warnings` add `#[allow(clippy::redundant_pattern_matching)]`
 
 error: redundant pattern matching, consider using `is_none()`
-  --> tests/ui/match_ref_pats.rs:45:12
+  --> tests/ui/match_ref_pats.rs:51:12
    |
 LL |     if let &None = &b {
    |     -------^^^^^----- help: try: `if b.is_none()`
 
 error: you don't need to add `&` to all patterns
-  --> tests/ui/match_ref_pats.rs:106:9
+  --> tests/ui/match_ref_pats.rs:112:9
    |
 LL | /         match foobar_variant!(0) {
 LL | |
diff --git a/src/tools/clippy/tests/ui/ptr_as_ptr.fixed b/src/tools/clippy/tests/ui/ptr_as_ptr.fixed
index 71fea6144e7..78e1ceb480a 100644
--- a/src/tools/clippy/tests/ui/ptr_as_ptr.fixed
+++ b/src/tools/clippy/tests/ui/ptr_as_ptr.fixed
@@ -2,8 +2,8 @@
 
 #![warn(clippy::ptr_as_ptr)]
 
-#[macro_use]
 extern crate proc_macros;
+use proc_macros::{external, inline_macros, with_span};
 
 mod issue_11278_a {
     #[derive(Debug)]
@@ -53,11 +53,13 @@ fn main() {
     //~^ ptr_as_ptr
 
     // Make sure the lint is triggered inside a macro
-    let _ = inline!($ptr.cast::<i32>());
-    //~^ ptr_as_ptr
+    // FIXME: `is_from_proc_macro` incorrectly stops the lint from firing here
+    let _ = inline!($ptr as *const i32);
 
     // Do not lint inside macros from external crates
     let _ = external!($ptr as *const i32);
+
+    let _ = with_span!(expr $ptr as *const i32);
 }
 
 #[clippy::msrv = "1.37"]
diff --git a/src/tools/clippy/tests/ui/ptr_as_ptr.rs b/src/tools/clippy/tests/ui/ptr_as_ptr.rs
index 4d507592a1e..70732cf0a6c 100644
--- a/src/tools/clippy/tests/ui/ptr_as_ptr.rs
+++ b/src/tools/clippy/tests/ui/ptr_as_ptr.rs
@@ -2,8 +2,8 @@
 
 #![warn(clippy::ptr_as_ptr)]
 
-#[macro_use]
 extern crate proc_macros;
+use proc_macros::{external, inline_macros, with_span};
 
 mod issue_11278_a {
     #[derive(Debug)]
@@ -53,11 +53,13 @@ fn main() {
     //~^ ptr_as_ptr
 
     // Make sure the lint is triggered inside a macro
+    // FIXME: `is_from_proc_macro` incorrectly stops the lint from firing here
     let _ = inline!($ptr as *const i32);
-    //~^ ptr_as_ptr
 
     // Do not lint inside macros from external crates
     let _ = external!($ptr as *const i32);
+
+    let _ = with_span!(expr $ptr as *const i32);
 }
 
 #[clippy::msrv = "1.37"]
diff --git a/src/tools/clippy/tests/ui/ptr_as_ptr.stderr b/src/tools/clippy/tests/ui/ptr_as_ptr.stderr
index adad159bb0f..c0a2a4b6d20 100644
--- a/src/tools/clippy/tests/ui/ptr_as_ptr.stderr
+++ b/src/tools/clippy/tests/ui/ptr_as_ptr.stderr
@@ -38,174 +38,166 @@ LL |     let _: *mut i32 = mut_ptr as _;
    |                       ^^^^^^^^^^^^ help: try `pointer::cast`, a safer alternative: `mut_ptr.cast()`
 
 error: `as` casting between raw pointers without changing their constness
-  --> tests/ui/ptr_as_ptr.rs:56:21
-   |
-LL |     let _ = inline!($ptr as *const i32);
-   |                     ^^^^^^^^^^^^^^^^^^ help: try `pointer::cast`, a safer alternative: `$ptr.cast::<i32>()`
-   |
-   = note: this error originates in the macro `__inline_mac_fn_main` (in Nightly builds, run with -Z macro-backtrace for more info)
-
-error: `as` casting between raw pointers without changing their constness
-  --> tests/ui/ptr_as_ptr.rs:78:13
+  --> tests/ui/ptr_as_ptr.rs:80:13
    |
 LL |     let _ = ptr as *const i32;
    |             ^^^^^^^^^^^^^^^^^ help: try `pointer::cast`, a safer alternative: `ptr.cast::<i32>()`
 
 error: `as` casting between raw pointers without changing their constness
-  --> tests/ui/ptr_as_ptr.rs:80:13
+  --> tests/ui/ptr_as_ptr.rs:82:13
    |
 LL |     let _ = mut_ptr as *mut i32;
    |             ^^^^^^^^^^^^^^^^^^^ help: try `pointer::cast`, a safer alternative: `mut_ptr.cast::<i32>()`
 
 error: `as` casting between raw pointers without changing their constness
-  --> tests/ui/ptr_as_ptr.rs:88:9
+  --> tests/ui/ptr_as_ptr.rs:90:9
    |
 LL |         ptr::null_mut() as *mut u32
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try call directly: `ptr::null_mut::<u32>()`
 
 error: `as` casting between raw pointers without changing their constness
-  --> tests/ui/ptr_as_ptr.rs:93:9
+  --> tests/ui/ptr_as_ptr.rs:95:9
    |
 LL |         std::ptr::null_mut() as *mut u32
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try call directly: `std::ptr::null_mut::<u32>()`
 
 error: `as` casting between raw pointers without changing their constness
-  --> tests/ui/ptr_as_ptr.rs:99:9
+  --> tests/ui/ptr_as_ptr.rs:101:9
    |
 LL |         ptr::null_mut() as *mut u32
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try call directly: `ptr::null_mut::<u32>()`
 
 error: `as` casting between raw pointers without changing their constness
-  --> tests/ui/ptr_as_ptr.rs:104:9
+  --> tests/ui/ptr_as_ptr.rs:106:9
    |
 LL |         core::ptr::null_mut() as *mut u32
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try call directly: `core::ptr::null_mut::<u32>()`
 
 error: `as` casting between raw pointers without changing their constness
-  --> tests/ui/ptr_as_ptr.rs:110:9
+  --> tests/ui/ptr_as_ptr.rs:112:9
    |
 LL |         ptr::null() as *const u32
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^ help: try call directly: `ptr::null::<u32>()`
 
 error: `as` casting between raw pointers without changing their constness
-  --> tests/ui/ptr_as_ptr.rs:115:9
+  --> tests/ui/ptr_as_ptr.rs:117:9
    |
 LL |         std::ptr::null() as *const u32
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try call directly: `std::ptr::null::<u32>()`
 
 error: `as` casting between raw pointers without changing their constness
-  --> tests/ui/ptr_as_ptr.rs:121:9
+  --> tests/ui/ptr_as_ptr.rs:123:9
    |
 LL |         ptr::null() as *const u32
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^ help: try call directly: `ptr::null::<u32>()`
 
 error: `as` casting between raw pointers without changing their constness
-  --> tests/ui/ptr_as_ptr.rs:126:9
+  --> tests/ui/ptr_as_ptr.rs:128:9
    |
 LL |         core::ptr::null() as *const u32
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try call directly: `core::ptr::null::<u32>()`
 
 error: `as` casting between raw pointers without changing their constness
-  --> tests/ui/ptr_as_ptr.rs:134:9
+  --> tests/ui/ptr_as_ptr.rs:136:9
    |
 LL |         ptr::null_mut() as *mut _
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^ help: try call directly: `ptr::null_mut()`
 
 error: `as` casting between raw pointers without changing their constness
-  --> tests/ui/ptr_as_ptr.rs:139:9
+  --> tests/ui/ptr_as_ptr.rs:141:9
    |
 LL |         std::ptr::null_mut() as *mut _
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try call directly: `std::ptr::null_mut()`
 
 error: `as` casting between raw pointers without changing their constness
-  --> tests/ui/ptr_as_ptr.rs:145:9
+  --> tests/ui/ptr_as_ptr.rs:147:9
    |
 LL |         ptr::null_mut() as *mut _
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^ help: try call directly: `ptr::null_mut()`
 
 error: `as` casting between raw pointers without changing their constness
-  --> tests/ui/ptr_as_ptr.rs:150:9
+  --> tests/ui/ptr_as_ptr.rs:152:9
    |
 LL |         core::ptr::null_mut() as *mut _
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try call directly: `core::ptr::null_mut()`
 
 error: `as` casting between raw pointers without changing their constness
-  --> tests/ui/ptr_as_ptr.rs:156:9
+  --> tests/ui/ptr_as_ptr.rs:158:9
    |
 LL |         ptr::null() as *const _
    |         ^^^^^^^^^^^^^^^^^^^^^^^ help: try call directly: `ptr::null()`
 
 error: `as` casting between raw pointers without changing their constness
-  --> tests/ui/ptr_as_ptr.rs:161:9
+  --> tests/ui/ptr_as_ptr.rs:163:9
    |
 LL |         std::ptr::null() as *const _
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try call directly: `std::ptr::null()`
 
 error: `as` casting between raw pointers without changing their constness
-  --> tests/ui/ptr_as_ptr.rs:167:9
+  --> tests/ui/ptr_as_ptr.rs:169:9
    |
 LL |         ptr::null() as *const _
    |         ^^^^^^^^^^^^^^^^^^^^^^^ help: try call directly: `ptr::null()`
 
 error: `as` casting between raw pointers without changing their constness
-  --> tests/ui/ptr_as_ptr.rs:172:9
+  --> tests/ui/ptr_as_ptr.rs:174:9
    |
 LL |         core::ptr::null() as *const _
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try call directly: `core::ptr::null()`
 
 error: `as` casting between raw pointers without changing their constness
-  --> tests/ui/ptr_as_ptr.rs:180:9
+  --> tests/ui/ptr_as_ptr.rs:182:9
    |
 LL |         ptr::null_mut() as _
    |         ^^^^^^^^^^^^^^^^^^^^ help: try call directly: `ptr::null_mut()`
 
 error: `as` casting between raw pointers without changing their constness
-  --> tests/ui/ptr_as_ptr.rs:185:9
+  --> tests/ui/ptr_as_ptr.rs:187:9
    |
 LL |         std::ptr::null_mut() as _
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^ help: try call directly: `std::ptr::null_mut()`
 
 error: `as` casting between raw pointers without changing their constness
-  --> tests/ui/ptr_as_ptr.rs:191:9
+  --> tests/ui/ptr_as_ptr.rs:193:9
    |
 LL |         ptr::null_mut() as _
    |         ^^^^^^^^^^^^^^^^^^^^ help: try call directly: `ptr::null_mut()`
 
 error: `as` casting between raw pointers without changing their constness
-  --> tests/ui/ptr_as_ptr.rs:196:9
+  --> tests/ui/ptr_as_ptr.rs:198:9
    |
 LL |         core::ptr::null_mut() as _
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try call directly: `core::ptr::null_mut()`
 
 error: `as` casting between raw pointers without changing their constness
-  --> tests/ui/ptr_as_ptr.rs:202:9
+  --> tests/ui/ptr_as_ptr.rs:204:9
    |
 LL |         ptr::null() as _
    |         ^^^^^^^^^^^^^^^^ help: try call directly: `ptr::null()`
 
 error: `as` casting between raw pointers without changing their constness
-  --> tests/ui/ptr_as_ptr.rs:207:9
+  --> tests/ui/ptr_as_ptr.rs:209:9
    |
 LL |         std::ptr::null() as _
    |         ^^^^^^^^^^^^^^^^^^^^^ help: try call directly: `std::ptr::null()`
 
 error: `as` casting between raw pointers without changing their constness
-  --> tests/ui/ptr_as_ptr.rs:213:9
+  --> tests/ui/ptr_as_ptr.rs:215:9
    |
 LL |         ptr::null() as _
    |         ^^^^^^^^^^^^^^^^ help: try call directly: `ptr::null()`
 
 error: `as` casting between raw pointers without changing their constness
-  --> tests/ui/ptr_as_ptr.rs:218:9
+  --> tests/ui/ptr_as_ptr.rs:220:9
    |
 LL |         core::ptr::null() as _
    |         ^^^^^^^^^^^^^^^^^^^^^^ help: try call directly: `core::ptr::null()`
 
 error: `as` casting between raw pointers without changing their constness
-  --> tests/ui/ptr_as_ptr.rs:226:43
+  --> tests/ui/ptr_as_ptr.rs:228:43
    |
 LL |         let _: fn() = std::mem::transmute(std::ptr::null::<()>() as *const u8);
    |                                           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try call directly: `std::ptr::null::<u8>()`
 
-error: aborting due to 34 previous errors
+error: aborting due to 33 previous errors
 
diff --git a/src/tools/clippy/tests/ui/similar_names.rs b/src/tools/clippy/tests/ui/similar_names.rs
index 69b6ab6220b..55a141209f0 100644
--- a/src/tools/clippy/tests/ui/similar_names.rs
+++ b/src/tools/clippy/tests/ui/similar_names.rs
@@ -89,6 +89,10 @@ fn main() {
 
     let iter: i32;
     let item: i32;
+
+    // 3 letter names are allowed to be similar
+    let kta: i32;
+    let ktv: i32;
 }
 
 fn foo() {
diff --git a/src/tools/clippy/tests/ui/similar_names.stderr b/src/tools/clippy/tests/ui/similar_names.stderr
index 8d722fb8b56..c226f73d4db 100644
--- a/src/tools/clippy/tests/ui/similar_names.stderr
+++ b/src/tools/clippy/tests/ui/similar_names.stderr
@@ -49,13 +49,13 @@ LL |     let parser: i32;
    |         ^^^^^^
 
 error: binding's name is too similar to existing binding
-  --> tests/ui/similar_names.rs:98:16
+  --> tests/ui/similar_names.rs:102:16
    |
 LL |         bpple: sprang,
    |                ^^^^^^
    |
 note: existing binding defined here
-  --> tests/ui/similar_names.rs:97:16
+  --> tests/ui/similar_names.rs:101:16
    |
 LL |         apple: spring,
    |                ^^^^^^
diff --git a/src/tools/clippy/tests/ui/unnecessary_operation.fixed b/src/tools/clippy/tests/ui/unnecessary_operation.fixed
index ac9fa4de20a..db5409bc491 100644
--- a/src/tools/clippy/tests/ui/unnecessary_operation.fixed
+++ b/src/tools/clippy/tests/ui/unnecessary_operation.fixed
@@ -78,25 +78,25 @@ fn main() {
     //~^ unnecessary_operation
     get_number();
     //~^ unnecessary_operation
-    5;get_number();
+    5; get_number();
     //~^ unnecessary_operation
     get_number();
     //~^ unnecessary_operation
     get_number();
     //~^ unnecessary_operation
-    5;6;get_number();
+    5; 6; get_number();
     //~^ unnecessary_operation
     get_number();
     //~^ unnecessary_operation
     get_number();
     //~^ unnecessary_operation
-    5;get_number();
+    5; get_number();
     //~^ unnecessary_operation
-    42;get_number();
+    42; get_number();
     //~^ unnecessary_operation
     assert!([42, 55].len() > get_usize());
     //~^ unnecessary_operation
-    42;get_number();
+    42; get_number();
     //~^ unnecessary_operation
     get_number();
     //~^ unnecessary_operation
diff --git a/src/tools/clippy/tests/ui/unnecessary_operation.stderr b/src/tools/clippy/tests/ui/unnecessary_operation.stderr
index 0fda1dfde19..3439ba2e33e 100644
--- a/src/tools/clippy/tests/ui/unnecessary_operation.stderr
+++ b/src/tools/clippy/tests/ui/unnecessary_operation.stderr
@@ -35,7 +35,7 @@ error: unnecessary operation
   --> tests/ui/unnecessary_operation.rs:81:5
    |
 LL |     5 + get_number();
-   |     ^^^^^^^^^^^^^^^^^ help: statement can be reduced to: `5;get_number();`
+   |     ^^^^^^^^^^^^^^^^^ help: statement can be reduced to: `5; get_number();`
 
 error: unnecessary operation
   --> tests/ui/unnecessary_operation.rs:83:5
@@ -53,7 +53,7 @@ error: unnecessary operation
   --> tests/ui/unnecessary_operation.rs:87:5
    |
 LL |     (5, 6, get_number());
-   |     ^^^^^^^^^^^^^^^^^^^^^ help: statement can be reduced to: `5;6;get_number();`
+   |     ^^^^^^^^^^^^^^^^^^^^^ help: statement can be reduced to: `5; 6; get_number();`
 
 error: unnecessary operation
   --> tests/ui/unnecessary_operation.rs:89:5
@@ -71,13 +71,13 @@ error: unnecessary operation
   --> tests/ui/unnecessary_operation.rs:93:5
    |
 LL |     5..get_number();
-   |     ^^^^^^^^^^^^^^^^ help: statement can be reduced to: `5;get_number();`
+   |     ^^^^^^^^^^^^^^^^ help: statement can be reduced to: `5; get_number();`
 
 error: unnecessary operation
   --> tests/ui/unnecessary_operation.rs:95:5
    |
 LL |     [42, get_number()];
-   |     ^^^^^^^^^^^^^^^^^^^ help: statement can be reduced to: `42;get_number();`
+   |     ^^^^^^^^^^^^^^^^^^^ help: statement can be reduced to: `42; get_number();`
 
 error: unnecessary operation
   --> tests/ui/unnecessary_operation.rs:97:5
@@ -89,7 +89,7 @@ error: unnecessary operation
   --> tests/ui/unnecessary_operation.rs:99:5
    |
 LL |     (42, get_number()).1;
-   |     ^^^^^^^^^^^^^^^^^^^^^ help: statement can be reduced to: `42;get_number();`
+   |     ^^^^^^^^^^^^^^^^^^^^^ help: statement can be reduced to: `42; get_number();`
 
 error: unnecessary operation
   --> tests/ui/unnecessary_operation.rs:101:5
diff --git a/src/tools/clippy/tests/ui/unnecessary_semicolon.edition2021.fixed b/src/tools/clippy/tests/ui/unnecessary_semicolon.edition2021.fixed
index f10d804c8cc..797f1505f49 100644
--- a/src/tools/clippy/tests/ui/unnecessary_semicolon.edition2021.fixed
+++ b/src/tools/clippy/tests/ui/unnecessary_semicolon.edition2021.fixed
@@ -63,3 +63,12 @@ fn issue14100() -> bool {
     // cast into the `bool` function return type.
     if return true {};
 }
+
+fn issue15426(x: u32) {
+    // removing the `;` would turn the stmt into an expr, but attrs aren't allowed on exprs
+    #[rustfmt::skip]
+    match x {
+        0b00 => {}  0b01 => {}
+        0b11 => {}  _    => {}
+    };
+}
diff --git a/src/tools/clippy/tests/ui/unnecessary_semicolon.edition2024.fixed b/src/tools/clippy/tests/ui/unnecessary_semicolon.edition2024.fixed
index 32a3bb9b408..d2609cea000 100644
--- a/src/tools/clippy/tests/ui/unnecessary_semicolon.edition2024.fixed
+++ b/src/tools/clippy/tests/ui/unnecessary_semicolon.edition2024.fixed
@@ -63,3 +63,12 @@ fn issue14100() -> bool {
     // cast into the `bool` function return type.
     if return true {};
 }
+
+fn issue15426(x: u32) {
+    // removing the `;` would turn the stmt into an expr, but attrs aren't allowed on exprs
+    #[rustfmt::skip]
+    match x {
+        0b00 => {}  0b01 => {}
+        0b11 => {}  _    => {}
+    };
+}
diff --git a/src/tools/clippy/tests/ui/unnecessary_semicolon.rs b/src/tools/clippy/tests/ui/unnecessary_semicolon.rs
index 91b28218022..55f1ec84cb0 100644
--- a/src/tools/clippy/tests/ui/unnecessary_semicolon.rs
+++ b/src/tools/clippy/tests/ui/unnecessary_semicolon.rs
@@ -63,3 +63,12 @@ fn issue14100() -> bool {
     // cast into the `bool` function return type.
     if return true {};
 }
+
+fn issue15426(x: u32) {
+    // removing the `;` would turn the stmt into an expr, but attrs aren't allowed on exprs
+    #[rustfmt::skip]
+    match x {
+        0b00 => {}  0b01 => {}
+        0b11 => {}  _    => {}
+    };
+}
diff --git a/src/tools/clippy/tests/ui/zero_sized_hashmap_values.rs b/src/tools/clippy/tests/ui/zero_sized_hashmap_values.rs
index dcbfd16843d..ee2fd19b5ee 100644
--- a/src/tools/clippy/tests/ui/zero_sized_hashmap_values.rs
+++ b/src/tools/clippy/tests/ui/zero_sized_hashmap_values.rs
@@ -92,6 +92,14 @@ fn issue14822() {
     //~^ zero_sized_map_values
 }
 
+fn issue15429() {
+    struct E<'a>(&'a [E<'a>]);
+
+    // The assertion error happens when the type being evaluated has escaping bound vars
+    // as it cannot be wrapped in a dummy binder during size computation.
+    type F = dyn for<'a> FnOnce(HashMap<u32, E<'a>>) -> u32;
+}
+
 fn main() {
     let _: HashMap<String, ()> = HashMap::new();
     //~^ zero_sized_map_values
diff --git a/src/tools/clippy/tests/ui/zero_sized_hashmap_values.stderr b/src/tools/clippy/tests/ui/zero_sized_hashmap_values.stderr
index d29491fa05c..52ffef280c1 100644
--- a/src/tools/clippy/tests/ui/zero_sized_hashmap_values.stderr
+++ b/src/tools/clippy/tests/ui/zero_sized_hashmap_values.stderr
@@ -89,7 +89,7 @@ LL |     type D = HashMap<u32, S<E>>;
    = help: consider using a set instead
 
 error: map with zero-sized value type
-  --> tests/ui/zero_sized_hashmap_values.rs:96:34
+  --> tests/ui/zero_sized_hashmap_values.rs:104:34
    |
 LL |     let _: HashMap<String, ()> = HashMap::new();
    |                                  ^^^^^^^
@@ -97,7 +97,7 @@ LL |     let _: HashMap<String, ()> = HashMap::new();
    = help: consider using a set instead
 
 error: map with zero-sized value type
-  --> tests/ui/zero_sized_hashmap_values.rs:96:12
+  --> tests/ui/zero_sized_hashmap_values.rs:104:12
    |
 LL |     let _: HashMap<String, ()> = HashMap::new();
    |            ^^^^^^^^^^^^^^^^^^^
@@ -105,7 +105,7 @@ LL |     let _: HashMap<String, ()> = HashMap::new();
    = help: consider using a set instead
 
 error: map with zero-sized value type
-  --> tests/ui/zero_sized_hashmap_values.rs:102:12
+  --> tests/ui/zero_sized_hashmap_values.rs:110:12
    |
 LL |     let _: HashMap<_, _> = std::iter::empty::<(String, ())>().collect();
    |            ^^^^^^^^^^^^^