about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/bootstrap/src/core/builder/cargo.rs5
-rw-r--r--src/bootstrap/src/core/config/config.rs3
-rw-r--r--src/bootstrap/src/core/config/toml/build.rs1
-rw-r--r--src/bootstrap/src/utils/change_tracker.rs5
-rw-r--r--src/librustdoc/html/static/js/rustdoc.d.ts25
-rw-r--r--src/librustdoc/html/static/js/search.js304
-rw-r--r--src/librustdoc/html/static/js/stringdex.d.ts2
-rw-r--r--src/librustdoc/html/static/js/stringdex.js99
-rw-r--r--src/tools/clippy/.github/ISSUE_TEMPLATE/new_lint.yml4
-rw-r--r--src/tools/clippy/.github/PULL_REQUEST_TEMPLATE.md4
-rw-r--r--src/tools/clippy/.github/workflows/feature_freeze.yml45
-rw-r--r--src/tools/clippy/.gitignore3
-rw-r--r--src/tools/clippy/CHANGELOG.md148
-rw-r--r--src/tools/clippy/Cargo.toml2
-rw-r--r--src/tools/clippy/book/src/README.md4
-rw-r--r--src/tools/clippy/book/src/SUMMARY.md1
-rw-r--r--src/tools/clippy/book/src/development/adding_lints.md3
-rw-r--r--src/tools/clippy/book/src/development/feature_freeze.md55
-rw-r--r--src/tools/clippy/clippy_config/Cargo.toml2
-rw-r--r--src/tools/clippy/clippy_lints/Cargo.toml2
-rw-r--r--src/tools/clippy/clippy_lints/src/attrs/useless_attribute.rs1
-rw-r--r--src/tools/clippy/clippy_lints/src/casts/as_underscore.rs8
-rw-r--r--src/tools/clippy/clippy_lints/src/casts/cast_possible_wrap.rs30
-rw-r--r--src/tools/clippy/clippy_lints/src/casts/cast_sign_loss.rs29
-rw-r--r--src/tools/clippy/clippy_lints/src/casts/mod.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/casts/utils.rs15
-rw-r--r--src/tools/clippy/clippy_lints/src/declared_lints.rs5
-rw-r--r--src/tools/clippy/clippy_lints/src/dereference.rs7
-rw-r--r--src/tools/clippy/clippy_lints/src/derive.rs527
-rw-r--r--src/tools/clippy/clippy_lints/src/derive/derive_ord_xor_partial_ord.rs50
-rw-r--r--src/tools/clippy/clippy_lints/src/derive/derive_partial_eq_without_eq.rs87
-rw-r--r--src/tools/clippy/clippy_lints/src/derive/derived_hash_with_manual_eq.rs49
-rw-r--r--src/tools/clippy/clippy_lints/src/derive/expl_impl_clone_on_copy.rs65
-rw-r--r--src/tools/clippy/clippy_lints/src/derive/mod.rs215
-rw-r--r--src/tools/clippy/clippy_lints/src/derive/unsafe_derive_deserialize.rs93
-rw-r--r--src/tools/clippy/clippy_lints/src/disallowed_macros.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/eta_reduction.rs27
-rw-r--r--src/tools/clippy/clippy_lints/src/functions/not_unsafe_ptr_arg_deref.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/functions/ref_option.rs48
-rw-r--r--src/tools/clippy/clippy_lints/src/future_not_send.rs109
-rw-r--r--src/tools/clippy/clippy_lints/src/invalid_upcast_comparisons.rs13
-rw-r--r--src/tools/clippy/clippy_lints/src/len_zero.rs6
-rw-r--r--src/tools/clippy/clippy_lints/src/let_with_type_underscore.rs16
-rw-r--r--src/tools/clippy/clippy_lints/src/lib.rs6
-rw-r--r--src/tools/clippy/clippy_lints/src/lifetimes.rs109
-rw-r--r--src/tools/clippy/clippy_lints/src/loops/explicit_iter_loop.rs6
-rw-r--r--src/tools/clippy/clippy_lints/src/loops/never_loop.rs59
-rw-r--r--src/tools/clippy/clippy_lints/src/manual_abs_diff.rs6
-rw-r--r--src/tools/clippy/clippy_lints/src/manual_option_as_slice.rs6
-rw-r--r--src/tools/clippy/clippy_lints/src/manual_slice_size_calculation.rs3
-rw-r--r--src/tools/clippy/clippy_lints/src/matches/manual_ok_err.rs16
-rw-r--r--src/tools/clippy/clippy_lints/src/matches/manual_utils.rs9
-rw-r--r--src/tools/clippy/clippy_lints/src/matches/needless_match.rs6
-rw-r--r--src/tools/clippy/clippy_lints/src/matches/rest_pat_in_fully_bound_struct.rs10
-rw-r--r--src/tools/clippy/clippy_lints/src/matches/single_match.rs8
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/implicit_clone.rs6
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/inefficient_to_string.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/iter_overeager_cloned.rs5
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/mod.rs75
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/mut_mutex_lock.rs5
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/or_fun_call.rs7
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/ptr_offset_with_cast.rs82
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/unnecessary_to_owned.rs13
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/useless_asref.rs6
-rw-r--r--src/tools/clippy/clippy_lints/src/min_ident_chars.rs6
-rw-r--r--src/tools/clippy/clippy_lints/src/misc.rs118
-rw-r--r--src/tools/clippy/clippy_lints/src/missing_doc.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/multiple_unsafe_ops_per_block.rs8
-rw-r--r--src/tools/clippy/clippy_lints/src/only_used_in_recursion.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/operators/erasing_op.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/ptr_offset_with_cast.rs151
-rw-r--r--src/tools/clippy/clippy_lints/src/question_mark.rs21
-rw-r--r--src/tools/clippy/clippy_lints/src/read_zero_byte_vec.rs27
-rw-r--r--src/tools/clippy/clippy_lints/src/redundant_clone.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/redundant_slicing.rs8
-rw-r--r--src/tools/clippy/clippy_lints/src/returns.rs513
-rw-r--r--src/tools/clippy/clippy_lints/src/returns/let_and_return.rs86
-rw-r--r--src/tools/clippy/clippy_lints/src/returns/mod.rs140
-rw-r--r--src/tools/clippy/clippy_lints/src/returns/needless_return.rs269
-rw-r--r--src/tools/clippy/clippy_lints/src/returns/needless_return_with_question_mark.rs60
-rw-r--r--src/tools/clippy/clippy_lints/src/semicolon_block.rs14
-rw-r--r--src/tools/clippy/clippy_lints/src/size_of_ref.rs5
-rw-r--r--src/tools/clippy/clippy_lints/src/toplevel_ref_arg.rs119
-rw-r--r--src/tools/clippy/clippy_lints/src/transmute/transmute_ptr_to_ref.rs44
-rw-r--r--src/tools/clippy/clippy_lints/src/transmute/transmute_ref_to_ref.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/uninit_vec.rs11
-rw-r--r--src/tools/clippy/clippy_lints/src/unused_peekable.rs6
-rw-r--r--src/tools/clippy/clippy_lints/src/unwrap.rs1
-rw-r--r--src/tools/clippy/clippy_lints/src/use_self.rs81
-rw-r--r--src/tools/clippy/clippy_lints/src/useless_conversion.rs14
-rw-r--r--src/tools/clippy/clippy_utils/Cargo.toml2
-rw-r--r--src/tools/clippy/clippy_utils/README.md2
-rw-r--r--src/tools/clippy/clippy_utils/src/check_proc_macro.rs146
-rw-r--r--src/tools/clippy/clippy_utils/src/lib.rs29
-rw-r--r--src/tools/clippy/clippy_utils/src/msrvs.rs4
-rw-r--r--src/tools/clippy/clippy_utils/src/source.rs5
-rw-r--r--src/tools/clippy/clippy_utils/src/sym.rs1
-rw-r--r--src/tools/clippy/clippy_utils/src/ty/mod.rs88
-rw-r--r--src/tools/clippy/declare_clippy_lint/Cargo.toml2
-rw-r--r--src/tools/clippy/rust-toolchain.toml2
-rw-r--r--src/tools/clippy/tests/no-profile-in-cargo-toml.rs3
-rw-r--r--src/tools/clippy/tests/ui-toml/ref_option/all/clippy.toml (renamed from src/tools/clippy/tests/ui/ref_option/all/clippy.toml)0
-rw-r--r--src/tools/clippy/tests/ui-toml/ref_option/private/clippy.toml (renamed from src/tools/clippy/tests/ui/ref_option/private/clippy.toml)0
-rw-r--r--src/tools/clippy/tests/ui-toml/ref_option/ref_option.all.fixed114
-rw-r--r--src/tools/clippy/tests/ui-toml/ref_option/ref_option.all.stderr (renamed from src/tools/clippy/tests/ui/ref_option/ref_option.all.stderr)68
-rw-r--r--src/tools/clippy/tests/ui-toml/ref_option/ref_option.private.fixed114
-rw-r--r--src/tools/clippy/tests/ui-toml/ref_option/ref_option.private.stderr (renamed from src/tools/clippy/tests/ui/ref_option/ref_option.private.stderr)44
-rw-r--r--src/tools/clippy/tests/ui-toml/ref_option/ref_option.rs114
-rw-r--r--src/tools/clippy/tests/ui-toml/ref_option/ref_option_traits.all.stderr (renamed from src/tools/clippy/tests/ui/ref_option/ref_option_traits.all.stderr)8
-rw-r--r--src/tools/clippy/tests/ui-toml/ref_option/ref_option_traits.private.stderr (renamed from src/tools/clippy/tests/ui/ref_option/ref_option_traits.private.stderr)4
-rw-r--r--src/tools/clippy/tests/ui-toml/ref_option/ref_option_traits.rs71
-rw-r--r--src/tools/clippy/tests/ui/as_underscore_unfixable.rs14
-rw-r--r--src/tools/clippy/tests/ui/as_underscore_unfixable.stderr20
-rw-r--r--src/tools/clippy/tests/ui/cast.rs13
-rw-r--r--src/tools/clippy/tests/ui/cast.stderr96
-rw-r--r--src/tools/clippy/tests/ui/checked_unwrap/simple_conditionals.rs22
-rw-r--r--src/tools/clippy/tests/ui/checked_unwrap/simple_conditionals.stderr36
-rw-r--r--src/tools/clippy/tests/ui/crashes/ice-15657.rs11
-rw-r--r--src/tools/clippy/tests/ui/crashes/ice-15666.fixed6
-rw-r--r--src/tools/clippy/tests/ui/crashes/ice-15666.rs6
-rw-r--r--src/tools/clippy/tests/ui/crashes/ice-15666.stderr16
-rw-r--r--src/tools/clippy/tests/ui/elidable_lifetime_names.fixed82
-rw-r--r--src/tools/clippy/tests/ui/elidable_lifetime_names.rs82
-rw-r--r--src/tools/clippy/tests/ui/elidable_lifetime_names.stderr146
-rw-r--r--src/tools/clippy/tests/ui/eta.fixed8
-rw-r--r--src/tools/clippy/tests/ui/eta.rs8
-rw-r--r--src/tools/clippy/tests/ui/invalid_upcast_comparisons.rs12
-rw-r--r--src/tools/clippy/tests/ui/invalid_upcast_comparisons.stderr8
-rw-r--r--src/tools/clippy/tests/ui/iter_overeager_cloned.fixed12
-rw-r--r--src/tools/clippy/tests/ui/iter_overeager_cloned.rs12
-rw-r--r--src/tools/clippy/tests/ui/iter_overeager_cloned.stderr4
-rw-r--r--src/tools/clippy/tests/ui/match_as_ref.fixed30
-rw-r--r--src/tools/clippy/tests/ui/match_as_ref.rs30
-rw-r--r--src/tools/clippy/tests/ui/multiple_unsafe_ops_per_block.rs119
-rw-r--r--src/tools/clippy/tests/ui/multiple_unsafe_ops_per_block.stderr143
-rw-r--r--src/tools/clippy/tests/ui/needless_return.fixed7
-rw-r--r--src/tools/clippy/tests/ui/needless_return.rs7
-rw-r--r--src/tools/clippy/tests/ui/never_loop.rs24
-rw-r--r--src/tools/clippy/tests/ui/never_loop.stderr97
-rw-r--r--src/tools/clippy/tests/ui/option_if_let_else.fixed10
-rw-r--r--src/tools/clippy/tests/ui/option_if_let_else.rs16
-rw-r--r--src/tools/clippy/tests/ui/option_if_let_else.stderr50
-rw-r--r--src/tools/clippy/tests/ui/or_fun_call.fixed16
-rw-r--r--src/tools/clippy/tests/ui/or_fun_call.rs22
-rw-r--r--src/tools/clippy/tests/ui/or_fun_call.stderr88
-rw-r--r--src/tools/clippy/tests/ui/ptr_offset_with_cast.fixed22
-rw-r--r--src/tools/clippy/tests/ui/ptr_offset_with_cast.rs22
-rw-r--r--src/tools/clippy/tests/ui/ptr_offset_with_cast.stderr41
-rw-r--r--src/tools/clippy/tests/ui/question_mark.fixed14
-rw-r--r--src/tools/clippy/tests/ui/question_mark.rs26
-rw-r--r--src/tools/clippy/tests/ui/question_mark.stderr92
-rw-r--r--src/tools/clippy/tests/ui/read_zero_byte_vec.rs27
-rw-r--r--src/tools/clippy/tests/ui/read_zero_byte_vec.stderr65
-rw-r--r--src/tools/clippy/tests/ui/ref_option/ref_option.all.fixed79
-rw-r--r--src/tools/clippy/tests/ui/ref_option/ref_option.private.fixed79
-rw-r--r--src/tools/clippy/tests/ui/ref_option/ref_option.rs79
-rw-r--r--src/tools/clippy/tests/ui/ref_option/ref_option_traits.rs40
-rw-r--r--src/tools/clippy/tests/ui/rest_pat_in_fully_bound_structs.fixed61
-rw-r--r--src/tools/clippy/tests/ui/rest_pat_in_fully_bound_structs.stderr18
-rw-r--r--src/tools/clippy/tests/ui/semicolon_inside_block.fixed17
-rw-r--r--src/tools/clippy/tests/ui/semicolon_inside_block.rs17
-rw-r--r--src/tools/clippy/tests/ui/semicolon_inside_block.stderr8
-rw-r--r--src/tools/clippy/tests/ui/track-diagnostics-clippy.stderr2
-rw-r--r--src/tools/clippy/tests/ui/transmute_ptr_to_ref.fixed39
-rw-r--r--src/tools/clippy/tests/ui/transmute_ptr_to_ref.rs39
-rw-r--r--src/tools/clippy/tests/ui/transmute_ptr_to_ref.stderr54
-rw-r--r--src/tools/clippy/tests/ui/use_self.fixed18
-rw-r--r--src/tools/clippy/tests/ui/use_self.rs16
-rw-r--r--src/tools/clippy/tests/ui/use_self.stderr8
-rw-r--r--src/tools/clippy/tests/ui/useless_attribute.fixed10
-rw-r--r--src/tools/clippy/tests/ui/useless_attribute.rs10
171 files changed, 4679 insertions, 2614 deletions
diff --git a/src/bootstrap/src/core/builder/cargo.rs b/src/bootstrap/src/core/builder/cargo.rs
index 6121bf7d9cd..ee2bb710674 100644
--- a/src/bootstrap/src/core/builder/cargo.rs
+++ b/src/bootstrap/src/core/builder/cargo.rs
@@ -1227,6 +1227,11 @@ impl Builder<'_> {
             rustflags.arg("-Zehcont-guard");
         }
 
+        // Optionally override the rc.exe when compiling rustc on Windows.
+        if let Some(windows_rc) = &self.config.windows_rc {
+            cargo.env("RUSTC_WINDOWS_RC", windows_rc);
+        }
+
         // For `cargo doc` invocations, make rustdoc print the Rust version into the docs
         // This replaces spaces with tabs because RUSTDOCFLAGS does not
         // support arguments with regular spaces. Hopefully someday Cargo will
diff --git a/src/bootstrap/src/core/config/config.rs b/src/bootstrap/src/core/config/config.rs
index efb7ad91699..a97399b3d4a 100644
--- a/src/bootstrap/src/core/config/config.rs
+++ b/src/bootstrap/src/core/config/config.rs
@@ -273,6 +273,7 @@ pub struct Config {
     pub gdb: Option<PathBuf>,
     pub lldb: Option<PathBuf>,
     pub python: Option<PathBuf>,
+    pub windows_rc: Option<PathBuf>,
     pub reuse: Option<PathBuf>,
     pub cargo_native_static: bool,
     pub configure_args: Vec<String>,
@@ -450,6 +451,7 @@ impl Config {
             nodejs: build_nodejs,
             npm: build_npm,
             python: build_python,
+            windows_rc: build_windows_rc,
             reuse: build_reuse,
             locked_deps: build_locked_deps,
             vendor: build_vendor,
@@ -1342,6 +1344,7 @@ impl Config {
                 .unwrap_or(rust_debug == Some(true)),
             vendor,
             verbose_tests,
+            windows_rc: build_windows_rc.map(PathBuf::from),
             // tidy-alphabetical-end
         }
     }
diff --git a/src/bootstrap/src/core/config/toml/build.rs b/src/bootstrap/src/core/config/toml/build.rs
index 25c19f1070a..a9d4d3961c9 100644
--- a/src/bootstrap/src/core/config/toml/build.rs
+++ b/src/bootstrap/src/core/config/toml/build.rs
@@ -37,6 +37,7 @@ define_config! {
         nodejs: Option<String> = "nodejs",
         npm: Option<String> = "npm",
         python: Option<String> = "python",
+        windows_rc: Option<String> = "windows-rc",
         reuse: Option<String> = "reuse",
         locked_deps: Option<bool> = "locked-deps",
         vendor: Option<bool> = "vendor",
diff --git a/src/bootstrap/src/utils/change_tracker.rs b/src/bootstrap/src/utils/change_tracker.rs
index 2c48cebd2df..6b187578c31 100644
--- a/src/bootstrap/src/utils/change_tracker.rs
+++ b/src/bootstrap/src/utils/change_tracker.rs
@@ -551,4 +551,9 @@ pub const CONFIG_CHANGE_HISTORY: &[ChangeInfo] = &[
         severity: ChangeSeverity::Info,
         summary: "There is now a bootstrap option called `rust.parallel-frontend-threads`, which can be used to set the number of threads for the compiler frontend used during compilation of Rust code.",
     },
+    ChangeInfo {
+        change_id: 146663,
+        severity: ChangeSeverity::Info,
+        summary: "New option `build.windows-rc` that will override which resource compiler on Windows will be used to compile Rust.",
+    },
 ];
diff --git a/src/librustdoc/html/static/js/rustdoc.d.ts b/src/librustdoc/html/static/js/rustdoc.d.ts
index 938ccc7d2c3..951eb2291b8 100644
--- a/src/librustdoc/html/static/js/rustdoc.d.ts
+++ b/src/librustdoc/html/static/js/rustdoc.d.ts
@@ -348,7 +348,7 @@ declare namespace rustdoc {
         returned: rustdoc.QueryElement[],
         is_alias: boolean,
         alias?: string,
-        original?: rustdoc.Rlow,
+        item: rustdoc.Row,
     }
 
     /**
@@ -533,4 +533,27 @@ declare namespace rustdoc {
      * Generated by `render_call_locations` in `render/mod.rs`.
      */
     type ScrapedLoc = [[number, number], string, string]
+
+    /**
+     * Each of these identifiers are used specially by
+     * type-driven search. Most of them are lang items
+     * in the compiler.
+     */
+    type TypeNameIds = {
+        "typeNameIdOfOutput": number,
+        "typeNameIdOfFnPtr": number,
+        "typeNameIdOfFn": number,
+        "typeNameIdOfFnMut": number,
+        "typeNameIdOfFnOnce": number,
+        "typeNameIdOfArray": number,
+        "typeNameIdOfSlice": number,
+        "typeNameIdOfArrayOrSlice": number,
+        "typeNameIdOfTuple": number,
+        "typeNameIdOfUnit": number,
+        "typeNameIdOfTupleOrUnit": number,
+        "typeNameIdOfReference": number,
+        "typeNameIdOfPointer": number,
+        "typeNameIdOfHof": number,
+        "typeNameIdOfNever": number,
+    };
 }
diff --git a/src/librustdoc/html/static/js/search.js b/src/librustdoc/html/static/js/search.js
index 3b84ae2bed0..482134933a6 100644
--- a/src/librustdoc/html/static/js/search.js
+++ b/src/librustdoc/html/static/js/search.js
@@ -1190,17 +1190,6 @@ class DocSearch {
         this.rootPath = rootPath;
         this.database = database;
 
-        this.typeNameIdOfOutput = -1;
-        this.typeNameIdOfArray = -1;
-        this.typeNameIdOfSlice = -1;
-        this.typeNameIdOfArrayOrSlice = -1;
-        this.typeNameIdOfTuple = -1;
-        this.typeNameIdOfUnit = -1;
-        this.typeNameIdOfTupleOrUnit = -1;
-        this.typeNameIdOfReference = -1;
-        this.typeNameIdOfPointer = -1;
-        this.typeNameIdOfHof = -1;
-
         this.utf8decoder = new TextDecoder();
 
         /** @type {Map<number|null, rustdoc.FunctionType>} */
@@ -1208,14 +1197,49 @@ class DocSearch {
     }
 
     /**
-     * Load search index. If you do not call this function, `execQuery`
-     * will never fulfill.
+     * Load type name ID set.
+     *
+     * Each of these identifiers are used specially by
+     * type-driven search. Most of them are lang items
+     * in the compiler.
+     *
+     * Use this function, which caches the result, and not
+     * getTypeNameIdsAsync, which is an internal implementation
+     * detail for this.
+     *
+     * @return {Promise<rustdoc.TypeNameIds>|rustdoc.TypeNameIds}
      */
-    async buildIndex() {
+    getTypeNameIds() {
+        if (this.typeNameIds) {
+            return this.typeNameIds;
+        }
         const nn = this.database.getData("normalizedName");
         if (!nn) {
-            return;
+            return {
+                typeNameIdOfOutput: -1,
+                typeNameIdOfFnPtr: -1,
+                typeNameIdOfFn: -1,
+                typeNameIdOfFnMut: -1,
+                typeNameIdOfFnOnce: -1,
+                typeNameIdOfArray: -1,
+                typeNameIdOfSlice: -1,
+                typeNameIdOfArrayOrSlice: -1,
+                typeNameIdOfTuple: -1,
+                typeNameIdOfUnit: -1,
+                typeNameIdOfTupleOrUnit: -1,
+                typeNameIdOfReference: -1,
+                typeNameIdOfPointer: -1,
+                typeNameIdOfHof: -1,
+                typeNameIdOfNever: -1,
+            };
         }
+        return this.getTypeNameIdsAsync(nn);
+    }
+    /**
+     * @param {stringdex.DataColumn} nn
+     * @returns {Promise<rustdoc.TypeNameIds>}
+     */
+    async getTypeNameIdsAsync(nn) {
         // Each of these identifiers are used specially by
         // type-driven search.
         const [
@@ -1274,21 +1298,39 @@ class DocSearch {
             }
             return -1;
         };
-        this.typeNameIdOfOutput = await first(output, TY_ASSOCTYPE, "");
-        this.typeNameIdOfFnPtr = await first(fn, TY_PRIMITIVE, "");
-        this.typeNameIdOfFn = await first(fn, TY_TRAIT, "core::ops");
-        this.typeNameIdOfFnMut = await first(fnMut, TY_TRAIT, "core::ops");
-        this.typeNameIdOfFnOnce = await first(fnOnce, TY_TRAIT, "core::ops");
-        this.typeNameIdOfArray = await first(array, TY_PRIMITIVE, "");
-        this.typeNameIdOfSlice = await first(slice, TY_PRIMITIVE, "");
-        this.typeNameIdOfArrayOrSlice = await first(arrayOrSlice, TY_PRIMITIVE, "");
-        this.typeNameIdOfTuple = await first(tuple, TY_PRIMITIVE, "");
-        this.typeNameIdOfUnit = await first(unit, TY_PRIMITIVE, "");
-        this.typeNameIdOfTupleOrUnit = await first(tupleOrUnit, TY_PRIMITIVE, "");
-        this.typeNameIdOfReference = await first(reference, TY_PRIMITIVE, "");
-        this.typeNameIdOfPointer = await first(pointer, TY_PRIMITIVE, "");
-        this.typeNameIdOfHof = await first(hof, TY_PRIMITIVE, "");
-        this.typeNameIdOfNever = await first(never, TY_PRIMITIVE, "");
+        const typeNameIdOfOutput = await first(output, TY_ASSOCTYPE, "");
+        const typeNameIdOfFnPtr = await first(fn, TY_PRIMITIVE, "");
+        const typeNameIdOfFn = await first(fn, TY_TRAIT, "core::ops");
+        const typeNameIdOfFnMut = await first(fnMut, TY_TRAIT, "core::ops");
+        const typeNameIdOfFnOnce = await first(fnOnce, TY_TRAIT, "core::ops");
+        const typeNameIdOfArray = await first(array, TY_PRIMITIVE, "");
+        const typeNameIdOfSlice = await first(slice, TY_PRIMITIVE, "");
+        const typeNameIdOfArrayOrSlice = await first(arrayOrSlice, TY_PRIMITIVE, "");
+        const typeNameIdOfTuple = await first(tuple, TY_PRIMITIVE, "");
+        const typeNameIdOfUnit = await first(unit, TY_PRIMITIVE, "");
+        const typeNameIdOfTupleOrUnit = await first(tupleOrUnit, TY_PRIMITIVE, "");
+        const typeNameIdOfReference = await first(reference, TY_PRIMITIVE, "");
+        const typeNameIdOfPointer = await first(pointer, TY_PRIMITIVE, "");
+        const typeNameIdOfHof = await first(hof, TY_PRIMITIVE, "");
+        const typeNameIdOfNever = await first(never, TY_PRIMITIVE, "");
+        this.typeNameIds = {
+            typeNameIdOfOutput,
+            typeNameIdOfFnPtr,
+            typeNameIdOfFn,
+            typeNameIdOfFnMut,
+            typeNameIdOfFnOnce,
+            typeNameIdOfArray,
+            typeNameIdOfSlice,
+            typeNameIdOfArrayOrSlice,
+            typeNameIdOfTuple,
+            typeNameIdOfUnit,
+            typeNameIdOfTupleOrUnit,
+            typeNameIdOfReference,
+            typeNameIdOfPointer,
+            typeNameIdOfHof,
+            typeNameIdOfNever,
+        };
+        return this.typeNameIds;
     }
 
     /**
@@ -1758,12 +1800,8 @@ class DocSearch {
         const l = crateNames.length;
         const names = [];
         for (let i = 0; i < l; ++i) {
-            names.push(crateNames.at(i).then(name => {
-                if (name === undefined) {
-                    return "";
-                }
-                return this.utf8decoder.decode(name);
-            }));
+            const name = await crateNames.at(i);
+            names.push(name === undefined ? "" : this.utf8decoder.decode(name));
         }
         return Promise.all(names);
     }
@@ -1820,6 +1858,9 @@ class DocSearch {
             modulePathData,
             exactModuleName,
             exactModulePathData,
+            parentName,
+            parentPath,
+            crate,
         ] = await Promise.all([
             entry && entry.modulePath !== null ? this.getName(entry.modulePath) : null,
             entry && entry.modulePath !== null ? this.getPathData(entry.modulePath) : null,
@@ -1829,6 +1870,13 @@ class DocSearch {
             entry && entry.exactModulePath !== null ?
                 this.getPathData(entry.exactModulePath) :
                 null,
+            entry && entry.parent !== null ?
+                this.getName(entry.parent) :
+                null,
+            entry && entry.parent !== null ?
+                this.getPathData(entry.parent) :
+                null,
+            entry ? nonnull(await this.getName(entry.krate)) : "",
         ]);
         const name = name_ === null ? "" : name_;
         const normalizedName = (name.indexOf("_") === -1 ?
@@ -1838,12 +1886,9 @@ class DocSearch {
             (modulePathData.modulePath === "" ?
                 moduleName :
                 `${modulePathData.modulePath}::${moduleName}`);
-        const [parentName, parentPath] = entry !== null && entry.parent !== null ?
-            await Promise.all([this.getName(entry.parent), this.getPathData(entry.parent)]) :
-            [null, null];
         return {
             id,
-            crate: entry ? nonnull(await this.getName(entry.krate)) : "",
+            crate,
             ty: entry ? entry.ty : nonnull(path).ty,
             name,
             normalizedName,
@@ -2148,6 +2193,7 @@ class DocSearch {
          * @returns {Promise<rustdoc.DisplayTypeSignature>}
          */
         const formatDisplayTypeSignature = async(obj, typeInfo, elems, returned) => {
+            const typeNameIds = await this.getTypeNameIds();
             const objType = obj.type;
             if (!objType) {
                 return {type: [], mappedNames: new Map(), whereClause: new Map()};
@@ -2173,10 +2219,12 @@ class DocSearch {
                                 return true;
                             },
                             0,
+                            typeNameIds,
                         );
                         return !!fnOutput;
                     },
                     0,
+                    typeNameIds,
                 );
             } else {
                 const highlighted = unifyFunctionTypes(
@@ -2189,6 +2237,7 @@ class DocSearch {
                         return true;
                     },
                     0,
+                    typeNameIds,
                 );
                 if (typeInfo === "elems") {
                     fnInputs = highlighted;
@@ -2268,7 +2317,7 @@ class DocSearch {
              * @returns {Promise<void>}
              */
             const writeHof = async(fnType, result) => {
-                const hofOutput = fnType.bindings.get(this.typeNameIdOfOutput) || [];
+                const hofOutput = fnType.bindings.get(typeNameIds.typeNameIdOfOutput) || [];
                 const hofInputs = fnType.generics;
                 pushText(fnType, result);
                 pushText({name: " (", highlighted: false}, result);
@@ -2309,11 +2358,14 @@ class DocSearch {
              * @returns {Promise<boolean>}
              */
             const writeSpecialPrimitive = async(fnType, result) => {
-                if (fnType.id === this.typeNameIdOfArray || fnType.id === this.typeNameIdOfSlice ||
-                    fnType.id === this.typeNameIdOfTuple || fnType.id === this.typeNameIdOfUnit) {
+                if (fnType.id === typeNameIds.typeNameIdOfArray ||
+                    fnType.id === typeNameIds.typeNameIdOfSlice ||
+                    fnType.id === typeNameIds.typeNameIdOfTuple ||
+                    fnType.id === typeNameIds.typeNameIdOfUnit
+                ) {
                     const [ob, sb] =
-                        fnType.id === this.typeNameIdOfArray ||
-                            fnType.id === this.typeNameIdOfSlice ?
+                        fnType.id === typeNameIds.typeNameIdOfArray ||
+                            fnType.id === typeNameIds.typeNameIdOfSlice ?
                         ["[", "]"] :
                         ["(", ")"];
                     pushText({ name: ob, highlighted: fnType.highlighted }, result);
@@ -2325,7 +2377,7 @@ class DocSearch {
                     );
                     pushText({ name: sb, highlighted: fnType.highlighted }, result);
                     return true;
-                } else if (fnType.id === this.typeNameIdOfReference) {
+                } else if (fnType.id === typeNameIds.typeNameIdOfReference) {
                     pushText({ name: "&", highlighted: fnType.highlighted }, result);
                     let prevHighlighted = false;
                     await onEachBtwnAsync(
@@ -2341,7 +2393,7 @@ class DocSearch {
                         }, result),
                     );
                     return true;
-                } else if (fnType.id === this.typeNameIdOfPointer) {
+                } else if (fnType.id === typeNameIds.typeNameIdOfPointer) {
                     pushText({ name: "*", highlighted: fnType.highlighted }, result);
                     if (fnType.generics.length < 2) {
                         pushText({ name: "const ", highlighted: fnType.highlighted }, result);
@@ -2361,14 +2413,14 @@ class DocSearch {
                     );
                     return true;
                 } else if (
-                    fnType.id === this.typeNameIdOfFn ||
-                    fnType.id === this.typeNameIdOfFnMut ||
-                    fnType.id === this.typeNameIdOfFnOnce ||
-                    fnType.id === this.typeNameIdOfFnPtr
+                    fnType.id === typeNameIds.typeNameIdOfFn ||
+                    fnType.id === typeNameIds.typeNameIdOfFnMut ||
+                    fnType.id === typeNameIds.typeNameIdOfFnOnce ||
+                    fnType.id === typeNameIds.typeNameIdOfFnPtr
                 ) {
                     await writeHof(fnType, result);
                     return true;
-                } else if (fnType.id === this.typeNameIdOfNever) {
+                } else if (fnType.id === typeNameIds.typeNameIdOfNever) {
                     pushText({ name: "!", highlighted: fnType.highlighted }, result);
                     return true;
                 }
@@ -2426,10 +2478,10 @@ class DocSearch {
                             return;
                         }
                     } else if (fnType.ty === TY_TRAIT && (
-                        fnType.id === this.typeNameIdOfFn ||
-                        fnType.id === this.typeNameIdOfFnMut ||
-                        fnType.id === this.typeNameIdOfFnOnce ||
-                        fnType.id === this.typeNameIdOfFnPtr
+                        fnType.id === typeNameIds.typeNameIdOfFn ||
+                        fnType.id === typeNameIds.typeNameIdOfFnMut ||
+                        fnType.id === typeNameIds.typeNameIdOfFnOnce ||
+                        fnType.id === typeNameIds.typeNameIdOfFnPtr
                     )) {
                         await writeHof(fnType, result);
                         return;
@@ -2540,7 +2592,7 @@ class DocSearch {
          * Add extra data to result objects, and filter items that have been
          * marked for removal.
          *
-         * @param {[rustdoc.PlainResultObject, rustdoc.Row][]} results
+         * @param {rustdoc.PlainResultObject[]} results
          * @param {"sig"|"elems"|"returned"|null} typeInfo
          * @param {Set<string>} duplicates
          * @returns {rustdoc.ResultObject[]}
@@ -2548,7 +2600,8 @@ class DocSearch {
         const transformResults = (results, typeInfo, duplicates) => {
             const out = [];
 
-            for (const [result, item] of results) {
+            for (const result of results) {
+                const item = result.item;
                 if (item.id !== -1) {
                     const res = buildHrefAndPath(item);
                     // many of these properties don't strictly need to be
@@ -2633,7 +2686,7 @@ class DocSearch {
                 const normalizedUserQuery = parsedQuery.userQuery.toLowerCase();
                 const isMixedCase = normalizedUserQuery !== userQuery;
                 /**
-                 * @type {[rustdoc.PlainResultObject, rustdoc.Row][]}
+                 * @type {rustdoc.PlainResultObject[]}
                  */
                 const result_list = [];
                 for (const result of results.values()) {
@@ -2641,23 +2694,22 @@ class DocSearch {
                         continue;
                     }
                     /**
-                     * @type {rustdoc.Row?}
+                     * @type {rustdoc.Row}
                      */
-                    const item = await this.getRow(result.id, typeInfo !== null);
-                    if (!item) {
-                        continue;
-                    }
+                    const item = result.item;
                     if (filterCrates !== null && item.crate !== filterCrates) {
                         continue;
                     }
                     if (item) {
-                        result_list.push([result, item]);
+                        result_list.push(result);
                     } else {
                         continue;
                     }
                 }
 
-                result_list.sort(([aaa, aai], [bbb, bbi]) => {
+                result_list.sort((aaa, bbb) => {
+                    const aai = aaa.item;
+                    const bbi = bbb.item;
                     /** @type {number} */
                     let a;
                     /** @type {number} */
@@ -2804,6 +2856,7 @@ class DocSearch {
          * @param {number} unboxingDepth
          *     - Limit checks that Ty matches Vec<Ty>,
          *       but not Vec<ParamEnvAnd<WithInfcx<ConstTy<Interner<Ty=Ty>>>>>
+         * @param {rustdoc.TypeNameIds} typeNameIds
          *
          * @return {rustdoc.HighlightedFunctionType[]|null}
          *     - Returns highlighted results if a match, null otherwise.
@@ -2815,6 +2868,7 @@ class DocSearch {
             mgensIn,
             solutionCb,
             unboxingDepth,
+            typeNameIds,
         ) {
             if (unboxingDepth >= UNBOXING_LIMIT) {
                 return null;
@@ -2837,7 +2891,12 @@ class DocSearch {
                 && queryElems[0].bindings.size === 0) {
                 const queryElem = queryElems[0];
                 for (const [i, fnType] of fnTypesIn.entries()) {
-                    if (!unifyFunctionTypeIsMatchCandidate(fnType, queryElem, mgens)) {
+                    if (!unifyFunctionTypeIsMatchCandidate(
+                        fnType,
+                        queryElem,
+                        mgens,
+                        typeNameIds,
+                    )) {
                         continue;
                     }
                     if (fnType.id !== null &&
@@ -2873,6 +2932,7 @@ class DocSearch {
                                 mgens ? new Map(mgens) : null,
                                 solutionCb,
                                 unboxingDepth,
+                                typeNameIds,
                             ) || fnType.generics,
                         });
                         return highlighted;
@@ -2885,6 +2945,7 @@ class DocSearch {
                         whereClause,
                         mgens,
                         unboxingDepth + 1,
+                        typeNameIds,
                     )) {
                         continue;
                     }
@@ -2898,6 +2959,7 @@ class DocSearch {
                             mgens,
                             solutionCb,
                             unboxingDepth + 1,
+                            typeNameIds,
                         );
                         if (highlightedGenerics) {
                             const highlighted = [...fnTypesIn];
@@ -2916,6 +2978,7 @@ class DocSearch {
                             mgens ? new Map(mgens) : null,
                             solutionCb,
                             unboxingDepth + 1,
+                            typeNameIds,
                         );
                         if (highlightedGenerics) {
                             const highlighted = [...fnTypesIn];
@@ -2960,7 +3023,12 @@ class DocSearch {
             let queryElemsTmp = null;
             for (let i = flast; i >= 0; i -= 1) {
                 const fnType = fnTypes[i];
-                if (!unifyFunctionTypeIsMatchCandidate(fnType, queryElem, mgens)) {
+                if (!unifyFunctionTypeIsMatchCandidate(
+                    fnType,
+                    queryElem,
+                    mgens,
+                    typeNameIds,
+                )) {
                     continue;
                 }
                 let mgensScratch;
@@ -3004,6 +3072,7 @@ class DocSearch {
                             whereClause,
                             mgensScratch,
                             unboxingDepth,
+                            typeNameIds,
                         );
                         if (!solution) {
                             return false;
@@ -3017,6 +3086,7 @@ class DocSearch {
                                 simplifiedMgens,
                                 solutionCb,
                                 unboxingDepth,
+                                typeNameIds,
                             );
                             if (unifiedGenerics !== null) {
                                 unifiedGenericsMgens = simplifiedMgens;
@@ -3026,6 +3096,7 @@ class DocSearch {
                         return false;
                     },
                     unboxingDepth,
+                    typeNameIds,
                 );
                 if (passesUnification) {
                     passesUnification.length = fl;
@@ -3042,6 +3113,7 @@ class DocSearch {
                                 unifiedGenericsMgens,
                                 solutionCb,
                                 unboxingDepth,
+                                typeNameIds,
                             // @ts-expect-error
                             ) : unifiedGenerics.splice(0, v.length)];
                         })),
@@ -3061,6 +3133,7 @@ class DocSearch {
                     whereClause,
                     mgens,
                     unboxingDepth + 1,
+                    typeNameIds,
                 )) {
                     continue;
                 }
@@ -3077,6 +3150,7 @@ class DocSearch {
                     mgens,
                     solutionCb,
                     unboxingDepth + 1,
+                    typeNameIds,
                 );
                 if (passesUnification) {
                     const highlightedGenerics = passesUnification.slice(
@@ -3117,6 +3191,7 @@ class DocSearch {
          * @param {number} unboxingDepth
          *     - Limit checks that Ty matches Vec<Ty>,
          *       but not Vec<ParamEnvAnd<WithInfcx<ConstTy<Interner<Ty=Ty>>>>>
+         * @param {rustdoc.TypeNameIds} typeNameIds
          *
          * @return {rustdoc.HighlightedFunctionType[]|null}
          *     - Returns highlighted results if a match, null otherwise.
@@ -3128,6 +3203,7 @@ class DocSearch {
             mgensIn,
             solutionCb,
             unboxingDepth,
+            typeNameIds,
         ) {
             if (unboxingDepth >= UNBOXING_LIMIT) {
                 return null;
@@ -3145,7 +3221,12 @@ class DocSearch {
             }
             const fnType = fnTypesIn[0];
             const queryElem = queryElems[0];
-            if (unifyFunctionTypeIsMatchCandidate(fnType, queryElem, mgens)) {
+            if (unifyFunctionTypeIsMatchCandidate(
+                fnType,
+                queryElem,
+                mgens,
+                typeNameIds,
+            )) {
                 if (fnType.id !== null &&
                     fnType.id < 0 &&
                     queryElem.id !== null &&
@@ -3163,6 +3244,7 @@ class DocSearch {
                             mgensScratch,
                             solutionCb,
                             unboxingDepth,
+                            typeNameIds,
                         );
                         if (fnTypesRemaining) {
                             const highlighted = [fnType, ...fnTypesRemaining];
@@ -3189,6 +3271,7 @@ class DocSearch {
                                 whereClause,
                                 mgensScratch,
                                 unboxingDepth,
+                                typeNameIds,
                             );
                             if (!solution) {
                                 return false;
@@ -3202,6 +3285,7 @@ class DocSearch {
                                     simplifiedMgens,
                                     solutionCb,
                                     unboxingDepth,
+                                    typeNameIds,
                                 );
                                 if (unifiedGenerics !== null) {
                                     return true;
@@ -3209,6 +3293,7 @@ class DocSearch {
                             }
                         },
                         unboxingDepth,
+                        typeNameIds,
                     );
                     if (fnTypesRemaining) {
                         const highlighted = [fnType, ...fnTypesRemaining];
@@ -3227,6 +3312,7 @@ class DocSearch {
                 whereClause,
                 mgens,
                 unboxingDepth + 1,
+                typeNameIds,
             )) {
                 let highlightedRemaining;
                 if (fnType.id !== null && fnType.id < 0) {
@@ -3248,6 +3334,7 @@ class DocSearch {
                                 mgensScratch,
                                 solutionCb,
                                 unboxingDepth,
+                                typeNameIds,
                             );
                             if (hl) {
                                 highlightedRemaining = hl;
@@ -3255,6 +3342,7 @@ class DocSearch {
                             return hl;
                         },
                         unboxingDepth + 1,
+                        typeNameIds,
                     );
                     if (highlightedGenerics) {
                         return [Object.assign({
@@ -3282,6 +3370,7 @@ class DocSearch {
                                 mgensScratch,
                                 solutionCb,
                                 unboxingDepth,
+                                typeNameIds,
                             );
                             if (hl) {
                                 highlightedRemaining = hl;
@@ -3289,6 +3378,7 @@ class DocSearch {
                             return hl;
                         },
                         unboxingDepth + 1,
+                        typeNameIds,
                     );
                     if (highlightedGenerics) {
                         return [Object.assign({}, fnType, {
@@ -3314,10 +3404,11 @@ class DocSearch {
          *
          * @param {rustdoc.FunctionType} fnType
          * @param {rustdoc.QueryElement} queryElem
+         * @param {rustdoc.TypeNameIds} typeNameIds
          * @param {Map<number,number>|null} mgensIn - Map query generics to function generics.
          * @returns {boolean}
          */
-        const unifyFunctionTypeIsMatchCandidate = (fnType, queryElem, mgensIn) => {
+        const unifyFunctionTypeIsMatchCandidate = (fnType, queryElem, mgensIn, typeNameIds) => {
             // type filters look like `trait:Read` or `enum:Result`
             if (!typePassesFilter(queryElem.typeFilter, fnType.ty)) {
                 return false;
@@ -3336,21 +3427,23 @@ class DocSearch {
             } else {
                 // For these special cases, matching code need added to the inverted index.
                 // search_index.rs -> convert_render_type does this
-                if (queryElem.id === this.typeNameIdOfArrayOrSlice &&
-                    (fnType.id === this.typeNameIdOfSlice || fnType.id === this.typeNameIdOfArray)
+                if (queryElem.id === typeNameIds.typeNameIdOfArrayOrSlice &&
+                    (fnType.id === typeNameIds.typeNameIdOfSlice ||
+                        fnType.id === typeNameIds.typeNameIdOfArray)
                 ) {
                     // [] matches primitive:array or primitive:slice
                     // if it matches, then we're fine, and this is an appropriate match candidate
-                } else if (queryElem.id === this.typeNameIdOfTupleOrUnit &&
-                    (fnType.id === this.typeNameIdOfTuple || fnType.id === this.typeNameIdOfUnit)
+                } else if (queryElem.id === typeNameIds.typeNameIdOfTupleOrUnit &&
+                    (fnType.id === typeNameIds.typeNameIdOfTuple ||
+                        fnType.id === typeNameIds.typeNameIdOfUnit)
                 ) {
                     // () matches primitive:tuple or primitive:unit
                     // if it matches, then we're fine, and this is an appropriate match candidate
-                } else if (queryElem.id === this.typeNameIdOfHof && (
-                    fnType.id === this.typeNameIdOfFn ||
-                    fnType.id === this.typeNameIdOfFnMut ||
-                    fnType.id === this.typeNameIdOfFnOnce ||
-                    fnType.id === this.typeNameIdOfFnPtr
+                } else if (queryElem.id === typeNameIds.typeNameIdOfHof && (
+                    fnType.id === typeNameIds.typeNameIdOfFn ||
+                    fnType.id === typeNameIds.typeNameIdOfFnMut ||
+                    fnType.id === typeNameIds.typeNameIdOfFnOnce ||
+                    fnType.id === typeNameIds.typeNameIdOfFnPtr
                 )) {
                     // -> matches fn, fnonce, and fnmut
                     // if it matches, then we're fine, and this is an appropriate match candidate
@@ -3414,6 +3507,7 @@ class DocSearch {
          * @param {Map<number,number>|null} mgensIn - Map query generics to function generics.
          *                                            Never modified.
          * @param {number} unboxingDepth
+         * @param {rustdoc.TypeNameIds} typeNameIds
          * @returns {false|{
          *     mgens: [Map<number,number>|null], simplifiedGenerics: rustdoc.FunctionType[]
          * }}
@@ -3424,6 +3518,7 @@ class DocSearch {
             whereClause,
             mgensIn,
             unboxingDepth,
+            typeNameIds,
         ) {
             if (fnType.bindings.size < queryElem.bindings.size) {
                 return false;
@@ -3455,6 +3550,7 @@ class DocSearch {
                                 return false;
                             },
                             unboxingDepth,
+                            typeNameIds,
                         );
                         return newSolutions;
                     });
@@ -3486,6 +3582,7 @@ class DocSearch {
          * @param {rustdoc.FunctionType[][]} whereClause - Trait bounds for generic items.
          * @param {Map<number,number>|null} mgens - Map query generics to function generics.
          * @param {number} unboxingDepth
+         * @param {rustdoc.TypeNameIds} typeNameIds
          * @returns {boolean}
          */
         function unifyFunctionTypeIsUnboxCandidate(
@@ -3494,6 +3591,7 @@ class DocSearch {
             whereClause,
             mgens,
             unboxingDepth,
+            typeNameIds,
         ) {
             if (unboxingDepth >= UNBOXING_LIMIT) {
                 return false;
@@ -3512,6 +3610,7 @@ class DocSearch {
                     whereClause,
                     mgens,
                     unboxingDepth,
+                    typeNameIds,
                 );
             } else if (fnType.unboxFlag &&
                 (fnType.generics.length > 0 || fnType.bindings.size > 0)) {
@@ -3525,6 +3624,7 @@ class DocSearch {
                     whereClause,
                     mgens,
                     unboxingDepth,
+                    typeNameIds,
                 );
             }
             return false;
@@ -3537,14 +3637,15 @@ class DocSearch {
          * @param {rustdoc.QueryElement[]} elems
          * @param {rustdoc.FunctionType[]} list    - A list of function types.
          * @param {rustdoc.FunctionType[][]} where_clause - Trait bounds for generic items.
+         * @param {rustdoc.TypeNameIds} typeNameIds
          */
-        function containsTypeFromQuery(elems, list, where_clause) {
+        function containsTypeFromQuery(elems, list, where_clause, typeNameIds) {
             if (!list) return false;
             for (const ty of elems) {
                 if (ty.id !== null && ty.id < 0) {
                     continue;
                 }
-                if (checkIfInList(list, ty, where_clause, null, 0)) {
+                if (checkIfInList(list, ty, where_clause, null, 0, typeNameIds)) {
                     return true;
                 }
             }
@@ -3560,12 +3661,13 @@ class DocSearch {
          * @param {rustdoc.FunctionType[][]} whereClause - Trait bounds for generic items.
          * @param {Map<number,number>|null} mgens - Map functions generics to query generics.
          * @param {number} unboxingDepth
+         * @param {rustdoc.TypeNameIds} typeNameIds
          *
          * @return {boolean} - Returns true if found, false otherwise.
          */
-        function checkIfInList(list, elem, whereClause, mgens, unboxingDepth) {
+        function checkIfInList(list, elem, whereClause, mgens, unboxingDepth, typeNameIds) {
             for (const entry of list) {
-                if (checkType(entry, elem, whereClause, mgens, unboxingDepth)) {
+                if (checkType(entry, elem, whereClause, mgens, unboxingDepth, typeNameIds)) {
                     return true;
                 }
             }
@@ -3580,11 +3682,12 @@ class DocSearch {
          * @param {rustdoc.QueryElement} elem          - The element from the parsed query.
          * @param {rustdoc.FunctionType[][]} whereClause - Trait bounds for generic items.
          * @param {Map<number,number>|null} mgens - Map query generics to function generics.
+         * @param {number} unboxingDepth
+         * @param {rustdoc.TypeNameIds} typeNameIds
          *
          * @return {boolean} - Returns true if the type matches, false otherwise.
          */
-        // @ts-expect-error
-        const checkType = (row, elem, whereClause, mgens, unboxingDepth) => {
+        const checkType = (row, elem, whereClause, mgens, unboxingDepth, typeNameIds) => {
             if (unboxingDepth >= UNBOXING_LIMIT) {
                 return false;
             }
@@ -3593,9 +3696,9 @@ class DocSearch {
                 row.generics.length === 0 && elem.generics.length === 0 &&
                 row.bindings.size === 0 && elem.bindings.size === 0 &&
                 // special case
-                elem.id !== this.typeNameIdOfArrayOrSlice &&
-                elem.id !== this.typeNameIdOfHof &&
-                elem.id !== this.typeNameIdOfTupleOrUnit
+                elem.id !== typeNameIds.typeNameIdOfArrayOrSlice &&
+                elem.id !== typeNameIds.typeNameIdOfHof &&
+                elem.id !== typeNameIds.typeNameIdOfTupleOrUnit
             ) {
                 return row.id === elem.id && typePassesFilter(elem.typeFilter, row.ty);
             } else {
@@ -3607,6 +3710,7 @@ class DocSearch {
                     mgens,
                     () => true,
                     unboxingDepth,
+                    typeNameIds,
                 );
             }
         };
@@ -3673,7 +3777,10 @@ class DocSearch {
         /**
          * Compute an "edit distance" that ignores missing path elements.
          * @param {string[]} contains search query path
-         * @param {rustdoc.Row} row indexed item
+         * @param {{
+         *     modulePath: string,
+         *     parent: { path: rustdoc.PathData, name: string}?,
+         * }} row indexed item
          * @returns {null|number} edit distance
          */
         function checkRowPath(contains, row) {
@@ -3752,7 +3859,7 @@ class DocSearch {
                         is_alias: true,
                         elems: [], // only used in type-based queries
                         returned: [], // only used in type-based queries
-                        original: await this.getRow(alias, false),
+                        item: nonnull(await this.getRow(alias, false)),
                     };
                 };
                 /**
@@ -3834,6 +3941,7 @@ class DocSearch {
                             elems: [], // only used in type-based queries
                             returned: [], // only used in type-based queries
                             is_alias: false,
+                            item: row,
                         } : null;
                     } else {
                         return {
@@ -3848,6 +3956,7 @@ class DocSearch {
                             elems: [], // only used in type-based queries
                             returned: [], // only used in type-based queries
                             is_alias: false,
+                            item: row,
                         };
                     }
                 };
@@ -4359,9 +4468,10 @@ class DocSearch {
                 };
 
                 // finally, we can do the actual unification loop
-                const [allInputs, allOutput] = await Promise.all([
+                const [allInputs, allOutput, typeNameIds] = await Promise.all([
                     unpackPostingsListAll(inputs, "invertedFunctionInputsIndex"),
                     unpackPostingsListAll(output, "invertedFunctionOutputIndex"),
+                    this.getTypeNameIds(),
                 ]);
                 let checkCounter = 0;
                 /**
@@ -4430,12 +4540,18 @@ class DocSearch {
                                             mgens,
                                             checkTypeMgensForConflict,
                                             0, // unboxing depth
+                                            typeNameIds,
                                         );
                                     },
                                     0, // unboxing depth
+                                    typeNameIds,
                                 )) {
                                     return null;
                                 }
+                                const item = await this.getRow(id, true);
+                                if (!item) {
+                                    return null;
+                                }
                                 const result = {
                                     id,
                                     dist: fnData.elemCount,
@@ -4444,8 +4560,9 @@ class DocSearch {
                                     elems: inputs,
                                     returned: output,
                                     is_alias: false,
+                                    item,
                                 };
-                                const entry = await this.getEntryData(id);
+                                const entry = item.entry;
                                 if ((entry && !isFnLikeTy(entry.ty)) ||
                                     (isReturnTypeQuery &&
                                         functionSignature &&
@@ -4453,6 +4570,7 @@ class DocSearch {
                                             output,
                                             functionSignature.inputs,
                                             functionSignature.where_clause,
+                                            typeNameIds,
                                         )
                                     )
                                 ) {
@@ -5273,7 +5391,6 @@ if (ROOT_PATH === null) {
 const database = await Stringdex.loadDatabase(hooks);
 if (typeof window !== "undefined") {
     docSearch = new DocSearch(ROOT_PATH, database);
-    await docSearch.buildIndex();
     onEachLazy(document.querySelectorAll(
         ".search-form.loading",
     ), form => {
@@ -5286,7 +5403,6 @@ if (typeof window !== "undefined") {
     }
 } else if (typeof exports !== "undefined") {
     docSearch = new DocSearch(ROOT_PATH, database);
-    await docSearch.buildIndex();
     return { docSearch, DocSearch };
 }
 };
diff --git a/src/librustdoc/html/static/js/stringdex.d.ts b/src/librustdoc/html/static/js/stringdex.d.ts
index 2eb1fdf95d8..71c6bfdf481 100644
--- a/src/librustdoc/html/static/js/stringdex.d.ts
+++ b/src/librustdoc/html/static/js/stringdex.d.ts
@@ -29,7 +29,7 @@ declare namespace stringdex {
      */
     interface DataColumn {
         isEmpty(id: number): boolean;
-        at(id: number): Promise<Uint8Array|undefined>;
+        at(id: number): Promise<Uint8Array>|Uint8Array|undefined;
         search(name: Uint8Array|string): Promise<Trie?>;
         searchLev(name: Uint8Array|string): AsyncGenerator<Trie>;
         length: number,
diff --git a/src/librustdoc/html/static/js/stringdex.js b/src/librustdoc/html/static/js/stringdex.js
index b7f605a1035..5bdc81e330e 100644
--- a/src/librustdoc/html/static/js/stringdex.js
+++ b/src/librustdoc/html/static/js/stringdex.js
@@ -2261,7 +2261,7 @@ function loadDatabase(hooks) {
             this.hashes = hashes;
             this.emptyset = emptyset;
             this.name = name;
-            /** @type {{"hash": Uint8Array, "data": Promise<Uint8Array[]>?, "end": number}[]} */
+            /** @type {{"hash": Uint8Array, "data": Uint8Array[]?, "end": number}[]} */
             this.buckets = [];
             this.bucket_keys = [];
             const l = counts.length;
@@ -2295,64 +2295,75 @@ function loadDatabase(hooks) {
         /**
          * Look up a cell by row ID.
          * @param {number} id
-         * @returns {Promise<Uint8Array|undefined>}
+         * @returns {Promise<Uint8Array>|Uint8Array|undefined}
          */
-        async at(id) {
+        at(id) {
             if (this.emptyset.contains(id)) {
-                return Promise.resolve(EMPTY_UINT8);
+                return EMPTY_UINT8;
             } else {
                 let idx = -1;
                 while (this.bucket_keys[idx + 1] <= id) {
                     idx += 1;
                 }
                 if (idx === -1 || idx >= this.bucket_keys.length) {
-                    return Promise.resolve(undefined);
+                    return undefined;
                 } else {
                     const start = this.bucket_keys[idx];
-                    const {hash, end} = this.buckets[idx];
-                    let data = this.buckets[idx].data;
+                    const bucket = this.buckets[idx];
+                    const data = this.buckets[idx].data;
                     if (data === null) {
-                        const dataSansEmptysetOrig = await registry.dataLoadByNameAndHash(
-                            this.name,
-                            hash,
-                        );
-                        // After the `await` resolves, another task might fill
-                        // in the data. If so, we should use that.
-                        data = this.buckets[idx].data;
-                        if (data !== null) {
-                            return (await data)[id - start];
-                        }
-                        const dataSansEmptyset = [...dataSansEmptysetOrig];
-                        /** @type {(Uint8Array[])|null} */
-                        let dataWithEmptyset = null;
-                        let pos = start;
-                        let insertCount = 0;
-                        while (pos < end) {
-                            if (this.emptyset.contains(pos)) {
-                                if (dataWithEmptyset === null) {
-                                    dataWithEmptyset = dataSansEmptyset.splice(0, insertCount);
-                                } else if (insertCount !== 0) {
-                                    dataWithEmptyset.push(
-                                        ...dataSansEmptyset.splice(0, insertCount),
-                                    );
-                                }
-                                insertCount = 0;
-                                dataWithEmptyset.push(EMPTY_UINT8);
-                            } else {
-                                insertCount += 1;
-                            }
-                            pos += 1;
-                        }
-                        data = Promise.resolve(
-                            dataWithEmptyset === null ?
-                                dataSansEmptyset :
-                                dataWithEmptyset.concat(dataSansEmptyset),
+                        return this.atAsyncFetch(id, start, bucket);
+                    } else {
+                        return data[id - start];
+                    }
+                }
+            }
+        }
+        /**
+         * Look up a cell by row ID.
+         * @param {number} id
+         * @param {number} start
+         * @param {{hash: Uint8Array, data: Uint8Array[] | null, end: number}} bucket
+         * @returns {Promise<Uint8Array>}
+         */
+        async atAsyncFetch(id, start, bucket) {
+            const {hash, end} = bucket;
+            const dataSansEmptysetOrig = await registry.dataLoadByNameAndHash(
+                this.name,
+                hash,
+            );
+            // After the `await` resolves, another task might fill
+            // in the data. If so, we should use that.
+            let data = bucket.data;
+            if (data !== null) {
+                return data[id - start];
+            }
+            const dataSansEmptyset = [...dataSansEmptysetOrig];
+            /** @type {(Uint8Array[])|null} */
+            let dataWithEmptyset = null;
+            let pos = start;
+            let insertCount = 0;
+            while (pos < end) {
+                if (this.emptyset.contains(pos)) {
+                    if (dataWithEmptyset === null) {
+                        dataWithEmptyset = dataSansEmptyset.splice(0, insertCount);
+                    } else if (insertCount !== 0) {
+                        dataWithEmptyset.push(
+                            ...dataSansEmptyset.splice(0, insertCount),
                         );
-                        this.buckets[idx].data = data;
                     }
-                    return (await data)[id - start];
+                    insertCount = 0;
+                    dataWithEmptyset.push(EMPTY_UINT8);
+                } else {
+                    insertCount += 1;
                 }
+                pos += 1;
             }
+            data = dataWithEmptyset === null ?
+                dataSansEmptyset :
+                dataWithEmptyset.concat(dataSansEmptyset);
+            bucket.data = data;
+            return data[id - start];
         }
         /**
          * Search by exact substring
diff --git a/src/tools/clippy/.github/ISSUE_TEMPLATE/new_lint.yml b/src/tools/clippy/.github/ISSUE_TEMPLATE/new_lint.yml
index a8202f6378f..6ad16aead60 100644
--- a/src/tools/clippy/.github/ISSUE_TEMPLATE/new_lint.yml
+++ b/src/tools/clippy/.github/ISSUE_TEMPLATE/new_lint.yml
@@ -1,7 +1,5 @@
 name: New lint suggestion
-description: |
-  Suggest a new Clippy lint (currently not accepting new lints)
-  Check out the Clippy book for more information about the feature freeze.
+description: Suggest a new Clippy lint.
 labels: ["A-lint"]
 body:
   - type: markdown
diff --git a/src/tools/clippy/.github/PULL_REQUEST_TEMPLATE.md b/src/tools/clippy/.github/PULL_REQUEST_TEMPLATE.md
index 83bfd8e9c68..9e49f60892d 100644
--- a/src/tools/clippy/.github/PULL_REQUEST_TEMPLATE.md
+++ b/src/tools/clippy/.github/PULL_REQUEST_TEMPLATE.md
@@ -32,10 +32,6 @@ order to get feedback.
 
 Delete this line and everything above before opening your PR.
 
-Note that we are currently not taking in new PRs that add new lints. We are in a
-feature freeze. Check out the book for more information. If you open a
-feature-adding pull request, its review will be delayed.
-
 ---
 
 *Please write a short comment explaining your change (or "none" for internal only changes)*
diff --git a/src/tools/clippy/.github/workflows/feature_freeze.yml b/src/tools/clippy/.github/workflows/feature_freeze.yml
deleted file mode 100644
index 5b139e76700..00000000000
--- a/src/tools/clippy/.github/workflows/feature_freeze.yml
+++ /dev/null
@@ -1,45 +0,0 @@
-name: Feature freeze check
-
-on:
-  pull_request_target:
-    types:
-      - opened
-    branches:
-      - master
-    paths:
-      - 'clippy_lints/src/declared_lints.rs'
-
-jobs:
-  auto-comment:
-    runs-on: ubuntu-latest
-
-    permissions:
-      pull-requests: write
-
-    # Do not in any case add code that runs anything coming from the content
-    # of the pull request, as malicious code would be able to access the private
-    # GitHub token.
-    steps:
-      - name: Add freeze warning comment
-        env:
-          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
-          GITHUB_REPOSITORY: ${{ github.repository }}
-          PR_NUMBER: ${{ github.event.pull_request.number }}
-        run: |
-          COMMENT=$(echo "**Seems that you are trying to add a new lint!**\n\
-          \n\
-          We are currently in a [feature freeze](https://doc.rust-lang.org/nightly/clippy/development/feature_freeze.html), so we are delaying all lint-adding PRs to September 18 and [focusing on bugfixes](https://github.com/rust-lang/rust-clippy/issues/15086).\n\
-          \n\
-          Thanks a lot for your contribution, and sorry for the inconvenience.\n\
-          \n\
-          With ❤ from the Clippy team.\n\
-          \n\
-          @rustbot note Feature-freeze\n\
-          @rustbot blocked\n\
-          @rustbot label +A-lint"
-          )
-          curl -s -H "Authorization: Bearer $GITHUB_TOKEN" \
-             -H "Content-Type: application/vnd.github.raw+json" \
-             -X POST \
-             --data "{\"body\":\"${COMMENT}\"}" \
-             "https://api.github.com/repos/${GITHUB_REPOSITORY}/issues/${PR_NUMBER}/comments"
diff --git a/src/tools/clippy/.gitignore b/src/tools/clippy/.gitignore
index 36a4cdc1c35..666c4ceac4d 100644
--- a/src/tools/clippy/.gitignore
+++ b/src/tools/clippy/.gitignore
@@ -48,3 +48,6 @@ helper.txt
 
 # mdbook generated output
 /book/book
+
+# Remove jujutsu directory from search tools
+.jj
diff --git a/src/tools/clippy/CHANGELOG.md b/src/tools/clippy/CHANGELOG.md
index eb2a76a8183..3f26b9470e8 100644
--- a/src/tools/clippy/CHANGELOG.md
+++ b/src/tools/clippy/CHANGELOG.md
@@ -6,7 +6,152 @@ document.
 
 ## Unreleased / Beta / In Rust Nightly
 
-[4ef75291...master](https://github.com/rust-lang/rust-clippy/compare/4ef75291...master)
+[e9b7045...master](https://github.com/rust-lang/rust-clippy/compare/e9b7045...master)
+
+## Rust 1.90
+
+Current stable, released 2025-09-18
+
+[View all 118 merged pull requests](https://github.com/rust-lang/rust-clippy/pulls?q=merged%3A2025-06-13T15%3A55%3A04Z..2025-07-25T13%3A24%3A00Z+base%3Amaster)
+
+Note: This Clippy release does not introduce many new lints and is focused entirely on bug fixes — see
+[#15086](https://github.com/rust-lang/rust-clippy/issues/15086) for more details.
+
+## New Lints
+
+* Added [`manual_is_multiple_of`] to `complexity` [#14292](https://github.com/rust-lang/rust-clippy/pull/14292)
+* Added [`doc_broken_link`] to `pedantic` [#13696](https://github.com/rust-lang/rust-clippy/pull/13696)
+
+### Moves and Deprecations
+
+* Move [`uninlined_format_args`] to `pedantic` (from `style`, now allow-by-default) [#15287](https://github.com/rust-lang/rust-clippy/pull/15287)
+
+### Enhancements
+
+* [`or_fun_call`] now lints `Option::get_or_insert`, `Result::map_or`, `Option/Result::and` methods 
+  [#15071](https://github.com/rust-lang/rust-clippy/pull/15071) 
+  [#15073](https://github.com/rust-lang/rust-clippy/pull/15073) 
+  [#15074](https://github.com/rust-lang/rust-clippy/pull/15074)
+* [`incompatible_msrv`] now recognizes types exceeding MSRV 
+  [#15296](https://github.com/rust-lang/rust-clippy/pull/15296)
+* [`incompatible_msrv`] now checks the right MSRV when in a `const` context 
+  [#15297](https://github.com/rust-lang/rust-clippy/pull/15297)
+* [`zero_ptr`] now lints in `const` context as well 
+  [#15152](https://github.com/rust-lang/rust-clippy/pull/15152)
+* [`map_identity`],[`flat_map_identity`] now recognizes `|[x, y]| [x, y]` as an identity function
+  [#15229](https://github.com/rust-lang/rust-clippy/pull/15229)
+* [`exit`] no longer fails on the main function when using `--test` or `--all-targets` flag 
+  [#15222](https://github.com/rust-lang/rust-clippy/pull/15222)
+
+### False Positive Fixes
+
+* [`if_then_some_else_none`] fixed FP when require type coercion
+  [#15267](https://github.com/rust-lang/rust-clippy/pull/15267)
+* [`module_name_repetitions`] fixed FP on exported macros
+  [#15319](https://github.com/rust-lang/rust-clippy/pull/15319)
+* [`unused_async`] fixed FP on function with `todo!`
+  [#15308](https://github.com/rust-lang/rust-clippy/pull/15308)
+* [`useless_attribute`] fixed FP when using `#[expect(redundant_imports)]` and similar lint attributes 
+  on `use` statements
+  [#15318](https://github.com/rust-lang/rust-clippy/pull/15318)
+* [`pattern_type_mismatch`] fixed FP in external macro
+  [#15306](https://github.com/rust-lang/rust-clippy/pull/15306)
+* [`large_enum_variant`] fixed FP by not suggesting `Box` in `no_std` mode
+  [#15241](https://github.com/rust-lang/rust-clippy/pull/15241)
+* [`missing_inline_in_public_items`] fixed FP on functions with `extern`
+  [#15313](https://github.com/rust-lang/rust-clippy/pull/15313)
+* [`needless_range_loop`] fixed FP on array literals
+  [#15314](https://github.com/rust-lang/rust-clippy/pull/15314)
+* [`ptr_as_ptr`] fixed wrong suggestions with turbo fish
+  [#15289](https://github.com/rust-lang/rust-clippy/pull/15289)
+* [`range_plus_one`], [`range_minus_one`] fixed FP by restricting lint to cases where it is safe 
+  to switch the range type
+  [#14432](https://github.com/rust-lang/rust-clippy/pull/14432)
+* [`ptr_arg`] fixed FP with underscore binding to `&T` or `&mut T` argument
+  [#15105](https://github.com/rust-lang/rust-clippy/pull/15105)
+* [`unsafe_derive_deserialize`] fixed FP caused by the standard library's `pin!()` macro
+  [#15137](https://github.com/rust-lang/rust-clippy/pull/15137)
+* [`unused_trait_names`] fixed FP in macros
+  [#14947](https://github.com/rust-lang/rust-clippy/pull/14947)
+* [`expect_fun_call`] fixed invalid suggestions
+  [#15122](https://github.com/rust-lang/rust-clippy/pull/15122)
+* [`manual_is_multiple_of`] fixed various false positives
+  [#15205](https://github.com/rust-lang/rust-clippy/pull/15205)
+* [`manual_assert`] fixed wrong suggestions for macros
+  [#15264](https://github.com/rust-lang/rust-clippy/pull/15264)
+* [`expect_used`] fixed false negative when meeting `Option::ok().expect`
+  [#15253](https://github.com/rust-lang/rust-clippy/pull/15253)
+* [`manual_abs_diff`] fixed wrong suggestions behind refs
+  [#15265](https://github.com/rust-lang/rust-clippy/pull/15265)
+* [`approx_constant`] fixed FP with overly precise literals and non trivially formatted numerals
+  [#15236](https://github.com/rust-lang/rust-clippy/pull/15236)
+* [`arithmetic_side_effects`] fixed FP on `NonZeroU*.get() - 1`
+  [#15238](https://github.com/rust-lang/rust-clippy/pull/15238)
+* [`legacy_numeric_constants`] fixed suggestion when call is inside parentheses
+  [#15191](https://github.com/rust-lang/rust-clippy/pull/15191)
+* [`manual_is_variant_and`] fixed inverted suggestions that could lead to code with different semantics
+  [#15206](https://github.com/rust-lang/rust-clippy/pull/15206)
+* [`unnecessary_map_or`] fixed FP by not proposing to replace `map_or` call when types wouldn't be correct
+  [#15181](https://github.com/rust-lang/rust-clippy/pull/15181)
+* [`return_and_then`] fixed FP in case of a partially used expression
+  [#15115](https://github.com/rust-lang/rust-clippy/pull/15115)
+* [`manual_let_else`] fixed FP with binding subpattern with unused name
+  [#15118](https://github.com/rust-lang/rust-clippy/pull/15118)
+* [`suboptimal_flops`] fixed FP with ambiguous float types in mul_add suggestions
+  [#15133](https://github.com/rust-lang/rust-clippy/pull/15133)
+* [`borrow_as_ptr`] fixed FP by not removing cast to trait object pointer
+  [#15145](https://github.com/rust-lang/rust-clippy/pull/15145)
+* [`unnecessary_operation`] fixed FP by not removing casts if they are useful to type the expression
+  [#15182](https://github.com/rust-lang/rust-clippy/pull/15182)
+* [`empty_loop`] fixed FP on intrinsic function declaration
+  [#15201](https://github.com/rust-lang/rust-clippy/pull/15201)
+* [`doc_nested_refdefs`] fixed FP where task lists are reported as refdefs
+  [#15146](https://github.com/rust-lang/rust-clippy/pull/15146)
+* [`std_instead_of_core`] fixed FP when not all items come from the new crate
+  [#15165](https://github.com/rust-lang/rust-clippy/pull/15165)
+* [`swap_with_temporary`] fixed FP leading to different semantics being suggested
+  [#15172](https://github.com/rust-lang/rust-clippy/pull/15172)
+* [`cast_possible_truncation`] fixed FP by not giving suggestions inside const context
+  [#15164](https://github.com/rust-lang/rust-clippy/pull/15164)
+* [`missing_panics_doc`] fixed FP by allowing unwrap() and expect()s in const-only contexts
+  [#15170](https://github.com/rust-lang/rust-clippy/pull/15170)
+* [`disallowed_script_idents`] fixed FP on identifiers with `_`
+  [#15123](https://github.com/rust-lang/rust-clippy/pull/15123)
+* [`wildcard_enum_match_arm`] fixed wrong suggestions with raw identifiers
+  [#15093](https://github.com/rust-lang/rust-clippy/pull/15093)
+* [`borrow_deref_ref`] fixed FP by not proposing replacing a reborrow when the reborrow is itself mutably borrowed
+  [#14967](https://github.com/rust-lang/rust-clippy/pull/14967)
+* [`manual_ok_err`] fixed wrong suggestions with references
+  [#15053](https://github.com/rust-lang/rust-clippy/pull/15053)
+* [`identity_op`] fixed FP when encountering `Default::default()`
+  [#15028](https://github.com/rust-lang/rust-clippy/pull/15028)
+* [`exhaustive_structs`] fixed FP on structs with default valued field
+  [#15022](https://github.com/rust-lang/rust-clippy/pull/15022)
+* [`collapsible_else_if`] fixed FP on conditionally compiled stmt
+  [#14906](https://github.com/rust-lang/rust-clippy/pull/14906)
+* [`missing_const_for_fn`] fixed FP by checking MSRV before emitting lint on function containing 
+  non-`Sized` trait bounds
+  [#15080](https://github.com/rust-lang/rust-clippy/pull/15080)
+* [`question_mark`] fixed FP when else branch of let-else contains `#[cfg]`
+  [#15082](https://github.com/rust-lang/rust-clippy/pull/15082)
+
+### ICE Fixes
+
+* [`single_match`] fixed ICE with deref patterns and string literals 
+  [#15124](https://github.com/rust-lang/rust-clippy/pull/15124)
+* [`needless_doctest_main`] fixed panic when doctest is invalid
+  [#15052](https://github.com/rust-lang/rust-clippy/pull/15052)
+* [`zero_sized_map_values`] do not attempt to compute size of a type with escaping lifetimes
+  [#15434](https://github.com/rust-lang/rust-clippy/pull/15434)
+
+### Documentation Improvements
+
+* [`manual_is_variant_and`] improved documentation to include equality comparison patterns 
+  [#15239](https://github.com/rust-lang/rust-clippy/pull/15239)
+* [`uninlined_format_args`] improved documentation with example of how to fix a `{:?}` parameter
+  [#15228](https://github.com/rust-lang/rust-clippy/pull/15228)
+* [`undocumented_unsafe_blocks`] improved documentation wording 
+  [#15213](https://github.com/rust-lang/rust-clippy/pull/15213)
 
 ## Rust 1.89
 
@@ -6408,6 +6553,7 @@ Released 2018-09-13
 [`redundant_feature_names`]: https://rust-lang.github.io/rust-clippy/master/index.html#redundant_feature_names
 [`redundant_field_names`]: https://rust-lang.github.io/rust-clippy/master/index.html#redundant_field_names
 [`redundant_guards`]: https://rust-lang.github.io/rust-clippy/master/index.html#redundant_guards
+[`redundant_iter_cloned`]: https://rust-lang.github.io/rust-clippy/master/index.html#redundant_iter_cloned
 [`redundant_locals`]: https://rust-lang.github.io/rust-clippy/master/index.html#redundant_locals
 [`redundant_pattern`]: https://rust-lang.github.io/rust-clippy/master/index.html#redundant_pattern
 [`redundant_pattern_matching`]: https://rust-lang.github.io/rust-clippy/master/index.html#redundant_pattern_matching
diff --git a/src/tools/clippy/Cargo.toml b/src/tools/clippy/Cargo.toml
index b3618932ded..e0638349989 100644
--- a/src/tools/clippy/Cargo.toml
+++ b/src/tools/clippy/Cargo.toml
@@ -1,6 +1,6 @@
 [package]
 name = "clippy"
-version = "0.1.91"
+version = "0.1.92"
 description = "A bunch of helpful lints to avoid common pitfalls in Rust"
 repository = "https://github.com/rust-lang/rust-clippy"
 readme = "README.md"
diff --git a/src/tools/clippy/book/src/README.md b/src/tools/clippy/book/src/README.md
index db73b49ecc2..5d2c3972b06 100644
--- a/src/tools/clippy/book/src/README.md
+++ b/src/tools/clippy/book/src/README.md
@@ -1,9 +1,5 @@
 # Clippy
 
-[### IMPORTANT NOTE FOR CONTRIBUTORS ================](development/feature_freeze.md)
-
-----
-
 [![License: MIT OR Apache-2.0](https://img.shields.io/crates/l/clippy.svg)](https://github.com/rust-lang/rust-clippy#license)
 
 A collection of lints to catch common mistakes and improve your
diff --git a/src/tools/clippy/book/src/SUMMARY.md b/src/tools/clippy/book/src/SUMMARY.md
index b66c3481e49..39fe7358ed8 100644
--- a/src/tools/clippy/book/src/SUMMARY.md
+++ b/src/tools/clippy/book/src/SUMMARY.md
@@ -13,7 +13,6 @@
     - [GitLab CI](continuous_integration/gitlab.md)
     - [Travis CI](continuous_integration/travis.md)
 - [Development](development/README.md)
-    - [IMPORTANT: FEATURE FREEZE](development/feature_freeze.md)
     - [Basics](development/basics.md)
     - [Adding Lints](development/adding_lints.md)
     - [Defining Lints](development/defining_lints.md)
diff --git a/src/tools/clippy/book/src/development/adding_lints.md b/src/tools/clippy/book/src/development/adding_lints.md
index a42a2983744..2b89e94cf8f 100644
--- a/src/tools/clippy/book/src/development/adding_lints.md
+++ b/src/tools/clippy/book/src/development/adding_lints.md
@@ -1,8 +1,5 @@
 # Adding a new lint
 
-[### IMPORTANT NOTE FOR CONTRIBUTORS ================](feature_freeze.md)
-
-
 You are probably here because you want to add a new lint to Clippy. If this is
 the first time you're contributing to Clippy, this document guides you through
 creating an example lint from scratch.
diff --git a/src/tools/clippy/book/src/development/feature_freeze.md b/src/tools/clippy/book/src/development/feature_freeze.md
deleted file mode 100644
index 260cb136cc0..00000000000
--- a/src/tools/clippy/book/src/development/feature_freeze.md
+++ /dev/null
@@ -1,55 +0,0 @@
-# IMPORTANT: FEATURE FREEZE
-
-This is a temporary notice.
-
-From the 26th of June until the 18th of September we will perform a feature freeze. Only bugfix PRs will be reviewed
-except already open ones. Every feature-adding PR opened in between those dates will be moved into a
-milestone to be reviewed separately at another time.
-
-We do this because of the long backlog of bugs that need to be addressed
-in order to continue being the state-of-the-art linter that Clippy has become known for being.
-
-## For contributors
-
-If you are a contributor or are planning to become one, **please do not open a lint-adding PR**, we have lots of open
-bugs of all levels of difficulty that you can address instead!
-
-We currently have about 800 lints, each one posing a maintainability challenge that needs to account to every possible
-use case of the whole ecosystem. Bugs are natural in every software, but the Clippy team considers that Clippy needs a
-refinement period.
-
-If you open a PR at this time, we will not review it but push it into a milestone until the refinement period ends,
-adding additional load into our reviewing schedules.
-
-## I want to help, what can I do
-
-Thanks a lot to everyone who wants to help Clippy become better software in this feature freeze period!
-If you'd like to help, making a bugfix, making sure that it works, and opening a PR is a great step!
-
-To find things to fix, go to the [tracking issue][tracking_issue], find an issue that you like, go there and claim that
-issue with `@rustbot claim`.
-
-As a general metric and always taking into account your skill and knowledge level, you can use this guide:
-
-- 🟥 [ICEs][search_ice], these are compiler errors that causes Clippy to panic and crash. Usually involves high-level
-debugging, sometimes interacting directly with the upstream compiler. Difficult to fix but a great challenge that
-improves a lot developer workflows!
-
-- 🟧 [Suggestion causes bug][sugg_causes_bug], Clippy suggested code that changed logic in some silent way.
-Unacceptable, as this may have disastrous consequences. Easier to fix than ICEs
-
-- 🟨 [Suggestion causes error][sugg_causes_error], Clippy suggested code snippet that caused a compiler error
-when applied. We need to make sure that Clippy doesn't suggest using a variable twice at the same time or similar
-easy-to-happen occurrences.
-
-- 🟩 [False positives][false_positive], a lint should not have fired, the easiest of them all, as this is "just"
-identifying the root of a false positive and making an exception for those cases.
-
-Note that false negatives do not have priority unless the case is very clear, as they are a feature-request in a
-trench coat.
-
-[search_ice]: https://github.com/rust-lang/rust-clippy/issues?q=sort%3Aupdated-desc+state%3Aopen+label%3A%22I-ICE%22
-[sugg_causes_bug]: https://github.com/rust-lang/rust-clippy/issues?q=sort%3Aupdated-desc%20state%3Aopen%20label%3AI-suggestion-causes-bug
-[sugg_causes_error]: https://github.com/rust-lang/rust-clippy/issues?q=sort%3Aupdated-desc%20state%3Aopen%20label%3AI-suggestion-causes-error%20
-[false_positive]: https://github.com/rust-lang/rust-clippy/issues?q=sort%3Aupdated-desc%20state%3Aopen%20label%3AI-false-positive
-[tracking_issue]: https://github.com/rust-lang/rust-clippy/issues/15086
diff --git a/src/tools/clippy/clippy_config/Cargo.toml b/src/tools/clippy/clippy_config/Cargo.toml
index 6ad2cf0d0b1..f8c748290e4 100644
--- a/src/tools/clippy/clippy_config/Cargo.toml
+++ b/src/tools/clippy/clippy_config/Cargo.toml
@@ -1,6 +1,6 @@
 [package]
 name = "clippy_config"
-version = "0.1.91"
+version = "0.1.92"
 edition = "2024"
 publish = false
 
diff --git a/src/tools/clippy/clippy_lints/Cargo.toml b/src/tools/clippy/clippy_lints/Cargo.toml
index 70184ee2ca5..51e59ae2050 100644
--- a/src/tools/clippy/clippy_lints/Cargo.toml
+++ b/src/tools/clippy/clippy_lints/Cargo.toml
@@ -1,6 +1,6 @@
 [package]
 name = "clippy_lints"
-version = "0.1.91"
+version = "0.1.92"
 description = "A bunch of helpful lints to avoid common pitfalls in Rust"
 repository = "https://github.com/rust-lang/rust-clippy"
 readme = "README.md"
diff --git a/src/tools/clippy/clippy_lints/src/attrs/useless_attribute.rs b/src/tools/clippy/clippy_lints/src/attrs/useless_attribute.rs
index b9b5cedb5aa..1cebc18edc9 100644
--- a/src/tools/clippy/clippy_lints/src/attrs/useless_attribute.rs
+++ b/src/tools/clippy/clippy_lints/src/attrs/useless_attribute.rs
@@ -30,6 +30,7 @@ pub(super) fn check(cx: &EarlyContext<'_>, item: &Item, attrs: &[Attribute]) {
                                 sym::ambiguous_glob_reexports
                                     | sym::dead_code
                                     | sym::deprecated
+                                    | sym::deprecated_in_future
                                     | sym::hidden_glob_reexports
                                     | sym::unreachable_pub
                                     | sym::unused
diff --git a/src/tools/clippy/clippy_lints/src/casts/as_underscore.rs b/src/tools/clippy/clippy_lints/src/casts/as_underscore.rs
index 3ac486dd63f..a73e48e5fd5 100644
--- a/src/tools/clippy/clippy_lints/src/casts/as_underscore.rs
+++ b/src/tools/clippy/clippy_lints/src/casts/as_underscore.rs
@@ -2,7 +2,7 @@ use clippy_utils::diagnostics::span_lint_and_then;
 use rustc_errors::Applicability;
 use rustc_hir::{Expr, Ty, TyKind};
 use rustc_lint::LateContext;
-use rustc_middle::ty;
+use rustc_middle::ty::IsSuggestable;
 
 use super::AS_UNDERSCORE;
 
@@ -10,15 +10,15 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, ty: &'tc
     if matches!(ty.kind, TyKind::Infer(())) {
         span_lint_and_then(cx, AS_UNDERSCORE, expr.span, "using `as _` conversion", |diag| {
             let ty_resolved = cx.typeck_results().expr_ty(expr);
-            if let ty::Error(_) = ty_resolved.kind() {
-                diag.help("consider giving the type explicitly");
-            } else {
+            if ty_resolved.is_suggestable(cx.tcx, true) {
                 diag.span_suggestion(
                     ty.span,
                     "consider giving the type explicitly",
                     ty_resolved,
                     Applicability::MachineApplicable,
                 );
+            } else {
+                diag.help("consider giving the type explicitly");
             }
         });
     }
diff --git a/src/tools/clippy/clippy_lints/src/casts/cast_possible_wrap.rs b/src/tools/clippy/clippy_lints/src/casts/cast_possible_wrap.rs
index e26c03ccda9..9eaa6e4cf26 100644
--- a/src/tools/clippy/clippy_lints/src/casts/cast_possible_wrap.rs
+++ b/src/tools/clippy/clippy_lints/src/casts/cast_possible_wrap.rs
@@ -1,4 +1,7 @@
 use clippy_utils::diagnostics::span_lint_and_then;
+use clippy_utils::msrvs::{self, Msrv};
+use clippy_utils::sugg::Sugg;
+use rustc_errors::Applicability;
 use rustc_hir::Expr;
 use rustc_lint::LateContext;
 use rustc_middle::ty::Ty;
@@ -16,7 +19,14 @@ enum EmitState {
     LintOnPtrSize(u64),
 }
 
-pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, cast_from: Ty<'_>, cast_to: Ty<'_>) {
+pub(super) fn check(
+    cx: &LateContext<'_>,
+    expr: &Expr<'_>,
+    cast_op: &Expr<'_>,
+    cast_from: Ty<'_>,
+    cast_to: Ty<'_>,
+    msrv: Msrv,
+) {
     let (Some(from_nbits), Some(to_nbits)) = (
         utils::int_ty_to_nbits(cx.tcx, cast_from),
         utils::int_ty_to_nbits(cx.tcx, cast_to),
@@ -85,5 +95,23 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, cast_from: Ty<'_>, ca
                 .note("`usize` and `isize` may be as small as 16 bits on some platforms")
                 .note("for more information see https://doc.rust-lang.org/reference/types/numeric.html#machine-dependent-integer-types");
         }
+
+        if msrv.meets(cx, msrvs::INTEGER_SIGN_CAST)
+            && let Some(cast) = utils::is_signedness_cast(cast_from, cast_to)
+        {
+            let method = match cast {
+                utils::CastTo::Signed => "cast_signed()",
+                utils::CastTo::Unsigned => "cast_unsigned()",
+            };
+            let mut app = Applicability::MaybeIncorrect;
+            let sugg = Sugg::hir_with_context(cx, cast_op, expr.span.ctxt(), "..", &mut app);
+
+            diag.span_suggestion(
+                expr.span,
+                format!("if this is intentional, use `{method}` instead"),
+                format!("{}.{method}", sugg.maybe_paren()),
+                app,
+            );
+        }
     });
 }
diff --git a/src/tools/clippy/clippy_lints/src/casts/cast_sign_loss.rs b/src/tools/clippy/clippy_lints/src/casts/cast_sign_loss.rs
index a70bd886191..f870d27b796 100644
--- a/src/tools/clippy/clippy_lints/src/casts/cast_sign_loss.rs
+++ b/src/tools/clippy/clippy_lints/src/casts/cast_sign_loss.rs
@@ -2,15 +2,18 @@ use std::convert::Infallible;
 use std::ops::ControlFlow;
 
 use clippy_utils::consts::{ConstEvalCtxt, Constant};
-use clippy_utils::diagnostics::span_lint;
+use clippy_utils::diagnostics::span_lint_and_then;
+use clippy_utils::msrvs::{self, Msrv};
+use clippy_utils::sugg::Sugg;
 use clippy_utils::visitors::{Descend, for_each_expr_without_closures};
 use clippy_utils::{method_chain_args, sext, sym};
+use rustc_errors::Applicability;
 use rustc_hir::{BinOpKind, Expr, ExprKind};
 use rustc_lint::LateContext;
 use rustc_middle::ty::{self, Ty};
 use rustc_span::Symbol;
 
-use super::CAST_SIGN_LOSS;
+use super::{CAST_SIGN_LOSS, utils};
 
 /// A list of methods that can never return a negative value.
 /// Includes methods that panic rather than returning a negative value.
@@ -42,13 +45,33 @@ pub(super) fn check<'cx>(
     cast_op: &Expr<'_>,
     cast_from: Ty<'cx>,
     cast_to: Ty<'_>,
+    msrv: Msrv,
 ) {
     if should_lint(cx, cast_op, cast_from, cast_to) {
-        span_lint(
+        span_lint_and_then(
             cx,
             CAST_SIGN_LOSS,
             expr.span,
             format!("casting `{cast_from}` to `{cast_to}` may lose the sign of the value"),
+            |diag| {
+                if msrv.meets(cx, msrvs::INTEGER_SIGN_CAST)
+                    && let Some(cast) = utils::is_signedness_cast(cast_from, cast_to)
+                {
+                    let method = match cast {
+                        utils::CastTo::Signed => "cast_signed()",
+                        utils::CastTo::Unsigned => "cast_unsigned()",
+                    };
+                    let mut app = Applicability::MaybeIncorrect;
+                    let sugg = Sugg::hir_with_context(cx, cast_op, expr.span.ctxt(), "..", &mut app);
+
+                    diag.span_suggestion(
+                        expr.span,
+                        format!("if this is intentional, use `{method}` instead"),
+                        format!("{}.{method}", sugg.maybe_paren()),
+                        app,
+                    );
+                }
+            },
         );
     }
 }
diff --git a/src/tools/clippy/clippy_lints/src/casts/mod.rs b/src/tools/clippy/clippy_lints/src/casts/mod.rs
index d2e62ee56e4..47cc1da0a6e 100644
--- a/src/tools/clippy/clippy_lints/src/casts/mod.rs
+++ b/src/tools/clippy/clippy_lints/src/casts/mod.rs
@@ -890,9 +890,9 @@ impl<'tcx> LateLintPass<'tcx> for Casts {
             if cast_to.is_numeric() {
                 cast_possible_truncation::check(cx, expr, cast_from_expr, cast_from, cast_to, cast_to_hir.span);
                 if cast_from.is_numeric() {
-                    cast_possible_wrap::check(cx, expr, cast_from, cast_to);
+                    cast_possible_wrap::check(cx, expr, cast_from_expr, cast_from, cast_to, self.msrv);
                     cast_precision_loss::check(cx, expr, cast_from, cast_to);
-                    cast_sign_loss::check(cx, expr, cast_from_expr, cast_from, cast_to);
+                    cast_sign_loss::check(cx, expr, cast_from_expr, cast_from, cast_to, self.msrv);
                     cast_abs_to_unsigned::check(cx, expr, cast_from_expr, cast_from, cast_to, self.msrv);
                     cast_nan_to_int::check(cx, expr, cast_from_expr, cast_from, cast_to);
                 }
diff --git a/src/tools/clippy/clippy_lints/src/casts/utils.rs b/src/tools/clippy/clippy_lints/src/casts/utils.rs
index d846d78b9ee..707fc2a8eed 100644
--- a/src/tools/clippy/clippy_lints/src/casts/utils.rs
+++ b/src/tools/clippy/clippy_lints/src/casts/utils.rs
@@ -60,3 +60,18 @@ pub(super) fn enum_ty_to_nbits(adt: AdtDef<'_>, tcx: TyCtxt<'_>) -> u64 {
         neg_bits.max(pos_bits).into()
     }
 }
+
+pub(super) enum CastTo {
+    Signed,
+    Unsigned,
+}
+/// Returns `Some` if the type cast is between 2 integral types that differ
+/// only in signedness, otherwise `None`. The value of `Some` is which
+/// signedness is casted to.
+pub(super) fn is_signedness_cast(cast_from: Ty<'_>, cast_to: Ty<'_>) -> Option<CastTo> {
+    match (cast_from.kind(), cast_to.kind()) {
+        (ty::Int(from), ty::Uint(to)) if from.to_unsigned() == *to => Some(CastTo::Unsigned),
+        (ty::Uint(from), ty::Int(to)) if *from == to.to_unsigned() => Some(CastTo::Signed),
+        _ => None,
+    }
+}
diff --git a/src/tools/clippy/clippy_lints/src/declared_lints.rs b/src/tools/clippy/clippy_lints/src/declared_lints.rs
index d0c7443a4a4..2a4bedc1845 100644
--- a/src/tools/clippy/clippy_lints/src/declared_lints.rs
+++ b/src/tools/clippy/clippy_lints/src/declared_lints.rs
@@ -448,10 +448,12 @@ pub static LINTS: &[&::declare_clippy_lint::LintInfo] = &[
     crate::methods::OR_THEN_UNWRAP_INFO,
     crate::methods::PATH_BUF_PUSH_OVERWRITE_INFO,
     crate::methods::PATH_ENDS_WITH_EXT_INFO,
+    crate::methods::PTR_OFFSET_WITH_CAST_INFO,
     crate::methods::RANGE_ZIP_WITH_LEN_INFO,
     crate::methods::READONLY_WRITE_LOCK_INFO,
     crate::methods::READ_LINE_WITHOUT_TRIM_INFO,
     crate::methods::REDUNDANT_AS_STR_INFO,
+    crate::methods::REDUNDANT_ITER_CLONED_INFO,
     crate::methods::REPEAT_ONCE_INFO,
     crate::methods::RESULT_FILTER_MAP_INFO,
     crate::methods::RESULT_MAP_OR_INTO_OPTION_INFO,
@@ -503,7 +505,6 @@ pub static LINTS: &[&::declare_clippy_lint::LintInfo] = &[
     crate::min_ident_chars::MIN_IDENT_CHARS_INFO,
     crate::minmax::MIN_MAX_INFO,
     crate::misc::SHORT_CIRCUIT_STATEMENT_INFO,
-    crate::misc::TOPLEVEL_REF_ARG_INFO,
     crate::misc::USED_UNDERSCORE_BINDING_INFO,
     crate::misc::USED_UNDERSCORE_ITEMS_INFO,
     crate::misc_early::BUILTIN_TYPE_SHADOW_INFO,
@@ -625,7 +626,6 @@ pub static LINTS: &[&::declare_clippy_lint::LintInfo] = &[
     crate::ptr::MUT_FROM_REF_INFO,
     crate::ptr::PTR_ARG_INFO,
     crate::ptr::PTR_EQ_INFO,
-    crate::ptr_offset_with_cast::PTR_OFFSET_WITH_CAST_INFO,
     crate::pub_underscore_fields::PUB_UNDERSCORE_FIELDS_INFO,
     crate::pub_use::PUB_USE_INFO,
     crate::question_mark::QUESTION_MARK_INFO,
@@ -706,6 +706,7 @@ pub static LINTS: &[&::declare_clippy_lint::LintInfo] = &[
     crate::tests_outside_test_module::TESTS_OUTSIDE_TEST_MODULE_INFO,
     crate::to_digit_is_some::TO_DIGIT_IS_SOME_INFO,
     crate::to_string_trait_impl::TO_STRING_TRAIT_IMPL_INFO,
+    crate::toplevel_ref_arg::TOPLEVEL_REF_ARG_INFO,
     crate::trailing_empty_array::TRAILING_EMPTY_ARRAY_INFO,
     crate::trait_bounds::TRAIT_DUPLICATION_IN_BOUNDS_INFO,
     crate::trait_bounds::TYPE_REPETITION_IN_BOUNDS_INFO,
diff --git a/src/tools/clippy/clippy_lints/src/dereference.rs b/src/tools/clippy/clippy_lints/src/dereference.rs
index 9645a26a68a..a70105db194 100644
--- a/src/tools/clippy/clippy_lints/src/dereference.rs
+++ b/src/tools/clippy/clippy_lints/src/dereference.rs
@@ -1,10 +1,9 @@
 use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_hir_and_then};
 use clippy_utils::source::{snippet_with_applicability, snippet_with_context};
 use clippy_utils::sugg::has_enclosing_paren;
-use clippy_utils::ty::{adjust_derefs_manually_drop, implements_trait, is_manually_drop};
+use clippy_utils::ty::{adjust_derefs_manually_drop, implements_trait, is_manually_drop, peel_and_count_ty_refs};
 use clippy_utils::{
     DefinedTy, ExprUseNode, expr_use_ctxt, get_parent_expr, is_block_like, is_lint_allowed, path_to_local,
-    peel_middle_ty_refs,
 };
 use rustc_ast::util::parser::ExprPrecedence;
 use rustc_data_structures::fx::FxIndexMap;
@@ -942,7 +941,7 @@ fn report<'tcx>(
             let (expr_str, expr_is_macro_call) =
                 snippet_with_context(cx, expr.span, data.first_expr.span.ctxt(), "..", &mut app);
             let ty = typeck.expr_ty(expr);
-            let (_, ref_count) = peel_middle_ty_refs(ty);
+            let (_, ref_count, _) = peel_and_count_ty_refs(ty);
             let deref_str = if ty_changed_count >= ref_count && ref_count != 0 {
                 // a deref call changing &T -> &U requires two deref operators the first time
                 // this occurs. One to remove the reference, a second to call the deref impl.
@@ -1045,7 +1044,7 @@ fn report<'tcx>(
             if let ty::Ref(_, dst, _) = data.adjusted_ty.kind()
                 && dst.is_slice()
             {
-                let (src, n_src_refs) = peel_middle_ty_refs(ty);
+                let (src, n_src_refs, _) = peel_and_count_ty_refs(ty);
                 if n_src_refs >= 2 && src.is_array() {
                     return;
                 }
diff --git a/src/tools/clippy/clippy_lints/src/derive.rs b/src/tools/clippy/clippy_lints/src/derive.rs
deleted file mode 100644
index c53a957f6a8..00000000000
--- a/src/tools/clippy/clippy_lints/src/derive.rs
+++ /dev/null
@@ -1,527 +0,0 @@
-use std::ops::ControlFlow;
-
-use clippy_utils::diagnostics::{span_lint_and_note, span_lint_and_then, span_lint_hir_and_then};
-use clippy_utils::ty::{implements_trait, implements_trait_with_env, is_copy};
-use clippy_utils::{has_non_exhaustive_attr, is_lint_allowed, paths};
-use rustc_errors::Applicability;
-use rustc_hir::def_id::DefId;
-use rustc_hir::intravisit::{FnKind, Visitor, walk_expr, walk_fn, walk_item};
-use rustc_hir::{self as hir, BlockCheckMode, BodyId, Expr, ExprKind, FnDecl, Impl, Item, ItemKind, UnsafeSource};
-use rustc_lint::{LateContext, LateLintPass};
-use rustc_middle::hir::nested_filter;
-use rustc_middle::ty::{
-    self, ClauseKind, GenericArgKind, GenericParamDefKind, ParamEnv, TraitPredicate, Ty, TyCtxt, Upcast,
-};
-use rustc_session::declare_lint_pass;
-use rustc_span::def_id::LocalDefId;
-use rustc_span::{Span, sym};
-
-declare_clippy_lint! {
-    /// ### What it does
-    /// Lints against manual `PartialEq` implementations for types with a derived `Hash`
-    /// implementation.
-    ///
-    /// ### Why is this bad?
-    /// The implementation of these traits must agree (for
-    /// example for use with `HashMap`) so it’s probably a bad idea to use a
-    /// default-generated `Hash` implementation with an explicitly defined
-    /// `PartialEq`. In particular, the following must hold for any type:
-    ///
-    /// ```text
-    /// k1 == k2 ⇒ hash(k1) == hash(k2)
-    /// ```
-    ///
-    /// ### Example
-    /// ```ignore
-    /// #[derive(Hash)]
-    /// struct Foo;
-    ///
-    /// impl PartialEq for Foo {
-    ///     ...
-    /// }
-    /// ```
-    #[clippy::version = "pre 1.29.0"]
-    pub DERIVED_HASH_WITH_MANUAL_EQ,
-    correctness,
-    "deriving `Hash` but implementing `PartialEq` explicitly"
-}
-
-declare_clippy_lint! {
-    /// ### What it does
-    /// Lints against manual `PartialOrd` and `Ord` implementations for types with a derived `Ord`
-    /// or `PartialOrd` implementation.
-    ///
-    /// ### Why is this bad?
-    /// The implementation of these traits must agree (for
-    /// example for use with `sort`) so it’s probably a bad idea to use a
-    /// default-generated `Ord` implementation with an explicitly defined
-    /// `PartialOrd`. In particular, the following must hold for any type
-    /// implementing `Ord`:
-    ///
-    /// ```text
-    /// k1.cmp(&k2) == k1.partial_cmp(&k2).unwrap()
-    /// ```
-    ///
-    /// ### Example
-    /// ```rust,ignore
-    /// #[derive(Ord, PartialEq, Eq)]
-    /// struct Foo;
-    ///
-    /// impl PartialOrd for Foo {
-    ///     ...
-    /// }
-    /// ```
-    /// Use instead:
-    /// ```rust,ignore
-    /// #[derive(PartialEq, Eq)]
-    /// struct Foo;
-    ///
-    /// impl PartialOrd for Foo {
-    ///     fn partial_cmp(&self, other: &Foo) -> Option<Ordering> {
-    ///        Some(self.cmp(other))
-    ///     }
-    /// }
-    ///
-    /// impl Ord for Foo {
-    ///     ...
-    /// }
-    /// ```
-    /// or, if you don't need a custom ordering:
-    /// ```rust,ignore
-    /// #[derive(Ord, PartialOrd, PartialEq, Eq)]
-    /// struct Foo;
-    /// ```
-    #[clippy::version = "1.47.0"]
-    pub DERIVE_ORD_XOR_PARTIAL_ORD,
-    correctness,
-    "deriving `Ord` but implementing `PartialOrd` explicitly"
-}
-
-declare_clippy_lint! {
-    /// ### What it does
-    /// Checks for explicit `Clone` implementations for `Copy`
-    /// types.
-    ///
-    /// ### Why is this bad?
-    /// To avoid surprising behavior, these traits should
-    /// agree and the behavior of `Copy` cannot be overridden. In almost all
-    /// situations a `Copy` type should have a `Clone` implementation that does
-    /// nothing more than copy the object, which is what `#[derive(Copy, Clone)]`
-    /// gets you.
-    ///
-    /// ### Example
-    /// ```rust,ignore
-    /// #[derive(Copy)]
-    /// struct Foo;
-    ///
-    /// impl Clone for Foo {
-    ///     // ..
-    /// }
-    /// ```
-    #[clippy::version = "pre 1.29.0"]
-    pub EXPL_IMPL_CLONE_ON_COPY,
-    pedantic,
-    "implementing `Clone` explicitly on `Copy` types"
-}
-
-declare_clippy_lint! {
-    /// ### What it does
-    /// Checks for deriving `serde::Deserialize` on a type that
-    /// has methods using `unsafe`.
-    ///
-    /// ### Why is this bad?
-    /// Deriving `serde::Deserialize` will create a constructor
-    /// that may violate invariants held by another constructor.
-    ///
-    /// ### Example
-    /// ```rust,ignore
-    /// use serde::Deserialize;
-    ///
-    /// #[derive(Deserialize)]
-    /// pub struct Foo {
-    ///     // ..
-    /// }
-    ///
-    /// impl Foo {
-    ///     pub fn new() -> Self {
-    ///         // setup here ..
-    ///     }
-    ///
-    ///     pub unsafe fn parts() -> (&str, &str) {
-    ///         // assumes invariants hold
-    ///     }
-    /// }
-    /// ```
-    #[clippy::version = "1.45.0"]
-    pub UNSAFE_DERIVE_DESERIALIZE,
-    pedantic,
-    "deriving `serde::Deserialize` on a type that has methods using `unsafe`"
-}
-
-declare_clippy_lint! {
-    /// ### What it does
-    /// Checks for types that derive `PartialEq` and could implement `Eq`.
-    ///
-    /// ### Why is this bad?
-    /// If a type `T` derives `PartialEq` and all of its members implement `Eq`,
-    /// then `T` can always implement `Eq`. Implementing `Eq` allows `T` to be used
-    /// in APIs that require `Eq` types. It also allows structs containing `T` to derive
-    /// `Eq` themselves.
-    ///
-    /// ### Example
-    /// ```no_run
-    /// #[derive(PartialEq)]
-    /// struct Foo {
-    ///     i_am_eq: i32,
-    ///     i_am_eq_too: Vec<String>,
-    /// }
-    /// ```
-    /// Use instead:
-    /// ```no_run
-    /// #[derive(PartialEq, Eq)]
-    /// struct Foo {
-    ///     i_am_eq: i32,
-    ///     i_am_eq_too: Vec<String>,
-    /// }
-    /// ```
-    #[clippy::version = "1.63.0"]
-    pub DERIVE_PARTIAL_EQ_WITHOUT_EQ,
-    nursery,
-    "deriving `PartialEq` on a type that can implement `Eq`, without implementing `Eq`"
-}
-
-declare_lint_pass!(Derive => [
-    EXPL_IMPL_CLONE_ON_COPY,
-    DERIVED_HASH_WITH_MANUAL_EQ,
-    DERIVE_ORD_XOR_PARTIAL_ORD,
-    UNSAFE_DERIVE_DESERIALIZE,
-    DERIVE_PARTIAL_EQ_WITHOUT_EQ
-]);
-
-impl<'tcx> LateLintPass<'tcx> for Derive {
-    fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'_>) {
-        if let ItemKind::Impl(Impl {
-            of_trait: Some(of_trait),
-            ..
-        }) = item.kind
-        {
-            let trait_ref = &of_trait.trait_ref;
-            let ty = cx.tcx.type_of(item.owner_id).instantiate_identity();
-            let is_automatically_derived = cx.tcx.is_automatically_derived(item.owner_id.to_def_id());
-
-            check_hash_peq(cx, item.span, trait_ref, ty, is_automatically_derived);
-            check_ord_partial_ord(cx, item.span, trait_ref, ty, is_automatically_derived);
-
-            if is_automatically_derived {
-                check_unsafe_derive_deserialize(cx, item, trait_ref, ty);
-                check_partial_eq_without_eq(cx, item.span, trait_ref, ty);
-            } else {
-                check_copy_clone(cx, item, trait_ref, ty);
-            }
-        }
-    }
-}
-
-/// Implementation of the `DERIVED_HASH_WITH_MANUAL_EQ` lint.
-fn check_hash_peq<'tcx>(
-    cx: &LateContext<'tcx>,
-    span: Span,
-    trait_ref: &hir::TraitRef<'_>,
-    ty: Ty<'tcx>,
-    hash_is_automatically_derived: bool,
-) {
-    if let Some(peq_trait_def_id) = cx.tcx.lang_items().eq_trait()
-        && let Some(def_id) = trait_ref.trait_def_id()
-        && cx.tcx.is_diagnostic_item(sym::Hash, def_id)
-    {
-        // Look for the PartialEq implementations for `ty`
-        cx.tcx.for_each_relevant_impl(peq_trait_def_id, ty, |impl_id| {
-            let peq_is_automatically_derived = cx.tcx.is_automatically_derived(impl_id);
-
-            if !hash_is_automatically_derived || peq_is_automatically_derived {
-                return;
-            }
-
-            let trait_ref = cx.tcx.impl_trait_ref(impl_id).expect("must be a trait implementation");
-
-            // Only care about `impl PartialEq<Foo> for Foo`
-            // For `impl PartialEq<B> for A, input_types is [A, B]
-            if trait_ref.instantiate_identity().args.type_at(1) == ty {
-                span_lint_and_then(
-                    cx,
-                    DERIVED_HASH_WITH_MANUAL_EQ,
-                    span,
-                    "you are deriving `Hash` but have implemented `PartialEq` explicitly",
-                    |diag| {
-                        if let Some(local_def_id) = impl_id.as_local() {
-                            let hir_id = cx.tcx.local_def_id_to_hir_id(local_def_id);
-                            diag.span_note(cx.tcx.hir_span(hir_id), "`PartialEq` implemented here");
-                        }
-                    },
-                );
-            }
-        });
-    }
-}
-
-/// Implementation of the `DERIVE_ORD_XOR_PARTIAL_ORD` lint.
-fn check_ord_partial_ord<'tcx>(
-    cx: &LateContext<'tcx>,
-    span: Span,
-    trait_ref: &hir::TraitRef<'_>,
-    ty: Ty<'tcx>,
-    ord_is_automatically_derived: bool,
-) {
-    if let Some(ord_trait_def_id) = cx.tcx.get_diagnostic_item(sym::Ord)
-        && let Some(partial_ord_trait_def_id) = cx.tcx.lang_items().partial_ord_trait()
-        && let Some(def_id) = &trait_ref.trait_def_id()
-        && *def_id == ord_trait_def_id
-    {
-        // Look for the PartialOrd implementations for `ty`
-        cx.tcx.for_each_relevant_impl(partial_ord_trait_def_id, ty, |impl_id| {
-            let partial_ord_is_automatically_derived = cx.tcx.is_automatically_derived(impl_id);
-
-            if partial_ord_is_automatically_derived == ord_is_automatically_derived {
-                return;
-            }
-
-            let trait_ref = cx.tcx.impl_trait_ref(impl_id).expect("must be a trait implementation");
-
-            // Only care about `impl PartialOrd<Foo> for Foo`
-            // For `impl PartialOrd<B> for A, input_types is [A, B]
-            if trait_ref.instantiate_identity().args.type_at(1) == ty {
-                let mess = if partial_ord_is_automatically_derived {
-                    "you are implementing `Ord` explicitly but have derived `PartialOrd`"
-                } else {
-                    "you are deriving `Ord` but have implemented `PartialOrd` explicitly"
-                };
-
-                span_lint_and_then(cx, DERIVE_ORD_XOR_PARTIAL_ORD, span, mess, |diag| {
-                    if let Some(local_def_id) = impl_id.as_local() {
-                        let hir_id = cx.tcx.local_def_id_to_hir_id(local_def_id);
-                        diag.span_note(cx.tcx.hir_span(hir_id), "`PartialOrd` implemented here");
-                    }
-                });
-            }
-        });
-    }
-}
-
-/// Implementation of the `EXPL_IMPL_CLONE_ON_COPY` lint.
-fn check_copy_clone<'tcx>(cx: &LateContext<'tcx>, item: &Item<'_>, trait_ref: &hir::TraitRef<'_>, ty: Ty<'tcx>) {
-    let clone_id = match cx.tcx.lang_items().clone_trait() {
-        Some(id) if trait_ref.trait_def_id() == Some(id) => id,
-        _ => return,
-    };
-    let Some(copy_id) = cx.tcx.lang_items().copy_trait() else {
-        return;
-    };
-    let (ty_adt, ty_subs) = match *ty.kind() {
-        // Unions can't derive clone.
-        ty::Adt(adt, subs) if !adt.is_union() => (adt, subs),
-        _ => return,
-    };
-    // If the current self type doesn't implement Copy (due to generic constraints), search to see if
-    // there's a Copy impl for any instance of the adt.
-    if !is_copy(cx, ty) {
-        if ty_subs.non_erasable_generics().next().is_some() {
-            let has_copy_impl = cx.tcx.local_trait_impls(copy_id).iter().any(|&id| {
-                matches!(cx.tcx.type_of(id).instantiate_identity().kind(), ty::Adt(adt, _)
-                                        if ty_adt.did() == adt.did())
-            });
-            if !has_copy_impl {
-                return;
-            }
-        } else {
-            return;
-        }
-    }
-    // Derive constrains all generic types to requiring Clone. Check if any type is not constrained for
-    // this impl.
-    if ty_subs.types().any(|ty| !implements_trait(cx, ty, clone_id, &[])) {
-        return;
-    }
-    // `#[repr(packed)]` structs with type/const parameters can't derive `Clone`.
-    // https://github.com/rust-lang/rust-clippy/issues/10188
-    if ty_adt.repr().packed()
-        && ty_subs
-            .iter()
-            .any(|arg| matches!(arg.kind(), GenericArgKind::Type(_) | GenericArgKind::Const(_)))
-    {
-        return;
-    }
-    // The presence of `unsafe` fields prevents deriving `Clone` automatically
-    if ty_adt.all_fields().any(|f| f.safety.is_unsafe()) {
-        return;
-    }
-
-    span_lint_and_note(
-        cx,
-        EXPL_IMPL_CLONE_ON_COPY,
-        item.span,
-        "you are implementing `Clone` explicitly on a `Copy` type",
-        Some(item.span),
-        "consider deriving `Clone` or removing `Copy`",
-    );
-}
-
-/// Implementation of the `UNSAFE_DERIVE_DESERIALIZE` lint.
-fn check_unsafe_derive_deserialize<'tcx>(
-    cx: &LateContext<'tcx>,
-    item: &Item<'_>,
-    trait_ref: &hir::TraitRef<'_>,
-    ty: Ty<'tcx>,
-) {
-    fn has_unsafe<'tcx>(cx: &LateContext<'tcx>, item: &'tcx Item<'_>) -> bool {
-        let mut visitor = UnsafeVisitor { cx };
-        walk_item(&mut visitor, item).is_break()
-    }
-
-    if let Some(trait_def_id) = trait_ref.trait_def_id()
-        && paths::SERDE_DESERIALIZE.matches(cx, trait_def_id)
-        && let ty::Adt(def, _) = ty.kind()
-        && let Some(local_def_id) = def.did().as_local()
-        && let adt_hir_id = cx.tcx.local_def_id_to_hir_id(local_def_id)
-        && !is_lint_allowed(cx, UNSAFE_DERIVE_DESERIALIZE, adt_hir_id)
-        && cx
-            .tcx
-            .inherent_impls(def.did())
-            .iter()
-            .map(|imp_did| cx.tcx.hir_expect_item(imp_did.expect_local()))
-            .any(|imp| has_unsafe(cx, imp))
-    {
-        span_lint_hir_and_then(
-            cx,
-            UNSAFE_DERIVE_DESERIALIZE,
-            adt_hir_id,
-            item.span,
-            "you are deriving `serde::Deserialize` on a type that has methods using `unsafe`",
-            |diag| {
-                diag.help(
-                    "consider implementing `serde::Deserialize` manually. See https://serde.rs/impl-deserialize.html",
-                );
-            },
-        );
-    }
-}
-
-struct UnsafeVisitor<'a, 'tcx> {
-    cx: &'a LateContext<'tcx>,
-}
-
-impl<'tcx> Visitor<'tcx> for UnsafeVisitor<'_, 'tcx> {
-    type Result = ControlFlow<()>;
-    type NestedFilter = nested_filter::All;
-
-    fn visit_fn(
-        &mut self,
-        kind: FnKind<'tcx>,
-        decl: &'tcx FnDecl<'_>,
-        body_id: BodyId,
-        _: Span,
-        id: LocalDefId,
-    ) -> Self::Result {
-        if let Some(header) = kind.header()
-            && header.is_unsafe()
-        {
-            ControlFlow::Break(())
-        } else {
-            walk_fn(self, kind, decl, body_id, id)
-        }
-    }
-
-    fn visit_expr(&mut self, expr: &'tcx Expr<'_>) -> Self::Result {
-        if let ExprKind::Block(block, _) = expr.kind
-            && block.rules == BlockCheckMode::UnsafeBlock(UnsafeSource::UserProvided)
-            && block
-                .span
-                .source_callee()
-                .and_then(|expr| expr.macro_def_id)
-                .is_none_or(|did| !self.cx.tcx.is_diagnostic_item(sym::pin_macro, did))
-        {
-            return ControlFlow::Break(());
-        }
-
-        walk_expr(self, expr)
-    }
-
-    fn maybe_tcx(&mut self) -> Self::MaybeTyCtxt {
-        self.cx.tcx
-    }
-}
-
-/// Implementation of the `DERIVE_PARTIAL_EQ_WITHOUT_EQ` lint.
-fn check_partial_eq_without_eq<'tcx>(cx: &LateContext<'tcx>, span: Span, trait_ref: &hir::TraitRef<'_>, ty: Ty<'tcx>) {
-    if let ty::Adt(adt, args) = ty.kind()
-        && cx.tcx.visibility(adt.did()).is_public()
-        && let Some(eq_trait_def_id) = cx.tcx.get_diagnostic_item(sym::Eq)
-        && let Some(def_id) = trait_ref.trait_def_id()
-        && cx.tcx.is_diagnostic_item(sym::PartialEq, def_id)
-        && !has_non_exhaustive_attr(cx.tcx, *adt)
-        && !ty_implements_eq_trait(cx.tcx, ty, eq_trait_def_id)
-        && let typing_env = typing_env_for_derived_eq(cx.tcx, adt.did(), eq_trait_def_id)
-        && let Some(local_def_id) = adt.did().as_local()
-        // If all of our fields implement `Eq`, we can implement `Eq` too
-        && adt
-            .all_fields()
-            .map(|f| f.ty(cx.tcx, args))
-            .all(|ty| implements_trait_with_env(cx.tcx, typing_env, ty, eq_trait_def_id, None, &[]))
-    {
-        span_lint_hir_and_then(
-            cx,
-            DERIVE_PARTIAL_EQ_WITHOUT_EQ,
-            cx.tcx.local_def_id_to_hir_id(local_def_id),
-            span.ctxt().outer_expn_data().call_site,
-            "you are deriving `PartialEq` and can implement `Eq`",
-            |diag| {
-                diag.span_suggestion(
-                    span.ctxt().outer_expn_data().call_site,
-                    "consider deriving `Eq` as well",
-                    "PartialEq, Eq",
-                    Applicability::MachineApplicable,
-                );
-            },
-        );
-    }
-}
-
-fn ty_implements_eq_trait<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>, eq_trait_id: DefId) -> bool {
-    tcx.non_blanket_impls_for_ty(eq_trait_id, ty).next().is_some()
-}
-
-/// Creates the `ParamEnv` used for the given type's derived `Eq` impl.
-fn typing_env_for_derived_eq(tcx: TyCtxt<'_>, did: DefId, eq_trait_id: DefId) -> ty::TypingEnv<'_> {
-    // Initial map from generic index to param def.
-    // Vec<(param_def, needs_eq)>
-    let mut params = tcx
-        .generics_of(did)
-        .own_params
-        .iter()
-        .map(|p| (p, matches!(p.kind, GenericParamDefKind::Type { .. })))
-        .collect::<Vec<_>>();
-
-    let ty_predicates = tcx.predicates_of(did).predicates;
-    for (p, _) in ty_predicates {
-        if let ClauseKind::Trait(p) = p.kind().skip_binder()
-            && p.trait_ref.def_id == eq_trait_id
-            && let ty::Param(self_ty) = p.trait_ref.self_ty().kind()
-        {
-            // Flag types which already have an `Eq` bound.
-            params[self_ty.index as usize].1 = false;
-        }
-    }
-
-    let param_env = ParamEnv::new(tcx.mk_clauses_from_iter(ty_predicates.iter().map(|&(p, _)| p).chain(
-        params.iter().filter(|&&(_, needs_eq)| needs_eq).map(|&(param, _)| {
-            ClauseKind::Trait(TraitPredicate {
-                trait_ref: ty::TraitRef::new(tcx, eq_trait_id, [tcx.mk_param_from_def(param)]),
-                polarity: ty::PredicatePolarity::Positive,
-            })
-            .upcast(tcx)
-        }),
-    )));
-    ty::TypingEnv {
-        typing_mode: ty::TypingMode::non_body_analysis(),
-        param_env,
-    }
-}
diff --git a/src/tools/clippy/clippy_lints/src/derive/derive_ord_xor_partial_ord.rs b/src/tools/clippy/clippy_lints/src/derive/derive_ord_xor_partial_ord.rs
new file mode 100644
index 00000000000..cbbcb2f7a3b
--- /dev/null
+++ b/src/tools/clippy/clippy_lints/src/derive/derive_ord_xor_partial_ord.rs
@@ -0,0 +1,50 @@
+use clippy_utils::diagnostics::span_lint_and_then;
+use rustc_hir as hir;
+use rustc_lint::LateContext;
+use rustc_middle::ty::Ty;
+use rustc_span::{Span, sym};
+
+use super::DERIVE_ORD_XOR_PARTIAL_ORD;
+
+/// Implementation of the `DERIVE_ORD_XOR_PARTIAL_ORD` lint.
+pub(super) fn check<'tcx>(
+    cx: &LateContext<'tcx>,
+    span: Span,
+    trait_ref: &hir::TraitRef<'_>,
+    ty: Ty<'tcx>,
+    ord_is_automatically_derived: bool,
+) {
+    if let Some(ord_trait_def_id) = cx.tcx.get_diagnostic_item(sym::Ord)
+        && let Some(partial_ord_trait_def_id) = cx.tcx.lang_items().partial_ord_trait()
+        && let Some(def_id) = &trait_ref.trait_def_id()
+        && *def_id == ord_trait_def_id
+    {
+        // Look for the PartialOrd implementations for `ty`
+        cx.tcx.for_each_relevant_impl(partial_ord_trait_def_id, ty, |impl_id| {
+            let partial_ord_is_automatically_derived = cx.tcx.is_automatically_derived(impl_id);
+
+            if partial_ord_is_automatically_derived == ord_is_automatically_derived {
+                return;
+            }
+
+            let trait_ref = cx.tcx.impl_trait_ref(impl_id).expect("must be a trait implementation");
+
+            // Only care about `impl PartialOrd<Foo> for Foo`
+            // For `impl PartialOrd<B> for A, input_types is [A, B]
+            if trait_ref.instantiate_identity().args.type_at(1) == ty {
+                let mess = if partial_ord_is_automatically_derived {
+                    "you are implementing `Ord` explicitly but have derived `PartialOrd`"
+                } else {
+                    "you are deriving `Ord` but have implemented `PartialOrd` explicitly"
+                };
+
+                span_lint_and_then(cx, DERIVE_ORD_XOR_PARTIAL_ORD, span, mess, |diag| {
+                    if let Some(local_def_id) = impl_id.as_local() {
+                        let hir_id = cx.tcx.local_def_id_to_hir_id(local_def_id);
+                        diag.span_note(cx.tcx.hir_span(hir_id), "`PartialOrd` implemented here");
+                    }
+                });
+            }
+        });
+    }
+}
diff --git a/src/tools/clippy/clippy_lints/src/derive/derive_partial_eq_without_eq.rs b/src/tools/clippy/clippy_lints/src/derive/derive_partial_eq_without_eq.rs
new file mode 100644
index 00000000000..ed7881c461f
--- /dev/null
+++ b/src/tools/clippy/clippy_lints/src/derive/derive_partial_eq_without_eq.rs
@@ -0,0 +1,87 @@
+use clippy_utils::diagnostics::span_lint_hir_and_then;
+use clippy_utils::has_non_exhaustive_attr;
+use clippy_utils::ty::implements_trait_with_env;
+use rustc_errors::Applicability;
+use rustc_hir as hir;
+use rustc_hir::def_id::DefId;
+use rustc_lint::LateContext;
+use rustc_middle::ty::{self, ClauseKind, GenericParamDefKind, ParamEnv, TraitPredicate, Ty, TyCtxt, Upcast};
+use rustc_span::{Span, sym};
+
+use super::DERIVE_PARTIAL_EQ_WITHOUT_EQ;
+
+/// Implementation of the `DERIVE_PARTIAL_EQ_WITHOUT_EQ` lint.
+pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, span: Span, trait_ref: &hir::TraitRef<'_>, ty: Ty<'tcx>) {
+    if let ty::Adt(adt, args) = ty.kind()
+        && cx.tcx.visibility(adt.did()).is_public()
+        && let Some(eq_trait_def_id) = cx.tcx.get_diagnostic_item(sym::Eq)
+        && let Some(def_id) = trait_ref.trait_def_id()
+        && cx.tcx.is_diagnostic_item(sym::PartialEq, def_id)
+        && !has_non_exhaustive_attr(cx.tcx, *adt)
+        && !ty_implements_eq_trait(cx.tcx, ty, eq_trait_def_id)
+        && let typing_env = typing_env_for_derived_eq(cx.tcx, adt.did(), eq_trait_def_id)
+        && let Some(local_def_id) = adt.did().as_local()
+        // If all of our fields implement `Eq`, we can implement `Eq` too
+        && adt
+            .all_fields()
+            .map(|f| f.ty(cx.tcx, args))
+            .all(|ty| implements_trait_with_env(cx.tcx, typing_env, ty, eq_trait_def_id, None, &[]))
+    {
+        span_lint_hir_and_then(
+            cx,
+            DERIVE_PARTIAL_EQ_WITHOUT_EQ,
+            cx.tcx.local_def_id_to_hir_id(local_def_id),
+            span.ctxt().outer_expn_data().call_site,
+            "you are deriving `PartialEq` and can implement `Eq`",
+            |diag| {
+                diag.span_suggestion(
+                    span.ctxt().outer_expn_data().call_site,
+                    "consider deriving `Eq` as well",
+                    "PartialEq, Eq",
+                    Applicability::MachineApplicable,
+                );
+            },
+        );
+    }
+}
+
+fn ty_implements_eq_trait<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>, eq_trait_id: DefId) -> bool {
+    tcx.non_blanket_impls_for_ty(eq_trait_id, ty).next().is_some()
+}
+
+/// Creates the `ParamEnv` used for the given type's derived `Eq` impl.
+fn typing_env_for_derived_eq(tcx: TyCtxt<'_>, did: DefId, eq_trait_id: DefId) -> ty::TypingEnv<'_> {
+    // Initial map from generic index to param def.
+    // Vec<(param_def, needs_eq)>
+    let mut params = tcx
+        .generics_of(did)
+        .own_params
+        .iter()
+        .map(|p| (p, matches!(p.kind, GenericParamDefKind::Type { .. })))
+        .collect::<Vec<_>>();
+
+    let ty_predicates = tcx.predicates_of(did).predicates;
+    for (p, _) in ty_predicates {
+        if let ClauseKind::Trait(p) = p.kind().skip_binder()
+            && p.trait_ref.def_id == eq_trait_id
+            && let ty::Param(self_ty) = p.trait_ref.self_ty().kind()
+        {
+            // Flag types which already have an `Eq` bound.
+            params[self_ty.index as usize].1 = false;
+        }
+    }
+
+    let param_env = ParamEnv::new(tcx.mk_clauses_from_iter(ty_predicates.iter().map(|&(p, _)| p).chain(
+        params.iter().filter(|&&(_, needs_eq)| needs_eq).map(|&(param, _)| {
+            ClauseKind::Trait(TraitPredicate {
+                trait_ref: ty::TraitRef::new(tcx, eq_trait_id, [tcx.mk_param_from_def(param)]),
+                polarity: ty::PredicatePolarity::Positive,
+            })
+            .upcast(tcx)
+        }),
+    )));
+    ty::TypingEnv {
+        typing_mode: ty::TypingMode::non_body_analysis(),
+        param_env,
+    }
+}
diff --git a/src/tools/clippy/clippy_lints/src/derive/derived_hash_with_manual_eq.rs b/src/tools/clippy/clippy_lints/src/derive/derived_hash_with_manual_eq.rs
new file mode 100644
index 00000000000..6f36a58025a
--- /dev/null
+++ b/src/tools/clippy/clippy_lints/src/derive/derived_hash_with_manual_eq.rs
@@ -0,0 +1,49 @@
+use clippy_utils::diagnostics::span_lint_and_then;
+use rustc_hir as hir;
+use rustc_lint::LateContext;
+use rustc_middle::ty::Ty;
+use rustc_span::{Span, sym};
+
+use super::DERIVED_HASH_WITH_MANUAL_EQ;
+
+/// Implementation of the `DERIVED_HASH_WITH_MANUAL_EQ` lint.
+pub(super) fn check<'tcx>(
+    cx: &LateContext<'tcx>,
+    span: Span,
+    trait_ref: &hir::TraitRef<'_>,
+    ty: Ty<'tcx>,
+    hash_is_automatically_derived: bool,
+) {
+    if let Some(peq_trait_def_id) = cx.tcx.lang_items().eq_trait()
+        && let Some(def_id) = trait_ref.trait_def_id()
+        && cx.tcx.is_diagnostic_item(sym::Hash, def_id)
+    {
+        // Look for the PartialEq implementations for `ty`
+        cx.tcx.for_each_relevant_impl(peq_trait_def_id, ty, |impl_id| {
+            let peq_is_automatically_derived = cx.tcx.is_automatically_derived(impl_id);
+
+            if !hash_is_automatically_derived || peq_is_automatically_derived {
+                return;
+            }
+
+            let trait_ref = cx.tcx.impl_trait_ref(impl_id).expect("must be a trait implementation");
+
+            // Only care about `impl PartialEq<Foo> for Foo`
+            // For `impl PartialEq<B> for A, input_types is [A, B]
+            if trait_ref.instantiate_identity().args.type_at(1) == ty {
+                span_lint_and_then(
+                    cx,
+                    DERIVED_HASH_WITH_MANUAL_EQ,
+                    span,
+                    "you are deriving `Hash` but have implemented `PartialEq` explicitly",
+                    |diag| {
+                        if let Some(local_def_id) = impl_id.as_local() {
+                            let hir_id = cx.tcx.local_def_id_to_hir_id(local_def_id);
+                            diag.span_note(cx.tcx.hir_span(hir_id), "`PartialEq` implemented here");
+                        }
+                    },
+                );
+            }
+        });
+    }
+}
diff --git a/src/tools/clippy/clippy_lints/src/derive/expl_impl_clone_on_copy.rs b/src/tools/clippy/clippy_lints/src/derive/expl_impl_clone_on_copy.rs
new file mode 100644
index 00000000000..6b97b4bd6b4
--- /dev/null
+++ b/src/tools/clippy/clippy_lints/src/derive/expl_impl_clone_on_copy.rs
@@ -0,0 +1,65 @@
+use clippy_utils::diagnostics::span_lint_and_note;
+use clippy_utils::ty::{implements_trait, is_copy};
+use rustc_hir::{self as hir, Item};
+use rustc_lint::LateContext;
+use rustc_middle::ty::{self, GenericArgKind, Ty};
+
+use super::EXPL_IMPL_CLONE_ON_COPY;
+
+/// Implementation of the `EXPL_IMPL_CLONE_ON_COPY` lint.
+pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, item: &Item<'_>, trait_ref: &hir::TraitRef<'_>, ty: Ty<'tcx>) {
+    let clone_id = match cx.tcx.lang_items().clone_trait() {
+        Some(id) if trait_ref.trait_def_id() == Some(id) => id,
+        _ => return,
+    };
+    let Some(copy_id) = cx.tcx.lang_items().copy_trait() else {
+        return;
+    };
+    let (ty_adt, ty_subs) = match *ty.kind() {
+        // Unions can't derive clone.
+        ty::Adt(adt, subs) if !adt.is_union() => (adt, subs),
+        _ => return,
+    };
+    // If the current self type doesn't implement Copy (due to generic constraints), search to see if
+    // there's a Copy impl for any instance of the adt.
+    if !is_copy(cx, ty) {
+        if ty_subs.non_erasable_generics().next().is_some() {
+            let has_copy_impl = cx.tcx.local_trait_impls(copy_id).iter().any(|&id| {
+                matches!(cx.tcx.type_of(id).instantiate_identity().kind(), ty::Adt(adt, _)
+                                        if ty_adt.did() == adt.did())
+            });
+            if !has_copy_impl {
+                return;
+            }
+        } else {
+            return;
+        }
+    }
+    // Derive constrains all generic types to requiring Clone. Check if any type is not constrained for
+    // this impl.
+    if ty_subs.types().any(|ty| !implements_trait(cx, ty, clone_id, &[])) {
+        return;
+    }
+    // `#[repr(packed)]` structs with type/const parameters can't derive `Clone`.
+    // https://github.com/rust-lang/rust-clippy/issues/10188
+    if ty_adt.repr().packed()
+        && ty_subs
+            .iter()
+            .any(|arg| matches!(arg.kind(), GenericArgKind::Type(_) | GenericArgKind::Const(_)))
+    {
+        return;
+    }
+    // The presence of `unsafe` fields prevents deriving `Clone` automatically
+    if ty_adt.all_fields().any(|f| f.safety.is_unsafe()) {
+        return;
+    }
+
+    span_lint_and_note(
+        cx,
+        EXPL_IMPL_CLONE_ON_COPY,
+        item.span,
+        "you are implementing `Clone` explicitly on a `Copy` type",
+        Some(item.span),
+        "consider deriving `Clone` or removing `Copy`",
+    );
+}
diff --git a/src/tools/clippy/clippy_lints/src/derive/mod.rs b/src/tools/clippy/clippy_lints/src/derive/mod.rs
new file mode 100644
index 00000000000..1d63394ce37
--- /dev/null
+++ b/src/tools/clippy/clippy_lints/src/derive/mod.rs
@@ -0,0 +1,215 @@
+use rustc_hir::{Impl, Item, ItemKind};
+use rustc_lint::{LateContext, LateLintPass};
+use rustc_session::declare_lint_pass;
+
+mod derive_ord_xor_partial_ord;
+mod derive_partial_eq_without_eq;
+mod derived_hash_with_manual_eq;
+mod expl_impl_clone_on_copy;
+mod unsafe_derive_deserialize;
+
+declare_clippy_lint! {
+    /// ### What it does
+    /// Lints against manual `PartialEq` implementations for types with a derived `Hash`
+    /// implementation.
+    ///
+    /// ### Why is this bad?
+    /// The implementation of these traits must agree (for
+    /// example for use with `HashMap`) so it’s probably a bad idea to use a
+    /// default-generated `Hash` implementation with an explicitly defined
+    /// `PartialEq`. In particular, the following must hold for any type:
+    ///
+    /// ```text
+    /// k1 == k2 ⇒ hash(k1) == hash(k2)
+    /// ```
+    ///
+    /// ### Example
+    /// ```ignore
+    /// #[derive(Hash)]
+    /// struct Foo;
+    ///
+    /// impl PartialEq for Foo {
+    ///     ...
+    /// }
+    /// ```
+    #[clippy::version = "pre 1.29.0"]
+    pub DERIVED_HASH_WITH_MANUAL_EQ,
+    correctness,
+    "deriving `Hash` but implementing `PartialEq` explicitly"
+}
+
+declare_clippy_lint! {
+    /// ### What it does
+    /// Lints against manual `PartialOrd` and `Ord` implementations for types with a derived `Ord`
+    /// or `PartialOrd` implementation.
+    ///
+    /// ### Why is this bad?
+    /// The implementation of these traits must agree (for
+    /// example for use with `sort`) so it’s probably a bad idea to use a
+    /// default-generated `Ord` implementation with an explicitly defined
+    /// `PartialOrd`. In particular, the following must hold for any type
+    /// implementing `Ord`:
+    ///
+    /// ```text
+    /// k1.cmp(&k2) == k1.partial_cmp(&k2).unwrap()
+    /// ```
+    ///
+    /// ### Example
+    /// ```rust,ignore
+    /// #[derive(Ord, PartialEq, Eq)]
+    /// struct Foo;
+    ///
+    /// impl PartialOrd for Foo {
+    ///     ...
+    /// }
+    /// ```
+    /// Use instead:
+    /// ```rust,ignore
+    /// #[derive(PartialEq, Eq)]
+    /// struct Foo;
+    ///
+    /// impl PartialOrd for Foo {
+    ///     fn partial_cmp(&self, other: &Foo) -> Option<Ordering> {
+    ///        Some(self.cmp(other))
+    ///     }
+    /// }
+    ///
+    /// impl Ord for Foo {
+    ///     ...
+    /// }
+    /// ```
+    /// or, if you don't need a custom ordering:
+    /// ```rust,ignore
+    /// #[derive(Ord, PartialOrd, PartialEq, Eq)]
+    /// struct Foo;
+    /// ```
+    #[clippy::version = "1.47.0"]
+    pub DERIVE_ORD_XOR_PARTIAL_ORD,
+    correctness,
+    "deriving `Ord` but implementing `PartialOrd` explicitly"
+}
+
+declare_clippy_lint! {
+    /// ### What it does
+    /// Checks for explicit `Clone` implementations for `Copy`
+    /// types.
+    ///
+    /// ### Why is this bad?
+    /// To avoid surprising behavior, these traits should
+    /// agree and the behavior of `Copy` cannot be overridden. In almost all
+    /// situations a `Copy` type should have a `Clone` implementation that does
+    /// nothing more than copy the object, which is what `#[derive(Copy, Clone)]`
+    /// gets you.
+    ///
+    /// ### Example
+    /// ```rust,ignore
+    /// #[derive(Copy)]
+    /// struct Foo;
+    ///
+    /// impl Clone for Foo {
+    ///     // ..
+    /// }
+    /// ```
+    #[clippy::version = "pre 1.29.0"]
+    pub EXPL_IMPL_CLONE_ON_COPY,
+    pedantic,
+    "implementing `Clone` explicitly on `Copy` types"
+}
+
+declare_clippy_lint! {
+    /// ### What it does
+    /// Checks for deriving `serde::Deserialize` on a type that
+    /// has methods using `unsafe`.
+    ///
+    /// ### Why is this bad?
+    /// Deriving `serde::Deserialize` will create a constructor
+    /// that may violate invariants held by another constructor.
+    ///
+    /// ### Example
+    /// ```rust,ignore
+    /// use serde::Deserialize;
+    ///
+    /// #[derive(Deserialize)]
+    /// pub struct Foo {
+    ///     // ..
+    /// }
+    ///
+    /// impl Foo {
+    ///     pub fn new() -> Self {
+    ///         // setup here ..
+    ///     }
+    ///
+    ///     pub unsafe fn parts() -> (&str, &str) {
+    ///         // assumes invariants hold
+    ///     }
+    /// }
+    /// ```
+    #[clippy::version = "1.45.0"]
+    pub UNSAFE_DERIVE_DESERIALIZE,
+    pedantic,
+    "deriving `serde::Deserialize` on a type that has methods using `unsafe`"
+}
+
+declare_clippy_lint! {
+    /// ### What it does
+    /// Checks for types that derive `PartialEq` and could implement `Eq`.
+    ///
+    /// ### Why is this bad?
+    /// If a type `T` derives `PartialEq` and all of its members implement `Eq`,
+    /// then `T` can always implement `Eq`. Implementing `Eq` allows `T` to be used
+    /// in APIs that require `Eq` types. It also allows structs containing `T` to derive
+    /// `Eq` themselves.
+    ///
+    /// ### Example
+    /// ```no_run
+    /// #[derive(PartialEq)]
+    /// struct Foo {
+    ///     i_am_eq: i32,
+    ///     i_am_eq_too: Vec<String>,
+    /// }
+    /// ```
+    /// Use instead:
+    /// ```no_run
+    /// #[derive(PartialEq, Eq)]
+    /// struct Foo {
+    ///     i_am_eq: i32,
+    ///     i_am_eq_too: Vec<String>,
+    /// }
+    /// ```
+    #[clippy::version = "1.63.0"]
+    pub DERIVE_PARTIAL_EQ_WITHOUT_EQ,
+    nursery,
+    "deriving `PartialEq` on a type that can implement `Eq`, without implementing `Eq`"
+}
+
+declare_lint_pass!(Derive => [
+    EXPL_IMPL_CLONE_ON_COPY,
+    DERIVED_HASH_WITH_MANUAL_EQ,
+    DERIVE_ORD_XOR_PARTIAL_ORD,
+    UNSAFE_DERIVE_DESERIALIZE,
+    DERIVE_PARTIAL_EQ_WITHOUT_EQ
+]);
+
+impl<'tcx> LateLintPass<'tcx> for Derive {
+    fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'_>) {
+        if let ItemKind::Impl(Impl {
+            of_trait: Some(of_trait),
+            ..
+        }) = item.kind
+        {
+            let trait_ref = &of_trait.trait_ref;
+            let ty = cx.tcx.type_of(item.owner_id).instantiate_identity();
+            let is_automatically_derived = cx.tcx.is_automatically_derived(item.owner_id.to_def_id());
+
+            derived_hash_with_manual_eq::check(cx, item.span, trait_ref, ty, is_automatically_derived);
+            derive_ord_xor_partial_ord::check(cx, item.span, trait_ref, ty, is_automatically_derived);
+
+            if is_automatically_derived {
+                unsafe_derive_deserialize::check(cx, item, trait_ref, ty);
+                derive_partial_eq_without_eq::check(cx, item.span, trait_ref, ty);
+            } else {
+                expl_impl_clone_on_copy::check(cx, item, trait_ref, ty);
+            }
+        }
+    }
+}
diff --git a/src/tools/clippy/clippy_lints/src/derive/unsafe_derive_deserialize.rs b/src/tools/clippy/clippy_lints/src/derive/unsafe_derive_deserialize.rs
new file mode 100644
index 00000000000..c391e7b6228
--- /dev/null
+++ b/src/tools/clippy/clippy_lints/src/derive/unsafe_derive_deserialize.rs
@@ -0,0 +1,93 @@
+use std::ops::ControlFlow;
+
+use clippy_utils::diagnostics::span_lint_hir_and_then;
+use clippy_utils::{is_lint_allowed, paths};
+use rustc_hir::def_id::LocalDefId;
+use rustc_hir::intravisit::{FnKind, Visitor, walk_expr, walk_fn, walk_item};
+use rustc_hir::{self as hir, BlockCheckMode, BodyId, Expr, ExprKind, FnDecl, Item, UnsafeSource};
+use rustc_lint::LateContext;
+use rustc_middle::hir::nested_filter;
+use rustc_middle::ty::{self, Ty};
+use rustc_span::{Span, sym};
+
+use super::UNSAFE_DERIVE_DESERIALIZE;
+
+/// Implementation of the `UNSAFE_DERIVE_DESERIALIZE` lint.
+pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, item: &Item<'_>, trait_ref: &hir::TraitRef<'_>, ty: Ty<'tcx>) {
+    fn has_unsafe<'tcx>(cx: &LateContext<'tcx>, item: &'tcx Item<'_>) -> bool {
+        let mut visitor = UnsafeVisitor { cx };
+        walk_item(&mut visitor, item).is_break()
+    }
+
+    if let Some(trait_def_id) = trait_ref.trait_def_id()
+        && paths::SERDE_DESERIALIZE.matches(cx, trait_def_id)
+        && let ty::Adt(def, _) = ty.kind()
+        && let Some(local_def_id) = def.did().as_local()
+        && let adt_hir_id = cx.tcx.local_def_id_to_hir_id(local_def_id)
+        && !is_lint_allowed(cx, UNSAFE_DERIVE_DESERIALIZE, adt_hir_id)
+        && cx
+            .tcx
+            .inherent_impls(def.did())
+            .iter()
+            .map(|imp_did| cx.tcx.hir_expect_item(imp_did.expect_local()))
+            .any(|imp| has_unsafe(cx, imp))
+    {
+        span_lint_hir_and_then(
+            cx,
+            UNSAFE_DERIVE_DESERIALIZE,
+            adt_hir_id,
+            item.span,
+            "you are deriving `serde::Deserialize` on a type that has methods using `unsafe`",
+            |diag| {
+                diag.help(
+                    "consider implementing `serde::Deserialize` manually. See https://serde.rs/impl-deserialize.html",
+                );
+            },
+        );
+    }
+}
+
+struct UnsafeVisitor<'a, 'tcx> {
+    cx: &'a LateContext<'tcx>,
+}
+
+impl<'tcx> Visitor<'tcx> for UnsafeVisitor<'_, 'tcx> {
+    type Result = ControlFlow<()>;
+    type NestedFilter = nested_filter::All;
+
+    fn visit_fn(
+        &mut self,
+        kind: FnKind<'tcx>,
+        decl: &'tcx FnDecl<'_>,
+        body_id: BodyId,
+        _: Span,
+        id: LocalDefId,
+    ) -> Self::Result {
+        if let Some(header) = kind.header()
+            && header.is_unsafe()
+        {
+            ControlFlow::Break(())
+        } else {
+            walk_fn(self, kind, decl, body_id, id)
+        }
+    }
+
+    fn visit_expr(&mut self, expr: &'tcx Expr<'_>) -> Self::Result {
+        if let ExprKind::Block(block, _) = expr.kind
+            && block.rules == BlockCheckMode::UnsafeBlock(UnsafeSource::UserProvided)
+            && block
+                .span
+                .source_callee()
+                .and_then(|expr| expr.macro_def_id)
+                .is_none_or(|did| !self.cx.tcx.is_diagnostic_item(sym::pin_macro, did))
+        {
+            return ControlFlow::Break(());
+        }
+
+        walk_expr(self, expr)
+    }
+
+    fn maybe_tcx(&mut self) -> Self::MaybeTyCtxt {
+        self.cx.tcx
+    }
+}
diff --git a/src/tools/clippy/clippy_lints/src/disallowed_macros.rs b/src/tools/clippy/clippy_lints/src/disallowed_macros.rs
index 49cd2671dc0..1c9c971730f 100644
--- a/src/tools/clippy/clippy_lints/src/disallowed_macros.rs
+++ b/src/tools/clippy/clippy_lints/src/disallowed_macros.rs
@@ -1,4 +1,3 @@
-
 use clippy_config::Conf;
 use clippy_config::types::{DisallowedPath, create_disallowed_map};
 use clippy_utils::diagnostics::{span_lint_and_then, span_lint_hir_and_then};
@@ -8,7 +7,8 @@ use rustc_data_structures::fx::FxHashSet;
 use rustc_hir::def::DefKind;
 use rustc_hir::def_id::DefIdMap;
 use rustc_hir::{
-    AmbigArg, Expr, ExprKind, ForeignItem, HirId, ImplItem, ImplItemImplKind, Item, ItemKind, OwnerId, Pat, Path, Stmt, TraitItem, Ty,
+    AmbigArg, Expr, ExprKind, ForeignItem, HirId, ImplItem, ImplItemImplKind, Item, ItemKind, OwnerId, Pat, Path, Stmt,
+    TraitItem, Ty,
 };
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_middle::ty::TyCtxt;
diff --git a/src/tools/clippy/clippy_lints/src/eta_reduction.rs b/src/tools/clippy/clippy_lints/src/eta_reduction.rs
index 2da1c2bad11..752f39b4e6d 100644
--- a/src/tools/clippy/clippy_lints/src/eta_reduction.rs
+++ b/src/tools/clippy/clippy_lints/src/eta_reduction.rs
@@ -197,6 +197,18 @@ fn check_closure<'tcx>(cx: &LateContext<'tcx>, outer_receiver: Option<&Expr<'tcx
                 // in a type which is `'static`.
                 // For now ignore all callee types which reference a type parameter.
                 && !generic_args.types().any(|t| matches!(t.kind(), ty::Param(_)))
+                // Rule out `AsyncFn*`s, because while they can be called as `|x| f(x)`,
+                // they can't be passed directly into a place expecting an `Fn*` (#13892)
+                && let Ok((closure_kind, _)) = cx
+                    .tcx
+                    .infer_ctxt()
+                    .build(cx.typing_mode())
+                    .err_ctxt()
+                    .type_implements_fn_trait(
+                        cx.param_env,
+                        Binder::bind_with_vars(callee_ty_adjusted, List::empty()),
+                        ty::PredicatePolarity::Positive,
+                    )
             {
                 span_lint_hir_and_then(
                     cx,
@@ -213,19 +225,10 @@ fn check_closure<'tcx>(cx: &LateContext<'tcx>, outer_receiver: Option<&Expr<'tcx
                                 // 'cuz currently nothing changes after deleting this check.
                                 local_used_in(cx, l, args) || local_used_after_expr(cx, l, expr)
                             }) {
-                                match cx
-                                    .tcx
-                                    .infer_ctxt()
-                                    .build(cx.typing_mode())
-                                    .err_ctxt()
-                                    .type_implements_fn_trait(
-                                        cx.param_env,
-                                        Binder::bind_with_vars(callee_ty_adjusted, List::empty()),
-                                        ty::PredicatePolarity::Positive,
-                                    ) {
+                                match closure_kind {
                                     // Mutable closure is used after current expr; we cannot consume it.
-                                    Ok((ClosureKind::FnMut, _)) => snippet = format!("&mut {snippet}"),
-                                    Ok((ClosureKind::Fn, _)) if !callee_ty_raw.is_ref() => {
+                                    ClosureKind::FnMut => snippet = format!("&mut {snippet}"),
+                                    ClosureKind::Fn if !callee_ty_raw.is_ref() => {
                                         snippet = format!("&{snippet}");
                                     },
                                     _ => (),
diff --git a/src/tools/clippy/clippy_lints/src/functions/not_unsafe_ptr_arg_deref.rs b/src/tools/clippy/clippy_lints/src/functions/not_unsafe_ptr_arg_deref.rs
index 906bbd006d4..72f87953040 100644
--- a/src/tools/clippy/clippy_lints/src/functions/not_unsafe_ptr_arg_deref.rs
+++ b/src/tools/clippy/clippy_lints/src/functions/not_unsafe_ptr_arg_deref.rs
@@ -4,7 +4,7 @@ use rustc_middle::ty;
 use rustc_span::def_id::LocalDefId;
 
 use clippy_utils::diagnostics::span_lint;
-use clippy_utils::ty::type_is_unsafe_function;
+use clippy_utils::ty::is_unsafe_fn;
 use clippy_utils::visitors::for_each_expr;
 use clippy_utils::{iter_input_pats, path_to_local};
 
@@ -51,7 +51,7 @@ fn check_raw_ptr<'tcx>(
             let typeck = cx.tcx.typeck_body(body.id());
             let _: Option<!> = for_each_expr(cx, body.value, |e| {
                 match e.kind {
-                    hir::ExprKind::Call(f, args) if type_is_unsafe_function(cx, typeck.expr_ty(f)) => {
+                    hir::ExprKind::Call(f, args) if is_unsafe_fn(cx, typeck.expr_ty(f)) => {
                         for arg in args {
                             check_arg(cx, &raw_ptrs, arg);
                         }
diff --git a/src/tools/clippy/clippy_lints/src/functions/ref_option.rs b/src/tools/clippy/clippy_lints/src/functions/ref_option.rs
index 106202d00d4..5dc1b7269b7 100644
--- a/src/tools/clippy/clippy_lints/src/functions/ref_option.rs
+++ b/src/tools/clippy/clippy_lints/src/functions/ref_option.rs
@@ -1,23 +1,20 @@
 use crate::functions::REF_OPTION;
 use clippy_utils::diagnostics::span_lint_and_then;
-use clippy_utils::is_trait_impl_item;
 use clippy_utils::source::snippet;
-use clippy_utils::ty::is_type_diagnostic_item;
+use clippy_utils::ty::option_arg_ty;
+use clippy_utils::{is_from_proc_macro, is_trait_impl_item};
 use rustc_errors::Applicability;
-use rustc_hir as hir;
 use rustc_hir::intravisit::FnKind;
-use rustc_hir::{FnDecl, HirId};
-use rustc_lint::LateContext;
-use rustc_middle::ty::{self, GenericArgKind, Mutability, Ty};
+use rustc_hir::{self as hir, FnDecl, HirId};
+use rustc_lint::{LateContext, LintContext};
+use rustc_middle::ty::{self, Mutability, Ty};
+use rustc_span::Span;
 use rustc_span::def_id::LocalDefId;
-use rustc_span::{Span, sym};
 
-fn check_ty<'a>(cx: &LateContext<'a>, param: &rustc_hir::Ty<'a>, param_ty: Ty<'a>, fixes: &mut Vec<(Span, String)>) {
-    if let ty::Ref(_, opt_ty, Mutability::Not) = param_ty.kind()
-        && is_type_diagnostic_item(cx, *opt_ty, sym::Option)
-        && let ty::Adt(_, opt_gen_args) = opt_ty.kind()
-        && let [gen_arg] = opt_gen_args.as_slice()
-        && let GenericArgKind::Type(gen_ty) = gen_arg.kind()
+fn check_ty<'a>(cx: &LateContext<'a>, param: &hir::Ty<'a>, param_ty: Ty<'a>, fixes: &mut Vec<(Span, String)>) {
+    if !param.span.in_external_macro(cx.sess().source_map())
+        && let ty::Ref(_, opt_ty, Mutability::Not) = param_ty.kind()
+        && let Some(gen_ty) = option_arg_ty(cx, *opt_ty)
         && !gen_ty.is_ref()
         // Need to gen the original spans, so first parsing mid, and hir parsing afterward
         && let hir::TyKind::Ref(lifetime, hir::MutTy { ty, .. }) = param.kind
@@ -27,6 +24,7 @@ fn check_ty<'a>(cx: &LateContext<'a>, param: &rustc_hir::Ty<'a>, param_ty: Ty<'a
             args: [hir::GenericArg::Type(opt_ty)],
             ..
         }) = last.args
+        && !is_from_proc_macro(cx, param)
     {
         let lifetime = snippet(cx, lifetime.ident.span, "..");
         fixes.push((
@@ -67,21 +65,24 @@ fn check_fn_sig<'a>(cx: &LateContext<'a>, decl: &FnDecl<'a>, span: Span, sig: ty
 #[allow(clippy::too_many_arguments)]
 pub(crate) fn check_fn<'a>(
     cx: &LateContext<'a>,
-    kind: FnKind<'_>,
+    kind: FnKind<'a>,
     decl: &FnDecl<'a>,
     span: Span,
     hir_id: HirId,
     def_id: LocalDefId,
-    body: &hir::Body<'_>,
+    body: &hir::Body<'a>,
     avoid_breaking_exported_api: bool,
 ) {
     if avoid_breaking_exported_api && cx.effective_visibilities.is_exported(def_id) {
         return;
     }
+    if span.in_external_macro(cx.sess().source_map()) {
+        return;
+    }
 
     if let FnKind::Closure = kind {
         // Compute the span of the closure parameters + return type if set
-        let span = if let hir::FnRetTy::Return(out_ty) = &decl.output {
+        let inputs_output_span = if let hir::FnRetTy::Return(out_ty) = &decl.output {
             if decl.inputs.is_empty() {
                 out_ty.span
             } else {
@@ -100,9 +101,18 @@ pub(crate) fn check_fn<'a>(
         };
         let sig = args.as_closure().sig().skip_binder();
 
-        check_fn_sig(cx, decl, span, sig);
+        if is_from_proc_macro(cx, &(&kind, body, hir_id, span)) {
+            return;
+        }
+
+        check_fn_sig(cx, decl, inputs_output_span, sig);
     } else if !is_trait_impl_item(cx, hir_id) {
         let sig = cx.tcx.fn_sig(def_id).instantiate_identity().skip_binder();
+
+        if is_from_proc_macro(cx, &(&kind, body, hir_id, span)) {
+            return;
+        }
+
         check_fn_sig(cx, decl, span, sig);
     }
 }
@@ -112,8 +122,10 @@ pub(super) fn check_trait_item<'a>(
     trait_item: &hir::TraitItem<'a>,
     avoid_breaking_exported_api: bool,
 ) {
-    if let hir::TraitItemKind::Fn(ref sig, _) = trait_item.kind
+    if !trait_item.span.in_external_macro(cx.sess().source_map())
+        && let hir::TraitItemKind::Fn(ref sig, _) = trait_item.kind
         && !(avoid_breaking_exported_api && cx.effective_visibilities.is_exported(trait_item.owner_id.def_id))
+        && !is_from_proc_macro(cx, trait_item)
     {
         let def_id = trait_item.owner_id.def_id;
         let ty_sig = cx.tcx.fn_sig(def_id).instantiate_identity().skip_binder();
diff --git a/src/tools/clippy/clippy_lints/src/future_not_send.rs b/src/tools/clippy/clippy_lints/src/future_not_send.rs
index 3ccfa51ab70..596047977a9 100644
--- a/src/tools/clippy/clippy_lints/src/future_not_send.rs
+++ b/src/tools/clippy/clippy_lints/src/future_not_send.rs
@@ -78,66 +78,65 @@ impl<'tcx> LateLintPass<'tcx> for FutureNotSend {
         if let ty::Alias(ty::Opaque, AliasTy { def_id, args, .. }) = *ret_ty.kind()
             && let Some(future_trait) = cx.tcx.lang_items().future_trait()
             && let Some(send_trait) = cx.tcx.get_diagnostic_item(sym::Send)
+            && let preds = cx.tcx.explicit_item_self_bounds(def_id)
+            // If is a Future
+            && preds
+                .iter_instantiated_copied(cx.tcx, args)
+                .filter_map(|(p, _)| p.as_trait_clause())
+                .any(|trait_pred| trait_pred.skip_binder().trait_ref.def_id == future_trait)
         {
-            let preds = cx.tcx.explicit_item_self_bounds(def_id);
-            let is_future = preds.iter_instantiated_copied(cx.tcx, args).any(|(p, _)| {
-                p.as_trait_clause()
-                    .is_some_and(|trait_pred| trait_pred.skip_binder().trait_ref.def_id == future_trait)
-            });
-            if is_future {
-                let span = decl.output.span();
-                let infcx = cx.tcx.infer_ctxt().build(cx.typing_mode());
-                let ocx = ObligationCtxt::new_with_diagnostics(&infcx);
-                let cause = traits::ObligationCause::misc(span, fn_def_id);
-                ocx.register_bound(cause, cx.param_env, ret_ty, send_trait);
-                let send_errors = ocx.select_all_or_error();
+            let span = decl.output.span();
+            let infcx = cx.tcx.infer_ctxt().build(cx.typing_mode());
+            let ocx = ObligationCtxt::new_with_diagnostics(&infcx);
+            let cause = traits::ObligationCause::misc(span, fn_def_id);
+            ocx.register_bound(cause, cx.param_env, ret_ty, send_trait);
+            let send_errors = ocx.select_all_or_error();
 
-                // Allow errors that try to prove `Send` for types that "mention" a generic parameter at the "top
-                // level".
-                // For example, allow errors that `T: Send` can't be proven, but reject `Rc<T>: Send` errors,
-                // which is always unconditionally `!Send` for any possible type `T`.
-                //
-                // We also allow associated type projections if the self type is either itself a projection or a
-                // type parameter.
-                // This is to prevent emitting warnings for e.g. holding a `<Fut as Future>::Output` across await
-                // points, where `Fut` is a type parameter.
+            // Allow errors that try to prove `Send` for types that "mention" a generic parameter at the "top
+            // level".
+            // For example, allow errors that `T: Send` can't be proven, but reject `Rc<T>: Send` errors,
+            // which is always unconditionally `!Send` for any possible type `T`.
+            //
+            // We also allow associated type projections if the self type is either itself a projection or a
+            // type parameter.
+            // This is to prevent emitting warnings for e.g. holding a `<Fut as Future>::Output` across await
+            // points, where `Fut` is a type parameter.
 
-                let is_send = send_errors.iter().all(|err| {
-                    err.obligation
-                        .predicate
-                        .as_trait_clause()
-                        .map(Binder::skip_binder)
-                        .is_some_and(|pred| {
-                            pred.def_id() == send_trait
-                                && pred.self_ty().has_param()
-                                && TyParamAtTopLevelVisitor.visit_ty(pred.self_ty()) == ControlFlow::Break(true)
-                        })
-                });
+            let is_send = send_errors.iter().all(|err| {
+                err.obligation
+                    .predicate
+                    .as_trait_clause()
+                    .map(Binder::skip_binder)
+                    .is_some_and(|pred| {
+                        pred.def_id() == send_trait
+                            && pred.self_ty().has_param()
+                            && TyParamAtTopLevelVisitor.visit_ty(pred.self_ty()) == ControlFlow::Break(true)
+                    })
+            });
 
-                if !is_send {
-                    span_lint_and_then(
-                        cx,
-                        FUTURE_NOT_SEND,
-                        span,
-                        "future cannot be sent between threads safely",
-                        |db| {
-                            for FulfillmentError { obligation, .. } in send_errors {
-                                infcx
-                                    .err_ctxt()
-                                    .maybe_note_obligation_cause_for_async_await(db, &obligation);
-                                if let PredicateKind::Clause(ClauseKind::Trait(trait_pred)) =
-                                    obligation.predicate.kind().skip_binder()
-                                {
-                                    db.note(format!(
-                                        "`{}` doesn't implement `{}`",
-                                        trait_pred.self_ty(),
-                                        trait_pred.trait_ref.print_only_trait_path(),
-                                    ));
-                                }
+            if !is_send {
+                span_lint_and_then(
+                    cx,
+                    FUTURE_NOT_SEND,
+                    span,
+                    "future cannot be sent between threads safely",
+                    |db| {
+                        for FulfillmentError { obligation, .. } in send_errors {
+                            infcx
+                                .err_ctxt()
+                                .maybe_note_obligation_cause_for_async_await(db, &obligation);
+                            if let PredicateKind::Clause(ClauseKind::Trait(trait_pred)) =
+                                obligation.predicate.kind().skip_binder()
+                            {
+                                db.note(format!(
+                                    "`{}` doesn't implement `{}`",
+                                    trait_pred.self_ty(),
+                                    trait_pred.trait_ref.print_only_trait_path(),
+                                ));
                             }
-                        },
-                    );
-                }
+                        }
+                    },
+                );
             }
         }
     }
diff --git a/src/tools/clippy/clippy_lints/src/invalid_upcast_comparisons.rs b/src/tools/clippy/clippy_lints/src/invalid_upcast_comparisons.rs
index b0ecc5d52dd..1666e8e5ae3 100644
--- a/src/tools/clippy/clippy_lints/src/invalid_upcast_comparisons.rs
+++ b/src/tools/clippy/clippy_lints/src/invalid_upcast_comparisons.rs
@@ -1,3 +1,4 @@
+use rustc_errors::Applicability;
 use rustc_hir::{Expr, ExprKind};
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_middle::ty::layout::LayoutOf;
@@ -9,7 +10,7 @@ use clippy_utils::comparisons;
 use clippy_utils::comparisons::Rel;
 use clippy_utils::consts::{ConstEvalCtxt, FullInt};
 use clippy_utils::diagnostics::span_lint;
-use clippy_utils::source::snippet;
+use clippy_utils::source::snippet_with_context;
 
 declare_clippy_lint! {
     /// ### What it does
@@ -69,13 +70,21 @@ fn numeric_cast_precast_bounds(cx: &LateContext<'_>, expr: &Expr<'_>) -> Option<
 
 fn err_upcast_comparison(cx: &LateContext<'_>, span: Span, expr: &Expr<'_>, always: bool) {
     if let ExprKind::Cast(cast_val, _) = expr.kind {
+        let mut applicability = Applicability::MachineApplicable;
+        let (cast_val_snip, _) = snippet_with_context(
+            cx,
+            cast_val.span,
+            expr.span.ctxt(),
+            "the expression",
+            &mut applicability,
+        );
         span_lint(
             cx,
             INVALID_UPCAST_COMPARISONS,
             span,
             format!(
                 "because of the numeric bounds on `{}` prior to casting, this expression is always {}",
-                snippet(cx, cast_val.span, "the expression"),
+                cast_val_snip,
                 if always { "true" } else { "false" },
             ),
         );
diff --git a/src/tools/clippy/clippy_lints/src/len_zero.rs b/src/tools/clippy/clippy_lints/src/len_zero.rs
index f44a5fdf715..28a0fbc0511 100644
--- a/src/tools/clippy/clippy_lints/src/len_zero.rs
+++ b/src/tools/clippy/clippy_lints/src/len_zero.rs
@@ -371,9 +371,9 @@ fn parse_len_output<'tcx>(cx: &LateContext<'tcx>, sig: FnSig<'tcx>) -> Option<Le
 
     match *sig.output().kind() {
         ty::Int(_) | ty::Uint(_) => Some(LenOutput::Integral),
-        ty::Adt(adt, subs) if subs.type_at(0).is_integral() => match cx.tcx.get_diagnostic_name(adt.did()) {
-            Some(sym::Option) => Some(LenOutput::Option(adt.did())),
-            Some(sym::Result) => Some(LenOutput::Result(adt.did())),
+        ty::Adt(adt, subs) => match cx.tcx.get_diagnostic_name(adt.did()) {
+            Some(sym::Option) => subs.type_at(0).is_integral().then(|| LenOutput::Option(adt.did())),
+            Some(sym::Result) => subs.type_at(0).is_integral().then(|| LenOutput::Result(adt.did())),
             _ => None,
         },
         _ => None,
diff --git a/src/tools/clippy/clippy_lints/src/let_with_type_underscore.rs b/src/tools/clippy/clippy_lints/src/let_with_type_underscore.rs
index 5b0f95ffc37..24a4c321bda 100644
--- a/src/tools/clippy/clippy_lints/src/let_with_type_underscore.rs
+++ b/src/tools/clippy/clippy_lints/src/let_with_type_underscore.rs
@@ -1,9 +1,9 @@
 use clippy_utils::diagnostics::span_lint_and_then;
 use clippy_utils::is_from_proc_macro;
 use clippy_utils::source::{IntoSpan, SpanRangeExt};
+use rustc_ast::{Local, TyKind};
 use rustc_errors::Applicability;
-use rustc_hir::{LetStmt, TyKind};
-use rustc_lint::{LateContext, LateLintPass};
+use rustc_lint::{EarlyContext, EarlyLintPass, LintContext};
 use rustc_session::declare_lint_pass;
 
 declare_clippy_lint! {
@@ -26,14 +26,14 @@ declare_clippy_lint! {
 }
 declare_lint_pass!(UnderscoreTyped => [LET_WITH_TYPE_UNDERSCORE]);
 
-impl<'tcx> LateLintPass<'tcx> for UnderscoreTyped {
-    fn check_local(&mut self, cx: &LateContext<'tcx>, local: &'tcx LetStmt<'_>) {
-        if let Some(ty) = local.ty // Ensure that it has a type defined
-            && let TyKind::Infer(()) = &ty.kind // that type is '_'
+impl EarlyLintPass for UnderscoreTyped {
+    fn check_local(&mut self, cx: &EarlyContext<'_>, local: &Local) {
+        if let Some(ty) = &local.ty // Ensure that it has a type defined
+            && let TyKind::Infer = ty.kind // that type is '_'
             && local.span.eq_ctxt(ty.span)
-            && let sm = cx.tcx.sess.source_map()
+            && let sm = cx.sess().source_map()
             && !local.span.in_external_macro(sm)
-            && !is_from_proc_macro(cx, ty)
+            && !is_from_proc_macro(cx, &**ty)
         {
             let span_to_remove = sm
                 .span_extend_to_prev_char_before(ty.span, ':', true)
diff --git a/src/tools/clippy/clippy_lints/src/lib.rs b/src/tools/clippy/clippy_lints/src/lib.rs
index a89cf3fdc1e..c56fa257b06 100644
--- a/src/tools/clippy/clippy_lints/src/lib.rs
+++ b/src/tools/clippy/clippy_lints/src/lib.rs
@@ -302,7 +302,6 @@ mod permissions_set_readonly_false;
 mod pointers_in_nomem_asm_block;
 mod precedence;
 mod ptr;
-mod ptr_offset_with_cast;
 mod pub_underscore_fields;
 mod pub_use;
 mod question_mark;
@@ -360,6 +359,7 @@ mod temporary_assignment;
 mod tests_outside_test_module;
 mod to_digit_is_some;
 mod to_string_trait_impl;
+mod toplevel_ref_arg;
 mod trailing_empty_array;
 mod trait_bounds;
 mod transmute;
@@ -592,7 +592,6 @@ pub fn register_lint_passes(store: &mut rustc_lint::LintStore, conf: &'static Co
     store.register_late_pass(|_| Box::new(unwrap::Unwrap));
     store.register_late_pass(move |_| Box::new(indexing_slicing::IndexingSlicing::new(conf)));
     store.register_late_pass(move |tcx| Box::new(non_copy_const::NonCopyConst::new(tcx, conf)));
-    store.register_late_pass(|_| Box::new(ptr_offset_with_cast::PtrOffsetWithCast));
     store.register_late_pass(|_| Box::new(redundant_clone::RedundantClone));
     store.register_late_pass(|_| Box::new(slow_vector_initialization::SlowVectorInit));
     store.register_late_pass(move |_| Box::new(unnecessary_wraps::UnnecessaryWraps::new(conf)));
@@ -744,7 +743,7 @@ pub fn register_lint_passes(store: &mut rustc_lint::LintStore, conf: &'static Co
     store.register_late_pass(|_| Box::new(missing_assert_message::MissingAssertMessage));
     store.register_late_pass(|_| Box::new(needless_maybe_sized::NeedlessMaybeSized));
     store.register_late_pass(|_| Box::new(redundant_async_block::RedundantAsyncBlock));
-    store.register_late_pass(|_| Box::new(let_with_type_underscore::UnderscoreTyped));
+    store.register_early_pass(|| Box::new(let_with_type_underscore::UnderscoreTyped));
     store.register_late_pass(move |_| Box::new(manual_main_separator_str::ManualMainSeparatorStr::new(conf)));
     store.register_late_pass(|_| Box::new(unnecessary_struct_initialization::UnnecessaryStruct));
     store.register_late_pass(move |_| Box::new(unnecessary_box_returns::UnnecessaryBoxReturns::new(conf)));
@@ -831,5 +830,6 @@ pub fn register_lint_passes(store: &mut rustc_lint::LintStore, conf: &'static Co
     store.register_late_pass(|_| Box::new(cloned_ref_to_slice_refs::ClonedRefToSliceRefs::new(conf)));
     store.register_late_pass(|_| Box::new(infallible_try_from::InfallibleTryFrom));
     store.register_late_pass(|_| Box::new(coerce_container_to_any::CoerceContainerToAny));
+    store.register_late_pass(|_| Box::new(toplevel_ref_arg::ToplevelRefArg));
     // add lints here, do not remove this comment, it's used in `new_lint`
 }
diff --git a/src/tools/clippy/clippy_lints/src/lifetimes.rs b/src/tools/clippy/clippy_lints/src/lifetimes.rs
index 149ae5e710c..d8b186b6787 100644
--- a/src/tools/clippy/clippy_lints/src/lifetimes.rs
+++ b/src/tools/clippy/clippy_lints/src/lifetimes.rs
@@ -745,7 +745,7 @@ fn report_elidable_impl_lifetimes<'tcx>(
     impl_: &'tcx Impl<'_>,
     map: &FxIndexMap<LocalDefId, Vec<Usage>>,
 ) {
-    let single_usages = map
+    let (elidable_lts, usages): (Vec<_>, Vec<_>) = map
         .iter()
         .filter_map(|(def_id, usages)| {
             if let [
@@ -762,14 +762,12 @@ fn report_elidable_impl_lifetimes<'tcx>(
                 None
             }
         })
-        .collect::<Vec<_>>();
+        .unzip();
 
-    if single_usages.is_empty() {
+    if elidable_lts.is_empty() {
         return;
     }
 
-    let (elidable_lts, usages): (Vec<_>, Vec<_>) = single_usages.into_iter().unzip();
-
     report_elidable_lifetimes(cx, impl_.generics, &elidable_lts, &usages, true);
 }
 
@@ -795,9 +793,7 @@ fn report_elidable_lifetimes(
         // In principle, the result of the call to `Node::ident` could be `unwrap`ped, as `DefId` should refer to a
         // `Node::GenericParam`.
         .filter_map(|&def_id| cx.tcx.hir_node_by_def_id(def_id).ident())
-        .map(|ident| ident.to_string())
-        .collect::<Vec<_>>()
-        .join(", ");
+        .format(", ");
 
     let elidable_usages: Vec<ElidableUsage> = usages
         .iter()
@@ -860,36 +856,89 @@ fn elision_suggestions(
         .filter(|param| !param.is_elided_lifetime() && !param.is_impl_trait())
         .collect::<Vec<_>>();
 
-    let mut suggestions = if elidable_lts.len() == explicit_params.len() {
+    if !elidable_lts
+        .iter()
+        .all(|lt| explicit_params.iter().any(|param| param.def_id == *lt))
+    {
+        return None;
+    }
+
+    let mut suggestions = if elidable_lts.is_empty() {
+        vec![]
+    } else if elidable_lts.len() == explicit_params.len() {
         // if all the params are elided remove the whole generic block
         //
         // fn x<'a>() {}
         //     ^^^^
         vec![(generics.span, String::new())]
     } else {
-        elidable_lts
-            .iter()
-            .map(|&id| {
-                let pos = explicit_params.iter().position(|param| param.def_id == id)?;
-                let param = explicit_params.get(pos)?;
-
-                let span = if let Some(next) = explicit_params.get(pos + 1) {
-                    // fn x<'prev, 'a, 'next>() {}
-                    //             ^^^^
-                    param.span.until(next.span)
+        match &explicit_params[..] {
+            // no params, nothing to elide
+            [] => unreachable!("handled by `elidable_lts.is_empty()`"),
+            [param] => {
+                if elidable_lts.contains(&param.def_id) {
+                    unreachable!("handled by `elidable_lts.len() == explicit_params.len()`")
                 } else {
-                    // `pos` should be at least 1 here, because the param in position 0 would either have a `next`
-                    // param or would have taken the `elidable_lts.len() == explicit_params.len()` branch.
-                    let prev = explicit_params.get(pos - 1)?;
-
-                    // fn x<'prev, 'a>() {}
-                    //           ^^^^
-                    param.span.with_lo(prev.span.hi())
+                    unreachable!("handled by `elidable_lts.is_empty()`")
+                }
+            },
+            [_, _, ..] => {
+                // Given a list like `<'a, 'b, 'c, 'd, ..>`,
+                //
+                // If there is a cluster of elidable lifetimes at the beginning, say `'a` and `'b`, we should
+                // suggest removing them _and_ the trailing comma. The span for that is `a.span.until(c.span)`:
+                // <'a, 'b, 'c, 'd, ..> => <'a, 'b, 'c, 'd, ..>
+                //  ^^  ^^                  ^^^^^^^^
+                //
+                // And since we know that `'c` isn't elidable--otherwise it would've been in the cluster--we can go
+                // over all the lifetimes after it, and for each elidable one, add a suggestion spanning the
+                // lifetime itself and the comma before, because each individual suggestion is guaranteed to leave
+                // the list valid:
+                // <.., 'c, 'd, 'e, 'f, 'g, ..> => <.., 'c, 'd, 'e, 'f, 'g, ..>
+                //          ^^      ^^  ^^                ^^^^    ^^^^^^^^
+                //
+                // In case there is no such starting cluster, we only need to do the second part of the algorithm:
+                // <'a, 'b, 'c, 'd, 'e, 'f, 'g, ..> => <'a, 'b , 'c, 'd, 'e, 'f, 'g, ..>
+                //      ^^  ^^      ^^  ^^                ^^^^^^^^^    ^^^^^^^^
+
+                // Split off the starting cluster
+                // TODO: use `slice::split_once` once stabilized (github.com/rust-lang/rust/issues/112811):
+                // ```
+                // let Some(split) = explicit_params.split_once(|param| !elidable_lts.contains(&param.def_id)) else {
+                //     // there were no lifetime param that couldn't be elided
+                //     unreachable!("handled by `elidable_lts.len() == explicit_params.len()`")
+                // };
+                // match split { /* .. */ }
+                // ```
+                let Some(split_pos) = explicit_params
+                    .iter()
+                    .position(|param| !elidable_lts.contains(&param.def_id))
+                else {
+                    // there were no lifetime param that couldn't be elided
+                    unreachable!("handled by `elidable_lts.len() == explicit_params.len()`")
                 };
-
-                Some((span, String::new()))
-            })
-            .collect::<Option<Vec<_>>>()?
+                let split = explicit_params
+                    .split_at_checked(split_pos)
+                    .expect("got `split_pos` from `position` on the same Vec");
+
+                match split {
+                    ([..], []) => unreachable!("handled by `elidable_lts.len() == explicit_params.len()`"),
+                    ([], [_]) => unreachable!("handled by `explicit_params.len() == 1`"),
+                    (cluster, rest @ [rest_first, ..]) => {
+                        // the span for the cluster
+                        (cluster.first().map(|fw| fw.span.until(rest_first.span)).into_iter())
+                            // the span for the remaining lifetimes (calculations independent of the cluster)
+                            .chain(
+                                rest.array_windows()
+                                    .filter(|[_, curr]| elidable_lts.contains(&curr.def_id))
+                                    .map(|[prev, curr]| curr.span.with_lo(prev.span.hi())),
+                            )
+                            .map(|sp| (sp, String::new()))
+                            .collect()
+                    },
+                }
+            },
+        }
     };
 
     suggestions.extend(usages.iter().map(|&usage| {
diff --git a/src/tools/clippy/clippy_lints/src/loops/explicit_iter_loop.rs b/src/tools/clippy/clippy_lints/src/loops/explicit_iter_loop.rs
index 6ce7f0b1f0b..af475c40586 100644
--- a/src/tools/clippy/clippy_lints/src/loops/explicit_iter_loop.rs
+++ b/src/tools/clippy/clippy_lints/src/loops/explicit_iter_loop.rs
@@ -138,9 +138,9 @@ fn is_ref_iterable<'tcx>(
             return Some((AdjustKind::None, self_ty));
         }
 
-        let res_ty = cx
-            .tcx
-            .erase_and_anonymize_regions(EarlyBinder::bind(req_res_ty).instantiate(cx.tcx, typeck.node_args(call_expr.hir_id)));
+        let res_ty = cx.tcx.erase_and_anonymize_regions(
+            EarlyBinder::bind(req_res_ty).instantiate(cx.tcx, typeck.node_args(call_expr.hir_id)),
+        );
         let mutbl = if let ty::Ref(_, _, mutbl) = *req_self_ty.kind() {
             Some(mutbl)
         } else {
diff --git a/src/tools/clippy/clippy_lints/src/loops/never_loop.rs b/src/tools/clippy/clippy_lints/src/loops/never_loop.rs
index 2ccff768097..544c3c34d02 100644
--- a/src/tools/clippy/clippy_lints/src/loops/never_loop.rs
+++ b/src/tools/clippy/clippy_lints/src/loops/never_loop.rs
@@ -22,7 +22,10 @@ pub(super) fn check<'tcx>(
     for_loop: Option<&ForLoop<'_>>,
 ) {
     match never_loop_block(cx, block, &mut Vec::new(), loop_id) {
-        NeverLoopResult::Diverging { ref break_spans } => {
+        NeverLoopResult::Diverging {
+            ref break_spans,
+            ref never_spans,
+        } => {
             span_lint_and_then(cx, NEVER_LOOP, span, "this loop never actually loops", |diag| {
                 if let Some(ForLoop {
                     arg: iterator,
@@ -34,12 +37,16 @@ pub(super) fn check<'tcx>(
                 {
                     // If the block contains a break or continue, or if the loop has a label, `MachineApplicable` is not
                     // appropriate.
-                    let app = if !contains_any_break_or_continue(block) && label.is_none() {
+                    let mut app = if !contains_any_break_or_continue(block) && label.is_none() {
                         Applicability::MachineApplicable
                     } else {
                         Applicability::Unspecified
                     };
 
+                    if !never_spans.is_empty() {
+                        app = Applicability::HasPlaceholders;
+                    }
+
                     let mut suggestions = vec![(
                         for_span.with_hi(iterator.span.hi()),
                         for_to_if_let_sugg(cx, iterator, pat),
@@ -51,6 +58,13 @@ pub(super) fn check<'tcx>(
                         suggestions,
                         app,
                     );
+
+                    for span in never_spans {
+                        diag.span_help(
+                            *span,
+                            "this code is unreachable. Consider moving the reachable parts out",
+                        );
+                    }
                 }
             });
         },
@@ -77,13 +91,16 @@ fn contains_any_break_or_continue(block: &Block<'_>) -> bool {
 /// The first two bits of information are in this enum, and the last part is in the
 /// `local_labels` variable, which contains a list of `(block_id, reachable)` pairs ordered by
 /// scope.
-#[derive(Clone)]
+#[derive(Clone, Debug)]
 enum NeverLoopResult {
     /// A continue may occur for the main loop.
     MayContinueMainLoop,
     /// We have not encountered any main loop continue,
     /// but we are diverging (subsequent control flow is not reachable)
-    Diverging { break_spans: Vec<Span> },
+    Diverging {
+        break_spans: Vec<Span>,
+        never_spans: Vec<Span>,
+    },
     /// We have not encountered any main loop continue,
     /// and subsequent control flow is (possibly) reachable
     Normal,
@@ -128,14 +145,18 @@ fn combine_branches(b1: NeverLoopResult, b2: NeverLoopResult) -> NeverLoopResult
         (
             NeverLoopResult::Diverging {
                 break_spans: mut break_spans1,
+                never_spans: mut never_spans1,
             },
             NeverLoopResult::Diverging {
                 break_spans: mut break_spans2,
+                never_spans: mut never_spans2,
             },
         ) => {
             break_spans1.append(&mut break_spans2);
+            never_spans1.append(&mut never_spans2);
             NeverLoopResult::Diverging {
                 break_spans: break_spans1,
+                never_spans: never_spans1,
             }
         },
     }
@@ -207,6 +228,8 @@ fn all_spans_after_expr(cx: &LateContext<'_>, expr: &Expr<'_>) -> Vec<Span> {
         }
 
         return vec![stmt.span];
+    } else if let Node::Block(_) = cx.tcx.parent_hir_node(expr.hir_id) {
+        return vec![expr.span];
     }
 
     vec![]
@@ -270,10 +293,13 @@ fn never_loop_expr<'tcx>(
         ExprKind::Match(e, arms, _) => {
             let e = never_loop_expr(cx, e, local_labels, main_loop_id);
             combine_seq(e, || {
-                arms.iter()
-                    .fold(NeverLoopResult::Diverging { break_spans: vec![] }, |a, b| {
-                        combine_branches(a, never_loop_expr(cx, b.body, local_labels, main_loop_id))
-                    })
+                arms.iter().fold(
+                    NeverLoopResult::Diverging {
+                        break_spans: vec![],
+                        never_spans: vec![],
+                    },
+                    |a, b| combine_branches(a, never_loop_expr(cx, b.body, local_labels, main_loop_id)),
+                )
             })
         },
         ExprKind::Block(b, _) => {
@@ -296,6 +322,7 @@ fn never_loop_expr<'tcx>(
             } else {
                 NeverLoopResult::Diverging {
                     break_spans: all_spans_after_expr(cx, expr),
+                    never_spans: vec![],
                 }
             }
         },
@@ -306,7 +333,10 @@ fn never_loop_expr<'tcx>(
             combine_seq(first, || {
                 // checks if break targets a block instead of a loop
                 mark_block_as_reachable(expr, local_labels);
-                NeverLoopResult::Diverging { break_spans: vec![] }
+                NeverLoopResult::Diverging {
+                    break_spans: vec![],
+                    never_spans: vec![],
+                }
             })
         },
         ExprKind::Break(dest, e) => {
@@ -322,11 +352,15 @@ fn never_loop_expr<'tcx>(
                     } else {
                         all_spans_after_expr(cx, expr)
                     },
+                    never_spans: vec![],
                 }
             })
         },
         ExprKind::Become(e) => combine_seq(never_loop_expr(cx, e, local_labels, main_loop_id), || {
-            NeverLoopResult::Diverging { break_spans: vec![] }
+            NeverLoopResult::Diverging {
+                break_spans: vec![],
+                never_spans: vec![],
+            }
         }),
         ExprKind::InlineAsm(asm) => combine_seq_many(asm.operands.iter().map(|(o, _)| match o {
             InlineAsmOperand::In { expr, .. } | InlineAsmOperand::InOut { expr, .. } => {
@@ -356,7 +390,10 @@ fn never_loop_expr<'tcx>(
     };
     let result = combine_seq(result, || {
         if cx.typeck_results().expr_ty(expr).is_never() {
-            NeverLoopResult::Diverging { break_spans: vec![] }
+            NeverLoopResult::Diverging {
+                break_spans: vec![],
+                never_spans: all_spans_after_expr(cx, expr),
+            }
         } else {
             NeverLoopResult::Normal
         }
diff --git a/src/tools/clippy/clippy_lints/src/manual_abs_diff.rs b/src/tools/clippy/clippy_lints/src/manual_abs_diff.rs
index 288f27db8ca..5814b6815a1 100644
--- a/src/tools/clippy/clippy_lints/src/manual_abs_diff.rs
+++ b/src/tools/clippy/clippy_lints/src/manual_abs_diff.rs
@@ -4,8 +4,8 @@ use clippy_utils::higher::If;
 use clippy_utils::msrvs::{self, Msrv};
 use clippy_utils::source::HasSession as _;
 use clippy_utils::sugg::Sugg;
-use clippy_utils::ty::is_type_diagnostic_item;
-use clippy_utils::{eq_expr_value, peel_blocks, peel_middle_ty_refs, span_contains_comment};
+use clippy_utils::ty::{is_type_diagnostic_item, peel_and_count_ty_refs};
+use clippy_utils::{eq_expr_value, peel_blocks, span_contains_comment};
 use rustc_errors::Applicability;
 use rustc_hir::{BinOpKind, Expr, ExprKind};
 use rustc_lint::{LateContext, LateLintPass};
@@ -107,7 +107,7 @@ impl ManualAbsDiff {
             |ty| is_type_diagnostic_item(cx, ty, sym::Duration) && self.msrv.meets(cx, msrvs::DURATION_ABS_DIFF);
 
         let a_ty = cx.typeck_results().expr_ty(a).peel_refs();
-        let (b_ty, b_n_refs) = peel_middle_ty_refs(cx.typeck_results().expr_ty(b));
+        let (b_ty, b_n_refs, _) = peel_and_count_ty_refs(cx.typeck_results().expr_ty(b));
 
         (a_ty == b_ty && (is_int(a_ty) || is_duration(a_ty))).then_some((a_ty, b_n_refs))
     }
diff --git a/src/tools/clippy/clippy_lints/src/manual_option_as_slice.rs b/src/tools/clippy/clippy_lints/src/manual_option_as_slice.rs
index 922db174e3d..b036e78cded 100644
--- a/src/tools/clippy/clippy_lints/src/manual_option_as_slice.rs
+++ b/src/tools/clippy/clippy_lints/src/manual_option_as_slice.rs
@@ -1,7 +1,7 @@
 use clippy_config::Conf;
 use clippy_utils::diagnostics::{span_lint, span_lint_and_sugg};
 use clippy_utils::msrvs::Msrv;
-use clippy_utils::{is_none_arm, msrvs, peel_hir_expr_refs, sym};
+use clippy_utils::{is_none_pattern, msrvs, peel_hir_expr_refs, sym};
 use rustc_errors::Applicability;
 use rustc_hir::def::{DefKind, Res};
 use rustc_hir::{Arm, Expr, ExprKind, LangItem, Pat, PatKind, QPath, is_range_literal};
@@ -60,8 +60,8 @@ impl LateLintPass<'_> for ManualOptionAsSlice {
         }
         match expr.kind {
             ExprKind::Match(scrutinee, [arm1, arm2], _) => {
-                if is_none_arm(cx, arm2) && check_arms(cx, arm2, arm1)
-                    || is_none_arm(cx, arm1) && check_arms(cx, arm1, arm2)
+                if is_none_pattern(cx, arm2.pat) && check_arms(cx, arm2, arm1)
+                    || is_none_pattern(cx, arm1.pat) && check_arms(cx, arm1, arm2)
                 {
                     check_as_ref(cx, scrutinee, span, self.msrv);
                 }
diff --git a/src/tools/clippy/clippy_lints/src/manual_slice_size_calculation.rs b/src/tools/clippy/clippy_lints/src/manual_slice_size_calculation.rs
index 0c09a47c965..de12fa29d02 100644
--- a/src/tools/clippy/clippy_lints/src/manual_slice_size_calculation.rs
+++ b/src/tools/clippy/clippy_lints/src/manual_slice_size_calculation.rs
@@ -2,6 +2,7 @@ use clippy_config::Conf;
 use clippy_utils::diagnostics::span_lint_and_sugg;
 use clippy_utils::msrvs::{self, Msrv};
 use clippy_utils::source::snippet_with_context;
+use clippy_utils::ty::peel_and_count_ty_refs;
 use clippy_utils::{expr_or_init, is_in_const_context, std_or_core};
 use rustc_errors::Applicability;
 use rustc_hir::{BinOpKind, Expr, ExprKind};
@@ -102,7 +103,7 @@ fn simplify_half<'tcx>(
         && let ExprKind::MethodCall(method_path, receiver, [], _) = expr1.kind
         && method_path.ident.name == sym::len
         && let receiver_ty = cx.typeck_results().expr_ty(receiver)
-        && let (receiver_ty, refs_count) = clippy_utils::ty::walk_ptrs_ty_depth(receiver_ty)
+        && let (receiver_ty, refs_count, _) = peel_and_count_ty_refs(receiver_ty)
         && let ty::Slice(ty1) = receiver_ty.kind()
         // expr2 is `size_of::<T2>()`?
         && let ExprKind::Call(func, []) = expr2.kind
diff --git a/src/tools/clippy/clippy_lints/src/matches/manual_ok_err.rs b/src/tools/clippy/clippy_lints/src/matches/manual_ok_err.rs
index edbb556fd97..a8490d6aa7d 100644
--- a/src/tools/clippy/clippy_lints/src/matches/manual_ok_err.rs
+++ b/src/tools/clippy/clippy_lints/src/matches/manual_ok_err.rs
@@ -1,7 +1,7 @@
 use clippy_utils::diagnostics::span_lint_and_sugg;
 use clippy_utils::source::{indent_of, reindent_multiline};
 use clippy_utils::sugg::Sugg;
-use clippy_utils::ty::{option_arg_ty, peel_mid_ty_refs_is_mutable};
+use clippy_utils::ty::{option_arg_ty, peel_and_count_ty_refs};
 use clippy_utils::{get_parent_expr, is_res_lang_ctor, path_res, peel_blocks, span_contains_comment};
 use rustc_ast::{BindingMode, Mutability};
 use rustc_errors::Applicability;
@@ -135,15 +135,11 @@ fn apply_lint(cx: &LateContext<'_>, expr: &Expr<'_>, scrutinee: &Expr<'_>, is_ok
     let scrut = Sugg::hir_with_applicability(cx, scrutinee, "..", &mut app).maybe_paren();
 
     let scrutinee_ty = cx.typeck_results().expr_ty(scrutinee);
-    let (_, n_ref, mutability) = peel_mid_ty_refs_is_mutable(scrutinee_ty);
-    let prefix = if n_ref > 0 {
-        if mutability == Mutability::Mut {
-            ".as_mut()"
-        } else {
-            ".as_ref()"
-        }
-    } else {
-        ""
+    let (_, _, mutability) = peel_and_count_ty_refs(scrutinee_ty);
+    let prefix = match mutability {
+        Some(Mutability::Mut) => ".as_mut()",
+        Some(Mutability::Not) => ".as_ref()",
+        None => "",
     };
 
     let sugg = format!("{scrut}{prefix}.{method}()");
diff --git a/src/tools/clippy/clippy_lints/src/matches/manual_utils.rs b/src/tools/clippy/clippy_lints/src/matches/manual_utils.rs
index dbae71bbb1b..d4bfdb7e440 100644
--- a/src/tools/clippy/clippy_lints/src/matches/manual_utils.rs
+++ b/src/tools/clippy/clippy_lints/src/matches/manual_utils.rs
@@ -2,7 +2,7 @@ use crate::map_unit_fn::OPTION_MAP_UNIT_FN;
 use crate::matches::MATCH_AS_REF;
 use clippy_utils::source::{snippet_with_applicability, snippet_with_context};
 use clippy_utils::sugg::Sugg;
-use clippy_utils::ty::{is_copy, is_type_diagnostic_item, peel_mid_ty_refs_is_mutable, type_is_unsafe_function};
+use clippy_utils::ty::{is_copy, is_type_diagnostic_item, is_unsafe_fn, peel_and_count_ty_refs};
 use clippy_utils::{
     CaptureKind, can_move_expr_to_closure, expr_requires_coercion, is_else_clause, is_lint_allowed, is_res_lang_ctor,
     path_res, path_to_local_id, peel_blocks, peel_hir_expr_refs, peel_hir_expr_while,
@@ -30,8 +30,9 @@ pub(super) fn check_with<'tcx, F>(
 where
     F: Fn(&LateContext<'tcx>, &'tcx Pat<'_>, &'tcx Expr<'_>, SyntaxContext) -> Option<SomeExpr<'tcx>>,
 {
-    let (scrutinee_ty, ty_ref_count, ty_mutability) =
-        peel_mid_ty_refs_is_mutable(cx.typeck_results().expr_ty(scrutinee));
+    let (scrutinee_ty, ty_ref_count, ty_mutability) = peel_and_count_ty_refs(cx.typeck_results().expr_ty(scrutinee));
+    let ty_mutability = ty_mutability.unwrap_or(Mutability::Mut);
+
     if !(is_type_diagnostic_item(cx, scrutinee_ty, sym::Option)
         && is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(expr), sym::Option))
     {
@@ -191,7 +192,7 @@ fn can_pass_as_func<'tcx>(cx: &LateContext<'tcx>, binding: HirId, expr: &'tcx Ex
         ExprKind::Call(func, [arg])
             if path_to_local_id(arg, binding)
                 && cx.typeck_results().expr_adjustments(arg).is_empty()
-                && !type_is_unsafe_function(cx, cx.typeck_results().expr_ty(func).peel_refs()) =>
+                && !is_unsafe_fn(cx, cx.typeck_results().expr_ty(func).peel_refs()) =>
         {
             Some(func)
         },
diff --git a/src/tools/clippy/clippy_lints/src/matches/needless_match.rs b/src/tools/clippy/clippy_lints/src/matches/needless_match.rs
index b04db03f8d2..3a2097c3df2 100644
--- a/src/tools/clippy/clippy_lints/src/matches/needless_match.rs
+++ b/src/tools/clippy/clippy_lints/src/matches/needless_match.rs
@@ -1,7 +1,7 @@
 use super::NEEDLESS_MATCH;
 use clippy_utils::diagnostics::span_lint_and_sugg;
 use clippy_utils::source::snippet_with_applicability;
-use clippy_utils::ty::{is_type_diagnostic_item, same_type_and_consts};
+use clippy_utils::ty::{is_type_diagnostic_item, same_type_modulo_regions};
 use clippy_utils::{
     SpanlessEq, eq_expr_value, get_parent_expr_for_hir, higher, is_else_clause, is_res_lang_ctor, over, path_res,
     peel_blocks_with_stmt,
@@ -122,7 +122,7 @@ fn expr_ty_matches_p_ty(cx: &LateContext<'_>, expr: &Expr<'_>, p_expr: &Expr<'_>
         // Compare match_expr ty with local in `let local = match match_expr {..}`
         Node::LetStmt(local) => {
             let results = cx.typeck_results();
-            return same_type_and_consts(results.node_type(local.hir_id), results.expr_ty(expr));
+            return same_type_modulo_regions(results.node_type(local.hir_id), results.expr_ty(expr));
         },
         // compare match_expr ty with RetTy in `fn foo() -> RetTy`
         Node::Item(item) => {
@@ -133,7 +133,7 @@ fn expr_ty_matches_p_ty(cx: &LateContext<'_>, expr: &Expr<'_>, p_expr: &Expr<'_>
                     .instantiate_identity()
                     .output()
                     .skip_binder();
-                return same_type_and_consts(output, cx.typeck_results().expr_ty(expr));
+                return same_type_modulo_regions(output, cx.typeck_results().expr_ty(expr));
             }
         },
         // check the parent expr for this whole block `{ match match_expr {..} }`
diff --git a/src/tools/clippy/clippy_lints/src/matches/rest_pat_in_fully_bound_struct.rs b/src/tools/clippy/clippy_lints/src/matches/rest_pat_in_fully_bound_struct.rs
index ae09c2e87d6..1130d82ab78 100644
--- a/src/tools/clippy/clippy_lints/src/matches/rest_pat_in_fully_bound_struct.rs
+++ b/src/tools/clippy/clippy_lints/src/matches/rest_pat_in_fully_bound_struct.rs
@@ -7,7 +7,7 @@ use super::REST_PAT_IN_FULLY_BOUND_STRUCTS;
 
 pub(crate) fn check(cx: &LateContext<'_>, pat: &Pat<'_>) {
     if !pat.span.from_expansion()
-        && let PatKind::Struct(QPath::Resolved(_, path), fields, Some(_)) = pat.kind
+        && let PatKind::Struct(QPath::Resolved(_, path), fields, Some(dotdot)) = pat.kind
         && let Some(def_id) = path.res.opt_def_id()
         && let ty = cx.tcx.type_of(def_id).instantiate_identity()
         && let ty::Adt(def, _) = ty.kind()
@@ -15,14 +15,18 @@ pub(crate) fn check(cx: &LateContext<'_>, pat: &Pat<'_>) {
         && fields.len() == def.non_enum_variant().fields.len()
         && !def.non_enum_variant().is_field_list_non_exhaustive()
     {
-        #[expect(clippy::collapsible_span_lint_calls, reason = "rust-clippy#7797")]
         span_lint_and_then(
             cx,
             REST_PAT_IN_FULLY_BOUND_STRUCTS,
             pat.span,
             "unnecessary use of `..` pattern in struct binding. All fields were already bound",
             |diag| {
-                diag.help("consider removing `..` from this binding");
+                diag.span_suggestion_verbose(
+                    dotdot,
+                    "consider removing `..` from this binding",
+                    "",
+                    rustc_errors::Applicability::MachineApplicable,
+                );
             },
         );
     }
diff --git a/src/tools/clippy/clippy_lints/src/matches/single_match.rs b/src/tools/clippy/clippy_lints/src/matches/single_match.rs
index bcf079b7007..83939d32579 100644
--- a/src/tools/clippy/clippy_lints/src/matches/single_match.rs
+++ b/src/tools/clippy/clippy_lints/src/matches/single_match.rs
@@ -2,10 +2,8 @@ use clippy_utils::diagnostics::span_lint_and_then;
 use clippy_utils::source::{
     SpanRangeExt, expr_block, snippet, snippet_block_with_context, snippet_with_applicability, snippet_with_context,
 };
-use clippy_utils::ty::implements_trait;
-use clippy_utils::{
-    is_lint_allowed, is_unit_expr, peel_blocks, peel_hir_pat_refs, peel_middle_ty_refs, peel_n_hir_expr_refs,
-};
+use clippy_utils::ty::{implements_trait, peel_and_count_ty_refs};
+use clippy_utils::{is_lint_allowed, is_unit_expr, peel_blocks, peel_hir_pat_refs, peel_n_hir_expr_refs};
 use core::ops::ControlFlow;
 use rustc_arena::DroplessArena;
 use rustc_errors::{Applicability, Diag};
@@ -133,7 +131,7 @@ fn report_single_pattern(
 
     let (pat, pat_ref_count) = peel_hir_pat_refs(arm.pat);
     let (msg, sugg) = if let PatKind::Expr(_) = pat.kind
-        && let (ty, ty_ref_count) = peel_middle_ty_refs(cx.typeck_results().expr_ty(ex))
+        && let (ty, ty_ref_count, _) = peel_and_count_ty_refs(cx.typeck_results().expr_ty(ex))
         && let Some(spe_trait_id) = cx.tcx.lang_items().structural_peq_trait()
         && let Some(pe_trait_id) = cx.tcx.lang_items().eq_trait()
         && (ty.is_integral()
diff --git a/src/tools/clippy/clippy_lints/src/methods/implicit_clone.rs b/src/tools/clippy/clippy_lints/src/methods/implicit_clone.rs
index 8a976d1b4dc..0ba84919395 100644
--- a/src/tools/clippy/clippy_lints/src/methods/implicit_clone.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/implicit_clone.rs
@@ -1,7 +1,7 @@
 use clippy_utils::diagnostics::span_lint_and_sugg;
 use clippy_utils::source::snippet_with_context;
-use clippy_utils::ty::implements_trait;
-use clippy_utils::{is_diag_item_method, is_diag_trait_item, peel_middle_ty_refs, sym};
+use clippy_utils::ty::{implements_trait, peel_and_count_ty_refs};
+use clippy_utils::{is_diag_item_method, is_diag_trait_item, sym};
 use rustc_errors::Applicability;
 use rustc_hir as hir;
 use rustc_lint::LateContext;
@@ -14,7 +14,7 @@ pub fn check(cx: &LateContext<'_>, method_name: Symbol, expr: &hir::Expr<'_>, re
         && is_clone_like(cx, method_name, method_def_id)
         && let return_type = cx.typeck_results().expr_ty(expr)
         && let input_type = cx.typeck_results().expr_ty(recv)
-        && let (input_type, ref_count) = peel_middle_ty_refs(input_type)
+        && let (input_type, ref_count, _) = peel_and_count_ty_refs(input_type)
         && !(ref_count > 0 && is_diag_trait_item(cx, method_def_id, sym::ToOwned))
         && let Some(ty_name) = input_type.ty_adt_def().map(|adt_def| cx.tcx.item_name(adt_def.did()))
         && return_type == input_type
diff --git a/src/tools/clippy/clippy_lints/src/methods/inefficient_to_string.rs b/src/tools/clippy/clippy_lints/src/methods/inefficient_to_string.rs
index 4ed7de81ea3..47195fdd65f 100644
--- a/src/tools/clippy/clippy_lints/src/methods/inefficient_to_string.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/inefficient_to_string.rs
@@ -1,6 +1,6 @@
 use clippy_utils::diagnostics::span_lint_and_then;
 use clippy_utils::source::snippet_with_applicability;
-use clippy_utils::ty::{is_type_lang_item, walk_ptrs_ty_depth};
+use clippy_utils::ty::{is_type_lang_item, peel_and_count_ty_refs};
 use rustc_errors::Applicability;
 use rustc_hir as hir;
 use rustc_lint::LateContext;
@@ -24,7 +24,7 @@ pub fn check(
         && let Some(args) = cx.typeck_results().node_args_opt(expr.hir_id)
         && let arg_ty = cx.typeck_results().expr_ty_adjusted(receiver)
         && let self_ty = args.type_at(0)
-        && let (deref_self_ty, deref_count) = walk_ptrs_ty_depth(self_ty)
+        && let (deref_self_ty, deref_count, _) = peel_and_count_ty_refs(self_ty)
         && deref_count >= 1
         && specializes_tostring(cx, deref_self_ty)
     {
diff --git a/src/tools/clippy/clippy_lints/src/methods/iter_overeager_cloned.rs b/src/tools/clippy/clippy_lints/src/methods/iter_overeager_cloned.rs
index f851ebe91f3..d43dc23a86b 100644
--- a/src/tools/clippy/clippy_lints/src/methods/iter_overeager_cloned.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/iter_overeager_cloned.rs
@@ -10,8 +10,7 @@ use rustc_middle::mir::{FakeReadCause, Mutability};
 use rustc_middle::ty::{self, BorrowKind};
 use rustc_span::{Symbol, sym};
 
-use super::ITER_OVEREAGER_CLONED;
-use crate::redundant_clone::REDUNDANT_CLONE;
+use super::{ITER_OVEREAGER_CLONED, REDUNDANT_ITER_CLONED};
 
 #[derive(Clone, Copy)]
 pub(super) enum Op<'a> {
@@ -96,7 +95,7 @@ pub(super) fn check<'tcx>(
         }
 
         let (lint, msg, trailing_clone) = match op {
-            Op::RmCloned | Op::NeedlessMove(_) => (REDUNDANT_CLONE, "unneeded cloning of iterator items", ""),
+            Op::RmCloned | Op::NeedlessMove(_) => (REDUNDANT_ITER_CLONED, "unneeded cloning of iterator items", ""),
             Op::LaterCloned | Op::FixClosure(_, _) => (
                 ITER_OVEREAGER_CLONED,
                 "unnecessarily eager cloning of iterator items",
diff --git a/src/tools/clippy/clippy_lints/src/methods/mod.rs b/src/tools/clippy/clippy_lints/src/methods/mod.rs
index 49ca81dafc2..8679689c8ad 100644
--- a/src/tools/clippy/clippy_lints/src/methods/mod.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/mod.rs
@@ -91,6 +91,7 @@ mod or_fun_call;
 mod or_then_unwrap;
 mod path_buf_push_overwrite;
 mod path_ends_with_ext;
+mod ptr_offset_with_cast;
 mod range_zip_with_len;
 mod read_line_without_trim;
 mod readonly_write_lock;
@@ -1727,6 +1728,43 @@ declare_clippy_lint! {
 
 declare_clippy_lint! {
     /// ### What it does
+    /// Checks for usage of the `offset` pointer method with a `usize` casted to an
+    /// `isize`.
+    ///
+    /// ### Why is this bad?
+    /// If we’re always increasing the pointer address, we can avoid the numeric
+    /// cast by using the `add` method instead.
+    ///
+    /// ### Example
+    /// ```no_run
+    /// let vec = vec![b'a', b'b', b'c'];
+    /// let ptr = vec.as_ptr();
+    /// let offset = 1_usize;
+    ///
+    /// unsafe {
+    ///     ptr.offset(offset as isize);
+    /// }
+    /// ```
+    ///
+    /// Could be written:
+    ///
+    /// ```no_run
+    /// let vec = vec![b'a', b'b', b'c'];
+    /// let ptr = vec.as_ptr();
+    /// let offset = 1_usize;
+    ///
+    /// unsafe {
+    ///     ptr.add(offset);
+    /// }
+    /// ```
+    #[clippy::version = "1.30.0"]
+    pub PTR_OFFSET_WITH_CAST,
+    complexity,
+    "unneeded pointer offset cast"
+}
+
+declare_clippy_lint! {
+    /// ### What it does
     /// Checks for `FileType::is_file()`.
     ///
     /// ### Why restrict this?
@@ -4576,6 +4614,31 @@ declare_clippy_lint! {
     "hardcoded localhost IP address"
 }
 
+declare_clippy_lint! {
+    /// ### What it does
+    /// Checks for calls to `Iterator::cloned` where the original value could be used
+    /// instead.
+    ///
+    /// ### Why is this bad?
+    /// It is not always possible for the compiler to eliminate useless allocations and
+    /// deallocations generated by redundant `clone()`s.
+    ///
+    /// ### Example
+    /// ```no_run
+    /// let x = vec![String::new()];
+    /// let _ = x.iter().cloned().map(|x| x.len());
+    /// ```
+    /// Use instead:
+    /// ```no_run
+    /// let x = vec![String::new()];
+    /// let _ = x.iter().map(|x| x.len());
+    /// ```
+    #[clippy::version = "1.90.0"]
+    pub REDUNDANT_ITER_CLONED,
+    perf,
+    "detects redundant calls to `Iterator::cloned`"
+}
+
 #[expect(clippy::struct_excessive_bools)]
 pub struct Methods {
     avoid_breaking_exported_api: bool,
@@ -4665,6 +4728,7 @@ impl_lint_pass!(Methods => [
     UNINIT_ASSUMED_INIT,
     MANUAL_SATURATING_ARITHMETIC,
     ZST_OFFSET,
+    PTR_OFFSET_WITH_CAST,
     FILETYPE_IS_FILE,
     OPTION_AS_REF_DEREF,
     UNNECESSARY_LAZY_EVALUATIONS,
@@ -4755,6 +4819,7 @@ impl_lint_pass!(Methods => [
     IO_OTHER_ERROR,
     SWAP_WITH_TEMPORARY,
     IP_CONSTANT,
+    REDUNDANT_ITER_CLONED,
 ]);
 
 /// Extracts a method call name, args, and `Span` of the method name.
@@ -4960,10 +5025,7 @@ impl Methods {
         // Handle method calls whose receiver and arguments may not come from expansion
         if let Some((name, recv, args, span, call_span)) = method_call(expr) {
             match (name, args) {
-                (
-                    sym::add | sym::offset | sym::sub | sym::wrapping_offset | sym::wrapping_add | sym::wrapping_sub,
-                    [_arg],
-                ) => {
+                (sym::add | sym::sub | sym::wrapping_add | sym::wrapping_sub, [_arg]) => {
                     zst_offset::check(cx, expr, recv);
                 },
                 (sym::all, [arg]) => {
@@ -5334,6 +5396,11 @@ impl Methods {
                     },
                     _ => iter_nth_zero::check(cx, expr, recv, n_arg),
                 },
+                (sym::offset | sym::wrapping_offset, [arg]) => {
+                    zst_offset::check(cx, expr, recv);
+
+                    ptr_offset_with_cast::check(cx, name, expr, recv, arg, self.msrv);
+                },
                 (sym::ok_or_else, [arg]) => {
                     unnecessary_lazy_eval::check(cx, expr, recv, arg, "ok_or");
                 },
diff --git a/src/tools/clippy/clippy_lints/src/methods/mut_mutex_lock.rs b/src/tools/clippy/clippy_lints/src/methods/mut_mutex_lock.rs
index 4235af882b0..9d2c5e6232d 100644
--- a/src/tools/clippy/clippy_lints/src/methods/mut_mutex_lock.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/mut_mutex_lock.rs
@@ -1,6 +1,6 @@
 use clippy_utils::diagnostics::span_lint_and_sugg;
 use clippy_utils::expr_custom_deref_adjustment;
-use clippy_utils::ty::{is_type_diagnostic_item, peel_mid_ty_refs_is_mutable};
+use clippy_utils::ty::{is_type_diagnostic_item, peel_and_count_ty_refs};
 use rustc_errors::Applicability;
 use rustc_hir::{Expr, Mutability};
 use rustc_lint::LateContext;
@@ -10,8 +10,7 @@ use super::MUT_MUTEX_LOCK;
 
 pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, ex: &'tcx Expr<'tcx>, recv: &'tcx Expr<'tcx>, name_span: Span) {
     if matches!(expr_custom_deref_adjustment(cx, recv), None | Some(Mutability::Mut))
-        && let (_, ref_depth, Mutability::Mut) = peel_mid_ty_refs_is_mutable(cx.typeck_results().expr_ty(recv))
-        && ref_depth >= 1
+        && let (_, _, Some(Mutability::Mut)) = peel_and_count_ty_refs(cx.typeck_results().expr_ty(recv))
         && let Some(method_id) = cx.typeck_results().type_dependent_def_id(ex.hir_id)
         && let Some(impl_id) = cx.tcx.impl_of_assoc(method_id)
         && is_type_diagnostic_item(cx, cx.tcx.type_of(impl_id).instantiate_identity(), sym::Mutex)
diff --git a/src/tools/clippy/clippy_lints/src/methods/or_fun_call.rs b/src/tools/clippy/clippy_lints/src/methods/or_fun_call.rs
index 04f0e3c0479..71b2f251ede 100644
--- a/src/tools/clippy/clippy_lints/src/methods/or_fun_call.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/or_fun_call.rs
@@ -2,6 +2,7 @@ use std::ops::ControlFlow;
 
 use clippy_utils::diagnostics::span_lint_and_sugg;
 use clippy_utils::eager_or_lazy::switch_to_lazy_eval;
+use clippy_utils::higher::VecArgs;
 use clippy_utils::source::snippet_with_context;
 use clippy_utils::ty::{expr_type_is_certain, implements_trait, is_type_diagnostic_item};
 use clippy_utils::visitors::for_each_expr;
@@ -97,6 +98,12 @@ pub(super) fn check<'tcx>(
             return false;
         }
 
+        // `.unwrap_or(vec![])` is as readable as `.unwrap_or_default()`. And if the expression is a
+        // non-empty `Vec`, then it will not be a default value anyway. Bail out in all cases.
+        if call_expr.and_then(|call_expr| VecArgs::hir(cx, call_expr)).is_some() {
+            return false;
+        }
+
         // needs to target Default::default in particular or be *::new and have a Default impl
         // available
         if (is_new(fun) && output_type_implements_default(fun))
diff --git a/src/tools/clippy/clippy_lints/src/methods/ptr_offset_with_cast.rs b/src/tools/clippy/clippy_lints/src/methods/ptr_offset_with_cast.rs
new file mode 100644
index 00000000000..d19d3b8eb89
--- /dev/null
+++ b/src/tools/clippy/clippy_lints/src/methods/ptr_offset_with_cast.rs
@@ -0,0 +1,82 @@
+use clippy_utils::diagnostics::span_lint_and_then;
+use clippy_utils::msrvs::{self, Msrv};
+use clippy_utils::sym;
+use rustc_errors::Applicability;
+use rustc_hir::{Expr, ExprKind};
+use rustc_lint::LateContext;
+use rustc_span::Symbol;
+use std::fmt;
+
+use super::PTR_OFFSET_WITH_CAST;
+
+pub(super) fn check(
+    cx: &LateContext<'_>,
+    method: Symbol,
+    expr: &Expr<'_>,
+    recv: &Expr<'_>,
+    arg: &Expr<'_>,
+    msrv: Msrv,
+) {
+    // `pointer::add` and `pointer::wrapping_add` are only stable since 1.26.0. These functions
+    // became const-stable in 1.61.0, the same version that `pointer::offset` became const-stable.
+    if !msrv.meets(cx, msrvs::POINTER_ADD_SUB_METHODS) {
+        return;
+    }
+
+    let method = match method {
+        sym::offset => Method::Offset,
+        sym::wrapping_offset => Method::WrappingOffset,
+        _ => return,
+    };
+
+    if !cx.typeck_results().expr_ty_adjusted(recv).is_raw_ptr() {
+        return;
+    }
+
+    // Check if the argument to the method call is a cast from usize.
+    let cast_lhs_expr = match arg.kind {
+        ExprKind::Cast(lhs, _) if cx.typeck_results().expr_ty(lhs).is_usize() => lhs,
+        _ => return,
+    };
+
+    let ExprKind::MethodCall(method_name, _, _, _) = expr.kind else {
+        return;
+    };
+
+    let msg = format!("use of `{method}` with a `usize` casted to an `isize`");
+    span_lint_and_then(cx, PTR_OFFSET_WITH_CAST, expr.span, msg, |diag| {
+        diag.multipart_suggestion(
+            format!("use `{}` instead", method.suggestion()),
+            vec![
+                (method_name.ident.span, method.suggestion().to_string()),
+                (arg.span.with_lo(cast_lhs_expr.span.hi()), String::new()),
+            ],
+            Applicability::MachineApplicable,
+        );
+    });
+}
+
+#[derive(Copy, Clone)]
+enum Method {
+    Offset,
+    WrappingOffset,
+}
+
+impl Method {
+    #[must_use]
+    fn suggestion(self) -> &'static str {
+        match self {
+            Self::Offset => "add",
+            Self::WrappingOffset => "wrapping_add",
+        }
+    }
+}
+
+impl fmt::Display for Method {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        match self {
+            Self::Offset => write!(f, "offset"),
+            Self::WrappingOffset => write!(f, "wrapping_offset"),
+        }
+    }
+}
diff --git a/src/tools/clippy/clippy_lints/src/methods/unnecessary_to_owned.rs b/src/tools/clippy/clippy_lints/src/methods/unnecessary_to_owned.rs
index c1f4904af7c..640931a8289 100644
--- a/src/tools/clippy/clippy_lints/src/methods/unnecessary_to_owned.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/unnecessary_to_owned.rs
@@ -3,11 +3,12 @@ use super::unnecessary_iter_cloned::{self, is_into_iter};
 use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_and_then};
 use clippy_utils::msrvs::{self, Msrv};
 use clippy_utils::source::{SpanRangeExt, snippet};
-use clippy_utils::ty::{get_iterator_item_ty, implements_trait, is_copy, is_type_diagnostic_item, is_type_lang_item};
+use clippy_utils::ty::{
+    get_iterator_item_ty, implements_trait, is_copy, is_type_diagnostic_item, is_type_lang_item, peel_and_count_ty_refs,
+};
 use clippy_utils::visitors::find_all_ret_expressions;
 use clippy_utils::{
-    fn_def_id, get_parent_expr, is_diag_item_method, is_diag_trait_item, is_expr_temporary_value, peel_middle_ty_refs,
-    return_ty, sym,
+    fn_def_id, get_parent_expr, is_diag_item_method, is_diag_trait_item, is_expr_temporary_value, return_ty, sym,
 };
 use rustc_errors::Applicability;
 use rustc_hir::def::{DefKind, Res};
@@ -119,8 +120,8 @@ fn check_addr_of_expr(
                 },
             ] = adjustments[..]
         && let receiver_ty = cx.typeck_results().expr_ty(receiver)
-        && let (target_ty, n_target_refs) = peel_middle_ty_refs(*target_ty)
-        && let (receiver_ty, n_receiver_refs) = peel_middle_ty_refs(receiver_ty)
+        && let (target_ty, n_target_refs, _) = peel_and_count_ty_refs(*target_ty)
+        && let (receiver_ty, n_receiver_refs, _) = peel_and_count_ty_refs(receiver_ty)
         // Only flag cases satisfying at least one of the following three conditions:
         // * the referent and receiver types are distinct
         // * the referent/receiver type is a copyable array
@@ -385,7 +386,7 @@ fn check_other_call_arg<'tcx>(
         && let fn_sig = cx.tcx.fn_sig(callee_def_id).instantiate_identity().skip_binder()
         && let Some(i) = recv.into_iter().chain(call_args).position(|arg| arg.hir_id == maybe_arg.hir_id)
         && let Some(input) = fn_sig.inputs().get(i)
-        && let (input, n_refs) = peel_middle_ty_refs(*input)
+        && let (input, n_refs, _) = peel_and_count_ty_refs(*input)
         && let (trait_predicates, _) = get_input_traits_and_projections(cx, callee_def_id, input)
         && let Some(sized_def_id) = cx.tcx.lang_items().sized_trait()
         && let Some(meta_sized_def_id) = cx.tcx.lang_items().meta_sized_trait()
diff --git a/src/tools/clippy/clippy_lints/src/methods/useless_asref.rs b/src/tools/clippy/clippy_lints/src/methods/useless_asref.rs
index 38fad239f67..e56f4b80d01 100644
--- a/src/tools/clippy/clippy_lints/src/methods/useless_asref.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/useless_asref.rs
@@ -1,6 +1,6 @@
 use clippy_utils::diagnostics::span_lint_and_sugg;
 use clippy_utils::source::snippet_with_applicability;
-use clippy_utils::ty::{implements_trait, should_call_clone_as_function, walk_ptrs_ty_depth};
+use clippy_utils::ty::{implements_trait, peel_and_count_ty_refs, should_call_clone_as_function};
 use clippy_utils::{get_parent_expr, is_diag_trait_item, path_to_local_id, peel_blocks, strip_pat_refs};
 use rustc_errors::Applicability;
 use rustc_hir::{self as hir, LangItem};
@@ -50,8 +50,8 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, call_name: Symbo
         // check if the type after `as_ref` or `as_mut` is the same as before
         let rcv_ty = cx.typeck_results().expr_ty(recvr);
         let res_ty = cx.typeck_results().expr_ty(expr);
-        let (base_res_ty, res_depth) = walk_ptrs_ty_depth(res_ty);
-        let (base_rcv_ty, rcv_depth) = walk_ptrs_ty_depth(rcv_ty);
+        let (base_res_ty, res_depth, _) = peel_and_count_ty_refs(res_ty);
+        let (base_rcv_ty, rcv_depth, _) = peel_and_count_ty_refs(rcv_ty);
         if base_rcv_ty == base_res_ty && rcv_depth >= res_depth {
             if let Some(parent) = get_parent_expr(cx, expr) {
                 // allow the `as_ref` or `as_mut` if it is followed by another method call
diff --git a/src/tools/clippy/clippy_lints/src/min_ident_chars.rs b/src/tools/clippy/clippy_lints/src/min_ident_chars.rs
index 6258e408217..1ceee836732 100644
--- a/src/tools/clippy/clippy_lints/src/min_ident_chars.rs
+++ b/src/tools/clippy/clippy_lints/src/min_ident_chars.rs
@@ -256,7 +256,11 @@ fn is_not_in_trait_impl(cx: &LateContext<'_>, pat: &Pat<'_>, ident: Ident) -> bo
 }
 
 fn get_param_name(impl_item: &ImplItem<'_>, cx: &LateContext<'_>, ident: Ident) -> Option<Symbol> {
-    if let ImplItemImplKind::Trait { trait_item_def_id: Ok(trait_item_def_id), .. } = impl_item.impl_kind {
+    if let ImplItemImplKind::Trait {
+        trait_item_def_id: Ok(trait_item_def_id),
+        ..
+    } = impl_item.impl_kind
+    {
         let trait_param_names = cx.tcx.fn_arg_idents(trait_item_def_id);
 
         let ImplItemKind::Fn(_, body_id) = impl_item.kind else {
diff --git a/src/tools/clippy/clippy_lints/src/misc.rs b/src/tools/clippy/clippy_lints/src/misc.rs
index 09ee6f7037c..19e9910dfe9 100644
--- a/src/tools/clippy/clippy_lints/src/misc.rs
+++ b/src/tools/clippy/clippy_lints/src/misc.rs
@@ -1,57 +1,11 @@
-use clippy_utils::diagnostics::{span_lint_and_then, span_lint_hir, span_lint_hir_and_then};
-use clippy_utils::source::{snippet, snippet_with_context};
+use clippy_utils::diagnostics::{span_lint_and_then, span_lint_hir_and_then};
 use clippy_utils::sugg::Sugg;
-use clippy_utils::{
-    SpanlessEq, fulfill_or_allowed, get_parent_expr, in_automatically_derived, is_lint_allowed, iter_input_pats,
-    last_path_segment,
-};
+use clippy_utils::{SpanlessEq, fulfill_or_allowed, get_parent_expr, in_automatically_derived, last_path_segment};
 use rustc_errors::Applicability;
 use rustc_hir::def::Res;
-use rustc_hir::intravisit::FnKind;
-use rustc_hir::{
-    BinOpKind, BindingMode, Body, ByRef, Expr, ExprKind, FnDecl, Mutability, PatKind, QPath, Stmt, StmtKind,
-};
+use rustc_hir::{BinOpKind, Expr, ExprKind, QPath, Stmt, StmtKind};
 use rustc_lint::{LateContext, LateLintPass, LintContext};
 use rustc_session::declare_lint_pass;
-use rustc_span::Span;
-use rustc_span::def_id::LocalDefId;
-
-use crate::ref_patterns::REF_PATTERNS;
-
-declare_clippy_lint! {
-    /// ### What it does
-    /// Checks for function arguments and let bindings denoted as
-    /// `ref`.
-    ///
-    /// ### Why is this bad?
-    /// The `ref` declaration makes the function take an owned
-    /// value, but turns the argument into a reference (which means that the value
-    /// is destroyed when exiting the function). This adds not much value: either
-    /// take a reference type, or take an owned value and create references in the
-    /// body.
-    ///
-    /// For let bindings, `let x = &foo;` is preferred over `let ref x = foo`. The
-    /// type of `x` is more obvious with the former.
-    ///
-    /// ### Known problems
-    /// If the argument is dereferenced within the function,
-    /// removing the `ref` will lead to errors. This can be fixed by removing the
-    /// dereferences, e.g., changing `*x` to `x` within the function.
-    ///
-    /// ### Example
-    /// ```no_run
-    /// fn foo(ref _x: u8) {}
-    /// ```
-    ///
-    /// Use instead:
-    /// ```no_run
-    /// fn foo(_x: &u8) {}
-    /// ```
-    #[clippy::version = "pre 1.29.0"]
-    pub TOPLEVEL_REF_ARG,
-    style,
-    "an entire binding declared as `ref`, in a function argument or a `let` statement"
-}
 
 declare_clippy_lint! {
     /// ### What it does
@@ -140,79 +94,13 @@ declare_clippy_lint! {
 }
 
 declare_lint_pass!(LintPass => [
-    TOPLEVEL_REF_ARG,
     USED_UNDERSCORE_BINDING,
     USED_UNDERSCORE_ITEMS,
     SHORT_CIRCUIT_STATEMENT,
 ]);
 
 impl<'tcx> LateLintPass<'tcx> for LintPass {
-    fn check_fn(
-        &mut self,
-        cx: &LateContext<'tcx>,
-        k: FnKind<'tcx>,
-        decl: &'tcx FnDecl<'_>,
-        body: &'tcx Body<'_>,
-        _: Span,
-        _: LocalDefId,
-    ) {
-        if !matches!(k, FnKind::Closure) {
-            for arg in iter_input_pats(decl, body) {
-                if let PatKind::Binding(BindingMode(ByRef::Yes(_), _), ..) = arg.pat.kind
-                    && is_lint_allowed(cx, REF_PATTERNS, arg.pat.hir_id)
-                    && !arg.span.in_external_macro(cx.tcx.sess.source_map())
-                {
-                    span_lint_hir(
-                        cx,
-                        TOPLEVEL_REF_ARG,
-                        arg.hir_id,
-                        arg.pat.span,
-                        "`ref` directly on a function parameter does not prevent taking ownership of the passed argument. \
-                        Consider using a reference type instead",
-                    );
-                }
-            }
-        }
-    }
-
     fn check_stmt(&mut self, cx: &LateContext<'tcx>, stmt: &'tcx Stmt<'_>) {
-        if let StmtKind::Let(local) = stmt.kind
-            && let PatKind::Binding(BindingMode(ByRef::Yes(mutabl), _), .., name, None) = local.pat.kind
-            && let Some(init) = local.init
-            // Do not emit if clippy::ref_patterns is not allowed to avoid having two lints for the same issue.
-            && is_lint_allowed(cx, REF_PATTERNS, local.pat.hir_id)
-            && !stmt.span.in_external_macro(cx.tcx.sess.source_map())
-        {
-            let ctxt = local.span.ctxt();
-            let mut app = Applicability::MachineApplicable;
-            let sugg_init = Sugg::hir_with_context(cx, init, ctxt, "..", &mut app);
-            let (mutopt, initref) = if mutabl == Mutability::Mut {
-                ("mut ", sugg_init.mut_addr())
-            } else {
-                ("", sugg_init.addr())
-            };
-            let tyopt = if let Some(ty) = local.ty {
-                let ty_snip = snippet_with_context(cx, ty.span, ctxt, "_", &mut app).0;
-                format!(": &{mutopt}{ty_snip}")
-            } else {
-                String::new()
-            };
-            span_lint_hir_and_then(
-                cx,
-                TOPLEVEL_REF_ARG,
-                init.hir_id,
-                local.pat.span,
-                "`ref` on an entire `let` pattern is discouraged, take a reference with `&` instead",
-                |diag| {
-                    diag.span_suggestion(
-                        stmt.span,
-                        "try",
-                        format!("let {name}{tyopt} = {initref};", name = snippet(cx, name.span, ".."),),
-                        app,
-                    );
-                },
-            );
-        }
         if let StmtKind::Semi(expr) = stmt.kind
             && let ExprKind::Binary(binop, a, b) = &expr.kind
             && matches!(binop.node, BinOpKind::And | BinOpKind::Or)
diff --git a/src/tools/clippy/clippy_lints/src/missing_doc.rs b/src/tools/clippy/clippy_lints/src/missing_doc.rs
index 39b5964bd87..1c62caa1c82 100644
--- a/src/tools/clippy/clippy_lints/src/missing_doc.rs
+++ b/src/tools/clippy/clippy_lints/src/missing_doc.rs
@@ -250,7 +250,7 @@ impl<'tcx> LateLintPass<'tcx> for MissingDoc {
             AssocContainer::Trait | AssocContainer::TraitImpl(_) => {
                 note_prev_span_then_ret!(self.prev_span, impl_item.span);
             },
-            AssocContainer::InherentImpl => {}
+            AssocContainer::InherentImpl => {},
         }
 
         let (article, desc) = cx.tcx.article_and_description(impl_item.owner_id.to_def_id());
diff --git a/src/tools/clippy/clippy_lints/src/multiple_unsafe_ops_per_block.rs b/src/tools/clippy/clippy_lints/src/multiple_unsafe_ops_per_block.rs
index c6c27e22b90..bc5e72270f4 100644
--- a/src/tools/clippy/clippy_lints/src/multiple_unsafe_ops_per_block.rs
+++ b/src/tools/clippy/clippy_lints/src/multiple_unsafe_ops_per_block.rs
@@ -1,3 +1,4 @@
+use clippy_utils::desugar_await;
 use clippy_utils::diagnostics::span_lint_and_then;
 use clippy_utils::visitors::{Descend, Visitable, for_each_expr};
 use core::ops::ControlFlow::Continue;
@@ -97,6 +98,13 @@ fn collect_unsafe_exprs<'tcx>(
 ) {
     for_each_expr(cx, node, |expr| {
         match expr.kind {
+            // The `await` itself will desugar to two unsafe calls, but we should ignore those.
+            // Instead, check the expression that is `await`ed
+            _ if let Some(e) = desugar_await(expr) => {
+                collect_unsafe_exprs(cx, e, unsafe_ops);
+                return Continue(Descend::No);
+            },
+
             ExprKind::InlineAsm(_) => unsafe_ops.push(("inline assembly used here", expr.span)),
 
             ExprKind::Field(e, _) => {
diff --git a/src/tools/clippy/clippy_lints/src/only_used_in_recursion.rs b/src/tools/clippy/clippy_lints/src/only_used_in_recursion.rs
index c4cad592e36..a21c361356e 100644
--- a/src/tools/clippy/clippy_lints/src/only_used_in_recursion.rs
+++ b/src/tools/clippy/clippy_lints/src/only_used_in_recursion.rs
@@ -252,7 +252,9 @@ impl<'tcx> LateLintPass<'tcx> for OnlyUsedInRecursion {
                 {
                     (
                         trait_item_id,
-                        FnKind::ImplTraitFn(std::ptr::from_ref(cx.tcx.erase_and_anonymize_regions(trait_ref.args)) as usize),
+                        FnKind::ImplTraitFn(
+                            std::ptr::from_ref(cx.tcx.erase_and_anonymize_regions(trait_ref.args)) as usize
+                        ),
                         usize::from(sig.decl.implicit_self.has_implicit_self()),
                     )
                 } else {
diff --git a/src/tools/clippy/clippy_lints/src/operators/erasing_op.rs b/src/tools/clippy/clippy_lints/src/operators/erasing_op.rs
index e3fc8d8fea7..8f5ee390f72 100644
--- a/src/tools/clippy/clippy_lints/src/operators/erasing_op.rs
+++ b/src/tools/clippy/clippy_lints/src/operators/erasing_op.rs
@@ -1,6 +1,6 @@
 use clippy_utils::consts::{ConstEvalCtxt, Constant};
 use clippy_utils::diagnostics::span_lint;
-use clippy_utils::ty::same_type_and_consts;
+use clippy_utils::ty::same_type_modulo_regions;
 
 use rustc_hir::{BinOpKind, Expr};
 use rustc_lint::LateContext;
@@ -29,7 +29,7 @@ pub(super) fn check<'tcx>(
 fn different_types(tck: &TypeckResults<'_>, input: &Expr<'_>, output: &Expr<'_>) -> bool {
     let input_ty = tck.expr_ty(input).peel_refs();
     let output_ty = tck.expr_ty(output).peel_refs();
-    !same_type_and_consts(input_ty, output_ty)
+    !same_type_modulo_regions(input_ty, output_ty)
 }
 
 fn check_op<'tcx>(
diff --git a/src/tools/clippy/clippy_lints/src/ptr_offset_with_cast.rs b/src/tools/clippy/clippy_lints/src/ptr_offset_with_cast.rs
deleted file mode 100644
index d8d813f9846..00000000000
--- a/src/tools/clippy/clippy_lints/src/ptr_offset_with_cast.rs
+++ /dev/null
@@ -1,151 +0,0 @@
-use clippy_utils::diagnostics::{span_lint, span_lint_and_sugg};
-use clippy_utils::source::SpanRangeExt;
-use clippy_utils::sym;
-use rustc_errors::Applicability;
-use rustc_hir::{Expr, ExprKind};
-use rustc_lint::{LateContext, LateLintPass};
-use rustc_session::declare_lint_pass;
-use std::fmt;
-
-declare_clippy_lint! {
-    /// ### What it does
-    /// Checks for usage of the `offset` pointer method with a `usize` casted to an
-    /// `isize`.
-    ///
-    /// ### Why is this bad?
-    /// If we’re always increasing the pointer address, we can avoid the numeric
-    /// cast by using the `add` method instead.
-    ///
-    /// ### Example
-    /// ```no_run
-    /// let vec = vec![b'a', b'b', b'c'];
-    /// let ptr = vec.as_ptr();
-    /// let offset = 1_usize;
-    ///
-    /// unsafe {
-    ///     ptr.offset(offset as isize);
-    /// }
-    /// ```
-    ///
-    /// Could be written:
-    ///
-    /// ```no_run
-    /// let vec = vec![b'a', b'b', b'c'];
-    /// let ptr = vec.as_ptr();
-    /// let offset = 1_usize;
-    ///
-    /// unsafe {
-    ///     ptr.add(offset);
-    /// }
-    /// ```
-    #[clippy::version = "1.30.0"]
-    pub PTR_OFFSET_WITH_CAST,
-    complexity,
-    "unneeded pointer offset cast"
-}
-
-declare_lint_pass!(PtrOffsetWithCast => [PTR_OFFSET_WITH_CAST]);
-
-impl<'tcx> LateLintPass<'tcx> for PtrOffsetWithCast {
-    fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
-        // Check if the expressions is a ptr.offset or ptr.wrapping_offset method call
-        let Some((receiver_expr, arg_expr, method)) = expr_as_ptr_offset_call(cx, expr) else {
-            return;
-        };
-
-        // Check if the argument to the method call is a cast from usize
-        let Some(cast_lhs_expr) = expr_as_cast_from_usize(cx, arg_expr) else {
-            return;
-        };
-
-        let msg = format!("use of `{method}` with a `usize` casted to an `isize`");
-        if let Some(sugg) = build_suggestion(cx, method, receiver_expr, cast_lhs_expr) {
-            span_lint_and_sugg(
-                cx,
-                PTR_OFFSET_WITH_CAST,
-                expr.span,
-                msg,
-                "try",
-                sugg,
-                Applicability::MachineApplicable,
-            );
-        } else {
-            span_lint(cx, PTR_OFFSET_WITH_CAST, expr.span, msg);
-        }
-    }
-}
-
-// If the given expression is a cast from a usize, return the lhs of the cast
-fn expr_as_cast_from_usize<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) -> Option<&'tcx Expr<'tcx>> {
-    if let ExprKind::Cast(cast_lhs_expr, _) = expr.kind
-        && is_expr_ty_usize(cx, cast_lhs_expr)
-    {
-        return Some(cast_lhs_expr);
-    }
-    None
-}
-
-// If the given expression is a ptr::offset  or ptr::wrapping_offset method call, return the
-// receiver, the arg of the method call, and the method.
-fn expr_as_ptr_offset_call<'tcx>(
-    cx: &LateContext<'tcx>,
-    expr: &'tcx Expr<'_>,
-) -> Option<(&'tcx Expr<'tcx>, &'tcx Expr<'tcx>, Method)> {
-    if let ExprKind::MethodCall(path_segment, arg_0, [arg_1], _) = &expr.kind
-        && is_expr_ty_raw_ptr(cx, arg_0)
-    {
-        if path_segment.ident.name == sym::offset {
-            return Some((arg_0, arg_1, Method::Offset));
-        }
-        if path_segment.ident.name == sym::wrapping_offset {
-            return Some((arg_0, arg_1, Method::WrappingOffset));
-        }
-    }
-    None
-}
-
-// Is the type of the expression a usize?
-fn is_expr_ty_usize(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
-    cx.typeck_results().expr_ty(expr) == cx.tcx.types.usize
-}
-
-// Is the type of the expression a raw pointer?
-fn is_expr_ty_raw_ptr(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
-    cx.typeck_results().expr_ty(expr).is_raw_ptr()
-}
-
-fn build_suggestion(
-    cx: &LateContext<'_>,
-    method: Method,
-    receiver_expr: &Expr<'_>,
-    cast_lhs_expr: &Expr<'_>,
-) -> Option<String> {
-    let receiver = receiver_expr.span.get_source_text(cx)?;
-    let cast_lhs = cast_lhs_expr.span.get_source_text(cx)?;
-    Some(format!("{receiver}.{}({cast_lhs})", method.suggestion()))
-}
-
-#[derive(Copy, Clone)]
-enum Method {
-    Offset,
-    WrappingOffset,
-}
-
-impl Method {
-    #[must_use]
-    fn suggestion(self) -> &'static str {
-        match self {
-            Self::Offset => "add",
-            Self::WrappingOffset => "wrapping_add",
-        }
-    }
-}
-
-impl fmt::Display for Method {
-    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        match self {
-            Self::Offset => write!(f, "offset"),
-            Self::WrappingOffset => write!(f, "wrapping_offset"),
-        }
-    }
-}
diff --git a/src/tools/clippy/clippy_lints/src/question_mark.rs b/src/tools/clippy/clippy_lints/src/question_mark.rs
index de12a25b03d..4aa100a50e0 100644
--- a/src/tools/clippy/clippy_lints/src/question_mark.rs
+++ b/src/tools/clippy/clippy_lints/src/question_mark.rs
@@ -8,9 +8,9 @@ use clippy_utils::source::snippet_with_applicability;
 use clippy_utils::sugg::Sugg;
 use clippy_utils::ty::{implements_trait, is_type_diagnostic_item};
 use clippy_utils::{
-    eq_expr_value, higher, is_else_clause, is_in_const_context, is_lint_allowed, is_path_lang_item, is_res_lang_ctor,
-    pat_and_expr_can_be_question_mark, path_res, path_to_local, path_to_local_id, peel_blocks, peel_blocks_with_stmt,
-    span_contains_cfg, span_contains_comment, sym,
+    eq_expr_value, fn_def_id_with_node_args, higher, is_else_clause, is_in_const_context, is_lint_allowed,
+    is_path_lang_item, is_res_lang_ctor, pat_and_expr_can_be_question_mark, path_res, path_to_local, path_to_local_id,
+    peel_blocks, peel_blocks_with_stmt, span_contains_cfg, span_contains_comment, sym,
 };
 use rustc_errors::Applicability;
 use rustc_hir::LangItem::{self, OptionNone, OptionSome, ResultErr, ResultOk};
@@ -393,8 +393,8 @@ fn check_arm_is_none_or_err<'tcx>(cx: &LateContext<'tcx>, mode: TryMode, arm: &A
                 && let ExprKind::Ret(Some(wrapped_ret_expr)) = arm_body.kind
                 && let ExprKind::Call(ok_ctor, [ret_expr]) = wrapped_ret_expr.kind
                 && is_res_lang_ctor(cx, path_res(cx, ok_ctor), ResultErr)
-                // check `...` is `val` from binding
-                && path_to_local_id(ret_expr, ok_val)
+                // check if `...` is `val` from binding or `val.into()`
+                && is_local_or_local_into(cx, ret_expr, ok_val)
             {
                 true
             } else {
@@ -417,6 +417,17 @@ fn check_arm_is_none_or_err<'tcx>(cx: &LateContext<'tcx>, mode: TryMode, arm: &A
     }
 }
 
+/// Check if `expr` is `val` or `val.into()`
+fn is_local_or_local_into(cx: &LateContext<'_>, expr: &Expr<'_>, val: HirId) -> bool {
+    let is_into_call = fn_def_id_with_node_args(cx, expr)
+        .and_then(|(fn_def_id, _)| cx.tcx.trait_of_assoc(fn_def_id))
+        .is_some_and(|trait_def_id| cx.tcx.is_diagnostic_item(sym::Into, trait_def_id));
+    match expr.kind {
+        ExprKind::MethodCall(_, recv, [], _) | ExprKind::Call(_, [recv]) => is_into_call && path_to_local_id(recv, val),
+        _ => path_to_local_id(expr, val),
+    }
+}
+
 fn check_arms_are_try<'tcx>(cx: &LateContext<'tcx>, mode: TryMode, arm1: &Arm<'tcx>, arm2: &Arm<'tcx>) -> bool {
     (check_arm_is_some_or_ok(cx, mode, arm1) && check_arm_is_none_or_err(cx, mode, arm2))
         || (check_arm_is_some_or_ok(cx, mode, arm2) && check_arm_is_none_or_err(cx, mode, arm1))
diff --git a/src/tools/clippy/clippy_lints/src/read_zero_byte_vec.rs b/src/tools/clippy/clippy_lints/src/read_zero_byte_vec.rs
index acd840401c6..b8d4e7c4651 100644
--- a/src/tools/clippy/clippy_lints/src/read_zero_byte_vec.rs
+++ b/src/tools/clippy/clippy_lints/src/read_zero_byte_vec.rs
@@ -1,6 +1,6 @@
 use clippy_utils::diagnostics::{span_lint_hir, span_lint_hir_and_then};
 use clippy_utils::higher::{VecInitKind, get_vec_init_kind};
-use clippy_utils::source::snippet;
+use clippy_utils::source::{indent_of, snippet};
 use clippy_utils::{get_enclosing_block, sym};
 
 use rustc_errors::Applicability;
@@ -83,10 +83,12 @@ impl<'tcx> LateLintPass<'tcx> for ReadZeroByteVec {
                             expr.span,
                             "reading zero byte data to `Vec`",
                             |diag| {
+                                let span = first_stmt_containing_expr(cx, expr).map_or(expr.span, |stmt| stmt.span);
+                                let indent = indent_of(cx, span).unwrap_or(0);
                                 diag.span_suggestion(
-                                    expr.span,
+                                    span.shrink_to_lo(),
                                     "try",
-                                    format!("{}.resize({len}, 0); {}", ident, snippet(cx, expr.span, "..")),
+                                    format!("{ident}.resize({len}, 0);\n{}", " ".repeat(indent)),
                                     applicability,
                                 );
                             },
@@ -100,14 +102,15 @@ impl<'tcx> LateLintPass<'tcx> for ReadZeroByteVec {
                                 expr.span,
                                 "reading zero byte data to `Vec`",
                                 |diag| {
+                                    let span = first_stmt_containing_expr(cx, expr).map_or(expr.span, |stmt| stmt.span);
+                                    let indent = indent_of(cx, span).unwrap_or(0);
                                     diag.span_suggestion(
-                                        expr.span,
+                                        span.shrink_to_lo(),
                                         "try",
                                         format!(
-                                            "{}.resize({}, 0); {}",
-                                            ident,
+                                            "{ident}.resize({}, 0);\n{}",
                                             snippet(cx, e.span, ".."),
-                                            snippet(cx, expr.span, "..")
+                                            " ".repeat(indent)
                                         ),
                                         applicability,
                                     );
@@ -130,6 +133,16 @@ impl<'tcx> LateLintPass<'tcx> for ReadZeroByteVec {
     }
 }
 
+fn first_stmt_containing_expr<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) -> Option<&'tcx hir::Stmt<'tcx>> {
+    cx.tcx.hir_parent_iter(expr.hir_id).find_map(|(_, node)| {
+        if let hir::Node::Stmt(stmt) = node {
+            Some(stmt)
+        } else {
+            None
+        }
+    })
+}
+
 struct ReadVecVisitor<'tcx> {
     local_id: HirId,
     read_zero_expr: Option<&'tcx Expr<'tcx>>,
diff --git a/src/tools/clippy/clippy_lints/src/redundant_clone.rs b/src/tools/clippy/clippy_lints/src/redundant_clone.rs
index 1d58cdd26d8..de6766cbe94 100644
--- a/src/tools/clippy/clippy_lints/src/redundant_clone.rs
+++ b/src/tools/clippy/clippy_lints/src/redundant_clone.rs
@@ -2,7 +2,7 @@ use clippy_utils::diagnostics::{span_lint_hir, span_lint_hir_and_then};
 use clippy_utils::fn_has_unsatisfiable_preds;
 use clippy_utils::mir::{LocalUsage, PossibleBorrowerMap, visit_local_usage};
 use clippy_utils::source::SpanRangeExt;
-use clippy_utils::ty::{has_drop, is_copy, is_type_lang_item, walk_ptrs_ty_depth};
+use clippy_utils::ty::{has_drop, is_copy, is_type_lang_item, peel_and_count_ty_refs};
 use rustc_errors::Applicability;
 use rustc_hir::intravisit::FnKind;
 use rustc_hir::{Body, FnDecl, LangItem, def_id};
@@ -263,7 +263,7 @@ fn is_call_with_ref_arg<'tcx>(
         && args.len() == 1
         && let mir::Operand::Move(mir::Place { local, .. }) = &args[0].node
         && let ty::FnDef(def_id, _) = *func.ty(mir, cx.tcx).kind()
-        && let (inner_ty, 1) = walk_ptrs_ty_depth(args[0].node.ty(mir, cx.tcx))
+        && let (inner_ty, 1, _) = peel_and_count_ty_refs(args[0].node.ty(mir, cx.tcx))
         && !is_copy(cx, inner_ty)
     {
         Some((def_id, *local, inner_ty, destination.as_local()?))
diff --git a/src/tools/clippy/clippy_lints/src/redundant_slicing.rs b/src/tools/clippy/clippy_lints/src/redundant_slicing.rs
index 324a05cdcc0..a358eff2ce5 100644
--- a/src/tools/clippy/clippy_lints/src/redundant_slicing.rs
+++ b/src/tools/clippy/clippy_lints/src/redundant_slicing.rs
@@ -1,7 +1,7 @@
 use clippy_utils::diagnostics::span_lint_and_then;
+use clippy_utils::get_parent_expr;
 use clippy_utils::source::snippet_with_context;
-use clippy_utils::ty::is_type_lang_item;
-use clippy_utils::{get_parent_expr, peel_middle_ty_refs};
+use clippy_utils::ty::{is_type_lang_item, peel_and_count_ty_refs};
 use rustc_ast::util::parser::ExprPrecedence;
 use rustc_errors::Applicability;
 use rustc_hir::{BorrowKind, Expr, ExprKind, LangItem, Mutability};
@@ -82,8 +82,8 @@ impl<'tcx> LateLintPass<'tcx> for RedundantSlicing {
             && let ExprKind::Index(indexed, range, _) = addressee.kind
             && is_type_lang_item(cx, cx.typeck_results().expr_ty_adjusted(range), LangItem::RangeFull)
         {
-            let (expr_ty, expr_ref_count) = peel_middle_ty_refs(cx.typeck_results().expr_ty(expr));
-            let (indexed_ty, indexed_ref_count) = peel_middle_ty_refs(cx.typeck_results().expr_ty(indexed));
+            let (expr_ty, expr_ref_count, _) = peel_and_count_ty_refs(cx.typeck_results().expr_ty(expr));
+            let (indexed_ty, indexed_ref_count, _) = peel_and_count_ty_refs(cx.typeck_results().expr_ty(indexed));
             let parent_expr = get_parent_expr(cx, expr);
             let needs_parens_for_prefix =
                 parent_expr.is_some_and(|parent| cx.precedence(parent) > ExprPrecedence::Prefix);
diff --git a/src/tools/clippy/clippy_lints/src/returns.rs b/src/tools/clippy/clippy_lints/src/returns.rs
deleted file mode 100644
index e0c93153a77..00000000000
--- a/src/tools/clippy/clippy_lints/src/returns.rs
+++ /dev/null
@@ -1,513 +0,0 @@
-use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_hir_and_then};
-use clippy_utils::source::{SpanRangeExt, snippet_with_context};
-use clippy_utils::sugg::has_enclosing_paren;
-use clippy_utils::visitors::for_each_expr;
-use clippy_utils::{
-    binary_expr_needs_parentheses, fn_def_id, is_from_proc_macro, is_inside_let_else, is_res_lang_ctor,
-    leaks_droppable_temporary_with_limited_lifetime, path_res, path_to_local_id, span_contains_cfg,
-    span_find_starting_semi, sym,
-};
-use core::ops::ControlFlow;
-use rustc_ast::MetaItemInner;
-use rustc_errors::Applicability;
-use rustc_hir::LangItem::ResultErr;
-use rustc_hir::intravisit::FnKind;
-use rustc_hir::{
-    Block, Body, Expr, ExprKind, FnDecl, HirId, ItemKind, LangItem, MatchSource, Node, OwnerNode, PatKind, QPath, Stmt,
-    StmtKind,
-};
-use rustc_lint::{LateContext, LateLintPass, Level, LintContext};
-use rustc_middle::ty::adjustment::Adjust;
-use rustc_middle::ty::{self, GenericArgKind, Ty};
-use rustc_session::declare_lint_pass;
-use rustc_span::def_id::LocalDefId;
-use rustc_span::edition::Edition;
-use rustc_span::{BytePos, Pos, Span};
-use std::borrow::Cow;
-use std::fmt::Display;
-
-declare_clippy_lint! {
-    /// ### What it does
-    /// Checks for `let`-bindings, which are subsequently
-    /// returned.
-    ///
-    /// ### Why is this bad?
-    /// It is just extraneous code. Remove it to make your code
-    /// more rusty.
-    ///
-    /// ### Known problems
-    /// In the case of some temporaries, e.g. locks, eliding the variable binding could lead
-    /// to deadlocks. See [this issue](https://github.com/rust-lang/rust/issues/37612).
-    /// This could become relevant if the code is later changed to use the code that would have been
-    /// bound without first assigning it to a let-binding.
-    ///
-    /// ### Example
-    /// ```no_run
-    /// fn foo() -> String {
-    ///     let x = String::new();
-    ///     x
-    /// }
-    /// ```
-    /// instead, use
-    /// ```no_run
-    /// fn foo() -> String {
-    ///     String::new()
-    /// }
-    /// ```
-    #[clippy::version = "pre 1.29.0"]
-    pub LET_AND_RETURN,
-    style,
-    "creating a let-binding and then immediately returning it like `let x = expr; x` at the end of a block"
-}
-
-declare_clippy_lint! {
-    /// ### What it does
-    /// Checks for return statements at the end of a block.
-    ///
-    /// ### Why is this bad?
-    /// Removing the `return` and semicolon will make the code
-    /// more rusty.
-    ///
-    /// ### Example
-    /// ```no_run
-    /// fn foo(x: usize) -> usize {
-    ///     return x;
-    /// }
-    /// ```
-    /// simplify to
-    /// ```no_run
-    /// fn foo(x: usize) -> usize {
-    ///     x
-    /// }
-    /// ```
-    #[clippy::version = "pre 1.29.0"]
-    pub NEEDLESS_RETURN,
-    // This lint requires some special handling in `check_final_expr` for `#[expect]`.
-    // This handling needs to be updated if the group gets changed. This should also
-    // be caught by tests.
-    style,
-    "using a return statement like `return expr;` where an expression would suffice"
-}
-
-declare_clippy_lint! {
-    /// ### What it does
-    /// Checks for return statements on `Err` paired with the `?` operator.
-    ///
-    /// ### Why is this bad?
-    /// The `return` is unnecessary.
-    ///
-    /// Returns may be used to add attributes to the return expression. Return
-    /// statements with attributes are therefore be accepted by this lint.
-    ///
-    /// ### Example
-    /// ```rust,ignore
-    /// fn foo(x: usize) -> Result<(), Box<dyn Error>> {
-    ///     if x == 0 {
-    ///         return Err(...)?;
-    ///     }
-    ///     Ok(())
-    /// }
-    /// ```
-    /// simplify to
-    /// ```rust,ignore
-    /// fn foo(x: usize) -> Result<(), Box<dyn Error>> {
-    ///     if x == 0 {
-    ///         Err(...)?;
-    ///     }
-    ///     Ok(())
-    /// }
-    /// ```
-    /// if paired with `try_err`, use instead:
-    /// ```rust,ignore
-    /// fn foo(x: usize) -> Result<(), Box<dyn Error>> {
-    ///     if x == 0 {
-    ///         return Err(...);
-    ///     }
-    ///     Ok(())
-    /// }
-    /// ```
-    #[clippy::version = "1.73.0"]
-    pub NEEDLESS_RETURN_WITH_QUESTION_MARK,
-    style,
-    "using a return statement like `return Err(expr)?;` where removing it would suffice"
-}
-
-#[derive(PartialEq, Eq)]
-enum RetReplacement<'tcx> {
-    Empty,
-    Block,
-    Unit,
-    NeedsPar(Cow<'tcx, str>, Applicability),
-    Expr(Cow<'tcx, str>, Applicability),
-}
-
-impl RetReplacement<'_> {
-    fn sugg_help(&self) -> &'static str {
-        match self {
-            Self::Empty | Self::Expr(..) => "remove `return`",
-            Self::Block => "replace `return` with an empty block",
-            Self::Unit => "replace `return` with a unit value",
-            Self::NeedsPar(..) => "remove `return` and wrap the sequence with parentheses",
-        }
-    }
-
-    fn applicability(&self) -> Applicability {
-        match self {
-            Self::Expr(_, ap) | Self::NeedsPar(_, ap) => *ap,
-            _ => Applicability::MachineApplicable,
-        }
-    }
-}
-
-impl Display for RetReplacement<'_> {
-    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
-        match self {
-            Self::Empty => write!(f, ""),
-            Self::Block => write!(f, "{{}}"),
-            Self::Unit => write!(f, "()"),
-            Self::NeedsPar(inner, _) => write!(f, "({inner})"),
-            Self::Expr(inner, _) => write!(f, "{inner}"),
-        }
-    }
-}
-
-declare_lint_pass!(Return => [LET_AND_RETURN, NEEDLESS_RETURN, NEEDLESS_RETURN_WITH_QUESTION_MARK]);
-
-/// Checks if a return statement is "needed" in the middle of a block, or if it can be removed. This
-/// is the case when the enclosing block expression is coerced to some other type, which only works
-/// because of the never-ness of `return` expressions
-fn stmt_needs_never_type(cx: &LateContext<'_>, stmt_hir_id: HirId) -> bool {
-    cx.tcx
-        .hir_parent_iter(stmt_hir_id)
-        .find_map(|(_, node)| if let Node::Expr(expr) = node { Some(expr) } else { None })
-        .is_some_and(|e| {
-            cx.typeck_results()
-                .expr_adjustments(e)
-                .iter()
-                .any(|adjust| adjust.target != cx.tcx.types.unit && matches!(adjust.kind, Adjust::NeverToAny))
-        })
-}
-
-impl<'tcx> LateLintPass<'tcx> for Return {
-    fn check_stmt(&mut self, cx: &LateContext<'tcx>, stmt: &'tcx Stmt<'_>) {
-        if !stmt.span.in_external_macro(cx.sess().source_map())
-            && let StmtKind::Semi(expr) = stmt.kind
-            && let ExprKind::Ret(Some(ret)) = expr.kind
-            // return Err(...)? desugars to a match
-            // over a Err(...).branch()
-            // which breaks down to a branch call, with the callee being
-            // the constructor of the Err variant
-            && let ExprKind::Match(maybe_cons, _, MatchSource::TryDesugar(_)) = ret.kind
-            && let ExprKind::Call(_, [maybe_result_err]) = maybe_cons.kind
-            && let ExprKind::Call(maybe_constr, _) = maybe_result_err.kind
-            && is_res_lang_ctor(cx, path_res(cx, maybe_constr), ResultErr)
-
-            // Ensure this is not the final stmt, otherwise removing it would cause a compile error
-            && let OwnerNode::Item(item) = cx.tcx.hir_owner_node(cx.tcx.hir_get_parent_item(expr.hir_id))
-            && let ItemKind::Fn { body, .. } = item.kind
-            && let block = cx.tcx.hir_body(body).value
-            && let ExprKind::Block(block, _) = block.kind
-            && !is_inside_let_else(cx.tcx, expr)
-            && let [.., final_stmt] = block.stmts
-            && final_stmt.hir_id != stmt.hir_id
-            && !is_from_proc_macro(cx, expr)
-            && !stmt_needs_never_type(cx, stmt.hir_id)
-        {
-            span_lint_and_sugg(
-                cx,
-                NEEDLESS_RETURN_WITH_QUESTION_MARK,
-                expr.span.until(ret.span),
-                "unneeded `return` statement with `?` operator",
-                "remove it",
-                String::new(),
-                Applicability::MachineApplicable,
-            );
-        }
-    }
-
-    fn check_block(&mut self, cx: &LateContext<'tcx>, block: &'tcx Block<'_>) {
-        // we need both a let-binding stmt and an expr
-        if let Some(retexpr) = block.expr
-            && let Some(stmt) = block.stmts.iter().last()
-            && let StmtKind::Let(local) = &stmt.kind
-            && local.ty.is_none()
-            && cx.tcx.hir_attrs(local.hir_id).is_empty()
-            && let Some(initexpr) = &local.init
-            && let PatKind::Binding(_, local_id, _, _) = local.pat.kind
-            && path_to_local_id(retexpr, local_id)
-            && (cx.sess().edition() >= Edition::Edition2024 || !last_statement_borrows(cx, initexpr))
-            && !initexpr.span.in_external_macro(cx.sess().source_map())
-            && !retexpr.span.in_external_macro(cx.sess().source_map())
-            && !local.span.from_expansion()
-            && !span_contains_cfg(cx, stmt.span.between(retexpr.span))
-        {
-            span_lint_hir_and_then(
-                cx,
-                LET_AND_RETURN,
-                retexpr.hir_id,
-                retexpr.span,
-                "returning the result of a `let` binding from a block",
-                |err| {
-                    err.span_label(local.span, "unnecessary `let` binding");
-
-                    if let Some(src) = initexpr.span.get_source_text(cx) {
-                        let sugg = if binary_expr_needs_parentheses(initexpr) {
-                            if has_enclosing_paren(&src) {
-                                src.to_owned()
-                            } else {
-                                format!("({src})")
-                            }
-                        } else if !cx.typeck_results().expr_adjustments(retexpr).is_empty() {
-                            if has_enclosing_paren(&src) {
-                                format!("{src} as _")
-                            } else {
-                                format!("({src}) as _")
-                            }
-                        } else {
-                            src.to_owned()
-                        };
-                        err.multipart_suggestion(
-                            "return the expression directly",
-                            vec![(local.span, String::new()), (retexpr.span, sugg)],
-                            Applicability::MachineApplicable,
-                        );
-                    } else {
-                        err.span_help(initexpr.span, "this expression can be directly returned");
-                    }
-                },
-            );
-        }
-    }
-
-    fn check_fn(
-        &mut self,
-        cx: &LateContext<'tcx>,
-        kind: FnKind<'tcx>,
-        _: &'tcx FnDecl<'tcx>,
-        body: &'tcx Body<'tcx>,
-        sp: Span,
-        _: LocalDefId,
-    ) {
-        if sp.from_expansion() {
-            return;
-        }
-
-        match kind {
-            FnKind::Closure => {
-                // when returning without value in closure, replace this `return`
-                // with an empty block to prevent invalid suggestion (see #6501)
-                let replacement = if let ExprKind::Ret(None) = &body.value.kind {
-                    RetReplacement::Block
-                } else {
-                    RetReplacement::Empty
-                };
-                check_final_expr(cx, body.value, vec![], replacement, None);
-            },
-            FnKind::ItemFn(..) | FnKind::Method(..) => {
-                check_block_return(cx, &body.value.kind, sp, vec![]);
-            },
-        }
-    }
-}
-
-// if `expr` is a block, check if there are needless returns in it
-fn check_block_return<'tcx>(cx: &LateContext<'tcx>, expr_kind: &ExprKind<'tcx>, sp: Span, mut semi_spans: Vec<Span>) {
-    if let ExprKind::Block(block, _) = expr_kind {
-        if let Some(block_expr) = block.expr {
-            check_final_expr(cx, block_expr, semi_spans, RetReplacement::Empty, None);
-        } else if let Some(stmt) = block.stmts.iter().last() {
-            match stmt.kind {
-                StmtKind::Expr(expr) => {
-                    check_final_expr(cx, expr, semi_spans, RetReplacement::Empty, None);
-                },
-                StmtKind::Semi(semi_expr) => {
-                    // Remove ending semicolons and any whitespace ' ' in between.
-                    // Without `return`, the suggestion might not compile if the semicolon is retained
-                    if let Some(semi_span) = stmt.span.trim_start(semi_expr.span) {
-                        let semi_span_to_remove =
-                            span_find_starting_semi(cx.sess().source_map(), semi_span.with_hi(sp.hi()));
-                        semi_spans.push(semi_span_to_remove);
-                    }
-                    check_final_expr(cx, semi_expr, semi_spans, RetReplacement::Empty, None);
-                },
-                _ => (),
-            }
-        }
-    }
-}
-
-fn check_final_expr<'tcx>(
-    cx: &LateContext<'tcx>,
-    expr: &'tcx Expr<'tcx>,
-    semi_spans: Vec<Span>, /* containing all the places where we would need to remove semicolons if finding an
-                            * needless return */
-    replacement: RetReplacement<'tcx>,
-    match_ty_opt: Option<Ty<'_>>,
-) {
-    let peeled_drop_expr = expr.peel_drop_temps();
-    match &peeled_drop_expr.kind {
-        // simple return is always "bad"
-        ExprKind::Ret(inner) => {
-            // check if expr return nothing
-            let ret_span = if inner.is_none() && replacement == RetReplacement::Empty {
-                extend_span_to_previous_non_ws(cx, peeled_drop_expr.span)
-            } else {
-                peeled_drop_expr.span
-            };
-
-            let replacement = if let Some(inner_expr) = inner {
-                // if desugar of `do yeet`, don't lint
-                if let ExprKind::Call(path_expr, [_]) = inner_expr.kind
-                    && let ExprKind::Path(QPath::LangItem(LangItem::TryTraitFromYeet, ..)) = path_expr.kind
-                {
-                    return;
-                }
-
-                let mut applicability = Applicability::MachineApplicable;
-                let (snippet, _) = snippet_with_context(cx, inner_expr.span, ret_span.ctxt(), "..", &mut applicability);
-                if binary_expr_needs_parentheses(inner_expr) {
-                    RetReplacement::NeedsPar(snippet, applicability)
-                } else {
-                    RetReplacement::Expr(snippet, applicability)
-                }
-            } else {
-                match match_ty_opt {
-                    Some(match_ty) => {
-                        match match_ty.kind() {
-                            // If the code got till here with
-                            // tuple not getting detected before it,
-                            // then we are sure it's going to be Unit
-                            // type
-                            ty::Tuple(_) => RetReplacement::Unit,
-                            // We don't want to anything in this case
-                            // cause we can't predict what the user would
-                            // want here
-                            _ => return,
-                        }
-                    },
-                    None => replacement,
-                }
-            };
-
-            if inner.is_some_and(|inner| leaks_droppable_temporary_with_limited_lifetime(cx, inner)) {
-                return;
-            }
-
-            if ret_span.from_expansion() || is_from_proc_macro(cx, expr) {
-                return;
-            }
-
-            // Returns may be used to turn an expression into a statement in rustc's AST.
-            // This allows the addition of attributes, like `#[allow]` (See: clippy#9361)
-            // `#[expect(clippy::needless_return)]` needs to be handled separately to
-            // actually fulfill the expectation (clippy::#12998)
-            match cx.tcx.hir_attrs(expr.hir_id) {
-                [] => {},
-                [attr] => {
-                    if matches!(Level::from_attr(attr), Some((Level::Expect, _)))
-                        && let metas = attr.meta_item_list()
-                        && let Some(lst) = metas
-                        && let [MetaItemInner::MetaItem(meta_item), ..] = lst.as_slice()
-                        && let [tool, lint_name] = meta_item.path.segments.as_slice()
-                        && tool.ident.name == sym::clippy
-                        && matches!(
-                            lint_name.ident.name,
-                            sym::needless_return | sym::style | sym::all | sym::warnings
-                        )
-                    {
-                        // This is an expectation of the `needless_return` lint
-                    } else {
-                        return;
-                    }
-                },
-                _ => return,
-            }
-
-            emit_return_lint(
-                cx,
-                peeled_drop_expr.span,
-                ret_span,
-                semi_spans,
-                &replacement,
-                expr.hir_id,
-            );
-        },
-        ExprKind::If(_, then, else_clause_opt) => {
-            check_block_return(cx, &then.kind, peeled_drop_expr.span, semi_spans.clone());
-            if let Some(else_clause) = else_clause_opt {
-                // The `RetReplacement` won't be used there as `else_clause` will be either a block or
-                // a `if` expression.
-                check_final_expr(cx, else_clause, semi_spans, RetReplacement::Empty, match_ty_opt);
-            }
-        },
-        // a match expr, check all arms
-        // an if/if let expr, check both exprs
-        // note, if without else is going to be a type checking error anyways
-        // (except for unit type functions) so we don't match it
-        ExprKind::Match(_, arms, MatchSource::Normal) => {
-            let match_ty = cx.typeck_results().expr_ty(peeled_drop_expr);
-            for arm in *arms {
-                check_final_expr(cx, arm.body, semi_spans.clone(), RetReplacement::Unit, Some(match_ty));
-            }
-        },
-        // if it's a whole block, check it
-        other_expr_kind => check_block_return(cx, other_expr_kind, peeled_drop_expr.span, semi_spans),
-    }
-}
-
-fn emit_return_lint(
-    cx: &LateContext<'_>,
-    lint_span: Span,
-    ret_span: Span,
-    semi_spans: Vec<Span>,
-    replacement: &RetReplacement<'_>,
-    at: HirId,
-) {
-    span_lint_hir_and_then(
-        cx,
-        NEEDLESS_RETURN,
-        at,
-        lint_span,
-        "unneeded `return` statement",
-        |diag| {
-            let suggestions = std::iter::once((ret_span, replacement.to_string()))
-                .chain(semi_spans.into_iter().map(|span| (span, String::new())))
-                .collect();
-
-            diag.multipart_suggestion_verbose(replacement.sugg_help(), suggestions, replacement.applicability());
-        },
-    );
-}
-
-fn last_statement_borrows<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) -> bool {
-    for_each_expr(cx, expr, |e| {
-        if let Some(def_id) = fn_def_id(cx, e)
-            && cx
-                .tcx
-                .fn_sig(def_id)
-                .instantiate_identity()
-                .skip_binder()
-                .output()
-                .walk()
-                .any(|arg| matches!(arg.kind(), GenericArgKind::Lifetime(re) if !re.is_static()))
-        {
-            ControlFlow::Break(())
-        } else {
-            ControlFlow::Continue(())
-        }
-    })
-    .is_some()
-}
-
-// Go backwards while encountering whitespace and extend the given Span to that point.
-fn extend_span_to_previous_non_ws(cx: &LateContext<'_>, sp: Span) -> Span {
-    if let Ok(prev_source) = cx.sess().source_map().span_to_prev_source(sp) {
-        let ws = [b' ', b'\t', b'\n'];
-        if let Some(non_ws_pos) = prev_source.bytes().rposition(|c| !ws.contains(&c)) {
-            let len = prev_source.len() - non_ws_pos - 1;
-            return sp.with_lo(sp.lo() - BytePos::from_usize(len));
-        }
-    }
-
-    sp
-}
diff --git a/src/tools/clippy/clippy_lints/src/returns/let_and_return.rs b/src/tools/clippy/clippy_lints/src/returns/let_and_return.rs
new file mode 100644
index 00000000000..e2002fb36e5
--- /dev/null
+++ b/src/tools/clippy/clippy_lints/src/returns/let_and_return.rs
@@ -0,0 +1,86 @@
+use clippy_utils::diagnostics::span_lint_hir_and_then;
+use clippy_utils::source::SpanRangeExt;
+use clippy_utils::sugg::has_enclosing_paren;
+use clippy_utils::visitors::for_each_expr;
+use clippy_utils::{binary_expr_needs_parentheses, fn_def_id, path_to_local_id, span_contains_cfg};
+use core::ops::ControlFlow;
+use rustc_errors::Applicability;
+use rustc_hir::{Block, Expr, PatKind, StmtKind};
+use rustc_lint::{LateContext, LintContext};
+use rustc_middle::ty::GenericArgKind;
+use rustc_span::edition::Edition;
+
+use super::LET_AND_RETURN;
+
+pub(super) fn check_block<'tcx>(cx: &LateContext<'tcx>, block: &'tcx Block<'_>) {
+    // we need both a let-binding stmt and an expr
+    if let Some(retexpr) = block.expr
+        && let Some(stmt) = block.stmts.last()
+        && let StmtKind::Let(local) = &stmt.kind
+        && local.ty.is_none()
+        && cx.tcx.hir_attrs(local.hir_id).is_empty()
+        && let Some(initexpr) = &local.init
+        && let PatKind::Binding(_, local_id, _, _) = local.pat.kind
+        && path_to_local_id(retexpr, local_id)
+        && (cx.sess().edition() >= Edition::Edition2024 || !last_statement_borrows(cx, initexpr))
+        && !initexpr.span.in_external_macro(cx.sess().source_map())
+        && !retexpr.span.in_external_macro(cx.sess().source_map())
+        && !local.span.from_expansion()
+        && !span_contains_cfg(cx, stmt.span.between(retexpr.span))
+    {
+        span_lint_hir_and_then(
+            cx,
+            LET_AND_RETURN,
+            retexpr.hir_id,
+            retexpr.span,
+            "returning the result of a `let` binding from a block",
+            |err| {
+                err.span_label(local.span, "unnecessary `let` binding");
+
+                if let Some(src) = initexpr.span.get_source_text(cx) {
+                    let sugg = if binary_expr_needs_parentheses(initexpr) {
+                        if has_enclosing_paren(&src) {
+                            src.to_owned()
+                        } else {
+                            format!("({src})")
+                        }
+                    } else if !cx.typeck_results().expr_adjustments(retexpr).is_empty() {
+                        if has_enclosing_paren(&src) {
+                            format!("{src} as _")
+                        } else {
+                            format!("({src}) as _")
+                        }
+                    } else {
+                        src.to_owned()
+                    };
+                    err.multipart_suggestion(
+                        "return the expression directly",
+                        vec![(local.span, String::new()), (retexpr.span, sugg)],
+                        Applicability::MachineApplicable,
+                    );
+                } else {
+                    err.span_help(initexpr.span, "this expression can be directly returned");
+                }
+            },
+        );
+    }
+}
+fn last_statement_borrows<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) -> bool {
+    for_each_expr(cx, expr, |e| {
+        if let Some(def_id) = fn_def_id(cx, e)
+            && cx
+                .tcx
+                .fn_sig(def_id)
+                .instantiate_identity()
+                .skip_binder()
+                .output()
+                .walk()
+                .any(|arg| matches!(arg.kind(), GenericArgKind::Lifetime(re) if !re.is_static()))
+        {
+            ControlFlow::Break(())
+        } else {
+            ControlFlow::Continue(())
+        }
+    })
+    .is_some()
+}
diff --git a/src/tools/clippy/clippy_lints/src/returns/mod.rs b/src/tools/clippy/clippy_lints/src/returns/mod.rs
new file mode 100644
index 00000000000..47c6332b9b8
--- /dev/null
+++ b/src/tools/clippy/clippy_lints/src/returns/mod.rs
@@ -0,0 +1,140 @@
+use rustc_hir::intravisit::FnKind;
+use rustc_hir::{Block, Body, FnDecl, Stmt};
+use rustc_lint::{LateContext, LateLintPass};
+use rustc_session::declare_lint_pass;
+use rustc_span::Span;
+use rustc_span::def_id::LocalDefId;
+
+mod let_and_return;
+mod needless_return;
+mod needless_return_with_question_mark;
+
+declare_clippy_lint! {
+    /// ### What it does
+    /// Checks for `let`-bindings, which are subsequently
+    /// returned.
+    ///
+    /// ### Why is this bad?
+    /// It is just extraneous code. Remove it to make your code
+    /// more rusty.
+    ///
+    /// ### Known problems
+    /// In the case of some temporaries, e.g. locks, eliding the variable binding could lead
+    /// to deadlocks. See [this issue](https://github.com/rust-lang/rust/issues/37612).
+    /// This could become relevant if the code is later changed to use the code that would have been
+    /// bound without first assigning it to a let-binding.
+    ///
+    /// ### Example
+    /// ```no_run
+    /// fn foo() -> String {
+    ///     let x = String::new();
+    ///     x
+    /// }
+    /// ```
+    /// instead, use
+    /// ```no_run
+    /// fn foo() -> String {
+    ///     String::new()
+    /// }
+    /// ```
+    #[clippy::version = "pre 1.29.0"]
+    pub LET_AND_RETURN,
+    style,
+    "creating a let-binding and then immediately returning it like `let x = expr; x` at the end of a block"
+}
+
+declare_clippy_lint! {
+    /// ### What it does
+    /// Checks for return statements at the end of a block.
+    ///
+    /// ### Why is this bad?
+    /// Removing the `return` and semicolon will make the code
+    /// more rusty.
+    ///
+    /// ### Example
+    /// ```no_run
+    /// fn foo(x: usize) -> usize {
+    ///     return x;
+    /// }
+    /// ```
+    /// simplify to
+    /// ```no_run
+    /// fn foo(x: usize) -> usize {
+    ///     x
+    /// }
+    /// ```
+    #[clippy::version = "pre 1.29.0"]
+    pub NEEDLESS_RETURN,
+    // This lint requires some special handling in `check_final_expr` for `#[expect]`.
+    // This handling needs to be updated if the group gets changed. This should also
+    // be caught by tests.
+    style,
+    "using a return statement like `return expr;` where an expression would suffice"
+}
+
+declare_clippy_lint! {
+    /// ### What it does
+    /// Checks for return statements on `Err` paired with the `?` operator.
+    ///
+    /// ### Why is this bad?
+    /// The `return` is unnecessary.
+    ///
+    /// Returns may be used to add attributes to the return expression. Return
+    /// statements with attributes are therefore be accepted by this lint.
+    ///
+    /// ### Example
+    /// ```rust,ignore
+    /// fn foo(x: usize) -> Result<(), Box<dyn Error>> {
+    ///     if x == 0 {
+    ///         return Err(...)?;
+    ///     }
+    ///     Ok(())
+    /// }
+    /// ```
+    /// simplify to
+    /// ```rust,ignore
+    /// fn foo(x: usize) -> Result<(), Box<dyn Error>> {
+    ///     if x == 0 {
+    ///         Err(...)?;
+    ///     }
+    ///     Ok(())
+    /// }
+    /// ```
+    /// if paired with `try_err`, use instead:
+    /// ```rust,ignore
+    /// fn foo(x: usize) -> Result<(), Box<dyn Error>> {
+    ///     if x == 0 {
+    ///         return Err(...);
+    ///     }
+    ///     Ok(())
+    /// }
+    /// ```
+    #[clippy::version = "1.73.0"]
+    pub NEEDLESS_RETURN_WITH_QUESTION_MARK,
+    style,
+    "using a return statement like `return Err(expr)?;` where removing it would suffice"
+}
+
+declare_lint_pass!(Return => [LET_AND_RETURN, NEEDLESS_RETURN, NEEDLESS_RETURN_WITH_QUESTION_MARK]);
+
+impl<'tcx> LateLintPass<'tcx> for Return {
+    fn check_stmt(&mut self, cx: &LateContext<'tcx>, stmt: &'tcx Stmt<'_>) {
+        needless_return_with_question_mark::check_stmt(cx, stmt);
+    }
+
+    fn check_block(&mut self, cx: &LateContext<'tcx>, block: &'tcx Block<'_>) {
+        let_and_return::check_block(cx, block);
+    }
+
+    fn check_fn(
+        &mut self,
+        cx: &LateContext<'tcx>,
+        kind: FnKind<'tcx>,
+        _: &'tcx FnDecl<'tcx>,
+        body: &'tcx Body<'tcx>,
+        sp: Span,
+        _: LocalDefId,
+    ) {
+        needless_return::check_fn(cx, kind, body, sp);
+    }
+}
diff --git a/src/tools/clippy/clippy_lints/src/returns/needless_return.rs b/src/tools/clippy/clippy_lints/src/returns/needless_return.rs
new file mode 100644
index 00000000000..04739fc1b22
--- /dev/null
+++ b/src/tools/clippy/clippy_lints/src/returns/needless_return.rs
@@ -0,0 +1,269 @@
+use clippy_utils::diagnostics::span_lint_hir_and_then;
+use clippy_utils::source::snippet_with_context;
+use clippy_utils::{
+    binary_expr_needs_parentheses, is_from_proc_macro, leaks_droppable_temporary_with_limited_lifetime,
+    span_contains_cfg, span_find_starting_semi, sym,
+};
+use rustc_ast::MetaItemInner;
+use rustc_errors::Applicability;
+use rustc_hir::intravisit::FnKind;
+use rustc_hir::{Body, Expr, ExprKind, HirId, LangItem, MatchSource, QPath, StmtKind};
+use rustc_lint::{LateContext, Level, LintContext};
+use rustc_middle::ty::{self, Ty};
+use rustc_span::{BytePos, Pos, Span};
+use std::borrow::Cow;
+use std::fmt::Display;
+
+use super::NEEDLESS_RETURN;
+
+#[derive(PartialEq, Eq)]
+enum RetReplacement<'tcx> {
+    Empty,
+    Block,
+    Unit,
+    NeedsPar(Cow<'tcx, str>, Applicability),
+    Expr(Cow<'tcx, str>, Applicability),
+}
+
+impl RetReplacement<'_> {
+    fn sugg_help(&self) -> &'static str {
+        match self {
+            Self::Empty | Self::Expr(..) => "remove `return`",
+            Self::Block => "replace `return` with an empty block",
+            Self::Unit => "replace `return` with a unit value",
+            Self::NeedsPar(..) => "remove `return` and wrap the sequence with parentheses",
+        }
+    }
+
+    fn applicability(&self) -> Applicability {
+        match self {
+            Self::Expr(_, ap) | Self::NeedsPar(_, ap) => *ap,
+            _ => Applicability::MachineApplicable,
+        }
+    }
+}
+
+impl Display for RetReplacement<'_> {
+    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+        match self {
+            Self::Empty => f.write_str(""),
+            Self::Block => f.write_str("{}"),
+            Self::Unit => f.write_str("()"),
+            Self::NeedsPar(inner, _) => write!(f, "({inner})"),
+            Self::Expr(inner, _) => write!(f, "{inner}"),
+        }
+    }
+}
+
+pub(super) fn check_fn<'tcx>(cx: &LateContext<'tcx>, kind: FnKind<'tcx>, body: &'tcx Body<'tcx>, sp: Span) {
+    if sp.from_expansion() {
+        return;
+    }
+
+    match kind {
+        FnKind::Closure => {
+            // when returning without value in closure, replace this `return`
+            // with an empty block to prevent invalid suggestion (see #6501)
+            let replacement = if let ExprKind::Ret(None) = &body.value.kind {
+                RetReplacement::Block
+            } else {
+                RetReplacement::Empty
+            };
+            check_final_expr(cx, body.value, vec![], replacement, None);
+        },
+        FnKind::ItemFn(..) | FnKind::Method(..) => {
+            check_block_return(cx, &body.value.kind, sp, vec![]);
+        },
+    }
+}
+
+// if `expr` is a block, check if there are needless returns in it
+fn check_block_return<'tcx>(cx: &LateContext<'tcx>, expr_kind: &ExprKind<'tcx>, sp: Span, mut semi_spans: Vec<Span>) {
+    if let ExprKind::Block(block, _) = expr_kind {
+        if let Some(block_expr) = block.expr {
+            check_final_expr(cx, block_expr, semi_spans, RetReplacement::Empty, None);
+        } else if let Some(stmt) = block.stmts.last() {
+            if span_contains_cfg(
+                cx,
+                Span::between(
+                    stmt.span,
+                    cx.sess().source_map().end_point(block.span), // the closing brace of the block
+                ),
+            ) {
+                return;
+            }
+            match stmt.kind {
+                StmtKind::Expr(expr) => {
+                    check_final_expr(cx, expr, semi_spans, RetReplacement::Empty, None);
+                },
+                StmtKind::Semi(semi_expr) => {
+                    // Remove ending semicolons and any whitespace ' ' in between.
+                    // Without `return`, the suggestion might not compile if the semicolon is retained
+                    if let Some(semi_span) = stmt.span.trim_start(semi_expr.span) {
+                        let semi_span_to_remove =
+                            span_find_starting_semi(cx.sess().source_map(), semi_span.with_hi(sp.hi()));
+                        semi_spans.push(semi_span_to_remove);
+                    }
+                    check_final_expr(cx, semi_expr, semi_spans, RetReplacement::Empty, None);
+                },
+                _ => (),
+            }
+        }
+    }
+}
+
+fn check_final_expr<'tcx>(
+    cx: &LateContext<'tcx>,
+    expr: &'tcx Expr<'tcx>,
+    semi_spans: Vec<Span>, /* containing all the places where we would need to remove semicolons if finding an
+                            * needless return */
+    replacement: RetReplacement<'tcx>,
+    match_ty_opt: Option<Ty<'_>>,
+) {
+    let peeled_drop_expr = expr.peel_drop_temps();
+    match &peeled_drop_expr.kind {
+        // simple return is always "bad"
+        ExprKind::Ret(inner) => {
+            // check if expr return nothing
+            let ret_span = if inner.is_none() && replacement == RetReplacement::Empty {
+                extend_span_to_previous_non_ws(cx, peeled_drop_expr.span)
+            } else {
+                peeled_drop_expr.span
+            };
+
+            let replacement = if let Some(inner_expr) = inner {
+                // if desugar of `do yeet`, don't lint
+                if let ExprKind::Call(path_expr, [_]) = inner_expr.kind
+                    && let ExprKind::Path(QPath::LangItem(LangItem::TryTraitFromYeet, ..)) = path_expr.kind
+                {
+                    return;
+                }
+
+                let mut applicability = Applicability::MachineApplicable;
+                let (snippet, _) = snippet_with_context(cx, inner_expr.span, ret_span.ctxt(), "..", &mut applicability);
+                if binary_expr_needs_parentheses(inner_expr) {
+                    RetReplacement::NeedsPar(snippet, applicability)
+                } else {
+                    RetReplacement::Expr(snippet, applicability)
+                }
+            } else {
+                match match_ty_opt {
+                    Some(match_ty) => {
+                        match match_ty.kind() {
+                            // If the code got till here with
+                            // tuple not getting detected before it,
+                            // then we are sure it's going to be Unit
+                            // type
+                            ty::Tuple(_) => RetReplacement::Unit,
+                            // We don't want to anything in this case
+                            // cause we can't predict what the user would
+                            // want here
+                            _ => return,
+                        }
+                    },
+                    None => replacement,
+                }
+            };
+
+            if inner.is_some_and(|inner| leaks_droppable_temporary_with_limited_lifetime(cx, inner)) {
+                return;
+            }
+
+            if ret_span.from_expansion() || is_from_proc_macro(cx, expr) {
+                return;
+            }
+
+            // Returns may be used to turn an expression into a statement in rustc's AST.
+            // This allows the addition of attributes, like `#[allow]` (See: clippy#9361)
+            // `#[expect(clippy::needless_return)]` needs to be handled separately to
+            // actually fulfill the expectation (clippy::#12998)
+            match cx.tcx.hir_attrs(expr.hir_id) {
+                [] => {},
+                [attr] => {
+                    if matches!(Level::from_attr(attr), Some((Level::Expect, _)))
+                        && let metas = attr.meta_item_list()
+                        && let Some(lst) = metas
+                        && let [MetaItemInner::MetaItem(meta_item), ..] = lst.as_slice()
+                        && let [tool, lint_name] = meta_item.path.segments.as_slice()
+                        && tool.ident.name == sym::clippy
+                        && matches!(
+                            lint_name.ident.name,
+                            sym::needless_return | sym::style | sym::all | sym::warnings
+                        )
+                    {
+                        // This is an expectation of the `needless_return` lint
+                    } else {
+                        return;
+                    }
+                },
+                _ => return,
+            }
+
+            emit_return_lint(
+                cx,
+                peeled_drop_expr.span,
+                ret_span,
+                semi_spans,
+                &replacement,
+                expr.hir_id,
+            );
+        },
+        ExprKind::If(_, then, else_clause_opt) => {
+            check_block_return(cx, &then.kind, peeled_drop_expr.span, semi_spans.clone());
+            if let Some(else_clause) = else_clause_opt {
+                // The `RetReplacement` won't be used there as `else_clause` will be either a block or
+                // a `if` expression.
+                check_final_expr(cx, else_clause, semi_spans, RetReplacement::Empty, match_ty_opt);
+            }
+        },
+        // a match expr, check all arms
+        // an if/if let expr, check both exprs
+        // note, if without else is going to be a type checking error anyways
+        // (except for unit type functions) so we don't match it
+        ExprKind::Match(_, arms, MatchSource::Normal) => {
+            let match_ty = cx.typeck_results().expr_ty(peeled_drop_expr);
+            for arm in *arms {
+                check_final_expr(cx, arm.body, semi_spans.clone(), RetReplacement::Unit, Some(match_ty));
+            }
+        },
+        // if it's a whole block, check it
+        other_expr_kind => check_block_return(cx, other_expr_kind, peeled_drop_expr.span, semi_spans),
+    }
+}
+
+fn emit_return_lint(
+    cx: &LateContext<'_>,
+    lint_span: Span,
+    ret_span: Span,
+    semi_spans: Vec<Span>,
+    replacement: &RetReplacement<'_>,
+    at: HirId,
+) {
+    span_lint_hir_and_then(
+        cx,
+        NEEDLESS_RETURN,
+        at,
+        lint_span,
+        "unneeded `return` statement",
+        |diag| {
+            let suggestions = std::iter::once((ret_span, replacement.to_string()))
+                .chain(semi_spans.into_iter().map(|span| (span, String::new())))
+                .collect();
+
+            diag.multipart_suggestion_verbose(replacement.sugg_help(), suggestions, replacement.applicability());
+        },
+    );
+}
+
+// Go backwards while encountering whitespace and extend the given Span to that point.
+fn extend_span_to_previous_non_ws(cx: &LateContext<'_>, sp: Span) -> Span {
+    if let Ok(prev_source) = cx.sess().source_map().span_to_prev_source(sp) {
+        let ws = [b' ', b'\t', b'\n'];
+        if let Some(non_ws_pos) = prev_source.bytes().rposition(|c| !ws.contains(&c)) {
+            let len = prev_source.len() - non_ws_pos - 1;
+            return sp.with_lo(sp.lo() - BytePos::from_usize(len));
+        }
+    }
+
+    sp
+}
diff --git a/src/tools/clippy/clippy_lints/src/returns/needless_return_with_question_mark.rs b/src/tools/clippy/clippy_lints/src/returns/needless_return_with_question_mark.rs
new file mode 100644
index 00000000000..c05038cd1e5
--- /dev/null
+++ b/src/tools/clippy/clippy_lints/src/returns/needless_return_with_question_mark.rs
@@ -0,0 +1,60 @@
+use clippy_utils::diagnostics::span_lint_and_sugg;
+use clippy_utils::{is_from_proc_macro, is_inside_let_else, is_res_lang_ctor, path_res};
+use rustc_errors::Applicability;
+use rustc_hir::LangItem::ResultErr;
+use rustc_hir::{ExprKind, HirId, ItemKind, MatchSource, Node, OwnerNode, Stmt, StmtKind};
+use rustc_lint::{LateContext, LintContext};
+use rustc_middle::ty::adjustment::Adjust;
+
+use super::NEEDLESS_RETURN_WITH_QUESTION_MARK;
+
+pub(super) fn check_stmt<'tcx>(cx: &LateContext<'tcx>, stmt: &'tcx Stmt<'_>) {
+    if !stmt.span.in_external_macro(cx.sess().source_map())
+        && let StmtKind::Semi(expr) = stmt.kind
+        && let ExprKind::Ret(Some(ret)) = expr.kind
+        // return Err(...)? desugars to a match
+        // over a Err(...).branch()
+        // which breaks down to a branch call, with the callee being
+        // the constructor of the Err variant
+        && let ExprKind::Match(maybe_cons, _, MatchSource::TryDesugar(_)) = ret.kind
+        && let ExprKind::Call(_, [maybe_result_err]) = maybe_cons.kind
+        && let ExprKind::Call(maybe_constr, _) = maybe_result_err.kind
+        && is_res_lang_ctor(cx, path_res(cx, maybe_constr), ResultErr)
+
+        // Ensure this is not the final stmt, otherwise removing it would cause a compile error
+        && let OwnerNode::Item(item) = cx.tcx.hir_owner_node(cx.tcx.hir_get_parent_item(expr.hir_id))
+        && let ItemKind::Fn { body, .. } = item.kind
+        && let block = cx.tcx.hir_body(body).value
+        && let ExprKind::Block(block, _) = block.kind
+        && !is_inside_let_else(cx.tcx, expr)
+        && let [.., final_stmt] = block.stmts
+        && final_stmt.hir_id != stmt.hir_id
+        && !is_from_proc_macro(cx, expr)
+        && !stmt_needs_never_type(cx, stmt.hir_id)
+    {
+        span_lint_and_sugg(
+            cx,
+            NEEDLESS_RETURN_WITH_QUESTION_MARK,
+            expr.span.until(ret.span),
+            "unneeded `return` statement with `?` operator",
+            "remove it",
+            String::new(),
+            Applicability::MachineApplicable,
+        );
+    }
+}
+
+/// Checks if a return statement is "needed" in the middle of a block, or if it can be removed.
+/// This is the case when the enclosing block expression is coerced to some other type,
+/// which only works because of the never-ness of `return` expressions
+fn stmt_needs_never_type(cx: &LateContext<'_>, stmt_hir_id: HirId) -> bool {
+    cx.tcx
+        .hir_parent_iter(stmt_hir_id)
+        .find_map(|(_, node)| if let Node::Expr(expr) = node { Some(expr) } else { None })
+        .is_some_and(|e| {
+            cx.typeck_results()
+                .expr_adjustments(e)
+                .iter()
+                .any(|adjust| adjust.target != cx.tcx.types.unit && matches!(adjust.kind, Adjust::NeverToAny))
+        })
+}
diff --git a/src/tools/clippy/clippy_lints/src/semicolon_block.rs b/src/tools/clippy/clippy_lints/src/semicolon_block.rs
index 1dea8f17c34..371d62a0684 100644
--- a/src/tools/clippy/clippy_lints/src/semicolon_block.rs
+++ b/src/tools/clippy/clippy_lints/src/semicolon_block.rs
@@ -1,5 +1,6 @@
 use clippy_config::Conf;
 use clippy_utils::diagnostics::span_lint_and_then;
+use clippy_utils::source::SpanRangeExt;
 use rustc_errors::Applicability;
 use rustc_hir::{Block, Expr, ExprKind, Stmt, StmtKind};
 use rustc_lint::{LateContext, LateLintPass, LintContext};
@@ -82,6 +83,19 @@ impl SemicolonBlock {
         let insert_span = tail.span.source_callsite().shrink_to_hi();
         let remove_span = semi_span.with_lo(block.span.hi());
 
+        // If the block is surrounded by parens (`({ 0 });`), the author probably knows what
+        // they're doing and why, so don't get in their way.
+        //
+        // This has the additional benefit of stopping the block being parsed as a function call:
+        // ```
+        // fn foo() {
+        //     ({ 0 }); // if we remove this `;`, this will parse as a `({ 0 })(5);` function call
+        //     (5);
+        // }
+        if remove_span.check_source_text(cx, |src| src.contains(')')) {
+            return;
+        }
+
         if self.semicolon_inside_block_ignore_singleline && get_line(cx, remove_span) == get_line(cx, insert_span) {
             return;
         }
diff --git a/src/tools/clippy/clippy_lints/src/size_of_ref.rs b/src/tools/clippy/clippy_lints/src/size_of_ref.rs
index 60d923bcd77..606e852aae9 100644
--- a/src/tools/clippy/clippy_lints/src/size_of_ref.rs
+++ b/src/tools/clippy/clippy_lints/src/size_of_ref.rs
@@ -1,5 +1,6 @@
 use clippy_utils::diagnostics::span_lint_and_help;
-use clippy_utils::{path_def_id, peel_middle_ty_refs};
+use clippy_utils::path_def_id;
+use clippy_utils::ty::peel_and_count_ty_refs;
 use rustc_hir::{Expr, ExprKind};
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_session::declare_lint_pass;
@@ -59,7 +60,7 @@ impl LateLintPass<'_> for SizeOfRef {
             && let Some(def_id) = path_def_id(cx, path)
             && cx.tcx.is_diagnostic_item(sym::mem_size_of_val, def_id)
             && let arg_ty = cx.typeck_results().expr_ty(arg)
-            && peel_middle_ty_refs(arg_ty).1 > 1
+            && peel_and_count_ty_refs(arg_ty).1 > 1
         {
             span_lint_and_help(
                 cx,
diff --git a/src/tools/clippy/clippy_lints/src/toplevel_ref_arg.rs b/src/tools/clippy/clippy_lints/src/toplevel_ref_arg.rs
new file mode 100644
index 00000000000..074b79263d3
--- /dev/null
+++ b/src/tools/clippy/clippy_lints/src/toplevel_ref_arg.rs
@@ -0,0 +1,119 @@
+use clippy_utils::diagnostics::{span_lint_hir, span_lint_hir_and_then};
+use clippy_utils::source::{snippet, snippet_with_context};
+use clippy_utils::sugg::Sugg;
+use clippy_utils::{is_lint_allowed, iter_input_pats};
+use rustc_errors::Applicability;
+use rustc_hir::intravisit::FnKind;
+use rustc_hir::{BindingMode, Body, ByRef, FnDecl, Mutability, PatKind, Stmt, StmtKind};
+use rustc_lint::{LateContext, LateLintPass};
+use rustc_session::declare_lint_pass;
+use rustc_span::Span;
+use rustc_span::def_id::LocalDefId;
+
+use crate::ref_patterns::REF_PATTERNS;
+
+declare_clippy_lint! {
+    /// ### What it does
+    /// Checks for function arguments and let bindings denoted as
+    /// `ref`.
+    ///
+    /// ### Why is this bad?
+    /// The `ref` declaration makes the function take an owned
+    /// value, but turns the argument into a reference (which means that the value
+    /// is destroyed when exiting the function). This adds not much value: either
+    /// take a reference type, or take an owned value and create references in the
+    /// body.
+    ///
+    /// For let bindings, `let x = &foo;` is preferred over `let ref x = foo`. The
+    /// type of `x` is more obvious with the former.
+    ///
+    /// ### Known problems
+    /// If the argument is dereferenced within the function,
+    /// removing the `ref` will lead to errors. This can be fixed by removing the
+    /// dereferences, e.g., changing `*x` to `x` within the function.
+    ///
+    /// ### Example
+    /// ```no_run
+    /// fn foo(ref _x: u8) {}
+    /// ```
+    ///
+    /// Use instead:
+    /// ```no_run
+    /// fn foo(_x: &u8) {}
+    /// ```
+    #[clippy::version = "pre 1.29.0"]
+    pub TOPLEVEL_REF_ARG,
+    style,
+    "an entire binding declared as `ref`, in a function argument or a `let` statement"
+}
+
+declare_lint_pass!(ToplevelRefArg => [TOPLEVEL_REF_ARG]);
+
+impl<'tcx> LateLintPass<'tcx> for ToplevelRefArg {
+    fn check_fn(
+        &mut self,
+        cx: &LateContext<'tcx>,
+        k: FnKind<'tcx>,
+        decl: &'tcx FnDecl<'_>,
+        body: &'tcx Body<'_>,
+        _: Span,
+        _: LocalDefId,
+    ) {
+        if !matches!(k, FnKind::Closure) {
+            for arg in iter_input_pats(decl, body) {
+                if let PatKind::Binding(BindingMode(ByRef::Yes(_), _), ..) = arg.pat.kind
+                    && is_lint_allowed(cx, REF_PATTERNS, arg.pat.hir_id)
+                    && !arg.span.in_external_macro(cx.tcx.sess.source_map())
+                {
+                    span_lint_hir(
+                        cx,
+                        TOPLEVEL_REF_ARG,
+                        arg.hir_id,
+                        arg.pat.span,
+                        "`ref` directly on a function parameter does not prevent taking ownership of the passed argument. \
+                            Consider using a reference type instead",
+                    );
+                }
+            }
+        }
+    }
+
+    fn check_stmt(&mut self, cx: &LateContext<'tcx>, stmt: &'tcx Stmt<'_>) {
+        if let StmtKind::Let(local) = stmt.kind
+            && let PatKind::Binding(BindingMode(ByRef::Yes(mutabl), _), .., name, None) = local.pat.kind
+            && let Some(init) = local.init
+            // Do not emit if clippy::ref_patterns is not allowed to avoid having two lints for the same issue.
+            && is_lint_allowed(cx, REF_PATTERNS, local.pat.hir_id)
+            && !stmt.span.in_external_macro(cx.tcx.sess.source_map())
+        {
+            let ctxt = local.span.ctxt();
+            let mut app = Applicability::MachineApplicable;
+            let sugg_init = Sugg::hir_with_context(cx, init, ctxt, "..", &mut app);
+            let (mutopt, initref) = match mutabl {
+                Mutability::Mut => ("mut ", sugg_init.mut_addr()),
+                Mutability::Not => ("", sugg_init.addr()),
+            };
+            let tyopt = if let Some(ty) = local.ty {
+                let ty_snip = snippet_with_context(cx, ty.span, ctxt, "_", &mut app).0;
+                format!(": &{mutopt}{ty_snip}")
+            } else {
+                String::new()
+            };
+            span_lint_hir_and_then(
+                cx,
+                TOPLEVEL_REF_ARG,
+                init.hir_id,
+                local.pat.span,
+                "`ref` on an entire `let` pattern is discouraged, take a reference with `&` instead",
+                |diag| {
+                    diag.span_suggestion(
+                        stmt.span,
+                        "try",
+                        format!("let {name}{tyopt} = {initref};", name = snippet(cx, name.span, ".."),),
+                        app,
+                    );
+                },
+            );
+        }
+    }
+}
diff --git a/src/tools/clippy/clippy_lints/src/transmute/transmute_ptr_to_ref.rs b/src/tools/clippy/clippy_lints/src/transmute/transmute_ptr_to_ref.rs
index e58212fae15..e67ab6a73d2 100644
--- a/src/tools/clippy/clippy_lints/src/transmute/transmute_ptr_to_ref.rs
+++ b/src/tools/clippy/clippy_lints/src/transmute/transmute_ptr_to_ref.rs
@@ -28,16 +28,27 @@ pub(super) fn check<'tcx>(
                 format!("transmute from a pointer type (`{from_ty}`) to a reference type (`{to_ty}`)"),
                 |diag| {
                     let arg = sugg::Sugg::hir(cx, arg, "..");
-                    let (deref, cast) = if *mutbl == Mutability::Mut {
-                        ("&mut *", "*mut")
-                    } else {
-                        ("&*", "*const")
+                    let (deref, cast) = match mutbl {
+                        Mutability::Mut => ("&mut *", "*mut"),
+                        Mutability::Not => ("&*", "*const"),
                     };
                     let mut app = Applicability::MachineApplicable;
 
                     let sugg = if let Some(ty) = get_explicit_type(path) {
                         let ty_snip = snippet_with_applicability(cx, ty.span, "..", &mut app);
-                        if msrv.meets(cx, msrvs::POINTER_CAST) {
+                        if !to_ref_ty.is_sized(cx.tcx, cx.typing_env()) {
+                            // We can't suggest `.cast()`, because that requires `to_ref_ty` to be Sized.
+                            if from_ptr_ty.has_erased_regions() {
+                                // We can't suggest `as *mut/const () as *mut/const to_ref_ty`, because the former is a
+                                // thin pointer, whereas the latter is a wide pointer, due of its pointee, `to_ref_ty`,
+                                // being !Sized.
+                                //
+                                // The only remaining option is be to skip `*mut/const ()`, but that might not be safe
+                                // to do because of the erased regions in `from_ptr_ty`, so reduce the applicability.
+                                app = Applicability::MaybeIncorrect;
+                            }
+                            sugg::make_unop(deref, arg.as_ty(format!("{cast} {ty_snip}"))).to_string()
+                        } else if msrv.meets(cx, msrvs::POINTER_CAST) {
                             format!("{deref}{}.cast::<{ty_snip}>()", arg.maybe_paren())
                         } else if from_ptr_ty.has_erased_regions() {
                             sugg::make_unop(deref, arg.as_ty(format!("{cast} () as {cast} {ty_snip}"))).to_string()
@@ -45,15 +56,22 @@ pub(super) fn check<'tcx>(
                             sugg::make_unop(deref, arg.as_ty(format!("{cast} {ty_snip}"))).to_string()
                         }
                     } else if *from_ptr_ty == *to_ref_ty {
-                        if from_ptr_ty.has_erased_regions() {
-                            if msrv.meets(cx, msrvs::POINTER_CAST) {
-                                format!("{deref}{}.cast::<{to_ref_ty}>()", arg.maybe_paren())
-                            } else {
-                                sugg::make_unop(deref, arg.as_ty(format!("{cast} () as {cast} {to_ref_ty}")))
-                                    .to_string()
-                            }
-                        } else {
+                        if !from_ptr_ty.has_erased_regions() {
                             sugg::make_unop(deref, arg).to_string()
+                        } else if !to_ref_ty.is_sized(cx.tcx, cx.typing_env()) {
+                            // 1. We can't suggest `.cast()`, because that requires `to_ref_ty` to be Sized.
+                            // 2. We can't suggest `as *mut/const () as *mut/const to_ref_ty`, because the former is a
+                            //    thin pointer, whereas the latter is a wide pointer, due of its pointee, `to_ref_ty`,
+                            //    being !Sized.
+                            //
+                            // The only remaining option is be to skip `*mut/const ()`, but that might not be safe to do
+                            // because of the erased regions in `from_ptr_ty`, so reduce the applicability.
+                            app = Applicability::MaybeIncorrect;
+                            sugg::make_unop(deref, arg.as_ty(format!("{cast} {to_ref_ty}"))).to_string()
+                        } else if msrv.meets(cx, msrvs::POINTER_CAST) {
+                            format!("{deref}{}.cast::<{to_ref_ty}>()", arg.maybe_paren())
+                        } else {
+                            sugg::make_unop(deref, arg.as_ty(format!("{cast} () as {cast} {to_ref_ty}"))).to_string()
                         }
                     } else {
                         sugg::make_unop(deref, arg.as_ty(format!("{cast} {to_ref_ty}"))).to_string()
diff --git a/src/tools/clippy/clippy_lints/src/transmute/transmute_ref_to_ref.rs b/src/tools/clippy/clippy_lints/src/transmute/transmute_ref_to_ref.rs
index 6aeb22d41a7..70c2a73ce6e 100644
--- a/src/tools/clippy/clippy_lints/src/transmute/transmute_ref_to_ref.rs
+++ b/src/tools/clippy/clippy_lints/src/transmute/transmute_ref_to_ref.rs
@@ -45,7 +45,9 @@ pub(super) fn check<'tcx>(
                 Applicability::MaybeIncorrect,
             );
             triggered = true;
-        } else if (cx.tcx.erase_and_anonymize_regions(from_ty) != cx.tcx.erase_and_anonymize_regions(to_ty)) && !const_context {
+        } else if (cx.tcx.erase_and_anonymize_regions(from_ty) != cx.tcx.erase_and_anonymize_regions(to_ty))
+            && !const_context
+        {
             span_lint_and_then(
                 cx,
                 TRANSMUTE_PTR_TO_PTR,
diff --git a/src/tools/clippy/clippy_lints/src/uninit_vec.rs b/src/tools/clippy/clippy_lints/src/uninit_vec.rs
index cee4a53f03c..51116b5eba9 100644
--- a/src/tools/clippy/clippy_lints/src/uninit_vec.rs
+++ b/src/tools/clippy/clippy_lints/src/uninit_vec.rs
@@ -1,4 +1,4 @@
-use clippy_utils::diagnostics::{span_lint, span_lint_and_then};
+use clippy_utils::diagnostics::{span_lint, span_lint_and_help};
 use clippy_utils::higher::{VecInitKind, get_vec_init_kind};
 use clippy_utils::ty::{is_type_diagnostic_item, is_uninit_value_valid_for_ty};
 use clippy_utils::{SpanlessEq, is_integer_literal, is_lint_allowed, path_to_local_id, peel_hir_expr_while, sym};
@@ -95,16 +95,13 @@ fn handle_uninit_vec_pair<'tcx>(
 
             // Check T of Vec<T>
             if !is_uninit_value_valid_for_ty(cx, args.type_at(0)) {
-                // FIXME: #7698, false positive of the internal lints
-                #[expect(clippy::collapsible_span_lint_calls)]
-                span_lint_and_then(
+                span_lint_and_help(
                     cx,
                     UNINIT_VEC,
                     vec![call_span, maybe_init_or_reserve.span],
                     "calling `set_len()` immediately after reserving a buffer creates uninitialized values",
-                    |diag| {
-                        diag.help("initialize the buffer or wrap the content in `MaybeUninit`");
-                    },
+                    None,
+                    "initialize the buffer or wrap the content in `MaybeUninit`",
                 );
             }
         } else {
diff --git a/src/tools/clippy/clippy_lints/src/unused_peekable.rs b/src/tools/clippy/clippy_lints/src/unused_peekable.rs
index 1f5351e32aa..5224b62e9fc 100644
--- a/src/tools/clippy/clippy_lints/src/unused_peekable.rs
+++ b/src/tools/clippy/clippy_lints/src/unused_peekable.rs
@@ -1,5 +1,5 @@
 use clippy_utils::diagnostics::span_lint_hir_and_then;
-use clippy_utils::ty::{is_type_diagnostic_item, peel_mid_ty_refs_is_mutable};
+use clippy_utils::ty::{is_type_diagnostic_item, peel_and_count_ty_refs};
 use clippy_utils::{fn_def_id, is_trait_method, path_to_local_id, peel_ref_operators, sym};
 use rustc_ast::Mutability;
 use rustc_hir::intravisit::{Visitor, walk_expr};
@@ -61,7 +61,7 @@ impl<'tcx> LateLintPass<'tcx> for UnusedPeekable {
                 && let Some(init) = local.init
                 && !init.span.from_expansion()
                 && let Some(ty) = cx.typeck_results().expr_ty_opt(init)
-                && let (ty, _, Mutability::Mut) = peel_mid_ty_refs_is_mutable(ty)
+                && let (ty, _, None | Some(Mutability::Mut)) = peel_and_count_ty_refs(ty)
                 && is_type_diagnostic_item(cx, ty, sym::IterPeekable)
             {
                 let mut vis = PeekableVisitor::new(cx, binding);
@@ -211,7 +211,7 @@ impl<'tcx> Visitor<'tcx> for PeekableVisitor<'_, 'tcx> {
 
 fn arg_is_mut_peekable(cx: &LateContext<'_>, arg: &Expr<'_>) -> bool {
     if let Some(ty) = cx.typeck_results().expr_ty_opt(arg)
-        && let (ty, _, Mutability::Mut) = peel_mid_ty_refs_is_mutable(ty)
+        && let (ty, _, None | Some(Mutability::Mut)) = peel_and_count_ty_refs(ty)
         && is_type_diagnostic_item(cx, ty, sym::IterPeekable)
     {
         true
diff --git a/src/tools/clippy/clippy_lints/src/unwrap.rs b/src/tools/clippy/clippy_lints/src/unwrap.rs
index 490da4f1e03..34dfe5b6546 100644
--- a/src/tools/clippy/clippy_lints/src/unwrap.rs
+++ b/src/tools/clippy/clippy_lints/src/unwrap.rs
@@ -292,6 +292,7 @@ impl<'tcx> Visitor<'tcx> for UnwrappableVariablesVisitor<'_, 'tcx> {
     fn visit_expr(&mut self, expr: &'tcx Expr<'_>) {
         // Shouldn't lint when `expr` is in macro.
         if expr.span.in_external_macro(self.cx.tcx.sess.source_map()) {
+            walk_expr(self, expr);
             return;
         }
         // Skip checking inside closures since they are visited through `Unwrap::check_fn()` already.
diff --git a/src/tools/clippy/clippy_lints/src/use_self.rs b/src/tools/clippy/clippy_lints/src/use_self.rs
index 8252e6d4869..9d5be922f43 100644
--- a/src/tools/clippy/clippy_lints/src/use_self.rs
+++ b/src/tools/clippy/clippy_lints/src/use_self.rs
@@ -2,20 +2,21 @@ use clippy_config::Conf;
 use clippy_utils::diagnostics::span_lint_and_sugg;
 use clippy_utils::is_from_proc_macro;
 use clippy_utils::msrvs::{self, Msrv};
-use clippy_utils::ty::{same_type_and_consts, ty_from_hir_ty};
+use clippy_utils::ty::{same_type_modulo_regions, ty_from_hir_ty};
 use rustc_data_structures::fx::FxHashSet;
 use rustc_errors::Applicability;
 use rustc_hir::def::{CtorOf, DefKind, Res};
 use rustc_hir::def_id::LocalDefId;
 use rustc_hir::intravisit::{InferKind, Visitor, VisitorExt, walk_ty};
 use rustc_hir::{
-    self as hir, AmbigArg, Expr, ExprKind, FnRetTy, FnSig, GenericArgsParentheses, GenericParam, GenericParamKind,
-    HirId, Impl, ImplItemKind, Item, ItemKind, Pat, PatExpr, PatExprKind, PatKind, Path, QPath, Ty, TyKind,
+    self as hir, AmbigArg, Expr, ExprKind, FnRetTy, FnSig, GenericArgsParentheses, GenericParamKind, HirId, Impl,
+    ImplItemKind, Item, ItemKind, Pat, PatExpr, PatExprKind, PatKind, Path, QPath, Ty, TyKind,
 };
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_middle::ty::Ty as MiddleTy;
 use rustc_session::impl_lint_pass;
 use rustc_span::Span;
+use std::iter;
 
 declare_clippy_lint! {
     /// ### What it does
@@ -101,17 +102,11 @@ impl<'tcx> LateLintPass<'tcx> for UseSelf {
             let types_to_skip = generics
                 .params
                 .iter()
-                .filter_map(|param| match param {
-                    GenericParam {
-                        kind:
-                            GenericParamKind::Const {
-                                ty: Ty { hir_id, .. }, ..
-                            },
-                        ..
-                    } => Some(*hir_id),
+                .filter_map(|param| match param.kind {
+                    GenericParamKind::Const { ty, .. } => Some(ty.hir_id),
                     _ => None,
                 })
-                .chain(std::iter::once(self_ty.hir_id))
+                .chain([self_ty.hir_id])
                 .collect();
             StackItem::Check {
                 impl_id: item.owner_id.def_id,
@@ -209,11 +204,11 @@ impl<'tcx> LateLintPass<'tcx> for UseSelf {
             && !types_to_skip.contains(&hir_ty.hir_id)
             && let ty = ty_from_hir_ty(cx, hir_ty.as_unambig_ty())
             && let impl_ty = cx.tcx.type_of(impl_id).instantiate_identity()
-            && same_type_and_consts(ty, impl_ty)
+            && same_type_modulo_regions(ty, impl_ty)
             // Ensure the type we encounter and the one from the impl have the same lifetime parameters. It may be that
-            // the lifetime parameters of `ty` are elided (`impl<'a> Foo<'a> { fn new() -> Self { Foo{..} } }`, in
+            // the lifetime parameters of `ty` are elided (`impl<'a> Foo<'a> { fn new() -> Self { Foo{..} } }`), in
             // which case we must still trigger the lint.
-            && (has_no_lifetime(ty) || same_lifetimes(ty, impl_ty))
+            && same_lifetimes(ty, impl_ty)
             && self.msrv.meets(cx, msrvs::TYPE_ALIAS_ENUM_VARIANTS)
         {
             span_lint(cx, hir_ty.span);
@@ -226,18 +221,16 @@ impl<'tcx> LateLintPass<'tcx> for UseSelf {
             && cx.typeck_results().expr_ty(expr) == cx.tcx.type_of(impl_id).instantiate_identity()
             && self.msrv.meets(cx, msrvs::TYPE_ALIAS_ENUM_VARIANTS)
         {
-        } else {
-            return;
-        }
-        match expr.kind {
-            ExprKind::Struct(QPath::Resolved(_, path), ..) => check_path(cx, path),
-            ExprKind::Call(fun, _) => {
-                if let ExprKind::Path(QPath::Resolved(_, path)) = fun.kind {
-                    check_path(cx, path);
-                }
-            },
-            ExprKind::Path(QPath::Resolved(_, path)) => check_path(cx, path),
-            _ => (),
+            match expr.kind {
+                ExprKind::Struct(QPath::Resolved(_, path), ..) => check_path(cx, path),
+                ExprKind::Call(fun, _) => {
+                    if let ExprKind::Path(QPath::Resolved(_, path)) = fun.kind {
+                        check_path(cx, path);
+                    }
+                },
+                ExprKind::Path(QPath::Resolved(_, path)) => check_path(cx, path),
+                _ => (),
+            }
         }
     }
 
@@ -307,36 +300,20 @@ fn lint_path_to_variant(cx: &LateContext<'_>, path: &Path<'_>) {
     }
 }
 
-/// Returns `true` if types `a` and `b` have the same lifetime parameters, otherwise returns
-/// `false`.
+/// Checks whether types `a` and `b` have the same lifetime parameters.
 ///
 /// This function does not check that types `a` and `b` are the same types.
 fn same_lifetimes<'tcx>(a: MiddleTy<'tcx>, b: MiddleTy<'tcx>) -> bool {
     use rustc_middle::ty::{Adt, GenericArgKind};
-    match (&a.kind(), &b.kind()) {
-        (&Adt(_, args_a), &Adt(_, args_b)) => {
-            args_a
-                .iter()
-                .zip(args_b.iter())
-                .all(|(arg_a, arg_b)| match (arg_a.kind(), arg_b.kind()) {
-                    // TODO: Handle inferred lifetimes
-                    (GenericArgKind::Lifetime(inner_a), GenericArgKind::Lifetime(inner_b)) => inner_a == inner_b,
-                    (GenericArgKind::Type(type_a), GenericArgKind::Type(type_b)) => same_lifetimes(type_a, type_b),
-                    _ => true,
-                })
+    match (a.kind(), b.kind()) {
+        (Adt(_, args_a), Adt(_, args_b)) => {
+            iter::zip(*args_a, *args_b).all(|(arg_a, arg_b)| match (arg_a.kind(), arg_b.kind()) {
+                // TODO: Handle inferred lifetimes
+                (GenericArgKind::Lifetime(inner_a), GenericArgKind::Lifetime(inner_b)) => inner_a == inner_b,
+                (GenericArgKind::Type(type_a), GenericArgKind::Type(type_b)) => same_lifetimes(type_a, type_b),
+                _ => true,
+            })
         },
         _ => a == b,
     }
 }
-
-/// Returns `true` if `ty` has no lifetime parameter, otherwise returns `false`.
-fn has_no_lifetime(ty: MiddleTy<'_>) -> bool {
-    use rustc_middle::ty::{Adt, GenericArgKind};
-    match ty.kind() {
-        &Adt(_, args) => !args
-            .iter()
-            // TODO: Handle inferred lifetimes
-            .any(|arg| matches!(arg.kind(), GenericArgKind::Lifetime(..))),
-        _ => true,
-    }
-}
diff --git a/src/tools/clippy/clippy_lints/src/useless_conversion.rs b/src/tools/clippy/clippy_lints/src/useless_conversion.rs
index e45f884cfcb..1b137017ecb 100644
--- a/src/tools/clippy/clippy_lints/src/useless_conversion.rs
+++ b/src/tools/clippy/clippy_lints/src/useless_conversion.rs
@@ -1,7 +1,7 @@
 use clippy_utils::diagnostics::{span_lint_and_help, span_lint_and_sugg, span_lint_and_then};
 use clippy_utils::source::{snippet, snippet_with_context};
 use clippy_utils::sugg::{DiagExt as _, Sugg};
-use clippy_utils::ty::{get_type_diagnostic_name, is_copy, is_type_diagnostic_item, same_type_and_consts};
+use clippy_utils::ty::{get_type_diagnostic_name, is_copy, is_type_diagnostic_item, same_type_modulo_regions};
 use clippy_utils::{
     get_parent_expr, is_inherent_method_call, is_trait_item, is_trait_method, is_ty_alias, path_to_local, sym,
 };
@@ -184,7 +184,7 @@ impl<'tcx> LateLintPass<'tcx> for UselessConversion {
                     && (is_trait_item(cx, arg, sym::Into) || is_trait_item(cx, arg, sym::From))
                     && let ty::FnDef(_, args) = cx.typeck_results().expr_ty(arg).kind()
                     && let &[from_ty, to_ty] = args.into_type_list(cx.tcx).as_slice()
-                    && same_type_and_consts(from_ty, to_ty)
+                    && same_type_modulo_regions(from_ty, to_ty)
                 {
                     span_lint_and_then(
                         cx,
@@ -207,7 +207,7 @@ impl<'tcx> LateLintPass<'tcx> for UselessConversion {
                 if is_trait_method(cx, e, sym::Into) && name.ident.name == sym::into {
                     let a = cx.typeck_results().expr_ty(e);
                     let b = cx.typeck_results().expr_ty(recv);
-                    if same_type_and_consts(a, b) {
+                    if same_type_modulo_regions(a, b) {
                         let mut app = Applicability::MachineApplicable;
                         let sugg = snippet_with_context(cx, recv.span, e.span.ctxt(), "<expr>", &mut app).0;
                         span_lint_and_sugg(
@@ -324,7 +324,7 @@ impl<'tcx> LateLintPass<'tcx> for UselessConversion {
                     // If the types are identical then .into_iter() can be removed, unless the type
                     // implements Copy, in which case .into_iter() returns a copy of the receiver and
                     // cannot be safely omitted.
-                    if same_type_and_consts(a, b) && !is_copy(cx, b) {
+                    if same_type_modulo_regions(a, b) && !is_copy(cx, b) {
                         // Below we check if the parent method call meets the following conditions:
                         // 1. First parameter is `&mut self` (requires mutable reference)
                         // 2. Second parameter implements the `FnMut` trait (e.g., Iterator::any)
@@ -371,7 +371,7 @@ impl<'tcx> LateLintPass<'tcx> for UselessConversion {
                     && is_type_diagnostic_item(cx, a, sym::Result)
                     && let ty::Adt(_, args) = a.kind()
                     && let Some(a_type) = args.types().next()
-                    && same_type_and_consts(a_type, b)
+                    && same_type_modulo_regions(a_type, b)
                 {
                     span_lint_and_help(
                         cx,
@@ -396,7 +396,7 @@ impl<'tcx> LateLintPass<'tcx> for UselessConversion {
                         && is_type_diagnostic_item(cx, a, sym::Result)
                         && let ty::Adt(_, args) = a.kind()
                         && let Some(a_type) = args.types().next()
-                        && same_type_and_consts(a_type, b)
+                        && same_type_modulo_regions(a_type, b)
                     {
                         let hint = format!("consider removing `{}()`", snippet(cx, path.span, "TryFrom::try_from"));
                         span_lint_and_help(
@@ -407,7 +407,7 @@ impl<'tcx> LateLintPass<'tcx> for UselessConversion {
                             None,
                             hint,
                         );
-                    } else if name == sym::from_fn && same_type_and_consts(a, b) {
+                    } else if name == sym::from_fn && same_type_modulo_regions(a, b) {
                         let mut app = Applicability::MachineApplicable;
                         let sugg = Sugg::hir_with_context(cx, arg, e.span.ctxt(), "<expr>", &mut app).maybe_paren();
                         let sugg_msg = format!("consider removing `{}()`", snippet(cx, path.span, "From::from"));
diff --git a/src/tools/clippy/clippy_utils/Cargo.toml b/src/tools/clippy/clippy_utils/Cargo.toml
index bdf7431f29f..d58b47bf6de 100644
--- a/src/tools/clippy/clippy_utils/Cargo.toml
+++ b/src/tools/clippy/clippy_utils/Cargo.toml
@@ -1,6 +1,6 @@
 [package]
 name = "clippy_utils"
-version = "0.1.91"
+version = "0.1.92"
 edition = "2024"
 description = "Helpful tools for writing lints, provided as they are used in Clippy"
 repository = "https://github.com/rust-lang/rust-clippy"
diff --git a/src/tools/clippy/clippy_utils/README.md b/src/tools/clippy/clippy_utils/README.md
index e01f563c49e..2c66fdc73f5 100644
--- a/src/tools/clippy/clippy_utils/README.md
+++ b/src/tools/clippy/clippy_utils/README.md
@@ -8,7 +8,7 @@ This crate is only guaranteed to build with this `nightly` toolchain:
 
 <!-- begin autogenerated nightly -->
 ```
-nightly-2025-09-04
+nightly-2025-09-18
 ```
 <!-- end autogenerated nightly -->
 
diff --git a/src/tools/clippy/clippy_utils/src/check_proc_macro.rs b/src/tools/clippy/clippy_utils/src/check_proc_macro.rs
index 1a25c90d735..948a7203402 100644
--- a/src/tools/clippy/clippy_utils/src/check_proc_macro.rs
+++ b/src/tools/clippy/clippy_utils/src/check_proc_macro.rs
@@ -13,20 +13,24 @@
 //! if the span is not from a `macro_rules` based macro.
 
 use rustc_abi::ExternAbi;
+use rustc_ast as ast;
 use rustc_ast::AttrStyle;
-use rustc_ast::ast::{AttrKind, Attribute, IntTy, LitIntType, LitKind, StrStyle, TraitObjectSyntax, UintTy};
+use rustc_ast::ast::{
+    AttrKind, Attribute, GenericArgs, IntTy, LitIntType, LitKind, StrStyle, TraitObjectSyntax, UintTy,
+};
 use rustc_ast::token::CommentKind;
 use rustc_hir::intravisit::FnKind;
 use rustc_hir::{
     Block, BlockCheckMode, Body, Closure, Destination, Expr, ExprKind, FieldDef, FnHeader, FnRetTy, HirId, Impl,
-    ImplItem, ImplItemImplKind, ImplItemKind, IsAuto, Item, ItemKind, Lit, LoopSource, MatchSource, MutTy, Node, Path, QPath, Safety,
-    TraitImplHeader, TraitItem, TraitItemKind, Ty, TyKind, UnOp, UnsafeSource, Variant, VariantData, YieldSource,
+    ImplItem, ImplItemImplKind, ImplItemKind, IsAuto, Item, ItemKind, Lit, LoopSource, MatchSource, MutTy, Node, Path,
+    QPath, Safety, TraitImplHeader, TraitItem, TraitItemKind, Ty, TyKind, UnOp, UnsafeSource, Variant, VariantData,
+    YieldSource,
 };
 use rustc_lint::{EarlyContext, LateContext, LintContext};
 use rustc_middle::ty::TyCtxt;
 use rustc_session::Session;
 use rustc_span::symbol::{Ident, kw};
-use rustc_span::{Span, Symbol};
+use rustc_span::{Span, Symbol, sym};
 
 /// The search pattern to look for. Used by `span_matches_pat`
 #[derive(Clone)]
@@ -289,7 +293,7 @@ fn impl_item_search_pat(item: &ImplItem<'_>) -> (Pat, Pat) {
         && !vis_span.is_empty()
     {
         start_pat = Pat::Str("pub");
-    };
+    }
     (start_pat, end_pat)
 }
 
@@ -321,14 +325,17 @@ fn fn_kind_pat(tcx: TyCtxt<'_>, kind: &FnKind<'_>, body: &Body<'_>, hir_id: HirI
     };
     match tcx.hir_node(hir_id) {
         Node::Item(Item { vis_span, .. })
-        | Node::ImplItem(ImplItem { impl_kind: ImplItemImplKind::Inherent { vis_span, .. }, .. }) => {
+        | Node::ImplItem(ImplItem {
+            impl_kind: ImplItemImplKind::Inherent { vis_span, .. },
+            ..
+        }) => {
             if !vis_span.is_empty() {
-                start_pat = Pat::Str("pub")
+                start_pat = Pat::Str("pub");
             }
         },
         Node::ImplItem(_) | Node::TraitItem(_) => {},
         _ => start_pat = Pat::Str(""),
-    };
+    }
     (start_pat, end_pat)
 }
 
@@ -403,6 +410,7 @@ fn ty_search_pat(ty: &Ty<'_>) -> (Pat, Pat) {
         TyKind::OpaqueDef(..) => (Pat::Str("impl"), Pat::Str("")),
         TyKind::Path(qpath) => qpath_search_pat(&qpath),
         TyKind::Infer(()) => (Pat::Str("_"), Pat::Str("_")),
+        TyKind::UnsafeBinder(binder_ty) => (Pat::Str("unsafe"), ty_search_pat(binder_ty.inner_ty).1),
         TyKind::TraitObject(_, tagged_ptr) if let TraitObjectSyntax::Dyn = tagged_ptr.tag() => {
             (Pat::Str("dyn"), Pat::Str(""))
         },
@@ -411,6 +419,127 @@ fn ty_search_pat(ty: &Ty<'_>) -> (Pat, Pat) {
     }
 }
 
+fn ast_ty_search_pat(ty: &ast::Ty) -> (Pat, Pat) {
+    use ast::{Extern, FnRetTy, MutTy, Safety, TraitObjectSyntax, TyKind};
+
+    match &ty.kind {
+        TyKind::Slice(..) | TyKind::Array(..) => (Pat::Str("["), Pat::Str("]")),
+        TyKind::Ptr(MutTy { ty, .. }) => (Pat::Str("*"), ast_ty_search_pat(ty).1),
+        TyKind::Ref(_, MutTy { ty, .. }) | TyKind::PinnedRef(_, MutTy { ty, .. }) => {
+            (Pat::Str("&"), ast_ty_search_pat(ty).1)
+        },
+        TyKind::FnPtr(fn_ptr) => (
+            if let Safety::Unsafe(_) = fn_ptr.safety {
+                Pat::Str("unsafe")
+            } else if let Extern::Explicit(strlit, _) = fn_ptr.ext
+                && strlit.symbol == sym::rust
+            {
+                Pat::MultiStr(&["fn", "extern"])
+            } else {
+                Pat::Str("extern")
+            },
+            match &fn_ptr.decl.output {
+                FnRetTy::Default(_) => {
+                    if let [.., param] = &*fn_ptr.decl.inputs {
+                        ast_ty_search_pat(&param.ty).1
+                    } else {
+                        Pat::Str("(")
+                    }
+                },
+                FnRetTy::Ty(ty) => ast_ty_search_pat(ty).1,
+            },
+        ),
+        TyKind::Never => (Pat::Str("!"), Pat::Str("!")),
+        // Parenthesis are trimmed from the text before the search patterns are matched.
+        // See: `span_matches_pat`
+        TyKind::Tup(tup) => match &**tup {
+            [] => (Pat::Str(")"), Pat::Str("(")),
+            [ty] => ast_ty_search_pat(ty),
+            [head, .., tail] => (ast_ty_search_pat(head).0, ast_ty_search_pat(tail).1),
+        },
+        TyKind::ImplTrait(..) => (Pat::Str("impl"), Pat::Str("")),
+        TyKind::Path(qself_path, path) => {
+            let start = if qself_path.is_some() {
+                Pat::Str("<")
+            } else if let Some(first) = path.segments.first() {
+                ident_search_pat(first.ident).0
+            } else {
+                // this shouldn't be possible, but sure
+                Pat::Str("")
+            };
+            let end = if let Some(last) = path.segments.last() {
+                match last.args.as_deref() {
+                    // last `>` in `std::foo::Bar<T>`
+                    Some(GenericArgs::AngleBracketed(_)) => Pat::Str(">"),
+                    Some(GenericArgs::Parenthesized(par_args)) => match &par_args.output {
+                        FnRetTy::Default(_) => {
+                            if let Some(last) = par_args.inputs.last() {
+                                // `B` in `(A, B)` -- `)` gets stripped
+                                ast_ty_search_pat(last).1
+                            } else {
+                                // `(` in `()` -- `)` gets stripped
+                                Pat::Str("(")
+                            }
+                        },
+                        // `C` in `(A, B) -> C`
+                        FnRetTy::Ty(ty) => ast_ty_search_pat(ty).1,
+                    },
+                    // last `..` in `(..)` -- `)` gets stripped
+                    Some(GenericArgs::ParenthesizedElided(_)) => Pat::Str(".."),
+                    // `bar` in `std::foo::bar`
+                    None => ident_search_pat(last.ident).1,
+                }
+            } else {
+                // this shouldn't be possible, but sure
+                #[allow(
+                    clippy::collapsible_else_if,
+                    reason = "we want to keep these cases together, since they are both impossible"
+                )]
+                if qself_path.is_some() {
+                    // last `>` in `<Vec as IntoIterator>`
+                    Pat::Str(">")
+                } else {
+                    Pat::Str("")
+                }
+            };
+            (start, end)
+        },
+        TyKind::Infer => (Pat::Str("_"), Pat::Str("_")),
+        TyKind::Paren(ty) => ast_ty_search_pat(ty),
+        TyKind::UnsafeBinder(binder_ty) => (Pat::Str("unsafe"), ast_ty_search_pat(&binder_ty.inner_ty).1),
+        TyKind::TraitObject(_, trait_obj_syntax) => {
+            if let TraitObjectSyntax::Dyn = trait_obj_syntax {
+                (Pat::Str("dyn"), Pat::Str(""))
+            } else {
+                // NOTE: `TraitObject` is incomplete. It will always return true then.
+                (Pat::Str(""), Pat::Str(""))
+            }
+        },
+        TyKind::MacCall(mac_call) => {
+            let start = if let Some(first) = mac_call.path.segments.first() {
+                ident_search_pat(first.ident).0
+            } else {
+                Pat::Str("")
+            };
+            (start, Pat::Str(""))
+        },
+
+        // implicit, so has no contents to match against
+        TyKind::ImplicitSelf
+
+        // experimental
+        |TyKind::Pat(..)
+
+        // unused
+        | TyKind::CVarArgs
+        | TyKind::Typeof(_)
+
+        // placeholder
+        | TyKind::Dummy
+        | TyKind::Err(_) => (Pat::Str(""), Pat::Str("")),
+    }
+}
+
 fn ident_search_pat(ident: Ident) -> (Pat, Pat) {
     (Pat::Sym(ident.name), Pat::Sym(ident.name))
 }
@@ -445,6 +574,7 @@ impl_with_search_pat!((_cx: LateContext<'tcx>, self: Lit) => lit_search_pat(&sel
 impl_with_search_pat!((_cx: LateContext<'tcx>, self: Path<'_>) => path_search_pat(self));
 
 impl_with_search_pat!((_cx: EarlyContext<'tcx>, self: Attribute) => attr_search_pat(self));
+impl_with_search_pat!((_cx: EarlyContext<'tcx>, self: ast::Ty) => ast_ty_search_pat(self));
 
 impl<'cx> WithSearchPat<'cx> for (&FnKind<'cx>, &Body<'cx>, HirId, Span) {
     type Context = LateContext<'cx>;
diff --git a/src/tools/clippy/clippy_utils/src/lib.rs b/src/tools/clippy/clippy_utils/src/lib.rs
index 120ab2e717d..feadc0ecf65 100644
--- a/src/tools/clippy/clippy_utils/src/lib.rs
+++ b/src/tools/clippy/clippy_utils/src/lib.rs
@@ -329,13 +329,17 @@ pub fn is_wild(pat: &Pat<'_>) -> bool {
     matches!(pat.kind, PatKind::Wild)
 }
 
-// Checks if arm has the form `None => None`
-pub fn is_none_arm(cx: &LateContext<'_>, arm: &Arm<'_>) -> bool {
-    matches!(
-        arm.pat.kind,
+/// Checks if the `pat` is `None`.
+pub fn is_none_pattern(cx: &LateContext<'_>, pat: &Pat<'_>) -> bool {
+    matches!(pat.kind,
         PatKind::Expr(PatExpr { kind: PatExprKind::Path(qpath), .. })
-            if is_res_lang_ctor(cx, cx.qpath_res(qpath, arm.pat.hir_id), OptionNone)
-    )
+            if is_res_lang_ctor(cx, cx.qpath_res(qpath, pat.hir_id), OptionNone))
+}
+
+/// Checks if `arm` has the form `None => None`.
+pub fn is_none_arm(cx: &LateContext<'_>, arm: &Arm<'_>) -> bool {
+    is_none_pattern(cx, arm.pat)
+        && matches!(peel_blocks(arm.body).kind, ExprKind::Path(qpath) if is_res_lang_ctor(cx, cx.qpath_res(&qpath, arm.body.hir_id), OptionNone))
 }
 
 /// Checks if the given `QPath` belongs to a type alias.
@@ -2374,15 +2378,12 @@ pub fn peel_hir_ty_refs<'a>(mut ty: &'a hir::Ty<'a>) -> (&'a hir::Ty<'a>, usize)
     }
 }
 
-/// Peels off all references on the type. Returns the underlying type and the number of references
-/// removed.
-pub fn peel_middle_ty_refs(mut ty: Ty<'_>) -> (Ty<'_>, usize) {
-    let mut count = 0;
-    while let rustc_ty::Ref(_, dest_ty, _) = ty.kind() {
-        ty = *dest_ty;
-        count += 1;
+/// Returns the base type for HIR references and pointers.
+pub fn peel_hir_ty_refs_and_ptrs<'tcx>(ty: &'tcx hir::Ty<'tcx>) -> &'tcx hir::Ty<'tcx> {
+    match &ty.kind {
+        TyKind::Ptr(mut_ty) | TyKind::Ref(_, mut_ty) => peel_hir_ty_refs_and_ptrs(mut_ty.ty),
+        _ => ty,
     }
-    (ty, count)
 }
 
 /// Removes `AddrOf` operators (`&`) or deref operators (`*`), but only if a reference type is
diff --git a/src/tools/clippy/clippy_utils/src/msrvs.rs b/src/tools/clippy/clippy_utils/src/msrvs.rs
index 896d607fbcd..6e07ed9ffcc 100644
--- a/src/tools/clippy/clippy_utils/src/msrvs.rs
+++ b/src/tools/clippy/clippy_utils/src/msrvs.rs
@@ -24,7 +24,7 @@ macro_rules! msrv_aliases {
 // names may refer to stabilized feature flags or library items
 msrv_aliases! {
     1,88,0 { LET_CHAINS }
-    1,87,0 { OS_STR_DISPLAY, INT_MIDPOINT, CONST_CHAR_IS_DIGIT, UNSIGNED_IS_MULTIPLE_OF }
+    1,87,0 { OS_STR_DISPLAY, INT_MIDPOINT, CONST_CHAR_IS_DIGIT, UNSIGNED_IS_MULTIPLE_OF, INTEGER_SIGN_CAST }
     1,85,0 { UINT_FLOAT_MIDPOINT, CONST_SIZE_OF_VAL }
     1,84,0 { CONST_OPTION_AS_SLICE, MANUAL_DANGLING_PTR }
     1,83,0 { CONST_EXTERN_FN, CONST_FLOAT_BITS_CONV, CONST_FLOAT_CLASSIFY, CONST_MUT_REFS, CONST_UNWRAP }
@@ -73,7 +73,7 @@ msrv_aliases! {
     1,29,0 { ITER_FLATTEN }
     1,28,0 { FROM_BOOL, REPEAT_WITH, SLICE_FROM_REF }
     1,27,0 { ITERATOR_TRY_FOLD }
-    1,26,0 { RANGE_INCLUSIVE, STRING_RETAIN }
+    1,26,0 { RANGE_INCLUSIVE, STRING_RETAIN, POINTER_ADD_SUB_METHODS }
     1,24,0 { IS_ASCII_DIGIT, PTR_NULL }
     1,18,0 { HASH_MAP_RETAIN, HASH_SET_RETAIN }
     1,17,0 { FIELD_INIT_SHORTHAND, STATIC_IN_CONST, EXPECT_ERR }
diff --git a/src/tools/clippy/clippy_utils/src/source.rs b/src/tools/clippy/clippy_utils/src/source.rs
index e675291b6f3..638d3290312 100644
--- a/src/tools/clippy/clippy_utils/src/source.rs
+++ b/src/tools/clippy/clippy_utils/src/source.rs
@@ -215,6 +215,11 @@ impl fmt::Display for SourceText {
         self.as_str().fmt(f)
     }
 }
+impl fmt::Debug for SourceText {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        self.as_str().fmt(f)
+    }
+}
 
 fn get_source_range(sm: &SourceMap, sp: Range<BytePos>) -> Option<SourceFileRange> {
     let start = sm.lookup_byte_offset(sp.start);
diff --git a/src/tools/clippy/clippy_utils/src/sym.rs b/src/tools/clippy/clippy_utils/src/sym.rs
index 8033b74a8d2..7530d3bc715 100644
--- a/src/tools/clippy/clippy_utils/src/sym.rs
+++ b/src/tools/clippy/clippy_utils/src/sym.rs
@@ -125,6 +125,7 @@ generate! {
     cycle,
     cyclomatic_complexity,
     de,
+    deprecated_in_future,
     diagnostics,
     disallowed_types,
     drain,
diff --git a/src/tools/clippy/clippy_utils/src/ty/mod.rs b/src/tools/clippy/clippy_utils/src/ty/mod.rs
index 3e41bce1dc4..e4bc3b76829 100644
--- a/src/tools/clippy/clippy_utils/src/ty/mod.rs
+++ b/src/tools/clippy/clippy_utils/src/ty/mod.rs
@@ -11,7 +11,7 @@ use rustc_hir as hir;
 use rustc_hir::attrs::AttributeKind;
 use rustc_hir::def::{CtorKind, CtorOf, DefKind, Res};
 use rustc_hir::def_id::DefId;
-use rustc_hir::{Expr, FnDecl, LangItem, TyKind, find_attr};
+use rustc_hir::{Expr, FnDecl, LangItem, find_attr};
 use rustc_hir_analysis::lower_ty;
 use rustc_infer::infer::TyCtxtInferExt;
 use rustc_lint::LateContext;
@@ -43,13 +43,8 @@ pub use type_certainty::expr_type_is_certain;
 /// Lower a [`hir::Ty`] to a [`rustc_middle::ty::Ty`].
 pub fn ty_from_hir_ty<'tcx>(cx: &LateContext<'tcx>, hir_ty: &hir::Ty<'tcx>) -> Ty<'tcx> {
     cx.maybe_typeck_results()
-        .and_then(|results| {
-            if results.hir_owner == hir_ty.hir_id.owner {
-                results.node_type_opt(hir_ty.hir_id)
-            } else {
-                None
-            }
-        })
+        .filter(|results| results.hir_owner == hir_ty.hir_id.owner)
+        .and_then(|results| results.node_type_opt(hir_ty.hir_id))
         .unwrap_or_else(|| lower_ty(cx.tcx, hir_ty))
 }
 
@@ -475,63 +470,50 @@ pub fn needs_ordered_drop<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool {
     needs_ordered_drop_inner(cx, ty, &mut FxHashSet::default())
 }
 
-/// Peels off all references on the type. Returns the underlying type, the number of references
-/// removed, and whether the pointer is ultimately mutable or not.
-pub fn peel_mid_ty_refs_is_mutable(ty: Ty<'_>) -> (Ty<'_>, usize, Mutability) {
-    fn f(ty: Ty<'_>, count: usize, mutability: Mutability) -> (Ty<'_>, usize, Mutability) {
-        match ty.kind() {
-            ty::Ref(_, ty, Mutability::Mut) => f(*ty, count + 1, mutability),
-            ty::Ref(_, ty, Mutability::Not) => f(*ty, count + 1, Mutability::Not),
-            _ => (ty, count, mutability),
-        }
-    }
-    f(ty, 0, Mutability::Mut)
-}
-
-/// Returns `true` if the given type is an `unsafe` function.
-pub fn type_is_unsafe_function<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool {
+/// Returns `true` if `ty` denotes an `unsafe fn`.
+pub fn is_unsafe_fn<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool {
     ty.is_fn() && ty.fn_sig(cx.tcx).safety().is_unsafe()
 }
 
-/// Returns the base type for HIR references and pointers.
-pub fn walk_ptrs_hir_ty<'tcx>(ty: &'tcx hir::Ty<'tcx>) -> &'tcx hir::Ty<'tcx> {
-    match ty.kind {
-        TyKind::Ptr(ref mut_ty) | TyKind::Ref(_, ref mut_ty) => walk_ptrs_hir_ty(mut_ty.ty),
-        _ => ty,
-    }
-}
-
-/// Returns the base type for references and raw pointers, and count reference
-/// depth.
-pub fn walk_ptrs_ty_depth(ty: Ty<'_>) -> (Ty<'_>, usize) {
-    fn inner(ty: Ty<'_>, depth: usize) -> (Ty<'_>, usize) {
-        match ty.kind() {
-            ty::Ref(_, ty, _) => inner(*ty, depth + 1),
-            _ => (ty, depth),
-        }
+/// Peels off all references on the type. Returns the underlying type, the number of references
+/// removed, and, if there were any such references, whether the pointer is ultimately mutable or
+/// not.
+pub fn peel_and_count_ty_refs(mut ty: Ty<'_>) -> (Ty<'_>, usize, Option<Mutability>) {
+    let mut count = 0;
+    let mut mutbl = None;
+    while let ty::Ref(_, dest_ty, m) = ty.kind() {
+        ty = *dest_ty;
+        count += 1;
+        mutbl.replace(mutbl.map_or(*m, |mutbl: Mutability| mutbl.min(*m)));
     }
-    inner(ty, 0)
+    (ty, count, mutbl)
 }
 
-/// Returns `true` if types `a` and `b` are same types having same `Const` generic args,
-/// otherwise returns `false`
-pub fn same_type_and_consts<'tcx>(a: Ty<'tcx>, b: Ty<'tcx>) -> bool {
+/// Checks whether `a` and `b` are same types having same `Const` generic args, but ignores
+/// lifetimes.
+///
+/// For example, the function would return `true` for
+/// - `u32` and `u32`
+/// - `[u8; N]` and `[u8; M]`, if `N=M`
+/// - `Option<T>` and `Option<U>`, if `same_type_modulo_regions(T, U)` holds
+/// - `&'a str` and `&'b str`
+///
+/// and `false` for:
+/// - `Result<u32, String>` and `Result<usize, String>`
+pub fn same_type_modulo_regions<'tcx>(a: Ty<'tcx>, b: Ty<'tcx>) -> bool {
     match (&a.kind(), &b.kind()) {
         (&ty::Adt(did_a, args_a), &ty::Adt(did_b, args_b)) => {
             if did_a != did_b {
                 return false;
             }
 
-            args_a
-                .iter()
-                .zip(args_b.iter())
-                .all(|(arg_a, arg_b)| match (arg_a.kind(), arg_b.kind()) {
-                    (GenericArgKind::Const(inner_a), GenericArgKind::Const(inner_b)) => inner_a == inner_b,
-                    (GenericArgKind::Type(type_a), GenericArgKind::Type(type_b)) => {
-                        same_type_and_consts(type_a, type_b)
-                    },
-                    _ => true,
-                })
+            iter::zip(*args_a, *args_b).all(|(arg_a, arg_b)| match (arg_a.kind(), arg_b.kind()) {
+                (GenericArgKind::Const(inner_a), GenericArgKind::Const(inner_b)) => inner_a == inner_b,
+                (GenericArgKind::Type(type_a), GenericArgKind::Type(type_b)) => {
+                    same_type_modulo_regions(type_a, type_b)
+                },
+                _ => true,
+            })
         },
         _ => a == b,
     }
diff --git a/src/tools/clippy/declare_clippy_lint/Cargo.toml b/src/tools/clippy/declare_clippy_lint/Cargo.toml
index ec0e59e7054..4de7b5fb592 100644
--- a/src/tools/clippy/declare_clippy_lint/Cargo.toml
+++ b/src/tools/clippy/declare_clippy_lint/Cargo.toml
@@ -1,6 +1,6 @@
 [package]
 name = "declare_clippy_lint"
-version = "0.1.91"
+version = "0.1.92"
 edition = "2024"
 repository = "https://github.com/rust-lang/rust-clippy"
 license = "MIT OR Apache-2.0"
diff --git a/src/tools/clippy/rust-toolchain.toml b/src/tools/clippy/rust-toolchain.toml
index ec2f24a0a6d..9c102de4482 100644
--- a/src/tools/clippy/rust-toolchain.toml
+++ b/src/tools/clippy/rust-toolchain.toml
@@ -1,6 +1,6 @@
 [toolchain]
 # begin autogenerated nightly
-channel = "nightly-2025-09-04"
+channel = "nightly-2025-09-18"
 # end autogenerated nightly
 components = ["cargo", "llvm-tools", "rust-src", "rust-std", "rustc", "rustc-dev", "rustfmt"]
 profile = "minimal"
diff --git a/src/tools/clippy/tests/no-profile-in-cargo-toml.rs b/src/tools/clippy/tests/no-profile-in-cargo-toml.rs
index 2ad9bfb75de..1f8c4fae9b3 100644
--- a/src/tools/clippy/tests/no-profile-in-cargo-toml.rs
+++ b/src/tools/clippy/tests/no-profile-in-cargo-toml.rs
@@ -17,6 +17,9 @@ fn no_profile_in_cargo_toml() {
     // keep it fast and simple.
     for entry in WalkDir::new(".")
         .into_iter()
+        // Do not recurse into `target` as lintcheck might put some sources (and their
+        //  `Cargo.toml`) there.
+        .filter_entry(|e| e.file_name() != "target")
         .filter_map(Result::ok)
         .filter(|e| e.file_name().to_str() == Some("Cargo.toml"))
     {
diff --git a/src/tools/clippy/tests/ui/ref_option/all/clippy.toml b/src/tools/clippy/tests/ui-toml/ref_option/all/clippy.toml
index cda8d17eed4..cda8d17eed4 100644
--- a/src/tools/clippy/tests/ui/ref_option/all/clippy.toml
+++ b/src/tools/clippy/tests/ui-toml/ref_option/all/clippy.toml
diff --git a/src/tools/clippy/tests/ui/ref_option/private/clippy.toml b/src/tools/clippy/tests/ui-toml/ref_option/private/clippy.toml
index 5f304987aa9..5f304987aa9 100644
--- a/src/tools/clippy/tests/ui/ref_option/private/clippy.toml
+++ b/src/tools/clippy/tests/ui-toml/ref_option/private/clippy.toml
diff --git a/src/tools/clippy/tests/ui-toml/ref_option/ref_option.all.fixed b/src/tools/clippy/tests/ui-toml/ref_option/ref_option.all.fixed
new file mode 100644
index 00000000000..f8f097e9a75
--- /dev/null
+++ b/src/tools/clippy/tests/ui-toml/ref_option/ref_option.all.fixed
@@ -0,0 +1,114 @@
+//@aux-build:../../ui/auxiliary/proc_macros.rs
+//@revisions: private all
+//@[private] rustc-env:CLIPPY_CONF_DIR=tests/ui-toml/ref_option/private
+//@[all] rustc-env:CLIPPY_CONF_DIR=tests/ui-toml/ref_option/all
+
+#![allow(unused, clippy::needless_lifetimes, clippy::borrowed_box)]
+#![warn(clippy::ref_option)]
+
+fn opt_u8(a: Option<&u8>) {}
+//~^ ref_option
+fn opt_gen<T>(a: Option<&T>) {}
+//~^ ref_option
+fn opt_string(a: std::option::Option<&String>) {}
+//~^ ref_option
+fn ret_u8<'a>(p: &'a str) -> Option<&'a u8> {
+    //~^ ref_option
+    panic!()
+}
+fn ret_u8_static() -> Option<&'static u8> {
+    //~^ ref_option
+    panic!()
+}
+fn mult_string(a: Option<&String>, b: Option<&Vec<u8>>) {}
+//~^ ref_option
+fn ret_box<'a>() -> Option<&'a Box<u8>> {
+    //~^ ref_option
+    panic!()
+}
+
+pub fn pub_opt_string(a: Option<&String>) {}
+//~[all]^ ref_option
+pub fn pub_mult_string(a: Option<&String>, b: Option<&Vec<u8>>) {}
+//~[all]^ ref_option
+
+pub struct PubStruct;
+
+impl PubStruct {
+    pub fn pub_opt_params(&self, a: Option<&()>) {}
+    //~[all]^ ref_option
+    pub fn pub_opt_ret(&self) -> Option<&String> {
+        //~[all]^ ref_option
+        panic!()
+    }
+
+    fn private_opt_params(&self, a: Option<&()>) {}
+    //~^ ref_option
+    fn private_opt_ret(&self) -> Option<&String> {
+        //~^ ref_option
+        panic!()
+    }
+}
+
+// valid, don't change
+fn mut_u8(a: &mut Option<u8>) {}
+pub fn pub_mut_u8(a: &mut Option<String>) {}
+
+// might be good to catch in the future
+fn mut_u8_ref(a: &mut &Option<u8>) {}
+pub fn pub_mut_u8_ref(a: &mut &Option<String>) {}
+fn lambdas() {
+    // Not handled for now, not sure if we should
+    let x = |a: &Option<String>| {};
+    let x = |a: &Option<String>| -> &Option<String> { panic!() };
+}
+
+pub mod external {
+    proc_macros::external!(
+        fn opt_u8(a: &Option<u8>) {}
+        fn ret_u8<'a>(p: &'a str) -> &'a Option<u8> {
+            panic!()
+        }
+        pub fn pub_opt_u8(a: &Option<u8>) {}
+
+        pub struct PubStruct;
+        impl PubStruct {
+            pub fn pub_opt_params(&self, a: &Option<()>) {}
+            pub fn pub_opt_ret(&self) -> &Option<String> {
+                panic!()
+            }
+
+            fn private_opt_params(&self, a: &Option<()>) {}
+            fn private_opt_ret(&self) -> &Option<String> {
+                panic!()
+            }
+        }
+    );
+}
+
+pub mod proc_macros {
+    proc_macros::with_span!(
+        span
+
+        fn opt_u8(a: &Option<u8>) {}
+        fn ret_u8<'a>(p: &'a str) -> &'a Option<u8> {
+            panic!()
+        }
+        pub fn pub_opt_u8(a: &Option<u8>) {}
+
+        pub struct PubStruct;
+        impl PubStruct {
+            pub fn pub_opt_params(&self, a: &Option<()>) {}
+            pub fn pub_opt_ret(&self) -> &Option<String> {
+                panic!()
+            }
+
+            fn private_opt_params(&self, a: &Option<()>) {}
+            fn private_opt_ret(&self) -> &Option<String> {
+                panic!()
+            }
+        }
+    );
+}
+
+fn main() {}
diff --git a/src/tools/clippy/tests/ui/ref_option/ref_option.all.stderr b/src/tools/clippy/tests/ui-toml/ref_option/ref_option.all.stderr
index bd43c28336e..45ce105e030 100644
--- a/src/tools/clippy/tests/ui/ref_option/ref_option.all.stderr
+++ b/src/tools/clippy/tests/ui-toml/ref_option/ref_option.all.stderr
@@ -1,5 +1,5 @@
 error: it is more idiomatic to use `Option<&T>` instead of `&Option<T>`
-  --> tests/ui/ref_option/ref_option.rs:8:1
+  --> tests/ui-toml/ref_option/ref_option.rs:9:1
    |
 LL | fn opt_u8(a: &Option<u8>) {}
    | ^^^^^^^^^^^^^-----------^^^^
@@ -10,7 +10,7 @@ LL | fn opt_u8(a: &Option<u8>) {}
    = help: to override `-D warnings` add `#[allow(clippy::ref_option)]`
 
 error: it is more idiomatic to use `Option<&T>` instead of `&Option<T>`
-  --> tests/ui/ref_option/ref_option.rs:10:1
+  --> tests/ui-toml/ref_option/ref_option.rs:11:1
    |
 LL | fn opt_gen<T>(a: &Option<T>) {}
    | ^^^^^^^^^^^^^^^^^----------^^^^
@@ -18,7 +18,7 @@ LL | fn opt_gen<T>(a: &Option<T>) {}
    |                  help: change this to: `Option<&T>`
 
 error: it is more idiomatic to use `Option<&T>` instead of `&Option<T>`
-  --> tests/ui/ref_option/ref_option.rs:12:1
+  --> tests/ui-toml/ref_option/ref_option.rs:13:1
    |
 LL | fn opt_string(a: &std::option::Option<String>) {}
    | ^^^^^^^^^^^^^^^^^----------------------------^^^^
@@ -26,10 +26,10 @@ LL | fn opt_string(a: &std::option::Option<String>) {}
    |                  help: change this to: `std::option::Option<&String>`
 
 error: it is more idiomatic to use `Option<&T>` instead of `&Option<T>`
-  --> tests/ui/ref_option/ref_option.rs:14:1
+  --> tests/ui-toml/ref_option/ref_option.rs:15:1
    |
-LL |   fn ret_string<'a>(p: &'a str) -> &'a Option<u8> {
-   |   ^                                -------------- help: change this to: `Option<&'a u8>`
+LL |   fn ret_u8<'a>(p: &'a str) -> &'a Option<u8> {
+   |   ^                            -------------- help: change this to: `Option<&'a u8>`
    |  _|
    | |
 LL | |
@@ -38,10 +38,10 @@ LL | | }
    | |_^
 
 error: it is more idiomatic to use `Option<&T>` instead of `&Option<T>`
-  --> tests/ui/ref_option/ref_option.rs:18:1
+  --> tests/ui-toml/ref_option/ref_option.rs:19:1
    |
-LL |   fn ret_string_static() -> &'static Option<u8> {
-   |   ^                         ------------------- help: change this to: `Option<&'static u8>`
+LL |   fn ret_u8_static() -> &'static Option<u8> {
+   |   ^                     ------------------- help: change this to: `Option<&'static u8>`
    |  _|
    | |
 LL | |
@@ -50,7 +50,7 @@ LL | | }
    | |_^
 
 error: it is more idiomatic to use `Option<&T>` instead of `&Option<T>`
-  --> tests/ui/ref_option/ref_option.rs:22:1
+  --> tests/ui-toml/ref_option/ref_option.rs:23:1
    |
 LL | fn mult_string(a: &Option<String>, b: &Option<Vec<u8>>) {}
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -62,7 +62,7 @@ LL + fn mult_string(a: Option<&String>, b: Option<&Vec<u8>>) {}
    |
 
 error: it is more idiomatic to use `Option<&T>` instead of `&Option<T>`
-  --> tests/ui/ref_option/ref_option.rs:24:1
+  --> tests/ui-toml/ref_option/ref_option.rs:25:1
    |
 LL |   fn ret_box<'a>() -> &'a Option<Box<u8>> {
    |   ^                   ------------------- help: change this to: `Option<&'a Box<u8>>`
@@ -74,7 +74,7 @@ LL | | }
    | |_^
 
 error: it is more idiomatic to use `Option<&T>` instead of `&Option<T>`
-  --> tests/ui/ref_option/ref_option.rs:29:1
+  --> tests/ui-toml/ref_option/ref_option.rs:30:1
    |
 LL | pub fn pub_opt_string(a: &Option<String>) {}
    | ^^^^^^^^^^^^^^^^^^^^^^^^^---------------^^^^
@@ -82,7 +82,7 @@ LL | pub fn pub_opt_string(a: &Option<String>) {}
    |                          help: change this to: `Option<&String>`
 
 error: it is more idiomatic to use `Option<&T>` instead of `&Option<T>`
-  --> tests/ui/ref_option/ref_option.rs:31:1
+  --> tests/ui-toml/ref_option/ref_option.rs:32:1
    |
 LL | pub fn pub_mult_string(a: &Option<String>, b: &Option<Vec<u8>>) {}
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -94,39 +94,7 @@ LL + pub fn pub_mult_string(a: Option<&String>, b: Option<&Vec<u8>>) {}
    |
 
 error: it is more idiomatic to use `Option<&T>` instead of `&Option<T>`
-  --> tests/ui/ref_option/ref_option.rs:35:5
-   |
-LL |     fn pub_trait_opt(&self, a: &Option<Vec<u8>>);
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^----------------^^
-   |                                |
-   |                                help: change this to: `Option<&Vec<u8>>`
-
-error: it is more idiomatic to use `Option<&T>` instead of `&Option<T>`
-  --> tests/ui/ref_option/ref_option.rs:37:5
-   |
-LL |     fn pub_trait_ret(&self) -> &Option<Vec<u8>>;
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^----------------^
-   |                                |
-   |                                help: change this to: `Option<&Vec<u8>>`
-
-error: it is more idiomatic to use `Option<&T>` instead of `&Option<T>`
-  --> tests/ui/ref_option/ref_option.rs:42:5
-   |
-LL |     fn trait_opt(&self, a: &Option<String>);
-   |     ^^^^^^^^^^^^^^^^^^^^^^^---------------^^
-   |                            |
-   |                            help: change this to: `Option<&String>`
-
-error: it is more idiomatic to use `Option<&T>` instead of `&Option<T>`
-  --> tests/ui/ref_option/ref_option.rs:44:5
-   |
-LL |     fn trait_ret(&self) -> &Option<String>;
-   |     ^^^^^^^^^^^^^^^^^^^^^^^---------------^
-   |                            |
-   |                            help: change this to: `Option<&String>`
-
-error: it is more idiomatic to use `Option<&T>` instead of `&Option<T>`
-  --> tests/ui/ref_option/ref_option.rs:51:5
+  --> tests/ui-toml/ref_option/ref_option.rs:38:5
    |
 LL |     pub fn pub_opt_params(&self, a: &Option<()>) {}
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-----------^^^^
@@ -134,7 +102,7 @@ LL |     pub fn pub_opt_params(&self, a: &Option<()>) {}
    |                                     help: change this to: `Option<&()>`
 
 error: it is more idiomatic to use `Option<&T>` instead of `&Option<T>`
-  --> tests/ui/ref_option/ref_option.rs:53:5
+  --> tests/ui-toml/ref_option/ref_option.rs:40:5
    |
 LL |       pub fn pub_opt_ret(&self) -> &Option<String> {
    |       ^                            --------------- help: change this to: `Option<&String>`
@@ -146,7 +114,7 @@ LL | |     }
    | |_____^
 
 error: it is more idiomatic to use `Option<&T>` instead of `&Option<T>`
-  --> tests/ui/ref_option/ref_option.rs:58:5
+  --> tests/ui-toml/ref_option/ref_option.rs:45:5
    |
 LL |     fn private_opt_params(&self, a: &Option<()>) {}
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-----------^^^^
@@ -154,7 +122,7 @@ LL |     fn private_opt_params(&self, a: &Option<()>) {}
    |                                     help: change this to: `Option<&()>`
 
 error: it is more idiomatic to use `Option<&T>` instead of `&Option<T>`
-  --> tests/ui/ref_option/ref_option.rs:60:5
+  --> tests/ui-toml/ref_option/ref_option.rs:47:5
    |
 LL |       fn private_opt_ret(&self) -> &Option<String> {
    |       ^                            --------------- help: change this to: `Option<&String>`
@@ -165,5 +133,5 @@ LL | |         panic!()
 LL | |     }
    | |_____^
 
-error: aborting due to 17 previous errors
+error: aborting due to 13 previous errors
 
diff --git a/src/tools/clippy/tests/ui-toml/ref_option/ref_option.private.fixed b/src/tools/clippy/tests/ui-toml/ref_option/ref_option.private.fixed
new file mode 100644
index 00000000000..4dd14a82206
--- /dev/null
+++ b/src/tools/clippy/tests/ui-toml/ref_option/ref_option.private.fixed
@@ -0,0 +1,114 @@
+//@aux-build:../../ui/auxiliary/proc_macros.rs
+//@revisions: private all
+//@[private] rustc-env:CLIPPY_CONF_DIR=tests/ui-toml/ref_option/private
+//@[all] rustc-env:CLIPPY_CONF_DIR=tests/ui-toml/ref_option/all
+
+#![allow(unused, clippy::needless_lifetimes, clippy::borrowed_box)]
+#![warn(clippy::ref_option)]
+
+fn opt_u8(a: Option<&u8>) {}
+//~^ ref_option
+fn opt_gen<T>(a: Option<&T>) {}
+//~^ ref_option
+fn opt_string(a: std::option::Option<&String>) {}
+//~^ ref_option
+fn ret_u8<'a>(p: &'a str) -> Option<&'a u8> {
+    //~^ ref_option
+    panic!()
+}
+fn ret_u8_static() -> Option<&'static u8> {
+    //~^ ref_option
+    panic!()
+}
+fn mult_string(a: Option<&String>, b: Option<&Vec<u8>>) {}
+//~^ ref_option
+fn ret_box<'a>() -> Option<&'a Box<u8>> {
+    //~^ ref_option
+    panic!()
+}
+
+pub fn pub_opt_string(a: &Option<String>) {}
+//~[all]^ ref_option
+pub fn pub_mult_string(a: &Option<String>, b: &Option<Vec<u8>>) {}
+//~[all]^ ref_option
+
+pub struct PubStruct;
+
+impl PubStruct {
+    pub fn pub_opt_params(&self, a: &Option<()>) {}
+    //~[all]^ ref_option
+    pub fn pub_opt_ret(&self) -> &Option<String> {
+        //~[all]^ ref_option
+        panic!()
+    }
+
+    fn private_opt_params(&self, a: Option<&()>) {}
+    //~^ ref_option
+    fn private_opt_ret(&self) -> Option<&String> {
+        //~^ ref_option
+        panic!()
+    }
+}
+
+// valid, don't change
+fn mut_u8(a: &mut Option<u8>) {}
+pub fn pub_mut_u8(a: &mut Option<String>) {}
+
+// might be good to catch in the future
+fn mut_u8_ref(a: &mut &Option<u8>) {}
+pub fn pub_mut_u8_ref(a: &mut &Option<String>) {}
+fn lambdas() {
+    // Not handled for now, not sure if we should
+    let x = |a: &Option<String>| {};
+    let x = |a: &Option<String>| -> &Option<String> { panic!() };
+}
+
+pub mod external {
+    proc_macros::external!(
+        fn opt_u8(a: &Option<u8>) {}
+        fn ret_u8<'a>(p: &'a str) -> &'a Option<u8> {
+            panic!()
+        }
+        pub fn pub_opt_u8(a: &Option<u8>) {}
+
+        pub struct PubStruct;
+        impl PubStruct {
+            pub fn pub_opt_params(&self, a: &Option<()>) {}
+            pub fn pub_opt_ret(&self) -> &Option<String> {
+                panic!()
+            }
+
+            fn private_opt_params(&self, a: &Option<()>) {}
+            fn private_opt_ret(&self) -> &Option<String> {
+                panic!()
+            }
+        }
+    );
+}
+
+pub mod proc_macros {
+    proc_macros::with_span!(
+        span
+
+        fn opt_u8(a: &Option<u8>) {}
+        fn ret_u8<'a>(p: &'a str) -> &'a Option<u8> {
+            panic!()
+        }
+        pub fn pub_opt_u8(a: &Option<u8>) {}
+
+        pub struct PubStruct;
+        impl PubStruct {
+            pub fn pub_opt_params(&self, a: &Option<()>) {}
+            pub fn pub_opt_ret(&self) -> &Option<String> {
+                panic!()
+            }
+
+            fn private_opt_params(&self, a: &Option<()>) {}
+            fn private_opt_ret(&self) -> &Option<String> {
+                panic!()
+            }
+        }
+    );
+}
+
+fn main() {}
diff --git a/src/tools/clippy/tests/ui/ref_option/ref_option.private.stderr b/src/tools/clippy/tests/ui-toml/ref_option/ref_option.private.stderr
index 88c65e429d8..a63efd60a03 100644
--- a/src/tools/clippy/tests/ui/ref_option/ref_option.private.stderr
+++ b/src/tools/clippy/tests/ui-toml/ref_option/ref_option.private.stderr
@@ -1,5 +1,5 @@
 error: it is more idiomatic to use `Option<&T>` instead of `&Option<T>`
-  --> tests/ui/ref_option/ref_option.rs:8:1
+  --> tests/ui-toml/ref_option/ref_option.rs:9:1
    |
 LL | fn opt_u8(a: &Option<u8>) {}
    | ^^^^^^^^^^^^^-----------^^^^
@@ -10,7 +10,7 @@ LL | fn opt_u8(a: &Option<u8>) {}
    = help: to override `-D warnings` add `#[allow(clippy::ref_option)]`
 
 error: it is more idiomatic to use `Option<&T>` instead of `&Option<T>`
-  --> tests/ui/ref_option/ref_option.rs:10:1
+  --> tests/ui-toml/ref_option/ref_option.rs:11:1
    |
 LL | fn opt_gen<T>(a: &Option<T>) {}
    | ^^^^^^^^^^^^^^^^^----------^^^^
@@ -18,7 +18,7 @@ LL | fn opt_gen<T>(a: &Option<T>) {}
    |                  help: change this to: `Option<&T>`
 
 error: it is more idiomatic to use `Option<&T>` instead of `&Option<T>`
-  --> tests/ui/ref_option/ref_option.rs:12:1
+  --> tests/ui-toml/ref_option/ref_option.rs:13:1
    |
 LL | fn opt_string(a: &std::option::Option<String>) {}
    | ^^^^^^^^^^^^^^^^^----------------------------^^^^
@@ -26,10 +26,10 @@ LL | fn opt_string(a: &std::option::Option<String>) {}
    |                  help: change this to: `std::option::Option<&String>`
 
 error: it is more idiomatic to use `Option<&T>` instead of `&Option<T>`
-  --> tests/ui/ref_option/ref_option.rs:14:1
+  --> tests/ui-toml/ref_option/ref_option.rs:15:1
    |
-LL |   fn ret_string<'a>(p: &'a str) -> &'a Option<u8> {
-   |   ^                                -------------- help: change this to: `Option<&'a u8>`
+LL |   fn ret_u8<'a>(p: &'a str) -> &'a Option<u8> {
+   |   ^                            -------------- help: change this to: `Option<&'a u8>`
    |  _|
    | |
 LL | |
@@ -38,10 +38,10 @@ LL | | }
    | |_^
 
 error: it is more idiomatic to use `Option<&T>` instead of `&Option<T>`
-  --> tests/ui/ref_option/ref_option.rs:18:1
+  --> tests/ui-toml/ref_option/ref_option.rs:19:1
    |
-LL |   fn ret_string_static() -> &'static Option<u8> {
-   |   ^                         ------------------- help: change this to: `Option<&'static u8>`
+LL |   fn ret_u8_static() -> &'static Option<u8> {
+   |   ^                     ------------------- help: change this to: `Option<&'static u8>`
    |  _|
    | |
 LL | |
@@ -50,7 +50,7 @@ LL | | }
    | |_^
 
 error: it is more idiomatic to use `Option<&T>` instead of `&Option<T>`
-  --> tests/ui/ref_option/ref_option.rs:22:1
+  --> tests/ui-toml/ref_option/ref_option.rs:23:1
    |
 LL | fn mult_string(a: &Option<String>, b: &Option<Vec<u8>>) {}
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -62,7 +62,7 @@ LL + fn mult_string(a: Option<&String>, b: Option<&Vec<u8>>) {}
    |
 
 error: it is more idiomatic to use `Option<&T>` instead of `&Option<T>`
-  --> tests/ui/ref_option/ref_option.rs:24:1
+  --> tests/ui-toml/ref_option/ref_option.rs:25:1
    |
 LL |   fn ret_box<'a>() -> &'a Option<Box<u8>> {
    |   ^                   ------------------- help: change this to: `Option<&'a Box<u8>>`
@@ -74,23 +74,7 @@ LL | | }
    | |_^
 
 error: it is more idiomatic to use `Option<&T>` instead of `&Option<T>`
-  --> tests/ui/ref_option/ref_option.rs:42:5
-   |
-LL |     fn trait_opt(&self, a: &Option<String>);
-   |     ^^^^^^^^^^^^^^^^^^^^^^^---------------^^
-   |                            |
-   |                            help: change this to: `Option<&String>`
-
-error: it is more idiomatic to use `Option<&T>` instead of `&Option<T>`
-  --> tests/ui/ref_option/ref_option.rs:44:5
-   |
-LL |     fn trait_ret(&self) -> &Option<String>;
-   |     ^^^^^^^^^^^^^^^^^^^^^^^---------------^
-   |                            |
-   |                            help: change this to: `Option<&String>`
-
-error: it is more idiomatic to use `Option<&T>` instead of `&Option<T>`
-  --> tests/ui/ref_option/ref_option.rs:58:5
+  --> tests/ui-toml/ref_option/ref_option.rs:45:5
    |
 LL |     fn private_opt_params(&self, a: &Option<()>) {}
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-----------^^^^
@@ -98,7 +82,7 @@ LL |     fn private_opt_params(&self, a: &Option<()>) {}
    |                                     help: change this to: `Option<&()>`
 
 error: it is more idiomatic to use `Option<&T>` instead of `&Option<T>`
-  --> tests/ui/ref_option/ref_option.rs:60:5
+  --> tests/ui-toml/ref_option/ref_option.rs:47:5
    |
 LL |       fn private_opt_ret(&self) -> &Option<String> {
    |       ^                            --------------- help: change this to: `Option<&String>`
@@ -109,5 +93,5 @@ LL | |         panic!()
 LL | |     }
    | |_____^
 
-error: aborting due to 11 previous errors
+error: aborting due to 9 previous errors
 
diff --git a/src/tools/clippy/tests/ui-toml/ref_option/ref_option.rs b/src/tools/clippy/tests/ui-toml/ref_option/ref_option.rs
new file mode 100644
index 00000000000..8397c2213d1
--- /dev/null
+++ b/src/tools/clippy/tests/ui-toml/ref_option/ref_option.rs
@@ -0,0 +1,114 @@
+//@aux-build:../../ui/auxiliary/proc_macros.rs
+//@revisions: private all
+//@[private] rustc-env:CLIPPY_CONF_DIR=tests/ui-toml/ref_option/private
+//@[all] rustc-env:CLIPPY_CONF_DIR=tests/ui-toml/ref_option/all
+
+#![allow(unused, clippy::needless_lifetimes, clippy::borrowed_box)]
+#![warn(clippy::ref_option)]
+
+fn opt_u8(a: &Option<u8>) {}
+//~^ ref_option
+fn opt_gen<T>(a: &Option<T>) {}
+//~^ ref_option
+fn opt_string(a: &std::option::Option<String>) {}
+//~^ ref_option
+fn ret_u8<'a>(p: &'a str) -> &'a Option<u8> {
+    //~^ ref_option
+    panic!()
+}
+fn ret_u8_static() -> &'static Option<u8> {
+    //~^ ref_option
+    panic!()
+}
+fn mult_string(a: &Option<String>, b: &Option<Vec<u8>>) {}
+//~^ ref_option
+fn ret_box<'a>() -> &'a Option<Box<u8>> {
+    //~^ ref_option
+    panic!()
+}
+
+pub fn pub_opt_string(a: &Option<String>) {}
+//~[all]^ ref_option
+pub fn pub_mult_string(a: &Option<String>, b: &Option<Vec<u8>>) {}
+//~[all]^ ref_option
+
+pub struct PubStruct;
+
+impl PubStruct {
+    pub fn pub_opt_params(&self, a: &Option<()>) {}
+    //~[all]^ ref_option
+    pub fn pub_opt_ret(&self) -> &Option<String> {
+        //~[all]^ ref_option
+        panic!()
+    }
+
+    fn private_opt_params(&self, a: &Option<()>) {}
+    //~^ ref_option
+    fn private_opt_ret(&self) -> &Option<String> {
+        //~^ ref_option
+        panic!()
+    }
+}
+
+// valid, don't change
+fn mut_u8(a: &mut Option<u8>) {}
+pub fn pub_mut_u8(a: &mut Option<String>) {}
+
+// might be good to catch in the future
+fn mut_u8_ref(a: &mut &Option<u8>) {}
+pub fn pub_mut_u8_ref(a: &mut &Option<String>) {}
+fn lambdas() {
+    // Not handled for now, not sure if we should
+    let x = |a: &Option<String>| {};
+    let x = |a: &Option<String>| -> &Option<String> { panic!() };
+}
+
+pub mod external {
+    proc_macros::external!(
+        fn opt_u8(a: &Option<u8>) {}
+        fn ret_u8<'a>(p: &'a str) -> &'a Option<u8> {
+            panic!()
+        }
+        pub fn pub_opt_u8(a: &Option<u8>) {}
+
+        pub struct PubStruct;
+        impl PubStruct {
+            pub fn pub_opt_params(&self, a: &Option<()>) {}
+            pub fn pub_opt_ret(&self) -> &Option<String> {
+                panic!()
+            }
+
+            fn private_opt_params(&self, a: &Option<()>) {}
+            fn private_opt_ret(&self) -> &Option<String> {
+                panic!()
+            }
+        }
+    );
+}
+
+pub mod proc_macros {
+    proc_macros::with_span!(
+        span
+
+        fn opt_u8(a: &Option<u8>) {}
+        fn ret_u8<'a>(p: &'a str) -> &'a Option<u8> {
+            panic!()
+        }
+        pub fn pub_opt_u8(a: &Option<u8>) {}
+
+        pub struct PubStruct;
+        impl PubStruct {
+            pub fn pub_opt_params(&self, a: &Option<()>) {}
+            pub fn pub_opt_ret(&self) -> &Option<String> {
+                panic!()
+            }
+
+            fn private_opt_params(&self, a: &Option<()>) {}
+            fn private_opt_ret(&self) -> &Option<String> {
+                panic!()
+            }
+        }
+    );
+}
+
+fn main() {}
diff --git a/src/tools/clippy/tests/ui/ref_option/ref_option_traits.all.stderr b/src/tools/clippy/tests/ui-toml/ref_option/ref_option_traits.all.stderr
index 886bf2b0349..602e148be60 100644
--- a/src/tools/clippy/tests/ui/ref_option/ref_option_traits.all.stderr
+++ b/src/tools/clippy/tests/ui-toml/ref_option/ref_option_traits.all.stderr
@@ -1,5 +1,5 @@
 error: it is more idiomatic to use `Option<&T>` instead of `&Option<T>`
-  --> tests/ui/ref_option/ref_option_traits.rs:9:5
+  --> tests/ui-toml/ref_option/ref_option_traits.rs:10:5
    |
 LL |     fn pub_trait_opt(&self, a: &Option<Vec<u8>>);
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^----------------^^
@@ -10,7 +10,7 @@ LL |     fn pub_trait_opt(&self, a: &Option<Vec<u8>>);
    = help: to override `-D warnings` add `#[allow(clippy::ref_option)]`
 
 error: it is more idiomatic to use `Option<&T>` instead of `&Option<T>`
-  --> tests/ui/ref_option/ref_option_traits.rs:11:5
+  --> tests/ui-toml/ref_option/ref_option_traits.rs:12:5
    |
 LL |     fn pub_trait_ret(&self) -> &Option<Vec<u8>>;
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^----------------^
@@ -18,7 +18,7 @@ LL |     fn pub_trait_ret(&self) -> &Option<Vec<u8>>;
    |                                help: change this to: `Option<&Vec<u8>>`
 
 error: it is more idiomatic to use `Option<&T>` instead of `&Option<T>`
-  --> tests/ui/ref_option/ref_option_traits.rs:16:5
+  --> tests/ui-toml/ref_option/ref_option_traits.rs:17:5
    |
 LL |     fn trait_opt(&self, a: &Option<String>);
    |     ^^^^^^^^^^^^^^^^^^^^^^^---------------^^
@@ -26,7 +26,7 @@ LL |     fn trait_opt(&self, a: &Option<String>);
    |                            help: change this to: `Option<&String>`
 
 error: it is more idiomatic to use `Option<&T>` instead of `&Option<T>`
-  --> tests/ui/ref_option/ref_option_traits.rs:18:5
+  --> tests/ui-toml/ref_option/ref_option_traits.rs:19:5
    |
 LL |     fn trait_ret(&self) -> &Option<String>;
    |     ^^^^^^^^^^^^^^^^^^^^^^^---------------^
diff --git a/src/tools/clippy/tests/ui/ref_option/ref_option_traits.private.stderr b/src/tools/clippy/tests/ui-toml/ref_option/ref_option_traits.private.stderr
index cfab7fa5734..20bea400edf 100644
--- a/src/tools/clippy/tests/ui/ref_option/ref_option_traits.private.stderr
+++ b/src/tools/clippy/tests/ui-toml/ref_option/ref_option_traits.private.stderr
@@ -1,5 +1,5 @@
 error: it is more idiomatic to use `Option<&T>` instead of `&Option<T>`
-  --> tests/ui/ref_option/ref_option_traits.rs:16:5
+  --> tests/ui-toml/ref_option/ref_option_traits.rs:17:5
    |
 LL |     fn trait_opt(&self, a: &Option<String>);
    |     ^^^^^^^^^^^^^^^^^^^^^^^---------------^^
@@ -10,7 +10,7 @@ LL |     fn trait_opt(&self, a: &Option<String>);
    = help: to override `-D warnings` add `#[allow(clippy::ref_option)]`
 
 error: it is more idiomatic to use `Option<&T>` instead of `&Option<T>`
-  --> tests/ui/ref_option/ref_option_traits.rs:18:5
+  --> tests/ui-toml/ref_option/ref_option_traits.rs:19:5
    |
 LL |     fn trait_ret(&self) -> &Option<String>;
    |     ^^^^^^^^^^^^^^^^^^^^^^^---------------^
diff --git a/src/tools/clippy/tests/ui-toml/ref_option/ref_option_traits.rs b/src/tools/clippy/tests/ui-toml/ref_option/ref_option_traits.rs
new file mode 100644
index 00000000000..e1477d7f846
--- /dev/null
+++ b/src/tools/clippy/tests/ui-toml/ref_option/ref_option_traits.rs
@@ -0,0 +1,71 @@
+//@no-rustfix: fixes are only done to traits, not the impls
+//@aux-build:../../ui/auxiliary/proc_macros.rs
+//@revisions: private all
+//@[private] rustc-env:CLIPPY_CONF_DIR=tests/ui-toml/ref_option/private
+//@[all] rustc-env:CLIPPY_CONF_DIR=tests/ui-toml/ref_option/all
+
+#![warn(clippy::ref_option)]
+
+pub trait PubTrait {
+    fn pub_trait_opt(&self, a: &Option<Vec<u8>>);
+    //~[all]^ ref_option
+    fn pub_trait_ret(&self) -> &Option<Vec<u8>>;
+    //~[all]^ ref_option
+}
+
+trait PrivateTrait {
+    fn trait_opt(&self, a: &Option<String>);
+    //~^ ref_option
+    fn trait_ret(&self) -> &Option<String>;
+    //~^ ref_option
+}
+
+pub struct PubStruct;
+
+impl PubTrait for PubStruct {
+    fn pub_trait_opt(&self, a: &Option<Vec<u8>>) {}
+    fn pub_trait_ret(&self) -> &Option<Vec<u8>> {
+        panic!()
+    }
+}
+
+struct PrivateStruct;
+
+impl PrivateTrait for PrivateStruct {
+    fn trait_opt(&self, a: &Option<String>) {}
+    fn trait_ret(&self) -> &Option<String> {
+        panic!()
+    }
+}
+
+pub mod external {
+    proc_macros::external!(
+        pub trait PubTrait {
+            fn pub_trait_opt(&self, a: &Option<Vec<u8>>);
+            fn pub_trait_ret(&self) -> &Option<Vec<u8>>;
+        }
+
+        trait PrivateTrait {
+            fn trait_opt(&self, a: &Option<String>);
+            fn trait_ret(&self) -> &Option<String>;
+        }
+    );
+}
+
+pub mod proc_macros {
+    proc_macros::with_span!(
+        span
+
+        pub trait PubTrait {
+            fn pub_trait_opt(&self, a: &Option<Vec<u8>>);
+            fn pub_trait_ret(&self) -> &Option<Vec<u8>>;
+        }
+
+        trait PrivateTrait {
+            fn trait_opt(&self, a: &Option<String>);
+            fn trait_ret(&self) -> &Option<String>;
+        }
+    );
+}
+
+fn main() {}
diff --git a/src/tools/clippy/tests/ui/as_underscore_unfixable.rs b/src/tools/clippy/tests/ui/as_underscore_unfixable.rs
new file mode 100644
index 00000000000..854feca7174
--- /dev/null
+++ b/src/tools/clippy/tests/ui/as_underscore_unfixable.rs
@@ -0,0 +1,14 @@
+//@no-rustfix
+
+#![warn(clippy::as_underscore)]
+
+fn main() {
+    // From issue #15282
+    let f = async || ();
+    let _: Box<dyn FnOnce() -> _> = Box::new(f) as _;
+    //~^ as_underscore
+
+    let barr = || (|| ());
+    let _: Box<dyn Fn() -> _> = Box::new(barr) as _;
+    //~^ as_underscore
+}
diff --git a/src/tools/clippy/tests/ui/as_underscore_unfixable.stderr b/src/tools/clippy/tests/ui/as_underscore_unfixable.stderr
new file mode 100644
index 00000000000..7385bea5c65
--- /dev/null
+++ b/src/tools/clippy/tests/ui/as_underscore_unfixable.stderr
@@ -0,0 +1,20 @@
+error: using `as _` conversion
+  --> tests/ui/as_underscore_unfixable.rs:8:37
+   |
+LL |     let _: Box<dyn FnOnce() -> _> = Box::new(f) as _;
+   |                                     ^^^^^^^^^^^^^^^^
+   |
+   = help: consider giving the type explicitly
+   = note: `-D clippy::as-underscore` implied by `-D warnings`
+   = help: to override `-D warnings` add `#[allow(clippy::as_underscore)]`
+
+error: using `as _` conversion
+  --> tests/ui/as_underscore_unfixable.rs:12:33
+   |
+LL |     let _: Box<dyn Fn() -> _> = Box::new(barr) as _;
+   |                                 ^^^^^^^^^^^^^^^^^^^
+   |
+   = help: consider giving the type explicitly
+
+error: aborting due to 2 previous errors
+
diff --git a/src/tools/clippy/tests/ui/cast.rs b/src/tools/clippy/tests/ui/cast.rs
index 525be821650..fab02bf7b24 100644
--- a/src/tools/clippy/tests/ui/cast.rs
+++ b/src/tools/clippy/tests/ui/cast.rs
@@ -569,3 +569,16 @@ fn issue12721() {
     (255 % 999999u64) as u8;
     //~^ cast_possible_truncation
 }
+
+mod issue14150 {
+    #[clippy::msrv = "1.87"]
+    fn msrv_supports_cast_signed() {
+        _ = 1u8 as i8;
+        //~^ cast_possible_wrap
+    }
+    #[clippy::msrv = "1.86"]
+    fn msrv_doesnt_supports_cast_signed() {
+        _ = 1u8 as i8;
+        //~^ cast_possible_wrap
+    }
+}
diff --git a/src/tools/clippy/tests/ui/cast.stderr b/src/tools/clippy/tests/ui/cast.stderr
index 1cb30d95667..8c48855123f 100644
--- a/src/tools/clippy/tests/ui/cast.stderr
+++ b/src/tools/clippy/tests/ui/cast.stderr
@@ -194,7 +194,7 @@ error: casting `u8` to `i8` may wrap around the value
   --> tests/ui/cast.rs:88:5
    |
 LL |     1u8 as i8;
-   |     ^^^^^^^^^
+   |     ^^^^^^^^^ help: if this is intentional, use `cast_signed()` instead: `1u8.cast_signed()`
    |
    = note: `-D clippy::cast-possible-wrap` implied by `-D warnings`
    = help: to override `-D warnings` add `#[allow(clippy::cast_possible_wrap)]`
@@ -203,25 +203,25 @@ error: casting `u16` to `i16` may wrap around the value
   --> tests/ui/cast.rs:91:5
    |
 LL |     1u16 as i16;
-   |     ^^^^^^^^^^^
+   |     ^^^^^^^^^^^ help: if this is intentional, use `cast_signed()` instead: `1u16.cast_signed()`
 
 error: casting `u32` to `i32` may wrap around the value
   --> tests/ui/cast.rs:94:5
    |
 LL |     1u32 as i32;
-   |     ^^^^^^^^^^^
+   |     ^^^^^^^^^^^ help: if this is intentional, use `cast_signed()` instead: `1u32.cast_signed()`
 
 error: casting `u64` to `i64` may wrap around the value
   --> tests/ui/cast.rs:97:5
    |
 LL |     1u64 as i64;
-   |     ^^^^^^^^^^^
+   |     ^^^^^^^^^^^ help: if this is intentional, use `cast_signed()` instead: `1u64.cast_signed()`
 
 error: casting `usize` to `isize` may wrap around the value
   --> tests/ui/cast.rs:100:5
    |
 LL |     1usize as isize;
-   |     ^^^^^^^^^^^^^^^
+   |     ^^^^^^^^^^^^^^^ help: if this is intentional, use `cast_signed()` instead: `1usize.cast_signed()`
 
 error: casting `usize` to `i8` may truncate the value
   --> tests/ui/cast.rs:104:5
@@ -321,43 +321,43 @@ error: casting `i32` to `u32` may lose the sign of the value
   --> tests/ui/cast.rs:138:5
    |
 LL |     -1i32 as u32;
-   |     ^^^^^^^^^^^^
+   |     ^^^^^^^^^^^^ help: if this is intentional, use `cast_unsigned()` instead: `(-1i32).cast_unsigned()`
 
 error: casting `isize` to `usize` may lose the sign of the value
   --> tests/ui/cast.rs:142:5
    |
 LL |     -1isize as usize;
-   |     ^^^^^^^^^^^^^^^^
+   |     ^^^^^^^^^^^^^^^^ help: if this is intentional, use `cast_unsigned()` instead: `(-1isize).cast_unsigned()`
 
 error: casting `i8` to `u8` may lose the sign of the value
   --> tests/ui/cast.rs:154:5
    |
 LL |     (i8::MIN).abs() as u8;
-   |     ^^^^^^^^^^^^^^^^^^^^^
+   |     ^^^^^^^^^^^^^^^^^^^^^ help: if this is intentional, use `cast_unsigned()` instead: `(i8::MIN).abs().cast_unsigned()`
 
 error: casting `i64` to `u64` may lose the sign of the value
   --> tests/ui/cast.rs:159:5
    |
 LL |     (-1i64).abs() as u64;
-   |     ^^^^^^^^^^^^^^^^^^^^
+   |     ^^^^^^^^^^^^^^^^^^^^ help: if this is intentional, use `cast_unsigned()` instead: `(-1i64).abs().cast_unsigned()`
 
 error: casting `isize` to `usize` may lose the sign of the value
   --> tests/ui/cast.rs:161:5
    |
 LL |     (-1isize).abs() as usize;
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^ help: if this is intentional, use `cast_unsigned()` instead: `(-1isize).abs().cast_unsigned()`
 
 error: casting `i64` to `u64` may lose the sign of the value
   --> tests/ui/cast.rs:169:5
    |
 LL |     (unsafe { (-1i64).checked_abs().unwrap_unchecked() }) as u64;
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: if this is intentional, use `cast_unsigned()` instead: `(unsafe { (-1i64).checked_abs().unwrap_unchecked() }).cast_unsigned()`
 
 error: casting `i64` to `u64` may lose the sign of the value
   --> tests/ui/cast.rs:185:5
    |
 LL |     (unsafe { (-1i64).checked_isqrt().unwrap_unchecked() }) as u64;
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: if this is intentional, use `cast_unsigned()` instead: `(unsafe { (-1i64).checked_isqrt().unwrap_unchecked() }).cast_unsigned()`
 
 error: casting `i64` to `i8` may truncate the value
   --> tests/ui/cast.rs:237:5
@@ -495,79 +495,79 @@ error: casting `i32` to `u32` may lose the sign of the value
   --> tests/ui/cast.rs:438:9
    |
 LL |         (x * x) as u32;
-   |         ^^^^^^^^^^^^^^
+   |         ^^^^^^^^^^^^^^ help: if this is intentional, use `cast_unsigned()` instead: `(x * x).cast_unsigned()`
 
 error: casting `i32` to `u32` may lose the sign of the value
   --> tests/ui/cast.rs:444:32
    |
 LL |     let _a = |x: i32| -> u32 { (x * x * x * x) as u32 };
-   |                                ^^^^^^^^^^^^^^^^^^^^^^
+   |                                ^^^^^^^^^^^^^^^^^^^^^^ help: if this is intentional, use `cast_unsigned()` instead: `(x * x * x * x).cast_unsigned()`
 
 error: casting `i32` to `u32` may lose the sign of the value
   --> tests/ui/cast.rs:447:5
    |
 LL |     (2_i32).checked_pow(3).unwrap() as u32;
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: if this is intentional, use `cast_unsigned()` instead: `(2_i32).checked_pow(3).unwrap().cast_unsigned()`
 
 error: casting `i32` to `u32` may lose the sign of the value
   --> tests/ui/cast.rs:449:5
    |
 LL |     (-2_i32).pow(3) as u32;
-   |     ^^^^^^^^^^^^^^^^^^^^^^
+   |     ^^^^^^^^^^^^^^^^^^^^^^ help: if this is intentional, use `cast_unsigned()` instead: `(-2_i32).pow(3).cast_unsigned()`
 
 error: casting `i32` to `u32` may lose the sign of the value
   --> tests/ui/cast.rs:454:5
    |
 LL |     (-5_i32 % 2) as u32;
-   |     ^^^^^^^^^^^^^^^^^^^
+   |     ^^^^^^^^^^^^^^^^^^^ help: if this is intentional, use `cast_unsigned()` instead: `(-5_i32 % 2).cast_unsigned()`
 
 error: casting `i32` to `u32` may lose the sign of the value
   --> tests/ui/cast.rs:457:5
    |
 LL |     (-5_i32 % -2) as u32;
-   |     ^^^^^^^^^^^^^^^^^^^^
+   |     ^^^^^^^^^^^^^^^^^^^^ help: if this is intentional, use `cast_unsigned()` instead: `(-5_i32 % -2).cast_unsigned()`
 
 error: casting `i32` to `u32` may lose the sign of the value
   --> tests/ui/cast.rs:461:5
    |
 LL |     (-2_i32 >> 1) as u32;
-   |     ^^^^^^^^^^^^^^^^^^^^
+   |     ^^^^^^^^^^^^^^^^^^^^ help: if this is intentional, use `cast_unsigned()` instead: `(-2_i32 >> 1).cast_unsigned()`
 
 error: casting `i32` to `u32` may lose the sign of the value
   --> tests/ui/cast.rs:465:5
    |
 LL |     (x * x) as u32;
-   |     ^^^^^^^^^^^^^^
+   |     ^^^^^^^^^^^^^^ help: if this is intentional, use `cast_unsigned()` instead: `(x * x).cast_unsigned()`
 
 error: casting `i32` to `u32` may lose the sign of the value
   --> tests/ui/cast.rs:467:5
    |
 LL |     (x * x * x) as u32;
-   |     ^^^^^^^^^^^^^^^^^^
+   |     ^^^^^^^^^^^^^^^^^^ help: if this is intentional, use `cast_unsigned()` instead: `(x * x * x).cast_unsigned()`
 
 error: casting `i16` to `u16` may lose the sign of the value
   --> tests/ui/cast.rs:471:5
    |
 LL |     (y * y * y * y * -2) as u16;
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: if this is intentional, use `cast_unsigned()` instead: `(y * y * y * y * -2).cast_unsigned()`
 
 error: casting `i16` to `u16` may lose the sign of the value
   --> tests/ui/cast.rs:474:5
    |
 LL |     (y * y * y / y * 2) as u16;
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: if this is intentional, use `cast_unsigned()` instead: `(y * y * y / y * 2).cast_unsigned()`
 
 error: casting `i16` to `u16` may lose the sign of the value
   --> tests/ui/cast.rs:476:5
    |
 LL |     (y * y / y * 2) as u16;
-   |     ^^^^^^^^^^^^^^^^^^^^^^
+   |     ^^^^^^^^^^^^^^^^^^^^^^ help: if this is intentional, use `cast_unsigned()` instead: `(y * y / y * 2).cast_unsigned()`
 
 error: casting `i16` to `u16` may lose the sign of the value
   --> tests/ui/cast.rs:479:5
    |
 LL |     (y / y * y * -2) as u16;
-   |     ^^^^^^^^^^^^^^^^^^^^^^^
+   |     ^^^^^^^^^^^^^^^^^^^^^^^ help: if this is intentional, use `cast_unsigned()` instead: `(y / y * y * -2).cast_unsigned()`
 
 error: equal expressions as operands to `/`
   --> tests/ui/cast.rs:479:6
@@ -581,97 +581,97 @@ error: casting `i16` to `u16` may lose the sign of the value
   --> tests/ui/cast.rs:483:5
    |
 LL |     (y + y + y + -2) as u16;
-   |     ^^^^^^^^^^^^^^^^^^^^^^^
+   |     ^^^^^^^^^^^^^^^^^^^^^^^ help: if this is intentional, use `cast_unsigned()` instead: `(y + y + y + -2).cast_unsigned()`
 
 error: casting `i16` to `u16` may lose the sign of the value
   --> tests/ui/cast.rs:486:5
    |
 LL |     (y + y + y + 2) as u16;
-   |     ^^^^^^^^^^^^^^^^^^^^^^
+   |     ^^^^^^^^^^^^^^^^^^^^^^ help: if this is intentional, use `cast_unsigned()` instead: `(y + y + y + 2).cast_unsigned()`
 
 error: casting `i16` to `u16` may lose the sign of the value
   --> tests/ui/cast.rs:490:5
    |
 LL |     (z + -2) as u16;
-   |     ^^^^^^^^^^^^^^^
+   |     ^^^^^^^^^^^^^^^ help: if this is intentional, use `cast_unsigned()` instead: `(z + -2).cast_unsigned()`
 
 error: casting `i16` to `u16` may lose the sign of the value
   --> tests/ui/cast.rs:493:5
    |
 LL |     (z + z + 2) as u16;
-   |     ^^^^^^^^^^^^^^^^^^
+   |     ^^^^^^^^^^^^^^^^^^ help: if this is intentional, use `cast_unsigned()` instead: `(z + z + 2).cast_unsigned()`
 
 error: casting `i32` to `u32` may lose the sign of the value
   --> tests/ui/cast.rs:497:9
    |
 LL |         (a * a * b * b * c * c) as u32;
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: if this is intentional, use `cast_unsigned()` instead: `(a * a * b * b * c * c).cast_unsigned()`
 
 error: casting `i32` to `u32` may lose the sign of the value
   --> tests/ui/cast.rs:499:9
    |
 LL |         (a * b * c) as u32;
-   |         ^^^^^^^^^^^^^^^^^^
+   |         ^^^^^^^^^^^^^^^^^^ help: if this is intentional, use `cast_unsigned()` instead: `(a * b * c).cast_unsigned()`
 
 error: casting `i32` to `u32` may lose the sign of the value
   --> tests/ui/cast.rs:502:9
    |
 LL |         (a * -b * c) as u32;
-   |         ^^^^^^^^^^^^^^^^^^^
+   |         ^^^^^^^^^^^^^^^^^^^ help: if this is intentional, use `cast_unsigned()` instead: `(a * -b * c).cast_unsigned()`
 
 error: casting `i32` to `u32` may lose the sign of the value
   --> tests/ui/cast.rs:505:9
    |
 LL |         (a * b * c * c) as u32;
-   |         ^^^^^^^^^^^^^^^^^^^^^^
+   |         ^^^^^^^^^^^^^^^^^^^^^^ help: if this is intentional, use `cast_unsigned()` instead: `(a * b * c * c).cast_unsigned()`
 
 error: casting `i32` to `u32` may lose the sign of the value
   --> tests/ui/cast.rs:507:9
    |
 LL |         (a * -2) as u32;
-   |         ^^^^^^^^^^^^^^^
+   |         ^^^^^^^^^^^^^^^ help: if this is intentional, use `cast_unsigned()` instead: `(a * -2).cast_unsigned()`
 
 error: casting `i32` to `u32` may lose the sign of the value
   --> tests/ui/cast.rs:510:9
    |
 LL |         (a * b * c * -2) as u32;
-   |         ^^^^^^^^^^^^^^^^^^^^^^^
+   |         ^^^^^^^^^^^^^^^^^^^^^^^ help: if this is intentional, use `cast_unsigned()` instead: `(a * b * c * -2).cast_unsigned()`
 
 error: casting `i32` to `u32` may lose the sign of the value
   --> tests/ui/cast.rs:513:9
    |
 LL |         (a / b) as u32;
-   |         ^^^^^^^^^^^^^^
+   |         ^^^^^^^^^^^^^^ help: if this is intentional, use `cast_unsigned()` instead: `(a / b).cast_unsigned()`
 
 error: casting `i32` to `u32` may lose the sign of the value
   --> tests/ui/cast.rs:515:9
    |
 LL |         (a / b * c) as u32;
-   |         ^^^^^^^^^^^^^^^^^^
+   |         ^^^^^^^^^^^^^^^^^^ help: if this is intentional, use `cast_unsigned()` instead: `(a / b * c).cast_unsigned()`
 
 error: casting `i32` to `u32` may lose the sign of the value
   --> tests/ui/cast.rs:518:9
    |
 LL |         (a / b + b * c) as u32;
-   |         ^^^^^^^^^^^^^^^^^^^^^^
+   |         ^^^^^^^^^^^^^^^^^^^^^^ help: if this is intentional, use `cast_unsigned()` instead: `(a / b + b * c).cast_unsigned()`
 
 error: casting `i32` to `u32` may lose the sign of the value
   --> tests/ui/cast.rs:521:9
    |
 LL |         a.saturating_pow(3) as u32;
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: if this is intentional, use `cast_unsigned()` instead: `a.saturating_pow(3).cast_unsigned()`
 
 error: casting `i32` to `u32` may lose the sign of the value
   --> tests/ui/cast.rs:524:9
    |
 LL |         (a.abs() * b.pow(2) / c.abs()) as u32
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: if this is intentional, use `cast_unsigned()` instead: `(a.abs() * b.pow(2) / c.abs()).cast_unsigned()`
 
 error: casting `i32` to `u32` may lose the sign of the value
   --> tests/ui/cast.rs:532:21
    |
 LL |             let _ = i32::MIN as u32; // cast_sign_loss
-   |                     ^^^^^^^^^^^^^^^
+   |                     ^^^^^^^^^^^^^^^ help: if this is intentional, use `cast_unsigned()` instead: `i32::MIN.cast_unsigned()`
 ...
 LL |     m!();
    |     ---- in this macro invocation
@@ -752,5 +752,17 @@ LL -     (255 % 999999u64) as u8;
 LL +     u8::try_from(255 % 999999u64);
    |
 
-error: aborting due to 92 previous errors
+error: casting `u8` to `i8` may wrap around the value
+  --> tests/ui/cast.rs:576:13
+   |
+LL |         _ = 1u8 as i8;
+   |             ^^^^^^^^^ help: if this is intentional, use `cast_signed()` instead: `1u8.cast_signed()`
+
+error: casting `u8` to `i8` may wrap around the value
+  --> tests/ui/cast.rs:581:13
+   |
+LL |         _ = 1u8 as i8;
+   |             ^^^^^^^^^
+
+error: aborting due to 94 previous errors
 
diff --git a/src/tools/clippy/tests/ui/checked_unwrap/simple_conditionals.rs b/src/tools/clippy/tests/ui/checked_unwrap/simple_conditionals.rs
index 785b2473c05..bba264080b4 100644
--- a/src/tools/clippy/tests/ui/checked_unwrap/simple_conditionals.rs
+++ b/src/tools/clippy/tests/ui/checked_unwrap/simple_conditionals.rs
@@ -273,6 +273,28 @@ const ISSUE14763: fn(Option<String>) = |x| {
     }
 };
 
+fn issue12295() {
+    let option = Some(());
+
+    if option.is_some() {
+        println!("{:?}", option.unwrap());
+        //~^ unnecessary_unwrap
+    } else {
+        println!("{:?}", option.unwrap());
+        //~^ panicking_unwrap
+    }
+
+    let result = Ok::<(), ()>(());
+
+    if result.is_ok() {
+        println!("{:?}", result.unwrap());
+        //~^ unnecessary_unwrap
+    } else {
+        println!("{:?}", result.unwrap());
+        //~^ panicking_unwrap
+    }
+}
+
 fn check_expect() {
     let x = Some(());
     if x.is_some() {
diff --git a/src/tools/clippy/tests/ui/checked_unwrap/simple_conditionals.stderr b/src/tools/clippy/tests/ui/checked_unwrap/simple_conditionals.stderr
index 939b509d85c..2007a859541 100644
--- a/src/tools/clippy/tests/ui/checked_unwrap/simple_conditionals.stderr
+++ b/src/tools/clippy/tests/ui/checked_unwrap/simple_conditionals.stderr
@@ -322,6 +322,40 @@ LL |         if x.is_some() {
 LL |             _ = x.unwrap();
    |                 ^^^^^^^^^^
 
+error: called `unwrap` on `option` after checking its variant with `is_some`
+  --> tests/ui/checked_unwrap/simple_conditionals.rs:280:26
+   |
+LL |     if option.is_some() {
+   |     ------------------- help: try: `if let Some(<item>) = option`
+LL |         println!("{:?}", option.unwrap());
+   |                          ^^^^^^^^^^^^^^^
+
+error: this call to `unwrap()` will always panic
+  --> tests/ui/checked_unwrap/simple_conditionals.rs:283:26
+   |
+LL |     if option.is_some() {
+   |        ---------------- because of this check
+...
+LL |         println!("{:?}", option.unwrap());
+   |                          ^^^^^^^^^^^^^^^
+
+error: called `unwrap` on `result` after checking its variant with `is_ok`
+  --> tests/ui/checked_unwrap/simple_conditionals.rs:290:26
+   |
+LL |     if result.is_ok() {
+   |     ----------------- help: try: `if let Ok(<item>) = result`
+LL |         println!("{:?}", result.unwrap());
+   |                          ^^^^^^^^^^^^^^^
+
+error: this call to `unwrap()` will always panic
+  --> tests/ui/checked_unwrap/simple_conditionals.rs:293:26
+   |
+LL |     if result.is_ok() {
+   |        -------------- because of this check
+...
+LL |         println!("{:?}", result.unwrap());
+   |                          ^^^^^^^^^^^^^^^
+
 error: creating a shared reference to mutable static
   --> tests/ui/checked_unwrap/simple_conditionals.rs:183:12
    |
@@ -332,5 +366,5 @@ LL |         if X.is_some() {
    = note: shared references to mutable statics are dangerous; it's undefined behavior if the static is mutated or if a mutable reference is created for it while the shared reference lives
    = note: `#[deny(static_mut_refs)]` (part of `#[deny(rust_2024_compatibility)]`) on by default
 
-error: aborting due to 36 previous errors
+error: aborting due to 40 previous errors
 
diff --git a/src/tools/clippy/tests/ui/crashes/ice-15657.rs b/src/tools/clippy/tests/ui/crashes/ice-15657.rs
new file mode 100644
index 00000000000..c6f6506cd8d
--- /dev/null
+++ b/src/tools/clippy/tests/ui/crashes/ice-15657.rs
@@ -0,0 +1,11 @@
+//@check-pass
+#![warn(clippy::len_zero)]
+
+pub struct S1;
+pub struct S2;
+
+impl S1 {
+    pub fn len(&self) -> S2 {
+        S2
+    }
+}
diff --git a/src/tools/clippy/tests/ui/crashes/ice-15666.fixed b/src/tools/clippy/tests/ui/crashes/ice-15666.fixed
new file mode 100644
index 00000000000..53b618765c0
--- /dev/null
+++ b/src/tools/clippy/tests/ui/crashes/ice-15666.fixed
@@ -0,0 +1,6 @@
+#![warn(clippy::elidable_lifetime_names)]
+
+struct UnitVariantAccess<'a, 'b, 's>(&'a &'b &'s ());
+trait Trait<'de> {}
+impl<'de> Trait<'de> for UnitVariantAccess<'_, 'de, '_> {}
+//~^ elidable_lifetime_names
diff --git a/src/tools/clippy/tests/ui/crashes/ice-15666.rs b/src/tools/clippy/tests/ui/crashes/ice-15666.rs
new file mode 100644
index 00000000000..1414b3d2035
--- /dev/null
+++ b/src/tools/clippy/tests/ui/crashes/ice-15666.rs
@@ -0,0 +1,6 @@
+#![warn(clippy::elidable_lifetime_names)]
+
+struct UnitVariantAccess<'a, 'b, 's>(&'a &'b &'s ());
+trait Trait<'de> {}
+impl<'de, 'a, 's> Trait<'de> for UnitVariantAccess<'a, 'de, 's> {}
+//~^ elidable_lifetime_names
diff --git a/src/tools/clippy/tests/ui/crashes/ice-15666.stderr b/src/tools/clippy/tests/ui/crashes/ice-15666.stderr
new file mode 100644
index 00000000000..b417c09b5c6
--- /dev/null
+++ b/src/tools/clippy/tests/ui/crashes/ice-15666.stderr
@@ -0,0 +1,16 @@
+error: the following explicit lifetimes could be elided: 'a, 's
+  --> tests/ui/crashes/ice-15666.rs:5:11
+   |
+LL | impl<'de, 'a, 's> Trait<'de> for UnitVariantAccess<'a, 'de, 's> {}
+   |           ^^  ^^                                   ^^       ^^
+   |
+   = note: `-D clippy::elidable-lifetime-names` implied by `-D warnings`
+   = help: to override `-D warnings` add `#[allow(clippy::elidable_lifetime_names)]`
+help: elide the lifetimes
+   |
+LL - impl<'de, 'a, 's> Trait<'de> for UnitVariantAccess<'a, 'de, 's> {}
+LL + impl<'de> Trait<'de> for UnitVariantAccess<'_, 'de, '_> {}
+   |
+
+error: aborting due to 1 previous error
+
diff --git a/src/tools/clippy/tests/ui/elidable_lifetime_names.fixed b/src/tools/clippy/tests/ui/elidable_lifetime_names.fixed
index abeee5c4cef..a6c4cb7a36a 100644
--- a/src/tools/clippy/tests/ui/elidable_lifetime_names.fixed
+++ b/src/tools/clippy/tests/ui/elidable_lifetime_names.fixed
@@ -192,3 +192,85 @@ mod issue13923 {
         x.b
     }
 }
+
+fn issue15666_original() {
+    struct UnitVariantAccess<'a, 'b, 's>(&'a &'b &'s ());
+
+    trait Trait<'de> {}
+
+    //~v elidable_lifetime_names
+    impl<'de> Trait<'de> for UnitVariantAccess<'_, 'de, '_> {}
+    //        ^^  ^^                                   ^^       ^^
+}
+
+#[allow(clippy::upper_case_acronyms)]
+fn issue15666() {
+    struct S1<'a>(&'a ());
+    struct S2<'a, 'b>(&'a &'b ());
+    struct S3<'a, 'b, 'c>(&'a &'b &'c ());
+
+    trait T {}
+    trait TA<'a> {}
+    trait TB<'b> {}
+    trait TC<'c> {}
+    trait TAB<'a, 'b> {}
+    trait TAC<'a, 'c> {}
+    trait TBC<'b, 'c> {}
+    trait TABC<'a, 'b, 'c> {}
+
+    // 1 lifetime
+
+    impl<'a> TA<'a> for S1<'a> {}
+
+    //~v elidable_lifetime_names
+    impl T for S1<'_> {}
+    //   ^^
+
+    // 2 lifetimes
+
+    impl<'a, 'b> TAB<'a, 'b> for S2<'a, 'b> {}
+
+    //~v elidable_lifetime_names
+    impl<'a> TA<'a> for S2<'a, '_> {}
+    //       ^^
+
+    //~v elidable_lifetime_names
+    impl<'b> TB<'b> for S2<'_, 'b> {}
+    //   ^^
+
+    //~v elidable_lifetime_names
+    impl T for S2<'_, '_> {}
+    //   ^^  ^^
+
+    // 3 lifetimes
+
+    impl<'a, 'b, 'c> TABC<'a, 'b, 'c> for S3<'a, 'b, 'c> {}
+
+    //~v elidable_lifetime_names
+    impl<'a, 'b> TAB<'a, 'b> for S3<'a, 'b, '_> {}
+    //           ^^
+
+    //~v elidable_lifetime_names
+    impl<'a, 'c> TAC<'a, 'c> for S3<'a, '_, 'c> {}
+    //       ^^
+
+    //~v elidable_lifetime_names
+    impl<'a> TA<'a> for S3<'a, '_, '_> {}
+    //       ^^  ^^
+
+    //~v elidable_lifetime_names
+    impl<'b, 'c> TBC<'b, 'c> for S3<'_, 'b, 'c> {}
+    //   ^^
+
+    //~v elidable_lifetime_names
+    impl<'b> TB<'b> for S3<'_, 'b, '_> {}
+    //   ^^      ^^
+
+    //~v elidable_lifetime_names
+    impl<'c> TC<'c> for S3<'_, '_, 'c> {}
+    //   ^^  ^^
+
+    //~v elidable_lifetime_names
+    impl T for S3<'_, '_, '_> {}
+    //   ^^  ^^  ^^
+}
diff --git a/src/tools/clippy/tests/ui/elidable_lifetime_names.rs b/src/tools/clippy/tests/ui/elidable_lifetime_names.rs
index fae3577a8e9..e08056b2fb5 100644
--- a/src/tools/clippy/tests/ui/elidable_lifetime_names.rs
+++ b/src/tools/clippy/tests/ui/elidable_lifetime_names.rs
@@ -192,3 +192,85 @@ mod issue13923 {
         x.b
     }
 }
+
+fn issue15666_original() {
+    struct UnitVariantAccess<'a, 'b, 's>(&'a &'b &'s ());
+
+    trait Trait<'de> {}
+
+    //~v elidable_lifetime_names
+    impl<'de, 'a, 's> Trait<'de> for UnitVariantAccess<'a, 'de, 's> {}
+    //        ^^  ^^                                   ^^       ^^
+}
+
+#[allow(clippy::upper_case_acronyms)]
+fn issue15666() {
+    struct S1<'a>(&'a ());
+    struct S2<'a, 'b>(&'a &'b ());
+    struct S3<'a, 'b, 'c>(&'a &'b &'c ());
+
+    trait T {}
+    trait TA<'a> {}
+    trait TB<'b> {}
+    trait TC<'c> {}
+    trait TAB<'a, 'b> {}
+    trait TAC<'a, 'c> {}
+    trait TBC<'b, 'c> {}
+    trait TABC<'a, 'b, 'c> {}
+
+    // 1 lifetime
+
+    impl<'a> TA<'a> for S1<'a> {}
+
+    //~v elidable_lifetime_names
+    impl<'a> T for S1<'a> {}
+    //   ^^
+
+    // 2 lifetimes
+
+    impl<'a, 'b> TAB<'a, 'b> for S2<'a, 'b> {}
+
+    //~v elidable_lifetime_names
+    impl<'a, 'b> TA<'a> for S2<'a, 'b> {}
+    //       ^^
+
+    //~v elidable_lifetime_names
+    impl<'a, 'b> TB<'b> for S2<'a, 'b> {}
+    //   ^^
+
+    //~v elidable_lifetime_names
+    impl<'a, 'b> T for S2<'a, 'b> {}
+    //   ^^  ^^
+
+    // 3 lifetimes
+
+    impl<'a, 'b, 'c> TABC<'a, 'b, 'c> for S3<'a, 'b, 'c> {}
+
+    //~v elidable_lifetime_names
+    impl<'a, 'b, 'c> TAB<'a, 'b> for S3<'a, 'b, 'c> {}
+    //           ^^
+
+    //~v elidable_lifetime_names
+    impl<'a, 'b, 'c> TAC<'a, 'c> for S3<'a, 'b, 'c> {}
+    //       ^^
+
+    //~v elidable_lifetime_names
+    impl<'a, 'b, 'c> TA<'a> for S3<'a, 'b, 'c> {}
+    //       ^^  ^^
+
+    //~v elidable_lifetime_names
+    impl<'a, 'b, 'c> TBC<'b, 'c> for S3<'a, 'b, 'c> {}
+    //   ^^
+
+    //~v elidable_lifetime_names
+    impl<'a, 'b, 'c> TB<'b> for S3<'a, 'b, 'c> {}
+    //   ^^      ^^
+
+    //~v elidable_lifetime_names
+    impl<'a, 'b, 'c> TC<'c> for S3<'a, 'b, 'c> {}
+    //   ^^  ^^
+
+    //~v elidable_lifetime_names
+    impl<'a, 'b, 'c> T for S3<'a, 'b, 'c> {}
+    //   ^^  ^^  ^^
+}
diff --git a/src/tools/clippy/tests/ui/elidable_lifetime_names.stderr b/src/tools/clippy/tests/ui/elidable_lifetime_names.stderr
index a60dfc69756..03fe383b8f6 100644
--- a/src/tools/clippy/tests/ui/elidable_lifetime_names.stderr
+++ b/src/tools/clippy/tests/ui/elidable_lifetime_names.stderr
@@ -158,5 +158,149 @@ LL |             o: &'t str,
 LL ~         ) -> Content<'t, '_> {
    |
 
-error: aborting due to 12 previous errors
+error: the following explicit lifetimes could be elided: 'a, 's
+  --> tests/ui/elidable_lifetime_names.rs:202:15
+   |
+LL |     impl<'de, 'a, 's> Trait<'de> for UnitVariantAccess<'a, 'de, 's> {}
+   |               ^^  ^^                                   ^^       ^^
+   |
+help: elide the lifetimes
+   |
+LL -     impl<'de, 'a, 's> Trait<'de> for UnitVariantAccess<'a, 'de, 's> {}
+LL +     impl<'de> Trait<'de> for UnitVariantAccess<'_, 'de, '_> {}
+   |
+
+error: the following explicit lifetimes could be elided: 'a
+  --> tests/ui/elidable_lifetime_names.rs:226:10
+   |
+LL |     impl<'a> T for S1<'a> {}
+   |          ^^           ^^
+   |
+help: elide the lifetimes
+   |
+LL -     impl<'a> T for S1<'a> {}
+LL +     impl T for S1<'_> {}
+   |
+
+error: the following explicit lifetimes could be elided: 'b
+  --> tests/ui/elidable_lifetime_names.rs:234:14
+   |
+LL |     impl<'a, 'b> TA<'a> for S2<'a, 'b> {}
+   |              ^^                    ^^
+   |
+help: elide the lifetimes
+   |
+LL -     impl<'a, 'b> TA<'a> for S2<'a, 'b> {}
+LL +     impl<'a> TA<'a> for S2<'a, '_> {}
+   |
+
+error: the following explicit lifetimes could be elided: 'a
+  --> tests/ui/elidable_lifetime_names.rs:238:10
+   |
+LL |     impl<'a, 'b> TB<'b> for S2<'a, 'b> {}
+   |          ^^                    ^^
+   |
+help: elide the lifetimes
+   |
+LL -     impl<'a, 'b> TB<'b> for S2<'a, 'b> {}
+LL +     impl<'b> TB<'b> for S2<'_, 'b> {}
+   |
+
+error: the following explicit lifetimes could be elided: 'a, 'b
+  --> tests/ui/elidable_lifetime_names.rs:242:10
+   |
+LL |     impl<'a, 'b> T for S2<'a, 'b> {}
+   |          ^^  ^^           ^^  ^^
+   |
+help: elide the lifetimes
+   |
+LL -     impl<'a, 'b> T for S2<'a, 'b> {}
+LL +     impl T for S2<'_, '_> {}
+   |
+
+error: the following explicit lifetimes could be elided: 'c
+  --> tests/ui/elidable_lifetime_names.rs:250:18
+   |
+LL |     impl<'a, 'b, 'c> TAB<'a, 'b> for S3<'a, 'b, 'c> {}
+   |                  ^^                             ^^
+   |
+help: elide the lifetimes
+   |
+LL -     impl<'a, 'b, 'c> TAB<'a, 'b> for S3<'a, 'b, 'c> {}
+LL +     impl<'a, 'b> TAB<'a, 'b> for S3<'a, 'b, '_> {}
+   |
+
+error: the following explicit lifetimes could be elided: 'b
+  --> tests/ui/elidable_lifetime_names.rs:254:14
+   |
+LL |     impl<'a, 'b, 'c> TAC<'a, 'c> for S3<'a, 'b, 'c> {}
+   |              ^^                             ^^
+   |
+help: elide the lifetimes
+   |
+LL -     impl<'a, 'b, 'c> TAC<'a, 'c> for S3<'a, 'b, 'c> {}
+LL +     impl<'a, 'c> TAC<'a, 'c> for S3<'a, '_, 'c> {}
+   |
+
+error: the following explicit lifetimes could be elided: 'b, 'c
+  --> tests/ui/elidable_lifetime_names.rs:258:14
+   |
+LL |     impl<'a, 'b, 'c> TA<'a> for S3<'a, 'b, 'c> {}
+   |              ^^  ^^                    ^^  ^^
+   |
+help: elide the lifetimes
+   |
+LL -     impl<'a, 'b, 'c> TA<'a> for S3<'a, 'b, 'c> {}
+LL +     impl<'a> TA<'a> for S3<'a, '_, '_> {}
+   |
+
+error: the following explicit lifetimes could be elided: 'a
+  --> tests/ui/elidable_lifetime_names.rs:262:10
+   |
+LL |     impl<'a, 'b, 'c> TBC<'b, 'c> for S3<'a, 'b, 'c> {}
+   |          ^^                             ^^
+   |
+help: elide the lifetimes
+   |
+LL -     impl<'a, 'b, 'c> TBC<'b, 'c> for S3<'a, 'b, 'c> {}
+LL +     impl<'b, 'c> TBC<'b, 'c> for S3<'_, 'b, 'c> {}
+   |
+
+error: the following explicit lifetimes could be elided: 'a, 'c
+  --> tests/ui/elidable_lifetime_names.rs:266:10
+   |
+LL |     impl<'a, 'b, 'c> TB<'b> for S3<'a, 'b, 'c> {}
+   |          ^^      ^^                ^^      ^^
+   |
+help: elide the lifetimes
+   |
+LL -     impl<'a, 'b, 'c> TB<'b> for S3<'a, 'b, 'c> {}
+LL +     impl<'b> TB<'b> for S3<'_, 'b, '_> {}
+   |
+
+error: the following explicit lifetimes could be elided: 'a, 'b
+  --> tests/ui/elidable_lifetime_names.rs:270:10
+   |
+LL |     impl<'a, 'b, 'c> TC<'c> for S3<'a, 'b, 'c> {}
+   |          ^^  ^^                    ^^  ^^
+   |
+help: elide the lifetimes
+   |
+LL -     impl<'a, 'b, 'c> TC<'c> for S3<'a, 'b, 'c> {}
+LL +     impl<'c> TC<'c> for S3<'_, '_, 'c> {}
+   |
+
+error: the following explicit lifetimes could be elided: 'a, 'b, 'c
+  --> tests/ui/elidable_lifetime_names.rs:274:10
+   |
+LL |     impl<'a, 'b, 'c> T for S3<'a, 'b, 'c> {}
+   |          ^^  ^^  ^^           ^^  ^^  ^^
+   |
+help: elide the lifetimes
+   |
+LL -     impl<'a, 'b, 'c> T for S3<'a, 'b, 'c> {}
+LL +     impl T for S3<'_, '_, '_> {}
+   |
+
+error: aborting due to 24 previous errors
 
diff --git a/src/tools/clippy/tests/ui/eta.fixed b/src/tools/clippy/tests/ui/eta.fixed
index 6944a979c05..107318e5323 100644
--- a/src/tools/clippy/tests/ui/eta.fixed
+++ b/src/tools/clippy/tests/ui/eta.fixed
@@ -635,3 +635,11 @@ fn issue8817() {
         //~| HELP: replace the closure with the tuple variant itself
         .unwrap(); // just for nicer formatting
 }
+
+async fn issue13892<'a, T, F>(maybe: Option<&'a T>, visitor: F)
+where
+    F: AsyncFn(&'a T),
+    T: 'a,
+{
+    maybe.map(|x| visitor(x));
+}
diff --git a/src/tools/clippy/tests/ui/eta.rs b/src/tools/clippy/tests/ui/eta.rs
index 5bcc1cb26fd..b85e8e75153 100644
--- a/src/tools/clippy/tests/ui/eta.rs
+++ b/src/tools/clippy/tests/ui/eta.rs
@@ -635,3 +635,11 @@ fn issue8817() {
         //~| HELP: replace the closure with the tuple variant itself
         .unwrap(); // just for nicer formatting
 }
+
+async fn issue13892<'a, T, F>(maybe: Option<&'a T>, visitor: F)
+where
+    F: AsyncFn(&'a T),
+    T: 'a,
+{
+    maybe.map(|x| visitor(x));
+}
diff --git a/src/tools/clippy/tests/ui/invalid_upcast_comparisons.rs b/src/tools/clippy/tests/ui/invalid_upcast_comparisons.rs
index 4f3194869f4..88ecca65e15 100644
--- a/src/tools/clippy/tests/ui/invalid_upcast_comparisons.rs
+++ b/src/tools/clippy/tests/ui/invalid_upcast_comparisons.rs
@@ -133,3 +133,15 @@ fn main() {
 
     -5 == (u32 as i32);
 }
+
+fn issue15662() {
+    macro_rules! add_one {
+        ($x:expr) => {
+            $x + 1
+        };
+    }
+
+    let x: u8 = 1;
+    (add_one!(x) as u32) > 300;
+    //~^ invalid_upcast_comparisons
+}
diff --git a/src/tools/clippy/tests/ui/invalid_upcast_comparisons.stderr b/src/tools/clippy/tests/ui/invalid_upcast_comparisons.stderr
index ef36f18eabc..cc042a7c4b0 100644
--- a/src/tools/clippy/tests/ui/invalid_upcast_comparisons.stderr
+++ b/src/tools/clippy/tests/ui/invalid_upcast_comparisons.stderr
@@ -163,5 +163,11 @@ error: because of the numeric bounds on `u8` prior to casting, this expression i
 LL |     -5 >= (u8 as i32);
    |     ^^^^^^^^^^^^^^^^^
 
-error: aborting due to 27 previous errors
+error: because of the numeric bounds on `add_one!(x)` prior to casting, this expression is always false
+  --> tests/ui/invalid_upcast_comparisons.rs:145:5
+   |
+LL |     (add_one!(x) as u32) > 300;
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 28 previous errors
 
diff --git a/src/tools/clippy/tests/ui/iter_overeager_cloned.fixed b/src/tools/clippy/tests/ui/iter_overeager_cloned.fixed
index b0e548f1790..4171f19469a 100644
--- a/src/tools/clippy/tests/ui/iter_overeager_cloned.fixed
+++ b/src/tools/clippy/tests/ui/iter_overeager_cloned.fixed
@@ -1,4 +1,4 @@
-#![warn(clippy::iter_overeager_cloned, clippy::redundant_clone, clippy::filter_next)]
+#![warn(clippy::iter_overeager_cloned, clippy::redundant_iter_cloned, clippy::filter_next)]
 #![allow(
     dead_code,
     clippy::let_unit_value,
@@ -16,7 +16,7 @@ fn main() {
     //~^ iter_overeager_cloned
 
     let _: usize = vec.iter().filter(|x| x == &"2").count();
-    //~^ redundant_clone
+    //~^ redundant_iter_cloned
 
     let _: Vec<_> = vec.iter().take(2).cloned().collect();
     //~^ iter_overeager_cloned
@@ -77,19 +77,19 @@ fn main() {
     }
 
     let _ = vec.iter().map(|x| x.len());
-    //~^ redundant_clone
+    //~^ redundant_iter_cloned
 
     // This would fail if changed.
     let _ = vec.iter().cloned().map(|x| x + "2");
 
     let _ = vec.iter().for_each(|x| assert!(!x.is_empty()));
-    //~^ redundant_clone
+    //~^ redundant_iter_cloned
 
     let _ = vec.iter().all(|x| x.len() == 1);
-    //~^ redundant_clone
+    //~^ redundant_iter_cloned
 
     let _ = vec.iter().any(|x| x.len() == 1);
-    //~^ redundant_clone
+    //~^ redundant_iter_cloned
 
     // Should probably stay as it is.
     let _ = [0, 1, 2, 3, 4].iter().cloned().take(10);
diff --git a/src/tools/clippy/tests/ui/iter_overeager_cloned.rs b/src/tools/clippy/tests/ui/iter_overeager_cloned.rs
index cedf62a6b47..fe6aba24dd3 100644
--- a/src/tools/clippy/tests/ui/iter_overeager_cloned.rs
+++ b/src/tools/clippy/tests/ui/iter_overeager_cloned.rs
@@ -1,4 +1,4 @@
-#![warn(clippy::iter_overeager_cloned, clippy::redundant_clone, clippy::filter_next)]
+#![warn(clippy::iter_overeager_cloned, clippy::redundant_iter_cloned, clippy::filter_next)]
 #![allow(
     dead_code,
     clippy::let_unit_value,
@@ -16,7 +16,7 @@ fn main() {
     //~^ iter_overeager_cloned
 
     let _: usize = vec.iter().filter(|x| x == &"2").cloned().count();
-    //~^ redundant_clone
+    //~^ redundant_iter_cloned
 
     let _: Vec<_> = vec.iter().cloned().take(2).collect();
     //~^ iter_overeager_cloned
@@ -78,19 +78,19 @@ fn main() {
     }
 
     let _ = vec.iter().cloned().map(|x| x.len());
-    //~^ redundant_clone
+    //~^ redundant_iter_cloned
 
     // This would fail if changed.
     let _ = vec.iter().cloned().map(|x| x + "2");
 
     let _ = vec.iter().cloned().for_each(|x| assert!(!x.is_empty()));
-    //~^ redundant_clone
+    //~^ redundant_iter_cloned
 
     let _ = vec.iter().cloned().all(|x| x.len() == 1);
-    //~^ redundant_clone
+    //~^ redundant_iter_cloned
 
     let _ = vec.iter().cloned().any(|x| x.len() == 1);
-    //~^ redundant_clone
+    //~^ redundant_iter_cloned
 
     // Should probably stay as it is.
     let _ = [0, 1, 2, 3, 4].iter().cloned().take(10);
diff --git a/src/tools/clippy/tests/ui/iter_overeager_cloned.stderr b/src/tools/clippy/tests/ui/iter_overeager_cloned.stderr
index 1616dec95b7..f234d19e4aa 100644
--- a/src/tools/clippy/tests/ui/iter_overeager_cloned.stderr
+++ b/src/tools/clippy/tests/ui/iter_overeager_cloned.stderr
@@ -25,8 +25,8 @@ LL |     let _: usize = vec.iter().filter(|x| x == &"2").cloned().count();
    |                                                    |
    |                                                    help: try: `.count()`
    |
-   = note: `-D clippy::redundant-clone` implied by `-D warnings`
-   = help: to override `-D warnings` add `#[allow(clippy::redundant_clone)]`
+   = note: `-D clippy::redundant-iter-cloned` implied by `-D warnings`
+   = help: to override `-D warnings` add `#[allow(clippy::redundant_iter_cloned)]`
 
 error: unnecessarily eager cloning of iterator items
   --> tests/ui/iter_overeager_cloned.rs:21:21
diff --git a/src/tools/clippy/tests/ui/match_as_ref.fixed b/src/tools/clippy/tests/ui/match_as_ref.fixed
index 8c07076af4a..a39f0c9299b 100644
--- a/src/tools/clippy/tests/ui/match_as_ref.fixed
+++ b/src/tools/clippy/tests/ui/match_as_ref.fixed
@@ -41,3 +41,33 @@ fn main() {
         None => None,
     };
 }
+
+mod issue15691 {
+    use std::ops::{Deref, DerefMut};
+
+    struct A(B);
+    struct B;
+
+    impl Deref for A {
+        type Target = B;
+        fn deref(&self) -> &Self::Target {
+            &self.0
+        }
+    }
+
+    impl DerefMut for A {
+        fn deref_mut(&mut self) -> &mut Self::Target {
+            &mut self.0
+        }
+    }
+
+    fn func() {
+        let mut a = Some(A(B));
+        let mut b = Some(B);
+        // Do not lint, we don't have `None => None`
+        let _ = match b {
+            Some(ref mut x) => Some(x),
+            None => a.as_deref_mut(),
+        };
+    }
+}
diff --git a/src/tools/clippy/tests/ui/match_as_ref.rs b/src/tools/clippy/tests/ui/match_as_ref.rs
index 3a5b1227331..04992816790 100644
--- a/src/tools/clippy/tests/ui/match_as_ref.rs
+++ b/src/tools/clippy/tests/ui/match_as_ref.rs
@@ -53,3 +53,33 @@ fn main() {
         None => None,
     };
 }
+
+mod issue15691 {
+    use std::ops::{Deref, DerefMut};
+
+    struct A(B);
+    struct B;
+
+    impl Deref for A {
+        type Target = B;
+        fn deref(&self) -> &Self::Target {
+            &self.0
+        }
+    }
+
+    impl DerefMut for A {
+        fn deref_mut(&mut self) -> &mut Self::Target {
+            &mut self.0
+        }
+    }
+
+    fn func() {
+        let mut a = Some(A(B));
+        let mut b = Some(B);
+        // Do not lint, we don't have `None => None`
+        let _ = match b {
+            Some(ref mut x) => Some(x),
+            None => a.as_deref_mut(),
+        };
+    }
+}
diff --git a/src/tools/clippy/tests/ui/multiple_unsafe_ops_per_block.rs b/src/tools/clippy/tests/ui/multiple_unsafe_ops_per_block.rs
index 016fd89a7b7..132673d5164 100644
--- a/src/tools/clippy/tests/ui/multiple_unsafe_ops_per_block.rs
+++ b/src/tools/clippy/tests/ui/multiple_unsafe_ops_per_block.rs
@@ -1,10 +1,10 @@
 //@needs-asm-support
 //@aux-build:proc_macros.rs
-#![allow(unused)]
-#![allow(deref_nullptr)]
-#![allow(clippy::unnecessary_operation)]
-#![allow(dropping_copy_types)]
-#![allow(clippy::assign_op_pattern)]
+#![expect(
+    dropping_copy_types,
+    clippy::unnecessary_operation,
+    clippy::unnecessary_literal_unwrap
+)]
 #![warn(clippy::multiple_unsafe_ops_per_block)]
 
 extern crate proc_macros;
@@ -105,17 +105,17 @@ fn correct3() {
     }
 }
 
-// tests from the issue (https://github.com/rust-lang/rust-clippy/issues/10064)
-
-unsafe fn read_char_bad(ptr: *const u8) -> char {
-    unsafe { char::from_u32_unchecked(*ptr.cast::<u32>()) }
-    //~^ multiple_unsafe_ops_per_block
-}
+fn issue10064() {
+    unsafe fn read_char_bad(ptr: *const u8) -> char {
+        unsafe { char::from_u32_unchecked(*ptr.cast::<u32>()) }
+        //~^ multiple_unsafe_ops_per_block
+    }
 
-// no lint
-unsafe fn read_char_good(ptr: *const u8) -> char {
-    let int_value = unsafe { *ptr.cast::<u32>() };
-    unsafe { core::char::from_u32_unchecked(int_value) }
+    // no lint
+    unsafe fn read_char_good(ptr: *const u8) -> char {
+        let int_value = unsafe { *ptr.cast::<u32>() };
+        unsafe { core::char::from_u32_unchecked(int_value) }
+    }
 }
 
 // no lint
@@ -126,42 +126,87 @@ fn issue10259() {
     });
 }
 
-fn _fn_ptr(x: unsafe fn()) {
-    unsafe {
-        //~^ multiple_unsafe_ops_per_block
-        x();
-        x();
+fn issue10367() {
+    fn fn_ptr(x: unsafe fn()) {
+        unsafe {
+            //~^ multiple_unsafe_ops_per_block
+            x();
+            x();
+        }
     }
-}
 
-fn _assoc_const() {
-    trait X {
-        const X: unsafe fn();
+    fn assoc_const() {
+        trait X {
+            const X: unsafe fn();
+        }
+        fn _f<T: X>() {
+            unsafe {
+                //~^ multiple_unsafe_ops_per_block
+                T::X();
+                T::X();
+            }
+        }
     }
-    fn _f<T: X>() {
+
+    fn field_fn_ptr(x: unsafe fn()) {
+        struct X(unsafe fn());
+        let x = X(x);
         unsafe {
             //~^ multiple_unsafe_ops_per_block
-            T::X();
-            T::X();
+            x.0();
+            x.0();
         }
     }
 }
 
-fn _field_fn_ptr(x: unsafe fn()) {
-    struct X(unsafe fn());
-    let x = X(x);
+// await expands to an unsafe block with several operations, but this is fine.
+async fn issue11312() {
+    async fn helper() {}
+
+    helper().await;
+}
+
+async fn issue13879() {
+    async fn foo() {}
+
+    // no lint: nothing unsafe beyond the `await` which we ignore
+    unsafe {
+        foo().await;
+    }
+
+    // no lint: only one unsafe call beyond the `await`
+    unsafe {
+        not_very_safe();
+        foo().await;
+    }
+
+    // lint: two unsafe calls beyond the `await`
     unsafe {
         //~^ multiple_unsafe_ops_per_block
-        x.0();
-        x.0();
+        not_very_safe();
+        STATIC += 1;
+        foo().await;
     }
-}
 
-// await expands to an unsafe block with several operations, but this is fine.: #11312
-async fn await_desugaring_silent() {
-    async fn helper() {}
+    async unsafe fn foo_unchecked() {}
 
-    helper().await;
+    // no lint: only one unsafe call in the `await`ed expr
+    unsafe {
+        foo_unchecked().await;
+    }
+
+    // lint: one unsafe call in the `await`ed expr, and one outside
+    unsafe {
+        //~^ multiple_unsafe_ops_per_block
+        not_very_safe();
+        foo_unchecked().await;
+    }
+
+    // lint: two unsafe calls in the `await`ed expr
+    unsafe {
+        //~^ multiple_unsafe_ops_per_block
+        Some(foo_unchecked()).unwrap_unchecked().await;
+    }
 }
 
 fn main() {}
diff --git a/src/tools/clippy/tests/ui/multiple_unsafe_ops_per_block.stderr b/src/tools/clippy/tests/ui/multiple_unsafe_ops_per_block.stderr
index 3130cecc252..922a464c6b6 100644
--- a/src/tools/clippy/tests/ui/multiple_unsafe_ops_per_block.stderr
+++ b/src/tools/clippy/tests/ui/multiple_unsafe_ops_per_block.stderr
@@ -113,84 +113,147 @@ LL |         asm!("nop");
    |         ^^^^^^^^^^^
 
 error: this `unsafe` block contains 2 unsafe operations, expected only one
-  --> tests/ui/multiple_unsafe_ops_per_block.rs:111:5
+  --> tests/ui/multiple_unsafe_ops_per_block.rs:110:9
    |
-LL |     unsafe { char::from_u32_unchecked(*ptr.cast::<u32>()) }
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL |         unsafe { char::from_u32_unchecked(*ptr.cast::<u32>()) }
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
 note: unsafe function call occurs here
-  --> tests/ui/multiple_unsafe_ops_per_block.rs:111:14
+  --> tests/ui/multiple_unsafe_ops_per_block.rs:110:18
    |
-LL |     unsafe { char::from_u32_unchecked(*ptr.cast::<u32>()) }
-   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL |         unsafe { char::from_u32_unchecked(*ptr.cast::<u32>()) }
+   |                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 note: raw pointer dereference occurs here
-  --> tests/ui/multiple_unsafe_ops_per_block.rs:111:39
+  --> tests/ui/multiple_unsafe_ops_per_block.rs:110:43
    |
-LL |     unsafe { char::from_u32_unchecked(*ptr.cast::<u32>()) }
-   |                                       ^^^^^^^^^^^^^^^^^^
+LL |         unsafe { char::from_u32_unchecked(*ptr.cast::<u32>()) }
+   |                                           ^^^^^^^^^^^^^^^^^^
 
 error: this `unsafe` block contains 2 unsafe operations, expected only one
-  --> tests/ui/multiple_unsafe_ops_per_block.rs:130:5
+  --> tests/ui/multiple_unsafe_ops_per_block.rs:131:9
    |
-LL | /     unsafe {
+LL | /         unsafe {
 LL | |
-LL | |         x();
-LL | |         x();
-LL | |     }
-   | |_____^
+LL | |             x();
+LL | |             x();
+LL | |         }
+   | |_________^
    |
 note: unsafe function call occurs here
-  --> tests/ui/multiple_unsafe_ops_per_block.rs:132:9
+  --> tests/ui/multiple_unsafe_ops_per_block.rs:133:13
    |
-LL |         x();
-   |         ^^^
+LL |             x();
+   |             ^^^
 note: unsafe function call occurs here
-  --> tests/ui/multiple_unsafe_ops_per_block.rs:133:9
+  --> tests/ui/multiple_unsafe_ops_per_block.rs:134:13
    |
-LL |         x();
-   |         ^^^
+LL |             x();
+   |             ^^^
 
 error: this `unsafe` block contains 2 unsafe operations, expected only one
-  --> tests/ui/multiple_unsafe_ops_per_block.rs:142:9
+  --> tests/ui/multiple_unsafe_ops_per_block.rs:143:13
+   |
+LL | /             unsafe {
+LL | |
+LL | |                 T::X();
+LL | |                 T::X();
+LL | |             }
+   | |_____________^
+   |
+note: unsafe function call occurs here
+  --> tests/ui/multiple_unsafe_ops_per_block.rs:145:17
+   |
+LL |                 T::X();
+   |                 ^^^^^^
+note: unsafe function call occurs here
+  --> tests/ui/multiple_unsafe_ops_per_block.rs:146:17
+   |
+LL |                 T::X();
+   |                 ^^^^^^
+
+error: this `unsafe` block contains 2 unsafe operations, expected only one
+  --> tests/ui/multiple_unsafe_ops_per_block.rs:154:9
    |
 LL | /         unsafe {
 LL | |
-LL | |             T::X();
-LL | |             T::X();
+LL | |             x.0();
+LL | |             x.0();
 LL | |         }
    | |_________^
    |
 note: unsafe function call occurs here
-  --> tests/ui/multiple_unsafe_ops_per_block.rs:144:13
+  --> tests/ui/multiple_unsafe_ops_per_block.rs:156:13
    |
-LL |             T::X();
-   |             ^^^^^^
+LL |             x.0();
+   |             ^^^^^
 note: unsafe function call occurs here
-  --> tests/ui/multiple_unsafe_ops_per_block.rs:145:13
+  --> tests/ui/multiple_unsafe_ops_per_block.rs:157:13
    |
-LL |             T::X();
-   |             ^^^^^^
+LL |             x.0();
+   |             ^^^^^
 
 error: this `unsafe` block contains 2 unsafe operations, expected only one
-  --> tests/ui/multiple_unsafe_ops_per_block.rs:153:5
+  --> tests/ui/multiple_unsafe_ops_per_block.rs:184:5
    |
 LL | /     unsafe {
 LL | |
-LL | |         x.0();
-LL | |         x.0();
+LL | |         not_very_safe();
+LL | |         STATIC += 1;
+LL | |         foo().await;
 LL | |     }
    | |_____^
    |
 note: unsafe function call occurs here
-  --> tests/ui/multiple_unsafe_ops_per_block.rs:155:9
+  --> tests/ui/multiple_unsafe_ops_per_block.rs:186:9
+   |
+LL |         not_very_safe();
+   |         ^^^^^^^^^^^^^^^
+note: modification of a mutable static occurs here
+  --> tests/ui/multiple_unsafe_ops_per_block.rs:187:9
+   |
+LL |         STATIC += 1;
+   |         ^^^^^^^^^^^
+
+error: this `unsafe` block contains 2 unsafe operations, expected only one
+  --> tests/ui/multiple_unsafe_ops_per_block.rs:199:5
+   |
+LL | /     unsafe {
+LL | |
+LL | |         not_very_safe();
+LL | |         foo_unchecked().await;
+LL | |     }
+   | |_____^
+   |
+note: unsafe function call occurs here
+  --> tests/ui/multiple_unsafe_ops_per_block.rs:201:9
+   |
+LL |         not_very_safe();
+   |         ^^^^^^^^^^^^^^^
+note: unsafe function call occurs here
+  --> tests/ui/multiple_unsafe_ops_per_block.rs:202:9
+   |
+LL |         foo_unchecked().await;
+   |         ^^^^^^^^^^^^^^^
+
+error: this `unsafe` block contains 2 unsafe operations, expected only one
+  --> tests/ui/multiple_unsafe_ops_per_block.rs:206:5
+   |
+LL | /     unsafe {
+LL | |
+LL | |         Some(foo_unchecked()).unwrap_unchecked().await;
+LL | |     }
+   | |_____^
+   |
+note: unsafe method call occurs here
+  --> tests/ui/multiple_unsafe_ops_per_block.rs:208:9
    |
-LL |         x.0();
-   |         ^^^^^
+LL |         Some(foo_unchecked()).unwrap_unchecked().await;
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 note: unsafe function call occurs here
-  --> tests/ui/multiple_unsafe_ops_per_block.rs:156:9
+  --> tests/ui/multiple_unsafe_ops_per_block.rs:208:14
    |
-LL |         x.0();
-   |         ^^^^^
+LL |         Some(foo_unchecked()).unwrap_unchecked().await;
+   |              ^^^^^^^^^^^^^^^
 
-error: aborting due to 8 previous errors
+error: aborting due to 11 previous errors
 
diff --git a/src/tools/clippy/tests/ui/needless_return.fixed b/src/tools/clippy/tests/ui/needless_return.fixed
index d571b97f519..f5f8bb21e81 100644
--- a/src/tools/clippy/tests/ui/needless_return.fixed
+++ b/src/tools/clippy/tests/ui/needless_return.fixed
@@ -517,3 +517,10 @@ mod else_ifs {
         }
     }
 }
+
+fn issue14474() -> u64 {
+    return 456;
+
+    #[cfg(false)]
+    123
+}
diff --git a/src/tools/clippy/tests/ui/needless_return.rs b/src/tools/clippy/tests/ui/needless_return.rs
index 2e4348ea338..495516c1c2e 100644
--- a/src/tools/clippy/tests/ui/needless_return.rs
+++ b/src/tools/clippy/tests/ui/needless_return.rs
@@ -526,3 +526,10 @@ mod else_ifs {
         }
     }
 }
+
+fn issue14474() -> u64 {
+    return 456;
+
+    #[cfg(false)]
+    123
+}
diff --git a/src/tools/clippy/tests/ui/never_loop.rs b/src/tools/clippy/tests/ui/never_loop.rs
index 48d4b8ad151..01db64a446c 100644
--- a/src/tools/clippy/tests/ui/never_loop.rs
+++ b/src/tools/clippy/tests/ui/never_loop.rs
@@ -498,3 +498,27 @@ fn issue15059() {
         ()
     }
 }
+
+fn issue15350() {
+    'bar: for _ in 0..100 {
+        //~^ never_loop
+        loop {
+            //~^ never_loop
+            println!("This will still run");
+            break 'bar;
+        }
+    }
+
+    'foo: for _ in 0..100 {
+        //~^ never_loop
+        loop {
+            //~^ never_loop
+            println!("This will still run");
+            loop {
+                //~^ never_loop
+                println!("This will still run");
+                break 'foo;
+            }
+        }
+    }
+}
diff --git a/src/tools/clippy/tests/ui/never_loop.stderr b/src/tools/clippy/tests/ui/never_loop.stderr
index 54b463266a3..4fda06cff4a 100644
--- a/src/tools/clippy/tests/ui/never_loop.stderr
+++ b/src/tools/clippy/tests/ui/never_loop.stderr
@@ -193,6 +193,19 @@ LL | |         return;
 LL | |     }
    | |_____^
    |
+help: this code is unreachable. Consider moving the reachable parts out
+  --> tests/ui/never_loop.rs:436:9
+   |
+LL | /         loop {
+LL | |
+LL | |             break 'outer;
+LL | |         }
+   | |_________^
+help: this code is unreachable. Consider moving the reachable parts out
+  --> tests/ui/never_loop.rs:440:9
+   |
+LL |         return;
+   |         ^^^^^^^
 help: if you need the first element of the iterator, try writing
    |
 LL -     'outer: for v in 0..10 {
@@ -297,5 +310,87 @@ LL ~
 LL ~         
    |
 
-error: aborting due to 24 previous errors
+error: this loop never actually loops
+  --> tests/ui/never_loop.rs:503:5
+   |
+LL | /     'bar: for _ in 0..100 {
+LL | |
+LL | |         loop {
+...  |
+LL | |     }
+   | |_____^
+   |
+help: this code is unreachable. Consider moving the reachable parts out
+  --> tests/ui/never_loop.rs:505:9
+   |
+LL | /         loop {
+LL | |
+LL | |             println!("This will still run");
+LL | |             break 'bar;
+LL | |         }
+   | |_________^
+help: if you need the first element of the iterator, try writing
+   |
+LL -     'bar: for _ in 0..100 {
+LL +     if let Some(_) = (0..100).next() {
+   |
+
+error: this loop never actually loops
+  --> tests/ui/never_loop.rs:505:9
+   |
+LL | /         loop {
+LL | |
+LL | |             println!("This will still run");
+LL | |             break 'bar;
+LL | |         }
+   | |_________^
+
+error: this loop never actually loops
+  --> tests/ui/never_loop.rs:512:5
+   |
+LL | /     'foo: for _ in 0..100 {
+LL | |
+LL | |         loop {
+...  |
+LL | |     }
+   | |_____^
+   |
+help: this code is unreachable. Consider moving the reachable parts out
+  --> tests/ui/never_loop.rs:514:9
+   |
+LL | /         loop {
+LL | |
+LL | |             println!("This will still run");
+LL | |             loop {
+...  |
+LL | |         }
+   | |_________^
+help: if you need the first element of the iterator, try writing
+   |
+LL -     'foo: for _ in 0..100 {
+LL +     if let Some(_) = (0..100).next() {
+   |
+
+error: this loop never actually loops
+  --> tests/ui/never_loop.rs:514:9
+   |
+LL | /         loop {
+LL | |
+LL | |             println!("This will still run");
+LL | |             loop {
+...  |
+LL | |         }
+   | |_________^
+
+error: this loop never actually loops
+  --> tests/ui/never_loop.rs:517:13
+   |
+LL | /             loop {
+LL | |
+LL | |                 println!("This will still run");
+LL | |                 break 'foo;
+LL | |             }
+   | |_____________^
+
+error: aborting due to 29 previous errors
 
diff --git a/src/tools/clippy/tests/ui/option_if_let_else.fixed b/src/tools/clippy/tests/ui/option_if_let_else.fixed
index 0f86de5646c..6ce067f5c24 100644
--- a/src/tools/clippy/tests/ui/option_if_let_else.fixed
+++ b/src/tools/clippy/tests/ui/option_if_let_else.fixed
@@ -125,6 +125,16 @@ fn complex_subpat() -> DummyEnum {
     DummyEnum::Two
 }
 
+// #10335
+pub fn test_result_err_ignored_1(r: Result<&[u8], &[u8]>) -> Vec<u8> {
+    r.map_or_else(|_| Vec::new(), |s| s.to_owned())
+}
+
+// #10335
+pub fn test_result_err_ignored_2(r: Result<&[u8], &[u8]>) -> Vec<u8> {
+    r.map_or_else(|_| Vec::new(), |s| s.to_owned())
+}
+
 fn main() {
     let optional = Some(5);
     let _ = optional.map_or(5, |x| x + 2);
diff --git a/src/tools/clippy/tests/ui/option_if_let_else.rs b/src/tools/clippy/tests/ui/option_if_let_else.rs
index 7aabd778f87..096d3aabf28 100644
--- a/src/tools/clippy/tests/ui/option_if_let_else.rs
+++ b/src/tools/clippy/tests/ui/option_if_let_else.rs
@@ -152,6 +152,22 @@ fn complex_subpat() -> DummyEnum {
     DummyEnum::Two
 }
 
+// #10335
+pub fn test_result_err_ignored_1(r: Result<&[u8], &[u8]>) -> Vec<u8> {
+    match r {
+        //~^ option_if_let_else
+        Ok(s) => s.to_owned(),
+        Err(_) => Vec::new(),
+    }
+}
+
+// #10335
+pub fn test_result_err_ignored_2(r: Result<&[u8], &[u8]>) -> Vec<u8> {
+    if let Ok(s) = r { s.to_owned() }
+    //~^ option_if_let_else
+    else { Vec::new() }
+}
+
 fn main() {
     let optional = Some(5);
     let _ = if let Some(x) = optional { x + 2 } else { 5 };
diff --git a/src/tools/clippy/tests/ui/option_if_let_else.stderr b/src/tools/clippy/tests/ui/option_if_let_else.stderr
index 2e2fe6f2049..21a80ae038d 100644
--- a/src/tools/clippy/tests/ui/option_if_let_else.stderr
+++ b/src/tools/clippy/tests/ui/option_if_let_else.stderr
@@ -188,14 +188,32 @@ LL +         true
 LL +     })
    |
 
+error: use Option::map_or_else instead of an if let/else
+  --> tests/ui/option_if_let_else.rs:157:5
+   |
+LL | /     match r {
+LL | |
+LL | |         Ok(s) => s.to_owned(),
+LL | |         Err(_) => Vec::new(),
+LL | |     }
+   | |_____^ help: try: `r.map_or_else(|_| Vec::new(), |s| s.to_owned())`
+
+error: use Option::map_or_else instead of an if let/else
+  --> tests/ui/option_if_let_else.rs:166:5
+   |
+LL | /     if let Ok(s) = r { s.to_owned() }
+LL | |
+LL | |     else { Vec::new() }
+   | |_______________________^ help: try: `r.map_or_else(|_| Vec::new(), |s| s.to_owned())`
+
 error: use Option::map_or instead of an if let/else
-  --> tests/ui/option_if_let_else.rs:157:13
+  --> tests/ui/option_if_let_else.rs:173:13
    |
 LL |     let _ = if let Some(x) = optional { x + 2 } else { 5 };
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `optional.map_or(5, |x| x + 2)`
 
 error: use Option::map_or instead of an if let/else
-  --> tests/ui/option_if_let_else.rs:168:13
+  --> tests/ui/option_if_let_else.rs:184:13
    |
 LL |       let _ = if let Some(x) = Some(0) {
    |  _____________^
@@ -217,13 +235,13 @@ LL ~         });
    |
 
 error: use Option::map_or instead of an if let/else
-  --> tests/ui/option_if_let_else.rs:197:13
+  --> tests/ui/option_if_let_else.rs:213:13
    |
 LL |     let _ = if let Some(x) = Some(0) { s.len() + x } else { s.len() };
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Some(0).map_or(s.len(), |x| s.len() + x)`
 
 error: use Option::map_or instead of an if let/else
-  --> tests/ui/option_if_let_else.rs:202:13
+  --> tests/ui/option_if_let_else.rs:218:13
    |
 LL |       let _ = if let Some(x) = Some(0) {
    |  _____________^
@@ -245,7 +263,7 @@ LL ~     });
    |
 
 error: use Option::map_or instead of an if let/else
-  --> tests/ui/option_if_let_else.rs:242:13
+  --> tests/ui/option_if_let_else.rs:258:13
    |
 LL |       let _ = match s {
    |  _____________^
@@ -256,7 +274,7 @@ LL | |     };
    | |_____^ help: try: `s.map_or(1, |string| string.len())`
 
 error: use Option::map_or instead of an if let/else
-  --> tests/ui/option_if_let_else.rs:247:13
+  --> tests/ui/option_if_let_else.rs:263:13
    |
 LL |       let _ = match Some(10) {
    |  _____________^
@@ -267,7 +285,7 @@ LL | |     };
    | |_____^ help: try: `Some(10).map_or(5, |a| a + 1)`
 
 error: use Option::map_or instead of an if let/else
-  --> tests/ui/option_if_let_else.rs:254:13
+  --> tests/ui/option_if_let_else.rs:270:13
    |
 LL |       let _ = match res {
    |  _____________^
@@ -278,7 +296,7 @@ LL | |     };
    | |_____^ help: try: `res.map_or(1, |a| a + 1)`
 
 error: use Option::map_or instead of an if let/else
-  --> tests/ui/option_if_let_else.rs:259:13
+  --> tests/ui/option_if_let_else.rs:275:13
    |
 LL |       let _ = match res {
    |  _____________^
@@ -289,13 +307,13 @@ LL | |     };
    | |_____^ help: try: `res.map_or(1, |a| a + 1)`
 
 error: use Option::map_or instead of an if let/else
-  --> tests/ui/option_if_let_else.rs:264:13
+  --> tests/ui/option_if_let_else.rs:280:13
    |
 LL |     let _ = if let Ok(a) = res { a + 1 } else { 5 };
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `res.map_or(5, |a| a + 1)`
 
 error: use Option::map_or instead of an if let/else
-  --> tests/ui/option_if_let_else.rs:282:17
+  --> tests/ui/option_if_let_else.rs:298:17
    |
 LL |           let _ = match initial {
    |  _________________^
@@ -306,7 +324,7 @@ LL | |         };
    | |_________^ help: try: `initial.as_ref().map_or(42, |value| do_something(value))`
 
 error: use Option::map_or instead of an if let/else
-  --> tests/ui/option_if_let_else.rs:290:17
+  --> tests/ui/option_if_let_else.rs:306:17
    |
 LL |           let _ = match initial {
    |  _________________^
@@ -317,7 +335,7 @@ LL | |         };
    | |_________^ help: try: `initial.as_mut().map_or(42, |value| do_something2(value))`
 
 error: use Option::map_or_else instead of an if let/else
-  --> tests/ui/option_if_let_else.rs:314:24
+  --> tests/ui/option_if_let_else.rs:330:24
    |
 LL |       let mut _hashmap = if let Some(hm) = &opt {
    |  ________________________^
@@ -329,19 +347,19 @@ LL | |     };
    | |_____^ help: try: `opt.as_ref().map_or_else(HashMap::new, |hm| hm.clone())`
 
 error: use Option::map_or_else instead of an if let/else
-  --> tests/ui/option_if_let_else.rs:321:19
+  --> tests/ui/option_if_let_else.rs:337:19
    |
 LL |     let mut _hm = if let Some(hm) = &opt { hm.clone() } else { new_map!() };
    |                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `opt.as_ref().map_or_else(|| new_map!(), |hm| hm.clone())`
 
 error: use Option::map_or instead of an if let/else
-  --> tests/ui/option_if_let_else.rs:372:22
+  --> tests/ui/option_if_let_else.rs:388:22
    |
 LL |     let _ = unsafe { if let Some(o) = *opt_raw_ptr { o } else { 1 } };
    |                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `(*opt_raw_ptr).map_or(1, |o| o)`
 
 error: use Option::map_or_else instead of an if let/else
-  --> tests/ui/option_if_let_else.rs:378:13
+  --> tests/ui/option_if_let_else.rs:394:13
    |
 LL |       let _ = match res {
    |  _____________^
@@ -351,5 +369,5 @@ LL | |         Err(_) => String::new(),
 LL | |     };
    | |_____^ help: try: `res.map_or_else(|_| String::new(), |s| s.clone())`
 
-error: aborting due to 27 previous errors
+error: aborting due to 29 previous errors
 
diff --git a/src/tools/clippy/tests/ui/or_fun_call.fixed b/src/tools/clippy/tests/ui/or_fun_call.fixed
index 0a8525a12f5..7a0be97017e 100644
--- a/src/tools/clippy/tests/ui/or_fun_call.fixed
+++ b/src/tools/clippy/tests/ui/or_fun_call.fixed
@@ -77,6 +77,22 @@ fn or_fun_call() {
     with_default_type.unwrap_or_default();
     //~^ unwrap_or_default
 
+    let with_default_literal = Some(1);
+    with_default_literal.unwrap_or(0);
+    // Do not lint because `.unwrap_or_default()` wouldn't be simpler
+
+    let with_default_literal = Some(1.0);
+    with_default_literal.unwrap_or(0.0);
+    // Do not lint because `.unwrap_or_default()` wouldn't be simpler
+
+    let with_default_literal = Some("foo");
+    with_default_literal.unwrap_or("");
+    // Do not lint because `.unwrap_or_default()` wouldn't be simpler
+
+    let with_default_vec_macro = Some(vec![1, 2, 3]);
+    with_default_vec_macro.unwrap_or(vec![]);
+    // Do not lint because `.unwrap_or_default()` wouldn't be simpler
+
     let self_default = None::<FakeDefault>;
     self_default.unwrap_or_else(<FakeDefault>::default);
     //~^ or_fun_call
diff --git a/src/tools/clippy/tests/ui/or_fun_call.rs b/src/tools/clippy/tests/ui/or_fun_call.rs
index b4f9b950a7f..724af606de9 100644
--- a/src/tools/clippy/tests/ui/or_fun_call.rs
+++ b/src/tools/clippy/tests/ui/or_fun_call.rs
@@ -77,6 +77,22 @@ fn or_fun_call() {
     with_default_type.unwrap_or(u64::default());
     //~^ unwrap_or_default
 
+    let with_default_literal = Some(1);
+    with_default_literal.unwrap_or(0);
+    // Do not lint because `.unwrap_or_default()` wouldn't be simpler
+
+    let with_default_literal = Some(1.0);
+    with_default_literal.unwrap_or(0.0);
+    // Do not lint because `.unwrap_or_default()` wouldn't be simpler
+
+    let with_default_literal = Some("foo");
+    with_default_literal.unwrap_or("");
+    // Do not lint because `.unwrap_or_default()` wouldn't be simpler
+
+    let with_default_vec_macro = Some(vec![1, 2, 3]);
+    with_default_vec_macro.unwrap_or(vec![]);
+    // Do not lint because `.unwrap_or_default()` wouldn't be simpler
+
     let self_default = None::<FakeDefault>;
     self_default.unwrap_or(<FakeDefault>::default());
     //~^ or_fun_call
@@ -86,7 +102,7 @@ fn or_fun_call() {
     //~^ unwrap_or_default
 
     let with_vec = Some(vec![1]);
-    with_vec.unwrap_or(vec![]);
+    with_vec.unwrap_or(Vec::new());
     //~^ unwrap_or_default
 
     let without_default = Some(Foo);
@@ -98,7 +114,7 @@ fn or_fun_call() {
     //~^ unwrap_or_default
 
     let mut map_vec = HashMap::<u64, Vec<i32>>::new();
-    map_vec.entry(42).or_insert(vec![]);
+    map_vec.entry(42).or_insert(Vec::new());
     //~^ unwrap_or_default
 
     let mut btree = BTreeMap::<u64, String>::new();
@@ -106,7 +122,7 @@ fn or_fun_call() {
     //~^ unwrap_or_default
 
     let mut btree_vec = BTreeMap::<u64, Vec<i32>>::new();
-    btree_vec.entry(42).or_insert(vec![]);
+    btree_vec.entry(42).or_insert(Vec::new());
     //~^ unwrap_or_default
 
     let stringy = Some(String::new());
diff --git a/src/tools/clippy/tests/ui/or_fun_call.stderr b/src/tools/clippy/tests/ui/or_fun_call.stderr
index 3e4df772668..40b25f91154 100644
--- a/src/tools/clippy/tests/ui/or_fun_call.stderr
+++ b/src/tools/clippy/tests/ui/or_fun_call.stderr
@@ -47,175 +47,175 @@ LL |     with_default_type.unwrap_or(u64::default());
    |                       ^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_default()`
 
 error: function call inside of `unwrap_or`
-  --> tests/ui/or_fun_call.rs:81:18
+  --> tests/ui/or_fun_call.rs:97:18
    |
 LL |     self_default.unwrap_or(<FakeDefault>::default());
    |                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_else(<FakeDefault>::default)`
 
 error: use of `unwrap_or` to construct default value
-  --> tests/ui/or_fun_call.rs:85:18
+  --> tests/ui/or_fun_call.rs:101:18
    |
 LL |     real_default.unwrap_or(<FakeDefault as Default>::default());
    |                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_default()`
 
 error: use of `unwrap_or` to construct default value
-  --> tests/ui/or_fun_call.rs:89:14
+  --> tests/ui/or_fun_call.rs:105:14
    |
-LL |     with_vec.unwrap_or(vec![]);
-   |              ^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_default()`
+LL |     with_vec.unwrap_or(Vec::new());
+   |              ^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_default()`
 
 error: function call inside of `unwrap_or`
-  --> tests/ui/or_fun_call.rs:93:21
+  --> tests/ui/or_fun_call.rs:109:21
    |
 LL |     without_default.unwrap_or(Foo::new());
    |                     ^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_else(Foo::new)`
 
 error: use of `or_insert` to construct default value
-  --> tests/ui/or_fun_call.rs:97:19
+  --> tests/ui/or_fun_call.rs:113:19
    |
 LL |     map.entry(42).or_insert(String::new());
    |                   ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `or_default()`
 
 error: use of `or_insert` to construct default value
-  --> tests/ui/or_fun_call.rs:101:23
+  --> tests/ui/or_fun_call.rs:117:23
    |
-LL |     map_vec.entry(42).or_insert(vec![]);
-   |                       ^^^^^^^^^^^^^^^^^ help: try: `or_default()`
+LL |     map_vec.entry(42).or_insert(Vec::new());
+   |                       ^^^^^^^^^^^^^^^^^^^^^ help: try: `or_default()`
 
 error: use of `or_insert` to construct default value
-  --> tests/ui/or_fun_call.rs:105:21
+  --> tests/ui/or_fun_call.rs:121:21
    |
 LL |     btree.entry(42).or_insert(String::new());
    |                     ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `or_default()`
 
 error: use of `or_insert` to construct default value
-  --> tests/ui/or_fun_call.rs:109:25
+  --> tests/ui/or_fun_call.rs:125:25
    |
-LL |     btree_vec.entry(42).or_insert(vec![]);
-   |                         ^^^^^^^^^^^^^^^^^ help: try: `or_default()`
+LL |     btree_vec.entry(42).or_insert(Vec::new());
+   |                         ^^^^^^^^^^^^^^^^^^^^^ help: try: `or_default()`
 
 error: use of `unwrap_or` to construct default value
-  --> tests/ui/or_fun_call.rs:113:21
+  --> tests/ui/or_fun_call.rs:129:21
    |
 LL |     let _ = stringy.unwrap_or(String::new());
    |                     ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_default()`
 
 error: function call inside of `ok_or`
-  --> tests/ui/or_fun_call.rs:118:17
+  --> tests/ui/or_fun_call.rs:134:17
    |
 LL |     let _ = opt.ok_or(format!("{} world.", hello));
    |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `ok_or_else(|| format!("{} world.", hello))`
 
 error: function call inside of `unwrap_or`
-  --> tests/ui/or_fun_call.rs:123:21
+  --> tests/ui/or_fun_call.rs:139:21
    |
 LL |     let _ = Some(1).unwrap_or(map[&1]);
    |                     ^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_else(|| map[&1])`
 
 error: function call inside of `unwrap_or`
-  --> tests/ui/or_fun_call.rs:126:21
+  --> tests/ui/or_fun_call.rs:142:21
    |
 LL |     let _ = Some(1).unwrap_or(map[&1]);
    |                     ^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_else(|| map[&1])`
 
 error: function call inside of `or`
-  --> tests/ui/or_fun_call.rs:151:35
+  --> tests/ui/or_fun_call.rs:167:35
    |
 LL |     let _ = Some("a".to_string()).or(Some("b".to_string()));
    |                                   ^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `or_else(|| Some("b".to_string()))`
 
 error: function call inside of `unwrap_or`
-  --> tests/ui/or_fun_call.rs:194:18
+  --> tests/ui/or_fun_call.rs:210:18
    |
 LL |             None.unwrap_or(ptr_to_ref(s));
    |                  ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_else(|| ptr_to_ref(s))`
 
 error: function call inside of `unwrap_or`
-  --> tests/ui/or_fun_call.rs:202:14
+  --> tests/ui/or_fun_call.rs:218:14
    |
 LL |         None.unwrap_or(unsafe { ptr_to_ref(s) });
    |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_else(|| unsafe { ptr_to_ref(s) })`
 
 error: function call inside of `unwrap_or`
-  --> tests/ui/or_fun_call.rs:205:14
+  --> tests/ui/or_fun_call.rs:221:14
    |
 LL |         None.unwrap_or( unsafe { ptr_to_ref(s) }    );
    |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_else(|| unsafe { ptr_to_ref(s) })`
 
 error: function call inside of `map_or`
-  --> tests/ui/or_fun_call.rs:281:25
+  --> tests/ui/or_fun_call.rs:297:25
    |
 LL |         let _ = Some(4).map_or(g(), |v| v);
    |                         ^^^^^^^^^^^^^^^^^^ help: try: `map_or_else(g, |v| v)`
 
 error: function call inside of `map_or`
-  --> tests/ui/or_fun_call.rs:283:25
+  --> tests/ui/or_fun_call.rs:299:25
    |
 LL |         let _ = Some(4).map_or(g(), f);
    |                         ^^^^^^^^^^^^^^ help: try: `map_or_else(g, f)`
 
 error: function call inside of `map_or`
-  --> tests/ui/or_fun_call.rs:286:25
+  --> tests/ui/or_fun_call.rs:302:25
    |
 LL |         let _ = Some(4).map_or("asd".to_string().len() as i32, f);
    |                         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map_or_else(|| "asd".to_string().len() as i32, f)`
 
 error: use of `unwrap_or_else` to construct default value
-  --> tests/ui/or_fun_call.rs:317:18
+  --> tests/ui/or_fun_call.rs:333:18
    |
 LL |         with_new.unwrap_or_else(Vec::new);
    |                  ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_default()`
 
 error: use of `unwrap_or_else` to construct default value
-  --> tests/ui/or_fun_call.rs:321:28
+  --> tests/ui/or_fun_call.rs:337:28
    |
 LL |         with_default_trait.unwrap_or_else(Default::default);
    |                            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_default()`
 
 error: use of `unwrap_or_else` to construct default value
-  --> tests/ui/or_fun_call.rs:325:27
+  --> tests/ui/or_fun_call.rs:341:27
    |
 LL |         with_default_type.unwrap_or_else(u64::default);
    |                           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_default()`
 
 error: use of `unwrap_or_else` to construct default value
-  --> tests/ui/or_fun_call.rs:329:22
+  --> tests/ui/or_fun_call.rs:345:22
    |
 LL |         real_default.unwrap_or_else(<FakeDefault as Default>::default);
    |                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_default()`
 
 error: use of `or_insert_with` to construct default value
-  --> tests/ui/or_fun_call.rs:333:23
+  --> tests/ui/or_fun_call.rs:349:23
    |
 LL |         map.entry(42).or_insert_with(String::new);
    |                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `or_default()`
 
 error: use of `or_insert_with` to construct default value
-  --> tests/ui/or_fun_call.rs:337:25
+  --> tests/ui/or_fun_call.rs:353:25
    |
 LL |         btree.entry(42).or_insert_with(String::new);
    |                         ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `or_default()`
 
 error: use of `unwrap_or_else` to construct default value
-  --> tests/ui/or_fun_call.rs:341:25
+  --> tests/ui/or_fun_call.rs:357:25
    |
 LL |         let _ = stringy.unwrap_or_else(String::new);
    |                         ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_default()`
 
 error: function call inside of `unwrap_or`
-  --> tests/ui/or_fun_call.rs:383:17
+  --> tests/ui/or_fun_call.rs:399:17
    |
 LL |     let _ = opt.unwrap_or({ f() }); // suggest `.unwrap_or_else(f)`
    |                 ^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_else(f)`
 
 error: function call inside of `unwrap_or`
-  --> tests/ui/or_fun_call.rs:388:17
+  --> tests/ui/or_fun_call.rs:404:17
    |
 LL |     let _ = opt.unwrap_or(f() + 1); // suggest `.unwrap_or_else(|| f() + 1)`
    |                 ^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_else(|| f() + 1)`
 
 error: function call inside of `unwrap_or`
-  --> tests/ui/or_fun_call.rs:393:17
+  --> tests/ui/or_fun_call.rs:409:17
    |
 LL |       let _ = opt.unwrap_or({
    |  _________________^
@@ -235,55 +235,55 @@ LL ~     });
    |
 
 error: function call inside of `map_or`
-  --> tests/ui/or_fun_call.rs:399:17
+  --> tests/ui/or_fun_call.rs:415:17
    |
 LL |     let _ = opt.map_or(f() + 1, |v| v); // suggest `.map_or_else(|| f() + 1, |v| v)`
    |                 ^^^^^^^^^^^^^^^^^^^^^^ help: try: `map_or_else(|| f() + 1, |v| v)`
 
 error: use of `unwrap_or` to construct default value
-  --> tests/ui/or_fun_call.rs:404:17
+  --> tests/ui/or_fun_call.rs:420:17
    |
 LL |     let _ = opt.unwrap_or({ i32::default() });
    |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_default()`
 
 error: function call inside of `unwrap_or`
-  --> tests/ui/or_fun_call.rs:411:21
+  --> tests/ui/or_fun_call.rs:427:21
    |
 LL |     let _ = opt_foo.unwrap_or(Foo { val: String::default() });
    |                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_else(|| Foo { val: String::default() })`
 
 error: function call inside of `map_or`
-  --> tests/ui/or_fun_call.rs:426:19
+  --> tests/ui/or_fun_call.rs:442:19
    |
 LL |         let _ = x.map_or(g(), |v| v);
    |                   ^^^^^^^^^^^^^^^^^^ help: try: `map_or_else(|_| g(), |v| v)`
 
 error: function call inside of `map_or`
-  --> tests/ui/or_fun_call.rs:428:19
+  --> tests/ui/or_fun_call.rs:444:19
    |
 LL |         let _ = x.map_or(g(), f);
    |                   ^^^^^^^^^^^^^^ help: try: `map_or_else(|_| g(), f)`
 
 error: function call inside of `map_or`
-  --> tests/ui/or_fun_call.rs:431:19
+  --> tests/ui/or_fun_call.rs:447:19
    |
 LL |         let _ = x.map_or("asd".to_string().len() as i32, f);
    |                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map_or_else(|_| "asd".to_string().len() as i32, f)`
 
 error: function call inside of `get_or_insert`
-  --> tests/ui/or_fun_call.rs:442:15
+  --> tests/ui/or_fun_call.rs:458:15
    |
 LL |     let _ = x.get_or_insert(g());
    |               ^^^^^^^^^^^^^^^^^^ help: try: `get_or_insert_with(g)`
 
 error: function call inside of `and`
-  --> tests/ui/or_fun_call.rs:452:15
+  --> tests/ui/or_fun_call.rs:468:15
    |
 LL |     let _ = x.and(g());
    |               ^^^^^^^^ help: try: `and_then(|_| g())`
 
 error: function call inside of `and`
-  --> tests/ui/or_fun_call.rs:462:15
+  --> tests/ui/or_fun_call.rs:478:15
    |
 LL |     let _ = x.and(g());
    |               ^^^^^^^^ help: try: `and_then(|_| g())`
diff --git a/src/tools/clippy/tests/ui/ptr_offset_with_cast.fixed b/src/tools/clippy/tests/ui/ptr_offset_with_cast.fixed
index 4fe9dcf46c3..42d1abeaa05 100644
--- a/src/tools/clippy/tests/ui/ptr_offset_with_cast.fixed
+++ b/src/tools/clippy/tests/ui/ptr_offset_with_cast.fixed
@@ -1,4 +1,4 @@
-#![allow(clippy::unnecessary_cast, clippy::useless_vec)]
+#![expect(clippy::unnecessary_cast, clippy::useless_vec, clippy::needless_borrow)]
 
 fn main() {
     let vec = vec![b'a', b'b', b'c'];
@@ -18,5 +18,25 @@ fn main() {
         //~^ ptr_offset_with_cast
         let _ = ptr.wrapping_offset(offset_isize as isize);
         let _ = ptr.wrapping_offset(offset_u8 as isize);
+
+        let _ = S.offset(offset_usize as isize);
+        let _ = S.wrapping_offset(offset_usize as isize);
+
+        let _ = (&ptr).add(offset_usize);
+        //~^ ptr_offset_with_cast
+        let _ = (&ptr).wrapping_add(offset_usize);
+        //~^ ptr_offset_with_cast
+    }
+}
+
+#[derive(Clone, Copy)]
+struct S;
+
+impl S {
+    fn offset(self, _: isize) -> Self {
+        self
+    }
+    fn wrapping_offset(self, _: isize) -> Self {
+        self
     }
 }
diff --git a/src/tools/clippy/tests/ui/ptr_offset_with_cast.rs b/src/tools/clippy/tests/ui/ptr_offset_with_cast.rs
index a1fb892733d..6d06a6af1fa 100644
--- a/src/tools/clippy/tests/ui/ptr_offset_with_cast.rs
+++ b/src/tools/clippy/tests/ui/ptr_offset_with_cast.rs
@@ -1,4 +1,4 @@
-#![allow(clippy::unnecessary_cast, clippy::useless_vec)]
+#![expect(clippy::unnecessary_cast, clippy::useless_vec, clippy::needless_borrow)]
 
 fn main() {
     let vec = vec![b'a', b'b', b'c'];
@@ -18,5 +18,25 @@ fn main() {
         //~^ ptr_offset_with_cast
         let _ = ptr.wrapping_offset(offset_isize as isize);
         let _ = ptr.wrapping_offset(offset_u8 as isize);
+
+        let _ = S.offset(offset_usize as isize);
+        let _ = S.wrapping_offset(offset_usize as isize);
+
+        let _ = (&ptr).offset(offset_usize as isize);
+        //~^ ptr_offset_with_cast
+        let _ = (&ptr).wrapping_offset(offset_usize as isize);
+        //~^ ptr_offset_with_cast
+    }
+}
+
+#[derive(Clone, Copy)]
+struct S;
+
+impl S {
+    fn offset(self, _: isize) -> Self {
+        self
+    }
+    fn wrapping_offset(self, _: isize) -> Self {
+        self
     }
 }
diff --git a/src/tools/clippy/tests/ui/ptr_offset_with_cast.stderr b/src/tools/clippy/tests/ui/ptr_offset_with_cast.stderr
index dcd5e027d18..022b3286c93 100644
--- a/src/tools/clippy/tests/ui/ptr_offset_with_cast.stderr
+++ b/src/tools/clippy/tests/ui/ptr_offset_with_cast.stderr
@@ -2,16 +2,51 @@ error: use of `offset` with a `usize` casted to an `isize`
   --> tests/ui/ptr_offset_with_cast.rs:12:17
    |
 LL |         let _ = ptr.offset(offset_usize as isize);
-   |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `ptr.add(offset_usize)`
+   |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
    = note: `-D clippy::ptr-offset-with-cast` implied by `-D warnings`
    = help: to override `-D warnings` add `#[allow(clippy::ptr_offset_with_cast)]`
+help: use `add` instead
+   |
+LL -         let _ = ptr.offset(offset_usize as isize);
+LL +         let _ = ptr.add(offset_usize);
+   |
 
 error: use of `wrapping_offset` with a `usize` casted to an `isize`
   --> tests/ui/ptr_offset_with_cast.rs:17:17
    |
 LL |         let _ = ptr.wrapping_offset(offset_usize as isize);
-   |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `ptr.wrapping_add(offset_usize)`
+   |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: use `wrapping_add` instead
+   |
+LL -         let _ = ptr.wrapping_offset(offset_usize as isize);
+LL +         let _ = ptr.wrapping_add(offset_usize);
+   |
+
+error: use of `offset` with a `usize` casted to an `isize`
+  --> tests/ui/ptr_offset_with_cast.rs:25:17
+   |
+LL |         let _ = (&ptr).offset(offset_usize as isize);
+   |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: use `add` instead
+   |
+LL -         let _ = (&ptr).offset(offset_usize as isize);
+LL +         let _ = (&ptr).add(offset_usize);
+   |
+
+error: use of `wrapping_offset` with a `usize` casted to an `isize`
+  --> tests/ui/ptr_offset_with_cast.rs:27:17
+   |
+LL |         let _ = (&ptr).wrapping_offset(offset_usize as isize);
+   |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: use `wrapping_add` instead
+   |
+LL -         let _ = (&ptr).wrapping_offset(offset_usize as isize);
+LL +         let _ = (&ptr).wrapping_add(offset_usize);
+   |
 
-error: aborting due to 2 previous errors
+error: aborting due to 4 previous errors
 
diff --git a/src/tools/clippy/tests/ui/question_mark.fixed b/src/tools/clippy/tests/ui/question_mark.fixed
index 8d6f5fbadca..ac81b324c20 100644
--- a/src/tools/clippy/tests/ui/question_mark.fixed
+++ b/src/tools/clippy/tests/ui/question_mark.fixed
@@ -1,6 +1,4 @@
 #![feature(try_blocks)]
-#![allow(unreachable_code)]
-#![allow(dead_code)]
 #![allow(clippy::unnecessary_wraps)]
 
 use std::sync::MutexGuard;
@@ -465,3 +463,15 @@ fn issue_13642(x: Option<i32>) -> Option<()> {
 
     None
 }
+
+fn issue_15679() -> Result<i32, String> {
+    let some_result: Result<i32, &'static str> = todo!();
+
+    some_result?;
+
+    some_result?;
+
+    some_result?;
+
+    Ok(0)
+}
diff --git a/src/tools/clippy/tests/ui/question_mark.rs b/src/tools/clippy/tests/ui/question_mark.rs
index f13eee29c11..b5866dac6b8 100644
--- a/src/tools/clippy/tests/ui/question_mark.rs
+++ b/src/tools/clippy/tests/ui/question_mark.rs
@@ -1,6 +1,4 @@
 #![feature(try_blocks)]
-#![allow(unreachable_code)]
-#![allow(dead_code)]
 #![allow(clippy::unnecessary_wraps)]
 
 use std::sync::MutexGuard;
@@ -561,3 +559,27 @@ fn issue_13642(x: Option<i32>) -> Option<()> {
 
     None
 }
+
+fn issue_15679() -> Result<i32, String> {
+    let some_result: Result<i32, &'static str> = todo!();
+
+    match some_result {
+        //~^ question_mark
+        Ok(val) => val,
+        Err(err) => return Err(err.into()),
+    };
+
+    match some_result {
+        //~^ question_mark
+        Ok(val) => val,
+        Err(err) => return Err(Into::into(err)),
+    };
+
+    match some_result {
+        //~^ question_mark
+        Ok(val) => val,
+        Err(err) => return Err(<&str as Into<String>>::into(err)),
+    };
+
+    Ok(0)
+}
diff --git a/src/tools/clippy/tests/ui/question_mark.stderr b/src/tools/clippy/tests/ui/question_mark.stderr
index d8ce4420aee..1ecd936292e 100644
--- a/src/tools/clippy/tests/ui/question_mark.stderr
+++ b/src/tools/clippy/tests/ui/question_mark.stderr
@@ -1,5 +1,5 @@
 error: this block may be rewritten with the `?` operator
-  --> tests/ui/question_mark.rs:9:5
+  --> tests/ui/question_mark.rs:7:5
    |
 LL | /     if a.is_none() {
 LL | |
@@ -11,7 +11,7 @@ LL | |     }
    = help: to override `-D warnings` add `#[allow(clippy::question_mark)]`
 
 error: this block may be rewritten with the `?` operator
-  --> tests/ui/question_mark.rs:55:9
+  --> tests/ui/question_mark.rs:53:9
    |
 LL | /         if (self.opt).is_none() {
 LL | |
@@ -20,7 +20,7 @@ LL | |         }
    | |_________^ help: replace it with: `(self.opt)?;`
 
 error: this block may be rewritten with the `?` operator
-  --> tests/ui/question_mark.rs:60:9
+  --> tests/ui/question_mark.rs:58:9
    |
 LL | /         if self.opt.is_none() {
 LL | |
@@ -29,7 +29,7 @@ LL | |         }
    | |_________^ help: replace it with: `self.opt?;`
 
 error: this block may be rewritten with the `?` operator
-  --> tests/ui/question_mark.rs:65:17
+  --> tests/ui/question_mark.rs:63:17
    |
 LL |           let _ = if self.opt.is_none() {
    |  _________________^
@@ -41,7 +41,7 @@ LL | |         };
    | |_________^ help: replace it with: `Some(self.opt?)`
 
 error: this block may be rewritten with the `?` operator
-  --> tests/ui/question_mark.rs:72:17
+  --> tests/ui/question_mark.rs:70:17
    |
 LL |           let _ = if let Some(x) = self.opt {
    |  _________________^
@@ -53,7 +53,7 @@ LL | |         };
    | |_________^ help: replace it with: `self.opt?`
 
 error: this block may be rewritten with the `?` operator
-  --> tests/ui/question_mark.rs:90:9
+  --> tests/ui/question_mark.rs:88:9
    |
 LL | /         if self.opt.is_none() {
 LL | |
@@ -62,7 +62,7 @@ LL | |         }
    | |_________^ help: replace it with: `self.opt.as_ref()?;`
 
 error: this block may be rewritten with the `?` operator
-  --> tests/ui/question_mark.rs:99:9
+  --> tests/ui/question_mark.rs:97:9
    |
 LL | /         if self.opt.is_none() {
 LL | |
@@ -71,7 +71,7 @@ LL | |         }
    | |_________^ help: replace it with: `self.opt.as_ref()?;`
 
 error: this block may be rewritten with the `?` operator
-  --> tests/ui/question_mark.rs:108:9
+  --> tests/ui/question_mark.rs:106:9
    |
 LL | /         if self.opt.is_none() {
 LL | |
@@ -80,7 +80,7 @@ LL | |         }
    | |_________^ help: replace it with: `self.opt.as_ref()?;`
 
 error: this block may be rewritten with the `?` operator
-  --> tests/ui/question_mark.rs:116:26
+  --> tests/ui/question_mark.rs:114:26
    |
 LL |           let v: &Vec<_> = if let Some(ref v) = self.opt {
    |  __________________________^
@@ -92,7 +92,7 @@ LL | |         };
    | |_________^ help: replace it with: `self.opt.as_ref()?`
 
 error: this block may be rewritten with the `?` operator
-  --> tests/ui/question_mark.rs:127:17
+  --> tests/ui/question_mark.rs:125:17
    |
 LL |           let v = if let Some(v) = self.opt {
    |  _________________^
@@ -104,7 +104,7 @@ LL | |         };
    | |_________^ help: replace it with: `self.opt?`
 
 error: this block may be rewritten with the `?` operator
-  --> tests/ui/question_mark.rs:149:5
+  --> tests/ui/question_mark.rs:147:5
    |
 LL | /     if f().is_none() {
 LL | |
@@ -113,7 +113,7 @@ LL | |     }
    | |_____^ help: replace it with: `f()?;`
 
 error: this `match` expression can be replaced with `?`
-  --> tests/ui/question_mark.rs:154:16
+  --> tests/ui/question_mark.rs:152:16
    |
 LL |       let _val = match f() {
    |  ________________^
@@ -124,7 +124,7 @@ LL | |     };
    | |_____^ help: try instead: `f()?`
 
 error: this `match` expression can be replaced with `?`
-  --> tests/ui/question_mark.rs:165:5
+  --> tests/ui/question_mark.rs:163:5
    |
 LL | /     match f() {
 LL | |
@@ -134,7 +134,7 @@ LL | |     };
    | |_____^ help: try instead: `f()?`
 
 error: this `match` expression can be replaced with `?`
-  --> tests/ui/question_mark.rs:171:5
+  --> tests/ui/question_mark.rs:169:5
    |
 LL | /     match opt_none!() {
 LL | |
@@ -144,13 +144,13 @@ LL | |     };
    | |_____^ help: try instead: `opt_none!()?`
 
 error: this block may be rewritten with the `?` operator
-  --> tests/ui/question_mark.rs:198:13
+  --> tests/ui/question_mark.rs:196:13
    |
 LL |     let _ = if let Ok(x) = x { x } else { return x };
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace it with: `x?`
 
 error: this block may be rewritten with the `?` operator
-  --> tests/ui/question_mark.rs:201:5
+  --> tests/ui/question_mark.rs:199:5
    |
 LL | /     if x.is_err() {
 LL | |
@@ -159,7 +159,7 @@ LL | |     }
    | |_____^ help: replace it with: `x?;`
 
 error: this `match` expression can be replaced with `?`
-  --> tests/ui/question_mark.rs:206:16
+  --> tests/ui/question_mark.rs:204:16
    |
 LL |       let _val = match func_returning_result() {
    |  ________________^
@@ -170,7 +170,7 @@ LL | |     };
    | |_____^ help: try instead: `func_returning_result()?`
 
 error: this `match` expression can be replaced with `?`
-  --> tests/ui/question_mark.rs:212:5
+  --> tests/ui/question_mark.rs:210:5
    |
 LL | /     match func_returning_result() {
 LL | |
@@ -180,7 +180,7 @@ LL | |     };
    | |_____^ help: try instead: `func_returning_result()?`
 
 error: this block may be rewritten with the `?` operator
-  --> tests/ui/question_mark.rs:304:5
+  --> tests/ui/question_mark.rs:302:5
    |
 LL | /     if let Err(err) = func_returning_result() {
 LL | |
@@ -189,7 +189,7 @@ LL | |     }
    | |_____^ help: replace it with: `func_returning_result()?;`
 
 error: this block may be rewritten with the `?` operator
-  --> tests/ui/question_mark.rs:312:5
+  --> tests/ui/question_mark.rs:310:5
    |
 LL | /     if let Err(err) = func_returning_result() {
 LL | |
@@ -198,7 +198,7 @@ LL | |     }
    | |_____^ help: replace it with: `func_returning_result()?;`
 
 error: this block may be rewritten with the `?` operator
-  --> tests/ui/question_mark.rs:395:13
+  --> tests/ui/question_mark.rs:393:13
    |
 LL | /             if a.is_none() {
 LL | |
@@ -208,7 +208,7 @@ LL | |             }
    | |_____________^ help: replace it with: `a?;`
 
 error: this `let...else` may be rewritten with the `?` operator
-  --> tests/ui/question_mark.rs:456:5
+  --> tests/ui/question_mark.rs:454:5
    |
 LL | /     let Some(v) = bar.foo.owned.clone() else {
 LL | |         return None;
@@ -216,7 +216,7 @@ LL | |     };
    | |______^ help: replace it with: `let v = bar.foo.owned.clone()?;`
 
 error: this `let...else` may be rewritten with the `?` operator
-  --> tests/ui/question_mark.rs:471:5
+  --> tests/ui/question_mark.rs:469:5
    |
 LL | /     let Some(ref x) = foo.opt_x else {
 LL | |         return None;
@@ -224,7 +224,7 @@ LL | |     };
    | |______^ help: replace it with: `let x = foo.opt_x.as_ref()?;`
 
 error: this `let...else` may be rewritten with the `?` operator
-  --> tests/ui/question_mark.rs:481:5
+  --> tests/ui/question_mark.rs:479:5
    |
 LL | /     let Some(ref mut x) = foo.opt_x else {
 LL | |         return None;
@@ -232,7 +232,7 @@ LL | |     };
    | |______^ help: replace it with: `let x = foo.opt_x.as_mut()?;`
 
 error: this `let...else` may be rewritten with the `?` operator
-  --> tests/ui/question_mark.rs:492:5
+  --> tests/ui/question_mark.rs:490:5
    |
 LL | /     let Some(ref x @ ref y) = foo.opt_x else {
 LL | |         return None;
@@ -240,7 +240,7 @@ LL | |     };
    | |______^ help: replace it with: `let x @ y = foo.opt_x.as_ref()?;`
 
 error: this `let...else` may be rewritten with the `?` operator
-  --> tests/ui/question_mark.rs:496:5
+  --> tests/ui/question_mark.rs:494:5
    |
 LL | /     let Some(ref x @ WrapperStructWithString(_)) = bar else {
 LL | |         return None;
@@ -248,7 +248,7 @@ LL | |     };
    | |______^ help: replace it with: `let x @ &WrapperStructWithString(_) = bar.as_ref()?;`
 
 error: this `let...else` may be rewritten with the `?` operator
-  --> tests/ui/question_mark.rs:500:5
+  --> tests/ui/question_mark.rs:498:5
    |
 LL | /     let Some(ref mut x @ WrapperStructWithString(_)) = bar else {
 LL | |         return None;
@@ -256,7 +256,7 @@ LL | |     };
    | |______^ help: replace it with: `let x @ &mut WrapperStructWithString(_) = bar.as_mut()?;`
 
 error: this block may be rewritten with the `?` operator
-  --> tests/ui/question_mark.rs:522:5
+  --> tests/ui/question_mark.rs:520:5
    |
 LL | /     if arg.is_none() {
 LL | |
@@ -265,7 +265,7 @@ LL | |     }
    | |_____^ help: replace it with: `arg?;`
 
 error: this `match` expression can be replaced with `?`
-  --> tests/ui/question_mark.rs:526:15
+  --> tests/ui/question_mark.rs:524:15
    |
 LL |       let val = match arg {
    |  _______________^
@@ -276,12 +276,42 @@ LL | |     };
    | |_____^ help: try instead: `arg?`
 
 error: this `let...else` may be rewritten with the `?` operator
-  --> tests/ui/question_mark.rs:536:5
+  --> tests/ui/question_mark.rs:534:5
    |
 LL | /     let Some(a) = *a else {
 LL | |         return None;
 LL | |     };
    | |______^ help: replace it with: `let a = (*a)?;`
 
-error: aborting due to 30 previous errors
+error: this `match` expression can be replaced with `?`
+  --> tests/ui/question_mark.rs:566:5
+   |
+LL | /     match some_result {
+LL | |
+LL | |         Ok(val) => val,
+LL | |         Err(err) => return Err(err.into()),
+LL | |     };
+   | |_____^ help: try instead: `some_result?`
+
+error: this `match` expression can be replaced with `?`
+  --> tests/ui/question_mark.rs:572:5
+   |
+LL | /     match some_result {
+LL | |
+LL | |         Ok(val) => val,
+LL | |         Err(err) => return Err(Into::into(err)),
+LL | |     };
+   | |_____^ help: try instead: `some_result?`
+
+error: this `match` expression can be replaced with `?`
+  --> tests/ui/question_mark.rs:578:5
+   |
+LL | /     match some_result {
+LL | |
+LL | |         Ok(val) => val,
+LL | |         Err(err) => return Err(<&str as Into<String>>::into(err)),
+LL | |     };
+   | |_____^ help: try instead: `some_result?`
+
+error: aborting due to 33 previous errors
 
diff --git a/src/tools/clippy/tests/ui/read_zero_byte_vec.rs b/src/tools/clippy/tests/ui/read_zero_byte_vec.rs
index 938d61b6860..720276cb554 100644
--- a/src/tools/clippy/tests/ui/read_zero_byte_vec.rs
+++ b/src/tools/clippy/tests/ui/read_zero_byte_vec.rs
@@ -120,3 +120,30 @@ fn allow_works<F: std::io::Read>(mut f: F) {
 }
 
 fn main() {}
+
+fn issue15575() -> usize {
+    use std::io::Read;
+    use std::net::TcpListener;
+
+    let listener = TcpListener::bind("127.0.0.1:9010").unwrap();
+    let mut stream_and_addr = listener.accept().unwrap();
+    let mut buf = Vec::with_capacity(32);
+    let num_bytes_received = stream_and_addr.0.read(&mut buf).unwrap();
+    //~^ read_zero_byte_vec
+
+    let cap = 1000;
+    let mut buf = Vec::with_capacity(cap);
+    let num_bytes_received = stream_and_addr.0.read(&mut buf).unwrap();
+    //~^ read_zero_byte_vec
+
+    let cap = 1000;
+    let mut buf = Vec::with_capacity(cap);
+    let num_bytes_received = { stream_and_addr.0.read(&mut buf) }.unwrap();
+    //~^ read_zero_byte_vec
+
+    use std::fs::File;
+    let mut f = File::open("foo.txt").unwrap();
+    let mut data = Vec::with_capacity(100);
+    f.read(&mut data).unwrap()
+    //~^ read_zero_byte_vec
+}
diff --git a/src/tools/clippy/tests/ui/read_zero_byte_vec.stderr b/src/tools/clippy/tests/ui/read_zero_byte_vec.stderr
index 8f255bc87ab..8dd74592e4c 100644
--- a/src/tools/clippy/tests/ui/read_zero_byte_vec.stderr
+++ b/src/tools/clippy/tests/ui/read_zero_byte_vec.stderr
@@ -2,16 +2,27 @@ error: reading zero byte data to `Vec`
   --> tests/ui/read_zero_byte_vec.rs:22:5
    |
 LL |     f.read_exact(&mut data).unwrap();
-   |     ^^^^^^^^^^^^^^^^^^^^^^^ help: try: `data.resize(20, 0); f.read_exact(&mut data)`
+   |     ^^^^^^^^^^^^^^^^^^^^^^^
    |
    = note: `-D clippy::read-zero-byte-vec` implied by `-D warnings`
    = help: to override `-D warnings` add `#[allow(clippy::read_zero_byte_vec)]`
+help: try
+   |
+LL ~     data.resize(20, 0);
+LL ~     f.read_exact(&mut data).unwrap();
+   |
 
 error: reading zero byte data to `Vec`
   --> tests/ui/read_zero_byte_vec.rs:28:5
    |
 LL |     f.read_exact(&mut data2)?;
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `data2.resize(cap, 0); f.read_exact(&mut data2)`
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: try
+   |
+LL ~     data2.resize(cap, 0);
+LL ~     f.read_exact(&mut data2)?;
+   |
 
 error: reading zero byte data to `Vec`
   --> tests/ui/read_zero_byte_vec.rs:33:5
@@ -67,5 +78,53 @@ error: reading zero byte data to `Vec`
 LL |     r.read_exact(&mut data2).await.unwrap();
    |     ^^^^^^^^^^^^^^^^^^^^^^^^
 
-error: aborting due to 11 previous errors
+error: reading zero byte data to `Vec`
+  --> tests/ui/read_zero_byte_vec.rs:131:30
+   |
+LL |     let num_bytes_received = stream_and_addr.0.read(&mut buf).unwrap();
+   |                              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: try
+   |
+LL ~     buf.resize(32, 0);
+LL ~     let num_bytes_received = stream_and_addr.0.read(&mut buf).unwrap();
+   |
+
+error: reading zero byte data to `Vec`
+  --> tests/ui/read_zero_byte_vec.rs:136:30
+   |
+LL |     let num_bytes_received = stream_and_addr.0.read(&mut buf).unwrap();
+   |                              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: try
+   |
+LL ~     buf.resize(cap, 0);
+LL ~     let num_bytes_received = stream_and_addr.0.read(&mut buf).unwrap();
+   |
+
+error: reading zero byte data to `Vec`
+  --> tests/ui/read_zero_byte_vec.rs:141:32
+   |
+LL |     let num_bytes_received = { stream_and_addr.0.read(&mut buf) }.unwrap();
+   |                                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: try
+   |
+LL ~     buf.resize(cap, 0);
+LL ~     let num_bytes_received = { stream_and_addr.0.read(&mut buf) }.unwrap();
+   |
+
+error: reading zero byte data to `Vec`
+  --> tests/ui/read_zero_byte_vec.rs:147:5
+   |
+LL |     f.read(&mut data).unwrap()
+   |     ^^^^^^^^^^^^^^^^^
+   |
+help: try
+   |
+LL ~     data.resize(100, 0);
+LL ~     f.read(&mut data).unwrap()
+   |
+
+error: aborting due to 15 previous errors
 
diff --git a/src/tools/clippy/tests/ui/ref_option/ref_option.all.fixed b/src/tools/clippy/tests/ui/ref_option/ref_option.all.fixed
deleted file mode 100644
index 4159e916f19..00000000000
--- a/src/tools/clippy/tests/ui/ref_option/ref_option.all.fixed
+++ /dev/null
@@ -1,79 +0,0 @@
-//@revisions: private all
-//@[private] rustc-env:CLIPPY_CONF_DIR=tests/ui/ref_option/private
-//@[all] rustc-env:CLIPPY_CONF_DIR=tests/ui/ref_option/all
-
-#![allow(unused, clippy::needless_lifetimes, clippy::borrowed_box)]
-#![warn(clippy::ref_option)]
-
-fn opt_u8(a: Option<&u8>) {}
-//~^ ref_option
-fn opt_gen<T>(a: Option<&T>) {}
-//~^ ref_option
-fn opt_string(a: std::option::Option<&String>) {}
-//~^ ref_option
-fn ret_string<'a>(p: &'a str) -> Option<&'a u8> {
-    //~^ ref_option
-    panic!()
-}
-fn ret_string_static() -> Option<&'static u8> {
-    //~^ ref_option
-    panic!()
-}
-fn mult_string(a: Option<&String>, b: Option<&Vec<u8>>) {}
-//~^ ref_option
-fn ret_box<'a>() -> Option<&'a Box<u8>> {
-    //~^ ref_option
-    panic!()
-}
-
-pub fn pub_opt_string(a: Option<&String>) {}
-//~[all]^ ref_option
-pub fn pub_mult_string(a: Option<&String>, b: Option<&Vec<u8>>) {}
-//~[all]^ ref_option
-
-pub trait PubTrait {
-    fn pub_trait_opt(&self, a: Option<&Vec<u8>>);
-    //~[all]^ ref_option
-    fn pub_trait_ret(&self) -> Option<&Vec<u8>>;
-    //~[all]^ ref_option
-}
-
-trait PrivateTrait {
-    fn trait_opt(&self, a: Option<&String>);
-    //~^ ref_option
-    fn trait_ret(&self) -> Option<&String>;
-    //~^ ref_option
-}
-
-pub struct PubStruct;
-
-impl PubStruct {
-    pub fn pub_opt_params(&self, a: Option<&()>) {}
-    //~[all]^ ref_option
-    pub fn pub_opt_ret(&self) -> Option<&String> {
-        //~[all]^ ref_option
-        panic!()
-    }
-
-    fn private_opt_params(&self, a: Option<&()>) {}
-    //~^ ref_option
-    fn private_opt_ret(&self) -> Option<&String> {
-        //~^ ref_option
-        panic!()
-    }
-}
-
-// valid, don't change
-fn mut_u8(a: &mut Option<u8>) {}
-pub fn pub_mut_u8(a: &mut Option<String>) {}
-
-// might be good to catch in the future
-fn mut_u8_ref(a: &mut &Option<u8>) {}
-pub fn pub_mut_u8_ref(a: &mut &Option<String>) {}
-fn lambdas() {
-    // Not handled for now, not sure if we should
-    let x = |a: &Option<String>| {};
-    let x = |a: &Option<String>| -> &Option<String> { panic!() };
-}
-
-fn main() {}
diff --git a/src/tools/clippy/tests/ui/ref_option/ref_option.private.fixed b/src/tools/clippy/tests/ui/ref_option/ref_option.private.fixed
deleted file mode 100644
index 3b158befb92..00000000000
--- a/src/tools/clippy/tests/ui/ref_option/ref_option.private.fixed
+++ /dev/null
@@ -1,79 +0,0 @@
-//@revisions: private all
-//@[private] rustc-env:CLIPPY_CONF_DIR=tests/ui/ref_option/private
-//@[all] rustc-env:CLIPPY_CONF_DIR=tests/ui/ref_option/all
-
-#![allow(unused, clippy::needless_lifetimes, clippy::borrowed_box)]
-#![warn(clippy::ref_option)]
-
-fn opt_u8(a: Option<&u8>) {}
-//~^ ref_option
-fn opt_gen<T>(a: Option<&T>) {}
-//~^ ref_option
-fn opt_string(a: std::option::Option<&String>) {}
-//~^ ref_option
-fn ret_string<'a>(p: &'a str) -> Option<&'a u8> {
-    //~^ ref_option
-    panic!()
-}
-fn ret_string_static() -> Option<&'static u8> {
-    //~^ ref_option
-    panic!()
-}
-fn mult_string(a: Option<&String>, b: Option<&Vec<u8>>) {}
-//~^ ref_option
-fn ret_box<'a>() -> Option<&'a Box<u8>> {
-    //~^ ref_option
-    panic!()
-}
-
-pub fn pub_opt_string(a: &Option<String>) {}
-//~[all]^ ref_option
-pub fn pub_mult_string(a: &Option<String>, b: &Option<Vec<u8>>) {}
-//~[all]^ ref_option
-
-pub trait PubTrait {
-    fn pub_trait_opt(&self, a: &Option<Vec<u8>>);
-    //~[all]^ ref_option
-    fn pub_trait_ret(&self) -> &Option<Vec<u8>>;
-    //~[all]^ ref_option
-}
-
-trait PrivateTrait {
-    fn trait_opt(&self, a: Option<&String>);
-    //~^ ref_option
-    fn trait_ret(&self) -> Option<&String>;
-    //~^ ref_option
-}
-
-pub struct PubStruct;
-
-impl PubStruct {
-    pub fn pub_opt_params(&self, a: &Option<()>) {}
-    //~[all]^ ref_option
-    pub fn pub_opt_ret(&self) -> &Option<String> {
-        //~[all]^ ref_option
-        panic!()
-    }
-
-    fn private_opt_params(&self, a: Option<&()>) {}
-    //~^ ref_option
-    fn private_opt_ret(&self) -> Option<&String> {
-        //~^ ref_option
-        panic!()
-    }
-}
-
-// valid, don't change
-fn mut_u8(a: &mut Option<u8>) {}
-pub fn pub_mut_u8(a: &mut Option<String>) {}
-
-// might be good to catch in the future
-fn mut_u8_ref(a: &mut &Option<u8>) {}
-pub fn pub_mut_u8_ref(a: &mut &Option<String>) {}
-fn lambdas() {
-    // Not handled for now, not sure if we should
-    let x = |a: &Option<String>| {};
-    let x = |a: &Option<String>| -> &Option<String> { panic!() };
-}
-
-fn main() {}
diff --git a/src/tools/clippy/tests/ui/ref_option/ref_option.rs b/src/tools/clippy/tests/ui/ref_option/ref_option.rs
deleted file mode 100644
index 35cd94174f8..00000000000
--- a/src/tools/clippy/tests/ui/ref_option/ref_option.rs
+++ /dev/null
@@ -1,79 +0,0 @@
-//@revisions: private all
-//@[private] rustc-env:CLIPPY_CONF_DIR=tests/ui/ref_option/private
-//@[all] rustc-env:CLIPPY_CONF_DIR=tests/ui/ref_option/all
-
-#![allow(unused, clippy::needless_lifetimes, clippy::borrowed_box)]
-#![warn(clippy::ref_option)]
-
-fn opt_u8(a: &Option<u8>) {}
-//~^ ref_option
-fn opt_gen<T>(a: &Option<T>) {}
-//~^ ref_option
-fn opt_string(a: &std::option::Option<String>) {}
-//~^ ref_option
-fn ret_string<'a>(p: &'a str) -> &'a Option<u8> {
-    //~^ ref_option
-    panic!()
-}
-fn ret_string_static() -> &'static Option<u8> {
-    //~^ ref_option
-    panic!()
-}
-fn mult_string(a: &Option<String>, b: &Option<Vec<u8>>) {}
-//~^ ref_option
-fn ret_box<'a>() -> &'a Option<Box<u8>> {
-    //~^ ref_option
-    panic!()
-}
-
-pub fn pub_opt_string(a: &Option<String>) {}
-//~[all]^ ref_option
-pub fn pub_mult_string(a: &Option<String>, b: &Option<Vec<u8>>) {}
-//~[all]^ ref_option
-
-pub trait PubTrait {
-    fn pub_trait_opt(&self, a: &Option<Vec<u8>>);
-    //~[all]^ ref_option
-    fn pub_trait_ret(&self) -> &Option<Vec<u8>>;
-    //~[all]^ ref_option
-}
-
-trait PrivateTrait {
-    fn trait_opt(&self, a: &Option<String>);
-    //~^ ref_option
-    fn trait_ret(&self) -> &Option<String>;
-    //~^ ref_option
-}
-
-pub struct PubStruct;
-
-impl PubStruct {
-    pub fn pub_opt_params(&self, a: &Option<()>) {}
-    //~[all]^ ref_option
-    pub fn pub_opt_ret(&self) -> &Option<String> {
-        //~[all]^ ref_option
-        panic!()
-    }
-
-    fn private_opt_params(&self, a: &Option<()>) {}
-    //~^ ref_option
-    fn private_opt_ret(&self) -> &Option<String> {
-        //~^ ref_option
-        panic!()
-    }
-}
-
-// valid, don't change
-fn mut_u8(a: &mut Option<u8>) {}
-pub fn pub_mut_u8(a: &mut Option<String>) {}
-
-// might be good to catch in the future
-fn mut_u8_ref(a: &mut &Option<u8>) {}
-pub fn pub_mut_u8_ref(a: &mut &Option<String>) {}
-fn lambdas() {
-    // Not handled for now, not sure if we should
-    let x = |a: &Option<String>| {};
-    let x = |a: &Option<String>| -> &Option<String> { panic!() };
-}
-
-fn main() {}
diff --git a/src/tools/clippy/tests/ui/ref_option/ref_option_traits.rs b/src/tools/clippy/tests/ui/ref_option/ref_option_traits.rs
deleted file mode 100644
index 4c773e84f8d..00000000000
--- a/src/tools/clippy/tests/ui/ref_option/ref_option_traits.rs
+++ /dev/null
@@ -1,40 +0,0 @@
-//@no-rustfix: fixes are only done to traits, not the impls
-//@revisions: private all
-//@[private] rustc-env:CLIPPY_CONF_DIR=tests/ui/ref_option/private
-//@[all] rustc-env:CLIPPY_CONF_DIR=tests/ui/ref_option/all
-
-#![warn(clippy::ref_option)]
-
-pub trait PubTrait {
-    fn pub_trait_opt(&self, a: &Option<Vec<u8>>);
-    //~[all]^ ref_option
-    fn pub_trait_ret(&self) -> &Option<Vec<u8>>;
-    //~[all]^ ref_option
-}
-
-trait PrivateTrait {
-    fn trait_opt(&self, a: &Option<String>);
-    //~^ ref_option
-    fn trait_ret(&self) -> &Option<String>;
-    //~^ ref_option
-}
-
-pub struct PubStruct;
-
-impl PubTrait for PubStruct {
-    fn pub_trait_opt(&self, a: &Option<Vec<u8>>) {}
-    fn pub_trait_ret(&self) -> &Option<Vec<u8>> {
-        panic!()
-    }
-}
-
-struct PrivateStruct;
-
-impl PrivateTrait for PrivateStruct {
-    fn trait_opt(&self, a: &Option<String>) {}
-    fn trait_ret(&self) -> &Option<String> {
-        panic!()
-    }
-}
-
-fn main() {}
diff --git a/src/tools/clippy/tests/ui/rest_pat_in_fully_bound_structs.fixed b/src/tools/clippy/tests/ui/rest_pat_in_fully_bound_structs.fixed
new file mode 100644
index 00000000000..ac200b3b19b
--- /dev/null
+++ b/src/tools/clippy/tests/ui/rest_pat_in_fully_bound_structs.fixed
@@ -0,0 +1,61 @@
+#![warn(clippy::rest_pat_in_fully_bound_structs)]
+#![allow(clippy::struct_field_names)]
+
+struct A {
+    a: i32,
+    b: i64,
+    c: &'static str,
+}
+
+macro_rules! foo {
+    ($param:expr) => {
+        match $param {
+            A { a: 0, b: 0, c: "", .. } => {},
+            _ => {},
+        }
+    };
+}
+
+fn main() {
+    let a_struct = A { a: 5, b: 42, c: "A" };
+
+    match a_struct {
+        A { a: 5, b: 42, c: "",  } => {}, // Lint
+        //~^ rest_pat_in_fully_bound_structs
+        A { a: 0, b: 0, c: "",  } => {}, // Lint
+        //~^ rest_pat_in_fully_bound_structs
+        _ => {},
+    }
+
+    match a_struct {
+        A { a: 5, b: 42, .. } => {},
+        A { a: 0, b: 0, c: "",  } => {}, // Lint
+        //~^ rest_pat_in_fully_bound_structs
+        _ => {},
+    }
+
+    // No lint
+    match a_struct {
+        A { a: 5, .. } => {},
+        A { a: 0, b: 0, .. } => {},
+        _ => {},
+    }
+
+    // No lint
+    foo!(a_struct);
+
+    #[non_exhaustive]
+    struct B {
+        a: u32,
+        b: u32,
+        c: u64,
+    }
+
+    let b_struct = B { a: 5, b: 42, c: 342 };
+
+    match b_struct {
+        B { a: 5, b: 42, .. } => {},
+        B { a: 0, b: 0, c: 128, .. } => {}, // No Lint
+        _ => {},
+    }
+}
diff --git a/src/tools/clippy/tests/ui/rest_pat_in_fully_bound_structs.stderr b/src/tools/clippy/tests/ui/rest_pat_in_fully_bound_structs.stderr
index d048933ddb7..8a2da302b9e 100644
--- a/src/tools/clippy/tests/ui/rest_pat_in_fully_bound_structs.stderr
+++ b/src/tools/clippy/tests/ui/rest_pat_in_fully_bound_structs.stderr
@@ -4,9 +4,13 @@ error: unnecessary use of `..` pattern in struct binding. All fields were alread
 LL |         A { a: 5, b: 42, c: "", .. } => {}, // Lint
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
-   = help: consider removing `..` from this binding
    = note: `-D clippy::rest-pat-in-fully-bound-structs` implied by `-D warnings`
    = help: to override `-D warnings` add `#[allow(clippy::rest_pat_in_fully_bound_structs)]`
+help: consider removing `..` from this binding
+   |
+LL -         A { a: 5, b: 42, c: "", .. } => {}, // Lint
+LL +         A { a: 5, b: 42, c: "",  } => {}, // Lint
+   |
 
 error: unnecessary use of `..` pattern in struct binding. All fields were already bound
   --> tests/ui/rest_pat_in_fully_bound_structs.rs:25:9
@@ -14,7 +18,11 @@ error: unnecessary use of `..` pattern in struct binding. All fields were alread
 LL |         A { a: 0, b: 0, c: "", .. } => {}, // Lint
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
-   = help: consider removing `..` from this binding
+help: consider removing `..` from this binding
+   |
+LL -         A { a: 0, b: 0, c: "", .. } => {}, // Lint
+LL +         A { a: 0, b: 0, c: "",  } => {}, // Lint
+   |
 
 error: unnecessary use of `..` pattern in struct binding. All fields were already bound
   --> tests/ui/rest_pat_in_fully_bound_structs.rs:32:9
@@ -22,7 +30,11 @@ error: unnecessary use of `..` pattern in struct binding. All fields were alread
 LL |         A { a: 0, b: 0, c: "", .. } => {}, // Lint
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
-   = help: consider removing `..` from this binding
+help: consider removing `..` from this binding
+   |
+LL -         A { a: 0, b: 0, c: "", .. } => {}, // Lint
+LL +         A { a: 0, b: 0, c: "",  } => {}, // Lint
+   |
 
 error: aborting due to 3 previous errors
 
diff --git a/src/tools/clippy/tests/ui/semicolon_inside_block.fixed b/src/tools/clippy/tests/ui/semicolon_inside_block.fixed
index 7308e78aae2..468f0a5b1e4 100644
--- a/src/tools/clippy/tests/ui/semicolon_inside_block.fixed
+++ b/src/tools/clippy/tests/ui/semicolon_inside_block.fixed
@@ -3,7 +3,8 @@
     clippy::unused_unit,
     clippy::unnecessary_operation,
     clippy::no_effect,
-    clippy::single_element_loop
+    clippy::single_element_loop,
+    clippy::double_parens
 )]
 #![warn(clippy::semicolon_inside_block)]
 
@@ -87,6 +88,20 @@ fn main() {
     unit_fn_block()
 }
 
+#[rustfmt::skip]
+fn issue15380() {
+    ( {0;0});
+
+    ({
+        0;
+        0
+    });
+
+    (({ 0 }))      ;
+
+    ( ( { 0 } ) ) ;
+}
+
 pub fn issue15388() {
     #[rustfmt::skip]
     {0; 0};
diff --git a/src/tools/clippy/tests/ui/semicolon_inside_block.rs b/src/tools/clippy/tests/ui/semicolon_inside_block.rs
index 467bf4d779f..101374af264 100644
--- a/src/tools/clippy/tests/ui/semicolon_inside_block.rs
+++ b/src/tools/clippy/tests/ui/semicolon_inside_block.rs
@@ -3,7 +3,8 @@
     clippy::unused_unit,
     clippy::unnecessary_operation,
     clippy::no_effect,
-    clippy::single_element_loop
+    clippy::single_element_loop,
+    clippy::double_parens
 )]
 #![warn(clippy::semicolon_inside_block)]
 
@@ -87,6 +88,20 @@ fn main() {
     unit_fn_block()
 }
 
+#[rustfmt::skip]
+fn issue15380() {
+    ( {0;0});
+
+    ({
+        0;
+        0
+    });
+
+    (({ 0 }))      ;
+
+    ( ( { 0 } ) ) ;
+}
+
 pub fn issue15388() {
     #[rustfmt::skip]
     {0; 0};
diff --git a/src/tools/clippy/tests/ui/semicolon_inside_block.stderr b/src/tools/clippy/tests/ui/semicolon_inside_block.stderr
index 23433f4e7ef..2046dd1c36b 100644
--- a/src/tools/clippy/tests/ui/semicolon_inside_block.stderr
+++ b/src/tools/clippy/tests/ui/semicolon_inside_block.stderr
@@ -1,5 +1,5 @@
 error: consider moving the `;` inside the block for consistent formatting
-  --> tests/ui/semicolon_inside_block.rs:38:5
+  --> tests/ui/semicolon_inside_block.rs:39:5
    |
 LL |     { unit_fn_block() };
    |     ^^^^^^^^^^^^^^^^^^^^
@@ -13,7 +13,7 @@ LL +     { unit_fn_block(); }
    |
 
 error: consider moving the `;` inside the block for consistent formatting
-  --> tests/ui/semicolon_inside_block.rs:40:5
+  --> tests/ui/semicolon_inside_block.rs:41:5
    |
 LL |     unsafe { unit_fn_block() };
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -25,7 +25,7 @@ LL +     unsafe { unit_fn_block(); }
    |
 
 error: consider moving the `;` inside the block for consistent formatting
-  --> tests/ui/semicolon_inside_block.rs:49:5
+  --> tests/ui/semicolon_inside_block.rs:50:5
    |
 LL | /     {
 LL | |
@@ -41,7 +41,7 @@ LL ~     }
    |
 
 error: consider moving the `;` inside the block for consistent formatting
-  --> tests/ui/semicolon_inside_block.rs:63:5
+  --> tests/ui/semicolon_inside_block.rs:64:5
    |
 LL |     { m!(()) };
    |     ^^^^^^^^^^^
diff --git a/src/tools/clippy/tests/ui/track-diagnostics-clippy.stderr b/src/tools/clippy/tests/ui/track-diagnostics-clippy.stderr
index d5533877b45..3ceb501463b 100644
--- a/src/tools/clippy/tests/ui/track-diagnostics-clippy.stderr
+++ b/src/tools/clippy/tests/ui/track-diagnostics-clippy.stderr
@@ -16,7 +16,7 @@ LL |         let d = 42;
 LL |         d
    |         ^
    |
-   = note: -Ztrack-diagnostics: created at clippy_lints/src/returns.rs:LL:CC
+   = note: -Ztrack-diagnostics: created at clippy_lints/src/returns/let_and_return.rs:LL:CC
    = note: `-D clippy::let-and-return` implied by `-D warnings`
    = help: to override `-D warnings` add `#[allow(clippy::let_and_return)]`
 help: return the expression directly
diff --git a/src/tools/clippy/tests/ui/transmute_ptr_to_ref.fixed b/src/tools/clippy/tests/ui/transmute_ptr_to_ref.fixed
index 61e3ac2fe88..c130575df96 100644
--- a/src/tools/clippy/tests/ui/transmute_ptr_to_ref.fixed
+++ b/src/tools/clippy/tests/ui/transmute_ptr_to_ref.fixed
@@ -5,7 +5,7 @@
     clippy::missing_transmute_annotations
 )]
 
-unsafe fn _ptr_to_ref<T, U>(p: *const T, m: *mut T, o: *const U, om: *mut U) {
+fn ptr_to_ref<T, U>(p: *const T, m: *mut T, o: *const U, om: *mut U) {
     unsafe {
         let _: &T = &*p;
         //~^ transmute_ptr_to_ref
@@ -37,7 +37,7 @@ unsafe fn _ptr_to_ref<T, U>(p: *const T, m: *mut T, o: *const U, om: *mut U) {
     }
 }
 
-fn _issue1231() {
+fn issue1231() {
     struct Foo<'a, T> {
         bar: &'a T,
     }
@@ -55,7 +55,7 @@ fn _issue1231() {
     //~^ transmute_ptr_to_ref
 }
 
-unsafe fn _issue8924<'a, 'b, 'c>(x: *const &'a u32, y: *const &'b u32) -> &'c &'b u32 {
+fn issue8924<'a, 'b, 'c>(x: *const &'a u32, y: *const &'b u32) -> &'c &'b u32 {
     unsafe {
         match 0 {
             0 => &*x.cast::<&u32>(),
@@ -71,7 +71,7 @@ unsafe fn _issue8924<'a, 'b, 'c>(x: *const &'a u32, y: *const &'b u32) -> &'c &'
 }
 
 #[clippy::msrv = "1.38"]
-unsafe fn _meets_msrv<'a, 'b, 'c>(x: *const &'a u32) -> &'c &'b u32 {
+fn meets_msrv<'a, 'b, 'c>(x: *const &'a u32) -> &'c &'b u32 {
     unsafe {
         let a = 0u32;
         let a = &a as *const u32;
@@ -89,7 +89,7 @@ unsafe fn _meets_msrv<'a, 'b, 'c>(x: *const &'a u32) -> &'c &'b u32 {
 }
 
 #[clippy::msrv = "1.37"]
-unsafe fn _under_msrv<'a, 'b, 'c>(x: *const &'a u32) -> &'c &'b u32 {
+fn under_msrv<'a, 'b, 'c>(x: *const &'a u32) -> &'c &'b u32 {
     unsafe {
         let a = 0u32;
         let a = &a as *const u32;
@@ -106,4 +106,33 @@ unsafe fn _under_msrv<'a, 'b, 'c>(x: *const &'a u32) -> &'c &'b u32 {
     }
 }
 
+// handle DSTs
+fn issue13357(ptr: *const [i32], s_ptr: *const &str, a_s_ptr: *const [&str]) {
+    unsafe {
+        // different types, without erased regions
+        let _ = &*(ptr as *const [u32]);
+        //~^ transmute_ptr_to_ref
+        let _: &[u32] = &*(ptr as *const [u32]);
+        //~^ transmute_ptr_to_ref
+
+        // different types, with erased regions
+        let _ = &*(a_s_ptr as *const [&[u8]]);
+        //~^ transmute_ptr_to_ref
+        let _: &[&[u8]] = &*(a_s_ptr as *const [&[u8]]);
+        //~^ transmute_ptr_to_ref
+
+        // same type, without erased regions
+        let _ = &*(ptr as *const [i32]);
+        //~^ transmute_ptr_to_ref
+        let _: &[i32] = &*ptr;
+        //~^ transmute_ptr_to_ref
+
+        // same type, with erased regions
+        let _ = &*(a_s_ptr as *const [&str]);
+        //~^ transmute_ptr_to_ref
+        let _: &[&str] = &*(a_s_ptr as *const [&str]);
+        //~^ transmute_ptr_to_ref
+    }
+}
+
 fn main() {}
diff --git a/src/tools/clippy/tests/ui/transmute_ptr_to_ref.rs b/src/tools/clippy/tests/ui/transmute_ptr_to_ref.rs
index 48e2f527b55..f79d54234a2 100644
--- a/src/tools/clippy/tests/ui/transmute_ptr_to_ref.rs
+++ b/src/tools/clippy/tests/ui/transmute_ptr_to_ref.rs
@@ -5,7 +5,7 @@
     clippy::missing_transmute_annotations
 )]
 
-unsafe fn _ptr_to_ref<T, U>(p: *const T, m: *mut T, o: *const U, om: *mut U) {
+fn ptr_to_ref<T, U>(p: *const T, m: *mut T, o: *const U, om: *mut U) {
     unsafe {
         let _: &T = std::mem::transmute(p);
         //~^ transmute_ptr_to_ref
@@ -37,7 +37,7 @@ unsafe fn _ptr_to_ref<T, U>(p: *const T, m: *mut T, o: *const U, om: *mut U) {
     }
 }
 
-fn _issue1231() {
+fn issue1231() {
     struct Foo<'a, T> {
         bar: &'a T,
     }
@@ -55,7 +55,7 @@ fn _issue1231() {
     //~^ transmute_ptr_to_ref
 }
 
-unsafe fn _issue8924<'a, 'b, 'c>(x: *const &'a u32, y: *const &'b u32) -> &'c &'b u32 {
+fn issue8924<'a, 'b, 'c>(x: *const &'a u32, y: *const &'b u32) -> &'c &'b u32 {
     unsafe {
         match 0 {
             0 => std::mem::transmute(x),
@@ -71,7 +71,7 @@ unsafe fn _issue8924<'a, 'b, 'c>(x: *const &'a u32, y: *const &'b u32) -> &'c &'
 }
 
 #[clippy::msrv = "1.38"]
-unsafe fn _meets_msrv<'a, 'b, 'c>(x: *const &'a u32) -> &'c &'b u32 {
+fn meets_msrv<'a, 'b, 'c>(x: *const &'a u32) -> &'c &'b u32 {
     unsafe {
         let a = 0u32;
         let a = &a as *const u32;
@@ -89,7 +89,7 @@ unsafe fn _meets_msrv<'a, 'b, 'c>(x: *const &'a u32) -> &'c &'b u32 {
 }
 
 #[clippy::msrv = "1.37"]
-unsafe fn _under_msrv<'a, 'b, 'c>(x: *const &'a u32) -> &'c &'b u32 {
+fn under_msrv<'a, 'b, 'c>(x: *const &'a u32) -> &'c &'b u32 {
     unsafe {
         let a = 0u32;
         let a = &a as *const u32;
@@ -106,4 +106,33 @@ unsafe fn _under_msrv<'a, 'b, 'c>(x: *const &'a u32) -> &'c &'b u32 {
     }
 }
 
+// handle DSTs
+fn issue13357(ptr: *const [i32], s_ptr: *const &str, a_s_ptr: *const [&str]) {
+    unsafe {
+        // different types, without erased regions
+        let _ = core::mem::transmute::<_, &[u32]>(ptr);
+        //~^ transmute_ptr_to_ref
+        let _: &[u32] = core::mem::transmute(ptr);
+        //~^ transmute_ptr_to_ref
+
+        // different types, with erased regions
+        let _ = core::mem::transmute::<_, &[&[u8]]>(a_s_ptr);
+        //~^ transmute_ptr_to_ref
+        let _: &[&[u8]] = core::mem::transmute(a_s_ptr);
+        //~^ transmute_ptr_to_ref
+
+        // same type, without erased regions
+        let _ = core::mem::transmute::<_, &[i32]>(ptr);
+        //~^ transmute_ptr_to_ref
+        let _: &[i32] = core::mem::transmute(ptr);
+        //~^ transmute_ptr_to_ref
+
+        // same type, with erased regions
+        let _ = core::mem::transmute::<_, &[&str]>(a_s_ptr);
+        //~^ transmute_ptr_to_ref
+        let _: &[&str] = core::mem::transmute(a_s_ptr);
+        //~^ transmute_ptr_to_ref
+    }
+}
+
 fn main() {}
diff --git a/src/tools/clippy/tests/ui/transmute_ptr_to_ref.stderr b/src/tools/clippy/tests/ui/transmute_ptr_to_ref.stderr
index 7685c345c86..3f404d295fe 100644
--- a/src/tools/clippy/tests/ui/transmute_ptr_to_ref.stderr
+++ b/src/tools/clippy/tests/ui/transmute_ptr_to_ref.stderr
@@ -43,13 +43,13 @@ error: transmute from a pointer type (`*mut U`) to a reference type (`&T`)
 LL |         let _: &T = std::mem::transmute(om);
    |                     ^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&*(om as *const T)`
 
-error: transmute from a pointer type (`*const i32`) to a reference type (`&_issue1231::Foo<'_, u8>`)
+error: transmute from a pointer type (`*const i32`) to a reference type (`&issue1231::Foo<'_, u8>`)
   --> tests/ui/transmute_ptr_to_ref.rs:46:32
    |
 LL |     let _: &Foo<u8> = unsafe { std::mem::transmute::<_, &Foo<_>>(raw) };
    |                                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&*raw.cast::<Foo<_>>()`
 
-error: transmute from a pointer type (`*const i32`) to a reference type (`&_issue1231::Foo<'_, &u8>`)
+error: transmute from a pointer type (`*const i32`) to a reference type (`&issue1231::Foo<'_, &u8>`)
   --> tests/ui/transmute_ptr_to_ref.rs:49:33
    |
 LL |     let _: &Foo<&u8> = unsafe { std::mem::transmute::<_, &Foo<&_>>(raw) };
@@ -133,5 +133,53 @@ error: transmute from a pointer type (`*const &u32`) to a reference type (`&&u32
 LL |             _ => std::mem::transmute::<_, &&'b u32>(x),
    |                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&*(x as *const () as *const &'b u32)`
 
-error: aborting due to 22 previous errors
+error: transmute from a pointer type (`*const [i32]`) to a reference type (`&[u32]`)
+  --> tests/ui/transmute_ptr_to_ref.rs:113:17
+   |
+LL |         let _ = core::mem::transmute::<_, &[u32]>(ptr);
+   |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&*(ptr as *const [u32])`
+
+error: transmute from a pointer type (`*const [i32]`) to a reference type (`&[u32]`)
+  --> tests/ui/transmute_ptr_to_ref.rs:115:25
+   |
+LL |         let _: &[u32] = core::mem::transmute(ptr);
+   |                         ^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&*(ptr as *const [u32])`
+
+error: transmute from a pointer type (`*const [&str]`) to a reference type (`&[&[u8]]`)
+  --> tests/ui/transmute_ptr_to_ref.rs:119:17
+   |
+LL |         let _ = core::mem::transmute::<_, &[&[u8]]>(a_s_ptr);
+   |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&*(a_s_ptr as *const [&[u8]])`
+
+error: transmute from a pointer type (`*const [&str]`) to a reference type (`&[&[u8]]`)
+  --> tests/ui/transmute_ptr_to_ref.rs:121:27
+   |
+LL |         let _: &[&[u8]] = core::mem::transmute(a_s_ptr);
+   |                           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&*(a_s_ptr as *const [&[u8]])`
+
+error: transmute from a pointer type (`*const [i32]`) to a reference type (`&[i32]`)
+  --> tests/ui/transmute_ptr_to_ref.rs:125:17
+   |
+LL |         let _ = core::mem::transmute::<_, &[i32]>(ptr);
+   |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&*(ptr as *const [i32])`
+
+error: transmute from a pointer type (`*const [i32]`) to a reference type (`&[i32]`)
+  --> tests/ui/transmute_ptr_to_ref.rs:127:25
+   |
+LL |         let _: &[i32] = core::mem::transmute(ptr);
+   |                         ^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&*ptr`
+
+error: transmute from a pointer type (`*const [&str]`) to a reference type (`&[&str]`)
+  --> tests/ui/transmute_ptr_to_ref.rs:131:17
+   |
+LL |         let _ = core::mem::transmute::<_, &[&str]>(a_s_ptr);
+   |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&*(a_s_ptr as *const [&str])`
+
+error: transmute from a pointer type (`*const [&str]`) to a reference type (`&[&str]`)
+  --> tests/ui/transmute_ptr_to_ref.rs:133:26
+   |
+LL |         let _: &[&str] = core::mem::transmute(a_s_ptr);
+   |                          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&*(a_s_ptr as *const [&str])`
+
+error: aborting due to 30 previous errors
 
diff --git a/src/tools/clippy/tests/ui/use_self.fixed b/src/tools/clippy/tests/ui/use_self.fixed
index cccb6bffabb..075e31d202b 100644
--- a/src/tools/clippy/tests/ui/use_self.fixed
+++ b/src/tools/clippy/tests/ui/use_self.fixed
@@ -530,8 +530,8 @@ mod issue7206 {
 
     impl<'a> S2<S<'a>> {
         fn new_again() -> Self {
-            Self::new()
-            //~^ use_self
+            S2::new()
+            // FIXME: ^Broken by PR #15611
         }
     }
 }
@@ -755,3 +755,17 @@ mod crash_check_13128 {
         }
     }
 }
+
+mod issue_13277 {
+    trait Foo {
+        type Item<'foo>;
+    }
+    struct Bar<'b> {
+        content: &'b str,
+    }
+    impl<'b> Foo for Option<Bar<'b>> {
+        // when checking whether `Option<Bar<'foo>>` has a lifetime, check not only the outer
+        // `Option<T>`, but also the inner `Bar<'foo>`
+        type Item<'foo> = Option<Bar<'foo>>;
+    }
+}
diff --git a/src/tools/clippy/tests/ui/use_self.rs b/src/tools/clippy/tests/ui/use_self.rs
index 09288677aa7..6fbba0bbc55 100644
--- a/src/tools/clippy/tests/ui/use_self.rs
+++ b/src/tools/clippy/tests/ui/use_self.rs
@@ -531,7 +531,7 @@ mod issue7206 {
     impl<'a> S2<S<'a>> {
         fn new_again() -> Self {
             S2::new()
-            //~^ use_self
+            // FIXME: ^Broken by PR #15611
         }
     }
 }
@@ -755,3 +755,17 @@ mod crash_check_13128 {
         }
     }
 }
+
+mod issue_13277 {
+    trait Foo {
+        type Item<'foo>;
+    }
+    struct Bar<'b> {
+        content: &'b str,
+    }
+    impl<'b> Foo for Option<Bar<'b>> {
+        // when checking whether `Option<Bar<'foo>>` has a lifetime, check not only the outer
+        // `Option<T>`, but also the inner `Bar<'foo>`
+        type Item<'foo> = Option<Bar<'foo>>;
+    }
+}
diff --git a/src/tools/clippy/tests/ui/use_self.stderr b/src/tools/clippy/tests/ui/use_self.stderr
index 781327696ac..5f65c53ea25 100644
--- a/src/tools/clippy/tests/ui/use_self.stderr
+++ b/src/tools/clippy/tests/ui/use_self.stderr
@@ -170,12 +170,6 @@ LL |             A::new::<submod::B>(submod::B {})
    |             ^ help: use the applicable keyword: `Self`
 
 error: unnecessary structure name repetition
-  --> tests/ui/use_self.rs:533:13
-   |
-LL |             S2::new()
-   |             ^^ help: use the applicable keyword: `Self`
-
-error: unnecessary structure name repetition
   --> tests/ui/use_self.rs:571:17
    |
 LL |                 Foo::Bar => unimplemented!(),
@@ -259,5 +253,5 @@ error: unnecessary structure name repetition
 LL |                 E::A => {},
    |                 ^ help: use the applicable keyword: `Self`
 
-error: aborting due to 43 previous errors
+error: aborting due to 42 previous errors
 
diff --git a/src/tools/clippy/tests/ui/useless_attribute.fixed b/src/tools/clippy/tests/ui/useless_attribute.fixed
index be4fb55ddfb..15070dd9c2c 100644
--- a/src/tools/clippy/tests/ui/useless_attribute.fixed
+++ b/src/tools/clippy/tests/ui/useless_attribute.fixed
@@ -158,3 +158,13 @@ pub mod redundant_imports_issue {
 
     empty!();
 }
+
+pub mod issue15636 {
+    pub mod f {
+        #[deprecated(since = "TBD")]
+        pub mod deprec {}
+    }
+
+    #[allow(deprecated_in_future)]
+    pub use f::deprec;
+}
diff --git a/src/tools/clippy/tests/ui/useless_attribute.rs b/src/tools/clippy/tests/ui/useless_attribute.rs
index 5a1bcf97a5b..3f530de7fd8 100644
--- a/src/tools/clippy/tests/ui/useless_attribute.rs
+++ b/src/tools/clippy/tests/ui/useless_attribute.rs
@@ -158,3 +158,13 @@ pub mod redundant_imports_issue {
 
     empty!();
 }
+
+pub mod issue15636 {
+    pub mod f {
+        #[deprecated(since = "TBD")]
+        pub mod deprec {}
+    }
+
+    #[allow(deprecated_in_future)]
+    pub use f::deprec;
+}