about summary refs log tree commit diff
diff options
context:
space:
mode:
authorPhilipp Krones <hello@philkrones.com>2024-05-02 17:26:44 +0200
committerPhilipp Krones <hello@philkrones.com>2024-05-02 17:26:44 +0200
commit15a648510d3ef4c3057d10729deb563f4d95877d (patch)
treeb4db38e3a6526446bd5cabda98b9813d5e8a3f30
parentf5efc3c286a8e625f7932f9e6f52e5812a4b67fc (diff)
parent20b085d500dfba5afe0869707bf357af3afe20be (diff)
downloadrust-15a648510d3ef4c3057d10729deb563f4d95877d.tar.gz
rust-15a648510d3ef4c3057d10729deb563f4d95877d.zip
Merge commit '20b085d500dfba5afe0869707bf357af3afe20be' into clippy-subtree-update
-rw-r--r--src/tools/clippy/CHANGELOG.md56
-rw-r--r--src/tools/clippy/Cargo.toml4
-rw-r--r--src/tools/clippy/book/src/development/adding_lints.md8
-rw-r--r--src/tools/clippy/book/src/lint_configuration.md15
-rw-r--r--src/tools/clippy/clippy_config/Cargo.toml2
-rw-r--r--src/tools/clippy/clippy_config/src/conf.rs9
-rw-r--r--src/tools/clippy/clippy_config/src/msrvs.rs2
-rw-r--r--src/tools/clippy/clippy_lints/Cargo.toml2
-rw-r--r--src/tools/clippy/clippy_lints/src/assigning_clones.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/box_default.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/cargo/mod.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/casts/cast_possible_truncation.rs7
-rw-r--r--src/tools/clippy/clippy_lints/src/casts/mod.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/collection_is_never_read.rs27
-rw-r--r--src/tools/clippy/clippy_lints/src/copies.rs44
-rw-r--r--src/tools/clippy/clippy_lints/src/dbg_macro.rs10
-rw-r--r--src/tools/clippy/clippy_lints/src/dereference.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/format_args.rs6
-rw-r--r--src/tools/clippy/clippy_lints/src/implied_bounds_in_impls.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/index_refutable_slice.rs9
-rw-r--r--src/tools/clippy/clippy_lints/src/large_stack_arrays.rs65
-rw-r--r--src/tools/clippy/clippy_lints/src/lib.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/loops/unused_enumerate_index.rs7
-rw-r--r--src/tools/clippy/clippy_lints/src/manual_assert.rs5
-rw-r--r--src/tools/clippy/clippy_lints/src/manual_is_ascii_check.rs101
-rw-r--r--src/tools/clippy/clippy_lints/src/matches/collapsible_match.rs23
-rw-r--r--src/tools/clippy/clippy_lints/src/matches/mod.rs23
-rw-r--r--src/tools/clippy/clippy_lints/src/matches/redundant_guards.rs27
-rw-r--r--src/tools/clippy/clippy_lints/src/matches/single_match.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/filter_map.rs5
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/iter_overeager_cloned.rs3
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/mod.rs17
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/readonly_write_lock.rs7
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/single_char_insert_string.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/single_char_pattern.rs6
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/single_char_push_string.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/unused_enumerate_index.rs9
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/utils.rs8
-rw-r--r--src/tools/clippy/clippy_lints/src/multiple_bound_locations.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/mut_key.rs67
-rw-r--r--src/tools/clippy/clippy_lints/src/needless_for_each.rs16
-rw-r--r--src/tools/clippy/clippy_lints/src/needless_late_init.rs3
-rw-r--r--src/tools/clippy/clippy_lints/src/needless_pass_by_ref_mut.rs26
-rw-r--r--src/tools/clippy/clippy_lints/src/needless_pass_by_value.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/non_canonical_impls.rs46
-rw-r--r--src/tools/clippy/clippy_lints/src/non_copy_const.rs99
-rw-r--r--src/tools/clippy/clippy_lints/src/operators/arithmetic_side_effects.rs53
-rw-r--r--src/tools/clippy/clippy_lints/src/ptr.rs9
-rw-r--r--src/tools/clippy/clippy_lints/src/question_mark.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/repeat_vec_with_capacity.rs5
-rw-r--r--src/tools/clippy/clippy_lints/src/size_of_ref.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/slow_vector_initialization.rs6
-rw-r--r--src/tools/clippy/clippy_lints/src/thread_local_initializer_can_be_made_const.rs36
-rw-r--r--src/tools/clippy/clippy_lints/src/to_string_trait_impl.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/trait_bounds.rs1
-rw-r--r--src/tools/clippy/clippy_lints/src/types/mod.rs12
-rw-r--r--src/tools/clippy/clippy_lints/src/utils/author.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/vec.rs6
-rw-r--r--src/tools/clippy/clippy_lints/src/vec_init_then_push.rs4
-rw-r--r--src/tools/clippy/clippy_utils/Cargo.toml2
-rw-r--r--src/tools/clippy/clippy_utils/src/lib.rs16
-rw-r--r--src/tools/clippy/clippy_utils/src/macros.rs10
-rw-r--r--src/tools/clippy/clippy_utils/src/paths.rs5
-rw-r--r--src/tools/clippy/clippy_utils/src/ty.rs124
-rw-r--r--src/tools/clippy/declare_clippy_lint/Cargo.toml2
-rw-r--r--src/tools/clippy/rust-toolchain2
-rw-r--r--src/tools/clippy/tests/compile-test.rs13
-rw-r--r--src/tools/clippy/tests/ui-toml/mut_key/mut_key.rs8
-rw-r--r--src/tools/clippy/tests/ui-toml/toml_unknown_key/conf_unknown_key.stderr3
-rw-r--r--src/tools/clippy/tests/ui-toml/useless_vec/clippy.toml1
-rw-r--r--src/tools/clippy/tests/ui-toml/useless_vec/useless_vec.fixed26
-rw-r--r--src/tools/clippy/tests/ui-toml/useless_vec/useless_vec.rs26
-rw-r--r--src/tools/clippy/tests/ui-toml/useless_vec/useless_vec.stderr11
-rw-r--r--src/tools/clippy/tests/ui/arithmetic_side_effects.rs10
-rw-r--r--src/tools/clippy/tests/ui/arithmetic_side_effects.stderr14
-rw-r--r--src/tools/clippy/tests/ui/auxiliary/proc_macros.rs17
-rw-r--r--src/tools/clippy/tests/ui/borrow_interior_mutable_const/traits.rs4
-rw-r--r--src/tools/clippy/tests/ui/borrow_interior_mutable_const/traits.stderr18
-rw-r--r--src/tools/clippy/tests/ui/box_default.fixed12
-rw-r--r--src/tools/clippy/tests/ui/box_default.rs12
-rw-r--r--src/tools/clippy/tests/ui/box_default.stderr8
-rw-r--r--src/tools/clippy/tests/ui/cast.rs21
-rw-r--r--src/tools/clippy/tests/ui/cast.stderr206
-rw-r--r--src/tools/clippy/tests/ui/collapsible_match.rs16
-rw-r--r--src/tools/clippy/tests/ui/collapsible_match.stderr68
-rw-r--r--src/tools/clippy/tests/ui/collection_is_never_read.rs14
-rw-r--r--src/tools/clippy/tests/ui/crashes/ice-5238.rs3
-rw-r--r--src/tools/clippy/tests/ui/declare_interior_mutable_const/traits.rs5
-rw-r--r--src/tools/clippy/tests/ui/declare_interior_mutable_const/traits.stderr20
-rw-r--r--src/tools/clippy/tests/ui/disallowed_names.rs5
-rw-r--r--src/tools/clippy/tests/ui/large_stack_arrays.rs48
-rw-r--r--src/tools/clippy/tests/ui/large_stack_arrays.stderr60
-rw-r--r--src/tools/clippy/tests/ui/manual_is_ascii_check.fixed27
-rw-r--r--src/tools/clippy/tests/ui/manual_is_ascii_check.rs27
-rw-r--r--src/tools/clippy/tests/ui/manual_is_ascii_check.stderr42
-rw-r--r--src/tools/clippy/tests/ui/mistyped_literal_suffix.fixed2
-rw-r--r--src/tools/clippy/tests/ui/mistyped_literal_suffix.rs2
-rw-r--r--src/tools/clippy/tests/ui/mut_key.rs10
-rw-r--r--src/tools/clippy/tests/ui/mut_key.stderr32
-rw-r--r--src/tools/clippy/tests/ui/needless_for_each_fixable.fixed4
-rw-r--r--src/tools/clippy/tests/ui/needless_for_each_fixable.rs4
-rw-r--r--src/tools/clippy/tests/ui/needless_pass_by_ref_mut.rs42
-rw-r--r--src/tools/clippy/tests/ui/needless_pass_by_ref_mut.stderr98
-rw-r--r--src/tools/clippy/tests/ui/needless_pass_by_ref_mut2.fixed24
-rw-r--r--src/tools/clippy/tests/ui/needless_pass_by_ref_mut2.rs24
-rw-r--r--src/tools/clippy/tests/ui/needless_pass_by_ref_mut2.stderr20
-rw-r--r--src/tools/clippy/tests/ui/non_canonical_partial_ord_impl.fixed18
-rw-r--r--src/tools/clippy/tests/ui/non_canonical_partial_ord_impl.rs18
-rw-r--r--src/tools/clippy/tests/ui/readonly_write_lock.fixed4
-rw-r--r--src/tools/clippy/tests/ui/readonly_write_lock.rs4
-rw-r--r--src/tools/clippy/tests/ui/redundant_guards.fixed12
-rw-r--r--src/tools/clippy/tests/ui/redundant_guards.rs12
-rw-r--r--src/tools/clippy/tests/ui/redundant_guards.stderr34
-rw-r--r--src/tools/clippy/tests/ui/redundant_locals.rs22
-rw-r--r--src/tools/clippy/tests/ui/single_char_pattern.fixed14
-rw-r--r--src/tools/clippy/tests/ui/single_char_pattern.rs8
-rw-r--r--src/tools/clippy/tests/ui/single_char_pattern.stderr62
-rw-r--r--src/tools/clippy/tests/ui/thread_local_initializer_can_be_made_const.fixed33
-rw-r--r--src/tools/clippy/tests/ui/thread_local_initializer_can_be_made_const.rs33
-rw-r--r--src/tools/clippy/tests/ui/type_complexity.rs2
-rw-r--r--src/tools/clippy/tests/ui/type_complexity.stderr30
-rw-r--r--src/tools/clippy/tests/ui/type_id_on_box_unfixable.rs2
-rw-r--r--src/tools/clippy/triagebot.toml1
-rw-r--r--src/tools/clippy/util/gh-pages/script.js2
124 files changed, 1664 insertions, 755 deletions
diff --git a/src/tools/clippy/CHANGELOG.md b/src/tools/clippy/CHANGELOG.md
index bd3a04e34ae..9c9ea114081 100644
--- a/src/tools/clippy/CHANGELOG.md
+++ b/src/tools/clippy/CHANGELOG.md
@@ -6,11 +6,62 @@ document.
 
 ## Unreleased / Beta / In Rust Nightly
 
-[66c29b97...master](https://github.com/rust-lang/rust-clippy/compare/66c29b97...master)
+[93f0a9a9...master](https://github.com/rust-lang/rust-clippy/compare/93f0a9a9...master)
+
+## Rust 1.78
+
+Current stable, released 2024-05-02
+
+[View all 112 merged pull requests](https://github.com/rust-lang/rust-clippy/pulls?q=merged%3A2024-01-26T05%3A46%3A23Z..2024-03-07T16%3A25%3A52Z+base%3Amaster)
+
+### New Lints
+
+* [`assigning_clones`]
+  [#12077](https://github.com/rust-lang/rust-clippy/pull/12077)
+* [`mixed_attributes_style`]
+  [#12354](https://github.com/rust-lang/rust-clippy/pull/12354)
+* [`empty_docs`]
+  [#12342](https://github.com/rust-lang/rust-clippy/pull/12342)
+* [`unnecessary_get_then_check`]
+  [#12339](https://github.com/rust-lang/rust-clippy/pull/12339)
+* [`multiple_bound_locations`]
+  [#12259](https://github.com/rust-lang/rust-clippy/pull/12259)
+* [`unnecessary_clippy_cfg`]
+  [#12303](https://github.com/rust-lang/rust-clippy/pull/12303)
+* [`deprecated_clippy_cfg_attr`]
+  [#12292](https://github.com/rust-lang/rust-clippy/pull/12292)
+* [`manual_c_str_literals`]
+  [#11919](https://github.com/rust-lang/rust-clippy/pull/11919)
+* [`ref_as_ptr`]
+  [#12087](https://github.com/rust-lang/rust-clippy/pull/12087)
+* [`lint_groups_priority`]
+  [#11832](https://github.com/rust-lang/rust-clippy/pull/11832)
+* [`unnecessary_result_map_or_else`]
+  [#12169](https://github.com/rust-lang/rust-clippy/pull/12169)
+* [`to_string_trait_impl`]
+  [#12122](https://github.com/rust-lang/rust-clippy/pull/12122)
+* [`incompatible_msrv`]
+  [#12160](https://github.com/rust-lang/rust-clippy/pull/12160)
+
+### Enhancements
+
+* [`thread_local_initializer_can_be_made_const`]: Now checks the [`msrv`] configuration
+  [#12405](https://github.com/rust-lang/rust-clippy/pull/12405)
+* [`disallowed_macros`]: Code generated by derive macros can no longer allow this lint
+  [#12267](https://github.com/rust-lang/rust-clippy/pull/12267)
+* [`wildcard_imports`]: Add configuration [`allowed-wildcard-imports`] to allow preconfigured wildcards
+  [#11979](https://github.com/rust-lang/rust-clippy/pull/11979)
+
+### ICE Fixes
+
+* [`ptr_as_ptr`]: No longer ICEs when the cast source is a function call to a local variable
+  [#12617](https://github.com/rust-lang/rust-clippy/pull/12617)
+* [`cast_sign_loss`]: Avoids an infinite loop when casting two chained `.unwrap()` calls
+  [#12508](https://github.com/rust-lang/rust-clippy/pull/12508)
 
 ## Rust 1.77
 
-Current stable, released 2024-03-18
+Released 2024-03-18
 
 [View all 93 merged pull requests](https://github.com/rust-lang/rust-clippy/pulls?q=merged%3A2023-12-16T18%3A20%3A00Z..2024-01-25T18%3A15%3A56Z+base%3Amaster)
 
@@ -5891,6 +5942,7 @@ Released 2018-09-13
 [`allow-print-in-tests`]: https://doc.rust-lang.org/clippy/lint_configuration.html#allow-print-in-tests
 [`allow-private-module-inception`]: https://doc.rust-lang.org/clippy/lint_configuration.html#allow-private-module-inception
 [`allow-unwrap-in-tests`]: https://doc.rust-lang.org/clippy/lint_configuration.html#allow-unwrap-in-tests
+[`allow-useless-vec-in-tests`]: https://doc.rust-lang.org/clippy/lint_configuration.html#allow-useless-vec-in-tests
 [`allowed-dotfiles`]: https://doc.rust-lang.org/clippy/lint_configuration.html#allowed-dotfiles
 [`allowed-duplicate-crates`]: https://doc.rust-lang.org/clippy/lint_configuration.html#allowed-duplicate-crates
 [`allowed-idents-below-min-chars`]: https://doc.rust-lang.org/clippy/lint_configuration.html#allowed-idents-below-min-chars
diff --git a/src/tools/clippy/Cargo.toml b/src/tools/clippy/Cargo.toml
index 43f20ecedc2..b48f3ab3919 100644
--- a/src/tools/clippy/Cargo.toml
+++ b/src/tools/clippy/Cargo.toml
@@ -1,6 +1,6 @@
 [package]
 name = "clippy"
-version = "0.1.79"
+version = "0.1.80"
 description = "A bunch of helpful lints to avoid common pitfalls in Rust"
 repository = "https://github.com/rust-lang/rust-clippy"
 readme = "README.md"
@@ -30,7 +30,7 @@ color-print = "0.3.4"
 anstream = "0.6.0"
 
 [dev-dependencies]
-ui_test = "0.22.2"
+ui_test = "0.23"
 regex = "1.5.5"
 toml = "0.7.3"
 walkdir = "2.3"
diff --git a/src/tools/clippy/book/src/development/adding_lints.md b/src/tools/clippy/book/src/development/adding_lints.md
index b80ac6370e7..415022612ca 100644
--- a/src/tools/clippy/book/src/development/adding_lints.md
+++ b/src/tools/clippy/book/src/development/adding_lints.md
@@ -299,10 +299,10 @@ This is good, because it makes writing this particular lint less complicated.
 We have to make this decision with every new Clippy lint. It boils down to using
 either [`EarlyLintPass`][early_lint_pass] or [`LateLintPass`][late_lint_pass].
 
-In short, the `LateLintPass` has access to type information while the
-`EarlyLintPass` doesn't. If you don't need access to type information, use the
-`EarlyLintPass`. The `EarlyLintPass` is also faster. However, linting speed
-hasn't really been a concern with Clippy so far.
+In short, the `EarlyLintPass` runs before type checking and
+[HIR](https://rustc-dev-guide.rust-lang.org/hir.html) lowering and the `LateLintPass`
+has access to type information. Consider using the `LateLintPass` unless you need
+something specific from the `EarlyLintPass`.
 
 Since we don't need type information for checking the function name, we used
 `--pass=early` when running the new lint automation and all the imports were
diff --git a/src/tools/clippy/book/src/lint_configuration.md b/src/tools/clippy/book/src/lint_configuration.md
index 7cefa685264..f6af9810ca1 100644
--- a/src/tools/clippy/book/src/lint_configuration.md
+++ b/src/tools/clippy/book/src/lint_configuration.md
@@ -132,6 +132,16 @@ Whether `unwrap` should be allowed in test functions or `#[cfg(test)]`
 * [`unwrap_used`](https://rust-lang.github.io/rust-clippy/master/index.html#unwrap_used)
 
 
+## `allow-useless-vec-in-tests`
+Whether `useless_vec` should ignore test functions or `#[cfg(test)]`
+
+**Default Value:** `false`
+
+---
+**Affected lints:**
+* [`useless_vec`](https://rust-lang.github.io/rust-clippy/master/index.html#useless_vec)
+
+
 ## `allowed-dotfiles`
 Additional dotfiles (files or directories starting with a dot) to allow
 
@@ -506,13 +516,14 @@ The maximum byte size a `Future` can have, before it triggers the `clippy::large
 
 
 ## `ignore-interior-mutability`
-A list of paths to types that should be treated like `Arc`, i.e. ignored but
-for the generic parameters for determining interior mutability
+A list of paths to types that should be treated as if they do not contain interior mutability
 
 **Default Value:** `["bytes::Bytes"]`
 
 ---
 **Affected lints:**
+* [`borrow_interior_mutable_const`](https://rust-lang.github.io/rust-clippy/master/index.html#borrow_interior_mutable_const)
+* [`declare_interior_mutable_const`](https://rust-lang.github.io/rust-clippy/master/index.html#declare_interior_mutable_const)
 * [`ifs_same_cond`](https://rust-lang.github.io/rust-clippy/master/index.html#ifs_same_cond)
 * [`mutable_key_type`](https://rust-lang.github.io/rust-clippy/master/index.html#mutable_key_type)
 
diff --git a/src/tools/clippy/clippy_config/Cargo.toml b/src/tools/clippy/clippy_config/Cargo.toml
index 8ba2ab56625..7f7dc9d6cfb 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.79"
+version = "0.1.80"
 edition = "2021"
 
 # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
diff --git a/src/tools/clippy/clippy_config/src/conf.rs b/src/tools/clippy/clippy_config/src/conf.rs
index 781282213cc..5cfcbdb57d7 100644
--- a/src/tools/clippy/clippy_config/src/conf.rs
+++ b/src/tools/clippy/clippy_config/src/conf.rs
@@ -463,14 +463,17 @@ define_Conf! {
     ///
     /// Whether print macros (ex. `println!`) should be allowed in test functions or `#[cfg(test)]`
     (allow_print_in_tests: bool = false),
+    /// Lint: USELESS_VEC.
+    ///
+    /// Whether `useless_vec` should ignore test functions or `#[cfg(test)]`
+    (allow_useless_vec_in_tests: bool = false),
     /// Lint: RESULT_LARGE_ERR.
     ///
     /// The maximum size of the `Err`-variant in a `Result` returned from a function
     (large_error_threshold: u64 = 128),
-    /// Lint: MUTABLE_KEY_TYPE, IFS_SAME_COND.
+    /// Lint: MUTABLE_KEY_TYPE, IFS_SAME_COND, BORROW_INTERIOR_MUTABLE_CONST, DECLARE_INTERIOR_MUTABLE_CONST.
     ///
-    /// A list of paths to types that should be treated like `Arc`, i.e. ignored but
-    /// for the generic parameters for determining interior mutability
+    /// A list of paths to types that should be treated as if they do not contain interior mutability
     (ignore_interior_mutability: Vec<String> = Vec::from(["bytes::Bytes".into()])),
     /// Lint: UNINLINED_FORMAT_ARGS.
     ///
diff --git a/src/tools/clippy/clippy_config/src/msrvs.rs b/src/tools/clippy/clippy_config/src/msrvs.rs
index 59dd5b334b8..14808440d48 100644
--- a/src/tools/clippy/clippy_config/src/msrvs.rs
+++ b/src/tools/clippy/clippy_config/src/msrvs.rs
@@ -23,7 +23,7 @@ msrv_aliases! {
     1,70,0 { OPTION_RESULT_IS_VARIANT_AND, BINARY_HEAP_RETAIN }
     1,68,0 { PATH_MAIN_SEPARATOR_STR }
     1,65,0 { LET_ELSE, POINTER_CAST_CONSTNESS }
-    1,63,0 { ASSIGNING_CLONES }
+    1,63,0 { CLONE_INTO }
     1,62,0 { BOOL_THEN_SOME, DEFAULT_ENUM_ATTRIBUTE }
     1,59,0 { THREAD_LOCAL_INITIALIZER_CAN_BE_MADE_CONST }
     1,58,0 { FORMAT_ARGS_CAPTURE, PATTERN_TRAIT_CHAR_ARRAY }
diff --git a/src/tools/clippy/clippy_lints/Cargo.toml b/src/tools/clippy/clippy_lints/Cargo.toml
index 1d954607eee..5e3a119337c 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.79"
+version = "0.1.80"
 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/assigning_clones.rs b/src/tools/clippy/clippy_lints/src/assigning_clones.rs
index dc7f44af2b7..f0dafb1ae0d 100644
--- a/src/tools/clippy/clippy_lints/src/assigning_clones.rs
+++ b/src/tools/clippy/clippy_lints/src/assigning_clones.rs
@@ -45,7 +45,7 @@ declare_clippy_lint! {
     ///     a.clone_from(&b);
     /// }
     /// ```
-    #[clippy::version = "1.77.0"]
+    #[clippy::version = "1.78.0"]
     pub ASSIGNING_CLONES,
     perf,
     "assigning the result of cloning may be inefficient"
@@ -153,7 +153,7 @@ fn extract_call<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) -> Option<
 fn is_ok_to_suggest<'tcx>(cx: &LateContext<'tcx>, lhs: &Expr<'tcx>, call: &CallCandidate<'tcx>, msrv: &Msrv) -> bool {
     // For calls to .to_owned we suggest using .clone_into(), which was only stablilized in 1.63.
     // If the current MSRV is below that, don't suggest the lint.
-    if !msrv.meets(msrvs::ASSIGNING_CLONES) && matches!(call.target, TargetTrait::ToOwned) {
+    if !msrv.meets(msrvs::CLONE_INTO) && matches!(call.target, TargetTrait::ToOwned) {
         return false;
     }
 
diff --git a/src/tools/clippy/clippy_lints/src/box_default.rs b/src/tools/clippy/clippy_lints/src/box_default.rs
index 4062212f408..8459f051d3d 100644
--- a/src/tools/clippy/clippy_lints/src/box_default.rs
+++ b/src/tools/clippy/clippy_lints/src/box_default.rs
@@ -121,9 +121,9 @@ fn given_type(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
             if let Some(index) = args.iter().position(|arg| arg.hir_id == expr.hir_id)
                 && let Some(sig) = expr_sig(cx, path)
                 && let Some(input) = sig.input(index)
-                && !cx.typeck_results().expr_ty_adjusted(expr).boxed_ty().is_trait()
+                && let Some(input_ty) = input.no_bound_vars()
             {
-                input.no_bound_vars().is_some()
+                input_ty == cx.typeck_results().expr_ty_adjusted(expr)
             } else {
                 false
             }
diff --git a/src/tools/clippy/clippy_lints/src/cargo/mod.rs b/src/tools/clippy/clippy_lints/src/cargo/mod.rs
index ca7fa4e5a41..593bc6c81ee 100644
--- a/src/tools/clippy/clippy_lints/src/cargo/mod.rs
+++ b/src/tools/clippy/clippy_lints/src/cargo/mod.rs
@@ -197,7 +197,7 @@ declare_clippy_lint! {
     /// pedantic = { level = "warn", priority = -1 }
     /// similar_names = "allow"
     /// ```
-    #[clippy::version = "1.76.0"]
+    #[clippy::version = "1.78.0"]
     pub LINT_GROUPS_PRIORITY,
     correctness,
     "a lint group in `Cargo.toml` at the same priority as a lint"
diff --git a/src/tools/clippy/clippy_lints/src/casts/cast_possible_truncation.rs b/src/tools/clippy/clippy_lints/src/casts/cast_possible_truncation.rs
index dbfa8e1ee91..7c5acd1a678 100644
--- a/src/tools/clippy/clippy_lints/src/casts/cast_possible_truncation.rs
+++ b/src/tools/clippy/clippy_lints/src/casts/cast_possible_truncation.rs
@@ -40,9 +40,14 @@ fn apply_reductions(cx: &LateContext<'_>, nbits: u64, expr: &Expr<'_>, signed: b
                     get_constant_bits(cx, right).map_or(0, |b| b.saturating_sub(1))
                 })
             },
-            BinOpKind::Rem | BinOpKind::BitAnd => get_constant_bits(cx, right)
+            BinOpKind::Rem => get_constant_bits(cx, right)
                 .unwrap_or(u64::MAX)
                 .min(apply_reductions(cx, nbits, left, signed)),
+            BinOpKind::BitAnd => get_constant_bits(cx, right)
+                .unwrap_or(u64::MAX)
+                .min(get_constant_bits(cx, left).unwrap_or(u64::MAX))
+                .min(apply_reductions(cx, nbits, right, signed))
+                .min(apply_reductions(cx, nbits, left, signed)),
             BinOpKind::Shr => apply_reductions(cx, nbits, left, signed)
                 .saturating_sub(constant_int(cx, right).map_or(0, |s| u64::try_from(s).unwrap_or_default())),
             _ => nbits,
diff --git a/src/tools/clippy/clippy_lints/src/casts/mod.rs b/src/tools/clippy/clippy_lints/src/casts/mod.rs
index d14898a8196..bd2c96f01f6 100644
--- a/src/tools/clippy/clippy_lints/src/casts/mod.rs
+++ b/src/tools/clippy/clippy_lints/src/casts/mod.rs
@@ -708,7 +708,7 @@ declare_clippy_lint! {
     /// let a_ref = &1;
     /// let a_ptr = std::ptr::from_ref(a_ref);
     /// ```
-    #[clippy::version = "1.77.0"]
+    #[clippy::version = "1.78.0"]
     pub REF_AS_PTR,
     pedantic,
     "using `as` to cast a reference to pointer"
diff --git a/src/tools/clippy/clippy_lints/src/collection_is_never_read.rs b/src/tools/clippy/clippy_lints/src/collection_is_never_read.rs
index 6942ca53640..70856b80881 100644
--- a/src/tools/clippy/clippy_lints/src/collection_is_never_read.rs
+++ b/src/tools/clippy/clippy_lints/src/collection_is_never_read.rs
@@ -1,9 +1,9 @@
 use clippy_utils::diagnostics::span_lint;
 use clippy_utils::ty::{is_type_diagnostic_item, is_type_lang_item};
-use clippy_utils::visitors::for_each_expr_with_closures;
+use clippy_utils::visitors::{for_each_expr_with_closures, Visitable};
 use clippy_utils::{get_enclosing_block, path_to_local_id};
 use core::ops::ControlFlow;
-use rustc_hir::{Block, ExprKind, HirId, LangItem, LetStmt, Node, PatKind};
+use rustc_hir::{Body, ExprKind, HirId, LangItem, LetStmt, Node, PatKind};
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_session::declare_lint_pass;
 use rustc_span::symbol::sym;
@@ -77,7 +77,7 @@ fn match_acceptable_type(cx: &LateContext<'_>, local: &LetStmt<'_>, collections:
         || is_type_lang_item(cx, ty, LangItem::String)
 }
 
-fn has_no_read_access<'tcx>(cx: &LateContext<'tcx>, id: HirId, block: &'tcx Block<'tcx>) -> bool {
+fn has_no_read_access<'tcx, T: Visitable<'tcx>>(cx: &LateContext<'tcx>, id: HirId, block: T) -> bool {
     let mut has_access = false;
     let mut has_read_access = false;
 
@@ -109,11 +109,30 @@ fn has_no_read_access<'tcx>(cx: &LateContext<'tcx>, id: HirId, block: &'tcx Bloc
         // traits (identified as local, based on the orphan rule), pessimistically assume that they might
         // have side effects, so consider them a read.
         if let Node::Expr(parent) = cx.tcx.parent_hir_node(expr.hir_id)
-            && let ExprKind::MethodCall(_, receiver, _, _) = parent.kind
+            && let ExprKind::MethodCall(_, receiver, args, _) = parent.kind
             && path_to_local_id(receiver, id)
             && let Some(method_def_id) = cx.typeck_results().type_dependent_def_id(parent.hir_id)
             && !method_def_id.is_local()
         {
+            // If this "official" method takes closures,
+            // it has read access if one of the closures has read access.
+            //
+            // items.retain(|item| send_item(item).is_ok());
+            let is_read_in_closure_arg = args.iter().any(|arg| {
+                if let ExprKind::Closure(closure) = arg.kind
+                    // To keep things simple, we only check the first param to see if its read.
+                    && let Body { params: [param, ..], value } = cx.tcx.hir().body(closure.body)
+                {
+                    !has_no_read_access(cx, param.hir_id, *value)
+                } else {
+                    false
+                }
+            });
+            if is_read_in_closure_arg {
+                has_read_access = true;
+                return ControlFlow::Break(());
+            }
+
             // The method call is a statement, so the return value is not used. That's not a read access:
             //
             // id.foo(args);
diff --git a/src/tools/clippy/clippy_lints/src/copies.rs b/src/tools/clippy/clippy_lints/src/copies.rs
index acdcb54be27..ccf1d9d6f8c 100644
--- a/src/tools/clippy/clippy_lints/src/copies.rs
+++ b/src/tools/clippy/clippy_lints/src/copies.rs
@@ -1,15 +1,14 @@
 use clippy_utils::diagnostics::{span_lint_and_note, span_lint_and_then};
 use clippy_utils::source::{first_line_of_span, indent_of, reindent_multiline, snippet, snippet_opt};
-use clippy_utils::ty::{is_interior_mut_ty, needs_ordered_drop};
+use clippy_utils::ty::{needs_ordered_drop, InteriorMut};
 use clippy_utils::visitors::for_each_expr;
 use clippy_utils::{
-    capture_local_usage, def_path_def_ids, eq_expr_value, find_binding_init, get_enclosing_block, hash_expr, hash_stmt,
-    if_sequence, is_else_clause, is_lint_allowed, path_to_local, search_same, ContainsName, HirEqInterExpr, SpanlessEq,
+    capture_local_usage, eq_expr_value, find_binding_init, get_enclosing_block, hash_expr, hash_stmt, if_sequence,
+    is_else_clause, is_lint_allowed, path_to_local, search_same, ContainsName, HirEqInterExpr, SpanlessEq,
 };
 use core::iter;
 use core::ops::ControlFlow;
 use rustc_errors::Applicability;
-use rustc_hir::def_id::DefIdSet;
 use rustc_hir::{intravisit, BinOpKind, Block, Expr, ExprKind, HirId, HirIdSet, Stmt, StmtKind};
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_session::impl_lint_pass;
@@ -159,40 +158,36 @@ declare_clippy_lint! {
     "`if` statement with shared code in all blocks"
 }
 
-pub struct CopyAndPaste {
+pub struct CopyAndPaste<'tcx> {
     ignore_interior_mutability: Vec<String>,
-    ignored_ty_ids: DefIdSet,
+    interior_mut: InteriorMut<'tcx>,
 }
 
-impl CopyAndPaste {
+impl CopyAndPaste<'_> {
     pub fn new(ignore_interior_mutability: Vec<String>) -> Self {
         Self {
             ignore_interior_mutability,
-            ignored_ty_ids: DefIdSet::new(),
+            interior_mut: InteriorMut::default(),
         }
     }
 }
 
-impl_lint_pass!(CopyAndPaste => [
+impl_lint_pass!(CopyAndPaste<'_> => [
     IFS_SAME_COND,
     SAME_FUNCTIONS_IN_IF_CONDITION,
     IF_SAME_THEN_ELSE,
     BRANCHES_SHARING_CODE
 ]);
 
-impl<'tcx> LateLintPass<'tcx> for CopyAndPaste {
+impl<'tcx> LateLintPass<'tcx> for CopyAndPaste<'tcx> {
     fn check_crate(&mut self, cx: &LateContext<'tcx>) {
-        for ignored_ty in &self.ignore_interior_mutability {
-            let path: Vec<&str> = ignored_ty.split("::").collect();
-            for id in def_path_def_ids(cx, path.as_slice()) {
-                self.ignored_ty_ids.insert(id);
-            }
-        }
+        self.interior_mut = InteriorMut::new(cx, &self.ignore_interior_mutability);
     }
+
     fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
         if !expr.span.from_expansion() && matches!(expr.kind, ExprKind::If(..)) && !is_else_clause(cx.tcx, expr) {
             let (conds, blocks) = if_sequence(expr);
-            lint_same_cond(cx, &conds, &self.ignored_ty_ids);
+            lint_same_cond(cx, &conds, &mut self.interior_mut);
             lint_same_fns_in_if_cond(cx, &conds);
             let all_same =
                 !is_lint_allowed(cx, IF_SAME_THEN_ELSE, expr.hir_id) && lint_if_same_then_else(cx, &conds, &blocks);
@@ -570,13 +565,14 @@ fn check_for_warn_of_moved_symbol(cx: &LateContext<'_>, symbols: &[(HirId, Symbo
     })
 }
 
-fn method_caller_is_mutable(cx: &LateContext<'_>, caller_expr: &Expr<'_>, ignored_ty_ids: &DefIdSet) -> bool {
+fn method_caller_is_mutable<'tcx>(
+    cx: &LateContext<'tcx>,
+    caller_expr: &Expr<'_>,
+    interior_mut: &mut InteriorMut<'tcx>,
+) -> bool {
     let caller_ty = cx.typeck_results().expr_ty(caller_expr);
-    // Check if given type has inner mutability and was not set to ignored by the configuration
-    let is_inner_mut_ty = is_interior_mut_ty(cx, caller_ty)
-        && !matches!(caller_ty.ty_adt_def(), Some(adt) if ignored_ty_ids.contains(&adt.did()));
 
-    is_inner_mut_ty
+    interior_mut.is_interior_mut_ty(cx, caller_ty)
         || caller_ty.is_mutable_ptr()
         // `find_binding_init` will return the binding iff its not mutable
         || path_to_local(caller_expr)
@@ -585,7 +581,7 @@ fn method_caller_is_mutable(cx: &LateContext<'_>, caller_expr: &Expr<'_>, ignore
 }
 
 /// Implementation of `IFS_SAME_COND`.
-fn lint_same_cond(cx: &LateContext<'_>, conds: &[&Expr<'_>], ignored_ty_ids: &DefIdSet) {
+fn lint_same_cond<'tcx>(cx: &LateContext<'tcx>, conds: &[&Expr<'_>], interior_mut: &mut InteriorMut<'tcx>) {
     for (i, j) in search_same(
         conds,
         |e| hash_expr(cx, e),
@@ -593,7 +589,7 @@ fn lint_same_cond(cx: &LateContext<'_>, conds: &[&Expr<'_>], ignored_ty_ids: &De
             // Ignore eq_expr side effects iff one of the expression kind is a method call
             // and the caller is not a mutable, including inner mutable type.
             if let ExprKind::MethodCall(_, caller, _, _) = lhs.kind {
-                if method_caller_is_mutable(cx, caller, ignored_ty_ids) {
+                if method_caller_is_mutable(cx, caller, interior_mut) {
                     false
                 } else {
                     SpanlessEq::new(cx).eq_expr(lhs, rhs)
diff --git a/src/tools/clippy/clippy_lints/src/dbg_macro.rs b/src/tools/clippy/clippy_lints/src/dbg_macro.rs
index e2296767431..db593726604 100644
--- a/src/tools/clippy/clippy_lints/src/dbg_macro.rs
+++ b/src/tools/clippy/clippy_lints/src/dbg_macro.rs
@@ -1,10 +1,10 @@
 use clippy_utils::diagnostics::span_lint_and_sugg;
+use clippy_utils::is_in_test;
 use clippy_utils::macros::{macro_backtrace, MacroCall};
 use clippy_utils::source::snippet_with_applicability;
-use clippy_utils::{is_in_cfg_test, is_in_test_function};
 use rustc_data_structures::fx::FxHashSet;
 use rustc_errors::Applicability;
-use rustc_hir::{Expr, ExprKind, HirId, Node};
+use rustc_hir::{Expr, ExprKind, Node};
 use rustc_lint::{LateContext, LateLintPass, LintContext};
 use rustc_middle::lint::in_external_macro;
 use rustc_session::impl_lint_pass;
@@ -63,7 +63,7 @@ impl LateLintPass<'_> for DbgMacro {
             !in_external_macro(cx.sess(), macro_call.span) &&
             self.checked_dbg_call_site.insert(macro_call.span) &&
             // allows `dbg!` in test code if allow-dbg-in-test is set to true in clippy.toml
-            !(self.allow_dbg_in_tests && is_in_test(cx, expr.hir_id))
+            !(self.allow_dbg_in_tests && is_in_test(cx.tcx, expr.hir_id))
         {
             let mut applicability = Applicability::MachineApplicable;
 
@@ -129,10 +129,6 @@ impl LateLintPass<'_> for DbgMacro {
     }
 }
 
-fn is_in_test(cx: &LateContext<'_>, hir_id: HirId) -> bool {
-    is_in_test_function(cx.tcx, hir_id) || is_in_cfg_test(cx.tcx, hir_id)
-}
-
 fn first_dbg_macro_in_expansion(cx: &LateContext<'_>, span: Span) -> Option<MacroCall> {
     macro_backtrace(span).find(|mc| cx.tcx.is_diagnostic_item(sym::dbg_macro, mc.def_id))
 }
diff --git a/src/tools/clippy/clippy_lints/src/dereference.rs b/src/tools/clippy/clippy_lints/src/dereference.rs
index 89e2b344968..b936b28470b 100644
--- a/src/tools/clippy/clippy_lints/src/dereference.rs
+++ b/src/tools/clippy/clippy_lints/src/dereference.rs
@@ -9,8 +9,8 @@ use rustc_data_structures::fx::FxIndexMap;
 use rustc_errors::Applicability;
 use rustc_hir::intravisit::{walk_ty, Visitor};
 use rustc_hir::{
-    self as hir, BindingMode, Body, BodyId, BorrowKind, Expr, ExprKind, HirId, MatchSource, Mutability, Node,
-    Pat, PatKind, Path, QPath, TyKind, UnOp,
+    self as hir, BindingMode, Body, BodyId, BorrowKind, Expr, ExprKind, HirId, MatchSource, Mutability, Node, Pat,
+    PatKind, Path, QPath, TyKind, UnOp,
 };
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_middle::ty::adjustment::{Adjust, Adjustment, AutoBorrow, AutoBorrowMutability};
diff --git a/src/tools/clippy/clippy_lints/src/format_args.rs b/src/tools/clippy/clippy_lints/src/format_args.rs
index 80db617c639..003a9995c15 100644
--- a/src/tools/clippy/clippy_lints/src/format_args.rs
+++ b/src/tools/clippy/clippy_lints/src/format_args.rs
@@ -4,7 +4,7 @@ use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_and_then};
 use clippy_utils::is_diag_trait_item;
 use clippy_utils::macros::{
     find_format_arg_expr, find_format_args, format_arg_removal_span, format_placeholder_format_span, is_assert_macro,
-    is_format_macro, is_panic, root_macro_call, root_macro_call_first_node, FormatParamUsage, MacroCall,
+    is_format_macro, is_panic, matching_root_macro_call, root_macro_call_first_node, FormatParamUsage, MacroCall,
 };
 use clippy_utils::source::snippet_opt;
 use clippy_utils::ty::{implements_trait, is_type_lang_item};
@@ -271,9 +271,7 @@ impl<'a, 'tcx> FormatArgsExpr<'a, 'tcx> {
                     let mut suggest_format = |spec| {
                         let message = format!("for the {spec} to apply consider using `format!()`");
 
-                        if let Some(mac_call) = root_macro_call(arg_span)
-                            && self.cx.tcx.is_diagnostic_item(sym::format_args_macro, mac_call.def_id)
-                        {
+                        if let Some(mac_call) = matching_root_macro_call(self.cx, arg_span, sym::format_args_macro) {
                             diag.span_suggestion(
                                 self.cx.sess().source_map().span_until_char(mac_call.span, '!'),
                                 message,
diff --git a/src/tools/clippy/clippy_lints/src/implied_bounds_in_impls.rs b/src/tools/clippy/clippy_lints/src/implied_bounds_in_impls.rs
index 7b97fc15caa..3bf8d618955 100644
--- a/src/tools/clippy/clippy_lints/src/implied_bounds_in_impls.rs
+++ b/src/tools/clippy/clippy_lints/src/implied_bounds_in_impls.rs
@@ -24,7 +24,7 @@ declare_clippy_lint! {
     ///
     /// ### Limitations
     /// This lint does not check for implied bounds transitively. Meaning that
-    /// it does't check for implied bounds from supertraits of supertraits
+    /// it doesn't check for implied bounds from supertraits of supertraits
     /// (e.g. `trait A {} trait B: A {} trait C: B {}`, then having an `fn() -> impl A + C`)
     ///
     /// ### Example
diff --git a/src/tools/clippy/clippy_lints/src/index_refutable_slice.rs b/src/tools/clippy/clippy_lints/src/index_refutable_slice.rs
index a4c3b06046e..128461ce7bc 100644
--- a/src/tools/clippy/clippy_lints/src/index_refutable_slice.rs
+++ b/src/tools/clippy/clippy_lints/src/index_refutable_slice.rs
@@ -93,12 +93,9 @@ fn find_slice_values(cx: &LateContext<'_>, pat: &hir::Pat<'_>) -> FxIndexMap<Hir
     let mut slices: FxIndexMap<HirId, SliceLintInformation> = FxIndexMap::default();
     pat.walk_always(|pat| {
         // We'll just ignore mut and ref mut for simplicity sake right now
-        if let hir::PatKind::Binding(
-            hir::BindingMode(by_ref, hir::Mutability::Not),
-            value_hir_id,
-            ident,
-            sub_pat,
-        ) = pat.kind && by_ref != hir::ByRef::Yes(hir::Mutability::Mut)
+        if let hir::PatKind::Binding(hir::BindingMode(by_ref, hir::Mutability::Not), value_hir_id, ident, sub_pat) =
+            pat.kind
+            && by_ref != hir::ByRef::Yes(hir::Mutability::Mut)
         {
             // This block catches bindings with sub patterns. It would be hard to build a correct suggestion
             // for them and it's likely that the user knows what they are doing in such a case.
diff --git a/src/tools/clippy/clippy_lints/src/large_stack_arrays.rs b/src/tools/clippy/clippy_lints/src/large_stack_arrays.rs
index afcb6745947..208d1bb6e68 100644
--- a/src/tools/clippy/clippy_lints/src/large_stack_arrays.rs
+++ b/src/tools/clippy/clippy_lints/src/large_stack_arrays.rs
@@ -1,10 +1,13 @@
-use clippy_utils::diagnostics::span_lint_and_help;
+use clippy_utils::diagnostics::span_lint_and_then;
+use clippy_utils::is_from_proc_macro;
+use clippy_utils::macros::macro_backtrace;
 use clippy_utils::source::snippet;
-use rustc_hir::{Expr, ExprKind, Item, ItemKind, Node};
+use rustc_hir::{ArrayLen, Expr, ExprKind, Item, ItemKind, Node};
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_middle::ty::layout::LayoutOf;
 use rustc_middle::ty::{self, ConstKind};
 use rustc_session::impl_lint_pass;
+use rustc_span::{sym, Span};
 
 declare_clippy_lint! {
     /// ### What it does
@@ -25,20 +28,41 @@ declare_clippy_lint! {
 
 pub struct LargeStackArrays {
     maximum_allowed_size: u128,
+    prev_vec_macro_callsite: Option<Span>,
 }
 
 impl LargeStackArrays {
     #[must_use]
     pub fn new(maximum_allowed_size: u128) -> Self {
-        Self { maximum_allowed_size }
+        Self {
+            maximum_allowed_size,
+            prev_vec_macro_callsite: None,
+        }
+    }
+
+    /// Check if the given span of an expr is already in a `vec!` call.
+    fn is_from_vec_macro(&mut self, cx: &LateContext<'_>, span: Span) -> bool {
+        // First, we check if this is span is within the last encountered `vec!` macro's root callsite.
+        self.prev_vec_macro_callsite
+            .is_some_and(|vec_mac| vec_mac.contains(span))
+            || {
+                // Then, we try backtracking the macro expansions, to see if there's a `vec!` macro,
+                // and update the `prev_vec_macro_callsite`.
+                let res = macro_backtrace(span).any(|mac| cx.tcx.is_diagnostic_item(sym::vec_macro, mac.def_id));
+                if res {
+                    self.prev_vec_macro_callsite = Some(span.source_callsite());
+                }
+                res
+            }
     }
 }
 
 impl_lint_pass!(LargeStackArrays => [LARGE_STACK_ARRAYS]);
 
 impl<'tcx> LateLintPass<'tcx> for LargeStackArrays {
-    fn check_expr(&mut self, cx: &LateContext<'_>, expr: &Expr<'_>) {
+    fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &Expr<'tcx>) {
         if let ExprKind::Repeat(_, _) | ExprKind::Array(_) = expr.kind
+            && !self.is_from_vec_macro(cx, expr.span)
             && let ty::Array(element_type, cst) = cx.typeck_results().expr_ty(expr).kind()
             && let ConstKind::Value(ty::ValTree::Leaf(element_count)) = cst.kind()
             && let Ok(element_count) = element_count.try_to_target_usize(cx.tcx)
@@ -54,7 +78,7 @@ impl<'tcx> LateLintPass<'tcx> for LargeStackArrays {
             })
             && self.maximum_allowed_size < u128::from(element_count) * u128::from(element_size)
         {
-            span_lint_and_help(
+            span_lint_and_then(
                 cx,
                 LARGE_STACK_ARRAYS,
                 expr.span,
@@ -62,12 +86,33 @@ impl<'tcx> LateLintPass<'tcx> for LargeStackArrays {
                     "allocating a local array larger than {} bytes",
                     self.maximum_allowed_size
                 ),
-                None,
-                format!(
-                    "consider allocating on the heap with `vec!{}.into_boxed_slice()`",
-                    snippet(cx, expr.span, "[...]")
-                ),
+                |diag| {
+                    if !might_be_expanded(cx, expr) {
+                        diag.help(format!(
+                            "consider allocating on the heap with `vec!{}.into_boxed_slice()`",
+                            snippet(cx, expr.span, "[...]")
+                        ));
+                    }
+                },
             );
         }
     }
 }
+
+/// Only giving help messages if the expr does not contains macro expanded codes.
+fn might_be_expanded<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'tcx>) -> bool {
+    /// Check if the span of `ArrayLen` of a repeat expression is within the expr's span,
+    /// if not, meaning this repeat expr is definitely from some proc-macro.
+    ///
+    /// This is a fail-safe to a case where even the `is_from_proc_macro` is unable to determain the
+    /// correct result.
+    fn repeat_expr_might_be_expanded<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'tcx>) -> bool {
+        let ExprKind::Repeat(_, ArrayLen::Body(anon_const)) = expr.kind else {
+            return false;
+        };
+        let len_span = cx.tcx.def_span(anon_const.def_id);
+        !expr.span.contains(len_span)
+    }
+
+    expr.span.from_expansion() || is_from_proc_macro(cx, expr) || repeat_expr_might_be_expanded(cx, expr)
+}
diff --git a/src/tools/clippy/clippy_lints/src/lib.rs b/src/tools/clippy/clippy_lints/src/lib.rs
index e2aac58bf97..2c44c3881aa 100644
--- a/src/tools/clippy/clippy_lints/src/lib.rs
+++ b/src/tools/clippy/clippy_lints/src/lib.rs
@@ -535,6 +535,7 @@ pub fn register_lints(store: &mut rustc_lint::LintStore, conf: &'static Conf) {
         allow_print_in_tests,
         allow_private_module_inception,
         allow_unwrap_in_tests,
+        allow_useless_vec_in_tests,
         ref allowed_dotfiles,
         ref allowed_idents_below_min_chars,
         ref allowed_scripts,
@@ -754,6 +755,7 @@ pub fn register_lints(store: &mut rustc_lint::LintStore, conf: &'static Conf) {
             too_large_for_stack,
             msrv: msrv(),
             span_to_lint_map: BTreeMap::new(),
+            allow_in_test: allow_useless_vec_in_tests,
         })
     });
     store.register_late_pass(|_| Box::new(panic_unimplemented::PanicUnimplemented));
diff --git a/src/tools/clippy/clippy_lints/src/loops/unused_enumerate_index.rs b/src/tools/clippy/clippy_lints/src/loops/unused_enumerate_index.rs
index 31f0f1cfeba..40ccfec02be 100644
--- a/src/tools/clippy/clippy_lints/src/loops/unused_enumerate_index.rs
+++ b/src/tools/clippy/clippy_lints/src/loops/unused_enumerate_index.rs
@@ -1,11 +1,12 @@
 use super::UNUSED_ENUMERATE_INDEX;
 use clippy_utils::diagnostics::{multispan_sugg, span_lint_and_then};
 use clippy_utils::source::snippet;
-use clippy_utils::{match_def_path, pat_is_wild, sugg};
+use clippy_utils::{pat_is_wild, sugg};
 use rustc_hir::def::DefKind;
 use rustc_hir::{Expr, ExprKind, Pat, PatKind};
 use rustc_lint::LateContext;
 use rustc_middle::ty;
+use rustc_span::sym;
 
 /// Checks for the `UNUSED_ENUMERATE_INDEX` lint.
 ///
@@ -16,9 +17,9 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, pat: &Pat<'tcx>, arg: &Expr<'_
         && let ty = cx.typeck_results().expr_ty(arg)
         && pat_is_wild(cx, &index.kind, body)
         && let ty::Adt(base, _) = *ty.kind()
-        && match_def_path(cx, base.did(), &clippy_utils::paths::CORE_ITER_ENUMERATE_STRUCT)
+        && cx.tcx.is_diagnostic_item(sym::Enumerate, base.did())
         && let Some((DefKind::AssocFn, call_id)) = cx.typeck_results().type_dependent_def(arg.hir_id)
-        && match_def_path(cx, call_id, &clippy_utils::paths::CORE_ITER_ENUMERATE_METHOD)
+        && cx.tcx.is_diagnostic_item(sym::enumerate_method, call_id)
     {
         span_lint_and_then(
             cx,
diff --git a/src/tools/clippy/clippy_lints/src/manual_assert.rs b/src/tools/clippy/clippy_lints/src/manual_assert.rs
index 76edbe8b755..d76b94eba23 100644
--- a/src/tools/clippy/clippy_lints/src/manual_assert.rs
+++ b/src/tools/clippy/clippy_lints/src/manual_assert.rs
@@ -1,12 +1,11 @@
 use crate::rustc_lint::LintContext;
 use clippy_utils::diagnostics::span_lint_and_then;
-use clippy_utils::macros::root_macro_call;
+use clippy_utils::macros::{is_panic, root_macro_call};
 use clippy_utils::{is_else_clause, is_parent_stmt, peel_blocks_with_stmt, span_extract_comment, sugg};
 use rustc_errors::Applicability;
 use rustc_hir::{Expr, ExprKind, UnOp};
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_session::declare_lint_pass;
-use rustc_span::sym;
 
 declare_clippy_lint! {
     /// ### What it does
@@ -42,7 +41,7 @@ impl<'tcx> LateLintPass<'tcx> for ManualAssert {
             && !expr.span.from_expansion()
             && let then = peel_blocks_with_stmt(then)
             && let Some(macro_call) = root_macro_call(then.span)
-            && cx.tcx.item_name(macro_call.def_id) == sym::panic
+            && is_panic(cx, macro_call.def_id)
             && !cx.tcx.sess.source_map().is_multiline(cond.span)
             && let Ok(panic_snippet) = cx.sess().source_map().span_to_snippet(macro_call.span)
             && let Some(panic_snippet) = panic_snippet.strip_suffix(')')
diff --git a/src/tools/clippy/clippy_lints/src/manual_is_ascii_check.rs b/src/tools/clippy/clippy_lints/src/manual_is_ascii_check.rs
index 338a299740a..6f6ba1852a6 100644
--- a/src/tools/clippy/clippy_lints/src/manual_is_ascii_check.rs
+++ b/src/tools/clippy/clippy_lints/src/manual_is_ascii_check.rs
@@ -1,15 +1,15 @@
 use clippy_config::msrvs::{self, Msrv};
-use clippy_utils::diagnostics::span_lint_and_sugg;
-use clippy_utils::macros::root_macro_call;
+use clippy_utils::diagnostics::span_lint_and_then;
+use clippy_utils::macros::matching_root_macro_call;
 use clippy_utils::sugg::Sugg;
-use clippy_utils::{higher, in_constant};
+use clippy_utils::{higher, in_constant, path_to_local, peel_ref_operators};
 use rustc_ast::ast::RangeLimits;
 use rustc_ast::LitKind::{Byte, Char};
 use rustc_errors::Applicability;
-use rustc_hir::{BorrowKind, Expr, ExprKind, PatKind, RangeEnd};
+use rustc_hir::{Expr, ExprKind, Node, Param, PatKind, RangeEnd};
 use rustc_lint::{LateContext, LateLintPass};
+use rustc_middle::ty;
 use rustc_session::impl_lint_pass;
-use rustc_span::def_id::DefId;
 use rustc_span::{sym, Span};
 
 declare_clippy_lint! {
@@ -97,12 +97,10 @@ impl<'tcx> LateLintPass<'tcx> for ManualIsAsciiCheck {
             return;
         }
 
-        if let Some(macro_call) = root_macro_call(expr.span)
-            && is_matches_macro(cx, macro_call.def_id)
-        {
+        if let Some(macro_call) = matching_root_macro_call(cx, expr.span, sym::matches_macro) {
             if let ExprKind::Match(recv, [arm, ..], _) = expr.kind {
                 let range = check_pat(&arm.pat.kind);
-                check_is_ascii(cx, macro_call.span, recv, &range);
+                check_is_ascii(cx, macro_call.span, recv, &range, None);
             }
         } else if let ExprKind::MethodCall(path, receiver, [arg], ..) = expr.kind
             && path.ident.name == sym!(contains)
@@ -111,42 +109,67 @@ impl<'tcx> LateLintPass<'tcx> for ManualIsAsciiCheck {
                 end: Some(end),
                 limits: RangeLimits::Closed,
             }) = higher::Range::hir(receiver)
+            && !matches!(cx.typeck_results().expr_ty(arg).peel_refs().kind(), ty::Param(_))
         {
+            let arg = peel_ref_operators(cx, arg);
+            let ty_sugg = get_ty_sugg(cx, arg, start);
             let range = check_range(start, end);
-            if let ExprKind::AddrOf(BorrowKind::Ref, _, e) = arg.kind {
-                check_is_ascii(cx, expr.span, e, &range);
-            } else {
-                check_is_ascii(cx, expr.span, arg, &range);
-            }
+            check_is_ascii(cx, expr.span, arg, &range, ty_sugg);
         }
     }
 
     extract_msrv_attr!(LateContext);
 }
 
-fn check_is_ascii(cx: &LateContext<'_>, span: Span, recv: &Expr<'_>, range: &CharRange) {
-    if let Some(sugg) = match range {
-        CharRange::UpperChar => Some("is_ascii_uppercase"),
-        CharRange::LowerChar => Some("is_ascii_lowercase"),
-        CharRange::FullChar => Some("is_ascii_alphabetic"),
-        CharRange::Digit => Some("is_ascii_digit"),
-        CharRange::HexDigit => Some("is_ascii_hexdigit"),
-        CharRange::Otherwise | CharRange::LowerHexLetter | CharRange::UpperHexLetter => None,
-    } {
-        let default_snip = "..";
-        let mut app = Applicability::MachineApplicable;
-        let recv = Sugg::hir_with_context(cx, recv, span.ctxt(), default_snip, &mut app).maybe_par();
+fn get_ty_sugg(cx: &LateContext<'_>, arg: &Expr<'_>, bound_expr: &Expr<'_>) -> Option<(Span, &'static str)> {
+    if let ExprKind::Lit(lit) = bound_expr.kind
+        && let local_hid = path_to_local(arg)?
+        && let Node::Param(Param { ty_span, span, .. }) = cx.tcx.parent_hir_node(local_hid)
+        // `ty_span` and `span` are the same for inferred type, thus a type suggestion must be given
+        && ty_span == span
+    {
+        let ty_str = match lit.node {
+            Char(_) => "char",
+            Byte(_) => "u8",
+            _ => return None,
+        };
+        return Some((*ty_span, ty_str));
+    }
+    None
+}
 
-        span_lint_and_sugg(
-            cx,
-            MANUAL_IS_ASCII_CHECK,
-            span,
-            "manual check for common ascii range",
-            "try",
-            format!("{recv}.{sugg}()"),
-            app,
-        );
+fn check_is_ascii(
+    cx: &LateContext<'_>,
+    span: Span,
+    recv: &Expr<'_>,
+    range: &CharRange,
+    ty_sugg: Option<(Span, &'_ str)>,
+) {
+    let sugg = match range {
+        CharRange::UpperChar => "is_ascii_uppercase",
+        CharRange::LowerChar => "is_ascii_lowercase",
+        CharRange::FullChar => "is_ascii_alphabetic",
+        CharRange::Digit => "is_ascii_digit",
+        CharRange::HexDigit => "is_ascii_hexdigit",
+        CharRange::Otherwise | CharRange::LowerHexLetter | CharRange::UpperHexLetter => return,
+    };
+    let default_snip = "..";
+    let mut app = Applicability::MachineApplicable;
+    let recv = Sugg::hir_with_context(cx, recv, span.ctxt(), default_snip, &mut app).maybe_par();
+    let mut suggestion = vec![(span, format!("{recv}.{sugg}()"))];
+    if let Some((ty_span, ty_str)) = ty_sugg {
+        suggestion.push((ty_span, format!("{recv}: {ty_str}")));
     }
+
+    span_lint_and_then(
+        cx,
+        MANUAL_IS_ASCII_CHECK,
+        span,
+        "manual check for common ascii range",
+        |diag| {
+            diag.multipart_suggestion("try", suggestion, app);
+        },
+    );
 }
 
 fn check_pat(pat_kind: &PatKind<'_>) -> CharRange {
@@ -187,11 +210,3 @@ fn check_range(start: &Expr<'_>, end: &Expr<'_>) -> CharRange {
         CharRange::Otherwise
     }
 }
-
-fn is_matches_macro(cx: &LateContext<'_>, macro_def_id: DefId) -> bool {
-    if let Some(name) = cx.tcx.get_diagnostic_name(macro_def_id) {
-        return sym::matches_macro == name;
-    }
-
-    false
-}
diff --git a/src/tools/clippy/clippy_lints/src/matches/collapsible_match.rs b/src/tools/clippy/clippy_lints/src/matches/collapsible_match.rs
index 6746920edc5..90cfdecc199 100644
--- a/src/tools/clippy/clippy_lints/src/matches/collapsible_match.rs
+++ b/src/tools/clippy/clippy_lints/src/matches/collapsible_match.rs
@@ -1,3 +1,4 @@
+use clippy_config::msrvs::Msrv;
 use clippy_utils::diagnostics::span_lint_and_then;
 use clippy_utils::higher::IfLetOrMatch;
 use clippy_utils::source::snippet;
@@ -11,12 +12,12 @@ use rustc_hir::{Arm, Expr, HirId, Pat, PatKind};
 use rustc_lint::LateContext;
 use rustc_span::Span;
 
-use super::COLLAPSIBLE_MATCH;
+use super::{pat_contains_disallowed_or, COLLAPSIBLE_MATCH};
 
-pub(super) fn check_match<'tcx>(cx: &LateContext<'tcx>, arms: &'tcx [Arm<'_>]) {
+pub(super) fn check_match<'tcx>(cx: &LateContext<'tcx>, arms: &'tcx [Arm<'_>], msrv: &Msrv) {
     if let Some(els_arm) = arms.iter().rfind(|arm| arm_is_wild_like(cx, arm)) {
         for arm in arms {
-            check_arm(cx, true, arm.pat, arm.body, arm.guard, Some(els_arm.body));
+            check_arm(cx, true, arm.pat, arm.body, arm.guard, Some(els_arm.body), msrv);
         }
     }
 }
@@ -26,8 +27,9 @@ pub(super) fn check_if_let<'tcx>(
     pat: &'tcx Pat<'_>,
     body: &'tcx Expr<'_>,
     else_expr: Option<&'tcx Expr<'_>>,
+    msrv: &Msrv,
 ) {
-    check_arm(cx, false, pat, body, None, else_expr);
+    check_arm(cx, false, pat, body, None, else_expr, msrv);
 }
 
 fn check_arm<'tcx>(
@@ -37,6 +39,7 @@ fn check_arm<'tcx>(
     outer_then_body: &'tcx Expr<'tcx>,
     outer_guard: Option<&'tcx Expr<'tcx>>,
     outer_else_body: Option<&'tcx Expr<'tcx>>,
+    msrv: &Msrv,
 ) {
     let inner_expr = peel_blocks_with_stmt(outer_then_body);
     if let Some(inner) = IfLetOrMatch::parse(cx, inner_expr)
@@ -57,7 +60,7 @@ fn check_arm<'tcx>(
         // match expression must be a local binding
         // match <local> { .. }
         && let Some(binding_id) = path_to_local(peel_ref_operators(cx, inner_scrutinee))
-        && !pat_contains_or(inner_then_pat)
+        && !pat_contains_disallowed_or(inner_then_pat, msrv)
         // the binding must come from the pattern of the containing match arm
         // ..<local>.. => match <local> { .. }
         && let (Some(binding_span), is_innermost_parent_pat_struct)
@@ -142,13 +145,3 @@ fn find_pat_binding_and_is_innermost_parent_pat_struct(pat: &Pat<'_>, hir_id: Hi
     });
     (span, is_innermost_parent_pat_struct)
 }
-
-fn pat_contains_or(pat: &Pat<'_>) -> bool {
-    let mut result = false;
-    pat.walk(|p| {
-        let is_or = matches!(p.kind, PatKind::Or(_));
-        result |= is_or;
-        !is_or
-    });
-    result
-}
diff --git a/src/tools/clippy/clippy_lints/src/matches/mod.rs b/src/tools/clippy/clippy_lints/src/matches/mod.rs
index fae2c4e4af9..ee9f48d71ad 100644
--- a/src/tools/clippy/clippy_lints/src/matches/mod.rs
+++ b/src/tools/clippy/clippy_lints/src/matches/mod.rs
@@ -27,7 +27,7 @@ mod wild_in_or_pats;
 use clippy_config::msrvs::{self, Msrv};
 use clippy_utils::source::walk_span_to_context;
 use clippy_utils::{higher, in_constant, is_direct_expn_of, is_span_match, span_contains_cfg};
-use rustc_hir::{Arm, Expr, ExprKind, LetStmt, MatchSource, Pat};
+use rustc_hir::{Arm, Expr, ExprKind, LetStmt, MatchSource, Pat, PatKind};
 use rustc_lint::{LateContext, LateLintPass, LintContext};
 use rustc_middle::lint::in_external_macro;
 use rustc_session::impl_lint_pass;
@@ -1040,7 +1040,7 @@ impl<'tcx> LateLintPass<'tcx> for Matches {
                 significant_drop_in_scrutinee::check(cx, expr, ex, arms, source);
             }
 
-            collapsible_match::check_match(cx, arms);
+            collapsible_match::check_match(cx, arms, &self.msrv);
             if !from_expansion {
                 // These don't depend on a relationship between multiple arms
                 match_wild_err_arm::check(cx, ex, arms);
@@ -1066,7 +1066,7 @@ impl<'tcx> LateLintPass<'tcx> for Matches {
                     needless_match::check_match(cx, ex, arms, expr);
                     match_on_vec_items::check(cx, ex);
                     match_str_case_mismatch::check(cx, ex, arms);
-                    redundant_guards::check(cx, arms);
+                    redundant_guards::check(cx, arms, &self.msrv);
 
                     if !in_constant(cx, expr.hir_id) {
                         manual_unwrap_or::check(cx, expr, ex, arms);
@@ -1083,7 +1083,7 @@ impl<'tcx> LateLintPass<'tcx> for Matches {
                 match_ref_pats::check(cx, ex, arms.iter().map(|el| el.pat), expr);
             }
         } else if let Some(if_let) = higher::IfLet::hir(cx, expr) {
-            collapsible_match::check_if_let(cx, if_let.let_pat, if_let.if_then, if_let.if_else);
+            collapsible_match::check_if_let(cx, if_let.let_pat, if_let.if_then, if_let.if_else, &self.msrv);
             if !from_expansion {
                 if let Some(else_expr) = if_let.if_else {
                     if self.msrv.meets(msrvs::MATCHES_MACRO) {
@@ -1195,3 +1195,18 @@ fn contains_cfg_arm(cx: &LateContext<'_>, e: &Expr<'_>, scrutinee: &Expr<'_>, ar
         Err(()) => true,
     }
 }
+
+/// Checks if `pat` contains OR patterns that cannot be nested due to a too low MSRV.
+fn pat_contains_disallowed_or(pat: &Pat<'_>, msrv: &Msrv) -> bool {
+    if msrv.meets(msrvs::OR_PATTERNS) {
+        return false;
+    }
+
+    let mut result = false;
+    pat.walk(|p| {
+        let is_or = matches!(p.kind, PatKind::Or(_));
+        result |= is_or;
+        !is_or
+    });
+    result
+}
diff --git a/src/tools/clippy/clippy_lints/src/matches/redundant_guards.rs b/src/tools/clippy/clippy_lints/src/matches/redundant_guards.rs
index 50cbccc3968..a75cf37945f 100644
--- a/src/tools/clippy/clippy_lints/src/matches/redundant_guards.rs
+++ b/src/tools/clippy/clippy_lints/src/matches/redundant_guards.rs
@@ -1,40 +1,32 @@
+use clippy_config::msrvs::Msrv;
 use clippy_utils::diagnostics::span_lint_and_then;
+use clippy_utils::macros::matching_root_macro_call;
 use clippy_utils::source::snippet;
 use clippy_utils::visitors::{for_each_expr, is_local_used};
 use clippy_utils::{in_constant, path_to_local};
 use rustc_ast::{BorrowKind, LitKind};
 use rustc_errors::Applicability;
 use rustc_hir::def::{DefKind, Res};
-use rustc_hir::{Arm, BinOpKind, Expr, ExprKind, MatchSource, Node, Pat, PatKind, UnOp};
+use rustc_hir::{Arm, BinOpKind, Expr, ExprKind, MatchSource, Node, PatKind, UnOp};
 use rustc_lint::LateContext;
 use rustc_span::symbol::Ident;
-use rustc_span::{Span, Symbol};
+use rustc_span::{sym, Span, Symbol};
 use std::borrow::Cow;
 use std::ops::ControlFlow;
 
-use super::REDUNDANT_GUARDS;
+use super::{pat_contains_disallowed_or, REDUNDANT_GUARDS};
 
-pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, arms: &'tcx [Arm<'tcx>]) {
+pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, arms: &'tcx [Arm<'tcx>], msrv: &Msrv) {
     for outer_arm in arms {
         let Some(guard) = outer_arm.guard else {
             continue;
         };
 
         // `Some(x) if matches!(x, y)`
-        if let ExprKind::Match(
-            scrutinee,
-            [
-                arm,
-                Arm {
-                    pat: Pat {
-                        kind: PatKind::Wild, ..
-                    },
-                    ..
-                },
-            ],
-            MatchSource::Normal,
-        ) = guard.kind
+        if let ExprKind::Match(scrutinee, [arm, _], MatchSource::Normal) = guard.kind
+            && matching_root_macro_call(cx, guard.span, sym::matches_macro).is_some()
             && let Some(binding) = get_pat_binding(cx, scrutinee, outer_arm)
+            && !pat_contains_disallowed_or(arm.pat, msrv)
         {
             let pat_span = match (arm.pat.kind, binding.byref_ident) {
                 (PatKind::Ref(pat, _), Some(_)) => pat.span,
@@ -53,6 +45,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, arms: &'tcx [Arm<'tcx>]) {
         // `Some(x) if let Some(2) = x`
         else if let ExprKind::Let(let_expr) = guard.kind
             && let Some(binding) = get_pat_binding(cx, let_expr.init, outer_arm)
+            && !pat_contains_disallowed_or(let_expr.pat, msrv)
         {
             let pat_span = match (let_expr.pat.kind, binding.byref_ident) {
                 (PatKind::Ref(pat, _), Some(_)) => pat.span,
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 37f72528140..69791414f72 100644
--- a/src/tools/clippy/clippy_lints/src/matches/single_match.rs
+++ b/src/tools/clippy/clippy_lints/src/matches/single_match.rs
@@ -75,7 +75,7 @@ fn report_single_pattern(
 ) {
     let lint = if els.is_some() { SINGLE_MATCH_ELSE } else { SINGLE_MATCH };
     let ctxt = expr.span.ctxt();
-    let mut app = Applicability::HasPlaceholders;
+    let mut app = Applicability::MachineApplicable;
     let els_str = els.map_or(String::new(), |els| {
         format!(" else {}", expr_block(cx, els, ctxt, "..", Some(expr.span), &mut app))
     });
diff --git a/src/tools/clippy/clippy_lints/src/methods/filter_map.rs b/src/tools/clippy/clippy_lints/src/methods/filter_map.rs
index 581e3b308c3..02a11257007 100644
--- a/src/tools/clippy/clippy_lints/src/methods/filter_map.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/filter_map.rs
@@ -1,5 +1,5 @@
 use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_and_then};
-use clippy_utils::macros::{is_panic, root_macro_call};
+use clippy_utils::macros::{is_panic, matching_root_macro_call, root_macro_call};
 use clippy_utils::source::{indent_of, reindent_multiline, snippet};
 use clippy_utils::ty::is_type_diagnostic_item;
 use clippy_utils::{higher, is_trait_method, path_to_local_id, peel_blocks, SpanlessEq};
@@ -247,8 +247,7 @@ impl<'tcx> OffendingFilterExpr<'tcx> {
             } else {
                 None
             }
-        } else if let Some(macro_call) = root_macro_call(expr.span)
-            && cx.tcx.get_diagnostic_name(macro_call.def_id) == Some(sym::matches_macro)
+        } else if matching_root_macro_call(cx, expr.span, sym::matches_macro).is_some()
             // we know for a fact that the wildcard pattern is the second arm
             && let ExprKind::Match(scrutinee, [arm, _], _) = expr.kind
             && path_to_local_id(scrutinee, filter_param_id)
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 6d70989546a..03b4680c522 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
@@ -89,8 +89,7 @@ pub(super) fn check<'tcx>(
                 }
 
                 match it.kind {
-                    PatKind::Binding(BindingMode(_, Mutability::Mut), _, _, _)
-                    | PatKind::Ref(_, Mutability::Mut) => {
+                    PatKind::Binding(BindingMode(_, Mutability::Mut), _, _, _) | PatKind::Ref(_, Mutability::Mut) => {
                         to_be_discarded = true;
                         false
                     },
diff --git a/src/tools/clippy/clippy_lints/src/methods/mod.rs b/src/tools/clippy/clippy_lints/src/methods/mod.rs
index 0939c028564..63545d6c503 100644
--- a/src/tools/clippy/clippy_lints/src/methods/mod.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/mod.rs
@@ -1145,11 +1145,16 @@ declare_clippy_lint! {
     /// `str` as an argument, e.g., `_.split("x")`.
     ///
     /// ### Why is this bad?
-    /// Performing these methods using a `char` is faster than
-    /// using a `str`.
+    /// While this can make a perf difference on some systems,
+    /// benchmarks have proven inconclusive. But at least using a
+    /// char literal makes it clear that we are looking at a single
+    /// character.
     ///
     /// ### Known problems
-    /// Does not catch multi-byte unicode characters.
+    /// Does not catch multi-byte unicode characters. This is by
+    /// design, on many machines, splitting by a non-ascii char is
+    /// actually slower. Please do your own measurements instead of
+    /// relying solely on the results of this lint.
     ///
     /// ### Example
     /// ```rust,ignore
@@ -1162,7 +1167,7 @@ declare_clippy_lint! {
     /// ```
     #[clippy::version = "pre 1.29.0"]
     pub SINGLE_CHAR_PATTERN,
-    perf,
+    pedantic,
     "using a single-character str where a char could be used, e.g., `_.split(\"x\")`"
 }
 
@@ -3988,7 +3993,7 @@ declare_clippy_lint! {
     /// let x: Result<u32, ()> = Ok(0);
     /// let y = x.unwrap_or_else(|err| handle_error(err));
     /// ```
-    #[clippy::version = "1.77.0"]
+    #[clippy::version = "1.78.0"]
     pub UNNECESSARY_RESULT_MAP_OR_ELSE,
     suspicious,
     "making no use of the \"map closure\" when calling `.map_or_else(|err| handle_error(err), |n| n)`"
@@ -4022,7 +4027,7 @@ declare_clippy_lint! {
     /// needs_cstr(c"Hello");
     /// unsafe { libc::puts(c"World".as_ptr()) }
     /// ```
-    #[clippy::version = "1.76.0"]
+    #[clippy::version = "1.78.0"]
     pub MANUAL_C_STR_LITERALS,
     pedantic,
     r#"creating a `CStr` through functions when `c""` literals can be used"#
diff --git a/src/tools/clippy/clippy_lints/src/methods/readonly_write_lock.rs b/src/tools/clippy/clippy_lints/src/methods/readonly_write_lock.rs
index 9b0180d9369..774aaec1afd 100644
--- a/src/tools/clippy/clippy_lints/src/methods/readonly_write_lock.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/readonly_write_lock.rs
@@ -4,7 +4,7 @@ use clippy_utils::mir::{enclosing_mir, visit_local_usage};
 use clippy_utils::source::snippet;
 use clippy_utils::ty::is_type_diagnostic_item;
 use rustc_errors::Applicability;
-use rustc_hir::{Expr, ExprKind, Node};
+use rustc_hir::{Expr, ExprKind, Node, PatKind};
 use rustc_lint::LateContext;
 use rustc_middle::mir::{Location, START_BLOCK};
 use rustc_span::sym;
@@ -25,6 +25,11 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, receiver
         && is_unwrap_call(cx, unwrap_call_expr)
         && let parent = cx.tcx.parent_hir_node(unwrap_call_expr.hir_id)
         && let Node::LetStmt(local) = parent
+        && let PatKind::Binding(.., ident, _) = local.pat.kind
+        // if the binding is prefixed with `_`, it typically means
+        // that this guard only exists to protect a section of code
+        // rather than the contained data
+        && !ident.as_str().starts_with('_')
         && let Some(mir) = enclosing_mir(cx.tcx, expr.hir_id)
         && let Some((local, _)) = mir
             .local_decls
diff --git a/src/tools/clippy/clippy_lints/src/methods/single_char_insert_string.rs b/src/tools/clippy/clippy_lints/src/methods/single_char_insert_string.rs
index 44a7ad394fa..20ec2b74d81 100644
--- a/src/tools/clippy/clippy_lints/src/methods/single_char_insert_string.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/single_char_insert_string.rs
@@ -10,7 +10,7 @@ use super::SINGLE_CHAR_ADD_STR;
 /// lint for length-1 `str`s as argument for `insert_str`
 pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, receiver: &hir::Expr<'_>, args: &[hir::Expr<'_>]) {
     let mut applicability = Applicability::MachineApplicable;
-    if let Some(extension_string) = get_hint_if_single_char_arg(cx, &args[1], &mut applicability) {
+    if let Some(extension_string) = get_hint_if_single_char_arg(cx, &args[1], &mut applicability, false) {
         let base_string_snippet =
             snippet_with_applicability(cx, receiver.span.source_callsite(), "_", &mut applicability);
         let pos_arg = snippet_with_applicability(cx, args[0].span, "..", &mut applicability);
diff --git a/src/tools/clippy/clippy_lints/src/methods/single_char_pattern.rs b/src/tools/clippy/clippy_lints/src/methods/single_char_pattern.rs
index 363b1f2b812..982a7901c45 100644
--- a/src/tools/clippy/clippy_lints/src/methods/single_char_pattern.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/single_char_pattern.rs
@@ -8,7 +8,7 @@ use rustc_span::symbol::Symbol;
 
 use super::SINGLE_CHAR_PATTERN;
 
-const PATTERN_METHODS: [(&str, usize); 24] = [
+const PATTERN_METHODS: [(&str, usize); 22] = [
     ("contains", 0),
     ("starts_with", 0),
     ("ends_with", 0),
@@ -27,8 +27,6 @@ const PATTERN_METHODS: [(&str, usize); 24] = [
     ("rmatches", 0),
     ("match_indices", 0),
     ("rmatch_indices", 0),
-    ("strip_prefix", 0),
-    ("strip_suffix", 0),
     ("trim_start_matches", 0),
     ("trim_end_matches", 0),
     ("replace", 0),
@@ -50,7 +48,7 @@ pub(super) fn check(
             && args.len() > pos
             && let arg = &args[pos]
             && let mut applicability = Applicability::MachineApplicable
-            && let Some(hint) = get_hint_if_single_char_arg(cx, arg, &mut applicability)
+            && let Some(hint) = get_hint_if_single_char_arg(cx, arg, &mut applicability, true)
         {
             span_lint_and_sugg(
                 cx,
diff --git a/src/tools/clippy/clippy_lints/src/methods/single_char_push_string.rs b/src/tools/clippy/clippy_lints/src/methods/single_char_push_string.rs
index 0698bd6a0c5..97c13825bc1 100644
--- a/src/tools/clippy/clippy_lints/src/methods/single_char_push_string.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/single_char_push_string.rs
@@ -10,7 +10,7 @@ use super::SINGLE_CHAR_ADD_STR;
 /// lint for length-1 `str`s as argument for `push_str`
 pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, receiver: &hir::Expr<'_>, args: &[hir::Expr<'_>]) {
     let mut applicability = Applicability::MachineApplicable;
-    if let Some(extension_string) = get_hint_if_single_char_arg(cx, &args[0], &mut applicability) {
+    if let Some(extension_string) = get_hint_if_single_char_arg(cx, &args[0], &mut applicability, false) {
         let base_string_snippet =
             snippet_with_applicability(cx, receiver.span.source_callsite(), "..", &mut applicability);
         let sugg = format!("{base_string_snippet}.push({extension_string})");
diff --git a/src/tools/clippy/clippy_lints/src/methods/unused_enumerate_index.rs b/src/tools/clippy/clippy_lints/src/methods/unused_enumerate_index.rs
index e5cc898612e..8b8a965b9f0 100644
--- a/src/tools/clippy/clippy_lints/src/methods/unused_enumerate_index.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/unused_enumerate_index.rs
@@ -1,7 +1,6 @@
 use clippy_utils::diagnostics::{multispan_sugg_with_applicability, span_lint_hir_and_then};
-use clippy_utils::paths::{CORE_ITER_ENUMERATE_METHOD, CORE_ITER_ENUMERATE_STRUCT};
 use clippy_utils::source::{snippet, snippet_opt};
-use clippy_utils::{expr_or_init, is_trait_method, match_def_path, pat_is_wild};
+use clippy_utils::{expr_or_init, is_trait_method, pat_is_wild};
 use rustc_errors::Applicability;
 use rustc_hir::{Expr, ExprKind, FnDecl, PatKind, TyKind};
 use rustc_lint::LateContext;
@@ -42,7 +41,7 @@ pub(super) fn check(cx: &LateContext<'_>, call_expr: &Expr<'_>, recv: &Expr<'_>,
     let recv_ty = cx.typeck_results().expr_ty(recv);
     if let Some(recv_ty_defid) = recv_ty.ty_adt_def().map(AdtDef::did)
         // If we call a method on a `std::iter::Enumerate` instance
-        && match_def_path(cx, recv_ty_defid, &CORE_ITER_ENUMERATE_STRUCT)
+        && cx.tcx.is_diagnostic_item(sym::Enumerate, recv_ty_defid)
         // If we are calling a method of the `Iterator` trait
         && is_trait_method(cx, call_expr, sym::Iterator)
         // And the map argument is a closure
@@ -75,10 +74,10 @@ pub(super) fn check(cx: &LateContext<'_>, call_expr: &Expr<'_>, recv: &Expr<'_>,
         && let ExprKind::MethodCall(_, enumerate_recv, _, enumerate_span) = recv_init_expr.kind
         && let Some(enumerate_defid) = cx.typeck_results().type_dependent_def_id(recv_init_expr.hir_id)
         // Make sure the method call is `std::iter::Iterator::enumerate`.
-        && match_def_path(cx, enumerate_defid, &CORE_ITER_ENUMERATE_METHOD)
+        && cx.tcx.is_diagnostic_item(sym::enumerate_method, enumerate_defid)
     {
         // Check if the tuple type was explicit. It may be the type system _needs_ the type of the element
-        // that would be explicited in the closure.
+        // that would be explicitly in the closure.
         let new_closure_param = match find_elem_explicit_type_span(closure.fn_decl) {
             // We have an explicit type. Get its snippet, that of the binding name, and do `binding: ty`.
             // Fallback to `..` if we fail getting either snippet.
diff --git a/src/tools/clippy/clippy_lints/src/methods/utils.rs b/src/tools/clippy/clippy_lints/src/methods/utils.rs
index ef00c812d51..c50f24f824a 100644
--- a/src/tools/clippy/clippy_lints/src/methods/utils.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/utils.rs
@@ -52,11 +52,17 @@ pub(super) fn get_hint_if_single_char_arg(
     cx: &LateContext<'_>,
     arg: &Expr<'_>,
     applicability: &mut Applicability,
+    ascii_only: bool,
 ) -> Option<String> {
     if let ExprKind::Lit(lit) = &arg.kind
         && let ast::LitKind::Str(r, style) = lit.node
         && let string = r.as_str()
-        && string.chars().count() == 1
+        && let len = if ascii_only {
+            string.len()
+        } else {
+            string.chars().count()
+        }
+        && len == 1
     {
         let snip = snippet_with_applicability(cx, arg.span, string, applicability);
         let ch = if let ast::StrStyle::Raw(nhash) = style {
diff --git a/src/tools/clippy/clippy_lints/src/multiple_bound_locations.rs b/src/tools/clippy/clippy_lints/src/multiple_bound_locations.rs
index 191b32408ef..d608f3bf7b4 100644
--- a/src/tools/clippy/clippy_lints/src/multiple_bound_locations.rs
+++ b/src/tools/clippy/clippy_lints/src/multiple_bound_locations.rs
@@ -29,7 +29,7 @@ declare_clippy_lint! {
     ///     F: Sized + std::fmt::Debug,
     /// {}
     /// ```
-    #[clippy::version = "1.77.0"]
+    #[clippy::version = "1.78.0"]
     pub MULTIPLE_BOUND_LOCATIONS,
     suspicious,
     "defining generic bounds in multiple locations"
diff --git a/src/tools/clippy/clippy_lints/src/mut_key.rs b/src/tools/clippy/clippy_lints/src/mut_key.rs
index 8c2f43c97f4..2eb534da092 100644
--- a/src/tools/clippy/clippy_lints/src/mut_key.rs
+++ b/src/tools/clippy/clippy_lints/src/mut_key.rs
@@ -1,7 +1,6 @@
 use clippy_utils::diagnostics::span_lint;
-use clippy_utils::ty::is_interior_mut_ty;
-use clippy_utils::{def_path_def_ids, trait_ref_of_method};
-use rustc_data_structures::fx::FxHashSet;
+use clippy_utils::trait_ref_of_method;
+use clippy_utils::ty::InteriorMut;
 use rustc_hir as hir;
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_middle::ty::{self, Ty};
@@ -23,27 +22,15 @@ declare_clippy_lint! {
     /// ### Known problems
     ///
     /// #### False Positives
-    /// It's correct to use a struct that contains interior mutability as a key, when its
+    /// It's correct to use a struct that contains interior mutability as a key when its
     /// implementation of `Hash` or `Ord` doesn't access any of the interior mutable types.
     /// However, this lint is unable to recognize this, so it will often cause false positives in
-    /// theses cases.  The `bytes` crate is a great example of this.
+    /// these cases.
     ///
     /// #### False Negatives
-    /// For custom `struct`s/`enum`s, this lint is unable to check for interior mutability behind
-    /// indirection.  For example, `struct BadKey<'a>(&'a Cell<usize>)` will be seen as immutable
-    /// and cause a false negative if its implementation of `Hash`/`Ord` accesses the `Cell`.
-    ///
-    /// This lint does check a few cases for indirection.  Firstly, using some standard library
-    /// types (`Option`, `Result`, `Box`, `Rc`, `Arc`, `Vec`, `VecDeque`, `BTreeMap` and
-    /// `BTreeSet`) directly as keys (e.g. in `HashMap<Box<Cell<usize>>, ()>`) **will** trigger the
-    /// lint, because the impls of `Hash`/`Ord` for these types directly call `Hash`/`Ord` on their
-    /// contained type.
-    ///
-    /// Secondly, the implementations of `Hash` and `Ord` for raw pointers (`*const T` or `*mut T`)
-    /// apply only to the **address** of the contained value.  Therefore, interior mutability
-    /// behind raw pointers (e.g. in `HashSet<*mut Cell<usize>>`) can't impact the value of `Hash`
-    /// or `Ord`, and therefore will not trigger this link.  For more info, see issue
-    /// [#6745](https://github.com/rust-lang/rust-clippy/issues/6745).
+    /// This lint does not follow raw pointers (`*const T` or `*mut T`) as `Hash` and `Ord`
+    /// apply only to the **address** of the contained value. This can cause false negatives for
+    /// custom collections that use raw pointers internally.
     ///
     /// ### Example
     /// ```no_run
@@ -51,13 +38,12 @@ declare_clippy_lint! {
     /// use std::collections::HashSet;
     /// use std::hash::{Hash, Hasher};
     /// use std::sync::atomic::AtomicUsize;
-    ///# #[allow(unused)]
     ///
     /// struct Bad(AtomicUsize);
     /// impl PartialEq for Bad {
     ///     fn eq(&self, rhs: &Self) -> bool {
     ///          ..
-    /// ; unimplemented!();
+    /// # ; true
     ///     }
     /// }
     ///
@@ -66,7 +52,7 @@ declare_clippy_lint! {
     /// impl Hash for Bad {
     ///     fn hash<H: Hasher>(&self, h: &mut H) {
     ///         ..
-    /// ; unimplemented!();
+    /// # ;
     ///     }
     /// }
     ///
@@ -80,25 +66,16 @@ declare_clippy_lint! {
     "Check for mutable `Map`/`Set` key type"
 }
 
-#[derive(Clone)]
-pub struct MutableKeyType {
+pub struct MutableKeyType<'tcx> {
     ignore_interior_mutability: Vec<String>,
-    ignore_mut_def_ids: FxHashSet<hir::def_id::DefId>,
+    interior_mut: InteriorMut<'tcx>,
 }
 
-impl_lint_pass!(MutableKeyType => [ MUTABLE_KEY_TYPE ]);
+impl_lint_pass!(MutableKeyType<'_> => [ MUTABLE_KEY_TYPE ]);
 
-impl<'tcx> LateLintPass<'tcx> for MutableKeyType {
+impl<'tcx> LateLintPass<'tcx> for MutableKeyType<'tcx> {
     fn check_crate(&mut self, cx: &LateContext<'tcx>) {
-        self.ignore_mut_def_ids.clear();
-        let mut path = Vec::new();
-        for ty in &self.ignore_interior_mutability {
-            path.extend(ty.split("::"));
-            for id in def_path_def_ids(cx, &path[..]) {
-                self.ignore_mut_def_ids.insert(id);
-            }
-            path.clear();
-        }
+        self.interior_mut = InteriorMut::without_pointers(cx, &self.ignore_interior_mutability);
     }
 
     fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx hir::Item<'tcx>) {
@@ -121,7 +98,7 @@ impl<'tcx> LateLintPass<'tcx> for MutableKeyType {
         }
     }
 
-    fn check_local(&mut self, cx: &LateContext<'_>, local: &hir::LetStmt<'_>) {
+    fn check_local(&mut self, cx: &LateContext<'tcx>, local: &hir::LetStmt<'tcx>) {
         if let hir::PatKind::Wild = local.pat.kind {
             return;
         }
@@ -129,15 +106,15 @@ impl<'tcx> LateLintPass<'tcx> for MutableKeyType {
     }
 }
 
-impl MutableKeyType {
+impl<'tcx> MutableKeyType<'tcx> {
     pub fn new(ignore_interior_mutability: Vec<String>) -> Self {
         Self {
             ignore_interior_mutability,
-            ignore_mut_def_ids: FxHashSet::default(),
+            interior_mut: InteriorMut::default(),
         }
     }
 
-    fn check_sig(&self, cx: &LateContext<'_>, fn_def_id: LocalDefId, decl: &hir::FnDecl<'_>) {
+    fn check_sig(&mut self, cx: &LateContext<'tcx>, fn_def_id: LocalDefId, decl: &hir::FnDecl<'tcx>) {
         let fn_sig = cx.tcx.fn_sig(fn_def_id).instantiate_identity();
         for (hir_ty, ty) in iter::zip(decl.inputs, fn_sig.inputs().skip_binder()) {
             self.check_ty_(cx, hir_ty.span, *ty);
@@ -151,7 +128,7 @@ impl MutableKeyType {
 
     // We want to lint 1. sets or maps with 2. not immutable key types and 3. no unerased
     // generics (because the compiler cannot ensure immutability for unknown types).
-    fn check_ty_<'tcx>(&self, cx: &LateContext<'tcx>, span: Span, ty: Ty<'tcx>) {
+    fn check_ty_(&mut self, cx: &LateContext<'tcx>, span: Span, ty: Ty<'tcx>) {
         let ty = ty.peel_refs();
         if let ty::Adt(def, args) = ty.kind() {
             let is_keyed_type = [sym::HashMap, sym::BTreeMap, sym::HashSet, sym::BTreeSet]
@@ -162,11 +139,7 @@ impl MutableKeyType {
             }
 
             let subst_ty = args.type_at(0);
-            // Determines if a type contains interior mutability which would affect its implementation of
-            // [`Hash`] or [`Ord`].
-            if is_interior_mut_ty(cx, subst_ty)
-                && !matches!(subst_ty.ty_adt_def(), Some(adt) if self.ignore_mut_def_ids.contains(&adt.did()))
-            {
+            if self.interior_mut.is_interior_mut_ty(cx, subst_ty) {
                 span_lint(cx, MUTABLE_KEY_TYPE, span, "mutable key type");
             }
         }
diff --git a/src/tools/clippy/clippy_lints/src/needless_for_each.rs b/src/tools/clippy/clippy_lints/src/needless_for_each.rs
index 84a07df1bb0..630018238f4 100644
--- a/src/tools/clippy/clippy_lints/src/needless_for_each.rs
+++ b/src/tools/clippy/clippy_lints/src/needless_for_each.rs
@@ -1,6 +1,6 @@
 use rustc_errors::Applicability;
 use rustc_hir::intravisit::{walk_expr, Visitor};
-use rustc_hir::{Closure, Expr, ExprKind, Stmt, StmtKind};
+use rustc_hir::{Block, BlockCheckMode, Closure, Expr, ExprKind, Stmt, StmtKind};
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_session::declare_lint_pass;
 use rustc_span::{sym, Span, Symbol};
@@ -35,6 +35,16 @@ declare_clippy_lint! {
     ///     println!("{}", elem);
     /// }
     /// ```
+    ///
+    /// ### Known Problems
+    /// When doing things such as:
+    /// ```ignore
+    /// let v = vec![0, 1, 2];
+    /// v.iter().for_each(|elem| unsafe {
+    ///     libc::printf(c"%d\n".as_ptr(), elem);
+    /// });
+    /// ```
+    /// This lint will not trigger.
     #[clippy::version = "1.53.0"]
     pub NEEDLESS_FOR_EACH,
     pedantic,
@@ -68,7 +78,9 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessForEach {
             // e.g. `v.iter().for_each(f)` is simpler and clearer than using `for` loop.
             && let ExprKind::Closure(&Closure { body, .. }) = for_each_arg.kind
             && let body = cx.tcx.hir().body(body)
-            && let ExprKind::Block(..) = body.value.kind
+            // Skip the lint if the body is not safe, so as not to suggest `for … in … unsafe {}`
+            // and suggesting `for … in … { unsafe { } }` is a little ugly.
+            && let ExprKind::Block(Block { rules: BlockCheckMode::DefaultBlock, .. }, ..) = body.value.kind
         {
             let mut ret_collector = RetCollector::default();
             ret_collector.visit_expr(body.value);
diff --git a/src/tools/clippy/clippy_lints/src/needless_late_init.rs b/src/tools/clippy/clippy_lints/src/needless_late_init.rs
index 0c0b1a73351..6605d1fa51a 100644
--- a/src/tools/clippy/clippy_lints/src/needless_late_init.rs
+++ b/src/tools/clippy/clippy_lints/src/needless_late_init.rs
@@ -6,8 +6,7 @@ use clippy_utils::visitors::{for_each_expr, for_each_expr_with_closures, is_loca
 use core::ops::ControlFlow;
 use rustc_errors::{Applicability, MultiSpan};
 use rustc_hir::{
-    BindingMode, Block, Expr, ExprKind, HirId, LetStmt, LocalSource, MatchSource, Node, Pat, PatKind, Stmt,
-    StmtKind,
+    BindingMode, Block, Expr, ExprKind, HirId, LetStmt, LocalSource, MatchSource, Node, Pat, PatKind, Stmt, StmtKind,
 };
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_session::declare_lint_pass;
diff --git a/src/tools/clippy/clippy_lints/src/needless_pass_by_ref_mut.rs b/src/tools/clippy/clippy_lints/src/needless_pass_by_ref_mut.rs
index 30d3e86dc4e..9e47c3ad0b7 100644
--- a/src/tools/clippy/clippy_lints/src/needless_pass_by_ref_mut.rs
+++ b/src/tools/clippy/clippy_lints/src/needless_pass_by_ref_mut.rs
@@ -83,7 +83,9 @@ fn should_skip<'tcx>(
     }
 
     if is_self(arg) {
-        return true;
+        // Interestingly enough, `self` arguments make `is_from_proc_macro` return `true`, hence why
+        // we return early here.
+        return false;
     }
 
     if let PatKind::Binding(.., name, _) = arg.pat.kind {
@@ -185,7 +187,7 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessPassByRefMut<'tcx> {
         }
         // Collect variables mutably used and spans which will need dereferencings from the
         // function body.
-        let MutablyUsedVariablesCtxt { mutably_used_vars, .. } = {
+        let mutably_used_vars = {
             let mut ctx = MutablyUsedVariablesCtxt {
                 mutably_used_vars: HirIdSet::default(),
                 prev_bind: None,
@@ -217,7 +219,7 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessPassByRefMut<'tcx> {
                     check_closures(&mut ctx, cx, &infcx, &mut checked_closures, async_closures);
                 }
             }
-            ctx
+            ctx.generate_mutably_used_ids_from_aliases()
         };
         for ((&input, &_), arg) in it {
             // Only take `&mut` arguments.
@@ -309,12 +311,22 @@ struct MutablyUsedVariablesCtxt<'tcx> {
 }
 
 impl<'tcx> MutablyUsedVariablesCtxt<'tcx> {
-    fn add_mutably_used_var(&mut self, mut used_id: HirId) {
-        while let Some(id) = self.aliases.get(&used_id) {
+    fn add_mutably_used_var(&mut self, used_id: HirId) {
+        self.mutably_used_vars.insert(used_id);
+    }
+
+    // Because the alias may come after the mutable use of a variable, we need to fill the map at
+    // the end.
+    fn generate_mutably_used_ids_from_aliases(mut self) -> HirIdSet {
+        let all_ids = self.mutably_used_vars.iter().copied().collect::<Vec<_>>();
+        for mut used_id in all_ids {
+            while let Some(id) = self.aliases.get(&used_id) {
+                self.mutably_used_vars.insert(used_id);
+                used_id = *id;
+            }
             self.mutably_used_vars.insert(used_id);
-            used_id = *id;
         }
-        self.mutably_used_vars.insert(used_id);
+        self.mutably_used_vars
     }
 
     fn would_be_alias_cycle(&self, alias: HirId, mut target: HirId) -> bool {
diff --git a/src/tools/clippy/clippy_lints/src/needless_pass_by_value.rs b/src/tools/clippy/clippy_lints/src/needless_pass_by_value.rs
index 53bcde68087..39d374d0d27 100644
--- a/src/tools/clippy/clippy_lints/src/needless_pass_by_value.rs
+++ b/src/tools/clippy/clippy_lints/src/needless_pass_by_value.rs
@@ -9,8 +9,8 @@ use rustc_ast::ast::Attribute;
 use rustc_errors::{Applicability, Diag};
 use rustc_hir::intravisit::FnKind;
 use rustc_hir::{
-    BindingMode, Body, FnDecl, GenericArg, HirId, HirIdSet, Impl, ItemKind, LangItem, Mutability, Node, PatKind,
-    QPath, TyKind,
+    BindingMode, Body, FnDecl, GenericArg, HirId, HirIdSet, Impl, ItemKind, LangItem, Mutability, Node, PatKind, QPath,
+    TyKind,
 };
 use rustc_hir_typeck::expr_use_visitor as euv;
 use rustc_infer::infer::TyCtxtInferExt;
diff --git a/src/tools/clippy/clippy_lints/src/non_canonical_impls.rs b/src/tools/clippy/clippy_lints/src/non_canonical_impls.rs
index fd3985a5daf..932d6fe54d6 100644
--- a/src/tools/clippy/clippy_lints/src/non_canonical_impls.rs
+++ b/src/tools/clippy/clippy_lints/src/non_canonical_impls.rs
@@ -182,17 +182,17 @@ impl LateLintPass<'_> for NonCanonicalImpls {
 
             if block.stmts.is_empty()
                 && let Some(expr) = block.expr
-                && let ExprKind::Call(
-                        Expr {
-                            kind: ExprKind::Path(some_path),
-                            hir_id: some_hir_id,
-                            ..
-                        },
-                        [cmp_expr],
-                    ) = expr.kind
-                && is_res_lang_ctor(cx, cx.qpath_res(some_path, *some_hir_id), LangItem::OptionSome)
-                // Fix #11178, allow `Self::cmp(self, ..)` too
-                && self_cmp_call(cx, cmp_expr, impl_item.owner_id.def_id, &mut needs_fully_qualified)
+                && expr_is_cmp(cx, &expr.kind, impl_item, &mut needs_fully_qualified)
+            {
+            }
+            // Fix #12683, allow [`needless_return`] here
+            else if block.expr.is_none()
+                && let Some(stmt) = block.stmts.first()
+                && let rustc_hir::StmtKind::Semi(Expr {
+                    kind: ExprKind::Ret(Some(Expr { kind: ret_kind, .. })),
+                    ..
+                }) = stmt.kind
+                && expr_is_cmp(cx, ret_kind, impl_item, &mut needs_fully_qualified)
             {
             } else {
                 // If `Self` and `Rhs` are not the same type, bail. This makes creating a valid
@@ -245,6 +245,30 @@ impl LateLintPass<'_> for NonCanonicalImpls {
     }
 }
 
+/// Return true if `expr_kind` is a `cmp` call.
+fn expr_is_cmp<'tcx>(
+    cx: &LateContext<'tcx>,
+    expr_kind: &'tcx ExprKind<'tcx>,
+    impl_item: &ImplItem<'_>,
+    needs_fully_qualified: &mut bool,
+) -> bool {
+    if let ExprKind::Call(
+        Expr {
+            kind: ExprKind::Path(some_path),
+            hir_id: some_hir_id,
+            ..
+        },
+        [cmp_expr],
+    ) = expr_kind
+    {
+        is_res_lang_ctor(cx, cx.qpath_res(some_path, *some_hir_id), LangItem::OptionSome)
+            // Fix #11178, allow `Self::cmp(self, ..)` too
+            && self_cmp_call(cx, cmp_expr, impl_item.owner_id.def_id, needs_fully_qualified)
+    } else {
+        false
+    }
+}
+
 /// Returns whether this is any of `self.cmp(..)`, `Self::cmp(self, ..)` or `Ord::cmp(self, ..)`.
 fn self_cmp_call<'tcx>(
     cx: &LateContext<'tcx>,
diff --git a/src/tools/clippy/clippy_lints/src/non_copy_const.rs b/src/tools/clippy/clippy_lints/src/non_copy_const.rs
index ff10a841aef..76d9cee18aa 100644
--- a/src/tools/clippy/clippy_lints/src/non_copy_const.rs
+++ b/src/tools/clippy/clippy_lints/src/non_copy_const.rs
@@ -5,9 +5,9 @@
 use std::ptr;
 
 use clippy_utils::diagnostics::span_lint_and_then;
+use clippy_utils::in_constant;
 use clippy_utils::macros::macro_backtrace;
-use clippy_utils::{def_path_def_ids, in_constant};
-use rustc_data_structures::fx::FxHashSet;
+use clippy_utils::ty::InteriorMut;
 use rustc_hir::def::{DefKind, Res};
 use rustc_hir::def_id::DefId;
 use rustc_hir::{
@@ -52,8 +52,8 @@ declare_clippy_lint! {
     /// There're other enums plus associated constants cases that the lint cannot handle.
     ///
     /// Types that have underlying or potential interior mutability trigger the lint whether
-    /// the interior mutable field is used or not. See issues
-    /// [#5812](https://github.com/rust-lang/rust-clippy/issues/5812) and
+    /// the interior mutable field is used or not. See issue
+    /// [#5812](https://github.com/rust-lang/rust-clippy/issues/5812)
     ///
     /// ### Example
     /// ```no_run
@@ -170,42 +170,22 @@ fn lint(cx: &LateContext<'_>, source: Source) {
     });
 }
 
-#[derive(Clone)]
-pub struct NonCopyConst {
+pub struct NonCopyConst<'tcx> {
     ignore_interior_mutability: Vec<String>,
-    ignore_mut_def_ids: FxHashSet<DefId>,
+    interior_mut: InteriorMut<'tcx>,
 }
 
-impl_lint_pass!(NonCopyConst => [DECLARE_INTERIOR_MUTABLE_CONST, BORROW_INTERIOR_MUTABLE_CONST]);
+impl_lint_pass!(NonCopyConst<'_> => [DECLARE_INTERIOR_MUTABLE_CONST, BORROW_INTERIOR_MUTABLE_CONST]);
 
-impl NonCopyConst {
+impl<'tcx> NonCopyConst<'tcx> {
     pub fn new(ignore_interior_mutability: Vec<String>) -> Self {
         Self {
             ignore_interior_mutability,
-            ignore_mut_def_ids: FxHashSet::default(),
+            interior_mut: InteriorMut::default(),
         }
     }
 
-    fn is_ty_ignored(&self, ty: Ty<'_>) -> bool {
-        matches!(ty.ty_adt_def(), Some(adt) if self.ignore_mut_def_ids.contains(&adt.did()))
-    }
-
-    fn is_unfrozen<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool {
-        // Ignore types whose layout is unknown since `is_freeze` reports every generic types as `!Freeze`,
-        // making it indistinguishable from `UnsafeCell`. i.e. it isn't a tool to prove a type is
-        // 'unfrozen'. However, this code causes a false negative in which
-        // a type contains a layout-unknown type, but also an unsafe cell like `const CELL: Cell<T>`.
-        // Yet, it's better than `ty.has_type_flags(TypeFlags::HAS_TY_PARAM | TypeFlags::HAS_PROJECTION)`
-        // since it works when a pointer indirection involves (`Cell<*const T>`).
-        // Making up a `ParamEnv` where every generic params and assoc types are `Freeze`is another option;
-        // but I'm not sure whether it's a decent way, if possible.
-        cx.tcx.layout_of(cx.param_env.and(ty)).is_ok() && !ty.is_freeze(cx.tcx, cx.param_env)
-    }
-
-    fn is_value_unfrozen_raw_inner<'tcx>(&self, cx: &LateContext<'tcx>, val: ty::ValTree<'tcx>, ty: Ty<'tcx>) -> bool {
-        if self.is_ty_ignored(ty) {
-            return false;
-        }
+    fn is_value_unfrozen_raw_inner(cx: &LateContext<'tcx>, val: ty::ValTree<'tcx>, ty: Ty<'tcx>) -> bool {
         match *ty.kind() {
             // the fact that we have to dig into every structs to search enums
             // leads us to the point checking `UnsafeCell` directly is the only option.
@@ -216,8 +196,7 @@ impl NonCopyConst {
             ty::Array(ty, _) => val
                 .unwrap_branch()
                 .iter()
-                .any(|field| self.is_value_unfrozen_raw_inner(cx, *field, ty)),
-            ty::Adt(def, _) if def.is_union() => false,
+                .any(|field| Self::is_value_unfrozen_raw_inner(cx, *field, ty)),
             ty::Adt(def, args) if def.is_enum() => {
                 let (&variant_index, fields) = val.unwrap_branch().split_first().unwrap();
                 let variant_index = VariantIdx::from_u32(variant_index.unwrap_leaf().try_to_u32().ok().unwrap());
@@ -230,24 +209,23 @@ impl NonCopyConst {
                             .iter()
                             .map(|field| field.ty(cx.tcx, args)),
                     )
-                    .any(|(field, ty)| self.is_value_unfrozen_raw_inner(cx, field, ty))
+                    .any(|(field, ty)| Self::is_value_unfrozen_raw_inner(cx, field, ty))
             },
             ty::Adt(def, args) => val
                 .unwrap_branch()
                 .iter()
                 .zip(def.non_enum_variant().fields.iter().map(|field| field.ty(cx.tcx, args)))
-                .any(|(field, ty)| self.is_value_unfrozen_raw_inner(cx, *field, ty)),
+                .any(|(field, ty)| Self::is_value_unfrozen_raw_inner(cx, *field, ty)),
             ty::Tuple(tys) => val
                 .unwrap_branch()
                 .iter()
                 .zip(tys)
-                .any(|(field, ty)| self.is_value_unfrozen_raw_inner(cx, *field, ty)),
+                .any(|(field, ty)| Self::is_value_unfrozen_raw_inner(cx, *field, ty)),
             _ => false,
         }
     }
 
-    fn is_value_unfrozen_raw<'tcx>(
-        &self,
+    fn is_value_unfrozen_raw(
         cx: &LateContext<'tcx>,
         result: Result<Option<ty::ValTree<'tcx>>, ErrorHandled>,
         ty: Ty<'tcx>,
@@ -277,11 +255,11 @@ impl NonCopyConst {
                 // I chose this way because unfrozen enums as assoc consts are rare (or, hopefully, none).
                 matches!(err, ErrorHandled::TooGeneric(..))
             },
-            |val| val.map_or(true, |val| self.is_value_unfrozen_raw_inner(cx, val, ty)),
+            |val| val.map_or(true, |val| Self::is_value_unfrozen_raw_inner(cx, val, ty)),
         )
     }
 
-    fn is_value_unfrozen_poly<'tcx>(&self, cx: &LateContext<'tcx>, body_id: BodyId, ty: Ty<'tcx>) -> bool {
+    fn is_value_unfrozen_poly(cx: &LateContext<'tcx>, body_id: BodyId, ty: Ty<'tcx>) -> bool {
         let def_id = body_id.hir_id.owner.to_def_id();
         let args = ty::GenericArgs::identity_for_item(cx.tcx, def_id);
         let instance = ty::Instance::new(def_id, args);
@@ -291,17 +269,17 @@ impl NonCopyConst {
         };
         let param_env = cx.tcx.param_env(def_id).with_reveal_all_normalized(cx.tcx);
         let result = cx.tcx.const_eval_global_id_for_typeck(param_env, cid, DUMMY_SP);
-        self.is_value_unfrozen_raw(cx, result, ty)
+        Self::is_value_unfrozen_raw(cx, result, ty)
     }
 
-    fn is_value_unfrozen_expr<'tcx>(&self, cx: &LateContext<'tcx>, hir_id: HirId, def_id: DefId, ty: Ty<'tcx>) -> bool {
+    fn is_value_unfrozen_expr(cx: &LateContext<'tcx>, hir_id: HirId, def_id: DefId, ty: Ty<'tcx>) -> bool {
         let args = cx.typeck_results().node_args(hir_id);
 
         let result = Self::const_eval_resolve(cx.tcx, cx.param_env, ty::UnevaluatedConst::new(def_id, args), DUMMY_SP);
-        self.is_value_unfrozen_raw(cx, result, ty)
+        Self::is_value_unfrozen_raw(cx, result, ty)
     }
 
-    pub fn const_eval_resolve<'tcx>(
+    pub fn const_eval_resolve(
         tcx: TyCtxt<'tcx>,
         param_env: ty::ParamEnv<'tcx>,
         ct: ty::UnevaluatedConst<'tcx>,
@@ -321,26 +299,17 @@ impl NonCopyConst {
     }
 }
 
-impl<'tcx> LateLintPass<'tcx> for NonCopyConst {
+impl<'tcx> LateLintPass<'tcx> for NonCopyConst<'tcx> {
     fn check_crate(&mut self, cx: &LateContext<'tcx>) {
-        self.ignore_mut_def_ids.clear();
-        let mut path = Vec::new();
-        for ty in &self.ignore_interior_mutability {
-            path.extend(ty.split("::"));
-            for id in def_path_def_ids(cx, &path[..]) {
-                self.ignore_mut_def_ids.insert(id);
-            }
-            path.clear();
-        }
+        self.interior_mut = InteriorMut::new(cx, &self.ignore_interior_mutability);
     }
 
     fn check_item(&mut self, cx: &LateContext<'tcx>, it: &'tcx Item<'_>) {
         if let ItemKind::Const(.., body_id) = it.kind {
             let ty = cx.tcx.type_of(it.owner_id).instantiate_identity();
             if !ignored_macro(cx, it)
-                && !self.is_ty_ignored(ty)
-                && Self::is_unfrozen(cx, ty)
-                && self.is_value_unfrozen_poly(cx, body_id, ty)
+                && self.interior_mut.is_interior_mut_ty(cx, ty)
+                && Self::is_value_unfrozen_poly(cx, body_id, ty)
             {
                 lint(cx, Source::Item { item: it.span });
             }
@@ -354,7 +323,7 @@ impl<'tcx> LateLintPass<'tcx> for NonCopyConst {
             // Normalize assoc types because ones originated from generic params
             // bounded other traits could have their bound.
             let normalized = cx.tcx.normalize_erasing_regions(cx.param_env, ty);
-            if !self.is_ty_ignored(ty) && Self::is_unfrozen(cx, normalized)
+            if self.interior_mut.is_interior_mut_ty(cx, normalized)
                 // When there's no default value, lint it only according to its type;
                 // in other words, lint consts whose value *could* be unfrozen, not definitely is.
                 // This feels inconsistent with how the lint treats generic types,
@@ -367,7 +336,7 @@ impl<'tcx> LateLintPass<'tcx> for NonCopyConst {
                 // i.e. having an enum doesn't necessary mean a type has a frozen variant.
                 // And, implementing it isn't a trivial task; it'll probably end up
                 // re-implementing the trait predicate evaluation specific to `Freeze`.
-                && body_id_opt.map_or(true, |body_id| self.is_value_unfrozen_poly(cx, body_id, normalized))
+                && body_id_opt.map_or(true, |body_id| Self::is_value_unfrozen_poly(cx, body_id, normalized))
             {
                 lint(cx, Source::Assoc { item: trait_item.span });
             }
@@ -409,8 +378,8 @@ impl<'tcx> LateLintPass<'tcx> for NonCopyConst {
                             // e.g. `layout_of(...).is_err() || has_frozen_variant(...);`
                         && let ty = cx.tcx.type_of(impl_item.owner_id).instantiate_identity()
                         && let normalized = cx.tcx.normalize_erasing_regions(cx.param_env, ty)
-                        && !self.is_ty_ignored(ty) && Self::is_unfrozen(cx, normalized)
-                        && self.is_value_unfrozen_poly(cx, *body_id, normalized)
+                        && self.interior_mut.is_interior_mut_ty(cx, normalized)
+                        && Self::is_value_unfrozen_poly(cx, *body_id, normalized)
                     {
                         lint(cx, Source::Assoc { item: impl_item.span });
                     }
@@ -420,9 +389,8 @@ impl<'tcx> LateLintPass<'tcx> for NonCopyConst {
                     // Normalize assoc types originated from generic params.
                     let normalized = cx.tcx.normalize_erasing_regions(cx.param_env, ty);
 
-                    if !self.is_ty_ignored(ty)
-                        && Self::is_unfrozen(cx, ty)
-                        && self.is_value_unfrozen_poly(cx, *body_id, normalized)
+                    if self.interior_mut.is_interior_mut_ty(cx, normalized)
+                        && Self::is_value_unfrozen_poly(cx, *body_id, normalized)
                     {
                         lint(cx, Source::Assoc { item: impl_item.span });
                     }
@@ -517,9 +485,8 @@ impl<'tcx> LateLintPass<'tcx> for NonCopyConst {
                 cx.typeck_results().expr_ty(dereferenced_expr)
             };
 
-            if !self.is_ty_ignored(ty)
-                && Self::is_unfrozen(cx, ty)
-                && self.is_value_unfrozen_expr(cx, expr.hir_id, item_def_id, ty)
+            if self.interior_mut.is_interior_mut_ty(cx, ty)
+                && Self::is_value_unfrozen_expr(cx, expr.hir_id, item_def_id, ty)
             {
                 lint(cx, Source::Expr { expr: expr.span });
             }
diff --git a/src/tools/clippy/clippy_lints/src/operators/arithmetic_side_effects.rs b/src/tools/clippy/clippy_lints/src/operators/arithmetic_side_effects.rs
index 96ea063aa74..7d6f26cde3e 100644
--- a/src/tools/clippy/clippy_lints/src/operators/arithmetic_side_effects.rs
+++ b/src/tools/clippy/clippy_lints/src/operators/arithmetic_side_effects.rs
@@ -7,14 +7,13 @@ use rustc_data_structures::fx::{FxHashMap, FxHashSet};
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_middle::ty::{self, Ty};
 use rustc_session::impl_lint_pass;
-use rustc_span::source_map::Spanned;
 use rustc_span::symbol::sym;
 use rustc_span::{Span, Symbol};
 use {rustc_ast as ast, rustc_hir as hir};
 
 const HARD_CODED_ALLOWED_BINARY: &[[&str; 2]] = &[["f32", "f32"], ["f64", "f64"], ["std::string::String", "str"]];
 const HARD_CODED_ALLOWED_UNARY: &[&str] = &["f32", "f64", "std::num::Saturating", "std::num::Wrapping"];
-const INTEGER_METHODS: &[Symbol] = &[
+const DISALLOWED_INT_METHODS: &[Symbol] = &[
     sym::saturating_div,
     sym::wrapping_div,
     sym::wrapping_rem,
@@ -27,8 +26,8 @@ pub struct ArithmeticSideEffects {
     allowed_unary: FxHashSet<String>,
     // Used to check whether expressions are constants, such as in enum discriminants and consts
     const_span: Option<Span>,
+    disallowed_int_methods: FxHashSet<Symbol>,
     expr_span: Option<Span>,
-    integer_methods: FxHashSet<Symbol>,
 }
 
 impl_lint_pass!(ArithmeticSideEffects => [ARITHMETIC_SIDE_EFFECTS]);
@@ -53,8 +52,8 @@ impl ArithmeticSideEffects {
             allowed_binary,
             allowed_unary,
             const_span: None,
+            disallowed_int_methods: DISALLOWED_INT_METHODS.iter().copied().collect(),
             expr_span: None,
-            integer_methods: INTEGER_METHODS.iter().copied().collect(),
         }
     }
 
@@ -91,10 +90,10 @@ impl ArithmeticSideEffects {
     fn has_specific_allowed_type_and_operation<'tcx>(
         cx: &LateContext<'tcx>,
         lhs_ty: Ty<'tcx>,
-        op: &Spanned<hir::BinOpKind>,
+        op: hir::BinOpKind,
         rhs_ty: Ty<'tcx>,
     ) -> bool {
-        let is_div_or_rem = matches!(op.node, hir::BinOpKind::Div | hir::BinOpKind::Rem);
+        let is_div_or_rem = matches!(op, hir::BinOpKind::Div | hir::BinOpKind::Rem);
         let is_non_zero_u = |cx: &LateContext<'tcx>, ty: Ty<'tcx>| {
             let tcx = cx.tcx;
 
@@ -166,13 +165,35 @@ impl ArithmeticSideEffects {
         None
     }
 
+    /// Methods like `add_assign` are send to their `BinOps` references.
+    fn manage_sugar_methods<'tcx>(
+        &mut self,
+        cx: &LateContext<'tcx>,
+        expr: &'tcx hir::Expr<'_>,
+        lhs: &'tcx hir::Expr<'_>,
+        ps: &hir::PathSegment<'_>,
+        rhs: &'tcx hir::Expr<'_>,
+    ) {
+        if ps.ident.name == sym::add || ps.ident.name == sym::add_assign {
+            self.manage_bin_ops(cx, expr, hir::BinOpKind::Add, lhs, rhs);
+        } else if ps.ident.name == sym::div || ps.ident.name == sym::div_assign {
+            self.manage_bin_ops(cx, expr, hir::BinOpKind::Div, lhs, rhs);
+        } else if ps.ident.name == sym::mul || ps.ident.name == sym::mul_assign {
+            self.manage_bin_ops(cx, expr, hir::BinOpKind::Mul, lhs, rhs);
+        } else if ps.ident.name == sym::rem || ps.ident.name == sym::rem_assign {
+            self.manage_bin_ops(cx, expr, hir::BinOpKind::Rem, lhs, rhs);
+        } else if ps.ident.name == sym::sub || ps.ident.name == sym::sub_assign {
+            self.manage_bin_ops(cx, expr, hir::BinOpKind::Sub, lhs, rhs);
+        }
+    }
+
     /// Manages when the lint should be triggered. Operations in constant environments, hard coded
-    /// types, custom allowed types and non-constant operations that won't overflow are ignored.
+    /// types, custom allowed types and non-constant operations that don't overflow are ignored.
     fn manage_bin_ops<'tcx>(
         &mut self,
         cx: &LateContext<'tcx>,
         expr: &'tcx hir::Expr<'_>,
-        op: &Spanned<hir::BinOpKind>,
+        op: hir::BinOpKind,
         lhs: &'tcx hir::Expr<'_>,
         rhs: &'tcx hir::Expr<'_>,
     ) {
@@ -180,7 +201,7 @@ impl ArithmeticSideEffects {
             return;
         }
         if !matches!(
-            op.node,
+            op,
             hir::BinOpKind::Add
                 | hir::BinOpKind::Div
                 | hir::BinOpKind::Mul
@@ -204,7 +225,7 @@ impl ArithmeticSideEffects {
             return;
         }
         let has_valid_op = if Self::is_integral(lhs_ty) && Self::is_integral(rhs_ty) {
-            if let hir::BinOpKind::Shl | hir::BinOpKind::Shr = op.node {
+            if let hir::BinOpKind::Shl | hir::BinOpKind::Shr = op {
                 // At least for integers, shifts are already handled by the CTFE
                 return;
             }
@@ -213,7 +234,7 @@ impl ArithmeticSideEffects {
                 Self::literal_integer(cx, actual_rhs),
             ) {
                 (None, None) => false,
-                (None, Some(n)) => match (&op.node, n) {
+                (None, Some(n)) => match (&op, n) {
                     // Division and module are always valid if applied to non-zero integers
                     (hir::BinOpKind::Div | hir::BinOpKind::Rem, local_n) if local_n != 0 => true,
                     // Adding or subtracting zeros is always a no-op
@@ -223,7 +244,7 @@ impl ArithmeticSideEffects {
                     => true,
                     _ => false,
                 },
-                (Some(n), None) => match (&op.node, n) {
+                (Some(n), None) => match (&op, n) {
                     // Adding or subtracting zeros is always a no-op
                     (hir::BinOpKind::Add | hir::BinOpKind::Sub, 0)
                     // Multiplication by 1 or 0 will never overflow
@@ -249,6 +270,7 @@ impl ArithmeticSideEffects {
         &mut self,
         args: &'tcx [hir::Expr<'_>],
         cx: &LateContext<'tcx>,
+        expr: &'tcx hir::Expr<'_>,
         ps: &'tcx hir::PathSegment<'_>,
         receiver: &'tcx hir::Expr<'_>,
     ) {
@@ -262,7 +284,8 @@ impl ArithmeticSideEffects {
         if !Self::is_integral(instance_ty) {
             return;
         }
-        if !self.integer_methods.contains(&ps.ident.name) {
+        self.manage_sugar_methods(cx, expr, receiver, ps, arg);
+        if !self.disallowed_int_methods.contains(&ps.ident.name) {
             return;
         }
         let (actual_arg, _) = peel_hir_expr_refs(arg);
@@ -310,10 +333,10 @@ impl<'tcx> LateLintPass<'tcx> for ArithmeticSideEffects {
         }
         match &expr.kind {
             hir::ExprKind::AssignOp(op, lhs, rhs) | hir::ExprKind::Binary(op, lhs, rhs) => {
-                self.manage_bin_ops(cx, expr, op, lhs, rhs);
+                self.manage_bin_ops(cx, expr, op.node, lhs, rhs);
             },
             hir::ExprKind::MethodCall(ps, receiver, args, _) => {
-                self.manage_method_call(args, cx, ps, receiver);
+                self.manage_method_call(args, cx, expr, ps, receiver);
             },
             hir::ExprKind::Unary(un_op, un_expr) => {
                 self.manage_unary_ops(cx, expr, un_expr, *un_op);
diff --git a/src/tools/clippy/clippy_lints/src/ptr.rs b/src/tools/clippy/clippy_lints/src/ptr.rs
index cc61ef9184c..2534e3c8468 100644
--- a/src/tools/clippy/clippy_lints/src/ptr.rs
+++ b/src/tools/clippy/clippy_lints/src/ptr.rs
@@ -11,9 +11,8 @@ use rustc_hir::def_id::DefId;
 use rustc_hir::hir_id::{HirId, HirIdMap};
 use rustc_hir::intravisit::{walk_expr, Visitor};
 use rustc_hir::{
-    self as hir, AnonConst, BinOpKind, BindingMode, Body, Expr, ExprKind, FnRetTy, FnSig, GenericArg,
-    ImplItemKind, ItemKind, Lifetime, Mutability, Node, Param, PatKind, QPath, TraitFn, TraitItem, TraitItemKind,
-    TyKind, Unsafety,
+    self as hir, AnonConst, BinOpKind, BindingMode, Body, Expr, ExprKind, FnRetTy, FnSig, GenericArg, ImplItemKind,
+    ItemKind, Lifetime, Mutability, Node, Param, PatKind, QPath, TraitFn, TraitItem, TraitItemKind, TyKind, Unsafety,
 };
 use rustc_infer::infer::TyCtxtInferExt;
 use rustc_infer::traits::{Obligation, ObligationCause};
@@ -687,9 +686,7 @@ fn check_ptr_arg_usage<'tcx>(cx: &LateContext<'tcx>, body: &'tcx Body<'_>, args:
             .filter_map(|(i, arg)| {
                 let param = &body.params[arg.idx];
                 match param.pat.kind {
-                    PatKind::Binding(BindingMode::NONE, id, _, None)
-                        if !is_lint_allowed(cx, PTR_ARG, param.hir_id) =>
-                    {
+                    PatKind::Binding(BindingMode::NONE, id, _, None) if !is_lint_allowed(cx, PTR_ARG, param.hir_id) => {
                         Some((id, i))
                     },
                     _ => {
diff --git a/src/tools/clippy/clippy_lints/src/question_mark.rs b/src/tools/clippy/clippy_lints/src/question_mark.rs
index 4ad967589a5..1f1ce147ca2 100644
--- a/src/tools/clippy/clippy_lints/src/question_mark.rs
+++ b/src/tools/clippy/clippy_lints/src/question_mark.rs
@@ -14,8 +14,8 @@ use rustc_errors::Applicability;
 use rustc_hir::def::Res;
 use rustc_hir::LangItem::{self, OptionNone, OptionSome, ResultErr, ResultOk};
 use rustc_hir::{
-    BindingMode, Block, Body, ByRef, Expr, ExprKind, LetStmt, Mutability, Node, PatKind, PathSegment, QPath,
-    Stmt, StmtKind,
+    BindingMode, Block, Body, ByRef, Expr, ExprKind, LetStmt, Mutability, Node, PatKind, PathSegment, QPath, Stmt,
+    StmtKind,
 };
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_middle::ty::Ty;
diff --git a/src/tools/clippy/clippy_lints/src/repeat_vec_with_capacity.rs b/src/tools/clippy/clippy_lints/src/repeat_vec_with_capacity.rs
index a358881bf80..792d8fc88f0 100644
--- a/src/tools/clippy/clippy_lints/src/repeat_vec_with_capacity.rs
+++ b/src/tools/clippy/clippy_lints/src/repeat_vec_with_capacity.rs
@@ -1,7 +1,7 @@
 use clippy_utils::consts::{constant, Constant};
 use clippy_utils::diagnostics::span_lint_and_then;
 use clippy_utils::higher::VecArgs;
-use clippy_utils::macros::root_macro_call;
+use clippy_utils::macros::matching_root_macro_call;
 use clippy_utils::source::snippet;
 use clippy_utils::{expr_or_init, fn_def_id, match_def_path, paths};
 use rustc_errors::Applicability;
@@ -65,8 +65,7 @@ fn emit_lint(cx: &LateContext<'_>, span: Span, kind: &str, note: &'static str, s
 
 /// Checks `vec![Vec::with_capacity(x); n]`
 fn check_vec_macro(cx: &LateContext<'_>, expr: &Expr<'_>) {
-    if let Some(mac_call) = root_macro_call(expr.span)
-        && cx.tcx.is_diagnostic_item(sym::vec_macro, mac_call.def_id)
+    if matching_root_macro_call(cx, expr.span, sym::vec_macro).is_some()
         && let Some(VecArgs::Repeat(repeat_expr, len_expr)) = VecArgs::hir(cx, expr)
         && fn_def_id(cx, repeat_expr).is_some_and(|did| match_def_path(cx, did, &paths::VEC_WITH_CAPACITY))
         && !len_expr.span.from_expansion()
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 14ca7a3f004..8d7f12af86e 100644
--- a/src/tools/clippy/clippy_lints/src/size_of_ref.rs
+++ b/src/tools/clippy/clippy_lints/src/size_of_ref.rs
@@ -28,7 +28,7 @@ declare_clippy_lint! {
     ///     fn size(&self) -> usize {
     ///         // Note that `&self` as an argument is a `&&Foo`: Because `self`
     ///         // is already a reference, `&self` is a double-reference.
-    ///         // The return value of `size_of_val()` therefor is the
+    ///         // The return value of `size_of_val()` therefore is the
     ///         // size of the reference-type, not the size of `self`.
     ///         std::mem::size_of_val(&self)
     ///     }
diff --git a/src/tools/clippy/clippy_lints/src/slow_vector_initialization.rs b/src/tools/clippy/clippy_lints/src/slow_vector_initialization.rs
index 28c254537ab..b0e25c02265 100644
--- a/src/tools/clippy/clippy_lints/src/slow_vector_initialization.rs
+++ b/src/tools/clippy/clippy_lints/src/slow_vector_initialization.rs
@@ -1,5 +1,5 @@
 use clippy_utils::diagnostics::span_lint_and_then;
-use clippy_utils::macros::root_macro_call;
+use clippy_utils::macros::matching_root_macro_call;
 use clippy_utils::sugg::Sugg;
 use clippy_utils::{
     get_enclosing_block, is_expr_path_def_path, is_integer_literal, is_path_diagnostic_item, path_to_local,
@@ -145,9 +145,7 @@ impl SlowVectorInit {
         // Generally don't warn if the vec initializer comes from an expansion, except for the vec! macro.
         // This lets us still warn on `vec![]`, while ignoring other kinds of macros that may output an
         // empty vec
-        if expr.span.from_expansion()
-            && root_macro_call(expr.span).map(|m| m.def_id) != cx.tcx.get_diagnostic_item(sym::vec_macro)
-        {
+        if expr.span.from_expansion() && matching_root_macro_call(cx, expr.span, sym::vec_macro).is_none() {
             return None;
         }
 
diff --git a/src/tools/clippy/clippy_lints/src/thread_local_initializer_can_be_made_const.rs b/src/tools/clippy/clippy_lints/src/thread_local_initializer_can_be_made_const.rs
index c1e24674e3e..4af3ee74d0e 100644
--- a/src/tools/clippy/clippy_lints/src/thread_local_initializer_can_be_made_const.rs
+++ b/src/tools/clippy/clippy_lints/src/thread_local_initializer_can_be_made_const.rs
@@ -1,13 +1,14 @@
 use clippy_config::msrvs::{self, Msrv};
 use clippy_utils::diagnostics::span_lint_and_sugg;
+use clippy_utils::macros::macro_backtrace;
 use clippy_utils::qualify_min_const_fn::is_min_const_fn;
 use clippy_utils::source::snippet;
 use clippy_utils::{fn_has_unsatisfiable_preds, peel_blocks};
 use rustc_errors::Applicability;
-use rustc_hir::{intravisit, ExprKind};
+use rustc_hir::{intravisit, Expr, ExprKind};
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_session::impl_lint_pass;
-use rustc_span::sym::thread_local_macro;
+use rustc_span::sym::{self, thread_local_macro};
 
 declare_clippy_lint! {
     /// ### What it does
@@ -69,6 +70,26 @@ fn is_thread_local_initializer(
     )
 }
 
+fn is_unreachable(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
+    if let Some(macro_call) = macro_backtrace(expr.span).next()
+        && let Some(diag_name) = cx.tcx.get_diagnostic_name(macro_call.def_id)
+    {
+        return (matches!(
+            diag_name,
+            sym::core_panic_macro
+                | sym::std_panic_macro
+                | sym::core_panic_2015_macro
+                | sym::std_panic_2015_macro
+                | sym::core_panic_2021_macro
+        ) && !cx.tcx.hir().is_inside_const_context(expr.hir_id))
+            || matches!(
+                diag_name,
+                sym::unimplemented_macro | sym::todo_macro | sym::unreachable_macro | sym::unreachable_2015_macro
+            );
+    }
+    false
+}
+
 #[inline]
 fn initializer_can_be_made_const(cx: &LateContext<'_>, defid: rustc_span::def_id::DefId, msrv: &Msrv) -> bool {
     // Building MIR for `fn`s with unsatisfiable preds results in ICE.
@@ -102,12 +123,17 @@ impl<'tcx> LateLintPass<'tcx> for ThreadLocalInitializerCanBeMadeConst {
             // for details on this issue, see:
             // https://github.com/rust-lang/rust-clippy/pull/12276
             && !cx.tcx.is_const_fn(defid)
-            && initializer_can_be_made_const(cx, defid, &self.msrv)
-            // we know that the function is const-qualifiable, so now
-            // we need only to get the initializer expression to span-lint it.
             && let ExprKind::Block(block, _) = body.value.kind
             && let Some(unpeeled) = block.expr
             && let ret_expr = peel_blocks(unpeeled)
+            // A common pattern around threadlocal! is to make the value unreachable
+            // to force an initialization before usage
+            // https://github.com/rust-lang/rust-clippy/issues/12637
+            // we ensure that this is reachable before we check in mir
+            && !is_unreachable(cx, ret_expr)
+            && initializer_can_be_made_const(cx, defid, &self.msrv)
+            // we know that the function is const-qualifiable, so now
+            // we need only to get the initializer expression to span-lint it.
             && let initializer_snippet = snippet(cx, ret_expr.span, "thread_local! { ... }")
             && initializer_snippet != "thread_local! { ... }"
         {
diff --git a/src/tools/clippy/clippy_lints/src/to_string_trait_impl.rs b/src/tools/clippy/clippy_lints/src/to_string_trait_impl.rs
index 59ae185c9de..0361836cdec 100644
--- a/src/tools/clippy/clippy_lints/src/to_string_trait_impl.rs
+++ b/src/tools/clippy/clippy_lints/src/to_string_trait_impl.rs
@@ -38,7 +38,7 @@ declare_clippy_lint! {
     ///   }
     /// }
     /// ```
-    #[clippy::version = "1.77.0"]
+    #[clippy::version = "1.78.0"]
     pub TO_STRING_TRAIT_IMPL,
     style,
     "check for direct implementations of `ToString`"
diff --git a/src/tools/clippy/clippy_lints/src/trait_bounds.rs b/src/tools/clippy/clippy_lints/src/trait_bounds.rs
index 9468d367a92..c05cd9ed593 100644
--- a/src/tools/clippy/clippy_lints/src/trait_bounds.rs
+++ b/src/tools/clippy/clippy_lints/src/trait_bounds.rs
@@ -237,6 +237,7 @@ impl TraitBounds {
         }
     }
 
+    #[allow(clippy::mutable_key_type)]
     fn check_type_repetition<'tcx>(&self, cx: &LateContext<'tcx>, gen: &'tcx Generics<'_>) {
         struct SpanlessTy<'cx, 'tcx> {
             ty: &'tcx Ty<'tcx>,
diff --git a/src/tools/clippy/clippy_lints/src/types/mod.rs b/src/tools/clippy/clippy_lints/src/types/mod.rs
index 0802cb2b7c7..5e45ab211ef 100644
--- a/src/tools/clippy/clippy_lints/src/types/mod.rs
+++ b/src/tools/clippy/clippy_lints/src/types/mod.rs
@@ -12,8 +12,8 @@ mod vec_box;
 use rustc_hir as hir;
 use rustc_hir::intravisit::FnKind;
 use rustc_hir::{
-    Body, FnDecl, FnRetTy, GenericArg, ImplItem, ImplItemKind, Item, ItemKind, LetStmt, MutTy, QPath, TraitItem,
-    TraitItemKind, TyKind,
+    Body, FnDecl, FnRetTy, GenericArg, ImplItem, ImplItemKind, Item, ItemKind, LetStmt, MutTy, QPath, TraitFn,
+    TraitItem, TraitItemKind, TyKind,
 };
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_session::impl_lint_pass;
@@ -420,7 +420,13 @@ impl<'tcx> LateLintPass<'tcx> for Types {
             TraitItemKind::Const(ty, _) | TraitItemKind::Type(_, Some(ty)) => {
                 self.check_ty(cx, ty, context);
             },
-            TraitItemKind::Fn(ref sig, _) => self.check_fn_decl(cx, sig.decl, context),
+            TraitItemKind::Fn(ref sig, trait_method) => {
+                // Check only methods without body
+                // Methods with body are covered by check_fn.
+                if let TraitFn::Required(_) = trait_method {
+                    self.check_fn_decl(cx, sig.decl, context);
+                }
+            },
             TraitItemKind::Type(..) => (),
         }
     }
diff --git a/src/tools/clippy/clippy_lints/src/utils/author.rs b/src/tools/clippy/clippy_lints/src/utils/author.rs
index 7f0769452c7..4448c9ae3df 100644
--- a/src/tools/clippy/clippy_lints/src/utils/author.rs
+++ b/src/tools/clippy/clippy_lints/src/utils/author.rs
@@ -7,8 +7,8 @@ use rustc_ast::LitIntType;
 use rustc_data_structures::fx::FxHashMap;
 use rustc_hir as hir;
 use rustc_hir::{
-    ArrayLen, BindingMode, CaptureBy, Closure, ClosureKind, CoroutineKind, ExprKind, FnRetTy, HirId, Lit,
-    PatKind, QPath, StmtKind, TyKind,
+    ArrayLen, BindingMode, CaptureBy, Closure, ClosureKind, CoroutineKind, ExprKind, FnRetTy, HirId, Lit, PatKind,
+    QPath, StmtKind, TyKind,
 };
 use rustc_lint::{LateContext, LateLintPass, LintContext};
 use rustc_session::declare_lint_pass;
diff --git a/src/tools/clippy/clippy_lints/src/vec.rs b/src/tools/clippy/clippy_lints/src/vec.rs
index 27ead55bf39..9edf7579d48 100644
--- a/src/tools/clippy/clippy_lints/src/vec.rs
+++ b/src/tools/clippy/clippy_lints/src/vec.rs
@@ -7,7 +7,7 @@ use clippy_utils::diagnostics::span_lint_hir_and_then;
 use clippy_utils::source::snippet_opt;
 use clippy_utils::ty::is_copy;
 use clippy_utils::visitors::for_each_local_use_after_expr;
-use clippy_utils::{get_parent_expr, higher, is_trait_method};
+use clippy_utils::{get_parent_expr, higher, is_in_test, is_trait_method};
 use rustc_errors::Applicability;
 use rustc_hir::{BorrowKind, Expr, ExprKind, HirId, LetStmt, Mutability, Node, Pat, PatKind};
 use rustc_lint::{LateContext, LateLintPass};
@@ -22,6 +22,7 @@ pub struct UselessVec {
     pub too_large_for_stack: u64,
     pub msrv: Msrv,
     pub span_to_lint_map: BTreeMap<Span, Option<(HirId, SuggestedType, String, Applicability)>>,
+    pub allow_in_test: bool,
 }
 
 declare_clippy_lint! {
@@ -57,6 +58,9 @@ impl<'tcx> LateLintPass<'tcx> for UselessVec {
         let Some(vec_args) = higher::VecArgs::hir(cx, expr.peel_borrows()) else {
             return;
         };
+        if self.allow_in_test && is_in_test(cx.tcx, expr.hir_id) {
+            return;
+        };
         // the parent callsite of this `vec!` expression, or span to the borrowed one such as `&vec!`
         let callsite = expr.span.parent_callsite().unwrap_or(expr.span);
 
diff --git a/src/tools/clippy/clippy_lints/src/vec_init_then_push.rs b/src/tools/clippy/clippy_lints/src/vec_init_then_push.rs
index c46f0298cc8..a599415a2dd 100644
--- a/src/tools/clippy/clippy_lints/src/vec_init_then_push.rs
+++ b/src/tools/clippy/clippy_lints/src/vec_init_then_push.rs
@@ -6,9 +6,7 @@ use clippy_utils::{get_parent_expr, path_to_local_id};
 use core::ops::ControlFlow;
 use rustc_errors::Applicability;
 use rustc_hir::def::Res;
-use rustc_hir::{
-    BindingMode, Block, Expr, ExprKind, HirId, LetStmt, Mutability, PatKind, QPath, Stmt, StmtKind, UnOp,
-};
+use rustc_hir::{BindingMode, Block, Expr, ExprKind, HirId, LetStmt, Mutability, PatKind, QPath, Stmt, StmtKind, UnOp};
 use rustc_lint::{LateContext, LateLintPass, LintContext};
 use rustc_middle::lint::in_external_macro;
 use rustc_session::impl_lint_pass;
diff --git a/src/tools/clippy/clippy_utils/Cargo.toml b/src/tools/clippy/clippy_utils/Cargo.toml
index d2bb719a517..ab883c25338 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.79"
+version = "0.1.80"
 edition = "2021"
 publish = false
 
diff --git a/src/tools/clippy/clippy_utils/src/lib.rs b/src/tools/clippy/clippy_utils/src/lib.rs
index 5e242aea354..a49414a058b 100644
--- a/src/tools/clippy/clippy_utils/src/lib.rs
+++ b/src/tools/clippy/clippy_utils/src/lib.rs
@@ -2328,10 +2328,10 @@ pub fn is_slice_of_primitives(cx: &LateContext<'_>, expr: &Expr<'_>) -> Option<S
 ///
 /// Given functions `eq` and `hash` such that `eq(a, b) == true`
 /// implies `hash(a) == hash(b)`
-pub fn search_same<T, Hash, Eq>(exprs: &[T], hash: Hash, eq: Eq) -> Vec<(&T, &T)>
+pub fn search_same<T, Hash, Eq>(exprs: &[T], mut hash: Hash, mut eq: Eq) -> Vec<(&T, &T)>
 where
-    Hash: Fn(&T) -> u64,
-    Eq: Fn(&T, &T) -> bool,
+    Hash: FnMut(&T) -> u64,
+    Eq: FnMut(&T, &T) -> bool,
 {
     match exprs {
         [a, b] if eq(a, b) => return vec![(a, b)],
@@ -2505,8 +2505,9 @@ fn with_test_item_names(tcx: TyCtxt<'_>, module: LocalModDefId, f: impl Fn(&[Sym
 /// Note: Add `//@compile-flags: --test` to UI tests with a `#[test]` function
 pub fn is_in_test_function(tcx: TyCtxt<'_>, id: HirId) -> bool {
     with_test_item_names(tcx, tcx.parent_module(id), |names| {
-        tcx.hir()
-            .parent_iter(id)
+        let node = tcx.hir_node(id);
+        once((id, node))
+            .chain(tcx.hir().parent_iter(id))
             // Since you can nest functions we need to collect all until we leave
             // function scope
             .any(|(_id, node)| {
@@ -2547,6 +2548,11 @@ pub fn is_in_cfg_test(tcx: TyCtxt<'_>, id: HirId) -> bool {
         .any(|parent_id| is_cfg_test(tcx, parent_id))
 }
 
+/// Checks if the node is in a `#[test]` function or has any parent node marked `#[cfg(test)]`
+pub fn is_in_test(tcx: TyCtxt<'_>, hir_id: HirId) -> bool {
+    is_in_test_function(tcx, hir_id) || is_in_cfg_test(tcx, hir_id)
+}
+
 /// Checks if the item of any of its parents has `#[cfg(...)]` attribute applied.
 pub fn inherits_cfg(tcx: TyCtxt<'_>, def_id: LocalDefId) -> bool {
     let hir = tcx.hir();
diff --git a/src/tools/clippy/clippy_utils/src/macros.rs b/src/tools/clippy/clippy_utils/src/macros.rs
index f166087dc3c..257dd76ab15 100644
--- a/src/tools/clippy/clippy_utils/src/macros.rs
+++ b/src/tools/clippy/clippy_utils/src/macros.rs
@@ -119,10 +119,20 @@ pub fn macro_backtrace(span: Span) -> impl Iterator<Item = MacroCall> {
 
 /// If the macro backtrace of `span` has a macro call at the root expansion
 /// (i.e. not a nested macro call), returns `Some` with the `MacroCall`
+///
+/// If you only want to check whether the root macro has a specific name,
+/// consider using [`matching_root_macro_call`] instead.
 pub fn root_macro_call(span: Span) -> Option<MacroCall> {
     macro_backtrace(span).last()
 }
 
+/// A combination of [`root_macro_call`] and
+/// [`is_diagnostic_item`](rustc_middle::ty::TyCtxt::is_diagnostic_item) that returns a `MacroCall`
+/// at the root expansion if only it matches the given name.
+pub fn matching_root_macro_call(cx: &LateContext<'_>, span: Span, name: Symbol) -> Option<MacroCall> {
+    root_macro_call(span).filter(|mc| cx.tcx.is_diagnostic_item(name, mc.def_id))
+}
+
 /// Like [`root_macro_call`], but only returns `Some` if `node` is the "first node"
 /// produced by the macro call, as in [`first_node_in_macro`].
 pub fn root_macro_call_first_node(cx: &LateContext<'_>, node: &impl HirNode) -> Option<MacroCall> {
diff --git a/src/tools/clippy/clippy_utils/src/paths.rs b/src/tools/clippy/clippy_utils/src/paths.rs
index 456b8019e95..9bf068ee3cd 100644
--- a/src/tools/clippy/clippy_utils/src/paths.rs
+++ b/src/tools/clippy/clippy_utils/src/paths.rs
@@ -19,8 +19,6 @@ pub const BTREESET_ITER: [&str; 6] = ["alloc", "collections", "btree", "set", "B
 pub const CLONE_TRAIT_METHOD: [&str; 4] = ["core", "clone", "Clone", "clone"];
 pub const CORE_ITER_CLONED: [&str; 6] = ["core", "iter", "traits", "iterator", "Iterator", "cloned"];
 pub const CORE_ITER_COPIED: [&str; 6] = ["core", "iter", "traits", "iterator", "Iterator", "copied"];
-pub const CORE_ITER_ENUMERATE_METHOD: [&str; 6] = ["core", "iter", "traits", "iterator", "Iterator", "enumerate"];
-pub const CORE_ITER_ENUMERATE_STRUCT: [&str; 5] = ["core", "iter", "adapters", "enumerate", "Enumerate"];
 pub const CORE_ITER_FILTER: [&str; 6] = ["core", "iter", "traits", "iterator", "Iterator", "filter"];
 pub const CORE_RESULT_OK_METHOD: [&str; 4] = ["core", "result", "Result", "ok"];
 pub const CSTRING_AS_C_STR: [&str; 5] = ["alloc", "ffi", "c_str", "CString", "as_c_str"];
@@ -73,7 +71,6 @@ pub const REGEX_NEW: [&str; 3] = ["regex", "Regex", "new"];
 pub const REGEX_SET_NEW: [&str; 3] = ["regex", "RegexSet", "new"];
 pub const SERDE_DESERIALIZE: [&str; 3] = ["serde", "de", "Deserialize"];
 pub const SERDE_DE_VISITOR: [&str; 3] = ["serde", "de", "Visitor"];
-pub const SLICE_GET: [&str; 4] = ["core", "slice", "<impl [T]>", "get"];
 pub const SLICE_INTO_VEC: [&str; 4] = ["alloc", "slice", "<impl [T]>", "into_vec"];
 pub const SLICE_INTO: [&str; 4] = ["core", "slice", "<impl [T]>", "iter"];
 pub const STD_IO_SEEK_FROM_CURRENT: [&str; 4] = ["std", "io", "SeekFrom", "Current"];
@@ -81,7 +78,6 @@ pub const STD_IO_SEEKFROM_START: [&str; 4] = ["std", "io", "SeekFrom", "Start"];
 pub const STRING_AS_MUT_STR: [&str; 4] = ["alloc", "string", "String", "as_mut_str"];
 pub const STRING_AS_STR: [&str; 4] = ["alloc", "string", "String", "as_str"];
 pub const STRING_NEW: [&str; 4] = ["alloc", "string", "String", "new"];
-pub const STR_BYTES: [&str; 4] = ["core", "str", "<impl str>", "bytes"];
 pub const STR_CHARS: [&str; 4] = ["core", "str", "<impl str>", "chars"];
 pub const STR_ENDS_WITH: [&str; 4] = ["core", "str", "<impl str>", "ends_with"];
 pub const STR_LEN: [&str; 4] = ["core", "str", "<impl str>", "len"];
@@ -108,7 +104,6 @@ pub const VEC_DEQUE_ITER: [&str; 5] = ["alloc", "collections", "vec_deque", "Vec
 pub const VEC_FROM_ELEM: [&str; 3] = ["alloc", "vec", "from_elem"];
 pub const VEC_NEW: [&str; 4] = ["alloc", "vec", "Vec", "new"];
 pub const VEC_WITH_CAPACITY: [&str; 4] = ["alloc", "vec", "Vec", "with_capacity"];
-pub const VEC_RESIZE: [&str; 4] = ["alloc", "vec", "Vec", "resize"];
 pub const INSTANT_NOW: [&str; 4] = ["std", "time", "Instant", "now"];
 pub const VEC_IS_EMPTY: [&str; 4] = ["alloc", "vec", "Vec", "is_empty"];
 pub const VEC_POP: [&str; 4] = ["alloc", "vec", "Vec", "pop"];
diff --git a/src/tools/clippy/clippy_utils/src/ty.rs b/src/tools/clippy/clippy_utils/src/ty.rs
index a06a82c5653..23750ed4d1b 100644
--- a/src/tools/clippy/clippy_utils/src/ty.rs
+++ b/src/tools/clippy/clippy_utils/src/ty.rs
@@ -29,9 +29,10 @@ use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt as _
 use rustc_trait_selection::traits::query::normalize::QueryNormalizeExt;
 use rustc_trait_selection::traits::{Obligation, ObligationCause};
 use std::assert_matches::debug_assert_matches;
+use std::collections::hash_map::Entry;
 use std::iter;
 
-use crate::{match_def_path, path_res};
+use crate::{def_path_def_ids, match_def_path, path_res};
 
 mod type_certainty;
 pub use type_certainty::expr_type_is_certain;
@@ -1198,47 +1199,88 @@ pub fn make_normalized_projection<'tcx>(
     helper(tcx, param_env, make_projection(tcx, container_id, assoc_ty, args)?)
 }
 
-/// Check if given type has inner mutability such as [`std::cell::Cell`] or [`std::cell::RefCell`]
-/// etc.
-pub fn is_interior_mut_ty<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool {
-    match *ty.kind() {
-        ty::Ref(_, inner_ty, mutbl) => mutbl == Mutability::Mut || is_interior_mut_ty(cx, inner_ty),
-        ty::Slice(inner_ty) => is_interior_mut_ty(cx, inner_ty),
-        ty::Array(inner_ty, size) => {
-            size.try_eval_target_usize(cx.tcx, cx.param_env)
-                .map_or(true, |u| u != 0)
-                && is_interior_mut_ty(cx, inner_ty)
-        },
-        ty::Tuple(fields) => fields.iter().any(|ty| is_interior_mut_ty(cx, ty)),
-        ty::Adt(def, args) => {
-            // Special case for collections in `std` who's impl of `Hash` or `Ord` delegates to
-            // that of their type parameters.  Note: we don't include `HashSet` and `HashMap`
-            // because they have no impl for `Hash` or `Ord`.
-            let def_id = def.did();
-            let is_std_collection = [
-                sym::Option,
-                sym::Result,
-                sym::LinkedList,
-                sym::Vec,
-                sym::VecDeque,
-                sym::BTreeMap,
-                sym::BTreeSet,
-                sym::Rc,
-                sym::Arc,
-            ]
+/// Helper to check if given type has inner mutability such as [`std::cell::Cell`] or
+/// [`std::cell::RefCell`].
+#[derive(Default, Debug)]
+pub struct InteriorMut<'tcx> {
+    ignored_def_ids: FxHashSet<DefId>,
+    ignore_pointers: bool,
+    tys: FxHashMap<Ty<'tcx>, Option<bool>>,
+}
+
+impl<'tcx> InteriorMut<'tcx> {
+    pub fn new(cx: &LateContext<'tcx>, ignore_interior_mutability: &[String]) -> Self {
+        let ignored_def_ids = ignore_interior_mutability
             .iter()
-            .any(|diag_item| cx.tcx.is_diagnostic_item(*diag_item, def_id));
-            let is_box = Some(def_id) == cx.tcx.lang_items().owned_box();
-            if is_std_collection || is_box {
-                // The type is mutable if any of its type parameters are
-                args.types().any(|ty| is_interior_mut_ty(cx, ty))
-            } else {
-                !ty.has_escaping_bound_vars()
-                    && cx.tcx.layout_of(cx.param_env.and(ty)).is_ok()
-                    && !ty.is_freeze(cx.tcx, cx.param_env)
-            }
-        },
-        _ => false,
+            .flat_map(|ignored_ty| {
+                let path: Vec<&str> = ignored_ty.split("::").collect();
+                def_path_def_ids(cx, path.as_slice())
+            })
+            .collect();
+
+        Self {
+            ignored_def_ids,
+            ..Self::default()
+        }
+    }
+
+    pub fn without_pointers(cx: &LateContext<'tcx>, ignore_interior_mutability: &[String]) -> Self {
+        Self {
+            ignore_pointers: true,
+            ..Self::new(cx, ignore_interior_mutability)
+        }
+    }
+
+    /// Check if given type has inner mutability such as [`std::cell::Cell`] or
+    /// [`std::cell::RefCell`] etc.
+    pub fn is_interior_mut_ty(&mut self, cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool {
+        match self.tys.entry(ty) {
+            Entry::Occupied(o) => return *o.get() == Some(true),
+            // Temporarily insert a `None` to break cycles
+            Entry::Vacant(v) => v.insert(None),
+        };
+
+        let interior_mut = match *ty.kind() {
+            ty::RawPtr(inner_ty, _) if !self.ignore_pointers => self.is_interior_mut_ty(cx, inner_ty),
+            ty::Ref(_, inner_ty, _) | ty::Slice(inner_ty) => self.is_interior_mut_ty(cx, inner_ty),
+            ty::Array(inner_ty, size) => {
+                size.try_eval_target_usize(cx.tcx, cx.param_env)
+                    .map_or(true, |u| u != 0)
+                    && self.is_interior_mut_ty(cx, inner_ty)
+            },
+            ty::Tuple(fields) => fields.iter().any(|ty| self.is_interior_mut_ty(cx, ty)),
+            ty::Adt(def, _) if def.is_unsafe_cell() => true,
+            ty::Adt(def, args) => {
+                let is_std_collection = matches!(
+                    cx.tcx.get_diagnostic_name(def.did()),
+                    Some(
+                        sym::LinkedList
+                            | sym::Vec
+                            | sym::VecDeque
+                            | sym::BTreeMap
+                            | sym::BTreeSet
+                            | sym::HashMap
+                            | sym::HashSet
+                            | sym::Arc
+                            | sym::Rc
+                    )
+                );
+
+                if is_std_collection || def.is_box() {
+                    // Include the types from std collections that are behind pointers internally
+                    args.types().any(|ty| self.is_interior_mut_ty(cx, ty))
+                } else if self.ignored_def_ids.contains(&def.did()) || def.is_phantom_data() {
+                    false
+                } else {
+                    def.all_fields()
+                        .any(|f| self.is_interior_mut_ty(cx, f.ty(cx.tcx, args)))
+                }
+            },
+            _ => false,
+        };
+
+        self.tys.insert(ty, Some(interior_mut));
+        interior_mut
     }
 }
 
diff --git a/src/tools/clippy/declare_clippy_lint/Cargo.toml b/src/tools/clippy/declare_clippy_lint/Cargo.toml
index 9a3a41e1d1e..c8c734c3a7c 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.79"
+version = "0.1.80"
 edition = "2021"
 publish = false
 
diff --git a/src/tools/clippy/rust-toolchain b/src/tools/clippy/rust-toolchain
index 521c0d12983..055f305eb8e 100644
--- a/src/tools/clippy/rust-toolchain
+++ b/src/tools/clippy/rust-toolchain
@@ -1,3 +1,3 @@
 [toolchain]
-channel = "nightly-2024-04-18"
+channel = "nightly-2024-05-02"
 components = ["cargo", "llvm-tools", "rust-src", "rust-std", "rustc", "rustc-dev", "rustfmt"]
diff --git a/src/tools/clippy/tests/compile-test.rs b/src/tools/clippy/tests/compile-test.rs
index 32a31f5e082..b06a11702ec 100644
--- a/src/tools/clippy/tests/compile-test.rs
+++ b/src/tools/clippy/tests/compile-test.rs
@@ -4,6 +4,7 @@
 #![warn(rust_2018_idioms, unused_lifetimes)]
 #![allow(unused_extern_crates)]
 
+use ui_test::custom_flags::rustfix::RustfixMode;
 use ui_test::spanned::Spanned;
 use ui_test::{status_emitter, Args, CommandBuilder, Config, Match, Mode, OutputConflictHandling};
 
@@ -122,10 +123,11 @@ fn base_config(test_dir: &str) -> (Config, Args) {
         out_dir: target_dir.join("ui_test"),
         ..Config::rustc(Path::new("tests").join(test_dir))
     };
-    config.comment_defaults.base().mode = Some(Spanned::dummy(Mode::Yolo {
-        rustfix: ui_test::RustfixMode::Everything,
-    }))
-    .into();
+    config.comment_defaults.base().mode = Some(Spanned::dummy(Mode::Yolo)).into();
+    config
+        .comment_defaults
+        .base()
+        .set_custom("rustfix", RustfixMode::Everything);
     config.comment_defaults.base().diagnostic_code_prefix = Some(Spanned::dummy("clippy::".into())).into();
     config.with_args(&args);
     let current_exe_path = env::current_exe().unwrap();
@@ -235,13 +237,12 @@ fn run_ui_cargo() {
         .push(("RUSTFLAGS".into(), Some("-Dwarnings".into())));
     // We need to do this while we still have a rustc in the `program` field.
     config.fill_host_and_target().unwrap();
-    config.dependencies_crate_manifest_path = None;
     config.program.program.set_file_name(if cfg!(windows) {
         "cargo-clippy.exe"
     } else {
         "cargo-clippy"
     });
-    config.comment_defaults.base().edition = Default::default();
+    config.comment_defaults.base().custom.clear();
 
     config
         .comment_defaults
diff --git a/src/tools/clippy/tests/ui-toml/mut_key/mut_key.rs b/src/tools/clippy/tests/ui-toml/mut_key/mut_key.rs
index 095e0d15448..3a8e3741e20 100644
--- a/src/tools/clippy/tests/ui-toml/mut_key/mut_key.rs
+++ b/src/tools/clippy/tests/ui-toml/mut_key/mut_key.rs
@@ -44,10 +44,18 @@ impl<T> Deref for Counted<T> {
     }
 }
 
+#[derive(Hash, PartialEq, Eq)]
+struct ContainsCounted {
+    inner: Counted<String>,
+}
+
 // This is not linted because `"mut_key::Counted"` is in
 // `arc_like_types` in `clippy.toml`
 fn should_not_take_this_arg(_v: HashSet<Counted<String>>) {}
 
+fn indirect(_: HashMap<ContainsCounted, usize>) {}
+
 fn main() {
     should_not_take_this_arg(HashSet::new());
+    indirect(HashMap::new());
 }
diff --git a/src/tools/clippy/tests/ui-toml/toml_unknown_key/conf_unknown_key.stderr b/src/tools/clippy/tests/ui-toml/toml_unknown_key/conf_unknown_key.stderr
index 24645b61fdb..722e9b3bc8d 100644
--- a/src/tools/clippy/tests/ui-toml/toml_unknown_key/conf_unknown_key.stderr
+++ b/src/tools/clippy/tests/ui-toml/toml_unknown_key/conf_unknown_key.stderr
@@ -11,6 +11,7 @@ error: error reading Clippy's configuration file: unknown field `foobar`, expect
            allow-print-in-tests
            allow-private-module-inception
            allow-unwrap-in-tests
+           allow-useless-vec-in-tests
            allowed-dotfiles
            allowed-duplicate-crates
            allowed-idents-below-min-chars
@@ -91,6 +92,7 @@ error: error reading Clippy's configuration file: unknown field `barfoo`, expect
            allow-print-in-tests
            allow-private-module-inception
            allow-unwrap-in-tests
+           allow-useless-vec-in-tests
            allowed-dotfiles
            allowed-duplicate-crates
            allowed-idents-below-min-chars
@@ -171,6 +173,7 @@ error: error reading Clippy's configuration file: unknown field `allow_mixed_uni
            allow-print-in-tests
            allow-private-module-inception
            allow-unwrap-in-tests
+           allow-useless-vec-in-tests
            allowed-dotfiles
            allowed-duplicate-crates
            allowed-idents-below-min-chars
diff --git a/src/tools/clippy/tests/ui-toml/useless_vec/clippy.toml b/src/tools/clippy/tests/ui-toml/useless_vec/clippy.toml
new file mode 100644
index 00000000000..230ca2d0ab7
--- /dev/null
+++ b/src/tools/clippy/tests/ui-toml/useless_vec/clippy.toml
@@ -0,0 +1 @@
+allow-useless-vec-in-tests = true
diff --git a/src/tools/clippy/tests/ui-toml/useless_vec/useless_vec.fixed b/src/tools/clippy/tests/ui-toml/useless_vec/useless_vec.fixed
new file mode 100644
index 00000000000..08323a0dcc9
--- /dev/null
+++ b/src/tools/clippy/tests/ui-toml/useless_vec/useless_vec.fixed
@@ -0,0 +1,26 @@
+//@compile-flags: --test
+#![warn(clippy::useless_vec)]
+#![allow(clippy::unnecessary_operation, clippy::no_effect)]
+
+fn foo(_: &[u32]) {}
+
+fn main() {
+    foo(&[1_u32]);
+}
+
+#[test]
+pub fn in_test() {
+    foo(&vec![2_u32]);
+}
+
+#[cfg(test)]
+fn in_cfg_test() {
+    foo(&vec![3_u32]);
+}
+
+#[cfg(test)]
+mod mod1 {
+    fn in_cfg_test_mod() {
+        super::foo(&vec![4_u32]);
+    }
+}
diff --git a/src/tools/clippy/tests/ui-toml/useless_vec/useless_vec.rs b/src/tools/clippy/tests/ui-toml/useless_vec/useless_vec.rs
new file mode 100644
index 00000000000..1f4b27c5342
--- /dev/null
+++ b/src/tools/clippy/tests/ui-toml/useless_vec/useless_vec.rs
@@ -0,0 +1,26 @@
+//@compile-flags: --test
+#![warn(clippy::useless_vec)]
+#![allow(clippy::unnecessary_operation, clippy::no_effect)]
+
+fn foo(_: &[u32]) {}
+
+fn main() {
+    foo(&vec![1_u32]);
+}
+
+#[test]
+pub fn in_test() {
+    foo(&vec![2_u32]);
+}
+
+#[cfg(test)]
+fn in_cfg_test() {
+    foo(&vec![3_u32]);
+}
+
+#[cfg(test)]
+mod mod1 {
+    fn in_cfg_test_mod() {
+        super::foo(&vec![4_u32]);
+    }
+}
diff --git a/src/tools/clippy/tests/ui-toml/useless_vec/useless_vec.stderr b/src/tools/clippy/tests/ui-toml/useless_vec/useless_vec.stderr
new file mode 100644
index 00000000000..633110c3c8d
--- /dev/null
+++ b/src/tools/clippy/tests/ui-toml/useless_vec/useless_vec.stderr
@@ -0,0 +1,11 @@
+error: useless use of `vec!`
+  --> tests/ui-toml/useless_vec/useless_vec.rs:8:9
+   |
+LL |     foo(&vec![1_u32]);
+   |         ^^^^^^^^^^^^ help: you can use a slice directly: `&[1_u32]`
+   |
+   = note: `-D clippy::useless-vec` implied by `-D warnings`
+   = help: to override `-D warnings` add `#[allow(clippy::useless_vec)]`
+
+error: aborting due to 1 previous error
+
diff --git a/src/tools/clippy/tests/ui/arithmetic_side_effects.rs b/src/tools/clippy/tests/ui/arithmetic_side_effects.rs
index fdec14a1528..66d71f337f2 100644
--- a/src/tools/clippy/tests/ui/arithmetic_side_effects.rs
+++ b/src/tools/clippy/tests/ui/arithmetic_side_effects.rs
@@ -521,4 +521,14 @@ pub fn issue_11393() {
     example_rem(x, maybe_zero);
 }
 
+pub fn issue_12318() {
+    use core::ops::{AddAssign, DivAssign, MulAssign, RemAssign, SubAssign};
+    let mut one: i32 = 1;
+    one.add_assign(1);
+    one.div_assign(1);
+    one.mul_assign(1);
+    one.rem_assign(1);
+    one.sub_assign(1);
+}
+
 fn main() {}
diff --git a/src/tools/clippy/tests/ui/arithmetic_side_effects.stderr b/src/tools/clippy/tests/ui/arithmetic_side_effects.stderr
index 741c892a52c..8039c0bfa24 100644
--- a/src/tools/clippy/tests/ui/arithmetic_side_effects.stderr
+++ b/src/tools/clippy/tests/ui/arithmetic_side_effects.stderr
@@ -715,5 +715,17 @@ error: arithmetic operation that can potentially result in unexpected side-effec
 LL |         x % maybe_zero
    |         ^^^^^^^^^^^^^^
 
-error: aborting due to 119 previous errors
+error: arithmetic operation that can potentially result in unexpected side-effects
+  --> tests/ui/arithmetic_side_effects.rs:527:5
+   |
+LL |     one.add_assign(1);
+   |     ^^^^^^^^^^^^^^^^^
+
+error: arithmetic operation that can potentially result in unexpected side-effects
+  --> tests/ui/arithmetic_side_effects.rs:531:5
+   |
+LL |     one.sub_assign(1);
+   |     ^^^^^^^^^^^^^^^^^
+
+error: aborting due to 121 previous errors
 
diff --git a/src/tools/clippy/tests/ui/auxiliary/proc_macros.rs b/src/tools/clippy/tests/ui/auxiliary/proc_macros.rs
index 3303eb14567..6e6919cd295 100644
--- a/src/tools/clippy/tests/ui/auxiliary/proc_macros.rs
+++ b/src/tools/clippy/tests/ui/auxiliary/proc_macros.rs
@@ -9,6 +9,7 @@ use proc_macro::token_stream::IntoIter;
 use proc_macro::Delimiter::{self, Brace, Parenthesis};
 use proc_macro::Spacing::{self, Alone, Joint};
 use proc_macro::{Group, Ident, Literal, Punct, Span, TokenStream, TokenTree as TT};
+use syn::spanned::Spanned;
 
 type Result<T> = core::result::Result<T, TokenStream>;
 
@@ -124,6 +125,22 @@ fn write_with_span(s: Span, mut input: IntoIter, out: &mut TokenStream) -> Resul
     Ok(())
 }
 
+/// Takes an array repeat expression such as `[0_u32; 2]`, and return the tokens with 10 times the
+/// original size, which turns to `[0_u32; 20]`.
+#[proc_macro]
+pub fn make_it_big(input: TokenStream) -> TokenStream {
+    let mut expr_repeat = syn::parse_macro_input!(input as syn::ExprRepeat);
+    let len_span = expr_repeat.len.span();
+    if let syn::Expr::Lit(expr_lit) = &mut *expr_repeat.len {
+        if let syn::Lit::Int(lit_int) = &expr_lit.lit {
+            let orig_val = lit_int.base10_parse::<usize>().expect("not a valid length parameter");
+            let new_val = orig_val.saturating_mul(10);
+            expr_lit.lit = syn::parse_quote_spanned!( len_span => #new_val);
+        }
+    }
+    quote::quote!(#expr_repeat).into()
+}
+
 /// Within the item this attribute is attached to, an `inline!` macro is available which expands the
 /// contained tokens as though they came from a macro expansion.
 ///
diff --git a/src/tools/clippy/tests/ui/borrow_interior_mutable_const/traits.rs b/src/tools/clippy/tests/ui/borrow_interior_mutable_const/traits.rs
index 4da3833cbf5..5570e7cd6d2 100644
--- a/src/tools/clippy/tests/ui/borrow_interior_mutable_const/traits.rs
+++ b/src/tools/clippy/tests/ui/borrow_interior_mutable_const/traits.rs
@@ -158,7 +158,7 @@ trait BothOfCellAndGeneric<T> {
     const INDIRECT: Cell<*const T>;
 
     fn function() {
-        let _ = &Self::DIRECT;
+        let _ = &Self::DIRECT; //~ ERROR: interior mutability
         let _ = &Self::INDIRECT; //~ ERROR: interior mutability
     }
 }
@@ -168,7 +168,7 @@ impl<T: ConstDefault> BothOfCellAndGeneric<T> for Vec<T> {
     const INDIRECT: Cell<*const T> = Cell::new(std::ptr::null());
 
     fn function() {
-        let _ = &Self::DIRECT;
+        let _ = &Self::DIRECT; //~ ERROR: interior mutability
         let _ = &Self::INDIRECT; //~ ERROR: interior mutability
     }
 }
diff --git a/src/tools/clippy/tests/ui/borrow_interior_mutable_const/traits.stderr b/src/tools/clippy/tests/ui/borrow_interior_mutable_const/traits.stderr
index 582b744b49f..8602b46b0dc 100644
--- a/src/tools/clippy/tests/ui/borrow_interior_mutable_const/traits.stderr
+++ b/src/tools/clippy/tests/ui/borrow_interior_mutable_const/traits.stderr
@@ -76,6 +76,14 @@ LL |         let _ = &Self::WRAPPED_SELF;
    = help: assign this const to a local or static variable, and use the variable here
 
 error: a `const` item with interior mutability should not be borrowed
+  --> tests/ui/borrow_interior_mutable_const/traits.rs:161:18
+   |
+LL |         let _ = &Self::DIRECT;
+   |                  ^^^^^^^^^^^^
+   |
+   = help: assign this const to a local or static variable, and use the variable here
+
+error: a `const` item with interior mutability should not be borrowed
   --> tests/ui/borrow_interior_mutable_const/traits.rs:162:18
    |
 LL |         let _ = &Self::INDIRECT;
@@ -84,6 +92,14 @@ LL |         let _ = &Self::INDIRECT;
    = help: assign this const to a local or static variable, and use the variable here
 
 error: a `const` item with interior mutability should not be borrowed
+  --> tests/ui/borrow_interior_mutable_const/traits.rs:171:18
+   |
+LL |         let _ = &Self::DIRECT;
+   |                  ^^^^^^^^^^^^
+   |
+   = help: assign this const to a local or static variable, and use the variable here
+
+error: a `const` item with interior mutability should not be borrowed
   --> tests/ui/borrow_interior_mutable_const/traits.rs:172:18
    |
 LL |         let _ = &Self::INDIRECT;
@@ -123,5 +139,5 @@ LL |     assert_eq!(u64::ATOMIC.load(Ordering::SeqCst), 9);
    |
    = help: assign this const to a local or static variable, and use the variable here
 
-error: aborting due to 15 previous errors
+error: aborting due to 17 previous errors
 
diff --git a/src/tools/clippy/tests/ui/box_default.fixed b/src/tools/clippy/tests/ui/box_default.fixed
index 6c2896b3aa0..1f2f57c2507 100644
--- a/src/tools/clippy/tests/ui/box_default.fixed
+++ b/src/tools/clippy/tests/ui/box_default.fixed
@@ -65,6 +65,8 @@ fn main() {
     // Would have a suggestion after https://github.com/rust-lang/rust/blob/fdd030127cc68afec44a8d3f6341525dd34e50ae/compiler/rustc_middle/src/ty/diagnostics.rs#L554-L563
     let mut unnameable = Box::new(Option::default());
     let _ = unnameable.insert(|| {});
+
+    let _ = Box::into_raw(Box::new(String::default()));
 }
 
 fn ret_ty_fn() -> Box<bool> {
@@ -75,6 +77,16 @@ fn call_ty_fn(_b: Box<u8>) {
     issue_9621_dyn_trait();
 }
 
+struct X<T>(T);
+
+impl<T: Default> X<T> {
+    fn x(_: Box<T>) {}
+
+    fn same_generic_param() {
+        Self::x(Box::default());
+    }
+}
+
 use std::io::{Read, Result};
 
 impl Read for ImplementsDefault {
diff --git a/src/tools/clippy/tests/ui/box_default.rs b/src/tools/clippy/tests/ui/box_default.rs
index e19a62a9022..addfebc24f5 100644
--- a/src/tools/clippy/tests/ui/box_default.rs
+++ b/src/tools/clippy/tests/ui/box_default.rs
@@ -65,6 +65,8 @@ fn main() {
     // Would have a suggestion after https://github.com/rust-lang/rust/blob/fdd030127cc68afec44a8d3f6341525dd34e50ae/compiler/rustc_middle/src/ty/diagnostics.rs#L554-L563
     let mut unnameable = Box::new(Option::default());
     let _ = unnameable.insert(|| {});
+
+    let _ = Box::into_raw(Box::new(String::default()));
 }
 
 fn ret_ty_fn() -> Box<bool> {
@@ -75,6 +77,16 @@ fn call_ty_fn(_b: Box<u8>) {
     issue_9621_dyn_trait();
 }
 
+struct X<T>(T);
+
+impl<T: Default> X<T> {
+    fn x(_: Box<T>) {}
+
+    fn same_generic_param() {
+        Self::x(Box::new(T::default()));
+    }
+}
+
 use std::io::{Read, Result};
 
 impl Read for ImplementsDefault {
diff --git a/src/tools/clippy/tests/ui/box_default.stderr b/src/tools/clippy/tests/ui/box_default.stderr
index f172a875dce..39fd0d29bbf 100644
--- a/src/tools/clippy/tests/ui/box_default.stderr
+++ b/src/tools/clippy/tests/ui/box_default.stderr
@@ -55,5 +55,11 @@ error: `Box::new(_)` of default value
 LL |     call_ty_fn(Box::new(u8::default()));
    |                ^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Box::default()`
 
-error: aborting due to 9 previous errors
+error: `Box::new(_)` of default value
+  --> tests/ui/box_default.rs:86:17
+   |
+LL |         Self::x(Box::new(T::default()));
+   |                 ^^^^^^^^^^^^^^^^^^^^^^ help: try: `Box::default()`
+
+error: aborting due to 10 previous errors
 
diff --git a/src/tools/clippy/tests/ui/cast.rs b/src/tools/clippy/tests/ui/cast.rs
index 215c008902d..453d62ce607 100644
--- a/src/tools/clippy/tests/ui/cast.rs
+++ b/src/tools/clippy/tests/ui/cast.rs
@@ -13,7 +13,8 @@
     clippy::cast_abs_to_unsigned,
     clippy::no_effect,
     clippy::unnecessary_operation,
-    clippy::unnecessary_literal_unwrap
+    clippy::unnecessary_literal_unwrap,
+    clippy::identity_op
 )]
 
 fn main() {
@@ -479,3 +480,21 @@ fn issue12506() -> usize {
     let bar: Result<Option<i64>, u32> = Ok(Some(10));
     bar.unwrap().unwrap() as usize
 }
+
+fn issue12721() {
+    fn x() -> u64 {
+        u64::MAX
+    }
+
+    // Don't lint.
+    (255 & 999999u64) as u8;
+    // Don't lint.
+    let _ = ((x() & 255) & 999999) as u8;
+    // Don't lint.
+    let _ = (999999 & (x() & 255)) as u8;
+
+    (256 & 999999u64) as u8;
+    //~^ ERROR: casting `u64` to `u8` may truncate the value
+    (255 % 999999u64) as u8;
+    //~^ ERROR: casting `u64` to `u8` may truncate the value
+}
diff --git a/src/tools/clippy/tests/ui/cast.stderr b/src/tools/clippy/tests/ui/cast.stderr
index 8b269c47176..43c0d8f4ed7 100644
--- a/src/tools/clippy/tests/ui/cast.stderr
+++ b/src/tools/clippy/tests/ui/cast.stderr
@@ -1,5 +1,5 @@
 error: casting `i32` to `f32` causes a loss of precision (`i32` is 32 bits wide, but `f32`'s mantissa is only 23 bits wide)
-  --> tests/ui/cast.rs:22:5
+  --> tests/ui/cast.rs:23:5
    |
 LL |     x0 as f32;
    |     ^^^^^^^^^
@@ -8,37 +8,37 @@ LL |     x0 as f32;
    = help: to override `-D warnings` add `#[allow(clippy::cast_precision_loss)]`
 
 error: casting `i64` to `f32` causes a loss of precision (`i64` is 64 bits wide, but `f32`'s mantissa is only 23 bits wide)
-  --> tests/ui/cast.rs:26:5
+  --> tests/ui/cast.rs:27:5
    |
 LL |     x1 as f32;
    |     ^^^^^^^^^
 
 error: casting `i64` to `f64` causes a loss of precision (`i64` is 64 bits wide, but `f64`'s mantissa is only 52 bits wide)
-  --> tests/ui/cast.rs:28:5
+  --> tests/ui/cast.rs:29:5
    |
 LL |     x1 as f64;
    |     ^^^^^^^^^
 
 error: casting `u32` to `f32` causes a loss of precision (`u32` is 32 bits wide, but `f32`'s mantissa is only 23 bits wide)
-  --> tests/ui/cast.rs:31:5
+  --> tests/ui/cast.rs:32:5
    |
 LL |     x2 as f32;
    |     ^^^^^^^^^
 
 error: casting `u64` to `f32` causes a loss of precision (`u64` is 64 bits wide, but `f32`'s mantissa is only 23 bits wide)
-  --> tests/ui/cast.rs:34:5
+  --> tests/ui/cast.rs:35:5
    |
 LL |     x3 as f32;
    |     ^^^^^^^^^
 
 error: casting `u64` to `f64` causes a loss of precision (`u64` is 64 bits wide, but `f64`'s mantissa is only 52 bits wide)
-  --> tests/ui/cast.rs:36:5
+  --> tests/ui/cast.rs:37:5
    |
 LL |     x3 as f64;
    |     ^^^^^^^^^
 
 error: casting `f32` to `i32` may truncate the value
-  --> tests/ui/cast.rs:39:5
+  --> tests/ui/cast.rs:40:5
    |
 LL |     1f32 as i32;
    |     ^^^^^^^^^^^
@@ -48,7 +48,7 @@ LL |     1f32 as i32;
    = help: to override `-D warnings` add `#[allow(clippy::cast_possible_truncation)]`
 
 error: casting `f32` to `u32` may truncate the value
-  --> tests/ui/cast.rs:41:5
+  --> tests/ui/cast.rs:42:5
    |
 LL |     1f32 as u32;
    |     ^^^^^^^^^^^
@@ -56,7 +56,7 @@ LL |     1f32 as u32;
    = help: if this is intentional allow the lint with `#[allow(clippy::cast_possible_truncation)]` ...
 
 error: casting `f32` to `u32` may lose the sign of the value
-  --> tests/ui/cast.rs:41:5
+  --> tests/ui/cast.rs:42:5
    |
 LL |     1f32 as u32;
    |     ^^^^^^^^^^^
@@ -65,7 +65,7 @@ LL |     1f32 as u32;
    = help: to override `-D warnings` add `#[allow(clippy::cast_sign_loss)]`
 
 error: casting `f64` to `f32` may truncate the value
-  --> tests/ui/cast.rs:45:5
+  --> tests/ui/cast.rs:46:5
    |
 LL |     1f64 as f32;
    |     ^^^^^^^^^^^
@@ -73,7 +73,7 @@ LL |     1f64 as f32;
    = help: if this is intentional allow the lint with `#[allow(clippy::cast_possible_truncation)]` ...
 
 error: casting `i32` to `i8` may truncate the value
-  --> tests/ui/cast.rs:47:5
+  --> tests/ui/cast.rs:48:5
    |
 LL |     1i32 as i8;
    |     ^^^^^^^^^^
@@ -85,7 +85,7 @@ LL |     i8::try_from(1i32);
    |     ~~~~~~~~~~~~~~~~~~
 
 error: casting `i32` to `u8` may truncate the value
-  --> tests/ui/cast.rs:49:5
+  --> tests/ui/cast.rs:50:5
    |
 LL |     1i32 as u8;
    |     ^^^^^^^^^^
@@ -97,7 +97,7 @@ LL |     u8::try_from(1i32);
    |     ~~~~~~~~~~~~~~~~~~
 
 error: casting `f64` to `isize` may truncate the value
-  --> tests/ui/cast.rs:51:5
+  --> tests/ui/cast.rs:52:5
    |
 LL |     1f64 as isize;
    |     ^^^^^^^^^^^^^
@@ -105,7 +105,7 @@ LL |     1f64 as isize;
    = help: if this is intentional allow the lint with `#[allow(clippy::cast_possible_truncation)]` ...
 
 error: casting `f64` to `usize` may truncate the value
-  --> tests/ui/cast.rs:53:5
+  --> tests/ui/cast.rs:54:5
    |
 LL |     1f64 as usize;
    |     ^^^^^^^^^^^^^
@@ -113,13 +113,13 @@ LL |     1f64 as usize;
    = help: if this is intentional allow the lint with `#[allow(clippy::cast_possible_truncation)]` ...
 
 error: casting `f64` to `usize` may lose the sign of the value
-  --> tests/ui/cast.rs:53:5
+  --> tests/ui/cast.rs:54:5
    |
 LL |     1f64 as usize;
    |     ^^^^^^^^^^^^^
 
 error: casting `u32` to `u16` may truncate the value
-  --> tests/ui/cast.rs:56:5
+  --> tests/ui/cast.rs:57:5
    |
 LL |     1f32 as u32 as u16;
    |     ^^^^^^^^^^^^^^^^^^
@@ -131,7 +131,7 @@ LL |     u16::try_from(1f32 as u32);
    |     ~~~~~~~~~~~~~~~~~~~~~~~~~~
 
 error: casting `f32` to `u32` may truncate the value
-  --> tests/ui/cast.rs:56:5
+  --> tests/ui/cast.rs:57:5
    |
 LL |     1f32 as u32 as u16;
    |     ^^^^^^^^^^^
@@ -139,13 +139,13 @@ LL |     1f32 as u32 as u16;
    = help: if this is intentional allow the lint with `#[allow(clippy::cast_possible_truncation)]` ...
 
 error: casting `f32` to `u32` may lose the sign of the value
-  --> tests/ui/cast.rs:56:5
+  --> tests/ui/cast.rs:57:5
    |
 LL |     1f32 as u32 as u16;
    |     ^^^^^^^^^^^
 
 error: casting `i32` to `i8` may truncate the value
-  --> tests/ui/cast.rs:61:22
+  --> tests/ui/cast.rs:62:22
    |
 LL |         let _x: i8 = 1i32 as _;
    |                      ^^^^^^^^^
@@ -157,7 +157,7 @@ LL |         let _x: i8 = 1i32.try_into();
    |                      ~~~~~~~~~~~~~~~
 
 error: casting `f32` to `i32` may truncate the value
-  --> tests/ui/cast.rs:63:9
+  --> tests/ui/cast.rs:64:9
    |
 LL |         1f32 as i32;
    |         ^^^^^^^^^^^
@@ -165,7 +165,7 @@ LL |         1f32 as i32;
    = help: if this is intentional allow the lint with `#[allow(clippy::cast_possible_truncation)]` ...
 
 error: casting `f64` to `i32` may truncate the value
-  --> tests/ui/cast.rs:65:9
+  --> tests/ui/cast.rs:66:9
    |
 LL |         1f64 as i32;
    |         ^^^^^^^^^^^
@@ -173,7 +173,7 @@ LL |         1f64 as i32;
    = help: if this is intentional allow the lint with `#[allow(clippy::cast_possible_truncation)]` ...
 
 error: casting `f32` to `u8` may truncate the value
-  --> tests/ui/cast.rs:67:9
+  --> tests/ui/cast.rs:68:9
    |
 LL |         1f32 as u8;
    |         ^^^^^^^^^^
@@ -181,13 +181,13 @@ LL |         1f32 as u8;
    = help: if this is intentional allow the lint with `#[allow(clippy::cast_possible_truncation)]` ...
 
 error: casting `f32` to `u8` may lose the sign of the value
-  --> tests/ui/cast.rs:67:9
+  --> tests/ui/cast.rs:68:9
    |
 LL |         1f32 as u8;
    |         ^^^^^^^^^^
 
 error: casting `u8` to `i8` may wrap around the value
-  --> tests/ui/cast.rs:72:5
+  --> tests/ui/cast.rs:73:5
    |
 LL |     1u8 as i8;
    |     ^^^^^^^^^
@@ -196,31 +196,31 @@ LL |     1u8 as i8;
    = help: to override `-D warnings` add `#[allow(clippy::cast_possible_wrap)]`
 
 error: casting `u16` to `i16` may wrap around the value
-  --> tests/ui/cast.rs:75:5
+  --> tests/ui/cast.rs:76:5
    |
 LL |     1u16 as i16;
    |     ^^^^^^^^^^^
 
 error: casting `u32` to `i32` may wrap around the value
-  --> tests/ui/cast.rs:77:5
+  --> tests/ui/cast.rs:78:5
    |
 LL |     1u32 as i32;
    |     ^^^^^^^^^^^
 
 error: casting `u64` to `i64` may wrap around the value
-  --> tests/ui/cast.rs:79:5
+  --> tests/ui/cast.rs:80:5
    |
 LL |     1u64 as i64;
    |     ^^^^^^^^^^^
 
 error: casting `usize` to `isize` may wrap around the value
-  --> tests/ui/cast.rs:81:5
+  --> tests/ui/cast.rs:82:5
    |
 LL |     1usize as isize;
    |     ^^^^^^^^^^^^^^^
 
 error: casting `usize` to `i8` may truncate the value
-  --> tests/ui/cast.rs:84:5
+  --> tests/ui/cast.rs:85:5
    |
 LL |     1usize as i8;
    |     ^^^^^^^^^^^^
@@ -232,7 +232,7 @@ LL |     i8::try_from(1usize);
    |     ~~~~~~~~~~~~~~~~~~~~
 
 error: casting `usize` to `i16` may truncate the value
-  --> tests/ui/cast.rs:87:5
+  --> tests/ui/cast.rs:88:5
    |
 LL |     1usize as i16;
    |     ^^^^^^^^^^^^^
@@ -244,7 +244,7 @@ LL |     i16::try_from(1usize);
    |     ~~~~~~~~~~~~~~~~~~~~~
 
 error: casting `usize` to `i16` may wrap around the value on targets with 16-bit wide pointers
-  --> tests/ui/cast.rs:87:5
+  --> tests/ui/cast.rs:88:5
    |
 LL |     1usize as i16;
    |     ^^^^^^^^^^^^^
@@ -253,7 +253,7 @@ LL |     1usize as i16;
    = note: for more information see https://doc.rust-lang.org/reference/types/numeric.html#machine-dependent-integer-types
 
 error: casting `usize` to `i32` may truncate the value on targets with 64-bit wide pointers
-  --> tests/ui/cast.rs:92:5
+  --> tests/ui/cast.rs:93:5
    |
 LL |     1usize as i32;
    |     ^^^^^^^^^^^^^
@@ -265,19 +265,19 @@ LL |     i32::try_from(1usize);
    |     ~~~~~~~~~~~~~~~~~~~~~
 
 error: casting `usize` to `i32` may wrap around the value on targets with 32-bit wide pointers
-  --> tests/ui/cast.rs:92:5
+  --> tests/ui/cast.rs:93:5
    |
 LL |     1usize as i32;
    |     ^^^^^^^^^^^^^
 
 error: casting `usize` to `i64` may wrap around the value on targets with 64-bit wide pointers
-  --> tests/ui/cast.rs:96:5
+  --> tests/ui/cast.rs:97:5
    |
 LL |     1usize as i64;
    |     ^^^^^^^^^^^^^
 
 error: casting `u16` to `isize` may wrap around the value on targets with 16-bit wide pointers
-  --> tests/ui/cast.rs:101:5
+  --> tests/ui/cast.rs:102:5
    |
 LL |     1u16 as isize;
    |     ^^^^^^^^^^^^^
@@ -286,13 +286,13 @@ LL |     1u16 as isize;
    = note: for more information see https://doc.rust-lang.org/reference/types/numeric.html#machine-dependent-integer-types
 
 error: casting `u32` to `isize` may wrap around the value on targets with 32-bit wide pointers
-  --> tests/ui/cast.rs:105:5
+  --> tests/ui/cast.rs:106:5
    |
 LL |     1u32 as isize;
    |     ^^^^^^^^^^^^^
 
 error: casting `u64` to `isize` may truncate the value on targets with 32-bit wide pointers
-  --> tests/ui/cast.rs:108:5
+  --> tests/ui/cast.rs:109:5
    |
 LL |     1u64 as isize;
    |     ^^^^^^^^^^^^^
@@ -304,55 +304,55 @@ LL |     isize::try_from(1u64);
    |     ~~~~~~~~~~~~~~~~~~~~~
 
 error: casting `u64` to `isize` may wrap around the value on targets with 64-bit wide pointers
-  --> tests/ui/cast.rs:108:5
+  --> tests/ui/cast.rs:109:5
    |
 LL |     1u64 as isize;
    |     ^^^^^^^^^^^^^
 
 error: casting `i32` to `u32` may lose the sign of the value
-  --> tests/ui/cast.rs:113:5
+  --> tests/ui/cast.rs:114:5
    |
 LL |     -1i32 as u32;
    |     ^^^^^^^^^^^^
 
 error: casting `isize` to `usize` may lose the sign of the value
-  --> tests/ui/cast.rs:116:5
+  --> tests/ui/cast.rs:117:5
    |
 LL |     -1isize as usize;
    |     ^^^^^^^^^^^^^^^^
 
 error: casting `i8` to `u8` may lose the sign of the value
-  --> tests/ui/cast.rs:127:5
+  --> tests/ui/cast.rs:128:5
    |
 LL |     (i8::MIN).abs() as u8;
    |     ^^^^^^^^^^^^^^^^^^^^^
 
 error: casting `i64` to `u64` may lose the sign of the value
-  --> tests/ui/cast.rs:131:5
+  --> tests/ui/cast.rs:132:5
    |
 LL |     (-1i64).abs() as u64;
    |     ^^^^^^^^^^^^^^^^^^^^
 
 error: casting `isize` to `usize` may lose the sign of the value
-  --> tests/ui/cast.rs:132:5
+  --> tests/ui/cast.rs:133:5
    |
 LL |     (-1isize).abs() as usize;
    |     ^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: casting `i64` to `u64` may lose the sign of the value
-  --> tests/ui/cast.rs:139:5
+  --> tests/ui/cast.rs:140:5
    |
 LL |     (unsafe { (-1i64).checked_abs().unwrap_unchecked() }) as u64;
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: casting `i64` to `u64` may lose the sign of the value
-  --> tests/ui/cast.rs:154:5
+  --> tests/ui/cast.rs:155:5
    |
 LL |     (unsafe { (-1i64).checked_isqrt().unwrap_unchecked() }) as u64;
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: casting `i64` to `i8` may truncate the value
-  --> tests/ui/cast.rs:205:5
+  --> tests/ui/cast.rs:206:5
    |
 LL |     (-99999999999i64).min(1) as i8;
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -364,7 +364,7 @@ LL |     i8::try_from((-99999999999i64).min(1));
    |     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
 error: casting `u64` to `u8` may truncate the value
-  --> tests/ui/cast.rs:219:5
+  --> tests/ui/cast.rs:220:5
    |
 LL |     999999u64.clamp(0, 256) as u8;
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -376,7 +376,7 @@ LL |     u8::try_from(999999u64.clamp(0, 256));
    |     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
 error: casting `main::E2` to `u8` may truncate the value
-  --> tests/ui/cast.rs:242:21
+  --> tests/ui/cast.rs:243:21
    |
 LL |             let _ = self as u8;
    |                     ^^^^^^^^^^
@@ -388,7 +388,7 @@ LL |             let _ = u8::try_from(self);
    |                     ~~~~~~~~~~~~~~~~~~
 
 error: casting `main::E2::B` to `u8` will truncate the value
-  --> tests/ui/cast.rs:244:21
+  --> tests/ui/cast.rs:245:21
    |
 LL |             let _ = Self::B as u8;
    |                     ^^^^^^^^^^^^^
@@ -397,7 +397,7 @@ LL |             let _ = Self::B as u8;
    = help: to override `-D warnings` add `#[allow(clippy::cast_enum_truncation)]`
 
 error: casting `main::E5` to `i8` may truncate the value
-  --> tests/ui/cast.rs:286:21
+  --> tests/ui/cast.rs:287:21
    |
 LL |             let _ = self as i8;
    |                     ^^^^^^^^^^
@@ -409,13 +409,13 @@ LL |             let _ = i8::try_from(self);
    |                     ~~~~~~~~~~~~~~~~~~
 
 error: casting `main::E5::A` to `i8` will truncate the value
-  --> tests/ui/cast.rs:288:21
+  --> tests/ui/cast.rs:289:21
    |
 LL |             let _ = Self::A as i8;
    |                     ^^^^^^^^^^^^^
 
 error: casting `main::E6` to `i16` may truncate the value
-  --> tests/ui/cast.rs:305:21
+  --> tests/ui/cast.rs:306:21
    |
 LL |             let _ = self as i16;
    |                     ^^^^^^^^^^^
@@ -427,7 +427,7 @@ LL |             let _ = i16::try_from(self);
    |                     ~~~~~~~~~~~~~~~~~~~
 
 error: casting `main::E7` to `usize` may truncate the value on targets with 32-bit wide pointers
-  --> tests/ui/cast.rs:324:21
+  --> tests/ui/cast.rs:325:21
    |
 LL |             let _ = self as usize;
    |                     ^^^^^^^^^^^^^
@@ -439,7 +439,7 @@ LL |             let _ = usize::try_from(self);
    |                     ~~~~~~~~~~~~~~~~~~~~~
 
 error: casting `main::E10` to `u16` may truncate the value
-  --> tests/ui/cast.rs:371:21
+  --> tests/ui/cast.rs:372:21
    |
 LL |             let _ = self as u16;
    |                     ^^^^^^^^^^^
@@ -451,7 +451,7 @@ LL |             let _ = u16::try_from(self);
    |                     ~~~~~~~~~~~~~~~~~~~
 
 error: casting `u32` to `u8` may truncate the value
-  --> tests/ui/cast.rs:382:13
+  --> tests/ui/cast.rs:383:13
    |
 LL |     let c = (q >> 16) as u8;
    |             ^^^^^^^^^^^^^^^
@@ -463,7 +463,7 @@ LL |     let c = u8::try_from(q >> 16);
    |             ~~~~~~~~~~~~~~~~~~~~~
 
 error: casting `u32` to `u8` may truncate the value
-  --> tests/ui/cast.rs:386:13
+  --> tests/ui/cast.rs:387:13
    |
 LL |     let c = (q / 1000) as u8;
    |             ^^^^^^^^^^^^^^^^
@@ -475,85 +475,85 @@ LL |     let c = u8::try_from(q / 1000);
    |             ~~~~~~~~~~~~~~~~~~~~~~
 
 error: casting `i32` to `u32` may lose the sign of the value
-  --> tests/ui/cast.rs:398:9
+  --> tests/ui/cast.rs:399:9
    |
 LL |         (x * x) as u32;
    |         ^^^^^^^^^^^^^^
 
 error: casting `i32` to `u32` may lose the sign of the value
-  --> tests/ui/cast.rs:403:32
+  --> tests/ui/cast.rs:404:32
    |
 LL |     let _a = |x: i32| -> u32 { (x * x * x * x) as u32 };
    |                                ^^^^^^^^^^^^^^^^^^^^^^
 
 error: casting `i32` to `u32` may lose the sign of the value
-  --> tests/ui/cast.rs:405:5
+  --> tests/ui/cast.rs:406:5
    |
 LL |     (2_i32).checked_pow(3).unwrap() as u32;
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: casting `i32` to `u32` may lose the sign of the value
-  --> tests/ui/cast.rs:406:5
+  --> tests/ui/cast.rs:407:5
    |
 LL |     (-2_i32).pow(3) as u32;
    |     ^^^^^^^^^^^^^^^^^^^^^^
 
 error: casting `i32` to `u32` may lose the sign of the value
-  --> tests/ui/cast.rs:411:5
+  --> tests/ui/cast.rs:412:5
    |
 LL |     (-5_i32 % 2) as u32;
    |     ^^^^^^^^^^^^^^^^^^^
 
 error: casting `i32` to `u32` may lose the sign of the value
-  --> tests/ui/cast.rs:413:5
+  --> tests/ui/cast.rs:414:5
    |
 LL |     (-5_i32 % -2) as u32;
    |     ^^^^^^^^^^^^^^^^^^^^
 
 error: casting `i32` to `u32` may lose the sign of the value
-  --> tests/ui/cast.rs:416:5
+  --> tests/ui/cast.rs:417:5
    |
 LL |     (-2_i32 >> 1) as u32;
    |     ^^^^^^^^^^^^^^^^^^^^
 
 error: casting `i32` to `u32` may lose the sign of the value
-  --> tests/ui/cast.rs:420:5
+  --> tests/ui/cast.rs:421:5
    |
 LL |     (x * x) as u32;
    |     ^^^^^^^^^^^^^^
 
 error: casting `i32` to `u32` may lose the sign of the value
-  --> tests/ui/cast.rs:421:5
+  --> tests/ui/cast.rs:422:5
    |
 LL |     (x * x * x) as u32;
    |     ^^^^^^^^^^^^^^^^^^
 
 error: casting `i16` to `u16` may lose the sign of the value
-  --> tests/ui/cast.rs:425:5
+  --> tests/ui/cast.rs:426:5
    |
 LL |     (y * y * y * y * -2) as u16;
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: casting `i16` to `u16` may lose the sign of the value
-  --> tests/ui/cast.rs:427:5
+  --> tests/ui/cast.rs:428:5
    |
 LL |     (y * y * y / y * 2) as u16;
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: casting `i16` to `u16` may lose the sign of the value
-  --> tests/ui/cast.rs:428:5
+  --> tests/ui/cast.rs:429:5
    |
 LL |     (y * y / y * 2) as u16;
    |     ^^^^^^^^^^^^^^^^^^^^^^
 
 error: casting `i16` to `u16` may lose the sign of the value
-  --> tests/ui/cast.rs:430:5
+  --> tests/ui/cast.rs:431:5
    |
 LL |     (y / y * y * -2) as u16;
    |     ^^^^^^^^^^^^^^^^^^^^^^^
 
 error: equal expressions as operands to `/`
-  --> tests/ui/cast.rs:430:6
+  --> tests/ui/cast.rs:431:6
    |
 LL |     (y / y * y * -2) as u16;
    |      ^^^^^
@@ -561,97 +561,97 @@ LL |     (y / y * y * -2) as u16;
    = note: `#[deny(clippy::eq_op)]` on by default
 
 error: casting `i16` to `u16` may lose the sign of the value
-  --> tests/ui/cast.rs:433:5
+  --> tests/ui/cast.rs:434:5
    |
 LL |     (y + y + y + -2) as u16;
    |     ^^^^^^^^^^^^^^^^^^^^^^^
 
 error: casting `i16` to `u16` may lose the sign of the value
-  --> tests/ui/cast.rs:435:5
+  --> tests/ui/cast.rs:436:5
    |
 LL |     (y + y + y + 2) as u16;
    |     ^^^^^^^^^^^^^^^^^^^^^^
 
 error: casting `i16` to `u16` may lose the sign of the value
-  --> tests/ui/cast.rs:439:5
+  --> tests/ui/cast.rs:440:5
    |
 LL |     (z + -2) as u16;
    |     ^^^^^^^^^^^^^^^
 
 error: casting `i16` to `u16` may lose the sign of the value
-  --> tests/ui/cast.rs:441:5
+  --> tests/ui/cast.rs:442:5
    |
 LL |     (z + z + 2) as u16;
    |     ^^^^^^^^^^^^^^^^^^
 
 error: casting `i32` to `u32` may lose the sign of the value
-  --> tests/ui/cast.rs:444:9
+  --> tests/ui/cast.rs:445:9
    |
 LL |         (a * a * b * b * c * c) as u32;
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: casting `i32` to `u32` may lose the sign of the value
-  --> tests/ui/cast.rs:445:9
+  --> tests/ui/cast.rs:446:9
    |
 LL |         (a * b * c) as u32;
    |         ^^^^^^^^^^^^^^^^^^
 
 error: casting `i32` to `u32` may lose the sign of the value
-  --> tests/ui/cast.rs:447:9
+  --> tests/ui/cast.rs:448:9
    |
 LL |         (a * -b * c) as u32;
    |         ^^^^^^^^^^^^^^^^^^^
 
 error: casting `i32` to `u32` may lose the sign of the value
-  --> tests/ui/cast.rs:449:9
+  --> tests/ui/cast.rs:450:9
    |
 LL |         (a * b * c * c) as u32;
    |         ^^^^^^^^^^^^^^^^^^^^^^
 
 error: casting `i32` to `u32` may lose the sign of the value
-  --> tests/ui/cast.rs:450:9
+  --> tests/ui/cast.rs:451:9
    |
 LL |         (a * -2) as u32;
    |         ^^^^^^^^^^^^^^^
 
 error: casting `i32` to `u32` may lose the sign of the value
-  --> tests/ui/cast.rs:452:9
+  --> tests/ui/cast.rs:453:9
    |
 LL |         (a * b * c * -2) as u32;
    |         ^^^^^^^^^^^^^^^^^^^^^^^
 
 error: casting `i32` to `u32` may lose the sign of the value
-  --> tests/ui/cast.rs:454:9
+  --> tests/ui/cast.rs:455:9
    |
 LL |         (a / b) as u32;
    |         ^^^^^^^^^^^^^^
 
 error: casting `i32` to `u32` may lose the sign of the value
-  --> tests/ui/cast.rs:455:9
+  --> tests/ui/cast.rs:456:9
    |
 LL |         (a / b * c) as u32;
    |         ^^^^^^^^^^^^^^^^^^
 
 error: casting `i32` to `u32` may lose the sign of the value
-  --> tests/ui/cast.rs:457:9
+  --> tests/ui/cast.rs:458:9
    |
 LL |         (a / b + b * c) as u32;
    |         ^^^^^^^^^^^^^^^^^^^^^^
 
 error: casting `i32` to `u32` may lose the sign of the value
-  --> tests/ui/cast.rs:459:9
+  --> tests/ui/cast.rs:460:9
    |
 LL |         a.saturating_pow(3) as u32;
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: casting `i32` to `u32` may lose the sign of the value
-  --> tests/ui/cast.rs:461:9
+  --> tests/ui/cast.rs:462:9
    |
 LL |         (a.abs() * b.pow(2) / c.abs()) as u32
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: casting `i32` to `u32` may lose the sign of the value
-  --> tests/ui/cast.rs:469:21
+  --> tests/ui/cast.rs:470:21
    |
 LL |             let _ = i32::MIN as u32; // cast_sign_loss
    |                     ^^^^^^^^^^^^^^^
@@ -662,7 +662,7 @@ LL |     m!();
    = note: this error originates in the macro `m` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error: casting `u32` to `u8` may truncate the value
-  --> tests/ui/cast.rs:470:21
+  --> tests/ui/cast.rs:471:21
    |
 LL |             let _ = u32::MAX as u8; // cast_possible_truncation
    |                     ^^^^^^^^^^^^^^
@@ -678,7 +678,7 @@ LL |             let _ = u8::try_from(u32::MAX); // cast_possible_truncation
    |                     ~~~~~~~~~~~~~~~~~~~~~~
 
 error: casting `f64` to `f32` may truncate the value
-  --> tests/ui/cast.rs:471:21
+  --> tests/ui/cast.rs:472:21
    |
 LL |             let _ = std::f64::consts::PI as f32; // cast_possible_truncation
    |                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -690,7 +690,7 @@ LL |     m!();
    = note: this error originates in the macro `m` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error: casting `i64` to `usize` may truncate the value on targets with 32-bit wide pointers
-  --> tests/ui/cast.rs:480:5
+  --> tests/ui/cast.rs:481:5
    |
 LL |     bar.unwrap().unwrap() as usize
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -702,10 +702,34 @@ LL |     usize::try_from(bar.unwrap().unwrap())
    |
 
 error: casting `i64` to `usize` may lose the sign of the value
-  --> tests/ui/cast.rs:480:5
+  --> tests/ui/cast.rs:481:5
    |
 LL |     bar.unwrap().unwrap() as usize
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
-error: aborting due to 90 previous errors
+error: casting `u64` to `u8` may truncate the value
+  --> tests/ui/cast.rs:496:5
+   |
+LL |     (256 & 999999u64) as u8;
+   |     ^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = help: if this is intentional allow the lint with `#[allow(clippy::cast_possible_truncation)]` ...
+help: ... or use `try_from` and handle the error accordingly
+   |
+LL |     u8::try_from(256 & 999999u64);
+   |     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+error: casting `u64` to `u8` may truncate the value
+  --> tests/ui/cast.rs:498:5
+   |
+LL |     (255 % 999999u64) as u8;
+   |     ^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = help: if this is intentional allow the lint with `#[allow(clippy::cast_possible_truncation)]` ...
+help: ... or use `try_from` and handle the error accordingly
+   |
+LL |     u8::try_from(255 % 999999u64);
+   |     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+error: aborting due to 92 previous errors
 
diff --git a/src/tools/clippy/tests/ui/collapsible_match.rs b/src/tools/clippy/tests/ui/collapsible_match.rs
index 7501fd2b0bd..2264b560791 100644
--- a/src/tools/clippy/tests/ui/collapsible_match.rs
+++ b/src/tools/clippy/tests/ui/collapsible_match.rs
@@ -4,7 +4,8 @@
     clippy::needless_return,
     clippy::no_effect,
     clippy::single_match,
-    clippy::uninlined_format_args
+    clippy::uninlined_format_args,
+    clippy::let_unit_value
 )]
 
 fn lint_cases(opt_opt: Option<Option<u32>>, res_opt: Result<Option<u32>, String>) {
@@ -238,13 +239,22 @@ fn negative_cases(res_opt: Result<Option<u32>, String>, res_res: Result<Result<u
         },
         _ => return,
     }
-    match make::<Option<E<u32>>>() {
+    #[clippy::msrv = "1.52.0"]
+    let _ = match make::<Option<E<u32>>>() {
         Some(val) => match val {
             E::A(val) | E::B(val) => foo(val),
             _ => return,
         },
         _ => return,
-    }
+    };
+    #[clippy::msrv = "1.53.0"]
+    let _ = match make::<Option<E<u32>>>() {
+        Some(val) => match val {
+            E::A(val) | E::B(val) => foo(val),
+            _ => return,
+        },
+        _ => return,
+    };
     if let Ok(val) = res_opt {
         if let Some(n) = val {
             let _ = || {
diff --git a/src/tools/clippy/tests/ui/collapsible_match.stderr b/src/tools/clippy/tests/ui/collapsible_match.stderr
index 46b484ab05c..01944baee79 100644
--- a/src/tools/clippy/tests/ui/collapsible_match.stderr
+++ b/src/tools/clippy/tests/ui/collapsible_match.stderr
@@ -1,5 +1,5 @@
 error: this `match` can be collapsed into the outer `match`
-  --> tests/ui/collapsible_match.rs:13:20
+  --> tests/ui/collapsible_match.rs:14:20
    |
 LL |           Ok(val) => match val {
    |  ____________________^
@@ -10,7 +10,7 @@ LL | |         },
    | |_________^
    |
 help: the outer pattern can be modified to include the inner pattern
-  --> tests/ui/collapsible_match.rs:13:12
+  --> tests/ui/collapsible_match.rs:14:12
    |
 LL |         Ok(val) => match val {
    |            ^^^ replace this binding
@@ -21,7 +21,7 @@ LL |             Some(n) => foo(n),
    = help: to override `-D warnings` add `#[allow(clippy::collapsible_match)]`
 
 error: this `match` can be collapsed into the outer `match`
-  --> tests/ui/collapsible_match.rs:23:20
+  --> tests/ui/collapsible_match.rs:24:20
    |
 LL |           Ok(val) => match val {
    |  ____________________^
@@ -32,7 +32,7 @@ LL | |         },
    | |_________^
    |
 help: the outer pattern can be modified to include the inner pattern
-  --> tests/ui/collapsible_match.rs:23:12
+  --> tests/ui/collapsible_match.rs:24:12
    |
 LL |         Ok(val) => match val {
    |            ^^^ replace this binding
@@ -41,7 +41,7 @@ LL |             Some(n) => foo(n),
    |             ^^^^^^^ with this pattern
 
 error: this `if let` can be collapsed into the outer `if let`
-  --> tests/ui/collapsible_match.rs:33:9
+  --> tests/ui/collapsible_match.rs:34:9
    |
 LL | /         if let Some(n) = val {
 LL | |
@@ -50,7 +50,7 @@ LL | |         }
    | |_________^
    |
 help: the outer pattern can be modified to include the inner pattern
-  --> tests/ui/collapsible_match.rs:32:15
+  --> tests/ui/collapsible_match.rs:33:15
    |
 LL |     if let Ok(val) = res_opt {
    |               ^^^ replace this binding
@@ -58,7 +58,7 @@ LL |         if let Some(n) = val {
    |                ^^^^^^^ with this pattern
 
 error: this `if let` can be collapsed into the outer `if let`
-  --> tests/ui/collapsible_match.rs:41:9
+  --> tests/ui/collapsible_match.rs:42:9
    |
 LL | /         if let Some(n) = val {
 LL | |
@@ -69,7 +69,7 @@ LL | |         }
    | |_________^
    |
 help: the outer pattern can be modified to include the inner pattern
-  --> tests/ui/collapsible_match.rs:40:15
+  --> tests/ui/collapsible_match.rs:41:15
    |
 LL |     if let Ok(val) = res_opt {
    |               ^^^ replace this binding
@@ -77,7 +77,7 @@ LL |         if let Some(n) = val {
    |                ^^^^^^^ with this pattern
 
 error: this `match` can be collapsed into the outer `if let`
-  --> tests/ui/collapsible_match.rs:53:9
+  --> tests/ui/collapsible_match.rs:54:9
    |
 LL | /         match val {
 LL | |
@@ -87,7 +87,7 @@ LL | |         }
    | |_________^
    |
 help: the outer pattern can be modified to include the inner pattern
-  --> tests/ui/collapsible_match.rs:52:15
+  --> tests/ui/collapsible_match.rs:53:15
    |
 LL |     if let Ok(val) = res_opt {
    |               ^^^ replace this binding
@@ -96,7 +96,7 @@ LL |             Some(n) => foo(n),
    |             ^^^^^^^ with this pattern
 
 error: this `if let` can be collapsed into the outer `match`
-  --> tests/ui/collapsible_match.rs:63:13
+  --> tests/ui/collapsible_match.rs:64:13
    |
 LL | /             if let Some(n) = val {
 LL | |
@@ -105,7 +105,7 @@ LL | |             }
    | |_____________^
    |
 help: the outer pattern can be modified to include the inner pattern
-  --> tests/ui/collapsible_match.rs:62:12
+  --> tests/ui/collapsible_match.rs:63:12
    |
 LL |         Ok(val) => {
    |            ^^^ replace this binding
@@ -113,7 +113,7 @@ LL |             if let Some(n) = val {
    |                    ^^^^^^^ with this pattern
 
 error: this `match` can be collapsed into the outer `if let`
-  --> tests/ui/collapsible_match.rs:73:9
+  --> tests/ui/collapsible_match.rs:74:9
    |
 LL | /         match val {
 LL | |
@@ -123,7 +123,7 @@ LL | |         }
    | |_________^
    |
 help: the outer pattern can be modified to include the inner pattern
-  --> tests/ui/collapsible_match.rs:72:15
+  --> tests/ui/collapsible_match.rs:73:15
    |
 LL |     if let Ok(val) = res_opt {
    |               ^^^ replace this binding
@@ -132,7 +132,7 @@ LL |             Some(n) => foo(n),
    |             ^^^^^^^ with this pattern
 
 error: this `if let` can be collapsed into the outer `match`
-  --> tests/ui/collapsible_match.rs:85:13
+  --> tests/ui/collapsible_match.rs:86:13
    |
 LL | /             if let Some(n) = val {
 LL | |
@@ -143,7 +143,7 @@ LL | |             }
    | |_____________^
    |
 help: the outer pattern can be modified to include the inner pattern
-  --> tests/ui/collapsible_match.rs:84:12
+  --> tests/ui/collapsible_match.rs:85:12
    |
 LL |         Ok(val) => {
    |            ^^^ replace this binding
@@ -151,7 +151,7 @@ LL |             if let Some(n) = val {
    |                    ^^^^^^^ with this pattern
 
 error: this `match` can be collapsed into the outer `match`
-  --> tests/ui/collapsible_match.rs:97:20
+  --> tests/ui/collapsible_match.rs:98:20
    |
 LL |           Ok(val) => match val {
    |  ____________________^
@@ -162,7 +162,7 @@ LL | |         },
    | |_________^
    |
 help: the outer pattern can be modified to include the inner pattern
-  --> tests/ui/collapsible_match.rs:97:12
+  --> tests/ui/collapsible_match.rs:98:12
    |
 LL |         Ok(val) => match val {
    |            ^^^ replace this binding
@@ -171,7 +171,7 @@ LL |             Some(n) => foo(n),
    |             ^^^^^^^ with this pattern
 
 error: this `match` can be collapsed into the outer `match`
-  --> tests/ui/collapsible_match.rs:107:22
+  --> tests/ui/collapsible_match.rs:108:22
    |
 LL |           Some(val) => match val {
    |  ______________________^
@@ -182,7 +182,7 @@ LL | |         },
    | |_________^
    |
 help: the outer pattern can be modified to include the inner pattern
-  --> tests/ui/collapsible_match.rs:107:14
+  --> tests/ui/collapsible_match.rs:108:14
    |
 LL |         Some(val) => match val {
    |              ^^^ replace this binding
@@ -190,8 +190,26 @@ LL |
 LL |             Some(n) => foo(n),
    |             ^^^^^^^ with this pattern
 
+error: this `match` can be collapsed into the outer `match`
+  --> tests/ui/collapsible_match.rs:252:22
+   |
+LL |           Some(val) => match val {
+   |  ______________________^
+LL | |             E::A(val) | E::B(val) => foo(val),
+LL | |             _ => return,
+LL | |         },
+   | |_________^
+   |
+help: the outer pattern can be modified to include the inner pattern
+  --> tests/ui/collapsible_match.rs:252:14
+   |
+LL |         Some(val) => match val {
+   |              ^^^ replace this binding
+LL |             E::A(val) | E::B(val) => foo(val),
+   |             ^^^^^^^^^^^^^^^^^^^^^ with this pattern
+
 error: this `if let` can be collapsed into the outer `if let`
-  --> tests/ui/collapsible_match.rs:273:9
+  --> tests/ui/collapsible_match.rs:283:9
    |
 LL | /         if let Some(u) = a {
 LL | |
@@ -200,7 +218,7 @@ LL | |         }
    | |_________^
    |
 help: the outer pattern can be modified to include the inner pattern
-  --> tests/ui/collapsible_match.rs:272:27
+  --> tests/ui/collapsible_match.rs:282:27
    |
 LL |     if let Issue9647::A { a, .. } = x {
    |                           ^ replace this binding
@@ -208,7 +226,7 @@ LL |         if let Some(u) = a {
    |                ^^^^^^^ with this pattern, prefixed by a:
 
 error: this `if let` can be collapsed into the outer `if let`
-  --> tests/ui/collapsible_match.rs:282:9
+  --> tests/ui/collapsible_match.rs:292:9
    |
 LL | /         if let Some(u) = a {
 LL | |
@@ -217,12 +235,12 @@ LL | |         }
    | |_________^
    |
 help: the outer pattern can be modified to include the inner pattern
-  --> tests/ui/collapsible_match.rs:281:35
+  --> tests/ui/collapsible_match.rs:291:35
    |
 LL |     if let Issue9647::A { a: Some(a), .. } = x {
    |                                   ^ replace this binding
 LL |         if let Some(u) = a {
    |                ^^^^^^^ with this pattern
 
-error: aborting due to 12 previous errors
+error: aborting due to 13 previous errors
 
diff --git a/src/tools/clippy/tests/ui/collection_is_never_read.rs b/src/tools/clippy/tests/ui/collection_is_never_read.rs
index bd281f7870c..eeb10da3402 100644
--- a/src/tools/clippy/tests/ui/collection_is_never_read.rs
+++ b/src/tools/clippy/tests/ui/collection_is_never_read.rs
@@ -222,3 +222,17 @@ fn supported_types() {
     //~^ ERROR: collection is never read
     x.push_front(1);
 }
+
+fn issue11783() {
+    struct Sender;
+    impl Sender {
+        fn send(&self, msg: String) -> Result<(), ()> {
+            // pretend to send message
+            println!("{msg}");
+            Ok(())
+        }
+    }
+
+    let mut users: Vec<Sender> = vec![];
+    users.retain(|user| user.send("hello".to_string()).is_ok());
+}
diff --git a/src/tools/clippy/tests/ui/crashes/ice-5238.rs b/src/tools/clippy/tests/ui/crashes/ice-5238.rs
index fe03a39ad1b..ee2ae4f1a04 100644
--- a/src/tools/clippy/tests/ui/crashes/ice-5238.rs
+++ b/src/tools/clippy/tests/ui/crashes/ice-5238.rs
@@ -3,7 +3,8 @@
 #![feature(coroutines, coroutine_trait, stmt_expr_attributes)]
 
 fn main() {
-    let _ = #[coroutine] || {
+    let _ = #[coroutine]
+    || {
         yield;
     };
 }
diff --git a/src/tools/clippy/tests/ui/declare_interior_mutable_const/traits.rs b/src/tools/clippy/tests/ui/declare_interior_mutable_const/traits.rs
index adc53891ef5..490073f97fb 100644
--- a/src/tools/clippy/tests/ui/declare_interior_mutable_const/traits.rs
+++ b/src/tools/clippy/tests/ui/declare_interior_mutable_const/traits.rs
@@ -121,13 +121,12 @@ impl SelfType for AtomicUsize {
 // Even though a constant contains a generic type, if it also have an interior mutable type,
 // it should be linted at the definition site.
 trait BothOfCellAndGeneric<T> {
-    // this is a false negative in the current implementation.
-    const DIRECT: Cell<T>;
+    const DIRECT: Cell<T>; //~ ERROR: interior mutable
     const INDIRECT: Cell<*const T>; //~ ERROR: interior mutable
 }
 
 impl<T: ConstDefault> BothOfCellAndGeneric<T> for u64 {
-    const DIRECT: Cell<T> = Cell::new(T::DEFAULT);
+    const DIRECT: Cell<T> = Cell::new(T::DEFAULT); //~ ERROR: interior mutable
     const INDIRECT: Cell<*const T> = Cell::new(std::ptr::null());
 }
 
diff --git a/src/tools/clippy/tests/ui/declare_interior_mutable_const/traits.stderr b/src/tools/clippy/tests/ui/declare_interior_mutable_const/traits.stderr
index 328453efa24..1d1e9e2002f 100644
--- a/src/tools/clippy/tests/ui/declare_interior_mutable_const/traits.stderr
+++ b/src/tools/clippy/tests/ui/declare_interior_mutable_const/traits.stderr
@@ -55,22 +55,34 @@ LL |     const WRAPPED_SELF: Option<Self> = Some(AtomicUsize::new(21));
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: a `const` item should never be interior mutable
-  --> tests/ui/declare_interior_mutable_const/traits.rs:126:5
+  --> tests/ui/declare_interior_mutable_const/traits.rs:124:5
+   |
+LL |     const DIRECT: Cell<T>;
+   |     ^^^^^^^^^^^^^^^^^^^^^^
+
+error: a `const` item should never be interior mutable
+  --> tests/ui/declare_interior_mutable_const/traits.rs:125:5
    |
 LL |     const INDIRECT: Cell<*const T>;
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: a `const` item should never be interior mutable
-  --> tests/ui/declare_interior_mutable_const/traits.rs:142:5
+  --> tests/ui/declare_interior_mutable_const/traits.rs:129:5
+   |
+LL |     const DIRECT: Cell<T> = Cell::new(T::DEFAULT);
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: a `const` item should never be interior mutable
+  --> tests/ui/declare_interior_mutable_const/traits.rs:141:5
    |
 LL |     const ATOMIC: AtomicUsize = AtomicUsize::new(18);
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: a `const` item should never be interior mutable
-  --> tests/ui/declare_interior_mutable_const/traits.rs:148:5
+  --> tests/ui/declare_interior_mutable_const/traits.rs:147:5
    |
 LL |     const BOUNDED_ASSOC_TYPE: T::ToBeBounded = AtomicUsize::new(19);
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
-error: aborting due to 11 previous errors
+error: aborting due to 13 previous errors
 
diff --git a/src/tools/clippy/tests/ui/disallowed_names.rs b/src/tools/clippy/tests/ui/disallowed_names.rs
index 9a701a2cbcf..13c883409bf 100644
--- a/src/tools/clippy/tests/ui/disallowed_names.rs
+++ b/src/tools/clippy/tests/ui/disallowed_names.rs
@@ -71,3 +71,8 @@ mod tests {
         }
     }
 }
+
+#[test]
+fn test_with_disallowed_name() {
+    let foo = 0;
+}
diff --git a/src/tools/clippy/tests/ui/large_stack_arrays.rs b/src/tools/clippy/tests/ui/large_stack_arrays.rs
index d5c4f95f8c4..6bcaf481c9f 100644
--- a/src/tools/clippy/tests/ui/large_stack_arrays.rs
+++ b/src/tools/clippy/tests/ui/large_stack_arrays.rs
@@ -1,6 +1,9 @@
+//@aux-build:proc_macros.rs
 #![warn(clippy::large_stack_arrays)]
 #![allow(clippy::large_enum_variant)]
 
+extern crate proc_macros;
+
 #[derive(Clone, Copy)]
 struct S {
     pub data: [u64; 32],
@@ -55,3 +58,48 @@ fn main() {
         [(); 20_000_000],
     );
 }
+
+#[allow(clippy::useless_vec)]
+fn issue_12586() {
+    macro_rules! dummy {
+        ($n:expr) => {
+            $n
+        };
+        // Weird rule to test help messages.
+        ($a:expr => $b:expr) => {
+            [$a, $b, $a, $b]
+            //~^ ERROR: allocating a local array larger than 512000 bytes
+        };
+        ($id:ident; $n:literal) => {
+            dummy!(::std::vec![$id;$n])
+        };
+        ($($id:expr),+ $(,)?) => {
+            ::std::vec![$($id),*]
+        }
+    }
+    macro_rules! create_then_move {
+        ($id:ident; $n:literal) => {{
+            let _x_ = [$id; $n];
+            //~^ ERROR: allocating a local array larger than 512000 bytes
+            _x_
+        }};
+    }
+
+    let x = [0u32; 50_000];
+    let y = vec![x, x, x, x, x];
+    let y = vec![dummy![x, x, x, x, x]];
+    let y = vec![dummy![[x, x, x, x, x]]];
+    let y = dummy![x, x, x, x, x];
+    let y = [x, x, dummy!(x), x, x];
+    //~^ ERROR: allocating a local array larger than 512000 bytes
+    let y = dummy![x => x];
+    let y = dummy![x;5];
+    let y = dummy!(vec![dummy![x, x, x, x, x]]);
+    let y = dummy![[x, x, x, x, x]];
+    //~^ ERROR: allocating a local array larger than 512000 bytes
+
+    let y = proc_macros::make_it_big!([x; 1]);
+    //~^ ERROR: allocating a local array larger than 512000 bytes
+    let y = vec![proc_macros::make_it_big!([x; 10])];
+    let y = vec![create_then_move![x; 5]; 5];
+}
diff --git a/src/tools/clippy/tests/ui/large_stack_arrays.stderr b/src/tools/clippy/tests/ui/large_stack_arrays.stderr
index 007ca61c2de..06294ee8b8c 100644
--- a/src/tools/clippy/tests/ui/large_stack_arrays.stderr
+++ b/src/tools/clippy/tests/ui/large_stack_arrays.stderr
@@ -1,5 +1,5 @@
 error: allocating a local array larger than 512000 bytes
-  --> tests/ui/large_stack_arrays.rs:29:14
+  --> tests/ui/large_stack_arrays.rs:32:14
    |
 LL |     let _x = [build(); 3];
    |              ^^^^^^^^^^^^
@@ -9,7 +9,7 @@ LL |     let _x = [build(); 3];
    = help: to override `-D warnings` add `#[allow(clippy::large_stack_arrays)]`
 
 error: allocating a local array larger than 512000 bytes
-  --> tests/ui/large_stack_arrays.rs:32:14
+  --> tests/ui/large_stack_arrays.rs:35:14
    |
 LL |     let _y = [build(), build(), build()];
    |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -17,7 +17,7 @@ LL |     let _y = [build(), build(), build()];
    = help: consider allocating on the heap with `vec![build(), build(), build()].into_boxed_slice()`
 
 error: allocating a local array larger than 512000 bytes
-  --> tests/ui/large_stack_arrays.rs:38:9
+  --> tests/ui/large_stack_arrays.rs:41:9
    |
 LL |         [0u32; 20_000_000],
    |         ^^^^^^^^^^^^^^^^^^
@@ -25,7 +25,7 @@ LL |         [0u32; 20_000_000],
    = help: consider allocating on the heap with `vec![0u32; 20_000_000].into_boxed_slice()`
 
 error: allocating a local array larger than 512000 bytes
-  --> tests/ui/large_stack_arrays.rs:40:9
+  --> tests/ui/large_stack_arrays.rs:43:9
    |
 LL |         [S { data: [0; 32] }; 5000],
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -33,7 +33,7 @@ LL |         [S { data: [0; 32] }; 5000],
    = help: consider allocating on the heap with `vec![S { data: [0; 32] }; 5000].into_boxed_slice()`
 
 error: allocating a local array larger than 512000 bytes
-  --> tests/ui/large_stack_arrays.rs:42:9
+  --> tests/ui/large_stack_arrays.rs:45:9
    |
 LL |         [Some(""); 20_000_000],
    |         ^^^^^^^^^^^^^^^^^^^^^^
@@ -41,7 +41,7 @@ LL |         [Some(""); 20_000_000],
    = help: consider allocating on the heap with `vec![Some(""); 20_000_000].into_boxed_slice()`
 
 error: allocating a local array larger than 512000 bytes
-  --> tests/ui/large_stack_arrays.rs:44:9
+  --> tests/ui/large_stack_arrays.rs:47:9
    |
 LL |         [E::T(0); 5000],
    |         ^^^^^^^^^^^^^^^
@@ -49,12 +49,56 @@ LL |         [E::T(0); 5000],
    = help: consider allocating on the heap with `vec![E::T(0); 5000].into_boxed_slice()`
 
 error: allocating a local array larger than 512000 bytes
-  --> tests/ui/large_stack_arrays.rs:46:9
+  --> tests/ui/large_stack_arrays.rs:49:9
    |
 LL |         [0u8; usize::MAX],
    |         ^^^^^^^^^^^^^^^^^
    |
    = help: consider allocating on the heap with `vec![0u8; usize::MAX].into_boxed_slice()`
 
-error: aborting due to 7 previous errors
+error: allocating a local array larger than 512000 bytes
+  --> tests/ui/large_stack_arrays.rs:93:13
+   |
+LL |     let y = [x, x, dummy!(x), x, x];
+   |             ^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = help: consider allocating on the heap with `vec![x, x, dummy!(x), x, x].into_boxed_slice()`
+
+error: allocating a local array larger than 512000 bytes
+  --> tests/ui/large_stack_arrays.rs:70:13
+   |
+LL |             [$a, $b, $a, $b]
+   |             ^^^^^^^^^^^^^^^^
+...
+LL |     let y = dummy![x => x];
+   |             -------------- in this macro invocation
+   |
+   = note: this error originates in the macro `dummy` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: allocating a local array larger than 512000 bytes
+  --> tests/ui/large_stack_arrays.rs:98:20
+   |
+LL |     let y = dummy![[x, x, x, x, x]];
+   |                    ^^^^^^^^^^^^^^^
+   |
+   = help: consider allocating on the heap with `vec![x, x, x, x, x].into_boxed_slice()`
+
+error: allocating a local array larger than 512000 bytes
+  --> tests/ui/large_stack_arrays.rs:101:39
+   |
+LL |     let y = proc_macros::make_it_big!([x; 1]);
+   |                                       ^^^^^^
+
+error: allocating a local array larger than 512000 bytes
+  --> tests/ui/large_stack_arrays.rs:82:23
+   |
+LL |             let _x_ = [$id; $n];
+   |                       ^^^^^^^^^
+...
+LL |     let y = vec![create_then_move![x; 5]; 5];
+   |                  ----------------------- in this macro invocation
+   |
+   = note: this error originates in the macro `create_then_move` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: aborting due to 12 previous errors
 
diff --git a/src/tools/clippy/tests/ui/manual_is_ascii_check.fixed b/src/tools/clippy/tests/ui/manual_is_ascii_check.fixed
index 9c4bd335ad8..a72caa3a37e 100644
--- a/src/tools/clippy/tests/ui/manual_is_ascii_check.fixed
+++ b/src/tools/clippy/tests/ui/manual_is_ascii_check.fixed
@@ -55,3 +55,30 @@ fn msrv_1_47() {
     const FOO: bool = 'x'.is_ascii_digit();
     const BAR: bool = 'x'.is_ascii_hexdigit();
 }
+
+#[allow(clippy::deref_addrof, clippy::needless_borrow)]
+fn with_refs() {
+    let cool_letter = &&'g';
+    cool_letter.is_ascii_digit();
+    cool_letter.is_ascii_lowercase();
+}
+
+fn generics() {
+    fn a<U>(u: &U) -> bool
+    where
+        char: PartialOrd<U>,
+        U: PartialOrd<char> + ?Sized,
+    {
+        ('A'..='Z').contains(u)
+    }
+
+    fn take_while<Item, F>(cond: F)
+    where
+        Item: Sized,
+        F: Fn(Item) -> bool,
+    {
+    }
+    take_while(|c: char| c.is_ascii_uppercase());
+    take_while(|c: u8| c.is_ascii_uppercase());
+    take_while(|c: char| c.is_ascii_uppercase());
+}
diff --git a/src/tools/clippy/tests/ui/manual_is_ascii_check.rs b/src/tools/clippy/tests/ui/manual_is_ascii_check.rs
index 785943cd24d..bb6e2a317da 100644
--- a/src/tools/clippy/tests/ui/manual_is_ascii_check.rs
+++ b/src/tools/clippy/tests/ui/manual_is_ascii_check.rs
@@ -55,3 +55,30 @@ fn msrv_1_47() {
     const FOO: bool = matches!('x', '0'..='9');
     const BAR: bool = matches!('x', '0'..='9' | 'a'..='f' | 'A'..='F');
 }
+
+#[allow(clippy::deref_addrof, clippy::needless_borrow)]
+fn with_refs() {
+    let cool_letter = &&'g';
+    ('0'..='9').contains(&&cool_letter);
+    ('a'..='z').contains(*cool_letter);
+}
+
+fn generics() {
+    fn a<U>(u: &U) -> bool
+    where
+        char: PartialOrd<U>,
+        U: PartialOrd<char> + ?Sized,
+    {
+        ('A'..='Z').contains(u)
+    }
+
+    fn take_while<Item, F>(cond: F)
+    where
+        Item: Sized,
+        F: Fn(Item) -> bool,
+    {
+    }
+    take_while(|c| ('A'..='Z').contains(&c));
+    take_while(|c| (b'A'..=b'Z').contains(&c));
+    take_while(|c: char| ('A'..='Z').contains(&c));
+}
diff --git a/src/tools/clippy/tests/ui/manual_is_ascii_check.stderr b/src/tools/clippy/tests/ui/manual_is_ascii_check.stderr
index 3632077ec80..a93ccace28a 100644
--- a/src/tools/clippy/tests/ui/manual_is_ascii_check.stderr
+++ b/src/tools/clippy/tests/ui/manual_is_ascii_check.stderr
@@ -133,5 +133,45 @@ error: manual check for common ascii range
 LL |     const BAR: bool = matches!('x', '0'..='9' | 'a'..='f' | 'A'..='F');
    |                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `'x'.is_ascii_hexdigit()`
 
-error: aborting due to 22 previous errors
+error: manual check for common ascii range
+  --> tests/ui/manual_is_ascii_check.rs:62:5
+   |
+LL |     ('0'..='9').contains(&&cool_letter);
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `cool_letter.is_ascii_digit()`
+
+error: manual check for common ascii range
+  --> tests/ui/manual_is_ascii_check.rs:63:5
+   |
+LL |     ('a'..='z').contains(*cool_letter);
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `cool_letter.is_ascii_lowercase()`
+
+error: manual check for common ascii range
+  --> tests/ui/manual_is_ascii_check.rs:81:20
+   |
+LL |     take_while(|c| ('A'..='Z').contains(&c));
+   |                    ^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: try
+   |
+LL |     take_while(|c: char| c.is_ascii_uppercase());
+   |                 ~~~~~~~  ~~~~~~~~~~~~~~~~~~~~~~
+
+error: manual check for common ascii range
+  --> tests/ui/manual_is_ascii_check.rs:82:20
+   |
+LL |     take_while(|c| (b'A'..=b'Z').contains(&c));
+   |                    ^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: try
+   |
+LL |     take_while(|c: u8| c.is_ascii_uppercase());
+   |                 ~~~~~  ~~~~~~~~~~~~~~~~~~~~~~
+
+error: manual check for common ascii range
+  --> tests/ui/manual_is_ascii_check.rs:83:26
+   |
+LL |     take_while(|c: char| ('A'..='Z').contains(&c));
+   |                          ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `c.is_ascii_uppercase()`
+
+error: aborting due to 27 previous errors
 
diff --git a/src/tools/clippy/tests/ui/mistyped_literal_suffix.fixed b/src/tools/clippy/tests/ui/mistyped_literal_suffix.fixed
index 861764a2aee..b84b3dc349e 100644
--- a/src/tools/clippy/tests/ui/mistyped_literal_suffix.fixed
+++ b/src/tools/clippy/tests/ui/mistyped_literal_suffix.fixed
@@ -32,7 +32,7 @@ fn main() {
     // testing that the suggestion actually fits in its type
     let fail30 = 127_i8; // should be i8
     let fail31 = 240_u8; // should be u8
-    let ok32 = 360_8; // doesnt fit in either, should be ignored
+    let ok32 = 360_8; // doesn't fit in either, should be ignored
     let fail33 = 0x1234_i16;
     let fail34 = 0xABCD_u16;
     let ok35 = 0x12345_16;
diff --git a/src/tools/clippy/tests/ui/mistyped_literal_suffix.rs b/src/tools/clippy/tests/ui/mistyped_literal_suffix.rs
index 4a15c335fd8..a47a736067a 100644
--- a/src/tools/clippy/tests/ui/mistyped_literal_suffix.rs
+++ b/src/tools/clippy/tests/ui/mistyped_literal_suffix.rs
@@ -32,7 +32,7 @@ fn main() {
     // testing that the suggestion actually fits in its type
     let fail30 = 127_8; // should be i8
     let fail31 = 240_8; // should be u8
-    let ok32 = 360_8; // doesnt fit in either, should be ignored
+    let ok32 = 360_8; // doesn't fit in either, should be ignored
     let fail33 = 0x1234_16;
     let fail34 = 0xABCD_16;
     let ok35 = 0x12345_16;
diff --git a/src/tools/clippy/tests/ui/mut_key.rs b/src/tools/clippy/tests/ui/mut_key.rs
index 2d70bfd4c77..81d8732b3b2 100644
--- a/src/tools/clippy/tests/ui/mut_key.rs
+++ b/src/tools/clippy/tests/ui/mut_key.rs
@@ -5,7 +5,7 @@ use std::rc::Rc;
 use std::sync::atomic::AtomicUsize;
 use std::sync::atomic::Ordering::Relaxed;
 use std::sync::Arc;
-//@no-rustfix
+
 struct Key(AtomicUsize);
 
 impl Clone for Key {
@@ -77,8 +77,6 @@ fn main() {
     //~^ ERROR: mutable key type
     let _map = HashMap::<&mut Cell<usize>, usize>::new();
     //~^ ERROR: mutable key type
-    let _map = HashMap::<&mut usize, usize>::new();
-    //~^ ERROR: mutable key type
     // Collection types from `std` who's impl of `Hash` or `Ord` delegate their type parameters
     let _map = HashMap::<Vec<Cell<usize>>, usize>::new();
     //~^ ERROR: mutable key type
@@ -92,8 +90,6 @@ fn main() {
     //~^ ERROR: mutable key type
     let _map = HashMap::<Option<Vec<Cell<usize>>>, usize>::new();
     //~^ ERROR: mutable key type
-    let _map = HashMap::<Result<&mut usize, ()>, usize>::new();
-    //~^ ERROR: mutable key type
     // Smart pointers from `std` who's impl of `Hash` or `Ord` delegate their type parameters
     let _map = HashMap::<Box<Cell<usize>>, usize>::new();
     //~^ ERROR: mutable key type
@@ -101,4 +97,8 @@ fn main() {
     //~^ ERROR: mutable key type
     let _map = HashMap::<Arc<Cell<usize>>, usize>::new();
     //~^ ERROR: mutable key type
+
+    // Not interior mutability
+    let _map = HashMap::<&mut usize, usize>::new();
+    let _map = HashMap::<Result<&mut usize, ()>, usize>::new();
 }
diff --git a/src/tools/clippy/tests/ui/mut_key.stderr b/src/tools/clippy/tests/ui/mut_key.stderr
index e54c3075d4f..5ad9aad2d0a 100644
--- a/src/tools/clippy/tests/ui/mut_key.stderr
+++ b/src/tools/clippy/tests/ui/mut_key.stderr
@@ -38,70 +38,58 @@ LL |     let _map = HashMap::<&mut Cell<usize>, usize>::new();
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: mutable key type
-  --> tests/ui/mut_key.rs:80:5
-   |
-LL |     let _map = HashMap::<&mut usize, usize>::new();
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-error: mutable key type
-  --> tests/ui/mut_key.rs:83:5
+  --> tests/ui/mut_key.rs:81:5
    |
 LL |     let _map = HashMap::<Vec<Cell<usize>>, usize>::new();
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: mutable key type
-  --> tests/ui/mut_key.rs:85:5
+  --> tests/ui/mut_key.rs:83:5
    |
 LL |     let _map = HashMap::<BTreeMap<Cell<usize>, ()>, usize>::new();
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: mutable key type
-  --> tests/ui/mut_key.rs:87:5
+  --> tests/ui/mut_key.rs:85:5
    |
 LL |     let _map = HashMap::<BTreeMap<(), Cell<usize>>, usize>::new();
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: mutable key type
-  --> tests/ui/mut_key.rs:89:5
+  --> tests/ui/mut_key.rs:87:5
    |
 LL |     let _map = HashMap::<BTreeSet<Cell<usize>>, usize>::new();
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: mutable key type
-  --> tests/ui/mut_key.rs:91:5
+  --> tests/ui/mut_key.rs:89:5
    |
 LL |     let _map = HashMap::<Option<Cell<usize>>, usize>::new();
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: mutable key type
-  --> tests/ui/mut_key.rs:93:5
+  --> tests/ui/mut_key.rs:91:5
    |
 LL |     let _map = HashMap::<Option<Vec<Cell<usize>>>, usize>::new();
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: mutable key type
-  --> tests/ui/mut_key.rs:95:5
-   |
-LL |     let _map = HashMap::<Result<&mut usize, ()>, usize>::new();
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-error: mutable key type
-  --> tests/ui/mut_key.rs:98:5
+  --> tests/ui/mut_key.rs:94:5
    |
 LL |     let _map = HashMap::<Box<Cell<usize>>, usize>::new();
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: mutable key type
-  --> tests/ui/mut_key.rs:100:5
+  --> tests/ui/mut_key.rs:96:5
    |
 LL |     let _map = HashMap::<Rc<Cell<usize>>, usize>::new();
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: mutable key type
-  --> tests/ui/mut_key.rs:102:5
+  --> tests/ui/mut_key.rs:98:5
    |
 LL |     let _map = HashMap::<Arc<Cell<usize>>, usize>::new();
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
-error: aborting due to 17 previous errors
+error: aborting due to 15 previous errors
 
diff --git a/src/tools/clippy/tests/ui/needless_for_each_fixable.fixed b/src/tools/clippy/tests/ui/needless_for_each_fixable.fixed
index 8c0e7ba7627..2362314290e 100644
--- a/src/tools/clippy/tests/ui/needless_for_each_fixable.fixed
+++ b/src/tools/clippy/tests/ui/needless_for_each_fixable.fixed
@@ -113,6 +113,10 @@ fn should_not_lint() {
     let _ = v.iter().for_each(|elem| {
         acc += elem;
     });
+    // `for_each` has a closure with an unsafe block.
+    v.iter().for_each(|elem| unsafe {
+        acc += elem;
+    });
 }
 
 fn main() {}
diff --git a/src/tools/clippy/tests/ui/needless_for_each_fixable.rs b/src/tools/clippy/tests/ui/needless_for_each_fixable.rs
index cdc903a636c..5b1186daa22 100644
--- a/src/tools/clippy/tests/ui/needless_for_each_fixable.rs
+++ b/src/tools/clippy/tests/ui/needless_for_each_fixable.rs
@@ -113,6 +113,10 @@ fn should_not_lint() {
     let _ = v.iter().for_each(|elem| {
         acc += elem;
     });
+    // `for_each` has a closure with an unsafe block.
+    v.iter().for_each(|elem| unsafe {
+        acc += elem;
+    });
 }
 
 fn main() {}
diff --git a/src/tools/clippy/tests/ui/needless_pass_by_ref_mut.rs b/src/tools/clippy/tests/ui/needless_pass_by_ref_mut.rs
index a92197fb0af..3f5f55f4002 100644
--- a/src/tools/clippy/tests/ui/needless_pass_by_ref_mut.rs
+++ b/src/tools/clippy/tests/ui/needless_pass_by_ref_mut.rs
@@ -44,18 +44,13 @@ fn non_mut_ref(_: &Vec<u32>) {}
 struct Bar;
 
 impl Bar {
-    // Should not warn on `&mut self`.
     fn bar(&mut self) {}
+    //~^ ERROR: this argument is a mutable reference, but not used mutably
 
     fn mushroom(&self, vec: &mut Vec<i32>) -> usize {
         //~^ ERROR: this argument is a mutable reference, but not used mutably
         vec.len()
     }
-
-    fn badger(&mut self, vec: &mut Vec<i32>) -> usize {
-        //~^ ERROR: this argument is a mutable reference, but not used mutably
-        vec.len()
-    }
 }
 
 trait Babar {
@@ -307,6 +302,41 @@ fn filter_copy<T: Copy>(predicate: &mut impl FnMut(T) -> bool) -> impl FnMut(&T)
     move |&item| predicate(item)
 }
 
+trait MutSelfTrait {
+    // Should not warn since it's a trait method.
+    fn mut_self(&mut self);
+}
+
+struct MutSelf {
+    a: u32,
+}
+
+impl MutSelf {
+    fn bar(&mut self) {}
+    //~^ ERROR: this argument is a mutable reference, but not used mutably
+    async fn foo(&mut self, u: &mut i32, v: &mut u32) {
+        //~^ ERROR: this argument is a mutable reference, but not used mutably
+        //~| ERROR: this argument is a mutable reference, but not used mutably
+        async {
+            *u += 1;
+        }
+        .await;
+    }
+    async fn foo2(&mut self, u: &mut i32, v: &mut u32) {
+        //~^ ERROR: this argument is a mutable reference, but not used mutably
+        async {
+            self.a += 1;
+            *u += 1;
+        }
+        .await;
+    }
+}
+
+impl MutSelfTrait for MutSelf {
+    // Should not warn since it's a trait method.
+    fn mut_self(&mut self) {}
+}
+
 // `is_from_proc_macro` stress tests
 fn _empty_tup(x: &mut (())) {}
 fn _single_tup(x: &mut ((i32,))) {}
diff --git a/src/tools/clippy/tests/ui/needless_pass_by_ref_mut.stderr b/src/tools/clippy/tests/ui/needless_pass_by_ref_mut.stderr
index 89dad3e60b1..21ca393dcb6 100644
--- a/src/tools/clippy/tests/ui/needless_pass_by_ref_mut.stderr
+++ b/src/tools/clippy/tests/ui/needless_pass_by_ref_mut.stderr
@@ -14,73 +14,73 @@ LL | fn foo6(s: &mut Vec<u32>) {
    |            ^^^^^^^^^^^^^ help: consider changing to: `&Vec<u32>`
 
 error: this argument is a mutable reference, but not used mutably
-  --> tests/ui/needless_pass_by_ref_mut.rs:50:29
+  --> tests/ui/needless_pass_by_ref_mut.rs:47:12
    |
-LL |     fn mushroom(&self, vec: &mut Vec<i32>) -> usize {
-   |                             ^^^^^^^^^^^^^ help: consider changing to: `&Vec<i32>`
+LL |     fn bar(&mut self) {}
+   |            ^^^^^^^^^ help: consider changing to: `&self`
 
 error: this argument is a mutable reference, but not used mutably
-  --> tests/ui/needless_pass_by_ref_mut.rs:55:31
+  --> tests/ui/needless_pass_by_ref_mut.rs:50:29
    |
-LL |     fn badger(&mut self, vec: &mut Vec<i32>) -> usize {
-   |                               ^^^^^^^^^^^^^ help: consider changing to: `&Vec<i32>`
+LL |     fn mushroom(&self, vec: &mut Vec<i32>) -> usize {
+   |                             ^^^^^^^^^^^^^ help: consider changing to: `&Vec<i32>`
 
 error: this argument is a mutable reference, but not used mutably
-  --> tests/ui/needless_pass_by_ref_mut.rs:132:16
+  --> tests/ui/needless_pass_by_ref_mut.rs:127:16
    |
 LL | async fn a1(x: &mut i32) {
    |                ^^^^^^^^ help: consider changing to: `&i32`
 
 error: this argument is a mutable reference, but not used mutably
-  --> tests/ui/needless_pass_by_ref_mut.rs:136:16
+  --> tests/ui/needless_pass_by_ref_mut.rs:131:16
    |
 LL | async fn a2(x: &mut i32, y: String) {
    |                ^^^^^^^^ help: consider changing to: `&i32`
 
 error: this argument is a mutable reference, but not used mutably
-  --> tests/ui/needless_pass_by_ref_mut.rs:140:16
+  --> tests/ui/needless_pass_by_ref_mut.rs:135:16
    |
 LL | async fn a3(x: &mut i32, y: String, z: String) {
    |                ^^^^^^^^ help: consider changing to: `&i32`
 
 error: this argument is a mutable reference, but not used mutably
-  --> tests/ui/needless_pass_by_ref_mut.rs:144:16
+  --> tests/ui/needless_pass_by_ref_mut.rs:139:16
    |
 LL | async fn a4(x: &mut i32, y: i32) {
    |                ^^^^^^^^ help: consider changing to: `&i32`
 
 error: this argument is a mutable reference, but not used mutably
-  --> tests/ui/needless_pass_by_ref_mut.rs:148:24
+  --> tests/ui/needless_pass_by_ref_mut.rs:143:24
    |
 LL | async fn a5(x: i32, y: &mut i32) {
    |                        ^^^^^^^^ help: consider changing to: `&i32`
 
 error: this argument is a mutable reference, but not used mutably
-  --> tests/ui/needless_pass_by_ref_mut.rs:152:24
+  --> tests/ui/needless_pass_by_ref_mut.rs:147:24
    |
 LL | async fn a6(x: i32, y: &mut i32) {
    |                        ^^^^^^^^ help: consider changing to: `&i32`
 
 error: this argument is a mutable reference, but not used mutably
-  --> tests/ui/needless_pass_by_ref_mut.rs:156:32
+  --> tests/ui/needless_pass_by_ref_mut.rs:151:32
    |
 LL | async fn a7(x: i32, y: i32, z: &mut i32) {
    |                                ^^^^^^^^ help: consider changing to: `&i32`
 
 error: this argument is a mutable reference, but not used mutably
-  --> tests/ui/needless_pass_by_ref_mut.rs:160:24
+  --> tests/ui/needless_pass_by_ref_mut.rs:155:24
    |
 LL | async fn a8(x: i32, a: &mut i32, y: i32, z: &mut i32) {
    |                        ^^^^^^^^ help: consider changing to: `&i32`
 
 error: this argument is a mutable reference, but not used mutably
-  --> tests/ui/needless_pass_by_ref_mut.rs:160:45
+  --> tests/ui/needless_pass_by_ref_mut.rs:155:45
    |
 LL | async fn a8(x: i32, a: &mut i32, y: i32, z: &mut i32) {
    |                                             ^^^^^^^^ help: consider changing to: `&i32`
 
 error: this argument is a mutable reference, but not used mutably
-  --> tests/ui/needless_pass_by_ref_mut.rs:194:16
+  --> tests/ui/needless_pass_by_ref_mut.rs:189:16
    |
 LL | fn cfg_warn(s: &mut u32) {}
    |                ^^^^^^^^ help: consider changing to: `&u32`
@@ -88,7 +88,7 @@ LL | fn cfg_warn(s: &mut u32) {}
    = note: this is cfg-gated and may require further changes
 
 error: this argument is a mutable reference, but not used mutably
-  --> tests/ui/needless_pass_by_ref_mut.rs:200:20
+  --> tests/ui/needless_pass_by_ref_mut.rs:195:20
    |
 LL |     fn cfg_warn(s: &mut u32) {}
    |                    ^^^^^^^^ help: consider changing to: `&u32`
@@ -96,19 +96,19 @@ LL |     fn cfg_warn(s: &mut u32) {}
    = note: this is cfg-gated and may require further changes
 
 error: this argument is a mutable reference, but not used mutably
-  --> tests/ui/needless_pass_by_ref_mut.rs:214:39
+  --> tests/ui/needless_pass_by_ref_mut.rs:209:39
    |
 LL | async fn inner_async2(x: &mut i32, y: &mut u32) {
    |                                       ^^^^^^^^ help: consider changing to: `&u32`
 
 error: this argument is a mutable reference, but not used mutably
-  --> tests/ui/needless_pass_by_ref_mut.rs:222:26
+  --> tests/ui/needless_pass_by_ref_mut.rs:217:26
    |
 LL | async fn inner_async3(x: &mut i32, y: &mut u32) {
    |                          ^^^^^^^^ help: consider changing to: `&i32`
 
 error: this argument is a mutable reference, but not used mutably
-  --> tests/ui/needless_pass_by_ref_mut.rs:241:34
+  --> tests/ui/needless_pass_by_ref_mut.rs:236:34
    |
 LL | pub async fn call_in_closure1(n: &mut str) {
    |                                  ^^^^^^^^ help: consider changing to: `&str`
@@ -116,15 +116,7 @@ LL | pub async fn call_in_closure1(n: &mut str) {
    = warning: changing this function will impact semver compatibility
 
 error: this argument is a mutable reference, but not used mutably
-  --> tests/ui/needless_pass_by_ref_mut.rs:253:25
-   |
-LL | pub async fn closure(n: &mut usize) -> impl '_ + FnMut() {
-   |                         ^^^^^^^^^^ help: consider changing to: `&usize`
-   |
-   = warning: changing this function will impact semver compatibility
-
-error: this argument is a mutable reference, but not used mutably
-  --> tests/ui/needless_pass_by_ref_mut.rs:260:20
+  --> tests/ui/needless_pass_by_ref_mut.rs:255:20
    |
 LL | pub fn closure2(n: &mut usize) -> impl '_ + FnMut() -> usize {
    |                    ^^^^^^^^^^ help: consider changing to: `&usize`
@@ -132,7 +124,7 @@ LL | pub fn closure2(n: &mut usize) -> impl '_ + FnMut() -> usize {
    = warning: changing this function will impact semver compatibility
 
 error: this argument is a mutable reference, but not used mutably
-  --> tests/ui/needless_pass_by_ref_mut.rs:271:26
+  --> tests/ui/needless_pass_by_ref_mut.rs:266:26
    |
 LL | pub async fn closure4(n: &mut usize) {
    |                          ^^^^^^^^^^ help: consider changing to: `&usize`
@@ -140,64 +132,88 @@ LL | pub async fn closure4(n: &mut usize) {
    = warning: changing this function will impact semver compatibility
 
 error: this argument is a mutable reference, but not used mutably
-  --> tests/ui/needless_pass_by_ref_mut.rs:311:18
+  --> tests/ui/needless_pass_by_ref_mut.rs:315:12
+   |
+LL |     fn bar(&mut self) {}
+   |            ^^^^^^^^^ help: consider changing to: `&self`
+
+error: this argument is a mutable reference, but not used mutably
+  --> tests/ui/needless_pass_by_ref_mut.rs:317:18
+   |
+LL |     async fn foo(&mut self, u: &mut i32, v: &mut u32) {
+   |                  ^^^^^^^^^ help: consider changing to: `&self`
+
+error: this argument is a mutable reference, but not used mutably
+  --> tests/ui/needless_pass_by_ref_mut.rs:317:45
+   |
+LL |     async fn foo(&mut self, u: &mut i32, v: &mut u32) {
+   |                                             ^^^^^^^^ help: consider changing to: `&u32`
+
+error: this argument is a mutable reference, but not used mutably
+  --> tests/ui/needless_pass_by_ref_mut.rs:325:46
+   |
+LL |     async fn foo2(&mut self, u: &mut i32, v: &mut u32) {
+   |                                              ^^^^^^^^ help: consider changing to: `&u32`
+
+error: this argument is a mutable reference, but not used mutably
+  --> tests/ui/needless_pass_by_ref_mut.rs:341:18
    |
 LL | fn _empty_tup(x: &mut (())) {}
    |                  ^^^^^^^^^ help: consider changing to: `&()`
 
 error: this argument is a mutable reference, but not used mutably
-  --> tests/ui/needless_pass_by_ref_mut.rs:312:19
+  --> tests/ui/needless_pass_by_ref_mut.rs:342:19
    |
 LL | fn _single_tup(x: &mut ((i32,))) {}
    |                   ^^^^^^^^^^^^^ help: consider changing to: `&(i32,)`
 
 error: this argument is a mutable reference, but not used mutably
-  --> tests/ui/needless_pass_by_ref_mut.rs:313:18
+  --> tests/ui/needless_pass_by_ref_mut.rs:343:18
    |
 LL | fn _multi_tup(x: &mut ((i32, u32))) {}
    |                  ^^^^^^^^^^^^^^^^^ help: consider changing to: `&(i32, u32)`
 
 error: this argument is a mutable reference, but not used mutably
-  --> tests/ui/needless_pass_by_ref_mut.rs:314:11
+  --> tests/ui/needless_pass_by_ref_mut.rs:344:11
    |
 LL | fn _fn(x: &mut (fn())) {}
    |           ^^^^^^^^^^^ help: consider changing to: `&fn()`
 
 error: this argument is a mutable reference, but not used mutably
-  --> tests/ui/needless_pass_by_ref_mut.rs:316:23
+  --> tests/ui/needless_pass_by_ref_mut.rs:346:23
    |
 LL | fn _extern_rust_fn(x: &mut extern "Rust" fn()) {}
    |                       ^^^^^^^^^^^^^^^^^^^^^^^ help: consider changing to: `&extern "Rust" fn()`
 
 error: this argument is a mutable reference, but not used mutably
-  --> tests/ui/needless_pass_by_ref_mut.rs:317:20
+  --> tests/ui/needless_pass_by_ref_mut.rs:347:20
    |
 LL | fn _extern_c_fn(x: &mut extern "C" fn()) {}
    |                    ^^^^^^^^^^^^^^^^^^^^ help: consider changing to: `&extern "C" fn()`
 
 error: this argument is a mutable reference, but not used mutably
-  --> tests/ui/needless_pass_by_ref_mut.rs:318:18
+  --> tests/ui/needless_pass_by_ref_mut.rs:348:18
    |
 LL | fn _unsafe_fn(x: &mut unsafe fn()) {}
    |                  ^^^^^^^^^^^^^^^^ help: consider changing to: `&unsafe fn()`
 
 error: this argument is a mutable reference, but not used mutably
-  --> tests/ui/needless_pass_by_ref_mut.rs:319:25
+  --> tests/ui/needless_pass_by_ref_mut.rs:349:25
    |
 LL | fn _unsafe_extern_fn(x: &mut unsafe extern "C" fn()) {}
    |                         ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider changing to: `&unsafe extern "C" fn()`
 
 error: this argument is a mutable reference, but not used mutably
-  --> tests/ui/needless_pass_by_ref_mut.rs:320:20
+  --> tests/ui/needless_pass_by_ref_mut.rs:350:20
    |
 LL | fn _fn_with_arg(x: &mut unsafe extern "C" fn(i32)) {}
    |                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider changing to: `&unsafe extern "C" fn(i32)`
 
 error: this argument is a mutable reference, but not used mutably
-  --> tests/ui/needless_pass_by_ref_mut.rs:321:20
+  --> tests/ui/needless_pass_by_ref_mut.rs:351:20
    |
 LL | fn _fn_with_ret(x: &mut unsafe extern "C" fn() -> (i32)) {}
    |                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider changing to: `&unsafe extern "C" fn() -> (i32)`
 
-error: aborting due to 31 previous errors
+error: aborting due to 34 previous errors
 
diff --git a/src/tools/clippy/tests/ui/needless_pass_by_ref_mut2.fixed b/src/tools/clippy/tests/ui/needless_pass_by_ref_mut2.fixed
new file mode 100644
index 00000000000..3c2576213cd
--- /dev/null
+++ b/src/tools/clippy/tests/ui/needless_pass_by_ref_mut2.fixed
@@ -0,0 +1,24 @@
+// If both `inner_async3` and `inner_async4` are present, aliases are declared after
+// they're used in `inner_async4` for some reasons... This test ensures that no
+// only `v` is marked as not used mutably in `inner_async4`.
+
+#![allow(clippy::redundant_closure_call)]
+#![warn(clippy::needless_pass_by_ref_mut)]
+
+pub async fn inner_async3(x: &i32, y: &mut u32) {
+    //~^ ERROR: this argument is a mutable reference, but not used mutably
+    async {
+        *y += 1;
+    }
+    .await;
+}
+
+pub async fn inner_async4(u: &mut i32, v: &u32) {
+    //~^ ERROR: this argument is a mutable reference, but not used mutably
+    async {
+        *u += 1;
+    }
+    .await;
+}
+
+fn main() {}
diff --git a/src/tools/clippy/tests/ui/needless_pass_by_ref_mut2.rs b/src/tools/clippy/tests/ui/needless_pass_by_ref_mut2.rs
new file mode 100644
index 00000000000..34b0b564deb
--- /dev/null
+++ b/src/tools/clippy/tests/ui/needless_pass_by_ref_mut2.rs
@@ -0,0 +1,24 @@
+// If both `inner_async3` and `inner_async4` are present, aliases are declared after
+// they're used in `inner_async4` for some reasons... This test ensures that no
+// only `v` is marked as not used mutably in `inner_async4`.
+
+#![allow(clippy::redundant_closure_call)]
+#![warn(clippy::needless_pass_by_ref_mut)]
+
+pub async fn inner_async3(x: &mut i32, y: &mut u32) {
+    //~^ ERROR: this argument is a mutable reference, but not used mutably
+    async {
+        *y += 1;
+    }
+    .await;
+}
+
+pub async fn inner_async4(u: &mut i32, v: &mut u32) {
+    //~^ ERROR: this argument is a mutable reference, but not used mutably
+    async {
+        *u += 1;
+    }
+    .await;
+}
+
+fn main() {}
diff --git a/src/tools/clippy/tests/ui/needless_pass_by_ref_mut2.stderr b/src/tools/clippy/tests/ui/needless_pass_by_ref_mut2.stderr
new file mode 100644
index 00000000000..c8753603225
--- /dev/null
+++ b/src/tools/clippy/tests/ui/needless_pass_by_ref_mut2.stderr
@@ -0,0 +1,20 @@
+error: this argument is a mutable reference, but not used mutably
+  --> tests/ui/needless_pass_by_ref_mut2.rs:8:30
+   |
+LL | pub async fn inner_async3(x: &mut i32, y: &mut u32) {
+   |                              ^^^^^^^^ help: consider changing to: `&i32`
+   |
+   = warning: changing this function will impact semver compatibility
+   = note: `-D clippy::needless-pass-by-ref-mut` implied by `-D warnings`
+   = help: to override `-D warnings` add `#[allow(clippy::needless_pass_by_ref_mut)]`
+
+error: this argument is a mutable reference, but not used mutably
+  --> tests/ui/needless_pass_by_ref_mut2.rs:16:43
+   |
+LL | pub async fn inner_async4(u: &mut i32, v: &mut u32) {
+   |                                           ^^^^^^^^ help: consider changing to: `&u32`
+   |
+   = warning: changing this function will impact semver compatibility
+
+error: aborting due to 2 previous errors
+
diff --git a/src/tools/clippy/tests/ui/non_canonical_partial_ord_impl.fixed b/src/tools/clippy/tests/ui/non_canonical_partial_ord_impl.fixed
index db55cc094e3..d444a753697 100644
--- a/src/tools/clippy/tests/ui/non_canonical_partial_ord_impl.fixed
+++ b/src/tools/clippy/tests/ui/non_canonical_partial_ord_impl.fixed
@@ -142,3 +142,21 @@ impl PartialOrd for H {
         Some(Ord::cmp(self, other))
     }
 }
+
+// #12683, do not lint
+
+#[derive(Eq, PartialEq)]
+struct I(u32);
+
+impl Ord for I {
+    fn cmp(&self, other: &Self) -> Ordering {
+        todo!();
+    }
+}
+
+impl PartialOrd for I {
+    #[allow(clippy::needless_return)]
+    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
+        return Some(self.cmp(other));
+    }
+}
diff --git a/src/tools/clippy/tests/ui/non_canonical_partial_ord_impl.rs b/src/tools/clippy/tests/ui/non_canonical_partial_ord_impl.rs
index 52f4b85b917..dc6c4354604 100644
--- a/src/tools/clippy/tests/ui/non_canonical_partial_ord_impl.rs
+++ b/src/tools/clippy/tests/ui/non_canonical_partial_ord_impl.rs
@@ -146,3 +146,21 @@ impl PartialOrd for H {
         Some(Ord::cmp(self, other))
     }
 }
+
+// #12683, do not lint
+
+#[derive(Eq, PartialEq)]
+struct I(u32);
+
+impl Ord for I {
+    fn cmp(&self, other: &Self) -> Ordering {
+        todo!();
+    }
+}
+
+impl PartialOrd for I {
+    #[allow(clippy::needless_return)]
+    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
+        return Some(self.cmp(other));
+    }
+}
diff --git a/src/tools/clippy/tests/ui/readonly_write_lock.fixed b/src/tools/clippy/tests/ui/readonly_write_lock.fixed
index 76f4a43ae53..4db13482ac7 100644
--- a/src/tools/clippy/tests/ui/readonly_write_lock.fixed
+++ b/src/tools/clippy/tests/ui/readonly_write_lock.fixed
@@ -43,3 +43,7 @@ fn main() {
         *writer1 = *writer2;
     }
 }
+
+fn issue12733(rw: &RwLock<()>) {
+    let _write_guard = rw.write().unwrap();
+}
diff --git a/src/tools/clippy/tests/ui/readonly_write_lock.rs b/src/tools/clippy/tests/ui/readonly_write_lock.rs
index 3d1d3855fe1..66ba1b2d696 100644
--- a/src/tools/clippy/tests/ui/readonly_write_lock.rs
+++ b/src/tools/clippy/tests/ui/readonly_write_lock.rs
@@ -43,3 +43,7 @@ fn main() {
         *writer1 = *writer2;
     }
 }
+
+fn issue12733(rw: &RwLock<()>) {
+    let _write_guard = rw.write().unwrap();
+}
diff --git a/src/tools/clippy/tests/ui/redundant_guards.fixed b/src/tools/clippy/tests/ui/redundant_guards.fixed
index ded91e08376..ed4b1c21915 100644
--- a/src/tools/clippy/tests/ui/redundant_guards.fixed
+++ b/src/tools/clippy/tests/ui/redundant_guards.fixed
@@ -136,6 +136,18 @@ fn f(s: Option<std::ffi::OsString>) {
     }
 }
 
+fn not_matches() {
+    match Some(42) {
+        // The pattern + guard is not equivalent to `Some(42)` because of the `panic!`
+        Some(v)
+            if match v {
+                42 => true,
+                _ => panic!(),
+            } => {},
+        _ => {},
+    }
+}
+
 struct S {
     a: usize,
 }
diff --git a/src/tools/clippy/tests/ui/redundant_guards.rs b/src/tools/clippy/tests/ui/redundant_guards.rs
index 2aaa2ace398..adbc4ed16cd 100644
--- a/src/tools/clippy/tests/ui/redundant_guards.rs
+++ b/src/tools/clippy/tests/ui/redundant_guards.rs
@@ -136,6 +136,18 @@ fn f(s: Option<std::ffi::OsString>) {
     }
 }
 
+fn not_matches() {
+    match Some(42) {
+        // The pattern + guard is not equivalent to `Some(42)` because of the `panic!`
+        Some(v)
+            if match v {
+                42 => true,
+                _ => panic!(),
+            } => {},
+        _ => {},
+    }
+}
+
 struct S {
     a: usize,
 }
diff --git a/src/tools/clippy/tests/ui/redundant_guards.stderr b/src/tools/clippy/tests/ui/redundant_guards.stderr
index 01ca91fcd09..fd12e083282 100644
--- a/src/tools/clippy/tests/ui/redundant_guards.stderr
+++ b/src/tools/clippy/tests/ui/redundant_guards.stderr
@@ -132,7 +132,7 @@ LL +         1 => {},
    |
 
 error: redundant guard
-  --> tests/ui/redundant_guards.rs:174:28
+  --> tests/ui/redundant_guards.rs:186:28
    |
 LL |             Some(ref x) if x == &1 => {},
    |                            ^^^^^^^
@@ -144,7 +144,7 @@ LL +             Some(1) => {},
    |
 
 error: redundant guard
-  --> tests/ui/redundant_guards.rs:175:28
+  --> tests/ui/redundant_guards.rs:187:28
    |
 LL |             Some(ref x) if &1 == x => {},
    |                            ^^^^^^^
@@ -156,7 +156,7 @@ LL +             Some(1) => {},
    |
 
 error: redundant guard
-  --> tests/ui/redundant_guards.rs:176:28
+  --> tests/ui/redundant_guards.rs:188:28
    |
 LL |             Some(ref x) if let &2 = x => {},
    |                            ^^^^^^^^^^
@@ -168,7 +168,7 @@ LL +             Some(2) => {},
    |
 
 error: redundant guard
-  --> tests/ui/redundant_guards.rs:177:28
+  --> tests/ui/redundant_guards.rs:189:28
    |
 LL |             Some(ref x) if matches!(x, &3) => {},
    |                            ^^^^^^^^^^^^^^^
@@ -180,7 +180,7 @@ LL +             Some(3) => {},
    |
 
 error: redundant guard
-  --> tests/ui/redundant_guards.rs:197:32
+  --> tests/ui/redundant_guards.rs:209:32
    |
 LL |             B { ref c, .. } if c == &1 => {},
    |                                ^^^^^^^
@@ -192,7 +192,7 @@ LL +             B { c: 1, .. } => {},
    |
 
 error: redundant guard
-  --> tests/ui/redundant_guards.rs:198:32
+  --> tests/ui/redundant_guards.rs:210:32
    |
 LL |             B { ref c, .. } if &1 == c => {},
    |                                ^^^^^^^
@@ -204,7 +204,7 @@ LL +             B { c: 1, .. } => {},
    |
 
 error: redundant guard
-  --> tests/ui/redundant_guards.rs:199:32
+  --> tests/ui/redundant_guards.rs:211:32
    |
 LL |             B { ref c, .. } if let &1 = c => {},
    |                                ^^^^^^^^^^
@@ -216,7 +216,7 @@ LL +             B { c: 1, .. } => {},
    |
 
 error: redundant guard
-  --> tests/ui/redundant_guards.rs:200:32
+  --> tests/ui/redundant_guards.rs:212:32
    |
 LL |             B { ref c, .. } if matches!(c, &1) => {},
    |                                ^^^^^^^^^^^^^^^
@@ -228,7 +228,7 @@ LL +             B { c: 1, .. } => {},
    |
 
 error: redundant guard
-  --> tests/ui/redundant_guards.rs:210:26
+  --> tests/ui/redundant_guards.rs:222:26
    |
 LL |         Some(Some(x)) if x.is_empty() => {},
    |                          ^^^^^^^^^^^^
@@ -240,7 +240,7 @@ LL +         Some(Some("")) => {},
    |
 
 error: redundant guard
-  --> tests/ui/redundant_guards.rs:221:26
+  --> tests/ui/redundant_guards.rs:233:26
    |
 LL |         Some(Some(x)) if x.is_empty() => {},
    |                          ^^^^^^^^^^^^
@@ -252,7 +252,7 @@ LL +         Some(Some([])) => {},
    |
 
 error: redundant guard
-  --> tests/ui/redundant_guards.rs:226:26
+  --> tests/ui/redundant_guards.rs:238:26
    |
 LL |         Some(Some(x)) if x.is_empty() => {},
    |                          ^^^^^^^^^^^^
@@ -264,7 +264,7 @@ LL +         Some(Some([])) => {},
    |
 
 error: redundant guard
-  --> tests/ui/redundant_guards.rs:237:26
+  --> tests/ui/redundant_guards.rs:249:26
    |
 LL |         Some(Some(x)) if x.starts_with(&[]) => {},
    |                          ^^^^^^^^^^^^^^^^^^
@@ -276,7 +276,7 @@ LL +         Some(Some([..])) => {},
    |
 
 error: redundant guard
-  --> tests/ui/redundant_guards.rs:242:26
+  --> tests/ui/redundant_guards.rs:254:26
    |
 LL |         Some(Some(x)) if x.starts_with(&[1]) => {},
    |                          ^^^^^^^^^^^^^^^^^^^
@@ -288,7 +288,7 @@ LL +         Some(Some([1, ..])) => {},
    |
 
 error: redundant guard
-  --> tests/ui/redundant_guards.rs:247:26
+  --> tests/ui/redundant_guards.rs:259:26
    |
 LL |         Some(Some(x)) if x.starts_with(&[1, 2]) => {},
    |                          ^^^^^^^^^^^^^^^^^^^^^^
@@ -300,7 +300,7 @@ LL +         Some(Some([1, 2, ..])) => {},
    |
 
 error: redundant guard
-  --> tests/ui/redundant_guards.rs:252:26
+  --> tests/ui/redundant_guards.rs:264:26
    |
 LL |         Some(Some(x)) if x.ends_with(&[1, 2]) => {},
    |                          ^^^^^^^^^^^^^^^^^^^^
@@ -312,7 +312,7 @@ LL +         Some(Some([.., 1, 2])) => {},
    |
 
 error: redundant guard
-  --> tests/ui/redundant_guards.rs:274:18
+  --> tests/ui/redundant_guards.rs:286:18
    |
 LL |             y if y.is_empty() => {},
    |                  ^^^^^^^^^^^^
@@ -324,7 +324,7 @@ LL +             "" => {},
    |
 
 error: redundant guard
-  --> tests/ui/redundant_guards.rs:293:22
+  --> tests/ui/redundant_guards.rs:305:22
    |
 LL |                 y if y.is_empty() => {},
    |                      ^^^^^^^^^^^^
diff --git a/src/tools/clippy/tests/ui/redundant_locals.rs b/src/tools/clippy/tests/ui/redundant_locals.rs
index e9d77182a91..d21aa240b2d 100644
--- a/src/tools/clippy/tests/ui/redundant_locals.rs
+++ b/src/tools/clippy/tests/ui/redundant_locals.rs
@@ -191,14 +191,20 @@ fn issue12225() {
         let v4 = v4;
         dbg!(&v4);
     });
-    assert_static(#[coroutine] static || {
-        let v5 = v5;
-        yield;
-    });
-    assert_static(#[coroutine] || {
-        let v6 = v6;
-        yield;
-    });
+    assert_static(
+        #[coroutine]
+        static || {
+            let v5 = v5;
+            yield;
+        },
+    );
+    assert_static(
+        #[coroutine]
+        || {
+            let v6 = v6;
+            yield;
+        },
+    );
 
     fn foo(a: &str, b: &str) {}
 
diff --git a/src/tools/clippy/tests/ui/single_char_pattern.fixed b/src/tools/clippy/tests/ui/single_char_pattern.fixed
index 9573fdbcfde..a18d6319f89 100644
--- a/src/tools/clippy/tests/ui/single_char_pattern.fixed
+++ b/src/tools/clippy/tests/ui/single_char_pattern.fixed
@@ -1,5 +1,5 @@
 #![allow(clippy::needless_raw_strings, clippy::needless_raw_string_hashes, unused_must_use)]
-
+#![warn(clippy::single_char_pattern)]
 use std::collections::HashSet;
 
 fn main() {
@@ -10,9 +10,9 @@ fn main() {
 
     let y = "x";
     x.split(y);
-    x.split('ß');
-    x.split('ℝ');
-    x.split('💣');
+    x.split("ß");
+    x.split("ℝ");
+    x.split("💣");
     // Can't use this lint for unicode code points which don't fit in a char
     x.split("❤️");
     x.split_inclusive('x');
@@ -34,8 +34,6 @@ fn main() {
     x.rmatch_indices('x');
     x.trim_start_matches('x');
     x.trim_end_matches('x');
-    x.strip_prefix('x');
-    x.strip_suffix('x');
     x.replace('x', "y");
     x.replacen('x', "y", 3);
     // Make sure we escape characters correctly.
@@ -64,4 +62,8 @@ fn main() {
     // Must escape backslash in raw strings when converting to char #8060
     x.split('\\');
     x.split('\\');
+
+    // should not warn, the char versions are actually slower in some cases
+    x.strip_prefix("x");
+    x.strip_suffix("x");
 }
diff --git a/src/tools/clippy/tests/ui/single_char_pattern.rs b/src/tools/clippy/tests/ui/single_char_pattern.rs
index 8a04480dbc6..b52e6fb2fdf 100644
--- a/src/tools/clippy/tests/ui/single_char_pattern.rs
+++ b/src/tools/clippy/tests/ui/single_char_pattern.rs
@@ -1,5 +1,5 @@
 #![allow(clippy::needless_raw_strings, clippy::needless_raw_string_hashes, unused_must_use)]
-
+#![warn(clippy::single_char_pattern)]
 use std::collections::HashSet;
 
 fn main() {
@@ -34,8 +34,6 @@ fn main() {
     x.rmatch_indices("x");
     x.trim_start_matches("x");
     x.trim_end_matches("x");
-    x.strip_prefix("x");
-    x.strip_suffix("x");
     x.replace("x", "y");
     x.replacen("x", "y", 3);
     // Make sure we escape characters correctly.
@@ -64,4 +62,8 @@ fn main() {
     // Must escape backslash in raw strings when converting to char #8060
     x.split(r#"\"#);
     x.split(r"\");
+
+    // should not warn, the char versions are actually slower in some cases
+    x.strip_prefix("x");
+    x.strip_suffix("x");
 }
diff --git a/src/tools/clippy/tests/ui/single_char_pattern.stderr b/src/tools/clippy/tests/ui/single_char_pattern.stderr
index 5a2ec6c764b..b2deed23cbd 100644
--- a/src/tools/clippy/tests/ui/single_char_pattern.stderr
+++ b/src/tools/clippy/tests/ui/single_char_pattern.stderr
@@ -8,24 +8,6 @@ LL |     x.split("x");
    = help: to override `-D warnings` add `#[allow(clippy::single_char_pattern)]`
 
 error: single-character string constant used as pattern
-  --> tests/ui/single_char_pattern.rs:13:13
-   |
-LL |     x.split("ß");
-   |             ^^^ help: consider using a `char`: `'ß'`
-
-error: single-character string constant used as pattern
-  --> tests/ui/single_char_pattern.rs:14:13
-   |
-LL |     x.split("ℝ");
-   |             ^^^ help: consider using a `char`: `'ℝ'`
-
-error: single-character string constant used as pattern
-  --> tests/ui/single_char_pattern.rs:15:13
-   |
-LL |     x.split("💣");
-   |             ^^^^ help: consider using a `char`: `'💣'`
-
-error: single-character string constant used as pattern
   --> tests/ui/single_char_pattern.rs:18:23
    |
 LL |     x.split_inclusive("x");
@@ -140,106 +122,94 @@ LL |     x.trim_end_matches("x");
    |                        ^^^ help: consider using a `char`: `'x'`
 
 error: single-character string constant used as pattern
-  --> tests/ui/single_char_pattern.rs:37:20
-   |
-LL |     x.strip_prefix("x");
-   |                    ^^^ help: consider using a `char`: `'x'`
-
-error: single-character string constant used as pattern
-  --> tests/ui/single_char_pattern.rs:38:20
-   |
-LL |     x.strip_suffix("x");
-   |                    ^^^ help: consider using a `char`: `'x'`
-
-error: single-character string constant used as pattern
-  --> tests/ui/single_char_pattern.rs:39:15
+  --> tests/ui/single_char_pattern.rs:37:15
    |
 LL |     x.replace("x", "y");
    |               ^^^ help: consider using a `char`: `'x'`
 
 error: single-character string constant used as pattern
-  --> tests/ui/single_char_pattern.rs:40:16
+  --> tests/ui/single_char_pattern.rs:38:16
    |
 LL |     x.replacen("x", "y", 3);
    |                ^^^ help: consider using a `char`: `'x'`
 
 error: single-character string constant used as pattern
-  --> tests/ui/single_char_pattern.rs:42:13
+  --> tests/ui/single_char_pattern.rs:40:13
    |
 LL |     x.split("\n");
    |             ^^^^ help: consider using a `char`: `'\n'`
 
 error: single-character string constant used as pattern
-  --> tests/ui/single_char_pattern.rs:43:13
+  --> tests/ui/single_char_pattern.rs:41:13
    |
 LL |     x.split("'");
    |             ^^^ help: consider using a `char`: `'\''`
 
 error: single-character string constant used as pattern
-  --> tests/ui/single_char_pattern.rs:44:13
+  --> tests/ui/single_char_pattern.rs:42:13
    |
 LL |     x.split("\'");
    |             ^^^^ help: consider using a `char`: `'\''`
 
 error: single-character string constant used as pattern
-  --> tests/ui/single_char_pattern.rs:46:13
+  --> tests/ui/single_char_pattern.rs:44:13
    |
 LL |     x.split("\"");
    |             ^^^^ help: consider using a `char`: `'"'`
 
 error: single-character string constant used as pattern
-  --> tests/ui/single_char_pattern.rs:51:31
+  --> tests/ui/single_char_pattern.rs:49:31
    |
 LL |     x.replace(';', ",").split(","); // issue #2978
    |                               ^^^ help: consider using a `char`: `','`
 
 error: single-character string constant used as pattern
-  --> tests/ui/single_char_pattern.rs:52:19
+  --> tests/ui/single_char_pattern.rs:50:19
    |
 LL |     x.starts_with("\x03"); // issue #2996
    |                   ^^^^^^ help: consider using a `char`: `'\x03'`
 
 error: single-character string constant used as pattern
-  --> tests/ui/single_char_pattern.rs:59:13
+  --> tests/ui/single_char_pattern.rs:57:13
    |
 LL |     x.split(r"a");
    |             ^^^^ help: consider using a `char`: `'a'`
 
 error: single-character string constant used as pattern
-  --> tests/ui/single_char_pattern.rs:60:13
+  --> tests/ui/single_char_pattern.rs:58:13
    |
 LL |     x.split(r#"a"#);
    |             ^^^^^^ help: consider using a `char`: `'a'`
 
 error: single-character string constant used as pattern
-  --> tests/ui/single_char_pattern.rs:61:13
+  --> tests/ui/single_char_pattern.rs:59:13
    |
 LL |     x.split(r###"a"###);
    |             ^^^^^^^^^^ help: consider using a `char`: `'a'`
 
 error: single-character string constant used as pattern
-  --> tests/ui/single_char_pattern.rs:62:13
+  --> tests/ui/single_char_pattern.rs:60:13
    |
 LL |     x.split(r###"'"###);
    |             ^^^^^^^^^^ help: consider using a `char`: `'\''`
 
 error: single-character string constant used as pattern
-  --> tests/ui/single_char_pattern.rs:63:13
+  --> tests/ui/single_char_pattern.rs:61:13
    |
 LL |     x.split(r###"#"###);
    |             ^^^^^^^^^^ help: consider using a `char`: `'#'`
 
 error: single-character string constant used as pattern
-  --> tests/ui/single_char_pattern.rs:65:13
+  --> tests/ui/single_char_pattern.rs:63:13
    |
 LL |     x.split(r#"\"#);
    |             ^^^^^^ help: consider using a `char`: `'\\'`
 
 error: single-character string constant used as pattern
-  --> tests/ui/single_char_pattern.rs:66:13
+  --> tests/ui/single_char_pattern.rs:64:13
    |
 LL |     x.split(r"\");
    |             ^^^^ help: consider using a `char`: `'\\'`
 
-error: aborting due to 40 previous errors
+error: aborting due to 35 previous errors
 
diff --git a/src/tools/clippy/tests/ui/thread_local_initializer_can_be_made_const.fixed b/src/tools/clippy/tests/ui/thread_local_initializer_can_be_made_const.fixed
index a6ed59d49c5..4c9bd0bd863 100644
--- a/src/tools/clippy/tests/ui/thread_local_initializer_can_be_made_const.fixed
+++ b/src/tools/clippy/tests/ui/thread_local_initializer_can_be_made_const.fixed
@@ -1,6 +1,6 @@
 #![warn(clippy::thread_local_initializer_can_be_made_const)]
 
-use std::cell::RefCell;
+use std::cell::{Cell, RefCell};
 
 fn main() {
     // lint and suggest const
@@ -36,6 +36,37 @@ fn main() {
     }
 }
 
+fn issue_12637() {
+    /// The set methods on LocalKey<Cell<T>> and LocalKey<RefCell<T>> are
+    /// guaranteed to bypass the thread_local's initialization expression.
+    /// See rust-lang/rust#92122. Thus, = panic!() is a useful idiom for
+    /// forcing the use of set on each thread before it accesses the thread local in any other
+    /// manner.
+    thread_local! {
+        static STATE_12637_PANIC: Cell<usize> = panic!();
+    }
+    STATE_12637_PANIC.set(9);
+    println!("{}", STATE_12637_PANIC.get());
+
+    thread_local! {
+        static STATE_12637_TODO: Cell<usize> = todo!();
+    }
+    STATE_12637_TODO.set(9);
+    println!("{}", STATE_12637_TODO.get());
+
+    thread_local! {
+        static STATE_12637_UNIMPLEMENTED: Cell<usize> = unimplemented!();
+    }
+    STATE_12637_UNIMPLEMENTED.set(9);
+    println!("{}", STATE_12637_UNIMPLEMENTED.get());
+
+    thread_local! {
+        static STATE_12637_UNREACHABLE: Cell<usize> = unreachable!();
+    }
+    STATE_12637_UNREACHABLE.set(9);
+    println!("{}", STATE_12637_UNREACHABLE.get());
+}
+
 #[clippy::msrv = "1.58"]
 fn f() {
     thread_local! {
diff --git a/src/tools/clippy/tests/ui/thread_local_initializer_can_be_made_const.rs b/src/tools/clippy/tests/ui/thread_local_initializer_can_be_made_const.rs
index 3f0159c5806..eb336f0dd19 100644
--- a/src/tools/clippy/tests/ui/thread_local_initializer_can_be_made_const.rs
+++ b/src/tools/clippy/tests/ui/thread_local_initializer_can_be_made_const.rs
@@ -1,6 +1,6 @@
 #![warn(clippy::thread_local_initializer_can_be_made_const)]
 
-use std::cell::RefCell;
+use std::cell::{Cell, RefCell};
 
 fn main() {
     // lint and suggest const
@@ -36,6 +36,37 @@ fn main() {
     }
 }
 
+fn issue_12637() {
+    /// The set methods on LocalKey<Cell<T>> and LocalKey<RefCell<T>> are
+    /// guaranteed to bypass the thread_local's initialization expression.
+    /// See rust-lang/rust#92122. Thus, = panic!() is a useful idiom for
+    /// forcing the use of set on each thread before it accesses the thread local in any other
+    /// manner.
+    thread_local! {
+        static STATE_12637_PANIC: Cell<usize> = panic!();
+    }
+    STATE_12637_PANIC.set(9);
+    println!("{}", STATE_12637_PANIC.get());
+
+    thread_local! {
+        static STATE_12637_TODO: Cell<usize> = todo!();
+    }
+    STATE_12637_TODO.set(9);
+    println!("{}", STATE_12637_TODO.get());
+
+    thread_local! {
+        static STATE_12637_UNIMPLEMENTED: Cell<usize> = unimplemented!();
+    }
+    STATE_12637_UNIMPLEMENTED.set(9);
+    println!("{}", STATE_12637_UNIMPLEMENTED.get());
+
+    thread_local! {
+        static STATE_12637_UNREACHABLE: Cell<usize> = unreachable!();
+    }
+    STATE_12637_UNREACHABLE.set(9);
+    println!("{}", STATE_12637_UNREACHABLE.get());
+}
+
 #[clippy::msrv = "1.58"]
 fn f() {
     thread_local! {
diff --git a/src/tools/clippy/tests/ui/type_complexity.rs b/src/tools/clippy/tests/ui/type_complexity.rs
index b057dc4e89f..be28ee2da0c 100644
--- a/src/tools/clippy/tests/ui/type_complexity.rs
+++ b/src/tools/clippy/tests/ui/type_complexity.rs
@@ -1,5 +1,3 @@
-//@compile-flags: -Zdeduplicate-diagnostics=yes
-
 #![warn(clippy::all)]
 #![allow(unused, clippy::needless_pass_by_value, clippy::vec_box, clippy::useless_vec)]
 #![feature(associated_type_defaults)]
diff --git a/src/tools/clippy/tests/ui/type_complexity.stderr b/src/tools/clippy/tests/ui/type_complexity.stderr
index bfbab8647e8..9e27899e4f9 100644
--- a/src/tools/clippy/tests/ui/type_complexity.stderr
+++ b/src/tools/clippy/tests/ui/type_complexity.stderr
@@ -1,5 +1,5 @@
 error: very complex type used. Consider factoring parts into `type` definitions
-  --> tests/ui/type_complexity.rs:9:12
+  --> tests/ui/type_complexity.rs:7:12
    |
 LL | const CST: (u32, (u32, (u32, (u32, u32)))) = (0, (0, (0, (0, 0))));
    |            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -8,85 +8,85 @@ LL | const CST: (u32, (u32, (u32, (u32, u32)))) = (0, (0, (0, (0, 0))));
    = help: to override `-D warnings` add `#[allow(clippy::type_complexity)]`
 
 error: very complex type used. Consider factoring parts into `type` definitions
-  --> tests/ui/type_complexity.rs:12:12
+  --> tests/ui/type_complexity.rs:10:12
    |
 LL | static ST: (u32, (u32, (u32, (u32, u32)))) = (0, (0, (0, (0, 0))));
    |            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: very complex type used. Consider factoring parts into `type` definitions
-  --> tests/ui/type_complexity.rs:16:8
+  --> tests/ui/type_complexity.rs:14:8
    |
 LL |     f: Vec<Vec<Box<(u32, u32, u32, u32)>>>,
    |        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: very complex type used. Consider factoring parts into `type` definitions
-  --> tests/ui/type_complexity.rs:20:11
+  --> tests/ui/type_complexity.rs:18:11
    |
 LL | struct Ts(Vec<Vec<Box<(u32, u32, u32, u32)>>>);
    |           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: very complex type used. Consider factoring parts into `type` definitions
-  --> tests/ui/type_complexity.rs:24:11
+  --> tests/ui/type_complexity.rs:22:11
    |
 LL |     Tuple(Vec<Vec<Box<(u32, u32, u32, u32)>>>),
    |           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: very complex type used. Consider factoring parts into `type` definitions
-  --> tests/ui/type_complexity.rs:26:17
+  --> tests/ui/type_complexity.rs:24:17
    |
 LL |     Struct { f: Vec<Vec<Box<(u32, u32, u32, u32)>>> },
    |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: very complex type used. Consider factoring parts into `type` definitions
-  --> tests/ui/type_complexity.rs:31:14
+  --> tests/ui/type_complexity.rs:29:14
    |
 LL |     const A: (u32, (u32, (u32, (u32, u32)))) = (0, (0, (0, (0, 0))));
    |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: very complex type used. Consider factoring parts into `type` definitions
-  --> tests/ui/type_complexity.rs:33:30
+  --> tests/ui/type_complexity.rs:31:30
    |
 LL |     fn impl_method(&self, p: Vec<Vec<Box<(u32, u32, u32, u32)>>>) {}
    |                              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: very complex type used. Consider factoring parts into `type` definitions
-  --> tests/ui/type_complexity.rs:38:14
+  --> tests/ui/type_complexity.rs:36:14
    |
 LL |     const A: Vec<Vec<Box<(u32, u32, u32, u32)>>>;
    |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: very complex type used. Consider factoring parts into `type` definitions
-  --> tests/ui/type_complexity.rs:40:14
+  --> tests/ui/type_complexity.rs:38:14
    |
 LL |     type B = Vec<Vec<Box<(u32, u32, u32, u32)>>>;
    |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: very complex type used. Consider factoring parts into `type` definitions
-  --> tests/ui/type_complexity.rs:42:25
+  --> tests/ui/type_complexity.rs:40:25
    |
 LL |     fn method(&self, p: Vec<Vec<Box<(u32, u32, u32, u32)>>>);
    |                         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: very complex type used. Consider factoring parts into `type` definitions
-  --> tests/ui/type_complexity.rs:44:29
+  --> tests/ui/type_complexity.rs:42:29
    |
 LL |     fn def_method(&self, p: Vec<Vec<Box<(u32, u32, u32, u32)>>>) {}
    |                             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: very complex type used. Consider factoring parts into `type` definitions
-  --> tests/ui/type_complexity.rs:57:15
+  --> tests/ui/type_complexity.rs:55:15
    |
 LL | fn test1() -> Vec<Vec<Box<(u32, u32, u32, u32)>>> {
    |               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: very complex type used. Consider factoring parts into `type` definitions
-  --> tests/ui/type_complexity.rs:62:14
+  --> tests/ui/type_complexity.rs:60:14
    |
 LL | fn test2(_x: Vec<Vec<Box<(u32, u32, u32, u32)>>>) {}
    |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: very complex type used. Consider factoring parts into `type` definitions
-  --> tests/ui/type_complexity.rs:66:13
+  --> tests/ui/type_complexity.rs:64:13
    |
 LL |     let _y: Vec<Vec<Box<(u32, u32, u32, u32)>>> = vec![];
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
diff --git a/src/tools/clippy/tests/ui/type_id_on_box_unfixable.rs b/src/tools/clippy/tests/ui/type_id_on_box_unfixable.rs
index f6d09834adb..67e398e604b 100644
--- a/src/tools/clippy/tests/ui/type_id_on_box_unfixable.rs
+++ b/src/tools/clippy/tests/ui/type_id_on_box_unfixable.rs
@@ -19,7 +19,7 @@ where
 impl<T> NormalTrait for T {}
 
 fn main() {
-    // (currently we don't look deeper than one level into the supertrait hierachy, but we probably
+    // (currently we don't look deeper than one level into the supertrait hierarchy, but we probably
     // could)
     let b: Box<dyn AnySubSubTrait> = Box::new(1);
     let _ = b.type_id();
diff --git a/src/tools/clippy/triagebot.toml b/src/tools/clippy/triagebot.toml
index 901977da25b..4d66b728b76 100644
--- a/src/tools/clippy/triagebot.toml
+++ b/src/tools/clippy/triagebot.toml
@@ -20,7 +20,6 @@ new_pr = true
 [assign]
 contributing_url = "https://github.com/rust-lang/rust-clippy/blob/master/CONTRIBUTING.md"
 users_on_vacation = [
-    "y21",
     "matthiaskrgr",
     "giraffate",
     "Centri3",
diff --git a/src/tools/clippy/util/gh-pages/script.js b/src/tools/clippy/util/gh-pages/script.js
index f59245e556c..c63edd5bf70 100644
--- a/src/tools/clippy/util/gh-pages/script.js
+++ b/src/tools/clippy/util/gh-pages/script.js
@@ -415,7 +415,7 @@
                 let terms = searchStr.split(" ");
                 let docsLowerCase = lint.docs.toLowerCase();
                 for (index = 0; index < terms.length; index++) {
-                    // This is more likely and will therefor be checked first
+                    // This is more likely and will therefore be checked first
                     if (docsLowerCase.indexOf(terms[index]) !== -1) {
                         continue;
                     }