about summary refs log tree commit diff
diff options
context:
space:
mode:
authorPhilipp Krones <hello@philkrones.com>2024-07-11 15:44:03 +0200
committerPhilipp Krones <hello@philkrones.com>2024-07-11 15:44:03 +0200
commit2ed6ed41beebb2aa2ffc91ab0da4c5f70c40366b (patch)
treef7ee58daa96b6179271bf0ccf98b5ff00ec17d4d
parentfdf7ea6b5b1cac83c0f29e681202cf18bf25b01c (diff)
parentb794b8e08c16517a941dc598bb1483e8e12a8592 (diff)
downloadrust-2ed6ed41beebb2aa2ffc91ab0da4c5f70c40366b.tar.gz
rust-2ed6ed41beebb2aa2ffc91ab0da4c5f70c40366b.zip
Merge commit 'b794b8e08c16517a941dc598bb1483e8e12a8592' into clippy-subtree-update
-rw-r--r--src/tools/clippy/.github/workflows/lintcheck.yml4
-rw-r--r--src/tools/clippy/CHANGELOG.md6
-rw-r--r--src/tools/clippy/book/src/lint_configuration.md3
-rw-r--r--src/tools/clippy/clippy.toml4
-rw-r--r--src/tools/clippy/clippy_config/src/conf.rs3
-rw-r--r--src/tools/clippy/clippy_config/src/msrvs.rs4
-rw-r--r--src/tools/clippy/clippy_dev/src/new_lint.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/almost_complete_range.rs104
-rw-r--r--src/tools/clippy/clippy_lints/src/assertions_on_constants.rs20
-rw-r--r--src/tools/clippy/clippy_lints/src/assigning_clones.rs496
-rw-r--r--src/tools/clippy/clippy_lints/src/await_holding_invalid.rs46
-rw-r--r--src/tools/clippy/clippy_lints/src/bool_to_int_with_if.rs134
-rw-r--r--src/tools/clippy/clippy_lints/src/byte_char_slices.rs80
-rw-r--r--src/tools/clippy/clippy_lints/src/casts/mod.rs113
-rw-r--r--src/tools/clippy/clippy_lints/src/casts/ptr_as_ptr.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/cfg_not_test.rs60
-rw-r--r--src/tools/clippy/clippy_lints/src/declared_lints.rs10
-rw-r--r--src/tools/clippy/clippy_lints/src/default.rs10
-rw-r--r--src/tools/clippy/clippy_lints/src/default_numeric_fallback.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/dereference.rs37
-rw-r--r--src/tools/clippy/clippy_lints/src/disallowed_methods.rs42
-rw-r--r--src/tools/clippy/clippy_lints/src/disallowed_names.rs46
-rw-r--r--src/tools/clippy/clippy_lints/src/disallowed_script_idents.rs41
-rw-r--r--src/tools/clippy/clippy_lints/src/doc/lazy_continuation.rs29
-rw-r--r--src/tools/clippy/clippy_lints/src/doc/mod.rs21
-rw-r--r--src/tools/clippy/clippy_lints/src/endian_bytes.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/functions/impl_trait_in_params.rs8
-rw-r--r--src/tools/clippy/clippy_lints/src/incompatible_msrv.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/inherent_to_string.rs5
-rw-r--r--src/tools/clippy/clippy_lints/src/init_numbered_fields.rs87
-rw-r--r--src/tools/clippy/clippy_lints/src/inline_fn_without_body.rs41
-rw-r--r--src/tools/clippy/clippy_lints/src/instant_subtraction.rs21
-rw-r--r--src/tools/clippy/clippy_lints/src/items_after_statements.rs59
-rw-r--r--src/tools/clippy/clippy_lints/src/iter_not_returning_iterator.rs21
-rw-r--r--src/tools/clippy/clippy_lints/src/iter_without_into_iter.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/large_const_arrays.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/large_enum_variant.rs17
-rw-r--r--src/tools/clippy/clippy_lints/src/large_futures.rs43
-rw-r--r--src/tools/clippy/clippy_lints/src/large_include_file.rs20
-rw-r--r--src/tools/clippy/clippy_lints/src/legacy_numeric_constants.rs46
-rw-r--r--src/tools/clippy/clippy_lints/src/len_zero.rs19
-rw-r--r--src/tools/clippy/clippy_lints/src/let_if_seq.rs8
-rw-r--r--src/tools/clippy/clippy_lints/src/let_underscore.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/let_with_type_underscore.rs17
-rw-r--r--src/tools/clippy/clippy_lints/src/lib.rs24
-rw-r--r--src/tools/clippy/clippy_lints/src/literal_representation.rs16
-rw-r--r--src/tools/clippy/clippy_lints/src/manual_bits.rs5
-rw-r--r--src/tools/clippy/clippy_lints/src/manual_float_methods.rs29
-rw-r--r--src/tools/clippy/clippy_lints/src/manual_let_else.rs6
-rw-r--r--src/tools/clippy/clippy_lints/src/manual_main_separator_str.rs8
-rw-r--r--src/tools/clippy/clippy_lints/src/manual_non_exhaustive.rs14
-rw-r--r--src/tools/clippy/clippy_lints/src/manual_range_patterns.rs5
-rw-r--r--src/tools/clippy/clippy_lints/src/manual_rem_euclid.rs49
-rw-r--r--src/tools/clippy/clippy_lints/src/manual_retain.rs3
-rw-r--r--src/tools/clippy/clippy_lints/src/manual_rotate.rs117
-rw-r--r--src/tools/clippy/clippy_lints/src/manual_slice_size_calculation.rs6
-rw-r--r--src/tools/clippy/clippy_lints/src/manual_strip.rs7
-rw-r--r--src/tools/clippy/clippy_lints/src/manual_unwrap_or_default.rs9
-rw-r--r--src/tools/clippy/clippy_lints/src/map_unit_fn.rs13
-rw-r--r--src/tools/clippy/clippy_lints/src/matches/mod.rs13
-rw-r--r--src/tools/clippy/clippy_lints/src/matches/significant_drop_in_scrutinee.rs111
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/manual_inspect.rs26
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/mod.rs9
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/unnecessary_to_owned.rs70
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/unwrap_expect_used.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/minmax.rs37
-rw-r--r--src/tools/clippy/clippy_lints/src/misc.rs6
-rw-r--r--src/tools/clippy/clippy_lints/src/missing_assert_message.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/missing_const_for_fn.rs33
-rw-r--r--src/tools/clippy/clippy_lints/src/missing_const_for_thread_local.rs (renamed from src/tools/clippy/clippy_lints/src/thread_local_initializer_can_be_made_const.rs)14
-rw-r--r--src/tools/clippy/clippy_lints/src/needless_pass_by_ref_mut.rs11
-rw-r--r--src/tools/clippy/clippy_lints/src/no_effect.rs11
-rw-r--r--src/tools/clippy/clippy_lints/src/operators/float_cmp.rs1
-rw-r--r--src/tools/clippy/clippy_lints/src/operators/mod.rs140
-rw-r--r--src/tools/clippy/clippy_lints/src/overflow_check_conditional.rs70
-rw-r--r--src/tools/clippy/clippy_lints/src/panicking_overflow_checks.rs86
-rw-r--r--src/tools/clippy/clippy_lints/src/renamed_lints.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/returns.rs47
-rw-r--r--src/tools/clippy/clippy_lints/src/same_name_method.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/set_contains_or_insert.rs125
-rw-r--r--src/tools/clippy/clippy_lints/src/utils/internal_lints.rs1
-rw-r--r--src/tools/clippy/clippy_lints/src/utils/internal_lints/compiler_lint_functions.rs73
-rw-r--r--src/tools/clippy/clippy_lints/src/wildcard_imports.rs19
-rw-r--r--src/tools/clippy/clippy_lints/src/write.rs5
-rw-r--r--src/tools/clippy/clippy_utils/src/lib.rs67
-rw-r--r--src/tools/clippy/clippy_utils/src/paths.rs1
-rw-r--r--src/tools/clippy/clippy_utils/src/ty.rs26
-rw-r--r--src/tools/clippy/lintcheck/Cargo.toml1
-rw-r--r--src/tools/clippy/lintcheck/README.md16
-rw-r--r--src/tools/clippy/lintcheck/lintcheck_crates.toml52
-rw-r--r--src/tools/clippy/lintcheck/src/config.rs4
-rw-r--r--src/tools/clippy/lintcheck/src/driver.rs2
-rw-r--r--src/tools/clippy/lintcheck/src/input.rs288
-rw-r--r--src/tools/clippy/lintcheck/src/json.rs99
-rw-r--r--src/tools/clippy/lintcheck/src/main.rs595
-rw-r--r--src/tools/clippy/lintcheck/src/output.rs235
-rw-r--r--src/tools/clippy/lintcheck/src/popular_crates.rs2
-rw-r--r--src/tools/clippy/lintcheck/src/recursive.rs7
-rw-r--r--src/tools/clippy/rust-toolchain3
-rw-r--r--src/tools/clippy/tests/ui-internal/disallow_span_lint.stderr16
-rw-r--r--src/tools/clippy/tests/ui-toml/await_holding_invalid_type/await_holding_invalid_type.stderr6
-rw-r--r--src/tools/clippy/tests/ui-toml/needless_pass_by_ref_mut/clippy.toml1
-rw-r--r--src/tools/clippy/tests/ui-toml/needless_pass_by_ref_mut/needless_pass_by_ref_mut.fixed10
-rw-r--r--src/tools/clippy/tests/ui-toml/needless_pass_by_ref_mut/needless_pass_by_ref_mut.rs10
-rw-r--r--src/tools/clippy/tests/ui-toml/needless_pass_by_ref_mut/needless_pass_by_ref_mut.stderr12
-rw-r--r--src/tools/clippy/tests/ui-toml/toml_disallowed_methods/conf_disallowed_methods.stderr36
-rw-r--r--src/tools/clippy/tests/ui/assertions_on_constants.rs11
-rw-r--r--src/tools/clippy/tests/ui/assertions_on_constants.stderr18
-rw-r--r--src/tools/clippy/tests/ui/await_holding_lock.rs26
-rw-r--r--src/tools/clippy/tests/ui/await_holding_lock.stderr78
-rw-r--r--src/tools/clippy/tests/ui/await_holding_refcell_ref.rs12
-rw-r--r--src/tools/clippy/tests/ui/await_holding_refcell_ref.stderr24
-rw-r--r--src/tools/clippy/tests/ui/byte_char_slices.fixed13
-rw-r--r--src/tools/clippy/tests/ui/byte_char_slices.rs13
-rw-r--r--src/tools/clippy/tests/ui/byte_char_slices.stderr38
-rw-r--r--src/tools/clippy/tests/ui/cfg_not_test.rs32
-rw-r--r--src/tools/clippy/tests/ui/cfg_not_test.stderr45
-rw-r--r--src/tools/clippy/tests/ui/crashes/ice-12616.stderr2
-rw-r--r--src/tools/clippy/tests/ui/disallowed_names.rs1
-rw-r--r--src/tools/clippy/tests/ui/doc/doc_lazy_blank_line.fixed47
-rw-r--r--src/tools/clippy/tests/ui/doc/doc_lazy_blank_line.rs43
-rw-r--r--src/tools/clippy/tests/ui/doc/doc_lazy_blank_line.stderr56
-rw-r--r--src/tools/clippy/tests/ui/doc/doc_lazy_blockquote.fixed12
-rw-r--r--src/tools/clippy/tests/ui/doc/doc_lazy_blockquote.rs12
-rw-r--r--src/tools/clippy/tests/ui/doc/doc_lazy_blockquote.stderr12
-rw-r--r--src/tools/clippy/tests/ui/doc/doc_lazy_list.fixed31
-rw-r--r--src/tools/clippy/tests/ui/doc/doc_lazy_list.rs22
-rw-r--r--src/tools/clippy/tests/ui/doc/doc_lazy_list.stderr49
-rw-r--r--src/tools/clippy/tests/ui/doc/unbalanced_ticks.rs17
-rw-r--r--src/tools/clippy/tests/ui/doc/unbalanced_ticks.stderr18
-rw-r--r--src/tools/clippy/tests/ui/explicit_auto_deref.fixed36
-rw-r--r--src/tools/clippy/tests/ui/explicit_auto_deref.rs36
-rw-r--r--src/tools/clippy/tests/ui/explicit_auto_deref.stderr8
-rw-r--r--src/tools/clippy/tests/ui/float_cmp.rs6
-rw-r--r--src/tools/clippy/tests/ui/float_cmp.stderr21
-rw-r--r--src/tools/clippy/tests/ui/float_cmp_const.rs8
-rw-r--r--src/tools/clippy/tests/ui/float_cmp_const.stderr29
-rw-r--r--src/tools/clippy/tests/ui/init_numbered_fields.fixed (renamed from src/tools/clippy/tests/ui/numbered_fields.fixed)9
-rw-r--r--src/tools/clippy/tests/ui/init_numbered_fields.rs (renamed from src/tools/clippy/tests/ui/numbered_fields.rs)9
-rw-r--r--src/tools/clippy/tests/ui/init_numbered_fields.stderr (renamed from src/tools/clippy/tests/ui/numbered_fields.stderr)12
-rw-r--r--src/tools/clippy/tests/ui/into_iter_without_iter.rs39
-rw-r--r--src/tools/clippy/tests/ui/iter_next_loop.rs2
-rw-r--r--src/tools/clippy/tests/ui/iter_next_loop.stderr10
-rw-r--r--src/tools/clippy/tests/ui/manual_inspect.stderr24
-rw-r--r--src/tools/clippy/tests/ui/manual_rotate.fixed31
-rw-r--r--src/tools/clippy/tests/ui/manual_rotate.rs31
-rw-r--r--src/tools/clippy/tests/ui/manual_rotate.stderr71
-rw-r--r--src/tools/clippy/tests/ui/missing_const_for_fn/cant_be_const.rs18
-rw-r--r--src/tools/clippy/tests/ui/missing_const_for_fn/could_be_const.fixed30
-rw-r--r--src/tools/clippy/tests/ui/missing_const_for_fn/could_be_const.rs30
-rw-r--r--src/tools/clippy/tests/ui/missing_const_for_fn/could_be_const.stderr41
-rw-r--r--src/tools/clippy/tests/ui/missing_const_for_fn/could_be_const_with_const_extern_fn.fixed14
-rw-r--r--src/tools/clippy/tests/ui/missing_const_for_fn/could_be_const_with_const_extern_fn.rs14
-rw-r--r--src/tools/clippy/tests/ui/missing_const_for_fn/could_be_const_with_const_extern_fn.stderr59
-rw-r--r--src/tools/clippy/tests/ui/missing_const_for_thread_local.fixed (renamed from src/tools/clippy/tests/ui/thread_local_initializer_can_be_made_const.fixed)2
-rw-r--r--src/tools/clippy/tests/ui/missing_const_for_thread_local.rs (renamed from src/tools/clippy/tests/ui/thread_local_initializer_can_be_made_const.rs)2
-rw-r--r--src/tools/clippy/tests/ui/missing_const_for_thread_local.stderr (renamed from src/tools/clippy/tests/ui/thread_local_initializer_can_be_made_const.stderr)16
-rw-r--r--src/tools/clippy/tests/ui/needless_pass_by_ref_mut.rs18
-rw-r--r--src/tools/clippy/tests/ui/needless_pass_by_ref_mut.stderr52
-rw-r--r--src/tools/clippy/tests/ui/needless_pass_by_ref_mut2.fixed4
-rw-r--r--src/tools/clippy/tests/ui/needless_pass_by_ref_mut2.rs4
-rw-r--r--src/tools/clippy/tests/ui/needless_pass_by_ref_mut2.stderr15
-rw-r--r--src/tools/clippy/tests/ui/needless_return.fixed35
-rw-r--r--src/tools/clippy/tests/ui/needless_return.rs35
-rw-r--r--src/tools/clippy/tests/ui/needless_return.stderr28
-rw-r--r--src/tools/clippy/tests/ui/overflow_check_conditional.rs36
-rw-r--r--src/tools/clippy/tests/ui/overflow_check_conditional.stderr53
-rw-r--r--src/tools/clippy/tests/ui/panicking_overflow_checks.rs27
-rw-r--r--src/tools/clippy/tests/ui/panicking_overflow_checks.stderr41
-rw-r--r--src/tools/clippy/tests/ui/ptr_as_ptr.stderr66
-rw-r--r--src/tools/clippy/tests/ui/rename.fixed4
-rw-r--r--src/tools/clippy/tests/ui/rename.rs4
-rw-r--r--src/tools/clippy/tests/ui/rename.stderr130
-rw-r--r--src/tools/clippy/tests/ui/set_contains_or_insert.rs83
-rw-r--r--src/tools/clippy/tests/ui/set_contains_or_insert.stderr61
-rw-r--r--src/tools/clippy/tests/ui/significant_drop_in_scrutinee.rs26
-rw-r--r--src/tools/clippy/tests/ui/significant_drop_in_scrutinee.stderr29
-rw-r--r--src/tools/clippy/tests/ui/unnecessary_operation.fixed14
-rw-r--r--src/tools/clippy/tests/ui/unnecessary_operation.rs14
-rw-r--r--src/tools/clippy/tests/ui/unnecessary_operation.stderr8
-rw-r--r--src/tools/clippy/tests/ui/unnecessary_to_owned.fixed19
-rw-r--r--src/tools/clippy/tests/ui/unnecessary_to_owned.rs19
-rw-r--r--src/tools/clippy/tests/ui/unnecessary_to_owned.stderr60
-rw-r--r--src/tools/clippy/tests/ui/wildcard_imports.fixed3
-rw-r--r--src/tools/clippy/tests/ui/wildcard_imports.rs3
-rw-r--r--src/tools/clippy/tests/ui/wildcard_imports.stderr10
-rw-r--r--src/tools/clippy/tests/ui/wildcard_imports_2021.edition2018.fixed3
-rw-r--r--src/tools/clippy/tests/ui/wildcard_imports_2021.edition2018.stderr10
-rw-r--r--src/tools/clippy/tests/ui/wildcard_imports_2021.edition2021.fixed3
-rw-r--r--src/tools/clippy/tests/ui/wildcard_imports_2021.edition2021.stderr10
-rw-r--r--src/tools/clippy/tests/ui/wildcard_imports_2021.rs3
191 files changed, 4147 insertions, 2494 deletions
diff --git a/src/tools/clippy/.github/workflows/lintcheck.yml b/src/tools/clippy/.github/workflows/lintcheck.yml
index 91c98b3a256..f016a770059 100644
--- a/src/tools/clippy/.github/workflows/lintcheck.yml
+++ b/src/tools/clippy/.github/workflows/lintcheck.yml
@@ -58,7 +58,7 @@ jobs:
 
     - name: Run lintcheck
       if: steps.cache-json.outputs.cache-hit != 'true'
-      run: ./target/debug/lintcheck --format json
+      run: ./target/debug/lintcheck --format json --warn-all
 
     - name: Upload base JSON
       uses: actions/upload-artifact@v4
@@ -86,7 +86,7 @@ jobs:
       run: cargo build --manifest-path=lintcheck/Cargo.toml
 
     - name: Run lintcheck
-      run: ./target/debug/lintcheck --format json
+      run: ./target/debug/lintcheck --format json --warn-all
 
     - name: Upload head JSON
       uses: actions/upload-artifact@v4
diff --git a/src/tools/clippy/CHANGELOG.md b/src/tools/clippy/CHANGELOG.md
index 70ef2c79364..55281f3cbec 100644
--- a/src/tools/clippy/CHANGELOG.md
+++ b/src/tools/clippy/CHANGELOG.md
@@ -5236,6 +5236,7 @@ Released 2018-09-13
 [`boxed_local`]: https://rust-lang.github.io/rust-clippy/master/index.html#boxed_local
 [`branches_sharing_code`]: https://rust-lang.github.io/rust-clippy/master/index.html#branches_sharing_code
 [`builtin_type_shadow`]: https://rust-lang.github.io/rust-clippy/master/index.html#builtin_type_shadow
+[`byte_char_slices`]: https://rust-lang.github.io/rust-clippy/master/index.html#byte_char_slices
 [`bytes_count_to_len`]: https://rust-lang.github.io/rust-clippy/master/index.html#bytes_count_to_len
 [`bytes_nth`]: https://rust-lang.github.io/rust-clippy/master/index.html#bytes_nth
 [`cargo_common_metadata`]: https://rust-lang.github.io/rust-clippy/master/index.html#cargo_common_metadata
@@ -5253,6 +5254,7 @@ Released 2018-09-13
 [`cast_sign_loss`]: https://rust-lang.github.io/rust-clippy/master/index.html#cast_sign_loss
 [`cast_slice_different_sizes`]: https://rust-lang.github.io/rust-clippy/master/index.html#cast_slice_different_sizes
 [`cast_slice_from_raw_parts`]: https://rust-lang.github.io/rust-clippy/master/index.html#cast_slice_from_raw_parts
+[`cfg_not_test`]: https://rust-lang.github.io/rust-clippy/master/index.html#cfg_not_test
 [`char_lit_as_u8`]: https://rust-lang.github.io/rust-clippy/master/index.html#char_lit_as_u8
 [`chars_last_cmp`]: https://rust-lang.github.io/rust-clippy/master/index.html#chars_last_cmp
 [`chars_next_cmp`]: https://rust-lang.github.io/rust-clippy/master/index.html#chars_next_cmp
@@ -5539,6 +5541,7 @@ Released 2018-09-13
 [`manual_range_patterns`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_range_patterns
 [`manual_rem_euclid`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_rem_euclid
 [`manual_retain`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_retain
+[`manual_rotate`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_rotate
 [`manual_saturating_arithmetic`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_saturating_arithmetic
 [`manual_slice_size_calculation`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_slice_size_calculation
 [`manual_split_once`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_split_once
@@ -5587,6 +5590,7 @@ Released 2018-09-13
 [`missing_assert_message`]: https://rust-lang.github.io/rust-clippy/master/index.html#missing_assert_message
 [`missing_asserts_for_indexing`]: https://rust-lang.github.io/rust-clippy/master/index.html#missing_asserts_for_indexing
 [`missing_const_for_fn`]: https://rust-lang.github.io/rust-clippy/master/index.html#missing_const_for_fn
+[`missing_const_for_thread_local`]: https://rust-lang.github.io/rust-clippy/master/index.html#missing_const_for_thread_local
 [`missing_docs_in_private_items`]: https://rust-lang.github.io/rust-clippy/master/index.html#missing_docs_in_private_items
 [`missing_enforced_import_renames`]: https://rust-lang.github.io/rust-clippy/master/index.html#missing_enforced_import_renames
 [`missing_errors_doc`]: https://rust-lang.github.io/rust-clippy/master/index.html#missing_errors_doc
@@ -5701,6 +5705,7 @@ Released 2018-09-13
 [`panic`]: https://rust-lang.github.io/rust-clippy/master/index.html#panic
 [`panic_in_result_fn`]: https://rust-lang.github.io/rust-clippy/master/index.html#panic_in_result_fn
 [`panic_params`]: https://rust-lang.github.io/rust-clippy/master/index.html#panic_params
+[`panicking_overflow_checks`]: https://rust-lang.github.io/rust-clippy/master/index.html#panicking_overflow_checks
 [`panicking_unwrap`]: https://rust-lang.github.io/rust-clippy/master/index.html#panicking_unwrap
 [`partial_pub_fields`]: https://rust-lang.github.io/rust-clippy/master/index.html#partial_pub_fields
 [`partialeq_ne_impl`]: https://rust-lang.github.io/rust-clippy/master/index.html#partialeq_ne_impl
@@ -5797,6 +5802,7 @@ Released 2018-09-13
 [`semicolon_outside_block`]: https://rust-lang.github.io/rust-clippy/master/index.html#semicolon_outside_block
 [`separated_literal_suffix`]: https://rust-lang.github.io/rust-clippy/master/index.html#separated_literal_suffix
 [`serde_api_misuse`]: https://rust-lang.github.io/rust-clippy/master/index.html#serde_api_misuse
+[`set_contains_or_insert`]: https://rust-lang.github.io/rust-clippy/master/index.html#set_contains_or_insert
 [`shadow_reuse`]: https://rust-lang.github.io/rust-clippy/master/index.html#shadow_reuse
 [`shadow_same`]: https://rust-lang.github.io/rust-clippy/master/index.html#shadow_same
 [`shadow_unrelated`]: https://rust-lang.github.io/rust-clippy/master/index.html#shadow_unrelated
diff --git a/src/tools/clippy/book/src/lint_configuration.md b/src/tools/clippy/book/src/lint_configuration.md
index cfd34c7d2a7..ad29339a84a 100644
--- a/src/tools/clippy/book/src/lint_configuration.md
+++ b/src/tools/clippy/book/src/lint_configuration.md
@@ -348,6 +348,7 @@ Suppress lints whenever the suggested change would cause breakage for other crat
 * [`enum_variant_names`](https://rust-lang.github.io/rust-clippy/master/index.html#enum_variant_names)
 * [`large_types_passed_by_value`](https://rust-lang.github.io/rust-clippy/master/index.html#large_types_passed_by_value)
 * [`linkedlist`](https://rust-lang.github.io/rust-clippy/master/index.html#linkedlist)
+* [`needless_pass_by_ref_mut`](https://rust-lang.github.io/rust-clippy/master/index.html#needless_pass_by_ref_mut)
 * [`option_option`](https://rust-lang.github.io/rust-clippy/master/index.html#option_option)
 * [`rc_buffer`](https://rust-lang.github.io/rust-clippy/master/index.html#rc_buffer)
 * [`rc_mutex`](https://rust-lang.github.io/rust-clippy/master/index.html#rc_mutex)
@@ -454,7 +455,7 @@ default configuration of Clippy. By default, any configuration will replace the
 * `doc-valid-idents = ["ClipPy"]` would replace the default list with `["ClipPy"]`.
 * `doc-valid-idents = ["ClipPy", ".."]` would append `ClipPy` to the default list.
 
-**Default Value:** `["KiB", "MiB", "GiB", "TiB", "PiB", "EiB", "DevOps", "DirectX", "ECMAScript", "GPLv2", "GPLv3", "GitHub", "GitLab", "IPv4", "IPv6", "ClojureScript", "CoffeeScript", "JavaScript", "PureScript", "TypeScript", "WebAssembly", "NaN", "NaNs", "OAuth", "GraphQL", "OCaml", "OpenDNS", "OpenGL", "OpenMP", "OpenSSH", "OpenSSL", "OpenStreetMap", "OpenTelemetry", "WebGL", "WebGL2", "WebGPU", "TensorFlow", "TrueType", "iOS", "macOS", "FreeBSD", "TeX", "LaTeX", "BibTeX", "BibLaTeX", "MinGW", "CamelCase"]`
+**Default Value:** `["KiB", "MiB", "GiB", "TiB", "PiB", "EiB", "DevOps", "DirectX", "ECMAScript", "GPLv2", "GPLv3", "GitHub", "GitLab", "IPv4", "IPv6", "ClojureScript", "CoffeeScript", "JavaScript", "PureScript", "TypeScript", "WebAssembly", "NaN", "NaNs", "OAuth", "GraphQL", "OCaml", "OpenDNS", "OpenGL", "OpenMP", "OpenSSH", "OpenSSL", "OpenStreetMap", "OpenTelemetry", "WebGL", "WebGL2", "WebGPU", "WebP", "OpenExr", "YCbCr", "sRGB", "TensorFlow", "TrueType", "iOS", "macOS", "FreeBSD", "TeX", "LaTeX", "BibTeX", "BibLaTeX", "MinGW", "CamelCase"]`
 
 ---
 **Affected lints:**
diff --git a/src/tools/clippy/clippy.toml b/src/tools/clippy/clippy.toml
index 62ed55beb1f..319b72e8c5d 100644
--- a/src/tools/clippy/clippy.toml
+++ b/src/tools/clippy/clippy.toml
@@ -1,6 +1,10 @@
 avoid-breaking-exported-api = false
 
 [[disallowed-methods]]
+path = "rustc_lint::context::LintContext::lint"
+reason = "this function does not add a link to our documentation, please use the `clippy_utils::diagnostics::span_lint*` functions instead"
+
+[[disallowed-methods]]
 path = "rustc_lint::context::LintContext::span_lint"
 reason = "this function does not add a link to our documentation, please use the `clippy_utils::diagnostics::span_lint*` functions instead"
 
diff --git a/src/tools/clippy/clippy_config/src/conf.rs b/src/tools/clippy/clippy_config/src/conf.rs
index dbab3b106a8..7f53aad6793 100644
--- a/src/tools/clippy/clippy_config/src/conf.rs
+++ b/src/tools/clippy/clippy_config/src/conf.rs
@@ -31,6 +31,7 @@ const DEFAULT_DOC_VALID_IDENTS: &[&str] = &[
     "OCaml",
     "OpenDNS", "OpenGL", "OpenMP", "OpenSSH", "OpenSSL", "OpenStreetMap", "OpenTelemetry",
     "WebGL", "WebGL2", "WebGPU",
+    "WebP", "OpenExr", "YCbCr", "sRGB",
     "TensorFlow",
     "TrueType",
     "iOS", "macOS", "FreeBSD",
@@ -262,7 +263,7 @@ define_Conf! {
     /// arithmetic-side-effects-allowed-unary = ["SomeType", "AnotherType"]
     /// ```
     (arithmetic_side_effects_allowed_unary: FxHashSet<String> = <_>::default()),
-    /// Lint: ENUM_VARIANT_NAMES, LARGE_TYPES_PASSED_BY_VALUE, TRIVIALLY_COPY_PASS_BY_REF, UNNECESSARY_WRAPS, UNUSED_SELF, UPPER_CASE_ACRONYMS, WRONG_SELF_CONVENTION, BOX_COLLECTION, REDUNDANT_ALLOCATION, RC_BUFFER, VEC_BOX, OPTION_OPTION, LINKEDLIST, RC_MUTEX, UNNECESSARY_BOX_RETURNS, SINGLE_CALL_FN.
+    /// Lint: ENUM_VARIANT_NAMES, LARGE_TYPES_PASSED_BY_VALUE, TRIVIALLY_COPY_PASS_BY_REF, UNNECESSARY_WRAPS, UNUSED_SELF, UPPER_CASE_ACRONYMS, WRONG_SELF_CONVENTION, BOX_COLLECTION, REDUNDANT_ALLOCATION, RC_BUFFER, VEC_BOX, OPTION_OPTION, LINKEDLIST, RC_MUTEX, UNNECESSARY_BOX_RETURNS, SINGLE_CALL_FN, NEEDLESS_PASS_BY_REF_MUT.
     ///
     /// Suppress lints whenever the suggested change would cause breakage for other crates.
     (avoid_breaking_exported_api: bool = true),
diff --git a/src/tools/clippy/clippy_config/src/msrvs.rs b/src/tools/clippy/clippy_config/src/msrvs.rs
index a5761d3270c..fc56ac51796 100644
--- a/src/tools/clippy/clippy_config/src/msrvs.rs
+++ b/src/tools/clippy/clippy_config/src/msrvs.rs
@@ -25,8 +25,8 @@ msrv_aliases! {
     1,68,0 { PATH_MAIN_SEPARATOR_STR }
     1,65,0 { LET_ELSE, POINTER_CAST_CONSTNESS }
     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,62,0 { BOOL_THEN_SOME, DEFAULT_ENUM_ATTRIBUTE, CONST_EXTERN_FN }
+    1,59,0 { THREAD_LOCAL_CONST_INIT }
     1,58,0 { FORMAT_ARGS_CAPTURE, PATTERN_TRAIT_CHAR_ARRAY, CONST_RAW_PTR_DEREF }
     1,56,0 { CONST_FN_UNION }
     1,55,0 { SEEK_REWIND }
diff --git a/src/tools/clippy/clippy_dev/src/new_lint.rs b/src/tools/clippy/clippy_dev/src/new_lint.rs
index 2e56eb8ec15..d762e30ef02 100644
--- a/src/tools/clippy/clippy_dev/src/new_lint.rs
+++ b/src/tools/clippy/clippy_dev/src/new_lint.rs
@@ -273,7 +273,7 @@ fn get_lint_file_contents(lint: &LintData<'_>, enable_msrv: bool) -> String {
     result.push_str(&if enable_msrv {
         formatdoc!(
             r#"
-            use clippy_utils::msrvs::{{self, Msrv}};
+            use clippy_config::msrvs::{{self, Msrv}};
             {pass_import}
             use rustc_lint::{{{context_import}, {pass_type}, LintContext}};
             use rustc_session::impl_lint_pass;
@@ -399,7 +399,7 @@ fn create_lint_for_ty(lint: &LintData<'_>, enable_msrv: bool, ty: &str) -> io::R
         let _: fmt::Result = writedoc!(
             lint_file_contents,
             r#"
-                use clippy_utils::msrvs::{{self, Msrv}};
+                use clippy_config::msrvs::{{self, Msrv}};
                 use rustc_lint::{{{context_import}, LintContext}};
 
                 use super::{name_upper};
diff --git a/src/tools/clippy/clippy_lints/src/almost_complete_range.rs b/src/tools/clippy/clippy_lints/src/almost_complete_range.rs
index 57a5cd8fba8..96e9c949b75 100644
--- a/src/tools/clippy/clippy_lints/src/almost_complete_range.rs
+++ b/src/tools/clippy/clippy_lints/src/almost_complete_range.rs
@@ -6,7 +6,6 @@ use rustc_errors::Applicability;
 use rustc_lint::{EarlyContext, EarlyLintPass, LintContext};
 use rustc_middle::lint::in_external_macro;
 use rustc_session::impl_lint_pass;
-use rustc_span::Span;
 
 declare_clippy_lint! {
     /// ### What it does
@@ -41,61 +40,80 @@ impl AlmostCompleteRange {
 }
 impl EarlyLintPass for AlmostCompleteRange {
     fn check_expr(&mut self, cx: &EarlyContext<'_>, e: &Expr) {
-        if let ExprKind::Range(Some(start), Some(end), RangeLimits::HalfOpen) = &e.kind {
-            let ctxt = e.span.ctxt();
-            let sugg = if let Some(start) = walk_span_to_context(start.span, ctxt)
-                && let Some(end) = walk_span_to_context(end.span, ctxt)
-                && self.msrv.meets(msrvs::RANGE_INCLUSIVE)
-            {
-                Some((trim_span(cx.sess().source_map(), start.between(end)), "..="))
-            } else {
-                None
-            };
-            check_range(cx, e.span, start, end, sugg);
+        if let ExprKind::Range(Some(start), Some(end), RangeLimits::HalfOpen) = &e.kind
+            && is_incomplete_range(start, end)
+            && !in_external_macro(cx.sess(), e.span)
+        {
+            span_lint_and_then(
+                cx,
+                ALMOST_COMPLETE_RANGE,
+                e.span,
+                "almost complete ascii range",
+                |diag| {
+                    let ctxt = e.span.ctxt();
+                    if let Some(start) = walk_span_to_context(start.span, ctxt)
+                        && let Some(end) = walk_span_to_context(end.span, ctxt)
+                        && self.msrv.meets(msrvs::RANGE_INCLUSIVE)
+                    {
+                        diag.span_suggestion(
+                            trim_span(cx.sess().source_map(), start.between(end)),
+                            "use an inclusive range",
+                            "..=".to_owned(),
+                            Applicability::MaybeIncorrect,
+                        );
+                    }
+                },
+            );
         }
     }
 
     fn check_pat(&mut self, cx: &EarlyContext<'_>, p: &Pat) {
         if let PatKind::Range(Some(start), Some(end), kind) = &p.kind
             && matches!(kind.node, RangeEnd::Excluded)
+            && is_incomplete_range(start, end)
+            && !in_external_macro(cx.sess(), p.span)
         {
-            let sugg = if self.msrv.meets(msrvs::RANGE_INCLUSIVE) {
-                "..="
-            } else {
-                "..."
-            };
-            check_range(cx, p.span, start, end, Some((kind.span, sugg)));
+            span_lint_and_then(
+                cx,
+                ALMOST_COMPLETE_RANGE,
+                p.span,
+                "almost complete ascii range",
+                |diag| {
+                    diag.span_suggestion(
+                        kind.span,
+                        "use an inclusive range",
+                        if self.msrv.meets(msrvs::RANGE_INCLUSIVE) {
+                            "..=".to_owned()
+                        } else {
+                            "...".to_owned()
+                        },
+                        Applicability::MaybeIncorrect,
+                    );
+                },
+            );
         }
     }
 
     extract_msrv_attr!(EarlyContext);
 }
 
-fn check_range(cx: &EarlyContext<'_>, span: Span, start: &Expr, end: &Expr, sugg: Option<(Span, &str)>) {
-    if let ExprKind::Lit(start_token_lit) = start.peel_parens().kind
-        && let ExprKind::Lit(end_token_lit) = end.peel_parens().kind
-        && matches!(
-            (
-                LitKind::from_token_lit(start_token_lit),
-                LitKind::from_token_lit(end_token_lit),
-            ),
-            (
-                Ok(LitKind::Byte(b'a') | LitKind::Char('a')),
-                Ok(LitKind::Byte(b'z') | LitKind::Char('z'))
-            ) | (
-                Ok(LitKind::Byte(b'A') | LitKind::Char('A')),
-                Ok(LitKind::Byte(b'Z') | LitKind::Char('Z')),
-            ) | (
-                Ok(LitKind::Byte(b'0') | LitKind::Char('0')),
-                Ok(LitKind::Byte(b'9') | LitKind::Char('9')),
+fn is_incomplete_range(start: &Expr, end: &Expr) -> bool {
+    match (&start.peel_parens().kind, &end.peel_parens().kind) {
+        (&ExprKind::Lit(start_lit), &ExprKind::Lit(end_lit)) => {
+            matches!(
+                (LitKind::from_token_lit(start_lit), LitKind::from_token_lit(end_lit),),
+                (
+                    Ok(LitKind::Byte(b'a') | LitKind::Char('a')),
+                    Ok(LitKind::Byte(b'z') | LitKind::Char('z'))
+                ) | (
+                    Ok(LitKind::Byte(b'A') | LitKind::Char('A')),
+                    Ok(LitKind::Byte(b'Z') | LitKind::Char('Z')),
+                ) | (
+                    Ok(LitKind::Byte(b'0') | LitKind::Char('0')),
+                    Ok(LitKind::Byte(b'9') | LitKind::Char('9')),
+                )
             )
-        )
-        && !in_external_macro(cx.sess(), span)
-    {
-        span_lint_and_then(cx, ALMOST_COMPLETE_RANGE, span, "almost complete ascii range", |diag| {
-            if let Some((span, sugg)) = sugg {
-                diag.span_suggestion(span, "use an inclusive range", sugg, Applicability::MaybeIncorrect);
-            }
-        });
+        },
+        _ => false,
     }
 }
diff --git a/src/tools/clippy/clippy_lints/src/assertions_on_constants.rs b/src/tools/clippy/clippy_lints/src/assertions_on_constants.rs
index 2003dd1fb0e..ed4cdce8cb8 100644
--- a/src/tools/clippy/clippy_lints/src/assertions_on_constants.rs
+++ b/src/tools/clippy/clippy_lints/src/assertions_on_constants.rs
@@ -1,7 +1,8 @@
-use clippy_utils::consts::{constant_with_source, Constant, ConstantSource};
+use clippy_utils::consts::{constant, Constant};
 use clippy_utils::diagnostics::span_lint_and_help;
+use clippy_utils::is_inside_always_const_context;
 use clippy_utils::macros::{find_assert_args, root_macro_call_first_node, PanicExpn};
-use rustc_hir::{Expr, Item, ItemKind, Node};
+use rustc_hir::{Expr, ExprKind};
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_session::declare_lint_pass;
 use rustc_span::sym;
@@ -42,17 +43,16 @@ impl<'tcx> LateLintPass<'tcx> for AssertionsOnConstants {
         let Some((condition, panic_expn)) = find_assert_args(cx, e, macro_call.expn) else {
             return;
         };
-        let Some((Constant::Bool(val), source)) = constant_with_source(cx, cx.typeck_results(), condition) else {
+        let Some(Constant::Bool(val)) = constant(cx, cx.typeck_results(), condition) else {
             return;
         };
-        if let ConstantSource::Constant = source
-            && let Node::Item(Item {
-                kind: ItemKind::Const(..),
-                ..
-            }) = cx.tcx.parent_hir_node(e.hir_id)
-        {
-            return;
+
+        match condition.kind {
+            ExprKind::Path(..) | ExprKind::Lit(_) => {},
+            _ if is_inside_always_const_context(cx.tcx, e.hir_id) => return,
+            _ => {},
         }
+
         if val {
             span_lint_and_help(
                 cx,
diff --git a/src/tools/clippy/clippy_lints/src/assigning_clones.rs b/src/tools/clippy/clippy_lints/src/assigning_clones.rs
index 406f38f411e..0de0031ed24 100644
--- a/src/tools/clippy/clippy_lints/src/assigning_clones.rs
+++ b/src/tools/clippy/clippy_lints/src/assigning_clones.rs
@@ -1,18 +1,16 @@
 use clippy_config::msrvs::{self, Msrv};
 use clippy_utils::diagnostics::span_lint_and_then;
-use clippy_utils::macros::HirNode;
 use clippy_utils::mir::{enclosing_mir, PossibleBorrowerMap};
 use clippy_utils::sugg::Sugg;
-use clippy_utils::{is_trait_method, local_is_initialized, path_to_local};
+use clippy_utils::{is_diag_trait_item, last_path_segment, local_is_initialized, path_to_local};
 use rustc_errors::Applicability;
 use rustc_hir::{self as hir, Expr, ExprKind};
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_middle::mir;
 use rustc_middle::ty::{self, Instance, Mutability};
 use rustc_session::impl_lint_pass;
-use rustc_span::def_id::DefId;
 use rustc_span::symbol::sym;
-use rustc_span::{ExpnKind, Span, SyntaxContext};
+use rustc_span::{Span, SyntaxContext};
 
 declare_clippy_lint! {
     /// ### What it does
@@ -68,165 +66,82 @@ impl AssigningClones {
 impl_lint_pass!(AssigningClones => [ASSIGNING_CLONES]);
 
 impl<'tcx> LateLintPass<'tcx> for AssigningClones {
-    fn check_expr(&mut self, cx: &LateContext<'tcx>, assign_expr: &'tcx Expr<'_>) {
-        // Do not fire the lint in macros
-        let ctxt = assign_expr.span().ctxt();
-        let expn_data = ctxt.outer_expn_data();
-        match expn_data.kind {
-            ExpnKind::AstPass(_) | ExpnKind::Desugaring(_) | ExpnKind::Macro(..) => return,
-            ExpnKind::Root => {},
-        }
-
-        let ExprKind::Assign(lhs, rhs, _span) = assign_expr.kind else {
-            return;
-        };
-
-        let Some(call) = extract_call(cx, rhs) else {
-            return;
-        };
-
-        if is_ok_to_suggest(cx, lhs, &call, &self.msrv) {
-            suggest(cx, ctxt, assign_expr, lhs, &call);
-        }
-    }
-
-    extract_msrv_attr!(LateContext);
-}
-
-// Try to resolve the call to `Clone::clone` or `ToOwned::to_owned`.
-fn extract_call<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) -> Option<CallCandidate<'tcx>> {
-    let fn_def_id = clippy_utils::fn_def_id(cx, expr)?;
-
-    // Fast paths to only check method calls without arguments or function calls with a single argument
-    let (target, kind, resolved_method) = match expr.kind {
-        ExprKind::MethodCall(path, receiver, [], _span) => {
-            let args = cx.typeck_results().node_args(expr.hir_id);
-
-            // If we could not resolve the method, don't apply the lint
-            let Ok(Some(resolved_method)) = Instance::try_resolve(cx.tcx, cx.param_env, fn_def_id, args) else {
-                return None;
-            };
-            if is_trait_method(cx, expr, sym::Clone) && path.ident.name == sym::clone {
-                (TargetTrait::Clone, CallKind::MethodCall { receiver }, resolved_method)
-            } else if is_trait_method(cx, expr, sym::ToOwned) && path.ident.name.as_str() == "to_owned" {
-                (TargetTrait::ToOwned, CallKind::MethodCall { receiver }, resolved_method)
-            } else {
-                return None;
+    fn check_expr(&mut self, cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) {
+        if let ExprKind::Assign(lhs, rhs, _) = e.kind
+            && let typeck = cx.typeck_results()
+            && let (call_kind, fn_name, fn_id, fn_arg, fn_gen_args) = match rhs.kind {
+                ExprKind::Call(f, [arg])
+                    if let ExprKind::Path(fn_path) = &f.kind
+                        && let Some(id) = typeck.qpath_res(fn_path, f.hir_id).opt_def_id() =>
+                {
+                    (CallKind::Ufcs, last_path_segment(fn_path).ident.name, id, arg, typeck.node_args(f.hir_id))
+                },
+                ExprKind::MethodCall(name, recv, [], _) if let Some(id) = typeck.type_dependent_def_id(rhs.hir_id) => {
+                    (CallKind::Method, name.ident.name, id, recv, typeck.node_args(rhs.hir_id))
+                },
+                _ => return,
             }
-        },
-        ExprKind::Call(function, [arg]) => {
-            let kind = cx.typeck_results().node_type(function.hir_id).kind();
-
-            // If we could not resolve the method, don't apply the lint
-            let Ok(Some(resolved_method)) = (match kind {
-                ty::FnDef(_, args) => Instance::try_resolve(cx.tcx, cx.param_env, fn_def_id, args),
-                _ => Ok(None),
-            }) else {
-                return None;
-            };
-            if cx.tcx.is_diagnostic_item(sym::to_owned_method, fn_def_id) {
-                (
-                    TargetTrait::ToOwned,
-                    CallKind::FunctionCall { self_arg: arg },
-                    resolved_method,
-                )
-            } else if let Some(trait_did) = cx.tcx.trait_of_item(fn_def_id)
-                && cx.tcx.is_diagnostic_item(sym::Clone, trait_did)
-            {
-                (
-                    TargetTrait::Clone,
-                    CallKind::FunctionCall { self_arg: arg },
-                    resolved_method,
-                )
-            } else {
-                return None;
+            && let ctxt = e.span.ctxt()
+            // Don't lint in macros.
+            && ctxt.is_root()
+            && let which_trait = match fn_name {
+                sym::clone if is_diag_trait_item(cx, fn_id, sym::Clone) => CloneTrait::Clone,
+                _ if fn_name.as_str() == "to_owned"
+                    && is_diag_trait_item(cx, fn_id, sym::ToOwned)
+                    && self.msrv.meets(msrvs::CLONE_INTO) =>
+                {
+                    CloneTrait::ToOwned
+                },
+                _ => return,
             }
-        },
-        _ => return None,
-    };
-
-    Some(CallCandidate {
-        span: expr.span,
-        target,
-        kind,
-        method_def_id: resolved_method.def_id(),
-    })
-}
-
-// Return true if we find that the called method has a custom implementation and isn't derived or
-// provided by default by the corresponding trait.
-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::CLONE_INTO) && matches!(call.target, TargetTrait::ToOwned) {
-        return false;
-    }
-
-    // If the left-hand side is a local variable, it might be uninitialized at this point.
-    // In that case we do not want to suggest the lint.
-    if let Some(local) = path_to_local(lhs) {
-        // TODO: This check currently bails if the local variable has no initializer.
-        // That is overly conservative - the lint should fire even if there was no initializer,
-        // but the variable has been initialized before `lhs` was evaluated.
-        if !local_is_initialized(cx, local) {
-            return false;
-        }
-    }
-
-    let Some(impl_block) = cx.tcx.impl_of_method(call.method_def_id) else {
-        return false;
-    };
-
-    // If the method implementation comes from #[derive(Clone)], then don't suggest the lint.
-    // Automatically generated Clone impls do not currently override `clone_from`.
-    // See e.g. https://github.com/rust-lang/rust/pull/98445#issuecomment-1190681305 for more details.
-    if cx.tcx.is_builtin_derived(impl_block) {
-        return false;
-    }
-
-    // If the call expression is inside an impl block that contains the method invoked by the
-    // call expression, we bail out to avoid suggesting something that could result in endless
-    // recursion.
-    if let Some(local_block_id) = impl_block.as_local()
-        && let Some(block) = cx.tcx.hir_node_by_def_id(local_block_id).as_owner()
-    {
-        let impl_block_owner = block.def_id();
-        if cx
-            .tcx
-            .hir()
-            .parent_id_iter(lhs.hir_id)
-            .any(|parent| parent.owner == impl_block_owner)
+            && let Ok(Some(resolved_fn)) = Instance::try_resolve(cx.tcx, cx.param_env, fn_id, fn_gen_args)
+            // TODO: This check currently bails if the local variable has no initializer.
+            // That is overly conservative - the lint should fire even if there was no initializer,
+            // but the variable has been initialized before `lhs` was evaluated.
+            && path_to_local(lhs).map_or(true, |lhs| local_is_initialized(cx, lhs))
+            && let Some(resolved_impl) = cx.tcx.impl_of_method(resolved_fn.def_id())
+            // Derived forms don't implement `clone_from`/`clone_into`.
+            // See https://github.com/rust-lang/rust/pull/98445#issuecomment-1190681305
+            && !cx.tcx.is_builtin_derived(resolved_impl)
+            // Don't suggest calling a function we're implementing.
+            && resolved_impl.as_local().map_or(true, |block_id| {
+                cx.tcx.hir().parent_owner_iter(e.hir_id).all(|(id, _)| id.def_id != block_id)
+            })
+            && let resolved_assoc_items = cx.tcx.associated_items(resolved_impl)
+            // Only suggest if `clone_from`/`clone_into` is explicitly implemented
+            && resolved_assoc_items.in_definition_order().any(|assoc|
+                match which_trait {
+                    CloneTrait::Clone => assoc.name == sym::clone_from,
+                    CloneTrait::ToOwned => assoc.name.as_str() == "clone_into",
+                }
+            )
+            && !clone_source_borrows_from_dest(cx, lhs, rhs.span)
         {
-            return false;
+            span_lint_and_then(
+                cx,
+                ASSIGNING_CLONES,
+                e.span,
+                match which_trait {
+                    CloneTrait::Clone => "assigning the result of `Clone::clone()` may be inefficient",
+                    CloneTrait::ToOwned => "assigning the result of `ToOwned::to_owned()` may be inefficient",
+                },
+                |diag| {
+                    let mut app = Applicability::Unspecified;
+                    diag.span_suggestion(
+                        e.span,
+                        match which_trait {
+                            CloneTrait::Clone => "use `clone_from()`",
+                            CloneTrait::ToOwned => "use `clone_into()`",
+                        },
+                        build_sugg(cx, ctxt, lhs, fn_arg, which_trait, call_kind, &mut app),
+                        app,
+                    );
+                },
+            );
         }
     }
 
-    // Find the function for which we want to check that it is implemented.
-    let provided_fn = match call.target {
-        TargetTrait::Clone => cx.tcx.get_diagnostic_item(sym::Clone).and_then(|clone| {
-            cx.tcx
-                .provided_trait_methods(clone)
-                .find(|item| item.name == sym::clone_from)
-        }),
-        TargetTrait::ToOwned => cx.tcx.get_diagnostic_item(sym::ToOwned).and_then(|to_owned| {
-            cx.tcx
-                .provided_trait_methods(to_owned)
-                .find(|item| item.name.as_str() == "clone_into")
-        }),
-    };
-    let Some(provided_fn) = provided_fn else {
-        return false;
-    };
-
-    if clone_source_borrows_from_dest(cx, lhs, call.span) {
-        return false;
-    }
-
-    // Now take a look if the impl block defines an implementation for the method that we're interested
-    // in. If not, then we're using a default implementation, which is not interesting, so we will
-    // not suggest the lint.
-    let implemented_fns = cx.tcx.impl_item_implementor_ids(impl_block);
-    implemented_fns.contains_key(&provided_fn.def_id)
+    extract_msrv_attr!(LateContext);
 }
 
 /// Checks if the data being cloned borrows from the place that is being assigned to:
@@ -239,16 +154,6 @@ fn is_ok_to_suggest<'tcx>(cx: &LateContext<'tcx>, lhs: &Expr<'tcx>, call: &CallC
 ///
 /// This cannot be written `s2.clone_into(&mut s)` because it has conflicting borrows.
 fn clone_source_borrows_from_dest(cx: &LateContext<'_>, lhs: &Expr<'_>, call_span: Span) -> bool {
-    /// If this basic block only exists to drop a local as part of an assignment, returns its
-    /// successor. Otherwise returns the basic block that was passed in.
-    fn skip_drop_block(mir: &mir::Body<'_>, bb: mir::BasicBlock) -> mir::BasicBlock {
-        if let mir::TerminatorKind::Drop { target, .. } = mir.basic_blocks[bb].terminator().kind {
-            target
-        } else {
-            bb
-        }
-    }
-
     let Some(mir) = enclosing_mir(cx.tcx, lhs.hir_id) else {
         return false;
     };
@@ -267,172 +172,123 @@ fn clone_source_borrows_from_dest(cx: &LateContext<'_>, lhs: &Expr<'_>, call_spa
     //
     // bb2:
     //  s = s_temp
-    for bb in mir.basic_blocks.iter() {
-        let terminator = bb.terminator();
-
-        // Look for the to_owned/clone call.
-        if terminator.source_info.span != call_span {
-            continue;
+    if let Some(terminator) = mir.basic_blocks.iter()
+            .map(mir::BasicBlockData::terminator)
+            .find(|term| term.source_info.span == call_span)
+        && let mir::TerminatorKind::Call { ref args, target: Some(assign_bb), .. } = terminator.kind
+        && let [source] = &**args
+        && let mir::Operand::Move(source) = &source.node
+        && let assign_bb = &mir.basic_blocks[assign_bb]
+        && let assign_bb = match assign_bb.terminator().kind {
+            // Skip the drop of the assignment's destination.
+            mir::TerminatorKind::Drop { target, .. } => &mir.basic_blocks[target],
+            _ => assign_bb,
         }
-
-        if let mir::TerminatorKind::Call { ref args, target: Some(assign_bb), .. } = terminator.kind
-            && let [source] = &**args
-            && let mir::Operand::Move(source) = &source.node
-            && let assign_bb = skip_drop_block(mir, assign_bb)
-            // Skip any storage statements as they are just noise
-            && let Some(assignment) = mir.basic_blocks[assign_bb].statements
-                .iter()
-                .find(|stmt| {
-                    !matches!(stmt.kind, mir::StatementKind::StorageDead(_) | mir::StatementKind::StorageLive(_))
-                })
-            && let mir::StatementKind::Assign(box (borrowed, _)) = &assignment.kind
-            && let Some(borrowers) = borrow_map.get(&borrowed.local)
-            && borrowers.contains(source.local)
-        {
-            return true;
-        }
-
-        return false;
+        // Skip any storage statements as they are just noise
+        && let Some(assignment) = assign_bb.statements
+            .iter()
+            .find(|stmt| {
+                !matches!(stmt.kind, mir::StatementKind::StorageDead(_) | mir::StatementKind::StorageLive(_))
+            })
+        && let mir::StatementKind::Assign(box (borrowed, _)) = &assignment.kind
+        && let Some(borrowers) = borrow_map.get(&borrowed.local)
+    {
+        borrowers.contains(source.local)
+    } else {
+        false
     }
-    false
-}
-
-fn suggest<'tcx>(
-    cx: &LateContext<'tcx>,
-    ctxt: SyntaxContext,
-    assign_expr: &Expr<'tcx>,
-    lhs: &Expr<'tcx>,
-    call: &CallCandidate<'tcx>,
-) {
-    span_lint_and_then(cx, ASSIGNING_CLONES, assign_expr.span, call.message(), |diag| {
-        let mut applicability = Applicability::Unspecified;
-
-        diag.span_suggestion(
-            assign_expr.span,
-            call.suggestion_msg(),
-            call.suggested_replacement(cx, ctxt, lhs, &mut applicability),
-            applicability,
-        );
-    });
 }
 
-#[derive(Copy, Clone, Debug)]
-enum CallKind<'tcx> {
-    MethodCall { receiver: &'tcx Expr<'tcx> },
-    FunctionCall { self_arg: &'tcx Expr<'tcx> },
-}
-
-#[derive(Copy, Clone, Debug)]
-enum TargetTrait {
+#[derive(Clone, Copy)]
+enum CloneTrait {
     Clone,
     ToOwned,
 }
 
-#[derive(Debug)]
-struct CallCandidate<'tcx> {
-    span: Span,
-    target: TargetTrait,
-    kind: CallKind<'tcx>,
-    // DefId of the called method from an impl block that implements the target trait
-    method_def_id: DefId,
+#[derive(Copy, Clone)]
+enum CallKind {
+    Ufcs,
+    Method,
 }
 
-impl<'tcx> CallCandidate<'tcx> {
-    #[inline]
-    fn message(&self) -> &'static str {
-        match self.target {
-            TargetTrait::Clone => "assigning the result of `Clone::clone()` may be inefficient",
-            TargetTrait::ToOwned => "assigning the result of `ToOwned::to_owned()` may be inefficient",
-        }
-    }
-
-    #[inline]
-    fn suggestion_msg(&self) -> &'static str {
-        match self.target {
-            TargetTrait::Clone => "use `clone_from()`",
-            TargetTrait::ToOwned => "use `clone_into()`",
-        }
-    }
-
-    fn suggested_replacement(
-        &self,
-        cx: &LateContext<'tcx>,
-        ctxt: SyntaxContext,
-        lhs: &Expr<'tcx>,
-        applicability: &mut Applicability,
-    ) -> String {
-        match self.target {
-            TargetTrait::Clone => {
-                match self.kind {
-                    CallKind::MethodCall { receiver } => {
-                        let receiver_sugg = if let ExprKind::Unary(hir::UnOp::Deref, ref_expr) = lhs.kind {
-                            // `*lhs = self_expr.clone();` -> `lhs.clone_from(self_expr)`
-                            Sugg::hir_with_applicability(cx, ref_expr, "_", applicability)
-                        } else {
-                            // `lhs = self_expr.clone();` -> `lhs.clone_from(self_expr)`
-                            Sugg::hir_with_applicability(cx, lhs, "_", applicability)
-                        }
-                        .maybe_par();
-
-                        // Determine whether we need to reference the argument to clone_from().
-                        let clone_receiver_type = cx.typeck_results().expr_ty(receiver);
-                        let clone_receiver_adj_type = cx.typeck_results().expr_ty_adjusted(receiver);
-                        let mut arg_sugg = Sugg::hir_with_context(cx, receiver, ctxt, "_", applicability);
-                        if clone_receiver_type != clone_receiver_adj_type {
-                            // The receiver may have been a value type, so we need to add an `&` to
-                            // be sure the argument to clone_from will be a reference.
-                            arg_sugg = arg_sugg.addr();
-                        };
-
-                        format!("{receiver_sugg}.clone_from({arg_sugg})")
-                    },
-                    CallKind::FunctionCall { self_arg, .. } => {
-                        let self_sugg = if let ExprKind::Unary(hir::UnOp::Deref, ref_expr) = lhs.kind {
-                            // `*lhs = Clone::clone(self_expr);` -> `Clone::clone_from(lhs, self_expr)`
-                            Sugg::hir_with_applicability(cx, ref_expr, "_", applicability)
-                        } else {
-                            // `lhs = Clone::clone(self_expr);` -> `Clone::clone_from(&mut lhs, self_expr)`
-                            Sugg::hir_with_applicability(cx, lhs, "_", applicability).mut_addr()
-                        };
-                        // The RHS had to be exactly correct before the call, there is no auto-deref for function calls.
-                        let rhs_sugg = Sugg::hir_with_context(cx, self_arg, ctxt, "_", applicability);
-
-                        format!("Clone::clone_from({self_sugg}, {rhs_sugg})")
-                    },
-                }
-            },
-            TargetTrait::ToOwned => {
-                let rhs_sugg = if let ExprKind::Unary(hir::UnOp::Deref, ref_expr) = lhs.kind {
-                    // `*lhs = rhs.to_owned()` -> `rhs.clone_into(lhs)`
-                    // `*lhs = ToOwned::to_owned(rhs)` -> `ToOwned::clone_into(rhs, lhs)`
-                    let sugg = Sugg::hir_with_applicability(cx, ref_expr, "_", applicability).maybe_par();
-                    let inner_type = cx.typeck_results().expr_ty(ref_expr);
-                    // If after unwrapping the dereference, the type is not a mutable reference, we add &mut to make it
-                    // deref to a mutable reference.
-                    if matches!(inner_type.kind(), ty::Ref(_, _, Mutability::Mut)) {
-                        sugg
+fn build_sugg<'tcx>(
+    cx: &LateContext<'tcx>,
+    ctxt: SyntaxContext,
+    lhs: &'tcx Expr<'_>,
+    fn_arg: &'tcx Expr<'_>,
+    which_trait: CloneTrait,
+    call_kind: CallKind,
+    app: &mut Applicability,
+) -> String {
+    match which_trait {
+        CloneTrait::Clone => {
+            match call_kind {
+                CallKind::Method => {
+                    let receiver_sugg = if let ExprKind::Unary(hir::UnOp::Deref, ref_expr) = lhs.kind {
+                        // `*lhs = self_expr.clone();` -> `lhs.clone_from(self_expr)`
+                        Sugg::hir_with_applicability(cx, ref_expr, "_", app)
                     } else {
-                        sugg.mut_addr()
+                        // `lhs = self_expr.clone();` -> `lhs.clone_from(self_expr)`
+                        Sugg::hir_with_applicability(cx, lhs, "_", app)
                     }
+                    .maybe_par();
+
+                    // Determine whether we need to reference the argument to clone_from().
+                    let clone_receiver_type = cx.typeck_results().expr_ty(fn_arg);
+                    let clone_receiver_adj_type = cx.typeck_results().expr_ty_adjusted(fn_arg);
+                    let mut arg_sugg = Sugg::hir_with_context(cx, fn_arg, ctxt, "_", app);
+                    if clone_receiver_type != clone_receiver_adj_type {
+                        // The receiver may have been a value type, so we need to add an `&` to
+                        // be sure the argument to clone_from will be a reference.
+                        arg_sugg = arg_sugg.addr();
+                    };
+
+                    format!("{receiver_sugg}.clone_from({arg_sugg})")
+                },
+                CallKind::Ufcs => {
+                    let self_sugg = if let ExprKind::Unary(hir::UnOp::Deref, ref_expr) = lhs.kind {
+                        // `*lhs = Clone::clone(self_expr);` -> `Clone::clone_from(lhs, self_expr)`
+                        Sugg::hir_with_applicability(cx, ref_expr, "_", app)
+                    } else {
+                        // `lhs = Clone::clone(self_expr);` -> `Clone::clone_from(&mut lhs, self_expr)`
+                        Sugg::hir_with_applicability(cx, lhs, "_", app).mut_addr()
+                    };
+                    // The RHS had to be exactly correct before the call, there is no auto-deref for function calls.
+                    let rhs_sugg = Sugg::hir_with_context(cx, fn_arg, ctxt, "_", app);
+
+                    format!("Clone::clone_from({self_sugg}, {rhs_sugg})")
+                },
+            }
+        },
+        CloneTrait::ToOwned => {
+            let rhs_sugg = if let ExprKind::Unary(hir::UnOp::Deref, ref_expr) = lhs.kind {
+                // `*lhs = rhs.to_owned()` -> `rhs.clone_into(lhs)`
+                // `*lhs = ToOwned::to_owned(rhs)` -> `ToOwned::clone_into(rhs, lhs)`
+                let sugg = Sugg::hir_with_applicability(cx, ref_expr, "_", app).maybe_par();
+                let inner_type = cx.typeck_results().expr_ty(ref_expr);
+                // If after unwrapping the dereference, the type is not a mutable reference, we add &mut to make it
+                // deref to a mutable reference.
+                if matches!(inner_type.kind(), ty::Ref(_, _, Mutability::Mut)) {
+                    sugg
                 } else {
-                    // `lhs = rhs.to_owned()` -> `rhs.clone_into(&mut lhs)`
-                    // `lhs = ToOwned::to_owned(rhs)` -> `ToOwned::clone_into(rhs, &mut lhs)`
-                    Sugg::hir_with_applicability(cx, lhs, "_", applicability)
-                        .maybe_par()
-                        .mut_addr()
-                };
-
-                match self.kind {
-                    CallKind::MethodCall { receiver } => {
-                        let receiver_sugg = Sugg::hir_with_context(cx, receiver, ctxt, "_", applicability);
-                        format!("{receiver_sugg}.clone_into({rhs_sugg})")
-                    },
-                    CallKind::FunctionCall { self_arg, .. } => {
-                        let self_sugg = Sugg::hir_with_context(cx, self_arg, ctxt, "_", applicability);
-                        format!("ToOwned::clone_into({self_sugg}, {rhs_sugg})")
-                    },
+                    sugg.mut_addr()
                 }
-            },
-        }
+            } else {
+                // `lhs = rhs.to_owned()` -> `rhs.clone_into(&mut lhs)`
+                // `lhs = ToOwned::to_owned(rhs)` -> `ToOwned::clone_into(rhs, &mut lhs)`
+                Sugg::hir_with_applicability(cx, lhs, "_", app).maybe_par().mut_addr()
+            };
+
+            match call_kind {
+                CallKind::Method => {
+                    let receiver_sugg = Sugg::hir_with_context(cx, fn_arg, ctxt, "_", app);
+                    format!("{receiver_sugg}.clone_into({rhs_sugg})")
+                },
+                CallKind::Ufcs => {
+                    let self_sugg = Sugg::hir_with_context(cx, fn_arg, ctxt, "_", app);
+                    format!("ToOwned::clone_into({self_sugg}, {rhs_sugg})")
+                },
+            }
+        },
     }
 }
diff --git a/src/tools/clippy/clippy_lints/src/await_holding_invalid.rs b/src/tools/clippy/clippy_lints/src/await_holding_invalid.rs
index f25a474d9bb..d4a1e2780d0 100644
--- a/src/tools/clippy/clippy_lints/src/await_holding_invalid.rs
+++ b/src/tools/clippy/clippy_lints/src/await_holding_invalid.rs
@@ -11,21 +11,25 @@ use rustc_span::{sym, Span};
 
 declare_clippy_lint! {
     /// ### What it does
-    /// Checks for calls to await while holding a non-async-aware MutexGuard.
+    /// Checks for calls to `await` while holding a non-async-aware
+    /// `MutexGuard`.
     ///
     /// ### Why is this bad?
-    /// The Mutex types found in std::sync and parking_lot
-    /// are not designed to operate in an async context across await points.
+    /// The Mutex types found in [`std::sync`][https://doc.rust-lang.org/stable/std/sync/] and
+    /// [`parking_lot`](https://docs.rs/parking_lot/latest/parking_lot/) are
+    /// not designed to operate in an async context across await points.
     ///
-    /// There are two potential solutions. One is to use an async-aware Mutex
-    /// type. Many asynchronous foundation crates provide such a Mutex type. The
-    /// other solution is to ensure the mutex is unlocked before calling await,
-    /// either by introducing a scope or an explicit call to Drop::drop.
+    /// There are two potential solutions. One is to use an async-aware `Mutex`
+    /// type. Many asynchronous foundation crates provide such a `Mutex` type.
+    /// The other solution is to ensure the mutex is unlocked before calling
+    /// `await`, either by introducing a scope or an explicit call to
+    /// [`Drop::drop`](https://doc.rust-lang.org/std/ops/trait.Drop.html).
     ///
     /// ### Known problems
     /// Will report false positive for explicitly dropped guards
-    /// ([#6446](https://github.com/rust-lang/rust-clippy/issues/6446)). A workaround for this is
-    /// to wrap the `.lock()` call in a block instead of explicitly dropping the guard.
+    /// ([#6446](https://github.com/rust-lang/rust-clippy/issues/6446)). A
+    /// workaround for this is to wrap the `.lock()` call in a block instead of
+    /// explicitly dropping the guard.
     ///
     /// ### Example
     /// ```no_run
@@ -73,11 +77,11 @@ declare_clippy_lint! {
 
 declare_clippy_lint! {
     /// ### What it does
-    /// Checks for calls to await while holding a `RefCell` `Ref` or `RefMut`.
+    /// Checks for calls to `await` while holding a `RefCell`, `Ref`, or `RefMut`.
     ///
     /// ### Why is this bad?
     /// `RefCell` refs only check for exclusive mutable access
-    /// at runtime. Holding onto a `RefCell` ref across an `await` suspension point
+    /// at runtime. Holding a `RefCell` ref across an await suspension point
     /// risks panics from a mutable ref shared while other refs are outstanding.
     ///
     /// ### Known problems
@@ -131,13 +135,13 @@ declare_clippy_lint! {
 
 declare_clippy_lint! {
     /// ### What it does
-    /// Allows users to configure types which should not be held across `await`
+    /// Allows users to configure types which should not be held across await
     /// suspension points.
     ///
     /// ### Why is this bad?
-    /// There are some types which are perfectly "safe" to be used concurrently
-    /// from a memory access perspective but will cause bugs at runtime if they
-    /// are held in such a way.
+    /// There are some types which are perfectly safe to use concurrently from
+    /// a memory access perspective, but that will cause bugs at runtime if
+    /// they are held in such a way.
     ///
     /// ### Example
     ///
@@ -228,15 +232,15 @@ impl AwaitHolding {
                         cx,
                         AWAIT_HOLDING_LOCK,
                         ty_cause.source_info.span,
-                        "this `MutexGuard` is held across an `await` point",
+                        "this `MutexGuard` is held across an await point",
                         |diag| {
                             diag.help(
                                 "consider using an async-aware `Mutex` type or ensuring the \
-                                `MutexGuard` is dropped before calling await",
+                                `MutexGuard` is dropped before calling `await`",
                             );
                             diag.span_note(
                                 await_points(),
-                                "these are all the `await` points this lock is held through",
+                                "these are all the await points this lock is held through",
                             );
                         },
                     );
@@ -245,12 +249,12 @@ impl AwaitHolding {
                         cx,
                         AWAIT_HOLDING_REFCELL_REF,
                         ty_cause.source_info.span,
-                        "this `RefCell` reference is held across an `await` point",
+                        "this `RefCell` reference is held across an await point",
                         |diag| {
                             diag.help("ensure the reference is dropped before calling `await`");
                             diag.span_note(
                                 await_points(),
-                                "these are all the `await` points this reference is held through",
+                                "these are all the await points this reference is held through",
                             );
                         },
                     );
@@ -268,7 +272,7 @@ fn emit_invalid_type(cx: &LateContext<'_>, span: Span, disallowed: &DisallowedPa
         AWAIT_HOLDING_INVALID_TYPE,
         span,
         format!(
-            "`{}` may not be held across an `await` point per `clippy.toml`",
+            "`{}` may not be held across an await point per `clippy.toml`",
             disallowed.path()
         ),
         |diag| {
diff --git a/src/tools/clippy/clippy_lints/src/bool_to_int_with_if.rs b/src/tools/clippy/clippy_lints/src/bool_to_int_with_if.rs
index cfb76cab6dc..561ca9bd986 100644
--- a/src/tools/clippy/clippy_lints/src/bool_to_int_with_if.rs
+++ b/src/tools/clippy/clippy_lints/src/bool_to_int_with_if.rs
@@ -1,13 +1,11 @@
-use clippy_utils::higher::If;
-use rustc_ast::LitKind;
-use rustc_hir::{Block, ExprKind};
-use rustc_lint::{LateContext, LateLintPass};
-use rustc_session::declare_lint_pass;
-
 use clippy_utils::diagnostics::span_lint_and_then;
 use clippy_utils::sugg::Sugg;
-use clippy_utils::{in_constant, is_else_clause, is_integer_literal};
+use clippy_utils::{in_constant, is_else_clause};
+use rustc_ast::LitKind;
 use rustc_errors::Applicability;
+use rustc_hir::{Expr, ExprKind};
+use rustc_lint::{LateContext, LateLintPass};
+use rustc_session::declare_lint_pass;
 
 declare_clippy_lint! {
     /// ### What it does
@@ -47,80 +45,64 @@ declare_clippy_lint! {
 declare_lint_pass!(BoolToIntWithIf => [BOOL_TO_INT_WITH_IF]);
 
 impl<'tcx> LateLintPass<'tcx> for BoolToIntWithIf {
-    fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx rustc_hir::Expr<'tcx>) {
-        if !expr.span.from_expansion() && !in_constant(cx, expr.hir_id) {
-            check_if_else(cx, expr);
-        }
-    }
-}
-
-fn check_if_else<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx rustc_hir::Expr<'tcx>) {
-    if let Some(If {
-        cond,
-        then,
-        r#else: Some(r#else),
-    }) = If::hir(expr)
-        && let Some(then_lit) = int_literal(then)
-        && let Some(else_lit) = int_literal(r#else)
-    {
-        let inverted = if is_integer_literal(then_lit, 1) && is_integer_literal(else_lit, 0) {
-            false
-        } else if is_integer_literal(then_lit, 0) && is_integer_literal(else_lit, 1) {
-            true
-        } else {
-            // Expression isn't boolean, exit
-            return;
-        };
-        let mut applicability = Applicability::MachineApplicable;
-        let snippet = {
-            let mut sugg = Sugg::hir_with_applicability(cx, cond, "..", &mut applicability);
-            if inverted {
-                sugg = !sugg;
-            }
-            sugg
-        };
-
-        let ty = cx.typeck_results().expr_ty(then_lit); // then and else must be of same type
+    fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) {
+        if let ExprKind::If(cond, then, Some(else_)) = expr.kind
+            && matches!(cond.kind, ExprKind::DropTemps(_))
+            && let Some(then_lit) = as_int_bool_lit(then)
+            && let Some(else_lit) = as_int_bool_lit(else_)
+            && then_lit != else_lit
+            && !expr.span.from_expansion()
+            && !in_constant(cx, expr.hir_id)
+        {
+            let ty = cx.typeck_results().expr_ty(then);
+            let mut applicability = Applicability::MachineApplicable;
+            let snippet = {
+                let mut sugg = Sugg::hir_with_applicability(cx, cond, "..", &mut applicability);
+                if !then_lit {
+                    sugg = !sugg;
+                }
+                sugg
+            };
+            let suggestion = {
+                let mut s = Sugg::NonParen(format!("{ty}::from({snippet})").into());
+                // when used in else clause if statement should be wrapped in curly braces
+                if is_else_clause(cx.tcx, expr) {
+                    s = s.blockify();
+                }
+                s
+            };
 
-        let suggestion = {
-            let wrap_in_curly = is_else_clause(cx.tcx, expr);
-            let mut s = Sugg::NonParen(format!("{ty}::from({snippet})").into());
-            if wrap_in_curly {
-                s = s.blockify();
-            }
-            s
-        }; // when used in else clause if statement should be wrapped in curly braces
+            let into_snippet = snippet.clone().maybe_par();
+            let as_snippet = snippet.as_ty(ty);
 
-        let into_snippet = snippet.clone().maybe_par();
-        let as_snippet = snippet.as_ty(ty);
-
-        span_lint_and_then(
-            cx,
-            BOOL_TO_INT_WITH_IF,
-            expr.span,
-            "boolean to int conversion using if",
-            |diag| {
-                diag.span_suggestion(expr.span, "replace with from", suggestion, applicability);
-                diag.note(format!(
-                    "`{as_snippet}` or `{into_snippet}.into()` can also be valid options"
-                ));
-            },
-        );
-    };
+            span_lint_and_then(
+                cx,
+                BOOL_TO_INT_WITH_IF,
+                expr.span,
+                "boolean to int conversion using if",
+                |diag| {
+                    diag.span_suggestion(expr.span, "replace with from", suggestion, applicability);
+                    diag.note(format!(
+                        "`{as_snippet}` or `{into_snippet}.into()` can also be valid options"
+                    ));
+                },
+            );
+        }
+    }
 }
 
-// If block contains only a int literal expression, return literal expression
-fn int_literal<'tcx>(expr: &'tcx rustc_hir::Expr<'tcx>) -> Option<&'tcx rustc_hir::Expr<'tcx>> {
-    if let ExprKind::Block(block, _) = expr.kind
-        && let Block {
-            stmts: [], // Shouldn't lint if statements with side effects
-            expr: Some(expr),
-            ..
-        } = block
-        && let ExprKind::Lit(lit) = &expr.kind
-        && let LitKind::Int(_, _) = lit.node
+fn as_int_bool_lit(e: &Expr<'_>) -> Option<bool> {
+    if let ExprKind::Block(b, _) = e.kind
+        && b.stmts.is_empty()
+        && let Some(e) = b.expr
+        && let ExprKind::Lit(lit) = e.kind
+        && let LitKind::Int(x, _) = lit.node
     {
-        Some(expr)
+        match x.get() {
+            0 => Some(false),
+            1 => Some(true),
+            _ => None,
+        }
     } else {
         None
     }
diff --git a/src/tools/clippy/clippy_lints/src/byte_char_slices.rs b/src/tools/clippy/clippy_lints/src/byte_char_slices.rs
new file mode 100644
index 00000000000..a9fe190f177
--- /dev/null
+++ b/src/tools/clippy/clippy_lints/src/byte_char_slices.rs
@@ -0,0 +1,80 @@
+use clippy_utils::diagnostics::span_lint_and_sugg;
+use rustc_ast::ast::{BorrowKind, Expr, ExprKind, Mutability};
+use rustc_ast::token::{Lit, LitKind};
+use rustc_errors::Applicability;
+use rustc_lint::{EarlyContext, EarlyLintPass};
+use rustc_session::declare_lint_pass;
+
+declare_clippy_lint! {
+    /// ### What it does
+    /// Checks for hard to read slices of byte characters, that could be more easily expressed as a
+    /// byte string.
+    ///
+    /// ### Why is this bad?
+    ///
+    /// Potentially makes the string harder to read.
+    ///
+    /// ### Example
+    /// ```ignore
+    /// &[b'H', b'e', b'l', b'l', b'o'];
+    /// ```
+    /// Use instead:
+    /// ```ignore
+    /// b"Hello"
+    /// ```
+    #[clippy::version = "1.68.0"]
+    pub BYTE_CHAR_SLICES,
+    style,
+    "hard to read byte char slice"
+}
+declare_lint_pass!(ByteCharSlice => [BYTE_CHAR_SLICES]);
+
+impl EarlyLintPass for ByteCharSlice {
+    fn check_expr(&mut self, cx: &EarlyContext<'_>, expr: &Expr) {
+        if let Some(slice) = is_byte_char_slices(expr)
+            && !expr.span.from_expansion()
+        {
+            span_lint_and_sugg(
+                cx,
+                BYTE_CHAR_SLICES,
+                expr.span,
+                "can be more succinctly written as a byte str",
+                "try",
+                format!("b\"{slice}\""),
+                Applicability::MaybeIncorrect,
+            );
+        }
+    }
+}
+
+fn is_byte_char_slices(expr: &Expr) -> Option<String> {
+    if let ExprKind::AddrOf(BorrowKind::Ref, Mutability::Not, expr) = &expr.kind {
+        match &expr.kind {
+            ExprKind::Array(members) => {
+                if members.is_empty() {
+                    return None;
+                }
+
+                members
+                    .iter()
+                    .map(|member| match &member.kind {
+                        ExprKind::Lit(Lit {
+                            kind: LitKind::Byte,
+                            symbol,
+                            ..
+                        }) => Some(symbol.as_str()),
+                        _ => None,
+                    })
+                    .map(|maybe_quote| match maybe_quote {
+                        Some("\"") => Some("\\\""),
+                        Some("\\'") => Some("'"),
+                        other => other,
+                    })
+                    .collect::<Option<String>>()
+            },
+            _ => None,
+        }
+    } else {
+        None
+    }
+}
diff --git a/src/tools/clippy/clippy_lints/src/casts/mod.rs b/src/tools/clippy/clippy_lints/src/casts/mod.rs
index e60c36ced75..54f0c7c4687 100644
--- a/src/tools/clippy/clippy_lints/src/casts/mod.rs
+++ b/src/tools/clippy/clippy_lints/src/casts/mod.rs
@@ -32,7 +32,7 @@ use rustc_session::impl_lint_pass;
 
 declare_clippy_lint! {
     /// ### What it does
-    /// Checks for casts from any numerical to a float type where
+    /// Checks for casts from any numeric type to a float type where
     /// the receiving type cannot store all values from the original type without
     /// rounding errors. This possible rounding is to be expected, so this lint is
     /// `Allow` by default.
@@ -58,14 +58,14 @@ declare_clippy_lint! {
 
 declare_clippy_lint! {
     /// ### What it does
-    /// Checks for casts from a signed to an unsigned numerical
+    /// Checks for casts from a signed to an unsigned numeric
     /// type. In this case, negative values wrap around to large positive values,
-    /// which can be quite surprising in practice. However, as the cast works as
+    /// which can be quite surprising in practice. However, since the cast works as
     /// defined, this lint is `Allow` by default.
     ///
     /// ### Why is this bad?
     /// Possibly surprising results. You can activate this lint
-    /// as a one-time check to see where numerical wrapping can arise.
+    /// as a one-time check to see where numeric wrapping can arise.
     ///
     /// ### Example
     /// ```no_run
@@ -80,7 +80,7 @@ declare_clippy_lint! {
 
 declare_clippy_lint! {
     /// ### What it does
-    /// Checks for casts between numerical types that may
+    /// Checks for casts between numeric types that may
     /// truncate large values. This is expected behavior, so the cast is `Allow` by
     /// default. It suggests user either explicitly ignore the lint,
     /// or use `try_from()` and handle the truncation, default, or panic explicitly.
@@ -120,17 +120,16 @@ declare_clippy_lint! {
 declare_clippy_lint! {
     /// ### What it does
     /// Checks for casts from an unsigned type to a signed type of
-    /// the same size, or possibly smaller due to target dependent integers.
-    /// Performing such a cast is a 'no-op' for the compiler, i.e., nothing is
-    /// changed at the bit level, and the binary representation of the value is
+    /// the same size, or possibly smaller due to target-dependent integers.
+    /// Performing such a cast is a no-op for the compiler (that is, nothing is
+    /// changed at the bit level), and the binary representation of the value is
     /// reinterpreted. This can cause wrapping if the value is too big
     /// for the target signed type. However, the cast works as defined, so this lint
     /// is `Allow` by default.
     ///
     /// ### Why is this bad?
     /// While such a cast is not bad in itself, the results can
-    /// be surprising when this is not the intended behavior, as demonstrated by the
-    /// example below.
+    /// be surprising when this is not the intended behavior:
     ///
     /// ### Example
     /// ```no_run
@@ -144,16 +143,16 @@ declare_clippy_lint! {
 
 declare_clippy_lint! {
     /// ### What it does
-    /// Checks for casts between numerical types that may
-    /// be replaced by safe conversion functions.
+    /// Checks for casts between numeric types that can be replaced by safe
+    /// conversion functions.
     ///
     /// ### Why is this bad?
-    /// Rust's `as` keyword will perform many kinds of
-    /// conversions, including silently lossy conversions. Conversion functions such
-    /// as `i32::from` will only perform lossless conversions. Using the conversion
-    /// functions prevents conversions from turning into silent lossy conversions if
-    /// the types of the input expressions ever change, and make it easier for
-    /// people reading the code to know that the conversion is lossless.
+    /// Rust's `as` keyword will perform many kinds of conversions, including
+    /// silently lossy conversions. Conversion functions such as `i32::from`
+    /// will only perform lossless conversions. Using the conversion functions
+    /// prevents conversions from becoming silently lossy if the input types
+    /// ever change, and makes it clear for people reading the code that the
+    /// conversion is lossless.
     ///
     /// ### Example
     /// ```no_run
@@ -177,19 +176,21 @@ declare_clippy_lint! {
 
 declare_clippy_lint! {
     /// ### What it does
-    /// Checks for casts to the same type, casts of int literals to integer types, casts of float
-    /// literals to float types and casts between raw pointers without changing type or constness.
+    /// Checks for casts to the same type, casts of int literals to integer
+    /// types, casts of float literals to float types, and casts between raw
+    /// pointers that don't change type or constness.
     ///
     /// ### Why is this bad?
     /// It's just unnecessary.
     ///
     /// ### Known problems
-    /// When the expression on the left is a function call, the lint considers the return type to be
-    /// a type alias if it's aliased through a `use` statement
-    /// (like `use std::io::Result as IoResult`). It will not lint such cases.
+    /// When the expression on the left is a function call, the lint considers
+    /// the return type to be a type alias if it's aliased through a `use`
+    /// statement (like `use std::io::Result as IoResult`). It will not lint
+    /// such cases.
     ///
-    /// This check is also rather primitive. It will only work on primitive types without any
-    /// intermediate references, raw pointers and trait objects may or may not work.
+    /// This check will only work on primitive types without any intermediate
+    /// references: raw pointers and trait objects may or may not work.
     ///
     /// ### Example
     /// ```no_run
@@ -211,17 +212,17 @@ declare_clippy_lint! {
 
 declare_clippy_lint! {
     /// ### What it does
-    /// Checks for casts, using `as` or `pointer::cast`,
-    /// from a less-strictly-aligned pointer to a more-strictly-aligned pointer
+    /// Checks for casts, using `as` or `pointer::cast`, from a
+    /// less strictly aligned pointer to a more strictly aligned pointer.
     ///
     /// ### Why is this bad?
-    /// Dereferencing the resulting pointer may be undefined
-    /// behavior.
+    /// Dereferencing the resulting pointer may be undefined behavior.
     ///
     /// ### Known problems
-    /// Using `std::ptr::read_unaligned` and `std::ptr::write_unaligned` or similar
-    /// on the resulting pointer is fine. Is over-zealous: Casts with manual alignment checks or casts like
-    /// u64-> u8 -> u16 can be fine. Miri is able to do a more in-depth analysis.
+    /// Using [`std::ptr::read_unaligned`](https://doc.rust-lang.org/std/ptr/fn.read_unaligned.html) and [`std::ptr::write_unaligned`](https://doc.rust-lang.org/std/ptr/fn.write_unaligned.html) or
+    /// similar on the resulting pointer is fine. Is over-zealous: casts with
+    /// manual alignment checks or casts like `u64` -> `u8` -> `u16` can be
+    /// fine. Miri is able to do a more in-depth analysis.
     ///
     /// ### Example
     /// ```no_run
@@ -234,20 +235,21 @@ declare_clippy_lint! {
     #[clippy::version = "pre 1.29.0"]
     pub CAST_PTR_ALIGNMENT,
     pedantic,
-    "cast from a pointer to a more-strictly-aligned pointer"
+    "cast from a pointer to a more strictly aligned pointer"
 }
 
 declare_clippy_lint! {
     /// ### What it does
-    /// Checks for casts of function pointers to something other than usize
+    /// Checks for casts of function pointers to something other than `usize`.
     ///
     /// ### Why is this bad?
-    /// Casting a function pointer to anything other than usize/isize is not portable across
-    /// architectures, because you end up losing bits if the target type is too small or end up with a
-    /// bunch of extra bits that waste space and add more instructions to the final binary than
-    /// strictly necessary for the problem
+    /// Casting a function pointer to anything other than `usize`/`isize` is
+    /// not portable across architectures. If the target type is too small the
+    /// address would be truncated, and target types larger than `usize` are
+    /// unnecessary.
     ///
-    /// Casting to isize also doesn't make sense since there are no signed addresses.
+    /// Casting to `isize` also doesn't make sense, since addresses are never
+    /// signed.
     ///
     /// ### Example
     /// ```no_run
@@ -263,17 +265,17 @@ declare_clippy_lint! {
     #[clippy::version = "pre 1.29.0"]
     pub FN_TO_NUMERIC_CAST,
     style,
-    "casting a function pointer to a numeric type other than usize"
+    "casting a function pointer to a numeric type other than `usize`"
 }
 
 declare_clippy_lint! {
     /// ### What it does
     /// Checks for casts of a function pointer to a numeric type not wide enough to
-    /// store address.
+    /// store an address.
     ///
     /// ### Why is this bad?
     /// Such a cast discards some bits of the function's address. If this is intended, it would be more
-    /// clearly expressed by casting to usize first, then casting the usize to the intended type (with
+    /// clearly expressed by casting to `usize` first, then casting the `usize` to the intended type (with
     /// a comment) to perform the truncation.
     ///
     /// ### Example
@@ -306,7 +308,7 @@ declare_clippy_lint! {
     /// ### Why restrict this?
     /// Casting a function pointer to an integer can have surprising results and can occur
     /// accidentally if parentheses are omitted from a function call. If you aren't doing anything
-    /// low-level with function pointers then you can opt-out of casting functions to integers in
+    /// low-level with function pointers then you can opt out of casting functions to integers in
     /// order to avoid mistakes. Alternatively, you can use this lint to audit all uses of function
     /// pointer casts in your code.
     ///
@@ -349,8 +351,8 @@ declare_clippy_lint! {
     /// ### Why is this bad?
     /// In general, casting values to smaller types is
     /// error-prone and should be avoided where possible. In the particular case of
-    /// converting a character literal to u8, it is easy to avoid by just using a
-    /// byte literal instead. As an added bonus, `b'a'` is even slightly shorter
+    /// converting a character literal to `u8`, it is easy to avoid by just using a
+    /// byte literal instead. As an added bonus, `b'a'` is also slightly shorter
     /// than `'a' as u8`.
     ///
     /// ### Example
@@ -371,12 +373,13 @@ declare_clippy_lint! {
 
 declare_clippy_lint! {
     /// ### What it does
-    /// Checks for `as` casts between raw pointers without changing its mutability,
-    /// namely `*const T` to `*const U` and `*mut T` to `*mut U`.
+    /// Checks for `as` casts between raw pointers that don't change their
+    /// constness, namely `*const T` to `*const U` and `*mut T` to `*mut U`.
     ///
     /// ### Why is this bad?
-    /// Though `as` casts between raw pointers are not terrible, `pointer::cast` is safer because
-    /// it cannot accidentally change the pointer's mutability nor cast the pointer to other types like `usize`.
+    /// Though `as` casts between raw pointers are not terrible,
+    /// `pointer::cast` is safer because it cannot accidentally change the
+    /// pointer's mutability, nor cast the pointer to other types like `usize`.
     ///
     /// ### Example
     /// ```no_run
@@ -395,12 +398,12 @@ declare_clippy_lint! {
     #[clippy::version = "1.51.0"]
     pub PTR_AS_PTR,
     pedantic,
-    "casting using `as` from and to raw pointers that doesn't change its mutability, where `pointer::cast` could take the place of `as`"
+    "casting using `as` between raw pointers that doesn't change their constness, where `pointer::cast` could take the place of `as`"
 }
 
 declare_clippy_lint! {
     /// ### What it does
-    /// Checks for `as` casts between raw pointers which change its constness, namely `*const T` to
+    /// Checks for `as` casts between raw pointers that change their constness, namely `*const T` to
     /// `*mut T` and `*mut T` to `*const T`.
     ///
     /// ### Why is this bad?
@@ -423,12 +426,12 @@ declare_clippy_lint! {
     #[clippy::version = "1.72.0"]
     pub PTR_CAST_CONSTNESS,
     pedantic,
-    "casting using `as` from and to raw pointers to change constness when specialized methods apply"
+    "casting using `as` on raw pointers to change constness when specialized methods apply"
 }
 
 declare_clippy_lint! {
     /// ### What it does
-    /// Checks for casts from an enum type to an integral type which will definitely truncate the
+    /// Checks for casts from an enum type to an integral type that will definitely truncate the
     /// value.
     ///
     /// ### Why is this bad?
@@ -442,7 +445,7 @@ declare_clippy_lint! {
     #[clippy::version = "1.61.0"]
     pub CAST_ENUM_TRUNCATION,
     suspicious,
-    "casts from an enum type to an integral type which will truncate the value"
+    "casts from an enum type to an integral type that will truncate the value"
 }
 
 declare_clippy_lint! {
@@ -621,7 +624,7 @@ declare_clippy_lint! {
 
 declare_clippy_lint! {
     /// ### What it does
-    /// Checks for the result of a `&self`-taking `as_ptr` being cast to a mutable pointer
+    /// Checks for the result of a `&self`-taking `as_ptr` being cast to a mutable pointer.
     ///
     /// ### Why is this bad?
     /// Since `as_ptr` takes a `&self`, the pointer won't have write permissions unless interior
diff --git a/src/tools/clippy/clippy_lints/src/casts/ptr_as_ptr.rs b/src/tools/clippy/clippy_lints/src/casts/ptr_as_ptr.rs
index 2c168405ee2..86c5f6b9f0b 100644
--- a/src/tools/clippy/clippy_lints/src/casts/ptr_as_ptr.rs
+++ b/src/tools/clippy/clippy_lints/src/casts/ptr_as_ptr.rs
@@ -92,7 +92,7 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, msrv: &Msrv) {
             cx,
             PTR_AS_PTR,
             expr.span,
-            "`as` casting between raw pointers without changing its mutability",
+            "`as` casting between raw pointers without changing their constness",
             help,
             final_suggestion,
             app,
diff --git a/src/tools/clippy/clippy_lints/src/cfg_not_test.rs b/src/tools/clippy/clippy_lints/src/cfg_not_test.rs
new file mode 100644
index 00000000000..b54f392bf2f
--- /dev/null
+++ b/src/tools/clippy/clippy_lints/src/cfg_not_test.rs
@@ -0,0 +1,60 @@
+use clippy_utils::diagnostics::span_lint_and_then;
+use rustc_ast::NestedMetaItem;
+use rustc_lint::{EarlyContext, EarlyLintPass};
+use rustc_session::declare_lint_pass;
+
+declare_clippy_lint! {
+    /// ### What it does
+    /// Checks for usage of `cfg` that excludes code from `test` builds. (i.e., `#{cfg(not(test))]`)
+    ///
+    /// ### Why is this bad?
+    /// This may give the false impression that a codebase has 100% coverage, yet actually has untested code.
+    /// Enabling this also guards against excessive mockery as well, which is an anti-pattern.
+    ///
+    /// ### Example
+    /// ```rust
+    /// # fn important_check() {}
+    /// #[cfg(not(test))]
+    /// important_check(); // I'm not actually tested, but not including me will falsely increase coverage!
+    /// ```
+    /// Use instead:
+    /// ```rust
+    /// # fn important_check() {}
+    /// important_check();
+    /// ```
+    #[clippy::version = "1.73.0"]
+    pub CFG_NOT_TEST,
+    restriction,
+    "enforce against excluding code from test builds"
+}
+
+declare_lint_pass!(CfgNotTest => [CFG_NOT_TEST]);
+
+impl EarlyLintPass for CfgNotTest {
+    fn check_attribute(&mut self, cx: &EarlyContext<'_>, attr: &rustc_ast::Attribute) {
+        if attr.has_name(rustc_span::sym::cfg) && contains_not_test(attr.meta_item_list().as_deref(), false) {
+            span_lint_and_then(
+                cx,
+                CFG_NOT_TEST,
+                attr.span,
+                "code is excluded from test builds",
+                |diag| {
+                    diag.help("consider not excluding any code from test builds");
+                    diag.note_once("this could increase code coverage despite not actually being tested");
+                },
+            );
+        }
+    }
+}
+
+fn contains_not_test(list: Option<&[NestedMetaItem]>, not: bool) -> bool {
+    list.is_some_and(|list| {
+        list.iter().any(|item| {
+            item.ident().is_some_and(|ident| match ident.name {
+                rustc_span::sym::not => contains_not_test(item.meta_item_list(), !not),
+                rustc_span::sym::test => not,
+                _ => contains_not_test(item.meta_item_list(), not),
+            })
+        })
+    })
+}
diff --git a/src/tools/clippy/clippy_lints/src/declared_lints.rs b/src/tools/clippy/clippy_lints/src/declared_lints.rs
index 638de5e818c..eabc67601a2 100644
--- a/src/tools/clippy/clippy_lints/src/declared_lints.rs
+++ b/src/tools/clippy/clippy_lints/src/declared_lints.rs
@@ -8,8 +8,6 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[
     #[cfg(feature = "internal")]
     crate::utils::internal_lints::collapsible_calls::COLLAPSIBLE_SPAN_LINT_CALLS_INFO,
     #[cfg(feature = "internal")]
-    crate::utils::internal_lints::compiler_lint_functions::COMPILER_LINT_FUNCTIONS_INFO,
-    #[cfg(feature = "internal")]
     crate::utils::internal_lints::interning_defined_symbol::INTERNING_DEFINED_SYMBOL_INFO,
     #[cfg(feature = "internal")]
     crate::utils::internal_lints::interning_defined_symbol::UNNECESSARY_SYMBOL_STR_INFO,
@@ -73,6 +71,7 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[
     crate::booleans::OVERLY_COMPLEX_BOOL_EXPR_INFO,
     crate::borrow_deref_ref::BORROW_DEREF_REF_INFO,
     crate::box_default::BOX_DEFAULT_INFO,
+    crate::byte_char_slices::BYTE_CHAR_SLICES_INFO,
     crate::cargo::CARGO_COMMON_METADATA_INFO,
     crate::cargo::LINT_GROUPS_PRIORITY_INFO,
     crate::cargo::MULTIPLE_CRATE_VERSIONS_INFO,
@@ -103,6 +102,7 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[
     crate::casts::REF_AS_PTR_INFO,
     crate::casts::UNNECESSARY_CAST_INFO,
     crate::casts::ZERO_PTR_INFO,
+    crate::cfg_not_test::CFG_NOT_TEST_INFO,
     crate::checked_conversions::CHECKED_CONVERSIONS_INFO,
     crate::cognitive_complexity::COGNITIVE_COMPLEXITY_INFO,
     crate::collapsible_if::COLLAPSIBLE_ELSE_IF_INFO,
@@ -313,6 +313,7 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[
     crate::manual_range_patterns::MANUAL_RANGE_PATTERNS_INFO,
     crate::manual_rem_euclid::MANUAL_REM_EUCLID_INFO,
     crate::manual_retain::MANUAL_RETAIN_INFO,
+    crate::manual_rotate::MANUAL_ROTATE_INFO,
     crate::manual_slice_size_calculation::MANUAL_SLICE_SIZE_CALCULATION_INFO,
     crate::manual_string_new::MANUAL_STRING_NEW_INFO,
     crate::manual_strip::MANUAL_STRIP_INFO,
@@ -503,6 +504,7 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[
     crate::missing_assert_message::MISSING_ASSERT_MESSAGE_INFO,
     crate::missing_asserts_for_indexing::MISSING_ASSERTS_FOR_INDEXING_INFO,
     crate::missing_const_for_fn::MISSING_CONST_FOR_FN_INFO,
+    crate::missing_const_for_thread_local::MISSING_CONST_FOR_THREAD_LOCAL_INFO,
     crate::missing_doc::MISSING_DOCS_IN_PRIVATE_ITEMS_INFO,
     crate::missing_enforced_import_rename::MISSING_ENFORCED_IMPORT_RENAMES_INFO,
     crate::missing_fields_in_debug::MISSING_FIELDS_IN_DEBUG_INFO,
@@ -585,12 +587,12 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[
     crate::operators::VERBOSE_BIT_MASK_INFO,
     crate::option_env_unwrap::OPTION_ENV_UNWRAP_INFO,
     crate::option_if_let_else::OPTION_IF_LET_ELSE_INFO,
-    crate::overflow_check_conditional::OVERFLOW_CHECK_CONDITIONAL_INFO,
     crate::panic_in_result_fn::PANIC_IN_RESULT_FN_INFO,
     crate::panic_unimplemented::PANIC_INFO,
     crate::panic_unimplemented::TODO_INFO,
     crate::panic_unimplemented::UNIMPLEMENTED_INFO,
     crate::panic_unimplemented::UNREACHABLE_INFO,
+    crate::panicking_overflow_checks::PANICKING_OVERFLOW_CHECKS_INFO,
     crate::partial_pub_fields::PARTIAL_PUB_FIELDS_INFO,
     crate::partialeq_ne_impl::PARTIALEQ_NE_IMPL_INFO,
     crate::partialeq_to_none::PARTIALEQ_TO_NONE_INFO,
@@ -644,6 +646,7 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[
     crate::semicolon_block::SEMICOLON_OUTSIDE_BLOCK_INFO,
     crate::semicolon_if_nothing_returned::SEMICOLON_IF_NOTHING_RETURNED_INFO,
     crate::serde_api::SERDE_API_MISUSE_INFO,
+    crate::set_contains_or_insert::SET_CONTAINS_OR_INSERT_INFO,
     crate::shadow::SHADOW_REUSE_INFO,
     crate::shadow::SHADOW_SAME_INFO,
     crate::shadow::SHADOW_UNRELATED_INFO,
@@ -679,7 +682,6 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[
     crate::tabs_in_doc_comments::TABS_IN_DOC_COMMENTS_INFO,
     crate::temporary_assignment::TEMPORARY_ASSIGNMENT_INFO,
     crate::tests_outside_test_module::TESTS_OUTSIDE_TEST_MODULE_INFO,
-    crate::thread_local_initializer_can_be_made_const::THREAD_LOCAL_INITIALIZER_CAN_BE_MADE_CONST_INFO,
     crate::to_digit_is_some::TO_DIGIT_IS_SOME_INFO,
     crate::to_string_trait_impl::TO_STRING_TRAIT_IMPL_INFO,
     crate::trailing_empty_array::TRAILING_EMPTY_ARRAY_INFO,
diff --git a/src/tools/clippy/clippy_lints/src/default.rs b/src/tools/clippy/clippy_lints/src/default.rs
index 2b3f4854255..72fa05be3cc 100644
--- a/src/tools/clippy/clippy_lints/src/default.rs
+++ b/src/tools/clippy/clippy_lints/src/default.rs
@@ -1,7 +1,7 @@
 use clippy_utils::diagnostics::{span_lint_and_note, span_lint_and_sugg};
 use clippy_utils::source::snippet_with_context;
 use clippy_utils::ty::{has_drop, is_copy};
-use clippy_utils::{any_parent_is_automatically_derived, contains_name, get_parent_expr, is_from_proc_macro};
+use clippy_utils::{contains_name, get_parent_expr, in_automatically_derived, is_from_proc_macro};
 use rustc_data_structures::fx::FxHashSet;
 use rustc_errors::Applicability;
 use rustc_hir::def::Res;
@@ -84,7 +84,7 @@ impl<'tcx> LateLintPass<'tcx> for Default {
             // Avoid cases already linted by `field_reassign_with_default`
             && !self.reassigned_linted.contains(&expr.span)
             && let ExprKind::Call(path, ..) = expr.kind
-            && !any_parent_is_automatically_derived(cx.tcx, expr.hir_id)
+            && !in_automatically_derived(cx.tcx, expr.hir_id)
             && let ExprKind::Path(ref qpath) = path.kind
             && let Some(def_id) = cx.qpath_res(qpath, path.hir_id).opt_def_id()
             && cx.tcx.is_diagnostic_item(sym::default_fn, def_id)
@@ -113,9 +113,9 @@ impl<'tcx> LateLintPass<'tcx> for Default {
         // start from the `let mut _ = _::default();` and look at all the following
         // statements, see if they re-assign the fields of the binding
         let stmts_head = match block.stmts {
+            [] | [_] => return,
             // Skip the last statement since there cannot possibly be any following statements that re-assign fields.
-            [head @ .., _] if !head.is_empty() => head,
-            _ => return,
+            [head @ .., _] => head,
         };
         for (stmt_idx, stmt) in stmts_head.iter().enumerate() {
             // find all binding statements like `let mut _ = T::default()` where `T::default()` is the
@@ -124,7 +124,7 @@ impl<'tcx> LateLintPass<'tcx> for Default {
             let (local, variant, binding_name, binding_type, span) = if let StmtKind::Let(local) = stmt.kind
                 // only take `let ...` statements
                 && let Some(expr) = local.init
-                && !any_parent_is_automatically_derived(cx.tcx, expr.hir_id)
+                && !in_automatically_derived(cx.tcx, expr.hir_id)
                 && !expr.span.from_expansion()
                 // only take bindings to identifiers
                 && let PatKind::Binding(_, binding_id, ident, _) = local.pat.kind
diff --git a/src/tools/clippy/clippy_lints/src/default_numeric_fallback.rs b/src/tools/clippy/clippy_lints/src/default_numeric_fallback.rs
index ff631909bcb..9af73db6849 100644
--- a/src/tools/clippy/clippy_lints/src/default_numeric_fallback.rs
+++ b/src/tools/clippy/clippy_lints/src/default_numeric_fallback.rs
@@ -50,6 +50,8 @@ declare_lint_pass!(DefaultNumericFallback => [DEFAULT_NUMERIC_FALLBACK]);
 impl<'tcx> LateLintPass<'tcx> for DefaultNumericFallback {
     fn check_body(&mut self, cx: &LateContext<'tcx>, body: &Body<'tcx>) {
         let hir = cx.tcx.hir();
+        // NOTE: this is different from `clippy_utils::is_inside_always_const_context`.
+        // Inline const supports type inference.
         let is_parent_const = matches!(
             hir.body_const_context(hir.body_owner_def_id(body.id())),
             Some(ConstContext::Const { inline: false } | ConstContext::Static(_))
diff --git a/src/tools/clippy/clippy_lints/src/dereference.rs b/src/tools/clippy/clippy_lints/src/dereference.rs
index a115f8d0631..253f9959e13 100644
--- a/src/tools/clippy/clippy_lints/src/dereference.rs
+++ b/src/tools/clippy/clippy_lints/src/dereference.rs
@@ -3,7 +3,8 @@ use clippy_utils::source::{snippet_with_applicability, snippet_with_context};
 use clippy_utils::sugg::has_enclosing_paren;
 use clippy_utils::ty::{implements_trait, is_manually_drop, peel_mid_ty_refs};
 use clippy_utils::{
-    expr_use_ctxt, get_parent_expr, is_block_like, is_lint_allowed, path_to_local, DefinedTy, ExprUseNode,
+    expr_use_ctxt, get_parent_expr, is_block_like, is_lint_allowed, path_to_local, peel_middle_ty_refs, DefinedTy,
+    ExprUseNode,
 };
 use core::mem;
 use rustc_ast::util::parser::{PREC_PREFIX, PREC_UNAMBIGUOUS};
@@ -175,6 +176,7 @@ struct StateData<'tcx> {
     adjusted_ty: Ty<'tcx>,
 }
 
+#[derive(Debug)]
 struct DerefedBorrow {
     count: usize,
     msg: &'static str,
@@ -182,6 +184,7 @@ struct DerefedBorrow {
     for_field_access: Option<Symbol>,
 }
 
+#[derive(Debug)]
 enum State {
     // Any number of deref method calls.
     DerefMethod {
@@ -744,7 +747,7 @@ fn in_postfix_position<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'tcx>) -> boo
     }
 }
 
-#[derive(Clone, Copy)]
+#[derive(Clone, Copy, Debug)]
 enum TyCoercionStability {
     Deref,
     Reborrow,
@@ -1042,16 +1045,28 @@ fn report<'tcx>(
                 return;
             }
 
-            let (prefix, precedence) = if let Some(mutability) = mutability
-                && !typeck.expr_ty(expr).is_ref()
+            let ty = typeck.expr_ty(expr);
+
+            // `&&[T; N]`, or `&&..&[T; N]` (src) cannot coerce to `&[T]` (dst).
+            if let ty::Ref(_, dst, _) = data.adjusted_ty.kind()
+                && dst.is_slice()
             {
-                let prefix = match mutability {
-                    Mutability::Not => "&",
-                    Mutability::Mut => "&mut ",
-                };
-                (prefix, PREC_PREFIX)
-            } else {
-                ("", 0)
+                let (src, n_src_refs) = peel_middle_ty_refs(ty);
+                if n_src_refs >= 2 && src.is_array() {
+                    return;
+                }
+            }
+
+            let (prefix, precedence) = match mutability {
+                Some(mutability) if !ty.is_ref() => {
+                    let prefix = match mutability {
+                        Mutability::Not => "&",
+                        Mutability::Mut => "&mut ",
+                    };
+                    (prefix, PREC_PREFIX)
+                },
+                None if !ty.is_ref() && data.adjusted_ty.is_ref() => ("&", 0),
+                _ => ("", 0),
             };
             span_lint_hir_and_then(
                 cx,
diff --git a/src/tools/clippy/clippy_lints/src/disallowed_methods.rs b/src/tools/clippy/clippy_lints/src/disallowed_methods.rs
index 9de879604e2..38fe687f7cc 100644
--- a/src/tools/clippy/clippy_lints/src/disallowed_methods.rs
+++ b/src/tools/clippy/clippy_lints/src/disallowed_methods.rs
@@ -1,6 +1,6 @@
 use clippy_config::types::DisallowedPath;
 use clippy_utils::diagnostics::span_lint_and_then;
-use clippy_utils::{fn_def_id, get_parent_expr, path_def_id};
+use rustc_hir::def::{CtorKind, DefKind, Res};
 use rustc_hir::def_id::DefIdMap;
 use rustc_hir::{Expr, ExprKind};
 use rustc_lint::{LateContext, LateLintPass};
@@ -83,26 +83,26 @@ impl<'tcx> LateLintPass<'tcx> for DisallowedMethods {
     }
 
     fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
-        let uncalled_path = if let Some(parent) = get_parent_expr(cx, expr)
-            && let ExprKind::Call(receiver, _) = parent.kind
-            && receiver.hir_id == expr.hir_id
-        {
-            None
-        } else {
-            path_def_id(cx, expr)
+        let (id, span) = match &expr.kind {
+            ExprKind::Path(path)
+                if let Res::Def(DefKind::Fn | DefKind::Ctor(_, CtorKind::Fn) | DefKind::AssocFn, id) =
+                    cx.qpath_res(path, expr.hir_id) =>
+            {
+                (id, expr.span)
+            },
+            ExprKind::MethodCall(name, ..) if let Some(id) = cx.typeck_results().type_dependent_def_id(expr.hir_id) => {
+                (id, name.ident.span)
+            },
+            _ => return,
         };
-        let Some(def_id) = uncalled_path.or_else(|| fn_def_id(cx, expr)) else {
-            return;
-        };
-        let conf = match self.disallowed.get(&def_id) {
-            Some(&index) => &self.conf_disallowed[index],
-            None => return,
-        };
-        let msg = format!("use of a disallowed method `{}`", conf.path());
-        span_lint_and_then(cx, DISALLOWED_METHODS, expr.span, msg, |diag| {
-            if let Some(reason) = conf.reason() {
-                diag.note(reason);
-            }
-        });
+        if let Some(&index) = self.disallowed.get(&id) {
+            let conf = &self.conf_disallowed[index];
+            let msg = format!("use of a disallowed method `{}`", conf.path());
+            span_lint_and_then(cx, DISALLOWED_METHODS, span, msg, |diag| {
+                if let Some(reason) = conf.reason() {
+                    diag.note(reason);
+                }
+            });
+        }
     }
 }
diff --git a/src/tools/clippy/clippy_lints/src/disallowed_names.rs b/src/tools/clippy/clippy_lints/src/disallowed_names.rs
index 2afbf184117..58809604c37 100644
--- a/src/tools/clippy/clippy_lints/src/disallowed_names.rs
+++ b/src/tools/clippy/clippy_lints/src/disallowed_names.rs
@@ -1,7 +1,7 @@
 use clippy_utils::diagnostics::span_lint;
-use clippy_utils::is_test_module_or_function;
+use clippy_utils::is_in_test;
 use rustc_data_structures::fx::FxHashSet;
-use rustc_hir::{Item, Pat, PatKind};
+use rustc_hir::{Pat, PatKind};
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_session::impl_lint_pass;
 
@@ -27,52 +27,30 @@ declare_clippy_lint! {
 #[derive(Clone, Debug)]
 pub struct DisallowedNames {
     disallow: FxHashSet<String>,
-    test_modules_deep: u32,
 }
 
 impl DisallowedNames {
     pub fn new(disallowed_names: &[String]) -> Self {
         Self {
             disallow: disallowed_names.iter().cloned().collect(),
-            test_modules_deep: 0,
         }
     }
-
-    fn in_test_module(&self) -> bool {
-        self.test_modules_deep != 0
-    }
 }
 
 impl_lint_pass!(DisallowedNames => [DISALLOWED_NAMES]);
 
 impl<'tcx> LateLintPass<'tcx> for DisallowedNames {
-    fn check_item(&mut self, cx: &LateContext<'_>, item: &Item<'_>) {
-        if is_test_module_or_function(cx.tcx, item) {
-            self.test_modules_deep = self.test_modules_deep.saturating_add(1);
-        }
-    }
-
     fn check_pat(&mut self, cx: &LateContext<'tcx>, pat: &'tcx Pat<'_>) {
-        // Check whether we are under the `test` attribute.
-        if self.in_test_module() {
-            return;
-        }
-
-        if let PatKind::Binding(.., ident, _) = pat.kind {
-            if self.disallow.contains(&ident.name.to_string()) {
-                span_lint(
-                    cx,
-                    DISALLOWED_NAMES,
-                    ident.span,
-                    format!("use of a disallowed/placeholder name `{}`", ident.name),
-                );
-            }
-        }
-    }
-
-    fn check_item_post(&mut self, cx: &LateContext<'_>, item: &Item<'_>) {
-        if is_test_module_or_function(cx.tcx, item) {
-            self.test_modules_deep = self.test_modules_deep.saturating_sub(1);
+        if let PatKind::Binding(.., ident, _) = pat.kind
+            && self.disallow.contains(&ident.name.to_string())
+            && !is_in_test(cx.tcx, pat.hir_id)
+        {
+            span_lint(
+                cx,
+                DISALLOWED_NAMES,
+                ident.span,
+                format!("use of a disallowed/placeholder name `{}`", ident.name),
+            );
         }
     }
 }
diff --git a/src/tools/clippy/clippy_lints/src/disallowed_script_idents.rs b/src/tools/clippy/clippy_lints/src/disallowed_script_idents.rs
index a995f06fb73..5ce11900adf 100644
--- a/src/tools/clippy/clippy_lints/src/disallowed_script_idents.rs
+++ b/src/tools/clippy/clippy_lints/src/disallowed_script_idents.rs
@@ -82,30 +82,25 @@ impl EarlyLintPass for DisallowedScriptIdents {
             // Note: `symbol.as_str()` is an expensive operation, thus should not be called
             // more than once for a single symbol.
             let symbol_str = symbol.as_str();
-            if symbol_str.is_ascii() {
-                continue;
-            }
 
-            for c in symbol_str.chars() {
-                // We want to iterate through all the scripts associated with this character
-                // and check whether at least of one scripts is in the whitelist.
-                let forbidden_script = c
-                    .script_extension()
-                    .iter()
-                    .find(|script| !self.whitelist.contains(script));
-                if let Some(script) = forbidden_script {
-                    span_lint(
-                        cx,
-                        DISALLOWED_SCRIPT_IDENTS,
-                        span,
-                        format!(
-                            "identifier `{symbol_str}` has a Unicode script that is not allowed by configuration: {}",
-                            script.full_name()
-                        ),
-                    );
-                    // We don't want to spawn warning multiple times over a single identifier.
-                    break;
-                }
+            // Check if any character in the symbol is not part of any allowed script.
+            // Fast path for ascii-only idents.
+            if !symbol_str.is_ascii()
+                && let Some(script) = symbol_str.chars().find_map(|c| {
+                    c.script_extension()
+                        .iter()
+                        .find(|script| !self.whitelist.contains(script))
+                })
+            {
+                span_lint(
+                    cx,
+                    DISALLOWED_SCRIPT_IDENTS,
+                    span,
+                    format!(
+                        "identifier `{symbol_str}` has a Unicode script that is not allowed by configuration: {}",
+                        script.full_name()
+                    ),
+                );
             }
         }
     }
diff --git a/src/tools/clippy/clippy_lints/src/doc/lazy_continuation.rs b/src/tools/clippy/clippy_lints/src/doc/lazy_continuation.rs
index 38bc58a5501..bd1cc46e185 100644
--- a/src/tools/clippy/clippy_lints/src/doc/lazy_continuation.rs
+++ b/src/tools/clippy/clippy_lints/src/doc/lazy_continuation.rs
@@ -22,6 +22,7 @@ pub(super) fn check(
     range: Range<usize>,
     mut span: Span,
     containers: &[super::Container],
+    line_break_span: Span,
 ) {
     if doc[range.clone()].contains('\t') {
         // We don't do tab stops correctly.
@@ -46,11 +47,35 @@ pub(super) fn check(
         .sum();
     if ccount < blockquote_level || lcount < list_indentation {
         let msg = if ccount < blockquote_level {
-            "doc quote missing `>` marker"
+            "doc quote line without `>` marker"
         } else {
-            "doc list item missing indentation"
+            "doc list item without indentation"
         };
         span_lint_and_then(cx, DOC_LAZY_CONTINUATION, span, msg, |diag| {
+            let snippet = clippy_utils::source::snippet(cx, line_break_span, "");
+            if snippet.chars().filter(|&c| c == '\n').count() > 1
+                && let Some(doc_comment_start) = snippet.rfind('\n')
+                && let doc_comment = snippet[doc_comment_start..].trim()
+                && (doc_comment == "///" || doc_comment == "//!")
+            {
+                // suggest filling in a blank line
+                diag.span_suggestion_with_style(
+                    line_break_span.shrink_to_lo(),
+                    "if this should be its own paragraph, add a blank doc comment line",
+                    format!("\n{doc_comment}"),
+                    Applicability::MaybeIncorrect,
+                    SuggestionStyle::ShowAlways,
+                );
+                if ccount > 0 || blockquote_level > 0 {
+                    diag.help("if this not intended to be a quote at all, escape it with `\\>`");
+                } else {
+                    let indent = list_indentation - lcount;
+                    diag.help(format!(
+                        "if this is intended to be part of the list, indent {indent} spaces"
+                    ));
+                }
+                return;
+            }
             if ccount == 0 && blockquote_level == 0 {
                 // simpler suggestion style for indentation
                 let indent = list_indentation - lcount;
diff --git a/src/tools/clippy/clippy_lints/src/doc/mod.rs b/src/tools/clippy/clippy_lints/src/doc/mod.rs
index 3e210fd153b..a2a1a51920f 100644
--- a/src/tools/clippy/clippy_lints/src/doc/mod.rs
+++ b/src/tools/clippy/clippy_lints/src/doc/mod.rs
@@ -6,7 +6,8 @@ use clippy_utils::ty::is_type_diagnostic_item;
 use clippy_utils::visitors::Visitable;
 use clippy_utils::{in_constant, is_entrypoint_fn, is_trait_impl_item, method_chain_args};
 use pulldown_cmark::Event::{
-    Code, DisplayMath, End, FootnoteReference, HardBreak, Html, InlineHtml, InlineMath, Rule, SoftBreak, Start, TaskListMarker, Text,
+    Code, DisplayMath, End, FootnoteReference, HardBreak, Html, InlineHtml, InlineMath, Rule, SoftBreak, Start,
+    TaskListMarker, Text,
 };
 use pulldown_cmark::Tag::{BlockQuote, CodeBlock, FootnoteDefinition, Heading, Item, Link, Paragraph};
 use pulldown_cmark::{BrokenLink, CodeBlockKind, CowStr, Options, TagEnd};
@@ -747,7 +748,8 @@ fn check_doc<'a, Events: Iterator<Item = (pulldown_cmark::Event<'a>, Range<usize
             },
             Start(FootnoteDefinition(..)) => in_footnote_definition = true,
             End(TagEnd::FootnoteDefinition) => in_footnote_definition = false,
-            Start(_) | End(_) => (), // We don't care about other tags
+            Start(_) | End(_)  // We don't care about other tags
+            | TaskListMarker(_) | Code(_) | Rule | InlineMath(..) | DisplayMath(..) => (),
             SoftBreak | HardBreak => {
                 if !containers.is_empty()
                     && let Some((next_event, next_range)) = events.peek()
@@ -762,13 +764,24 @@ fn check_doc<'a, Events: Iterator<Item = (pulldown_cmark::Event<'a>, Range<usize
                         range.end..next_range.start,
                         Span::new(span.hi(), next_span.lo(), span.ctxt(), span.parent()),
                         &containers[..],
+                        span,
                     );
                 }
             },
-            TaskListMarker(_) | Code(_) | Rule | InlineMath(..) | DisplayMath(..) => (),
             FootnoteReference(text) | Text(text) => {
                 paragraph_range.end = range.end;
-                ticks_unbalanced |= text.contains('`') && !in_code;
+                let range_ = range.clone();
+                ticks_unbalanced |= text.contains('`')
+                    && !in_code
+                    && doc[range.clone()].bytes().enumerate().any(|(i, c)| {
+                        // scan the markdown source code bytes for backquotes that aren't preceded by backslashes
+                        // - use bytes, instead of chars, to avoid utf8 decoding overhead (special chars are ascii)
+                        // - relevant backquotes are within doc[range], but backslashes are not, because they're not
+                        //   actually part of the rendered text (pulldown-cmark doesn't emit any events for escapes)
+                        // - if `range_.start + i == 0`, then `range_.start + i - 1 == -1`, and since we're working in
+                        //   usize, that would underflow and maybe panic
+                        c == b'`' && (range_.start + i == 0 || doc.as_bytes().get(range_.start + i - 1) != Some(&b'\\'))
+                    });
                 if Some(&text) == in_link.as_ref() || ticks_unbalanced {
                     // Probably a link of the form `<http://example.com>`
                     // Which are represented as a link to "http://example.com" with
diff --git a/src/tools/clippy/clippy_lints/src/endian_bytes.rs b/src/tools/clippy/clippy_lints/src/endian_bytes.rs
index bb766e96338..99328e3e643 100644
--- a/src/tools/clippy/clippy_lints/src/endian_bytes.rs
+++ b/src/tools/clippy/clippy_lints/src/endian_bytes.rs
@@ -33,7 +33,7 @@ declare_clippy_lint! {
     /// Checks for the usage of the `to_le_bytes` method and/or the function `from_le_bytes`.
     ///
     /// ### Why restrict this?
-    /// To ensure use of big endian or the target’s endianness rather than little endian.
+    /// To ensure use of big-endian or the target’s endianness rather than little-endian.
     ///
     /// ### Example
     /// ```rust,ignore
@@ -51,7 +51,7 @@ declare_clippy_lint! {
     /// Checks for the usage of the `to_be_bytes` method and/or the function `from_be_bytes`.
     ///
     /// ### Why restrict this?
-    /// To ensure use of little endian or the target’s endianness rather than big endian.
+    /// To ensure use of little-endian or the target’s endianness rather than big-endian.
     ///
     /// ### Example
     /// ```rust,ignore
diff --git a/src/tools/clippy/clippy_lints/src/functions/impl_trait_in_params.rs b/src/tools/clippy/clippy_lints/src/functions/impl_trait_in_params.rs
index 6fb38a0d6dd..cf85c74e688 100644
--- a/src/tools/clippy/clippy_lints/src/functions/impl_trait_in_params.rs
+++ b/src/tools/clippy/clippy_lints/src/functions/impl_trait_in_params.rs
@@ -1,5 +1,5 @@
 use clippy_utils::diagnostics::span_lint_and_then;
-use clippy_utils::is_in_test_function;
+use clippy_utils::is_in_test;
 
 use rustc_hir as hir;
 use rustc_hir::intravisit::FnKind;
@@ -41,7 +41,7 @@ fn report(cx: &LateContext<'_>, param: &GenericParam<'_>, generics: &Generics<'_
 pub(super) fn check_fn<'tcx>(cx: &LateContext<'_>, kind: &'tcx FnKind<'_>, body: &'tcx Body<'_>, hir_id: HirId) {
     if let FnKind::ItemFn(_, generics, _) = kind
         && cx.tcx.visibility(cx.tcx.hir().body_owner_def_id(body.id())).is_public()
-        && !is_in_test_function(cx.tcx, hir_id)
+        && !is_in_test(cx.tcx, hir_id)
     {
         for param in generics.params {
             if param.is_impl_trait() {
@@ -59,7 +59,7 @@ pub(super) fn check_impl_item(cx: &LateContext<'_>, impl_item: &ImplItem<'_>) {
         && of_trait.is_none()
         && let body = cx.tcx.hir().body(body_id)
         && cx.tcx.visibility(cx.tcx.hir().body_owner_def_id(body.id())).is_public()
-        && !is_in_test_function(cx.tcx, impl_item.hir_id())
+        && !is_in_test(cx.tcx, impl_item.hir_id())
     {
         for param in impl_item.generics.params {
             if param.is_impl_trait() {
@@ -75,7 +75,7 @@ pub(super) fn check_trait_item(cx: &LateContext<'_>, trait_item: &TraitItem<'_>,
         && let hir::Node::Item(item) = cx.tcx.parent_hir_node(trait_item.hir_id())
         // ^^ (Will always be a trait)
         && !item.vis_span.is_empty() // Is public
-        && !is_in_test_function(cx.tcx, trait_item.hir_id())
+        && !is_in_test(cx.tcx, trait_item.hir_id())
     {
         for param in trait_item.generics.params {
             if param.is_impl_trait() {
diff --git a/src/tools/clippy/clippy_lints/src/incompatible_msrv.rs b/src/tools/clippy/clippy_lints/src/incompatible_msrv.rs
index 35b4481bfee..5c63d48adaf 100644
--- a/src/tools/clippy/clippy_lints/src/incompatible_msrv.rs
+++ b/src/tools/clippy/clippy_lints/src/incompatible_msrv.rs
@@ -1,6 +1,6 @@
 use clippy_config::msrvs::Msrv;
 use clippy_utils::diagnostics::span_lint;
-use clippy_utils::is_in_test_function;
+use clippy_utils::is_in_test;
 use rustc_attr::{StabilityLevel, StableSince};
 use rustc_data_structures::fx::FxHashMap;
 use rustc_hir::{Expr, ExprKind, HirId};
@@ -88,7 +88,7 @@ impl IncompatibleMsrv {
             return;
         }
         let version = self.get_def_id_version(cx.tcx, def_id);
-        if self.msrv.meets(version) || is_in_test_function(cx.tcx, node) {
+        if self.msrv.meets(version) || is_in_test(cx.tcx, node) {
             return;
         }
         if let ExpnKind::AstPass(_) | ExpnKind::Desugaring(_) = span.ctxt().outer_expn_data().kind {
diff --git a/src/tools/clippy/clippy_lints/src/inherent_to_string.rs b/src/tools/clippy/clippy_lints/src/inherent_to_string.rs
index 9aedf5ec7e8..ec6174bc030 100644
--- a/src/tools/clippy/clippy_lints/src/inherent_to_string.rs
+++ b/src/tools/clippy/clippy_lints/src/inherent_to_string.rs
@@ -91,10 +91,6 @@ declare_lint_pass!(InherentToString => [INHERENT_TO_STRING, INHERENT_TO_STRING_S
 
 impl<'tcx> LateLintPass<'tcx> for InherentToString {
     fn check_impl_item(&mut self, cx: &LateContext<'tcx>, impl_item: &'tcx ImplItem<'_>) {
-        if impl_item.span.from_expansion() {
-            return;
-        }
-
         // Check if item is a method called `to_string` and has a parameter 'self'
         if let ImplItemKind::Fn(ref signature, _) = impl_item.kind
             // #11201
@@ -106,6 +102,7 @@ impl<'tcx> LateLintPass<'tcx> for InherentToString {
             && decl.implicit_self.has_implicit_self()
             && decl.inputs.len() == 1
             && impl_item.generics.params.iter().all(|p| matches!(p.kind, GenericParamKind::Lifetime { .. }))
+            && !impl_item.span.from_expansion()
             // Check if return type is String
             && is_type_lang_item(cx, return_ty(cx, impl_item.owner_id), LangItem::String)
             // Filters instances of to_string which are required by a trait
diff --git a/src/tools/clippy/clippy_lints/src/init_numbered_fields.rs b/src/tools/clippy/clippy_lints/src/init_numbered_fields.rs
index 1c8fd0a27f9..7f183bb601e 100644
--- a/src/tools/clippy/clippy_lints/src/init_numbered_fields.rs
+++ b/src/tools/clippy/clippy_lints/src/init_numbered_fields.rs
@@ -1,13 +1,12 @@
-use clippy_utils::diagnostics::span_lint_and_sugg;
+use clippy_utils::diagnostics::span_lint_and_then;
 use clippy_utils::source::{snippet_with_applicability, snippet_with_context};
 use rustc_errors::Applicability;
 use rustc_hir::def::{DefKind, Res};
 use rustc_hir::{Expr, ExprKind};
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_session::declare_lint_pass;
+use rustc_span::SyntaxContext;
 use std::borrow::Cow;
-use std::cmp::Reverse;
-use std::collections::BinaryHeap;
 
 declare_clippy_lint! {
     /// ### What it does
@@ -44,38 +43,56 @@ declare_lint_pass!(NumberedFields => [INIT_NUMBERED_FIELDS]);
 
 impl<'tcx> LateLintPass<'tcx> for NumberedFields {
     fn check_expr(&mut self, cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) {
-        if let ExprKind::Struct(path, fields, None) = e.kind {
-            if !fields.is_empty()
-                && !e.span.from_expansion()
-                && fields
-                    .iter()
-                    .all(|f| f.ident.as_str().as_bytes().iter().all(u8::is_ascii_digit))
-                && !matches!(cx.qpath_res(path, e.hir_id), Res::Def(DefKind::TyAlias, ..))
-            {
-                let expr_spans = fields
-                    .iter()
-                    .map(|f| (Reverse(f.ident.as_str().parse::<usize>().unwrap()), f.expr.span))
-                    .collect::<BinaryHeap<_>>();
-                let mut appl = Applicability::MachineApplicable;
-                let snippet = format!(
-                    "{}({})",
-                    snippet_with_applicability(cx, path.span(), "..", &mut appl),
-                    expr_spans
-                        .into_iter_sorted()
-                        .map(|(_, span)| snippet_with_context(cx, span, path.span().ctxt(), "..", &mut appl).0)
-                        .intersperse(Cow::Borrowed(", "))
-                        .collect::<String>()
-                );
-                span_lint_and_sugg(
-                    cx,
-                    INIT_NUMBERED_FIELDS,
-                    e.span,
-                    "used a field initializer for a tuple struct",
-                    "try",
-                    snippet,
-                    appl,
-                );
-            }
+        if let ExprKind::Struct(path, fields @ [field, ..], None) = e.kind
+            // If the first character of any field is a digit it has to be a tuple.
+            && field.ident.as_str().as_bytes().first().is_some_and(u8::is_ascii_digit)
+            // Type aliases can't be used as functions.
+            && !matches!(
+                cx.qpath_res(path, e.hir_id),
+                Res::Def(DefKind::TyAlias | DefKind::AssocTy, _)
+            )
+            // This is the only syntax macros can use that works for all struct types.
+            && !e.span.from_expansion()
+            && let mut has_side_effects = false
+            && let Ok(mut expr_spans) = fields
+                .iter()
+                .map(|f| {
+                    has_side_effects |= f.expr.can_have_side_effects();
+                    f.ident.as_str().parse::<usize>().map(|x| (x, f.expr.span))
+                })
+                .collect::<Result<Vec<_>, _>>()
+            // We can only reorder the expressions if there are no side effects.
+            && (!has_side_effects || expr_spans.is_sorted_by_key(|&(idx, _)| idx))
+        {
+            span_lint_and_then(
+                cx,
+                INIT_NUMBERED_FIELDS,
+                e.span,
+                "used a field initializer for a tuple struct",
+                |diag| {
+                    if !has_side_effects {
+                        // We already checked the order if there are side effects.
+                        expr_spans.sort_by_key(|&(idx, _)| idx);
+                    }
+                    let mut app = Applicability::MachineApplicable;
+                    diag.span_suggestion(
+                        e.span,
+                        "use tuple initialization",
+                        format!(
+                            "{}({})",
+                            snippet_with_applicability(cx, path.span(), "..", &mut app),
+                            expr_spans
+                                .into_iter()
+                                .map(
+                                    |(_, span)| snippet_with_context(cx, span, SyntaxContext::root(), "..", &mut app).0
+                                )
+                                .intersperse(Cow::Borrowed(", "))
+                                .collect::<String>()
+                        ),
+                        app,
+                    );
+                },
+            );
         }
     }
 }
diff --git a/src/tools/clippy/clippy_lints/src/inline_fn_without_body.rs b/src/tools/clippy/clippy_lints/src/inline_fn_without_body.rs
index 860258fd030..5657c58bb0a 100644
--- a/src/tools/clippy/clippy_lints/src/inline_fn_without_body.rs
+++ b/src/tools/clippy/clippy_lints/src/inline_fn_without_body.rs
@@ -2,12 +2,11 @@
 
 use clippy_utils::diagnostics::span_lint_and_then;
 use clippy_utils::sugg::DiagExt;
-use rustc_ast::ast::Attribute;
 use rustc_errors::Applicability;
 use rustc_hir::{TraitFn, TraitItem, TraitItemKind};
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_session::declare_lint_pass;
-use rustc_span::{sym, Symbol};
+use rustc_span::sym;
 
 declare_clippy_lint! {
     /// ### What it does
@@ -34,27 +33,23 @@ declare_lint_pass!(InlineFnWithoutBody => [INLINE_FN_WITHOUT_BODY]);
 
 impl<'tcx> LateLintPass<'tcx> for InlineFnWithoutBody {
     fn check_trait_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx TraitItem<'_>) {
-        if let TraitItemKind::Fn(_, TraitFn::Required(_)) = item.kind {
-            let attrs = cx.tcx.hir().attrs(item.hir_id());
-            check_attrs(cx, item.ident.name, attrs);
+        if let TraitItemKind::Fn(_, TraitFn::Required(_)) = item.kind
+            && let Some(attr) = cx
+                .tcx
+                .hir()
+                .attrs(item.hir_id())
+                .iter()
+                .find(|a| a.has_name(sym::inline))
+        {
+            span_lint_and_then(
+                cx,
+                INLINE_FN_WITHOUT_BODY,
+                attr.span,
+                format!("use of `#[inline]` on trait method `{}` which has no body", item.ident),
+                |diag| {
+                    diag.suggest_remove_item(cx, attr.span, "remove", Applicability::MachineApplicable);
+                },
+            );
         }
     }
 }
-
-fn check_attrs(cx: &LateContext<'_>, name: Symbol, attrs: &[Attribute]) {
-    for attr in attrs {
-        if !attr.has_name(sym::inline) {
-            continue;
-        }
-
-        span_lint_and_then(
-            cx,
-            INLINE_FN_WITHOUT_BODY,
-            attr.span,
-            format!("use of `#[inline]` on trait method `{name}` which has no body"),
-            |diag| {
-                diag.suggest_remove_item(cx, attr.span, "remove", Applicability::MachineApplicable);
-            },
-        );
-    }
-}
diff --git a/src/tools/clippy/clippy_lints/src/instant_subtraction.rs b/src/tools/clippy/clippy_lints/src/instant_subtraction.rs
index 10b00f632bb..5fe152d1e30 100644
--- a/src/tools/clippy/clippy_lints/src/instant_subtraction.rs
+++ b/src/tools/clippy/clippy_lints/src/instant_subtraction.rs
@@ -85,16 +85,19 @@ impl LateLintPass<'_> for InstantSubtraction {
             lhs,
             rhs,
         ) = expr.kind
+            && let typeck = cx.typeck_results()
+            && ty::is_type_diagnostic_item(cx, typeck.expr_ty(lhs), sym::Instant)
         {
+            let rhs_ty = typeck.expr_ty(rhs);
+
             if is_instant_now_call(cx, lhs)
-                && is_an_instant(cx, rhs)
+                && ty::is_type_diagnostic_item(cx, rhs_ty, sym::Instant)
                 && let Some(sugg) = Sugg::hir_opt(cx, rhs)
             {
                 print_manual_instant_elapsed_sugg(cx, expr, sugg);
-            } else if !expr.span.from_expansion()
+            } else if ty::is_type_diagnostic_item(cx, rhs_ty, sym::Duration)
+                && !expr.span.from_expansion()
                 && self.msrv.meets(msrvs::TRY_FROM)
-                && is_an_instant(cx, lhs)
-                && is_a_duration(cx, rhs)
             {
                 print_unchecked_duration_subtraction_sugg(cx, lhs, rhs, expr);
             }
@@ -115,16 +118,6 @@ fn is_instant_now_call(cx: &LateContext<'_>, expr_block: &'_ Expr<'_>) -> bool {
     }
 }
 
-fn is_an_instant(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
-    let expr_ty = cx.typeck_results().expr_ty(expr);
-    ty::is_type_diagnostic_item(cx, expr_ty, sym::Instant)
-}
-
-fn is_a_duration(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
-    let expr_ty = cx.typeck_results().expr_ty(expr);
-    ty::is_type_diagnostic_item(cx, expr_ty, sym::Duration)
-}
-
 fn print_manual_instant_elapsed_sugg(cx: &LateContext<'_>, expr: &Expr<'_>, sugg: Sugg<'_>) {
     span_lint_and_sugg(
         cx,
diff --git a/src/tools/clippy/clippy_lints/src/items_after_statements.rs b/src/tools/clippy/clippy_lints/src/items_after_statements.rs
index 39223c20470..a88d8e24fda 100644
--- a/src/tools/clippy/clippy_lints/src/items_after_statements.rs
+++ b/src/tools/clippy/clippy_lints/src/items_after_statements.rs
@@ -54,36 +54,35 @@ declare_lint_pass!(ItemsAfterStatements => [ITEMS_AFTER_STATEMENTS]);
 
 impl LateLintPass<'_> for ItemsAfterStatements {
     fn check_block(&mut self, cx: &LateContext<'_>, block: &Block<'_>) {
-        if in_external_macro(cx.sess(), block.span) {
-            return;
-        }
-
-        // skip initial items
-        let stmts = block
-            .stmts
-            .iter()
-            .skip_while(|stmt| matches!(stmt.kind, StmtKind::Item(..)));
-
-        // lint on all further items
-        for stmt in stmts {
-            if let StmtKind::Item(item_id) = stmt.kind {
-                let item = cx.tcx.hir().item(item_id);
-                if in_external_macro(cx.sess(), item.span) || !item.span.eq_ctxt(block.span) {
-                    return;
-                }
-                if let ItemKind::Macro(..) = item.kind {
-                    // do not lint `macro_rules`, but continue processing further statements
-                    continue;
-                }
-                span_lint_hir(
-                    cx,
-                    ITEMS_AFTER_STATEMENTS,
-                    item.hir_id(),
-                    item.span,
-                    "adding items after statements is confusing, since items exist from the \
-                     start of the scope",
-                );
-            }
+        if block.stmts.len() > 1 {
+            let ctxt = block.span.ctxt();
+            let mut in_external = None;
+            block
+                .stmts
+                .iter()
+                .skip_while(|stmt| matches!(stmt.kind, StmtKind::Item(..)))
+                .filter_map(|stmt| match stmt.kind {
+                    StmtKind::Item(id) => Some(cx.tcx.hir().item(id)),
+                    _ => None,
+                })
+                // Ignore macros since they can only see previously defined locals.
+                .filter(|item| !matches!(item.kind, ItemKind::Macro(..)))
+                // Stop linting if macros define items.
+                .take_while(|item| item.span.ctxt() == ctxt)
+                // Don't use `next` due to the complex filter chain.
+                .for_each(|item| {
+                    // Only do the macro check once, but delay it until it's needed.
+                    if !*in_external.get_or_insert_with(|| in_external_macro(cx.sess(), block.span)) {
+                        span_lint_hir(
+                            cx,
+                            ITEMS_AFTER_STATEMENTS,
+                            item.hir_id(),
+                            item.span,
+                            "adding items after statements is confusing, since items exist from the \
+                                start of the scope",
+                        );
+                    }
+                });
         }
     }
 }
diff --git a/src/tools/clippy/clippy_lints/src/iter_not_returning_iterator.rs b/src/tools/clippy/clippy_lints/src/iter_not_returning_iterator.rs
index 1b5f1b49947..ba0cd5d6eb3 100644
--- a/src/tools/clippy/clippy_lints/src/iter_not_returning_iterator.rs
+++ b/src/tools/clippy/clippy_lints/src/iter_not_returning_iterator.rs
@@ -4,7 +4,7 @@ use rustc_hir::def_id::LocalDefId;
 use rustc_hir::{FnSig, ImplItem, ImplItemKind, Item, ItemKind, Node, TraitItem, TraitItemKind};
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_session::declare_lint_pass;
-use rustc_span::symbol::sym;
+use rustc_span::{sym, Symbol};
 
 declare_clippy_lint! {
     /// ### What it does
@@ -43,30 +43,27 @@ declare_lint_pass!(IterNotReturningIterator => [ITER_NOT_RETURNING_ITERATOR]);
 
 impl<'tcx> LateLintPass<'tcx> for IterNotReturningIterator {
     fn check_trait_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx TraitItem<'_>) {
-        let name = item.ident.name.as_str();
-        if matches!(name, "iter" | "iter_mut") {
-            if let TraitItemKind::Fn(fn_sig, _) = &item.kind {
-                check_sig(cx, name, fn_sig, item.owner_id.def_id);
-            }
+        if let TraitItemKind::Fn(fn_sig, _) = &item.kind
+            && matches!(item.ident.name, sym::iter | sym::iter_mut)
+        {
+            check_sig(cx, item.ident.name, fn_sig, item.owner_id.def_id);
         }
     }
 
     fn check_impl_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx ImplItem<'tcx>) {
-        let name = item.ident.name.as_str();
-        if matches!(name, "iter" | "iter_mut")
+        if let ImplItemKind::Fn(fn_sig, _) = &item.kind
+            && matches!(item.ident.name, sym::iter | sym::iter_mut)
             && !matches!(
                 cx.tcx.parent_hir_node(item.hir_id()),
                 Node::Item(Item { kind: ItemKind::Impl(i), .. }) if i.of_trait.is_some()
             )
         {
-            if let ImplItemKind::Fn(fn_sig, _) = &item.kind {
-                check_sig(cx, name, fn_sig, item.owner_id.def_id);
-            }
+            check_sig(cx, item.ident.name, fn_sig, item.owner_id.def_id);
         }
     }
 }
 
-fn check_sig(cx: &LateContext<'_>, name: &str, sig: &FnSig<'_>, fn_id: LocalDefId) {
+fn check_sig(cx: &LateContext<'_>, name: Symbol, sig: &FnSig<'_>, fn_id: LocalDefId) {
     if sig.decl.implicit_self.has_implicit_self() {
         let ret_ty = cx
             .tcx
diff --git a/src/tools/clippy/clippy_lints/src/iter_without_into_iter.rs b/src/tools/clippy/clippy_lints/src/iter_without_into_iter.rs
index 6b03f2597b0..1e6404190d3 100644
--- a/src/tools/clippy/clippy_lints/src/iter_without_into_iter.rs
+++ b/src/tools/clippy/clippy_lints/src/iter_without_into_iter.rs
@@ -125,13 +125,13 @@ fn is_ty_exported(cx: &LateContext<'_>, ty: Ty<'_>) -> bool {
 
 impl LateLintPass<'_> for IterWithoutIntoIter {
     fn check_item(&mut self, cx: &LateContext<'_>, item: &rustc_hir::Item<'_>) {
-        if !in_external_macro(cx.sess(), item.span)
-            && let ItemKind::Impl(imp) = item.kind
+        if let ItemKind::Impl(imp) = item.kind
             && let TyKind::Ref(_, self_ty_without_ref) = &imp.self_ty.kind
             && let Some(trait_ref) = imp.of_trait
             && trait_ref
                 .trait_def_id()
                 .is_some_and(|did| cx.tcx.is_diagnostic_item(sym::IntoIterator, did))
+            && !in_external_macro(cx.sess(), item.span)
             && let &ty::Ref(_, ty, mtbl) = cx.tcx.type_of(item.owner_id).instantiate_identity().kind()
             && let expected_method_name = match mtbl {
                 Mutability::Mut => sym::iter_mut,
diff --git a/src/tools/clippy/clippy_lints/src/large_const_arrays.rs b/src/tools/clippy/clippy_lints/src/large_const_arrays.rs
index 7f8197c0cc0..b18ab625e60 100644
--- a/src/tools/clippy/clippy_lints/src/large_const_arrays.rs
+++ b/src/tools/clippy/clippy_lints/src/large_const_arrays.rs
@@ -46,12 +46,12 @@ impl_lint_pass!(LargeConstArrays => [LARGE_CONST_ARRAYS]);
 
 impl<'tcx> LateLintPass<'tcx> for LargeConstArrays {
     fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'_>) {
-        if !item.span.from_expansion()
-            && let ItemKind::Const(_, generics, _) = &item.kind
+        if let ItemKind::Const(_, generics, _) = &item.kind
             // Since static items may not have generics, skip generic const items.
             // FIXME(generic_const_items): I don't think checking `generics.hwcp` suffices as it
             // doesn't account for empty where-clauses that only consist of keyword `where` IINM.
             && generics.params.is_empty() && !generics.has_where_clause_predicates
+            && !item.span.from_expansion()
             && let ty = cx.tcx.type_of(item.owner_id).instantiate_identity()
             && let ty::Array(element_type, cst) = ty.kind()
             && let ConstKind::Value(_, ty::ValTree::Leaf(element_count)) = cst.kind()
diff --git a/src/tools/clippy/clippy_lints/src/large_enum_variant.rs b/src/tools/clippy/clippy_lints/src/large_enum_variant.rs
index 0bf7389ef9c..85daadcc537 100644
--- a/src/tools/clippy/clippy_lints/src/large_enum_variant.rs
+++ b/src/tools/clippy/clippy_lints/src/large_enum_variant.rs
@@ -77,17 +77,12 @@ impl_lint_pass!(LargeEnumVariant => [LARGE_ENUM_VARIANT]);
 
 impl<'tcx> LateLintPass<'tcx> for LargeEnumVariant {
     fn check_item(&mut self, cx: &LateContext<'tcx>, item: &Item<'tcx>) {
-        if in_external_macro(cx.tcx.sess, item.span) {
-            return;
-        }
-        if let ItemKind::Enum(ref def, _) = item.kind {
-            let ty = cx.tcx.type_of(item.owner_id).instantiate_identity();
-            let ty::Adt(adt, subst) = ty.kind() else {
-                panic!("already checked whether this is an enum")
-            };
-            if adt.variants().len() <= 1 {
-                return;
-            }
+        if let ItemKind::Enum(ref def, _) = item.kind
+            && let ty = cx.tcx.type_of(item.owner_id).instantiate_identity()
+            && let ty::Adt(adt, subst) = ty.kind()
+            && adt.variants().len() > 1
+            && !in_external_macro(cx.tcx.sess, item.span)
+        {
             let variants_size = AdtVariantInfo::new(cx, *adt, subst);
 
             let mut difference = variants_size[0].size - variants_size[1].size;
diff --git a/src/tools/clippy/clippy_lints/src/large_futures.rs b/src/tools/clippy/clippy_lints/src/large_futures.rs
index 07488a512a3..602227e4249 100644
--- a/src/tools/clippy/clippy_lints/src/large_futures.rs
+++ b/src/tools/clippy/clippy_lints/src/large_futures.rs
@@ -54,29 +54,26 @@ impl_lint_pass!(LargeFuture => [LARGE_FUTURES]);
 
 impl<'tcx> LateLintPass<'tcx> for LargeFuture {
     fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) {
-        if matches!(expr.span.ctxt().outer_expn_data().kind, rustc_span::ExpnKind::Macro(..)) {
-            return;
-        }
-        if let ExprKind::Match(expr, _, MatchSource::AwaitDesugar) = expr.kind {
-            if let ExprKind::Call(func, [expr, ..]) = expr.kind
-                && let ExprKind::Path(QPath::LangItem(LangItem::IntoFutureIntoFuture, ..)) = func.kind
-                && let ty = cx.typeck_results().expr_ty(expr)
-                && let Some(future_trait_def_id) = cx.tcx.lang_items().future_trait()
-                && implements_trait(cx, ty, future_trait_def_id, &[])
-                && let Ok(layout) = cx.tcx.layout_of(cx.param_env.and(ty))
-                && let size = layout.layout.size()
-                && size >= Size::from_bytes(self.future_size_threshold)
-            {
-                span_lint_and_sugg(
-                    cx,
-                    LARGE_FUTURES,
-                    expr.span,
-                    format!("large future with a size of {} bytes", size.bytes()),
-                    "consider `Box::pin` on it",
-                    format!("Box::pin({})", snippet(cx, expr.span, "..")),
-                    Applicability::Unspecified,
-                );
-            }
+        if let ExprKind::Match(scrutinee, _, MatchSource::AwaitDesugar) = expr.kind
+            && let ExprKind::Call(func, [arg, ..]) = scrutinee.kind
+            && let ExprKind::Path(QPath::LangItem(LangItem::IntoFutureIntoFuture, ..)) = func.kind
+            && !expr.span.from_expansion()
+            && let ty = cx.typeck_results().expr_ty(arg)
+            && let Some(future_trait_def_id) = cx.tcx.lang_items().future_trait()
+            && implements_trait(cx, ty, future_trait_def_id, &[])
+            && let Ok(layout) = cx.tcx.layout_of(cx.param_env.and(ty))
+            && let size = layout.layout.size()
+            && size >= Size::from_bytes(self.future_size_threshold)
+        {
+            span_lint_and_sugg(
+                cx,
+                LARGE_FUTURES,
+                arg.span,
+                format!("large future with a size of {} bytes", size.bytes()),
+                "consider `Box::pin` on it",
+                format!("Box::pin({})", snippet(cx, arg.span, "..")),
+                Applicability::Unspecified,
+            );
         }
     }
 }
diff --git a/src/tools/clippy/clippy_lints/src/large_include_file.rs b/src/tools/clippy/clippy_lints/src/large_include_file.rs
index 07efee159aa..2688283a6ce 100644
--- a/src/tools/clippy/clippy_lints/src/large_include_file.rs
+++ b/src/tools/clippy/clippy_lints/src/large_include_file.rs
@@ -1,5 +1,4 @@
 use clippy_utils::diagnostics::span_lint_and_note;
-use clippy_utils::is_lint_allowed;
 use clippy_utils::macros::root_macro_call_first_node;
 use rustc_ast::LitKind;
 use rustc_hir::{Expr, ExprKind};
@@ -52,24 +51,19 @@ impl_lint_pass!(LargeIncludeFile => [LARGE_INCLUDE_FILE]);
 
 impl LateLintPass<'_> for LargeIncludeFile {
     fn check_expr(&mut self, cx: &LateContext<'_>, expr: &'_ Expr<'_>) {
-        if let Some(macro_call) = root_macro_call_first_node(cx, expr)
-            && !is_lint_allowed(cx, LARGE_INCLUDE_FILE, expr.hir_id)
-            && (cx.tcx.is_diagnostic_item(sym::include_bytes_macro, macro_call.def_id)
-                || cx.tcx.is_diagnostic_item(sym::include_str_macro, macro_call.def_id))
-            && let ExprKind::Lit(lit) = &expr.kind
-        {
-            let len = match &lit.node {
+        if let ExprKind::Lit(lit) = &expr.kind
+            && let len = match &lit.node {
                 // include_bytes
                 LitKind::ByteStr(bstr, _) => bstr.len(),
                 // include_str
                 LitKind::Str(sym, _) => sym.as_str().len(),
                 _ => return,
-            };
-
-            if len as u64 <= self.max_file_size {
-                return;
             }
-
+            && len as u64 > self.max_file_size
+            && let Some(macro_call) = root_macro_call_first_node(cx, expr)
+            && (cx.tcx.is_diagnostic_item(sym::include_bytes_macro, macro_call.def_id)
+                || cx.tcx.is_diagnostic_item(sym::include_str_macro, macro_call.def_id))
+        {
             span_lint_and_note(
                 cx,
                 LARGE_INCLUDE_FILE,
diff --git a/src/tools/clippy/clippy_lints/src/legacy_numeric_constants.rs b/src/tools/clippy/clippy_lints/src/legacy_numeric_constants.rs
index eadfeb6e341..a08b40bef37 100644
--- a/src/tools/clippy/clippy_lints/src/legacy_numeric_constants.rs
+++ b/src/tools/clippy/clippy_lints/src/legacy_numeric_constants.rs
@@ -48,15 +48,11 @@ impl_lint_pass!(LegacyNumericConstants => [LEGACY_NUMERIC_CONSTANTS]);
 
 impl<'tcx> LateLintPass<'tcx> for LegacyNumericConstants {
     fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'tcx>) {
-        let Self { msrv } = self;
-
-        if !msrv.meets(NUMERIC_ASSOCIATED_CONSTANTS) || in_external_macro(cx.sess(), item.span) {
-            return;
-        }
-
         // Integer modules are "TBD" deprecated, and the contents are too,
         // so lint on the `use` statement directly.
         if let ItemKind::Use(path, kind @ (UseKind::Single | UseKind::Glob)) = item.kind
+            && self.msrv.meets(NUMERIC_ASSOCIATED_CONSTANTS)
+            && !in_external_macro(cx.sess(), item.span)
             && let Some(def_id) = path.res[0].opt_def_id()
         {
             let module = if is_integer_module(cx, def_id) {
@@ -103,12 +99,7 @@ impl<'tcx> LateLintPass<'tcx> for LegacyNumericConstants {
     }
 
     fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx rustc_hir::Expr<'tcx>) {
-        let Self { msrv } = self;
-
-        if !msrv.meets(NUMERIC_ASSOCIATED_CONSTANTS) || in_external_macro(cx.sess(), expr.span) {
-            return;
-        }
-        let ExprKind::Path(qpath) = expr.kind else {
+        let ExprKind::Path(qpath) = &expr.kind else {
             return;
         };
 
@@ -129,10 +120,10 @@ impl<'tcx> LateLintPass<'tcx> for LegacyNumericConstants {
             )
         // `<integer>::xxx_value` check
         } else if let QPath::TypeRelative(_, last_segment) = qpath
-            && let Some(def_id) = cx.qpath_res(&qpath, expr.hir_id).opt_def_id()
-            && is_integer_method(cx, def_id)
+            && let Some(def_id) = cx.qpath_res(qpath, expr.hir_id).opt_def_id()
             && let Some(par_expr) = get_parent_expr(cx, expr)
-            && let ExprKind::Call(_, _) = par_expr.kind
+            && let ExprKind::Call(_, []) = par_expr.kind
+            && is_integer_method(cx, def_id)
         {
             let name = last_segment.ident.name.as_str();
 
@@ -145,19 +136,20 @@ impl<'tcx> LateLintPass<'tcx> for LegacyNumericConstants {
             return;
         };
 
-        if is_from_proc_macro(cx, expr) {
-            return;
+        if self.msrv.meets(NUMERIC_ASSOCIATED_CONSTANTS)
+            && !in_external_macro(cx.sess(), expr.span)
+            && !is_from_proc_macro(cx, expr)
+        {
+            span_lint_hir_and_then(cx, LEGACY_NUMERIC_CONSTANTS, expr.hir_id, span, msg, |diag| {
+                diag.span_suggestion_with_style(
+                    span,
+                    "use the associated constant instead",
+                    sugg,
+                    Applicability::MaybeIncorrect,
+                    SuggestionStyle::ShowAlways,
+                );
+            });
         }
-
-        span_lint_hir_and_then(cx, LEGACY_NUMERIC_CONSTANTS, expr.hir_id, span, msg, |diag| {
-            diag.span_suggestion_with_style(
-                span,
-                "use the associated constant instead",
-                sugg,
-                Applicability::MaybeIncorrect,
-                SuggestionStyle::ShowAlways,
-            );
-        });
     }
 
     extract_msrv_attr!(LateContext);
diff --git a/src/tools/clippy/clippy_lints/src/len_zero.rs b/src/tools/clippy/clippy_lints/src/len_zero.rs
index 57e0a7aa2c7..4c737371bd2 100644
--- a/src/tools/clippy/clippy_lints/src/len_zero.rs
+++ b/src/tools/clippy/clippy_lints/src/len_zero.rs
@@ -121,11 +121,9 @@ declare_lint_pass!(LenZero => [LEN_ZERO, LEN_WITHOUT_IS_EMPTY, COMPARISON_TO_EMP
 
 impl<'tcx> LateLintPass<'tcx> for LenZero {
     fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'_>) {
-        if item.span.from_expansion() {
-            return;
-        }
-
-        if let ItemKind::Trait(_, _, _, _, trait_items) = item.kind {
+        if let ItemKind::Trait(_, _, _, _, trait_items) = item.kind
+            && !item.span.from_expansion()
+        {
             check_trait_items(cx, item, trait_items);
         }
     }
@@ -162,17 +160,14 @@ impl<'tcx> LateLintPass<'tcx> for LenZero {
     }
 
     fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
-        if expr.span.from_expansion() {
-            return;
-        }
-
         if let ExprKind::Let(lt) = expr.kind
-            && has_is_empty(cx, lt.init)
             && match lt.pat.kind {
                 PatKind::Slice([], None, []) => true,
                 PatKind::Lit(lit) if is_empty_string(lit) => true,
                 _ => false,
             }
+            && !expr.span.from_expansion()
+            && has_is_empty(cx, lt.init)
         {
             let mut applicability = Applicability::MachineApplicable;
 
@@ -190,7 +185,9 @@ impl<'tcx> LateLintPass<'tcx> for LenZero {
             );
         }
 
-        if let ExprKind::Binary(Spanned { node: cmp, .. }, left, right) = expr.kind {
+        if let ExprKind::Binary(Spanned { node: cmp, .. }, left, right) = expr.kind
+            && !expr.span.from_expansion()
+        {
             // expr.span might contains parenthesis, see issue #10529
             let actual_span = span_without_enclosing_paren(cx, expr.span);
             match cmp {
diff --git a/src/tools/clippy/clippy_lints/src/let_if_seq.rs b/src/tools/clippy/clippy_lints/src/let_if_seq.rs
index a65cb3f4dfb..0e488cee6b7 100644
--- a/src/tools/clippy/clippy_lints/src/let_if_seq.rs
+++ b/src/tools/clippy/clippy_lints/src/let_if_seq.rs
@@ -58,12 +58,10 @@ declare_lint_pass!(LetIfSeq => [USELESS_LET_IF_SEQ]);
 
 impl<'tcx> LateLintPass<'tcx> for LetIfSeq {
     fn check_block(&mut self, cx: &LateContext<'tcx>, block: &'tcx hir::Block<'_>) {
-        let mut it = block.stmts.iter().peekable();
-        while let Some(stmt) = it.next() {
-            if let Some(expr) = it.peek()
-                && let hir::StmtKind::Let(local) = stmt.kind
+        for [stmt, next] in block.stmts.array_windows::<2>() {
+            if let hir::StmtKind::Let(local) = stmt.kind
                 && let hir::PatKind::Binding(mode, canonical_id, ident, None) = local.pat.kind
-                && let hir::StmtKind::Expr(if_) = expr.kind
+                && let hir::StmtKind::Expr(if_) = next.kind
                 && let hir::ExprKind::If(
                     hir::Expr {
                         kind: hir::ExprKind::DropTemps(cond),
diff --git a/src/tools/clippy/clippy_lints/src/let_underscore.rs b/src/tools/clippy/clippy_lints/src/let_underscore.rs
index 9fd4f509aa4..8fa63f3e8fd 100644
--- a/src/tools/clippy/clippy_lints/src/let_underscore.rs
+++ b/src/tools/clippy/clippy_lints/src/let_underscore.rs
@@ -139,9 +139,9 @@ const SYNC_GUARD_PATHS: [&[&str]; 3] = [
 impl<'tcx> LateLintPass<'tcx> for LetUnderscore {
     fn check_local(&mut self, cx: &LateContext<'tcx>, local: &LetStmt<'tcx>) {
         if matches!(local.source, LocalSource::Normal)
-            && !in_external_macro(cx.tcx.sess, local.span)
             && let PatKind::Wild = local.pat.kind
             && let Some(init) = local.init
+            && !in_external_macro(cx.tcx.sess, local.span)
         {
             let init_ty = cx.typeck_results().expr_ty(init);
             let contains_sync_guard = init_ty.walk().any(|inner| match inner.unpack() {
diff --git a/src/tools/clippy/clippy_lints/src/let_with_type_underscore.rs b/src/tools/clippy/clippy_lints/src/let_with_type_underscore.rs
index 593b29154b4..5a11702d7ce 100644
--- a/src/tools/clippy/clippy_lints/src/let_with_type_underscore.rs
+++ b/src/tools/clippy/clippy_lints/src/let_with_type_underscore.rs
@@ -1,5 +1,5 @@
 use clippy_utils::diagnostics::span_lint_and_help;
-use clippy_utils::source::snippet;
+use clippy_utils::is_from_proc_macro;
 use rustc_hir::{LetStmt, TyKind};
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_middle::lint::in_external_macro;
@@ -25,19 +25,14 @@ declare_clippy_lint! {
 }
 declare_lint_pass!(UnderscoreTyped => [LET_WITH_TYPE_UNDERSCORE]);
 
-impl LateLintPass<'_> for UnderscoreTyped {
-    fn check_local(&mut self, cx: &LateContext<'_>, local: &LetStmt<'_>) {
-        if !in_external_macro(cx.tcx.sess, local.span)
-            && let Some(ty) = local.ty // Ensure that it has a type defined
+impl<'tcx> LateLintPass<'tcx> for UnderscoreTyped {
+    fn check_local(&mut self, cx: &LateContext<'tcx>, local: &'tcx LetStmt<'_>) {
+        if let Some(ty) = local.ty // Ensure that it has a type defined
             && let TyKind::Infer = &ty.kind // that type is '_'
             && local.span.eq_ctxt(ty.span)
+            && !in_external_macro(cx.tcx.sess, local.span)
+            && !is_from_proc_macro(cx, ty)
         {
-            // NOTE: Using `is_from_proc_macro` on `init` will require that it's initialized,
-            // this doesn't. Alternatively, `WithSearchPat` can be implemented for `Ty`
-            if snippet(cx, ty.span, "_").trim() != "_" {
-                return;
-            }
-
             span_lint_and_help(
                 cx,
                 LET_WITH_TYPE_UNDERSCORE,
diff --git a/src/tools/clippy/clippy_lints/src/lib.rs b/src/tools/clippy/clippy_lints/src/lib.rs
index 32fad0f02ce..c2dc26d6605 100644
--- a/src/tools/clippy/clippy_lints/src/lib.rs
+++ b/src/tools/clippy/clippy_lints/src/lib.rs
@@ -4,7 +4,9 @@
 #![feature(f128)]
 #![feature(f16)]
 #![feature(if_let_guard)]
+#![feature(is_sorted)]
 #![feature(iter_intersperse)]
+#![feature(iter_partition_in_place)]
 #![feature(let_chains)]
 #![cfg_attr(bootstrap, feature(lint_reasons))]
 #![feature(never_type)]
@@ -90,8 +92,10 @@ mod bool_to_int_with_if;
 mod booleans;
 mod borrow_deref_ref;
 mod box_default;
+mod byte_char_slices;
 mod cargo;
 mod casts;
+mod cfg_not_test;
 mod checked_conversions;
 mod cognitive_complexity;
 mod collapsible_if;
@@ -212,6 +216,7 @@ mod manual_non_exhaustive;
 mod manual_range_patterns;
 mod manual_rem_euclid;
 mod manual_retain;
+mod manual_rotate;
 mod manual_slice_size_calculation;
 mod manual_string_new;
 mod manual_strip;
@@ -229,6 +234,7 @@ mod mismatching_type_param_order;
 mod missing_assert_message;
 mod missing_asserts_for_indexing;
 mod missing_const_for_fn;
+mod missing_const_for_thread_local;
 mod missing_doc;
 mod missing_enforced_import_rename;
 mod missing_fields_in_debug;
@@ -275,9 +281,9 @@ mod only_used_in_recursion;
 mod operators;
 mod option_env_unwrap;
 mod option_if_let_else;
-mod overflow_check_conditional;
 mod panic_in_result_fn;
 mod panic_unimplemented;
+mod panicking_overflow_checks;
 mod partial_pub_fields;
 mod partialeq_ne_impl;
 mod partialeq_to_none;
@@ -318,6 +324,7 @@ mod self_named_constructors;
 mod semicolon_block;
 mod semicolon_if_nothing_returned;
 mod serde_api;
+mod set_contains_or_insert;
 mod shadow;
 mod significant_drop_tightening;
 mod single_call_fn;
@@ -339,7 +346,6 @@ mod swap_ptr_to_ref;
 mod tabs_in_doc_comments;
 mod temporary_assignment;
 mod tests_outside_test_module;
-mod thread_local_initializer_can_be_made_const;
 mod to_digit_is_some;
 mod to_string_trait_impl;
 mod trailing_empty_array;
@@ -639,9 +645,6 @@ pub fn register_lints(store: &mut rustc_lint::LintStore, conf: &'static Conf) {
         });
         store.register_early_pass(|| Box::new(utils::internal_lints::produce_ice::ProduceIce));
         store.register_late_pass(|_| Box::new(utils::internal_lints::collapsible_calls::CollapsibleCalls));
-        store.register_late_pass(|_| {
-            Box::new(utils::internal_lints::compiler_lint_functions::CompilerLintFunctions::new())
-        });
         store.register_late_pass(|_| Box::new(utils::internal_lints::invalid_paths::InvalidPaths));
         store.register_late_pass(|_| {
             Box::<utils::internal_lints::interning_defined_symbol::InterningDefinedSymbol>::default()
@@ -788,7 +791,7 @@ pub fn register_lints(store: &mut rustc_lint::LintStore, conf: &'static Conf) {
     let format_args = format_args_storage.clone();
     store.register_late_pass(move |_| Box::new(format::UselessFormat::new(format_args.clone())));
     store.register_late_pass(|_| Box::new(swap::Swap));
-    store.register_late_pass(|_| Box::new(overflow_check_conditional::OverflowCheckConditional));
+    store.register_late_pass(|_| Box::new(panicking_overflow_checks::PanickingOverflowChecks));
     store.register_late_pass(|_| Box::<new_without_default::NewWithoutDefault>::default());
     store.register_late_pass(move |_| Box::new(disallowed_names::DisallowedNames::new(disallowed_names)));
     store.register_late_pass(move |_| {
@@ -1024,6 +1027,7 @@ pub fn register_lints(store: &mut rustc_lint::LintStore, conf: &'static Conf) {
     store.register_late_pass(|_| Box::new(default_instead_of_iter_empty::DefaultIterEmpty));
     store.register_late_pass(move |_| Box::new(manual_rem_euclid::ManualRemEuclid::new(msrv())));
     store.register_late_pass(move |_| Box::new(manual_retain::ManualRetain::new(msrv())));
+    store.register_late_pass(move |_| Box::new(manual_rotate::ManualRotate));
     store.register_late_pass(move |_| {
         Box::new(operators::Operators::new(
             verbose_bit_mask_threshold,
@@ -1153,9 +1157,8 @@ pub fn register_lints(store: &mut rustc_lint::LintStore, conf: &'static Conf) {
             behavior: pub_underscore_fields_behavior,
         })
     });
-    store.register_late_pass(move |_| {
-        Box::new(thread_local_initializer_can_be_made_const::ThreadLocalInitializerCanBeMadeConst::new(msrv()))
-    });
+    store
+        .register_late_pass(move |_| Box::new(missing_const_for_thread_local::MissingConstForThreadLocal::new(msrv())));
     store.register_late_pass(move |_| Box::new(incompatible_msrv::IncompatibleMsrv::new(msrv())));
     store.register_late_pass(|_| Box::new(to_string_trait_impl::ToStringTraitImpl));
     store.register_early_pass(|| Box::new(multiple_bound_locations::MultipleBoundLocations));
@@ -1171,6 +1174,9 @@ pub fn register_lints(store: &mut rustc_lint::LintStore, conf: &'static Conf) {
     });
     store.register_late_pass(move |_| Box::new(string_patterns::StringPatterns::new(msrv())));
     store.register_early_pass(|| Box::new(field_scoped_visibility_modifiers::FieldScopedVisibilityModifiers));
+    store.register_late_pass(|_| Box::new(set_contains_or_insert::HashsetInsertAfterContains));
+    store.register_early_pass(|| Box::new(byte_char_slices::ByteCharSlice));
+    store.register_early_pass(|| Box::new(cfg_not_test::CfgNotTest));
     // add lints here, do not remove this comment, it's used in `new_lint`
 }
 
diff --git a/src/tools/clippy/clippy_lints/src/literal_representation.rs b/src/tools/clippy/clippy_lints/src/literal_representation.rs
index d2a140a36a8..7481543941a 100644
--- a/src/tools/clippy/clippy_lints/src/literal_representation.rs
+++ b/src/tools/clippy/clippy_lints/src/literal_representation.rs
@@ -233,11 +233,9 @@ impl_lint_pass!(LiteralDigitGrouping => [
 
 impl EarlyLintPass for LiteralDigitGrouping {
     fn check_expr(&mut self, cx: &EarlyContext<'_>, expr: &Expr) {
-        if in_external_macro(cx.sess(), expr.span) {
-            return;
-        }
-
-        if let ExprKind::Lit(lit) = expr.kind {
+        if let ExprKind::Lit(lit) = expr.kind
+            && !in_external_macro(cx.sess(), expr.span)
+        {
             self.check_lit(cx, lit, expr.span);
         }
     }
@@ -448,11 +446,9 @@ impl_lint_pass!(DecimalLiteralRepresentation => [DECIMAL_LITERAL_REPRESENTATION]
 
 impl EarlyLintPass for DecimalLiteralRepresentation {
     fn check_expr(&mut self, cx: &EarlyContext<'_>, expr: &Expr) {
-        if in_external_macro(cx.sess(), expr.span) {
-            return;
-        }
-
-        if let ExprKind::Lit(lit) = expr.kind {
+        if let ExprKind::Lit(lit) = expr.kind
+            && !in_external_macro(cx.sess(), expr.span)
+        {
             self.check_lit(cx, lit, expr.span);
         }
     }
diff --git a/src/tools/clippy/clippy_lints/src/manual_bits.rs b/src/tools/clippy/clippy_lints/src/manual_bits.rs
index 24fc2b4faea..d9f6be6dc2b 100644
--- a/src/tools/clippy/clippy_lints/src/manual_bits.rs
+++ b/src/tools/clippy/clippy_lints/src/manual_bits.rs
@@ -50,13 +50,10 @@ impl_lint_pass!(ManualBits => [MANUAL_BITS]);
 
 impl<'tcx> LateLintPass<'tcx> for ManualBits {
     fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
-        if !self.msrv.meets(msrvs::MANUAL_BITS) {
-            return;
-        }
-
         if let ExprKind::Binary(bin_op, left_expr, right_expr) = expr.kind
             && let BinOpKind::Mul = &bin_op.node
             && !in_external_macro(cx.sess(), expr.span)
+            && self.msrv.meets(msrvs::MANUAL_BITS)
             && let ctxt = expr.span.ctxt()
             && left_expr.span.ctxt() == ctxt
             && right_expr.span.ctxt() == ctxt
diff --git a/src/tools/clippy/clippy_lints/src/manual_float_methods.rs b/src/tools/clippy/clippy_lints/src/manual_float_methods.rs
index 89eea0b4456..03416ba96de 100644
--- a/src/tools/clippy/clippy_lints/src/manual_float_methods.rs
+++ b/src/tools/clippy/clippy_lints/src/manual_float_methods.rs
@@ -82,29 +82,26 @@ impl Variant {
 
 impl<'tcx> LateLintPass<'tcx> for ManualFloatMethods {
     fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) {
-        if !in_external_macro(cx.sess(), expr.span)
-            && (
-                matches!(cx.tcx.constness(cx.tcx.hir().enclosing_body_owner(expr.hir_id)), Constness::NotConst)
-                    || cx.tcx.features().declared(sym!(const_float_classify))
-            ) && let ExprKind::Binary(kind, lhs, rhs) = expr.kind
+        if let ExprKind::Binary(kind, lhs, rhs) = expr.kind
             && let ExprKind::Binary(lhs_kind, lhs_lhs, lhs_rhs) = lhs.kind
             && let ExprKind::Binary(rhs_kind, rhs_lhs, rhs_rhs) = rhs.kind
             // Checking all possible scenarios using a function would be a hopeless task, as we have
             // 16 possible alignments of constants/operands. For now, let's use `partition`.
-            && let (operands, constants) = [lhs_lhs, lhs_rhs, rhs_lhs, rhs_rhs]
-                .into_iter()
-                .partition::<Vec<&Expr<'_>>, _>(|i| path_to_local(i).is_some())
-            && let [first, second] = &*operands
-            && let Some([const_1, const_2]) = constants
-                .into_iter()
-                .map(|i| constant(cx, cx.typeck_results(), i))
-                .collect::<Option<Vec<_>>>()
-                .as_deref()
+            && let mut exprs = [lhs_lhs, lhs_rhs, rhs_lhs, rhs_rhs]
+            && exprs.iter_mut().partition_in_place(|i| path_to_local(i).is_some()) == 2
+            && !in_external_macro(cx.sess(), expr.span)
+            && (
+                matches!(cx.tcx.constness(cx.tcx.hir().enclosing_body_owner(expr.hir_id)), Constness::NotConst)
+                    || cx.tcx.features().declared(sym!(const_float_classify))
+            )
+            && let [first, second, const_1, const_2] = exprs
+            && let Some(const_1) = constant(cx, cx.typeck_results(), const_1)
+            && let Some(const_2) = constant(cx, cx.typeck_results(), const_2)
             && path_to_local(first).is_some_and(|f| path_to_local(second).is_some_and(|s| f == s))
             // The actual infinity check, we also allow `NEG_INFINITY` before` INFINITY` just in
             // case somebody does that for some reason
-            && (is_infinity(const_1) && is_neg_infinity(const_2)
-                || is_neg_infinity(const_1) && is_infinity(const_2))
+            && (is_infinity(&const_1) && is_neg_infinity(&const_2)
+                || is_neg_infinity(&const_1) && is_infinity(&const_2))
             && let Some(local_snippet) = snippet_opt(cx, first.span)
         {
             let variant = match (kind.node, lhs_kind.node, rhs_kind.node) {
diff --git a/src/tools/clippy/clippy_lints/src/manual_let_else.rs b/src/tools/clippy/clippy_lints/src/manual_let_else.rs
index 03e4d668dd8..ebebdf679a8 100644
--- a/src/tools/clippy/clippy_lints/src/manual_let_else.rs
+++ b/src/tools/clippy/clippy_lints/src/manual_let_else.rs
@@ -49,16 +49,14 @@ declare_clippy_lint! {
 
 impl<'tcx> QuestionMark {
     pub(crate) fn check_manual_let_else(&mut self, cx: &LateContext<'tcx>, stmt: &'tcx Stmt<'tcx>) {
-        if !self.msrv.meets(msrvs::LET_ELSE) || in_external_macro(cx.sess(), stmt.span) {
-            return;
-        }
-
         if let StmtKind::Let(local) = stmt.kind
             && let Some(init) = local.init
             && local.els.is_none()
             && local.ty.is_none()
             && init.span.eq_ctxt(stmt.span)
             && let Some(if_let_or_match) = IfLetOrMatch::parse(cx, init)
+            && self.msrv.meets(msrvs::LET_ELSE)
+            && !in_external_macro(cx.sess(), stmt.span)
         {
             match if_let_or_match {
                 IfLetOrMatch::IfLet(if_let_expr, let_pat, if_then, if_else, ..) => {
diff --git a/src/tools/clippy/clippy_lints/src/manual_main_separator_str.rs b/src/tools/clippy/clippy_lints/src/manual_main_separator_str.rs
index 5732bdda7f2..8e8cdc3fb07 100644
--- a/src/tools/clippy/clippy_lints/src/manual_main_separator_str.rs
+++ b/src/tools/clippy/clippy_lints/src/manual_main_separator_str.rs
@@ -47,13 +47,13 @@ impl_lint_pass!(ManualMainSeparatorStr => [MANUAL_MAIN_SEPARATOR_STR]);
 
 impl LateLintPass<'_> for ManualMainSeparatorStr {
     fn check_expr(&mut self, cx: &LateContext<'_>, expr: &Expr<'_>) {
-        if self.msrv.meets(msrvs::PATH_MAIN_SEPARATOR_STR)
-            && let (target, _) = peel_hir_expr_refs(expr)
-            && is_trait_method(cx, target, sym::ToString)
-            && let ExprKind::MethodCall(path, receiver, &[], _) = target.kind
+        let (target, _) = peel_hir_expr_refs(expr);
+        if let ExprKind::MethodCall(path, receiver, &[], _) = target.kind
             && path.ident.name == sym::to_string
             && let ExprKind::Path(QPath::Resolved(None, path)) = receiver.kind
             && let Res::Def(DefKind::Const, receiver_def_id) = path.res
+            && is_trait_method(cx, target, sym::ToString)
+            && self.msrv.meets(msrvs::PATH_MAIN_SEPARATOR_STR)
             && match_def_path(cx, receiver_def_id, &paths::PATH_MAIN_SEPARATOR)
             && let ty::Ref(_, ty, Mutability::Not) = cx.typeck_results().expr_ty_adjusted(expr).kind()
             && ty.is_str()
diff --git a/src/tools/clippy/clippy_lints/src/manual_non_exhaustive.rs b/src/tools/clippy/clippy_lints/src/manual_non_exhaustive.rs
index d2ac0ad8363..73a505fd73f 100644
--- a/src/tools/clippy/clippy_lints/src/manual_non_exhaustive.rs
+++ b/src/tools/clippy/clippy_lints/src/manual_non_exhaustive.rs
@@ -97,19 +97,15 @@ impl_lint_pass!(ManualNonExhaustiveEnum => [MANUAL_NON_EXHAUSTIVE]);
 
 impl EarlyLintPass for ManualNonExhaustiveStruct {
     fn check_item(&mut self, cx: &EarlyContext<'_>, item: &ast::Item) {
-        if !self.msrv.meets(msrvs::NON_EXHAUSTIVE) {
-            return;
-        }
-
-        if let ast::ItemKind::Struct(variant_data, _) = &item.kind {
-            let (fields, delimiter) = match variant_data {
+        if let ast::ItemKind::Struct(variant_data, _) = &item.kind
+            && let (fields, delimiter) = match variant_data {
                 ast::VariantData::Struct { fields, .. } => (&**fields, '{'),
                 ast::VariantData::Tuple(fields, _) => (&**fields, '('),
                 ast::VariantData::Unit(_) => return,
-            };
-            if fields.len() <= 1 {
-                return;
             }
+            && fields.len() > 1
+            && self.msrv.meets(msrvs::NON_EXHAUSTIVE)
+        {
             let mut iter = fields.iter().filter_map(|f| match f.vis.kind {
                 VisibilityKind::Public => None,
                 VisibilityKind::Inherited => Some(Ok(f)),
diff --git a/src/tools/clippy/clippy_lints/src/manual_range_patterns.rs b/src/tools/clippy/clippy_lints/src/manual_range_patterns.rs
index ec60de92c4b..07d4abbf5cd 100644
--- a/src/tools/clippy/clippy_lints/src/manual_range_patterns.rs
+++ b/src/tools/clippy/clippy_lints/src/manual_range_patterns.rs
@@ -76,14 +76,11 @@ impl Num {
 
 impl LateLintPass<'_> for ManualRangePatterns {
     fn check_pat(&mut self, cx: &LateContext<'_>, pat: &'_ rustc_hir::Pat<'_>) {
-        if in_external_macro(cx.sess(), pat.span) {
-            return;
-        }
-
         // a pattern like 1 | 2 seems fine, lint if there are at least 3 alternatives
         // or at least one range
         if let PatKind::Or(pats) = pat.kind
             && (pats.len() >= 3 || pats.iter().any(|p| matches!(p.kind, PatKind::Range(..))))
+            && !in_external_macro(cx.sess(), pat.span)
         {
             let mut min = Num::dummy(i128::MAX);
             let mut max = Num::dummy(i128::MIN);
diff --git a/src/tools/clippy/clippy_lints/src/manual_rem_euclid.rs b/src/tools/clippy/clippy_lints/src/manual_rem_euclid.rs
index ab9bca170cf..b518dc26937 100644
--- a/src/tools/clippy/clippy_lints/src/manual_rem_euclid.rs
+++ b/src/tools/clippy/clippy_lints/src/manual_rem_euclid.rs
@@ -48,35 +48,30 @@ impl_lint_pass!(ManualRemEuclid => [MANUAL_REM_EUCLID]);
 
 impl<'tcx> LateLintPass<'tcx> for ManualRemEuclid {
     fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
-        if !self.msrv.meets(msrvs::REM_EUCLID) {
-            return;
-        }
-
-        if in_constant(cx, expr.hir_id) && !self.msrv.meets(msrvs::REM_EUCLID_CONST) {
-            return;
-        }
-
-        if in_external_macro(cx.sess(), expr.span) {
-            return;
-        }
-
         // (x % c + c) % c
-        if let ExprKind::Binary(op1, expr1, right) = expr.kind
-            && op1.node == BinOpKind::Rem
+        if let ExprKind::Binary(rem_op, rem_lhs, rem_rhs) = expr.kind
+            && rem_op.node == BinOpKind::Rem
+            && let ExprKind::Binary(add_op, add_lhs, add_rhs) = rem_lhs.kind
+            && add_op.node == BinOpKind::Add
             && let ctxt = expr.span.ctxt()
-            && expr1.span.ctxt() == ctxt
-            && let Some(const1) = check_for_unsigned_int_constant(cx, right)
-            && let ExprKind::Binary(op2, left, right) = expr1.kind
-            && op2.node == BinOpKind::Add
-            && let Some((const2, expr2)) = check_for_either_unsigned_int_constant(cx, left, right)
-            && expr2.span.ctxt() == ctxt
-            && let ExprKind::Binary(op3, expr3, right) = expr2.kind
-            && op3.node == BinOpKind::Rem
-            && let Some(const3) = check_for_unsigned_int_constant(cx, right)
+            && rem_lhs.span.ctxt() == ctxt
+            && rem_rhs.span.ctxt() == ctxt
+            && add_lhs.span.ctxt() == ctxt
+            && add_rhs.span.ctxt() == ctxt
+            && !in_external_macro(cx.sess(), expr.span)
+            && self.msrv.meets(msrvs::REM_EUCLID)
+            && (self.msrv.meets(msrvs::REM_EUCLID_CONST) || !in_constant(cx, expr.hir_id))
+            && let Some(const1) = check_for_unsigned_int_constant(cx, rem_rhs)
+            && let Some((const2, add_other)) = check_for_either_unsigned_int_constant(cx, add_lhs, add_rhs)
+            && let ExprKind::Binary(rem2_op, rem2_lhs, rem2_rhs) = add_other.kind
+            && rem2_op.node == BinOpKind::Rem
+            && const1 == const2
+            && let Some(hir_id) = path_to_local(rem2_lhs)
+            && let Some(const3) = check_for_unsigned_int_constant(cx, rem2_rhs)
             // Also ensures the const is nonzero since zero can't be a divisor
-            && const1 == const2 && const2 == const3
-            && let Some(hir_id) = path_to_local(expr3)
-            && let Node::Pat(_) = cx.tcx.hir_node(hir_id)
+            && const2 == const3
+            && rem2_lhs.span.ctxt() == ctxt
+            && rem2_rhs.span.ctxt() == ctxt
         {
             // Apply only to params or locals with annotated types
             match cx.tcx.parent_hir_node(hir_id) {
@@ -91,7 +86,7 @@ impl<'tcx> LateLintPass<'tcx> for ManualRemEuclid {
             };
 
             let mut app = Applicability::MachineApplicable;
-            let rem_of = snippet_with_context(cx, expr3.span, ctxt, "_", &mut app).0;
+            let rem_of = snippet_with_context(cx, rem2_lhs.span, ctxt, "_", &mut app).0;
             span_lint_and_sugg(
                 cx,
                 MANUAL_REM_EUCLID,
diff --git a/src/tools/clippy/clippy_lints/src/manual_retain.rs b/src/tools/clippy/clippy_lints/src/manual_retain.rs
index 3ddb06a1e08..8f7b8abd0c3 100644
--- a/src/tools/clippy/clippy_lints/src/manual_retain.rs
+++ b/src/tools/clippy/clippy_lints/src/manual_retain.rs
@@ -70,9 +70,8 @@ impl_lint_pass!(ManualRetain => [MANUAL_RETAIN]);
 impl<'tcx> LateLintPass<'tcx> for ManualRetain {
     fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>) {
         if let Assign(left_expr, collect_expr, _) = &expr.kind
-            && let hir::ExprKind::MethodCall(seg, ..) = &collect_expr.kind
+            && let hir::ExprKind::MethodCall(seg, target_expr, [], _) = &collect_expr.kind
             && seg.args.is_none()
-            && let hir::ExprKind::MethodCall(_, target_expr, [], _) = &collect_expr.kind
             && let Some(collect_def_id) = cx.typeck_results().type_dependent_def_id(collect_expr.hir_id)
             && cx.tcx.is_diagnostic_item(sym::iterator_collect_fn, collect_def_id)
         {
diff --git a/src/tools/clippy/clippy_lints/src/manual_rotate.rs b/src/tools/clippy/clippy_lints/src/manual_rotate.rs
new file mode 100644
index 00000000000..a517a4d5075
--- /dev/null
+++ b/src/tools/clippy/clippy_lints/src/manual_rotate.rs
@@ -0,0 +1,117 @@
+use std::fmt::Display;
+
+use clippy_utils::consts::{constant, Constant};
+use clippy_utils::diagnostics::span_lint_and_sugg;
+use clippy_utils::sugg;
+use rustc_errors::Applicability;
+use rustc_hir::{BinOpKind, Expr, ExprKind};
+use rustc_lint::{LateContext, LateLintPass};
+use rustc_middle::ty;
+use rustc_session::declare_lint_pass;
+
+declare_clippy_lint! {
+    /// ### What it does
+    ///
+    /// It detects manual bit rotations that could be rewritten using standard
+    /// functions `rotate_left` or `rotate_right`.
+    ///
+    /// ### Why is this bad?
+    ///
+    /// Calling the function better conveys the intent.
+    ///
+    /// ### Known issues
+    ///
+    /// Currently, the lint only catches shifts by constant amount.
+    ///
+    /// ### Example
+    /// ```no_run
+    /// let x = 12345678_u32;
+    /// let _ = (x >> 8) | (x << 24);
+    /// ```
+    /// Use instead:
+    /// ```no_run
+    /// let x = 12345678_u32;
+    /// let _ = x.rotate_right(8);
+    /// ```
+    #[clippy::version = "1.81.0"]
+    pub MANUAL_ROTATE,
+    style,
+    "using bit shifts to rotate integers"
+}
+
+declare_lint_pass!(ManualRotate => [MANUAL_ROTATE]);
+
+#[derive(Clone, Copy, Debug, PartialEq, Eq)]
+enum ShiftDirection {
+    Left,
+    Right,
+}
+
+impl Display for ShiftDirection {
+    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+        f.write_str(match self {
+            Self::Left => "rotate_left",
+            Self::Right => "rotate_right",
+        })
+    }
+}
+
+fn parse_shift<'tcx>(
+    cx: &LateContext<'tcx>,
+    expr: &'tcx Expr<'tcx>,
+) -> Option<(ShiftDirection, u128, &'tcx Expr<'tcx>)> {
+    if let ExprKind::Binary(op, l, r) = expr.kind {
+        let dir = match op.node {
+            BinOpKind::Shl => ShiftDirection::Left,
+            BinOpKind::Shr => ShiftDirection::Right,
+            _ => return None,
+        };
+        let const_expr = constant(cx, cx.typeck_results(), r)?;
+        if let Constant::Int(shift) = const_expr {
+            return Some((dir, shift, l));
+        }
+    }
+    None
+}
+
+impl LateLintPass<'_> for ManualRotate {
+    fn check_expr<'tcx>(&mut self, cx: &LateContext<'tcx>, expr: &Expr<'tcx>) {
+        if let ExprKind::Binary(op, l, r) = expr.kind
+            && let BinOpKind::Add | BinOpKind::BitOr = op.node
+            && let Some((l_shift_dir, l_amount, l_expr)) = parse_shift(cx, l)
+            && let Some((r_shift_dir, r_amount, r_expr)) = parse_shift(cx, r)
+        {
+            if l_shift_dir == r_shift_dir {
+                return;
+            }
+            if !clippy_utils::eq_expr_value(cx, l_expr, r_expr) {
+                return;
+            }
+            let Some(bit_width) = (match cx.typeck_results().expr_ty(expr).kind() {
+                ty::Int(itype) => itype.bit_width(),
+                ty::Uint(itype) => itype.bit_width(),
+                _ => return,
+            }) else {
+                return;
+            };
+            if l_amount + r_amount == u128::from(bit_width) {
+                let (shift_function, amount) = if l_amount < r_amount {
+                    (l_shift_dir, l_amount)
+                } else {
+                    (r_shift_dir, r_amount)
+                };
+                let mut applicability = Applicability::MachineApplicable;
+                let expr_sugg = sugg::Sugg::hir_with_applicability(cx, l_expr, "_", &mut applicability).maybe_par();
+                span_lint_and_sugg(
+                    cx,
+                    MANUAL_ROTATE,
+                    expr.span,
+                    "there is no need to manually implement bit rotation",
+                    "this expression can be rewritten as",
+                    format!("{expr_sugg}.{shift_function}({amount})"),
+                    Applicability::MachineApplicable,
+                );
+            }
+        }
+    }
+}
diff --git a/src/tools/clippy/clippy_lints/src/manual_slice_size_calculation.rs b/src/tools/clippy/clippy_lints/src/manual_slice_size_calculation.rs
index 1de686dbcb5..429ee2637c2 100644
--- a/src/tools/clippy/clippy_lints/src/manual_slice_size_calculation.rs
+++ b/src/tools/clippy/clippy_lints/src/manual_slice_size_calculation.rs
@@ -40,11 +40,11 @@ declare_lint_pass!(ManualSliceSizeCalculation => [MANUAL_SLICE_SIZE_CALCULATION]
 
 impl<'tcx> LateLintPass<'tcx> for ManualSliceSizeCalculation {
     fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) {
-        // Does not apply inside const because size_of_val is not cost in stable.
-        if !in_constant(cx, expr.hir_id)
-            && let ExprKind::Binary(ref op, left, right) = expr.kind
+        if let ExprKind::Binary(ref op, left, right) = expr.kind
             && BinOpKind::Mul == op.node
             && !expr.span.from_expansion()
+            // Does not apply inside const because size_of_val is not cost in stable.
+            && !in_constant(cx, expr.hir_id)
             && let Some(receiver) = simplify(cx, left, right)
         {
             let ctxt = expr.span.ctxt();
diff --git a/src/tools/clippy/clippy_lints/src/manual_strip.rs b/src/tools/clippy/clippy_lints/src/manual_strip.rs
index 45af9f07718..6a523ad1564 100644
--- a/src/tools/clippy/clippy_lints/src/manual_strip.rs
+++ b/src/tools/clippy/clippy_lints/src/manual_strip.rs
@@ -66,14 +66,11 @@ enum StripKind {
 
 impl<'tcx> LateLintPass<'tcx> for ManualStrip {
     fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
-        if !self.msrv.meets(msrvs::STR_STRIP_PREFIX) {
-            return;
-        }
-
         if let Some(higher::If { cond, then, .. }) = higher::If::hir(expr)
             && let ExprKind::MethodCall(_, target_arg, [pattern], _) = cond.kind
-            && let Some(method_def_id) = cx.typeck_results().type_dependent_def_id(cond.hir_id)
             && let ExprKind::Path(target_path) = &target_arg.kind
+            && self.msrv.meets(msrvs::STR_STRIP_PREFIX)
+            && let Some(method_def_id) = cx.typeck_results().type_dependent_def_id(cond.hir_id)
         {
             let strip_kind = if match_def_path(cx, method_def_id, &paths::STR_STARTS_WITH) {
                 StripKind::Prefix
diff --git a/src/tools/clippy/clippy_lints/src/manual_unwrap_or_default.rs b/src/tools/clippy/clippy_lints/src/manual_unwrap_or_default.rs
index 58b2ebebbf0..f1acc4b2174 100644
--- a/src/tools/clippy/clippy_lints/src/manual_unwrap_or_default.rs
+++ b/src/tools/clippy/clippy_lints/src/manual_unwrap_or_default.rs
@@ -172,11 +172,10 @@ fn handle<'tcx>(cx: &LateContext<'tcx>, if_let_or_match: IfLetOrMatch<'tcx>, exp
 
 impl<'tcx> LateLintPass<'tcx> for ManualUnwrapOrDefault {
     fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) {
-        if expr.span.from_expansion() || in_constant(cx, expr.hir_id) {
-            return;
-        }
-        // Call handle only if the expression is `if let` or `match`
-        if let Some(if_let_or_match) = IfLetOrMatch::parse(cx, expr) {
+        if let Some(if_let_or_match) = IfLetOrMatch::parse(cx, expr)
+            && !expr.span.from_expansion()
+            && !in_constant(cx, expr.hir_id)
+        {
             handle(cx, if_let_or_match, expr);
         }
     }
diff --git a/src/tools/clippy/clippy_lints/src/map_unit_fn.rs b/src/tools/clippy/clippy_lints/src/map_unit_fn.rs
index 9db04b615be..2db71b1f7a3 100644
--- a/src/tools/clippy/clippy_lints/src/map_unit_fn.rs
+++ b/src/tools/clippy/clippy_lints/src/map_unit_fn.rs
@@ -253,14 +253,11 @@ fn lint_map_unit_fn(
 
 impl<'tcx> LateLintPass<'tcx> for MapUnit {
     fn check_stmt(&mut self, cx: &LateContext<'_>, stmt: &hir::Stmt<'_>) {
-        if stmt.span.from_expansion() {
-            return;
-        }
-
-        if let hir::StmtKind::Semi(expr) = stmt.kind {
-            if let Some(arglists) = method_chain_args(expr, &["map"]) {
-                lint_map_unit_fn(cx, stmt, expr, arglists[0]);
-            }
+        if let hir::StmtKind::Semi(expr) = stmt.kind
+            && !stmt.span.from_expansion()
+            && let Some(arglists) = method_chain_args(expr, &["map"])
+        {
+            lint_map_unit_fn(cx, stmt, expr, arglists[0]);
         }
     }
 }
diff --git a/src/tools/clippy/clippy_lints/src/matches/mod.rs b/src/tools/clippy/clippy_lints/src/matches/mod.rs
index bf7156cc53e..22a299ae3d8 100644
--- a/src/tools/clippy/clippy_lints/src/matches/mod.rs
+++ b/src/tools/clippy/clippy_lints/src/matches/mod.rs
@@ -1019,6 +1019,7 @@ impl_lint_pass!(Matches => [
 ]);
 
 impl<'tcx> LateLintPass<'tcx> for Matches {
+    #[expect(clippy::too_many_lines)]
     fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
         if is_direct_expn_of(expr.span, "matches").is_none() && in_external_macro(cx.sess(), expr.span) {
             return;
@@ -1037,7 +1038,7 @@ impl<'tcx> LateLintPass<'tcx> for Matches {
                 return;
             }
             if matches!(source, MatchSource::Normal | MatchSource::ForLoopDesugar) {
-                significant_drop_in_scrutinee::check(cx, expr, ex, arms, source);
+                significant_drop_in_scrutinee::check_match(cx, expr, ex, arms, source);
             }
 
             collapsible_match::check_match(cx, arms, &self.msrv);
@@ -1084,6 +1085,7 @@ impl<'tcx> LateLintPass<'tcx> for Matches {
             }
         } 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, &self.msrv);
+            significant_drop_in_scrutinee::check_if_let(cx, expr, if_let.let_expr, if_let.if_then, if_let.if_else);
             if !from_expansion {
                 if let Some(else_expr) = if_let.if_else {
                     if self.msrv.meets(msrvs::MATCHES_MACRO) {
@@ -1126,8 +1128,13 @@ impl<'tcx> LateLintPass<'tcx> for Matches {
                 );
                 needless_match::check_if_let(cx, expr, &if_let);
             }
-        } else if !from_expansion {
-            redundant_pattern_match::check(cx, expr);
+        } else {
+            if let Some(while_let) = higher::WhileLet::hir(expr) {
+                significant_drop_in_scrutinee::check_while_let(cx, expr, while_let.let_expr, while_let.if_then);
+            }
+            if !from_expansion {
+                redundant_pattern_match::check(cx, expr);
+            }
         }
     }
 
diff --git a/src/tools/clippy/clippy_lints/src/matches/significant_drop_in_scrutinee.rs b/src/tools/clippy/clippy_lints/src/matches/significant_drop_in_scrutinee.rs
index 2f72e59834f..9047c9627d9 100644
--- a/src/tools/clippy/clippy_lints/src/matches/significant_drop_in_scrutinee.rs
+++ b/src/tools/clippy/clippy_lints/src/matches/significant_drop_in_scrutinee.rs
@@ -16,7 +16,7 @@ use rustc_span::Span;
 
 use super::SIGNIFICANT_DROP_IN_SCRUTINEE;
 
-pub(super) fn check<'tcx>(
+pub(super) fn check_match<'tcx>(
     cx: &LateContext<'tcx>,
     expr: &'tcx Expr<'tcx>,
     scrutinee: &'tcx Expr<'_>,
@@ -27,10 +27,89 @@ pub(super) fn check<'tcx>(
         return;
     }
 
-    let (suggestions, message) = has_significant_drop_in_scrutinee(cx, scrutinee, source);
+    let scrutinee = match (source, &scrutinee.kind) {
+        (MatchSource::ForLoopDesugar, ExprKind::Call(_, [e])) => e,
+        _ => scrutinee,
+    };
+
+    let message = if source == MatchSource::Normal {
+        "temporary with significant `Drop` in `match` scrutinee will live until the end of the `match` expression"
+    } else {
+        "temporary with significant `Drop` in `for` loop condition will live until the end of the `for` expression"
+    };
+
+    let arms = arms.iter().map(|arm| arm.body).collect::<Vec<_>>();
+
+    check(cx, expr, scrutinee, &arms, message, Suggestion::Emit);
+}
+
+pub(super) fn check_if_let<'tcx>(
+    cx: &LateContext<'tcx>,
+    expr: &'tcx Expr<'tcx>,
+    scrutinee: &'tcx Expr<'_>,
+    if_then: &'tcx Expr<'_>,
+    if_else: Option<&'tcx Expr<'_>>,
+) {
+    if is_lint_allowed(cx, SIGNIFICANT_DROP_IN_SCRUTINEE, expr.hir_id) {
+        return;
+    }
+
+    let message =
+        "temporary with significant `Drop` in `if let` scrutinee will live until the end of the `if let` expression";
+
+    if let Some(if_else) = if_else {
+        check(cx, expr, scrutinee, &[if_then, if_else], message, Suggestion::Emit);
+    } else {
+        check(cx, expr, scrutinee, &[if_then], message, Suggestion::Emit);
+    }
+}
+
+pub(super) fn check_while_let<'tcx>(
+    cx: &LateContext<'tcx>,
+    expr: &'tcx Expr<'tcx>,
+    scrutinee: &'tcx Expr<'_>,
+    body: &'tcx Expr<'_>,
+) {
+    if is_lint_allowed(cx, SIGNIFICANT_DROP_IN_SCRUTINEE, expr.hir_id) {
+        return;
+    }
+
+    check(
+        cx,
+        expr,
+        scrutinee,
+        &[body],
+        "temporary with significant `Drop` in `while let` scrutinee will live until the end of the `while let` expression",
+        // Don't emit wrong suggestions: We cannot fix the significant drop in the `while let` scrutinee by simply
+        // moving it out. We need to change the `while` to a `loop` instead.
+        Suggestion::DontEmit,
+    );
+}
+
+#[derive(Copy, Clone, Debug)]
+enum Suggestion {
+    Emit,
+    DontEmit,
+}
+
+fn check<'tcx>(
+    cx: &LateContext<'tcx>,
+    expr: &'tcx Expr<'tcx>,
+    scrutinee: &'tcx Expr<'_>,
+    arms: &[&'tcx Expr<'_>],
+    message: &'static str,
+    sugg: Suggestion,
+) {
+    let mut helper = SigDropHelper::new(cx);
+    let suggestions = helper.find_sig_drop(scrutinee);
+
     for found in suggestions {
         span_lint_and_then(cx, SIGNIFICANT_DROP_IN_SCRUTINEE, found.found_span, message, |diag| {
-            set_diagnostic(diag, cx, expr, found);
+            match sugg {
+                Suggestion::Emit => set_suggestion(diag, cx, expr, found),
+                Suggestion::DontEmit => (),
+            }
+
             let s = Span::new(expr.span.hi(), expr.span.hi(), expr.span.ctxt(), None);
             diag.span_label(s, "temporary lives until here");
             for span in has_significant_drop_in_arms(cx, arms) {
@@ -41,7 +120,7 @@ pub(super) fn check<'tcx>(
     }
 }
 
-fn set_diagnostic<'tcx>(diag: &mut Diag<'_, ()>, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>, found: FoundSigDrop) {
+fn set_suggestion<'tcx>(diag: &mut Diag<'_, ()>, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>, found: FoundSigDrop) {
     let original = snippet(cx, found.found_span, "..");
     let trailing_indent = " ".repeat(indent_of(cx, found.found_span).unwrap_or(0));
 
@@ -79,26 +158,6 @@ fn set_diagnostic<'tcx>(diag: &mut Diag<'_, ()>, cx: &LateContext<'tcx>, expr: &
     );
 }
 
-/// If the expression is an `ExprKind::Match`, check if the scrutinee has a significant drop that
-/// may have a surprising lifetime.
-fn has_significant_drop_in_scrutinee<'tcx>(
-    cx: &LateContext<'tcx>,
-    scrutinee: &'tcx Expr<'tcx>,
-    source: MatchSource,
-) -> (Vec<FoundSigDrop>, &'static str) {
-    let mut helper = SigDropHelper::new(cx);
-    let scrutinee = match (source, &scrutinee.kind) {
-        (MatchSource::ForLoopDesugar, ExprKind::Call(_, [e])) => e,
-        _ => scrutinee,
-    };
-    let message = if source == MatchSource::Normal {
-        "temporary with significant `Drop` in `match` scrutinee will live until the end of the `match` expression"
-    } else {
-        "temporary with significant `Drop` in `for` loop condition will live until the end of the `for` expression"
-    };
-    (helper.find_sig_drop(scrutinee), message)
-}
-
 struct SigDropChecker<'a, 'tcx> {
     seen_types: FxHashSet<Ty<'tcx>>,
     cx: &'a LateContext<'tcx>,
@@ -428,10 +487,10 @@ impl<'a, 'tcx> ArmSigDropHelper<'a, 'tcx> {
     }
 }
 
-fn has_significant_drop_in_arms<'tcx>(cx: &LateContext<'tcx>, arms: &'tcx [Arm<'_>]) -> FxHashSet<Span> {
+fn has_significant_drop_in_arms<'tcx>(cx: &LateContext<'tcx>, arms: &[&'tcx Expr<'_>]) -> FxHashSet<Span> {
     let mut helper = ArmSigDropHelper::new(cx);
     for arm in arms {
-        helper.visit_expr(arm.body);
+        helper.visit_expr(arm);
     }
     helper.found_sig_drop_spans
 }
diff --git a/src/tools/clippy/clippy_lints/src/methods/manual_inspect.rs b/src/tools/clippy/clippy_lints/src/methods/manual_inspect.rs
index e3ce64c246a..cac2e11f591 100644
--- a/src/tools/clippy/clippy_lints/src/methods/manual_inspect.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/manual_inspect.rs
@@ -167,14 +167,12 @@ pub(crate) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, arg: &Expr<'_>, name:
             } else {
                 edits.extend(addr_of_edits);
             }
-            edits.push((
-                name_span,
-                String::from(match name {
-                    "map" => "inspect",
-                    "map_err" => "inspect_err",
-                    _ => return,
-                }),
-            ));
+            let edit = match name {
+                "map" => "inspect",
+                "map_err" => "inspect_err",
+                _ => return,
+            };
+            edits.push((name_span, edit.to_string()));
             edits.push((
                 final_expr
                     .span
@@ -187,9 +185,15 @@ pub(crate) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, arg: &Expr<'_>, name:
             } else {
                 Applicability::MachineApplicable
             };
-            span_lint_and_then(cx, MANUAL_INSPECT, name_span, "", |diag| {
-                diag.multipart_suggestion("try", edits, app);
-            });
+            span_lint_and_then(
+                cx,
+                MANUAL_INSPECT,
+                name_span,
+                format!("using `{name}` over `{edit}`"),
+                |diag| {
+                    diag.multipart_suggestion("try", edits, app);
+                },
+            );
         }
     }
 }
diff --git a/src/tools/clippy/clippy_lints/src/methods/mod.rs b/src/tools/clippy/clippy_lints/src/methods/mod.rs
index 1408f454820..a846552cddf 100644
--- a/src/tools/clippy/clippy_lints/src/methods/mod.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/mod.rs
@@ -628,12 +628,11 @@ declare_clippy_lint! {
 
 declare_clippy_lint! {
     /// ### What it does
-    /// Checks for usage of `_.and_then(|x| Some(y))`, `_.and_then(|x| Ok(y))` or
-    /// `_.or_else(|x| Err(y))`.
+    /// Checks for usage of `_.and_then(|x| Some(y))`, `_.and_then(|x| Ok(y))`
+    /// or `_.or_else(|x| Err(y))`.
     ///
     /// ### Why is this bad?
-    /// Readability, this can be written more concisely as
-    /// `_.map(|x| y)` or `_.map_err(|x| y)`.
+    /// This can be written more concisely as `_.map(|x| y)` or `_.map_err(|x| y)`.
     ///
     /// ### Example
     /// ```no_run
@@ -4121,7 +4120,7 @@ declare_clippy_lint! {
     /// ```no_run
     /// let x = Some(0).inspect(|x| println!("{x}"));
     /// ```
-    #[clippy::version = "1.78.0"]
+    #[clippy::version = "1.81.0"]
     pub MANUAL_INSPECT,
     complexity,
     "use of `map` returning the original item"
diff --git a/src/tools/clippy/clippy_lints/src/methods/unnecessary_to_owned.rs b/src/tools/clippy/clippy_lints/src/methods/unnecessary_to_owned.rs
index ae9aa83efd6..5d899415d77 100644
--- a/src/tools/clippy/clippy_lints/src/methods/unnecessary_to_owned.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/unnecessary_to_owned.rs
@@ -1,13 +1,15 @@
 use super::implicit_clone::is_clone_like;
 use super::unnecessary_iter_cloned::{self, is_into_iter};
 use clippy_config::msrvs::{self, Msrv};
-use clippy_utils::diagnostics::span_lint_and_sugg;
-use clippy_utils::source::snippet_opt;
+use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_and_then};
+use clippy_utils::source::{snippet, snippet_opt};
 use clippy_utils::ty::{
     get_iterator_item_ty, implements_trait, is_copy, is_type_diagnostic_item, is_type_lang_item, peel_mid_ty_refs,
 };
 use clippy_utils::visitors::find_all_ret_expressions;
-use clippy_utils::{fn_def_id, get_parent_expr, is_diag_item_method, is_diag_trait_item, return_ty};
+use clippy_utils::{
+    fn_def_id, get_parent_expr, is_diag_item_method, is_diag_trait_item, match_def_path, paths, return_ty,
+};
 use rustc_errors::Applicability;
 use rustc_hir::def::{DefKind, Res};
 use rustc_hir::def_id::DefId;
@@ -52,6 +54,9 @@ pub fn check<'tcx>(
             if check_into_iter_call_arg(cx, expr, method_name, receiver, msrv) {
                 return;
             }
+            if check_string_from_utf8(cx, expr, receiver) {
+                return;
+            }
             check_other_call_arg(cx, expr, method_name, receiver);
         }
     } else {
@@ -240,6 +245,65 @@ fn check_into_iter_call_arg(
     false
 }
 
+/// Checks for `&String::from_utf8(bytes.{to_vec,to_owned,...}()).unwrap()` coercing to `&str`,
+/// which can be written as just `std::str::from_utf8(bytes).unwrap()`.
+fn check_string_from_utf8<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>, receiver: &'tcx Expr<'tcx>) -> bool {
+    if let Some((call, arg)) = skip_addr_of_ancestors(cx, expr)
+        && !arg.span.from_expansion()
+        && let ExprKind::Call(callee, _) = call.kind
+        && fn_def_id(cx, call).is_some_and(|did| match_def_path(cx, did, &paths::STRING_FROM_UTF8))
+        && let Some(unwrap_call) = get_parent_expr(cx, call)
+        && let ExprKind::MethodCall(unwrap_method_name, ..) = unwrap_call.kind
+        && matches!(unwrap_method_name.ident.name, sym::unwrap | sym::expect)
+        && let Some(ref_string) = get_parent_expr(cx, unwrap_call)
+        && let ExprKind::AddrOf(BorrowKind::Ref, Mutability::Not, _) = ref_string.kind
+        && let adjusted_ty = cx.typeck_results().expr_ty_adjusted(ref_string)
+        // `&...` creates a `&String`, so only actually lint if this coerces to a `&str`
+        && matches!(adjusted_ty.kind(), ty::Ref(_, ty, _) if ty.is_str())
+    {
+        span_lint_and_then(
+            cx,
+            UNNECESSARY_TO_OWNED,
+            ref_string.span,
+            "allocating a new `String` only to create a temporary `&str` from it",
+            |diag| {
+                let arg_suggestion = format!(
+                    "{borrow}{recv_snippet}",
+                    recv_snippet = snippet(cx, receiver.span.source_callsite(), ".."),
+                    borrow = if cx.typeck_results().expr_ty(receiver).is_ref() {
+                        ""
+                    } else {
+                        // If not already a reference, prefix with a borrow so that it can coerce to one
+                        "&"
+                    }
+                );
+
+                diag.multipart_suggestion(
+                    "convert from `&[u8]` to `&str` directly",
+                    vec![
+                        // `&String::from_utf8(bytes.to_vec()).unwrap()`
+                        //   ^^^^^^^^^^^^^^^^^
+                        (callee.span, "core::str::from_utf8".into()),
+                        // `&String::from_utf8(bytes.to_vec()).unwrap()`
+                        //  ^
+                        (
+                            ref_string.span.shrink_to_lo().to(unwrap_call.span.shrink_to_lo()),
+                            String::new(),
+                        ),
+                        // `&String::from_utf8(bytes.to_vec()).unwrap()`
+                        //                     ^^^^^^^^^^^^^^
+                        (arg.span, arg_suggestion),
+                    ],
+                    Applicability::MachineApplicable,
+                );
+            },
+        );
+        true
+    } else {
+        false
+    }
+}
+
 /// Checks whether `expr` is an argument in an `into_iter` call and, if so, determines whether its
 /// call of a `to_owned`-like function is unnecessary.
 fn check_split_call_arg(cx: &LateContext<'_>, expr: &Expr<'_>, method_name: Symbol, receiver: &Expr<'_>) -> bool {
diff --git a/src/tools/clippy/clippy_lints/src/methods/unwrap_expect_used.rs b/src/tools/clippy/clippy_lints/src/methods/unwrap_expect_used.rs
index 516b8984ad7..5b0bd0f716a 100644
--- a/src/tools/clippy/clippy_lints/src/methods/unwrap_expect_used.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/unwrap_expect_used.rs
@@ -1,6 +1,6 @@
 use clippy_utils::diagnostics::span_lint_and_then;
 use clippy_utils::ty::{is_never_like, is_type_diagnostic_item};
-use clippy_utils::{is_in_cfg_test, is_in_test_function, is_lint_allowed};
+use clippy_utils::{is_in_test, is_lint_allowed};
 use rustc_hir::Expr;
 use rustc_lint::{LateContext, Lint};
 use rustc_middle::ty;
@@ -61,7 +61,7 @@ pub(super) fn check(
 
     let method_suffix = if is_err { "_err" } else { "" };
 
-    if allow_unwrap_in_tests && (is_in_test_function(cx.tcx, expr.hir_id) || is_in_cfg_test(cx.tcx, expr.hir_id)) {
+    if allow_unwrap_in_tests && is_in_test(cx.tcx, expr.hir_id) {
         return;
     }
 
diff --git a/src/tools/clippy/clippy_lints/src/minmax.rs b/src/tools/clippy/clippy_lints/src/minmax.rs
index fca626fa5c3..c3fbca1d560 100644
--- a/src/tools/clippy/clippy_lints/src/minmax.rs
+++ b/src/tools/clippy/clippy_lints/src/minmax.rs
@@ -5,7 +5,7 @@ use rustc_hir::{Expr, ExprKind};
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_session::declare_lint_pass;
 use rustc_span::sym;
-use std::cmp::Ordering;
+use std::cmp::Ordering::{Equal, Greater, Less};
 
 declare_clippy_lint! {
     /// ### What it does
@@ -36,26 +36,21 @@ declare_lint_pass!(MinMaxPass => [MIN_MAX]);
 
 impl<'tcx> LateLintPass<'tcx> for MinMaxPass {
     fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
-        if let Some((outer_max, outer_c, oe)) = min_max(cx, expr) {
-            if let Some((inner_max, inner_c, ie)) = min_max(cx, oe) {
-                if outer_max == inner_max {
-                    return;
-                }
-                match (
-                    outer_max,
-                    Constant::partial_cmp(cx.tcx, cx.typeck_results().expr_ty(ie), &outer_c, &inner_c),
-                ) {
-                    (_, None) | (MinMax::Max, Some(Ordering::Less)) | (MinMax::Min, Some(Ordering::Greater)) => (),
-                    _ => {
-                        span_lint(
-                            cx,
-                            MIN_MAX,
-                            expr.span,
-                            "this `min`/`max` combination leads to constant result",
-                        );
-                    },
-                }
-            }
+        if let Some((outer_max, outer_c, oe)) = min_max(cx, expr)
+            && let Some((inner_max, inner_c, ie)) = min_max(cx, oe)
+            && outer_max != inner_max
+            && let Some(ord) = Constant::partial_cmp(cx.tcx, cx.typeck_results().expr_ty(ie), &outer_c, &inner_c)
+            && matches!(
+                (outer_max, ord),
+                (MinMax::Max, Equal | Greater) | (MinMax::Min, Equal | Less)
+            )
+        {
+            span_lint(
+                cx,
+                MIN_MAX,
+                expr.span,
+                "this `min`/`max` combination leads to constant result",
+            );
         }
     }
 }
diff --git a/src/tools/clippy/clippy_lints/src/misc.rs b/src/tools/clippy/clippy_lints/src/misc.rs
index f3f9bf11a61..32c8731c537 100644
--- a/src/tools/clippy/clippy_lints/src/misc.rs
+++ b/src/tools/clippy/clippy_lints/src/misc.rs
@@ -2,8 +2,8 @@ use clippy_utils::diagnostics::{span_lint, span_lint_and_then, span_lint_hir_and
 use clippy_utils::source::{snippet, snippet_with_context};
 use clippy_utils::sugg::Sugg;
 use clippy_utils::{
-    any_parent_is_automatically_derived, fulfill_or_allowed, get_parent_expr, is_lint_allowed, iter_input_pats,
-    last_path_segment, SpanlessEq,
+    fulfill_or_allowed, get_parent_expr, in_automatically_derived, is_lint_allowed, iter_input_pats, last_path_segment,
+    SpanlessEq,
 };
 use rustc_errors::Applicability;
 use rustc_hir::def::Res;
@@ -206,7 +206,7 @@ impl<'tcx> LateLintPass<'tcx> for LintPass {
     fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
         if in_external_macro(cx.sess(), expr.span)
             || expr.span.desugaring_kind().is_some()
-            || any_parent_is_automatically_derived(cx.tcx, expr.hir_id)
+            || in_automatically_derived(cx.tcx, expr.hir_id)
         {
             return;
         }
diff --git a/src/tools/clippy/clippy_lints/src/missing_assert_message.rs b/src/tools/clippy/clippy_lints/src/missing_assert_message.rs
index dd98352da86..935ed48dacc 100644
--- a/src/tools/clippy/clippy_lints/src/missing_assert_message.rs
+++ b/src/tools/clippy/clippy_lints/src/missing_assert_message.rs
@@ -1,6 +1,6 @@
 use clippy_utils::diagnostics::span_lint_and_help;
+use clippy_utils::is_in_test;
 use clippy_utils::macros::{find_assert_args, find_assert_eq_args, root_macro_call_first_node, PanicExpn};
-use clippy_utils::{is_in_cfg_test, is_in_test_function};
 use rustc_hir::Expr;
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_session::declare_lint_pass;
@@ -62,7 +62,7 @@ impl<'tcx> LateLintPass<'tcx> for MissingAssertMessage {
         };
 
         // This lint would be very noisy in tests, so just ignore if we're in test context
-        if is_in_test_function(cx.tcx, expr.hir_id) || is_in_cfg_test(cx.tcx, expr.hir_id) {
+        if is_in_test(cx.tcx, expr.hir_id) {
             return;
         }
 
diff --git a/src/tools/clippy/clippy_lints/src/missing_const_for_fn.rs b/src/tools/clippy/clippy_lints/src/missing_const_for_fn.rs
index bb0d714a31f..ed5f46ddc8d 100644
--- a/src/tools/clippy/clippy_lints/src/missing_const_for_fn.rs
+++ b/src/tools/clippy/clippy_lints/src/missing_const_for_fn.rs
@@ -8,9 +8,11 @@ use rustc_hir::intravisit::FnKind;
 use rustc_hir::{self as hir, Body, Constness, FnDecl, GenericParamKind};
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_middle::lint::in_external_macro;
+use rustc_middle::ty;
 use rustc_session::impl_lint_pass;
 use rustc_span::def_id::LocalDefId;
 use rustc_span::Span;
+use rustc_target::spec::abi::Abi;
 
 declare_clippy_lint! {
     /// ### What it does
@@ -115,7 +117,10 @@ impl<'tcx> LateLintPass<'tcx> for MissingConstForFn {
                     .iter()
                     .any(|param| matches!(param.kind, GenericParamKind::Const { .. }));
 
-                if already_const(header) || has_const_generic_params {
+                if already_const(header)
+                    || has_const_generic_params
+                    || !could_be_const_with_abi(cx, &self.msrv, header.abi)
+                {
                     return;
                 }
             },
@@ -127,6 +132,10 @@ impl<'tcx> LateLintPass<'tcx> for MissingConstForFn {
             FnKind::Closure => return,
         }
 
+        if fn_inputs_has_impl_trait_ty(cx, def_id) {
+            return;
+        }
+
         let hir_id = cx.tcx.local_def_id_to_hir_id(def_id);
 
         // Const fns are not allowed as methods in a trait.
@@ -171,3 +180,25 @@ impl<'tcx> LateLintPass<'tcx> for MissingConstForFn {
 fn already_const(header: hir::FnHeader) -> bool {
     header.constness == Constness::Const
 }
+
+fn could_be_const_with_abi(cx: &LateContext<'_>, msrv: &Msrv, abi: Abi) -> bool {
+    match abi {
+        Abi::Rust => true,
+        // `const extern "C"` was stablized after 1.62.0
+        Abi::C { unwind: false } => msrv.meets(msrvs::CONST_EXTERN_FN),
+        // Rest ABIs are still unstable and need the `const_extern_fn` feature enabled.
+        _ => cx.tcx.features().const_extern_fn,
+    }
+}
+
+/// Return `true` when the given `def_id` is a function that has `impl Trait` ty as one of
+/// its parameter types.
+fn fn_inputs_has_impl_trait_ty(cx: &LateContext<'_>, def_id: LocalDefId) -> bool {
+    let inputs = cx.tcx.fn_sig(def_id).instantiate_identity().inputs().skip_binder();
+    inputs.iter().any(|input| {
+        matches!(
+            input.kind(),
+            ty::Alias(ty::AliasTyKind::Weak, alias_ty) if cx.tcx.type_of(alias_ty.def_id).skip_binder().is_impl_trait()
+        )
+    })
+}
diff --git a/src/tools/clippy/clippy_lints/src/thread_local_initializer_can_be_made_const.rs b/src/tools/clippy/clippy_lints/src/missing_const_for_thread_local.rs
index 4af3ee74d0e..ab1b4aa3dee 100644
--- a/src/tools/clippy/clippy_lints/src/thread_local_initializer_can_be_made_const.rs
+++ b/src/tools/clippy/clippy_lints/src/missing_const_for_thread_local.rs
@@ -39,23 +39,23 @@ declare_clippy_lint! {
     /// }
     /// ```
     #[clippy::version = "1.77.0"]
-    pub THREAD_LOCAL_INITIALIZER_CAN_BE_MADE_CONST,
+    pub MISSING_CONST_FOR_THREAD_LOCAL,
     perf,
     "suggest using `const` in `thread_local!` macro"
 }
 
-pub struct ThreadLocalInitializerCanBeMadeConst {
+pub struct MissingConstForThreadLocal {
     msrv: Msrv,
 }
 
-impl ThreadLocalInitializerCanBeMadeConst {
+impl MissingConstForThreadLocal {
     #[must_use]
     pub fn new(msrv: Msrv) -> Self {
         Self { msrv }
     }
 }
 
-impl_lint_pass!(ThreadLocalInitializerCanBeMadeConst => [THREAD_LOCAL_INITIALIZER_CAN_BE_MADE_CONST]);
+impl_lint_pass!(MissingConstForThreadLocal => [MISSING_CONST_FOR_THREAD_LOCAL]);
 
 #[inline]
 fn is_thread_local_initializer(
@@ -102,7 +102,7 @@ fn initializer_can_be_made_const(cx: &LateContext<'_>, defid: rustc_span::def_id
     false
 }
 
-impl<'tcx> LateLintPass<'tcx> for ThreadLocalInitializerCanBeMadeConst {
+impl<'tcx> LateLintPass<'tcx> for MissingConstForThreadLocal {
     fn check_fn(
         &mut self,
         cx: &LateContext<'tcx>,
@@ -113,7 +113,7 @@ impl<'tcx> LateLintPass<'tcx> for ThreadLocalInitializerCanBeMadeConst {
         local_defid: rustc_span::def_id::LocalDefId,
     ) {
         let defid = local_defid.to_def_id();
-        if self.msrv.meets(msrvs::THREAD_LOCAL_INITIALIZER_CAN_BE_MADE_CONST)
+        if self.msrv.meets(msrvs::THREAD_LOCAL_CONST_INIT)
             && is_thread_local_initializer(cx, fn_kind, span).unwrap_or(false)
             // Some implementations of `thread_local!` include an initializer fn.
             // In the case of a const initializer, the init fn is also const,
@@ -139,7 +139,7 @@ impl<'tcx> LateLintPass<'tcx> for ThreadLocalInitializerCanBeMadeConst {
         {
             span_lint_and_sugg(
                 cx,
-                THREAD_LOCAL_INITIALIZER_CAN_BE_MADE_CONST,
+                MISSING_CONST_FOR_THREAD_LOCAL,
                 unpeeled.span,
                 "initializer for `thread_local` value can be made `const`",
                 "replace with",
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 57ba0da5331..5ffd41d78e0 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
@@ -27,7 +27,7 @@ declare_clippy_lint! {
     /// Check if a `&mut` function argument is actually used mutably.
     ///
     /// Be careful if the function is publicly reexported as it would break compatibility with
-    /// users of this function.
+    /// users of this function, when the users pass this function as an argument.
     ///
     /// ### Why is this bad?
     /// Less `mut` means less fights with the borrow checker. It can also lead to more
@@ -138,6 +138,10 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessPassByRefMut<'tcx> {
             return;
         }
 
+        if self.avoid_breaking_exported_api && cx.effective_visibilities.is_exported(fn_def_id) {
+            return;
+        }
+
         let hir_id = cx.tcx.local_def_id_to_hir_id(fn_def_id);
         let is_async = match kind {
             FnKind::ItemFn(.., header) => {
@@ -262,9 +266,6 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessPassByRefMut<'tcx> {
             .iter()
             .filter(|(def_id, _)| !self.used_fn_def_ids.contains(def_id))
         {
-            let show_semver_warning =
-                self.avoid_breaking_exported_api && cx.effective_visibilities.is_exported(*fn_def_id);
-
             let mut is_cfged = None;
             for input in unused {
                 // If the argument is never used mutably, we emit the warning.
@@ -284,7 +285,7 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessPassByRefMut<'tcx> {
                                 format!("&{}", snippet(cx, cx.tcx.hir().span(inner_ty.ty.hir_id), "_"),),
                                 Applicability::Unspecified,
                             );
-                            if show_semver_warning {
+                            if cx.effective_visibilities.is_exported(*fn_def_id) {
                                 diag.warn("changing this function will impact semver compatibility");
                             }
                             if *is_cfged {
diff --git a/src/tools/clippy/clippy_lints/src/no_effect.rs b/src/tools/clippy/clippy_lints/src/no_effect.rs
index 87f886b1128..0ecfa7baa72 100644
--- a/src/tools/clippy/clippy_lints/src/no_effect.rs
+++ b/src/tools/clippy/clippy_lints/src/no_effect.rs
@@ -1,7 +1,9 @@
 use clippy_utils::diagnostics::{span_lint_hir, span_lint_hir_and_then};
 use clippy_utils::source::snippet_opt;
 use clippy_utils::ty::has_drop;
-use clippy_utils::{any_parent_is_automatically_derived, is_lint_allowed, path_to_local, peel_blocks};
+use clippy_utils::{
+    in_automatically_derived, is_inside_always_const_context, is_lint_allowed, path_to_local, peel_blocks,
+};
 use rustc_errors::Applicability;
 use rustc_hir::def::{DefKind, Res};
 use rustc_hir::{
@@ -185,7 +187,7 @@ impl NoEffect {
                 && has_no_effect(cx, init)
                 && let PatKind::Binding(_, hir_id, ident, _) = local.pat.kind
                 && ident.name.to_ident_string().starts_with('_')
-                && !any_parent_is_automatically_derived(cx.tcx, local.hir_id)
+                && !in_automatically_derived(cx.tcx, local.hir_id)
             {
                 if let Some(l) = self.local_bindings.last_mut() {
                     l.push(hir_id);
@@ -258,13 +260,16 @@ fn has_no_effect(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
 
 fn check_unnecessary_operation(cx: &LateContext<'_>, stmt: &Stmt<'_>) {
     if let StmtKind::Semi(expr) = stmt.kind
+        && !in_external_macro(cx.sess(), stmt.span)
         && let ctxt = stmt.span.ctxt()
         && expr.span.ctxt() == ctxt
         && let Some(reduced) = reduce_expression(cx, expr)
-        && !in_external_macro(cx.sess(), stmt.span)
         && reduced.iter().all(|e| e.span.ctxt() == ctxt)
     {
         if let ExprKind::Index(..) = &expr.kind {
+            if is_inside_always_const_context(cx.tcx, expr.hir_id) {
+                return;
+            }
             let snippet =
                 if let (Some(arr), Some(func)) = (snippet_opt(cx, reduced[0].span), snippet_opt(cx, reduced[1].span)) {
                     format!("assert!({}.len() > {});", &arr, &func)
diff --git a/src/tools/clippy/clippy_lints/src/operators/float_cmp.rs b/src/tools/clippy/clippy_lints/src/operators/float_cmp.rs
index faab79de9d3..0e5b440c50f 100644
--- a/src/tools/clippy/clippy_lints/src/operators/float_cmp.rs
+++ b/src/tools/clippy/clippy_lints/src/operators/float_cmp.rs
@@ -57,7 +57,6 @@ pub(crate) fn check<'tcx>(
                     Applicability::HasPlaceholders, // snippet
                 );
             }
-            diag.note("`f32::EPSILON` and `f64::EPSILON` are available for the `error_margin`");
         });
     }
 }
diff --git a/src/tools/clippy/clippy_lints/src/operators/mod.rs b/src/tools/clippy/clippy_lints/src/operators/mod.rs
index 48a442705b2..59834781a58 100644
--- a/src/tools/clippy/clippy_lints/src/operators/mod.rs
+++ b/src/tools/clippy/clippy_lints/src/operators/mod.rs
@@ -242,6 +242,13 @@ declare_clippy_lint! {
     /// # let x = 1;
     /// if (x | 1 > 3) {  }
     /// ```
+    ///
+    /// Use instead:
+    ///
+    /// ```no_run
+    /// # let x = 1;
+    /// if (x >= 2) {  }
+    /// ```
     #[clippy::version = "pre 1.29.0"]
     pub INEFFECTIVE_BIT_MASK,
     correctness,
@@ -265,6 +272,13 @@ declare_clippy_lint! {
     /// # let x = 1;
     /// if x & 0b1111 == 0 { }
     /// ```
+    ///
+    /// Use instead:
+    ///
+    /// ```no_run
+    /// # let x: i32 = 1;
+    /// if x.trailing_zeros() > 4 { }
+    /// ```
     #[clippy::version = "pre 1.29.0"]
     pub VERBOSE_BIT_MASK,
     pedantic,
@@ -560,74 +574,128 @@ declare_clippy_lint! {
     /// implement equality for a type involving floats).
     ///
     /// ### Why is this bad?
-    /// Floating point calculations are usually imprecise, so
-    /// asking if two values are *exactly* equal is asking for trouble. For a good
-    /// guide on what to do, see [the floating point
-    /// guide](http://www.floating-point-gui.de/errors/comparison).
+    /// Floating point calculations are usually imprecise, so asking if two values are *exactly*
+    /// equal is asking for trouble because arriving at the same logical result via different
+    /// routes (e.g. calculation versus constant) may yield different values.
     ///
     /// ### Example
+    ///
     /// ```no_run
-    /// let x = 1.2331f64;
-    /// let y = 1.2332f64;
+    /// let a: f64 = 1000.1;
+    /// let b: f64 = 0.2;
+    /// let x = a + b;
+    /// let y = 1000.3; // Expected value.
     ///
-    /// if y == 1.23f64 { }
-    /// if y != x {} // where both are floats
+    /// // Actual value: 1000.3000000000001
+    /// println!("{x}");
+    ///
+    /// let are_equal = x == y;
+    /// println!("{are_equal}"); // false
     /// ```
     ///
-    /// Use instead:
+    /// The correct way to compare floating point numbers is to define an allowed error margin. This
+    /// may be challenging if there is no "natural" error margin to permit. Broadly speaking, there
+    /// are two cases:
+    ///
+    /// 1. If your values are in a known range and you can define a threshold for "close enough to
+    ///    be equal", it may be appropriate to define an absolute error margin. For example, if your
+    ///    data is "length of vehicle in centimeters", you may consider 0.1 cm to be "close enough".
+    /// 1. If your code is more general and you do not know the range of values, you should use a
+    ///    relative error margin, accepting e.g. 0.1% of error regardless of specific values.
+    ///
+    /// For the scenario where you can define a meaningful absolute error margin, consider using:
+    ///
     /// ```no_run
-    /// # let x = 1.2331f64;
-    /// # let y = 1.2332f64;
-    /// let error_margin = f64::EPSILON; // Use an epsilon for comparison
-    /// // Or, if Rust <= 1.42, use `std::f64::EPSILON` constant instead.
-    /// // let error_margin = std::f64::EPSILON;
-    /// if (y - 1.23f64).abs() < error_margin { }
-    /// if (y - x).abs() > error_margin { }
+    /// let a: f64 = 1000.1;
+    /// let b: f64 = 0.2;
+    /// let x = a + b;
+    /// let y = 1000.3; // Expected value.
+    ///
+    /// const ALLOWED_ERROR_VEHICLE_LENGTH_CM: f64 = 0.1;
+    /// let within_tolerance = (x - y).abs() < ALLOWED_ERROR_VEHICLE_LENGTH_CM;
+    /// println!("{within_tolerance}"); // true
     /// ```
+    ///
+    /// NB! Do not use `f64::EPSILON` - while the error margin is often called "epsilon", this is
+    /// a different use of the term that is not suitable for floating point equality comparison.
+    /// Indeed, for the example above using `f64::EPSILON` as the allowed error would return `false`.
+    ///
+    /// For the scenario where no meaningful absolute error can be defined, refer to
+    /// [the floating point guide](https://www.floating-point-gui.de/errors/comparison)
+    /// for a reference implementation of relative error based comparison of floating point values.
+    /// `MIN_NORMAL` in the reference implementation is equivalent to `MIN_POSITIVE` in Rust.
     #[clippy::version = "pre 1.29.0"]
     pub FLOAT_CMP,
     pedantic,
-    "using `==` or `!=` on float values instead of comparing difference with an epsilon"
+    "using `==` or `!=` on float values instead of comparing difference with an allowed error"
 }
 
 declare_clippy_lint! {
     /// ### What it does
-    /// Checks for (in-)equality comparisons on floating-point
-    /// value and constant, except in functions called `*eq*` (which probably
+    /// Checks for (in-)equality comparisons on constant floating-point
+    /// values (apart from zero), except in functions called `*eq*` (which probably
     /// implement equality for a type involving floats).
     ///
     /// ### Why restrict this?
-    /// Floating point calculations are usually imprecise, so
-    /// asking if two values are *exactly* equal is asking for trouble. For a good
-    /// guide on what to do, see [the floating point
-    /// guide](http://www.floating-point-gui.de/errors/comparison).
+    /// Floating point calculations are usually imprecise, so asking if two values are *exactly*
+    /// equal is asking for trouble because arriving at the same logical result via different
+    /// routes (e.g. calculation versus constant) may yield different values.
     ///
     /// ### Example
+    ///
     /// ```no_run
-    /// let x: f64 = 1.0;
-    /// const ONE: f64 = 1.00;
+    /// let a: f64 = 1000.1;
+    /// let b: f64 = 0.2;
+    /// let x = a + b;
+    /// const Y: f64 = 1000.3; // Expected value.
+    ///
+    /// // Actual value: 1000.3000000000001
+    /// println!("{x}");
     ///
-    /// if x == ONE { } // where both are floats
+    /// let are_equal = x == Y;
+    /// println!("{are_equal}"); // false
     /// ```
     ///
-    /// Use instead:
+    /// The correct way to compare floating point numbers is to define an allowed error margin. This
+    /// may be challenging if there is no "natural" error margin to permit. Broadly speaking, there
+    /// are two cases:
+    ///
+    /// 1. If your values are in a known range and you can define a threshold for "close enough to
+    ///    be equal", it may be appropriate to define an absolute error margin. For example, if your
+    ///    data is "length of vehicle in centimeters", you may consider 0.1 cm to be "close enough".
+    /// 1. If your code is more general and you do not know the range of values, you should use a
+    ///    relative error margin, accepting e.g. 0.1% of error regardless of specific values.
+    ///
+    /// For the scenario where you can define a meaningful absolute error margin, consider using:
+    ///
     /// ```no_run
-    /// # let x: f64 = 1.0;
-    /// # const ONE: f64 = 1.00;
-    /// let error_margin = f64::EPSILON; // Use an epsilon for comparison
-    /// // Or, if Rust <= 1.42, use `std::f64::EPSILON` constant instead.
-    /// // let error_margin = std::f64::EPSILON;
-    /// if (x - ONE).abs() < error_margin { }
+    /// let a: f64 = 1000.1;
+    /// let b: f64 = 0.2;
+    /// let x = a + b;
+    /// const Y: f64 = 1000.3; // Expected value.
+    ///
+    /// const ALLOWED_ERROR_VEHICLE_LENGTH_CM: f64 = 0.1;
+    /// let within_tolerance = (x - Y).abs() < ALLOWED_ERROR_VEHICLE_LENGTH_CM;
+    /// println!("{within_tolerance}"); // true
     /// ```
+    ///
+    /// NB! Do not use `f64::EPSILON` - while the error margin is often called "epsilon", this is
+    /// a different use of the term that is not suitable for floating point equality comparison.
+    /// Indeed, for the example above using `f64::EPSILON` as the allowed error would return `false`.
+    ///
+    /// For the scenario where no meaningful absolute error can be defined, refer to
+    /// [the floating point guide](https://www.floating-point-gui.de/errors/comparison)
+    /// for a reference implementation of relative error based comparison of floating point values.
+    /// `MIN_NORMAL` in the reference implementation is equivalent to `MIN_POSITIVE` in Rust.
     #[clippy::version = "pre 1.29.0"]
     pub FLOAT_CMP_CONST,
     restriction,
-    "using `==` or `!=` on float constants instead of comparing difference with an epsilon"
+    "using `==` or `!=` on float constants instead of comparing difference with an allowed error"
 }
 
 declare_clippy_lint! {
     /// ### What it does
-    /// Checks for getting the remainder of a division by one or minus
+    /// Checks for getting the remainder of integer division by one or minus
     /// one.
     ///
     /// ### Why is this bad?
@@ -646,7 +714,7 @@ declare_clippy_lint! {
     #[clippy::version = "pre 1.29.0"]
     pub MODULO_ONE,
     correctness,
-    "taking a number modulo +/-1, which can either panic/overflow or always returns 0"
+    "taking an integer modulo +/-1, which can either panic/overflow or always returns 0"
 }
 
 declare_clippy_lint! {
diff --git a/src/tools/clippy/clippy_lints/src/overflow_check_conditional.rs b/src/tools/clippy/clippy_lints/src/overflow_check_conditional.rs
deleted file mode 100644
index de789879331..00000000000
--- a/src/tools/clippy/clippy_lints/src/overflow_check_conditional.rs
+++ /dev/null
@@ -1,70 +0,0 @@
-use clippy_utils::diagnostics::span_lint;
-use clippy_utils::SpanlessEq;
-use rustc_hir::{BinOpKind, Expr, ExprKind, QPath};
-use rustc_lint::{LateContext, LateLintPass};
-use rustc_session::declare_lint_pass;
-
-declare_clippy_lint! {
-    /// ### What it does
-    /// Detects classic underflow/overflow checks.
-    ///
-    /// ### Why is this bad?
-    /// Most classic C underflow/overflow checks will fail in
-    /// Rust. Users can use functions like `overflowing_*` and `wrapping_*` instead.
-    ///
-    /// ### Example
-    /// ```no_run
-    /// # let a = 1;
-    /// # let b = 2;
-    /// a + b < a;
-    /// ```
-    #[clippy::version = "pre 1.29.0"]
-    pub OVERFLOW_CHECK_CONDITIONAL,
-    complexity,
-    "overflow checks inspired by C which are likely to panic"
-}
-
-declare_lint_pass!(OverflowCheckConditional => [OVERFLOW_CHECK_CONDITIONAL]);
-
-const OVERFLOW_MSG: &str = "you are trying to use classic C overflow conditions that will fail in Rust";
-const UNDERFLOW_MSG: &str = "you are trying to use classic C underflow conditions that will fail in Rust";
-
-impl<'tcx> LateLintPass<'tcx> for OverflowCheckConditional {
-    // a + b < a, a > a + b, a < a - b, a - b > a
-    fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
-        let eq = |l, r| SpanlessEq::new(cx).eq_path_segment(l, r);
-        if let ExprKind::Binary(ref op, first, second) = expr.kind
-            && let ExprKind::Binary(ref op2, ident1, ident2) = first.kind
-            && let ExprKind::Path(QPath::Resolved(_, path1)) = ident1.kind
-            && let ExprKind::Path(QPath::Resolved(_, path2)) = ident2.kind
-            && let ExprKind::Path(QPath::Resolved(_, path3)) = second.kind
-            && (eq(&path1.segments[0], &path3.segments[0]) || eq(&path2.segments[0], &path3.segments[0]))
-            && cx.typeck_results().expr_ty(ident1).is_integral()
-            && cx.typeck_results().expr_ty(ident2).is_integral()
-        {
-            if op.node == BinOpKind::Lt && op2.node == BinOpKind::Add {
-                span_lint(cx, OVERFLOW_CHECK_CONDITIONAL, expr.span, OVERFLOW_MSG);
-            }
-            if op.node == BinOpKind::Gt && op2.node == BinOpKind::Sub {
-                span_lint(cx, OVERFLOW_CHECK_CONDITIONAL, expr.span, UNDERFLOW_MSG);
-            }
-        }
-
-        if let ExprKind::Binary(ref op, first, second) = expr.kind
-            && let ExprKind::Binary(ref op2, ident1, ident2) = second.kind
-            && let ExprKind::Path(QPath::Resolved(_, path1)) = ident1.kind
-            && let ExprKind::Path(QPath::Resolved(_, path2)) = ident2.kind
-            && let ExprKind::Path(QPath::Resolved(_, path3)) = first.kind
-            && (eq(&path1.segments[0], &path3.segments[0]) || eq(&path2.segments[0], &path3.segments[0]))
-            && cx.typeck_results().expr_ty(ident1).is_integral()
-            && cx.typeck_results().expr_ty(ident2).is_integral()
-        {
-            if op.node == BinOpKind::Gt && op2.node == BinOpKind::Add {
-                span_lint(cx, OVERFLOW_CHECK_CONDITIONAL, expr.span, OVERFLOW_MSG);
-            }
-            if op.node == BinOpKind::Lt && op2.node == BinOpKind::Sub {
-                span_lint(cx, OVERFLOW_CHECK_CONDITIONAL, expr.span, UNDERFLOW_MSG);
-            }
-        }
-    }
-}
diff --git a/src/tools/clippy/clippy_lints/src/panicking_overflow_checks.rs b/src/tools/clippy/clippy_lints/src/panicking_overflow_checks.rs
new file mode 100644
index 00000000000..7f100a746d5
--- /dev/null
+++ b/src/tools/clippy/clippy_lints/src/panicking_overflow_checks.rs
@@ -0,0 +1,86 @@
+use clippy_utils::diagnostics::span_lint;
+use clippy_utils::eq_expr_value;
+use rustc_hir::{BinOpKind, Expr, ExprKind};
+use rustc_lint::{LateContext, LateLintPass};
+use rustc_middle::lint::in_external_macro;
+use rustc_middle::ty;
+use rustc_session::declare_lint_pass;
+
+declare_clippy_lint! {
+    /// ### What it does
+    /// Detects C-style underflow/overflow checks.
+    ///
+    /// ### Why is this bad?
+    /// These checks will, by default, panic in debug builds rather than check
+    /// whether the operation caused an overflow.
+    ///
+    /// ### Example
+    /// ```no_run
+    /// # let a = 1i32;
+    /// # let b = 2i32;
+    /// if a + b < a {
+    ///     // handle overflow
+    /// }
+    /// ```
+    ///
+    /// Use instead:
+    /// ```no_run
+    /// # let a = 1i32;
+    /// # let b = 2i32;
+    /// if a.checked_add(b).is_none() {
+    ///     // handle overflow
+    /// }
+    /// ```
+    ///
+    /// Or:
+    /// ```no_run
+    /// # let a = 1i32;
+    /// # let b = 2i32;
+    /// if a.overflowing_add(b).1 {
+    ///     // handle overflow
+    /// }
+    /// ```
+    #[clippy::version = "pre 1.29.0"]
+    pub PANICKING_OVERFLOW_CHECKS,
+    correctness,
+    "overflow checks which will panic in debug mode"
+}
+
+declare_lint_pass!(PanickingOverflowChecks => [PANICKING_OVERFLOW_CHECKS]);
+
+impl<'tcx> LateLintPass<'tcx> for PanickingOverflowChecks {
+    // a + b < a, a > a + b, a < a - b, a - b > a
+    fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
+        if let ExprKind::Binary(op, lhs, rhs) = expr.kind
+            && let (lt, gt) = match op.node {
+                BinOpKind::Lt => (lhs, rhs),
+                BinOpKind::Gt => (rhs, lhs),
+                _ => return,
+            }
+            && let ctxt = expr.span.ctxt()
+            && let (op_lhs, op_rhs, other, commutative) = match (&lt.kind, &gt.kind) {
+                (&ExprKind::Binary(op, lhs, rhs), _) if op.node == BinOpKind::Add && ctxt == lt.span.ctxt() => {
+                    (lhs, rhs, gt, true)
+                },
+                (_, &ExprKind::Binary(op, lhs, rhs)) if op.node == BinOpKind::Sub && ctxt == gt.span.ctxt() => {
+                    (lhs, rhs, lt, false)
+                },
+                _ => return,
+            }
+            && let typeck = cx.typeck_results()
+            && let ty = typeck.expr_ty(op_lhs)
+            && matches!(ty.kind(), ty::Uint(_))
+            && ty == typeck.expr_ty(op_rhs)
+            && ty == typeck.expr_ty(other)
+            && !in_external_macro(cx.tcx.sess, expr.span)
+            && (eq_expr_value(cx, op_lhs, other) || (commutative && eq_expr_value(cx, op_rhs, other)))
+        {
+            span_lint(
+                cx,
+                PANICKING_OVERFLOW_CHECKS,
+                expr.span,
+                "you are trying to use classic C overflow conditions that will fail in Rust",
+            );
+        }
+    }
+}
diff --git a/src/tools/clippy/clippy_lints/src/renamed_lints.rs b/src/tools/clippy/clippy_lints/src/renamed_lints.rs
index 85979903b58..8e999f3e89a 100644
--- a/src/tools/clippy/clippy_lints/src/renamed_lints.rs
+++ b/src/tools/clippy/clippy_lints/src/renamed_lints.rs
@@ -26,12 +26,14 @@ pub static RENAMED_LINTS: &[(&str, &str)] = &[
     ("clippy::option_map_unwrap_or", "clippy::map_unwrap_or"),
     ("clippy::option_map_unwrap_or_else", "clippy::map_unwrap_or"),
     ("clippy::option_unwrap_used", "clippy::unwrap_used"),
+    ("clippy::overflow_check_conditional", "clippy::panicking_overflow_checks"),
     ("clippy::ref_in_deref", "clippy::needless_borrow"),
     ("clippy::result_expect_used", "clippy::expect_used"),
     ("clippy::result_map_unwrap_or_else", "clippy::map_unwrap_or"),
     ("clippy::result_unwrap_used", "clippy::unwrap_used"),
     ("clippy::single_char_push_str", "clippy::single_char_add_str"),
     ("clippy::stutter", "clippy::module_name_repetitions"),
+    ("clippy::thread_local_initializer_can_be_made_const", "clippy::missing_const_for_thread_local"),
     ("clippy::to_string_in_display", "clippy::recursive_format_impl"),
     ("clippy::unwrap_or_else_default", "clippy::unwrap_or_default"),
     ("clippy::zero_width_space", "clippy::invisible_characters"),
diff --git a/src/tools/clippy/clippy_lints/src/returns.rs b/src/tools/clippy/clippy_lints/src/returns.rs
index c11da3147ef..8ced47b48a4 100644
--- a/src/tools/clippy/clippy_lints/src/returns.rs
+++ b/src/tools/clippy/clippy_lints/src/returns.rs
@@ -7,6 +7,7 @@ use clippy_utils::{
     path_to_local_id, span_contains_cfg, span_find_starting_semi,
 };
 use core::ops::ControlFlow;
+use rustc_ast::NestedMetaItem;
 use rustc_errors::Applicability;
 use rustc_hir::intravisit::FnKind;
 use rustc_hir::LangItem::ResultErr;
@@ -14,13 +15,13 @@ use rustc_hir::{
     Block, Body, Expr, ExprKind, FnDecl, HirId, ItemKind, LangItem, MatchSource, Node, OwnerNode, PatKind, QPath, Stmt,
     StmtKind,
 };
-use rustc_lint::{LateContext, LateLintPass, LintContext};
+use rustc_lint::{LateContext, LateLintPass, Level, LintContext};
 use rustc_middle::lint::in_external_macro;
 use rustc_middle::ty::adjustment::Adjust;
 use rustc_middle::ty::{self, GenericArgKind, Ty};
 use rustc_session::declare_lint_pass;
 use rustc_span::def_id::LocalDefId;
-use rustc_span::{BytePos, Pos, Span};
+use rustc_span::{sym, BytePos, Pos, Span};
 use std::borrow::Cow;
 use std::fmt::Display;
 
@@ -80,6 +81,9 @@ declare_clippy_lint! {
     /// ```
     #[clippy::version = "pre 1.29.0"]
     pub NEEDLESS_RETURN,
+    // This lint requires some special handling in `check_final_expr` for `#[expect]`.
+    // This handling needs to be updated if the group gets changed. This should also
+    // be caught by tests.
     style,
     "using a return statement like `return expr;` where an expression would suffice"
 }
@@ -91,6 +95,9 @@ declare_clippy_lint! {
     /// ### Why is this bad?
     /// The `return` is unnecessary.
     ///
+    /// Returns may be used to add attributes to the return expression. Return
+    /// statements with attributes are therefore be accepted by this lint.
+    ///
     /// ### Example
     /// ```rust,ignore
     /// fn foo(x: usize) -> Result<(), Box<dyn Error>> {
@@ -377,13 +384,39 @@ fn check_final_expr<'tcx>(
                 }
             };
 
-            if !cx.tcx.hir().attrs(expr.hir_id).is_empty() {
-                return;
-            }
             let borrows = inner.map_or(false, |inner| last_statement_borrows(cx, inner));
             if borrows {
                 return;
             }
+            if ret_span.from_expansion() {
+                return;
+            }
+
+            // Returns may be used to turn an expression into a statement in rustc's AST.
+            // This allows the addition of attributes, like `#[allow]` (See: clippy#9361)
+            // `#[expect(clippy::needless_return)]` needs to be handled separatly to
+            // actually fullfil the expectation (clippy::#12998)
+            match cx.tcx.hir().attrs(expr.hir_id) {
+                [] => {},
+                [attr] => {
+                    if matches!(Level::from_attr(attr), Some(Level::Expect(_)))
+                        && let metas = attr.meta_item_list()
+                        && let Some(lst) = metas
+                        && let [NestedMetaItem::MetaItem(meta_item)] = lst.as_slice()
+                        && let [tool, lint_name] = meta_item.path.segments.as_slice()
+                        && tool.ident.name == sym::clippy
+                        && matches!(
+                            lint_name.ident.name.as_str(),
+                            "needless_return" | "style" | "all" | "warnings"
+                        )
+                    {
+                        // This is an expectation of the `needless_return` lint
+                    } else {
+                        return;
+                    }
+                },
+                _ => return,
+            }
 
             emit_return_lint(cx, ret_span, semi_spans, &replacement, expr.hir_id);
         },
@@ -415,10 +448,6 @@ fn emit_return_lint(
     replacement: &RetReplacement<'_>,
     at: HirId,
 ) {
-    if ret_span.from_expansion() {
-        return;
-    }
-
     span_lint_hir_and_then(
         cx,
         NEEDLESS_RETURN,
diff --git a/src/tools/clippy/clippy_lints/src/same_name_method.rs b/src/tools/clippy/clippy_lints/src/same_name_method.rs
index 8fdd19c549f..508f3ae6def 100644
--- a/src/tools/clippy/clippy_lints/src/same_name_method.rs
+++ b/src/tools/clippy/clippy_lints/src/same_name_method.rs
@@ -12,7 +12,7 @@ use std::collections::{BTreeMap, BTreeSet};
 declare_clippy_lint! {
     /// ### What it does
     /// It lints if a struct has two methods with the same name:
-    /// one from a trait, another not from trait.
+    /// one from a trait, another not from a trait.
     ///
     /// ### Why restrict this?
     /// Confusing.
diff --git a/src/tools/clippy/clippy_lints/src/set_contains_or_insert.rs b/src/tools/clippy/clippy_lints/src/set_contains_or_insert.rs
new file mode 100644
index 00000000000..5e65b9fa517
--- /dev/null
+++ b/src/tools/clippy/clippy_lints/src/set_contains_or_insert.rs
@@ -0,0 +1,125 @@
+use std::ops::ControlFlow;
+
+use clippy_utils::diagnostics::span_lint;
+use clippy_utils::ty::is_type_diagnostic_item;
+use clippy_utils::visitors::for_each_expr;
+use clippy_utils::{higher, peel_hir_expr_while, SpanlessEq};
+use rustc_hir::{Expr, ExprKind, UnOp};
+use rustc_lint::{LateContext, LateLintPass};
+use rustc_session::declare_lint_pass;
+use rustc_span::symbol::Symbol;
+use rustc_span::{sym, Span};
+
+declare_clippy_lint! {
+    /// ### What it does
+    /// Checks for usage of `contains` to see if a value is not
+    /// present on `HashSet` followed by a `insert`.
+    ///
+    /// ### Why is this bad?
+    /// Using just `insert` and checking the returned `bool` is more efficient.
+    ///
+    /// ### Known problems
+    /// In case the value that wants to be inserted is borrowed and also expensive or impossible
+    /// to clone. In such a scenario, the developer might want to check with `contains` before inserting,
+    /// to avoid the clone. In this case, it will report a false positive.
+    ///
+    /// ### Example
+    /// ```rust
+    /// use std::collections::HashSet;
+    /// let mut set = HashSet::new();
+    /// let value = 5;
+    /// if !set.contains(&value) {
+    ///     set.insert(value);
+    ///     println!("inserted {value:?}");
+    /// }
+    /// ```
+    /// Use instead:
+    /// ```rust
+    /// use std::collections::HashSet;
+    /// let mut set = HashSet::new();
+    /// let value = 5;
+    /// if set.insert(&value) {
+    ///     println!("inserted {value:?}");
+    /// }
+    /// ```
+    #[clippy::version = "1.80.0"]
+    pub SET_CONTAINS_OR_INSERT,
+    nursery,
+    "call to `HashSet::contains` followed by `HashSet::insert`"
+}
+
+declare_lint_pass!(HashsetInsertAfterContains => [SET_CONTAINS_OR_INSERT]);
+
+impl<'tcx> LateLintPass<'tcx> for HashsetInsertAfterContains {
+    fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
+        if !expr.span.from_expansion()
+            && let Some(higher::If {
+                cond: cond_expr,
+                then: then_expr,
+                ..
+            }) = higher::If::hir(expr)
+            && let Some(contains_expr) = try_parse_op_call(cx, cond_expr, sym!(contains))//try_parse_contains(cx, cond_expr)
+            && let Some(insert_expr) = find_insert_calls(cx, &contains_expr, then_expr)
+        {
+            span_lint(
+                cx,
+                SET_CONTAINS_OR_INSERT,
+                vec![contains_expr.span, insert_expr.span],
+                "usage of `HashSet::insert` after `HashSet::contains`",
+            );
+        }
+    }
+}
+
+struct OpExpr<'tcx> {
+    receiver: &'tcx Expr<'tcx>,
+    value: &'tcx Expr<'tcx>,
+    span: Span,
+}
+
+fn try_parse_op_call<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, symbol: Symbol) -> Option<OpExpr<'tcx>> {
+    let expr = peel_hir_expr_while(expr, |e| {
+        if let ExprKind::Unary(UnOp::Not, e) = e.kind {
+            Some(e)
+        } else {
+            None
+        }
+    });
+
+    if let ExprKind::MethodCall(path, receiver, [value], span) = expr.kind {
+        let value = value.peel_borrows();
+        let value = peel_hir_expr_while(value, |e| {
+            if let ExprKind::Unary(UnOp::Deref, e) = e.kind {
+                Some(e)
+            } else {
+                None
+            }
+        });
+        let receiver = receiver.peel_borrows();
+        let receiver_ty = cx.typeck_results().expr_ty(receiver).peel_refs();
+        if value.span.eq_ctxt(expr.span)
+            && is_type_diagnostic_item(cx, receiver_ty, sym::HashSet)
+            && path.ident.name == symbol
+        {
+            return Some(OpExpr { receiver, value, span });
+        }
+    }
+    None
+}
+
+fn find_insert_calls<'tcx>(
+    cx: &LateContext<'tcx>,
+    contains_expr: &OpExpr<'tcx>,
+    expr: &'tcx Expr<'_>,
+) -> Option<OpExpr<'tcx>> {
+    for_each_expr(cx, expr, |e| {
+        if let Some(insert_expr) = try_parse_op_call(cx, e, sym!(insert))
+            && SpanlessEq::new(cx).eq_expr(contains_expr.receiver, insert_expr.receiver)
+            && SpanlessEq::new(cx).eq_expr(contains_expr.value, insert_expr.value)
+        {
+            ControlFlow::Break(insert_expr)
+        } else {
+            ControlFlow::Continue(())
+        }
+    })
+}
diff --git a/src/tools/clippy/clippy_lints/src/utils/internal_lints.rs b/src/tools/clippy/clippy_lints/src/utils/internal_lints.rs
index 877a77fd6d2..1d294c2944b 100644
--- a/src/tools/clippy/clippy_lints/src/utils/internal_lints.rs
+++ b/src/tools/clippy/clippy_lints/src/utils/internal_lints.rs
@@ -1,6 +1,5 @@
 pub mod almost_standard_lint_formulation;
 pub mod collapsible_calls;
-pub mod compiler_lint_functions;
 pub mod interning_defined_symbol;
 pub mod invalid_paths;
 pub mod lint_without_lint_pass;
diff --git a/src/tools/clippy/clippy_lints/src/utils/internal_lints/compiler_lint_functions.rs b/src/tools/clippy/clippy_lints/src/utils/internal_lints/compiler_lint_functions.rs
deleted file mode 100644
index 9b6b6871818..00000000000
--- a/src/tools/clippy/clippy_lints/src/utils/internal_lints/compiler_lint_functions.rs
+++ /dev/null
@@ -1,73 +0,0 @@
-use clippy_utils::diagnostics::span_lint_and_help;
-use clippy_utils::ty::match_type;
-use clippy_utils::{is_lint_allowed, paths};
-use rustc_data_structures::fx::FxHashMap;
-use rustc_hir::{Expr, ExprKind};
-use rustc_lint::{LateContext, LateLintPass};
-use rustc_session::impl_lint_pass;
-
-declare_clippy_lint! {
-    /// ### What it does
-    /// Checks for calls to `cx.span_lint*` and suggests to use the `utils::*`
-    /// variant of the function.
-    ///
-    /// ### Why is this bad?
-    /// The `utils::*` variants also add a link to the Clippy documentation to the
-    /// warning/error messages.
-    ///
-    /// ### Example
-    /// ```rust,ignore
-    /// cx.span_lint(LINT_NAME, "message");
-    /// ```
-    ///
-    /// Use instead:
-    /// ```rust,ignore
-    /// utils::span_lint(cx, LINT_NAME, "message");
-    /// ```
-    pub COMPILER_LINT_FUNCTIONS,
-    internal,
-    "usage of the lint functions of the compiler instead of the utils::* variant"
-}
-
-impl_lint_pass!(CompilerLintFunctions => [COMPILER_LINT_FUNCTIONS]);
-
-#[derive(Clone, Default)]
-pub struct CompilerLintFunctions {
-    map: FxHashMap<&'static str, &'static str>,
-}
-
-impl CompilerLintFunctions {
-    #[must_use]
-    pub fn new() -> Self {
-        let mut map = FxHashMap::default();
-        map.insert("span_lint", "utils::span_lint");
-        map.insert("lint", "utils::span_lint");
-        map.insert("span_lint_note", "utils::span_lint_and_note");
-        map.insert("span_lint_help", "utils::span_lint_and_help");
-        Self { map }
-    }
-}
-
-impl<'tcx> LateLintPass<'tcx> for CompilerLintFunctions {
-    fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
-        if is_lint_allowed(cx, COMPILER_LINT_FUNCTIONS, expr.hir_id) {
-            return;
-        }
-
-        if let ExprKind::MethodCall(path, self_arg, _, _) = &expr.kind
-            && let fn_name = path.ident
-            && let Some(sugg) = self.map.get(fn_name.as_str())
-            && let ty = cx.typeck_results().expr_ty(self_arg).peel_refs()
-            && (match_type(cx, ty, &paths::EARLY_CONTEXT) || match_type(cx, ty, &paths::LATE_CONTEXT))
-        {
-            span_lint_and_help(
-                cx,
-                COMPILER_LINT_FUNCTIONS,
-                path.ident.span,
-                "usage of a compiler lint function",
-                None,
-                format!("please use the Clippy variant of this function: `{sugg}`"),
-            );
-        }
-    }
-}
diff --git a/src/tools/clippy/clippy_lints/src/wildcard_imports.rs b/src/tools/clippy/clippy_lints/src/wildcard_imports.rs
index 436f0cb79fb..a0a60ca8875 100644
--- a/src/tools/clippy/clippy_lints/src/wildcard_imports.rs
+++ b/src/tools/clippy/clippy_lints/src/wildcard_imports.rs
@@ -1,5 +1,5 @@
 use clippy_utils::diagnostics::span_lint_and_sugg;
-use clippy_utils::is_test_module_or_function;
+use clippy_utils::is_in_test;
 use clippy_utils::source::{snippet, snippet_with_applicability};
 use rustc_data_structures::fx::FxHashSet;
 use rustc_errors::Applicability;
@@ -100,7 +100,6 @@ declare_clippy_lint! {
 #[derive(Default)]
 pub struct WildcardImports {
     warn_on_all: bool,
-    test_modules_deep: u32,
     allowed_segments: FxHashSet<String>,
 }
 
@@ -108,7 +107,6 @@ impl WildcardImports {
     pub fn new(warn_on_all: bool, allowed_wildcard_imports: FxHashSet<String>) -> Self {
         Self {
             warn_on_all,
-            test_modules_deep: 0,
             allowed_segments: allowed_wildcard_imports,
         }
     }
@@ -122,15 +120,12 @@ impl LateLintPass<'_> for WildcardImports {
             return;
         }
 
-        if is_test_module_or_function(cx.tcx, item) {
-            self.test_modules_deep = self.test_modules_deep.saturating_add(1);
-        }
         let module = cx.tcx.parent_module_from_def_id(item.owner_id.def_id);
         if cx.tcx.visibility(item.owner_id.def_id) != ty::Visibility::Restricted(module.to_def_id()) {
             return;
         }
         if let ItemKind::Use(use_path, UseKind::Glob) = &item.kind
-            && (self.warn_on_all || !self.check_exceptions(item, use_path.segments))
+            && (self.warn_on_all || !self.check_exceptions(cx, item, use_path.segments))
             && let used_imports = cx.tcx.names_imported_by_glob_use(item.owner_id.def_id)
             && !used_imports.is_empty() // Already handled by `unused_imports`
             && !used_imports.contains(&kw::Underscore)
@@ -180,20 +175,14 @@ impl LateLintPass<'_> for WildcardImports {
             span_lint_and_sugg(cx, lint, span, message, "try", sugg, applicability);
         }
     }
-
-    fn check_item_post(&mut self, cx: &LateContext<'_>, item: &Item<'_>) {
-        if is_test_module_or_function(cx.tcx, item) {
-            self.test_modules_deep = self.test_modules_deep.saturating_sub(1);
-        }
-    }
 }
 
 impl WildcardImports {
-    fn check_exceptions(&self, item: &Item<'_>, segments: &[PathSegment<'_>]) -> bool {
+    fn check_exceptions(&self, cx: &LateContext<'_>, item: &Item<'_>, segments: &[PathSegment<'_>]) -> bool {
         item.span.from_expansion()
             || is_prelude_import(segments)
-            || (is_super_only_import(segments) && self.test_modules_deep > 0)
             || is_allowed_via_config(segments, &self.allowed_segments)
+            || (is_super_only_import(segments) && is_in_test(cx.tcx, item.hir_id()))
     }
 }
 
diff --git a/src/tools/clippy/clippy_lints/src/write.rs b/src/tools/clippy/clippy_lints/src/write.rs
index 652ce88bd95..96e53b7ef0b 100644
--- a/src/tools/clippy/clippy_lints/src/write.rs
+++ b/src/tools/clippy/clippy_lints/src/write.rs
@@ -1,7 +1,7 @@
 use clippy_utils::diagnostics::{span_lint, span_lint_and_then};
+use clippy_utils::is_in_test;
 use clippy_utils::macros::{format_arg_removal_span, root_macro_call_first_node, FormatArgsStorage, MacroCall};
 use clippy_utils::source::{expand_past_previous_comma, snippet_opt};
-use clippy_utils::{is_in_cfg_test, is_in_test_function};
 use rustc_ast::token::LitKind;
 use rustc_ast::{
     FormatArgPosition, FormatArgPositionKind, FormatArgs, FormatArgsPiece, FormatOptions, FormatPlaceholder,
@@ -297,8 +297,7 @@ impl<'tcx> LateLintPass<'tcx> for Write {
             .as_ref()
             .map_or(false, |crate_name| crate_name == "build_script_build");
 
-        let allowed_in_tests = self.allow_print_in_tests
-            && (is_in_test_function(cx.tcx, expr.hir_id) || is_in_cfg_test(cx.tcx, expr.hir_id));
+        let allowed_in_tests = self.allow_print_in_tests && is_in_test(cx.tcx, expr.hir_id);
         match diag_name {
             sym::print_macro | sym::println_macro if !allowed_in_tests => {
                 if !is_build_script {
diff --git a/src/tools/clippy/clippy_utils/src/lib.rs b/src/tools/clippy/clippy_utils/src/lib.rs
index 935a25d7931..bdb3b5e45c4 100644
--- a/src/tools/clippy/clippy_utils/src/lib.rs
+++ b/src/tools/clippy/clippy_utils/src/lib.rs
@@ -102,10 +102,11 @@ use rustc_hir::hir_id::{HirIdMap, HirIdSet};
 use rustc_hir::intravisit::{walk_expr, FnKind, Visitor};
 use rustc_hir::LangItem::{OptionNone, OptionSome, ResultErr, ResultOk};
 use rustc_hir::{
-    self as hir, def, Arm, ArrayLen, BindingMode, Block, BlockCheckMode, Body, ByRef, Closure, Destination, Expr,
-    ExprField, ExprKind, FnDecl, FnRetTy, GenericArgs, HirId, Impl, ImplItem, ImplItemKind, ImplItemRef, Item,
-    ItemKind, LangItem, LetStmt, MatchSource, Mutability, Node, OwnerId, Param, Pat, PatKind, Path, PathSegment,
-    PrimTy, QPath, Stmt, StmtKind, TraitItem, TraitItemKind, TraitItemRef, TraitRef, TyKind, UnOp,
+    self as hir, def, Arm, ArrayLen, BindingMode, Block, BlockCheckMode, Body, ByRef, Closure, ConstContext,
+    Destination, Expr, ExprField, ExprKind, FnDecl, FnRetTy, GenericArgs, HirId, Impl, ImplItem, ImplItemKind,
+    ImplItemRef, Item, ItemKind, LangItem, LetStmt, MatchSource, Mutability, Node, OwnerId, OwnerNode, Param, Pat,
+    PatKind, Path, PathSegment, PrimTy, QPath, Stmt, StmtKind, TraitItem, TraitItemKind, TraitItemRef, TraitRef,
+    TyKind, UnOp,
 };
 use rustc_lexer::{tokenize, TokenKind};
 use rustc_lint::{LateContext, Level, Lint, LintContext};
@@ -210,7 +211,10 @@ pub fn local_is_initialized(cx: &LateContext<'_>, local: HirId) -> bool {
     false
 }
 
-/// Returns `true` if the given `NodeId` is inside a constant context
+/// Returns `true` if the given `HirId` is inside a constant context.
+///
+/// This is the same as `is_inside_always_const_context`, but also includes
+/// `const fn`.
 ///
 /// # Example
 ///
@@ -223,6 +227,24 @@ pub fn in_constant(cx: &LateContext<'_>, id: HirId) -> bool {
     cx.tcx.hir().is_inside_const_context(id)
 }
 
+/// Returns `true` if the given `HirId` is inside an always constant context.
+///
+/// This context includes:
+///  * const/static items
+///  * const blocks (or inline consts)
+///  * associated constants
+pub fn is_inside_always_const_context(tcx: TyCtxt<'_>, hir_id: HirId) -> bool {
+    use ConstContext::{Const, ConstFn, Static};
+    let hir = tcx.hir();
+    let Some(ctx) = hir.body_const_context(hir.enclosing_body_owner(hir_id)) else {
+        return false;
+    };
+    match ctx {
+        ConstFn => false,
+        Static(_) | Const { inline: _ } => true,
+    }
+}
+
 /// Checks if a `Res` refers to a constructor of a `LangItem`
 /// For example, use this to check whether a function call or a pattern is `Some(..)`.
 pub fn is_res_lang_ctor(cx: &LateContext<'_>, res: Res, lang_item: LangItem) -> bool {
@@ -1904,8 +1926,18 @@ pub fn any_parent_has_attr(tcx: TyCtxt<'_>, node: HirId, symbol: Symbol) -> bool
     false
 }
 
-pub fn any_parent_is_automatically_derived(tcx: TyCtxt<'_>, node: HirId) -> bool {
-    any_parent_has_attr(tcx, node, sym::automatically_derived)
+/// Checks if the given HIR node is inside an `impl` block with the `automatically_derived`
+/// attribute.
+pub fn in_automatically_derived(tcx: TyCtxt<'_>, id: HirId) -> bool {
+    tcx.hir()
+        .parent_owner_iter(id)
+        .filter(|(_, node)| matches!(node, OwnerNode::Item(item) if matches!(item.kind, ItemKind::Impl(_))))
+        .any(|(id, _)| {
+            has_attr(
+                tcx.hir().attrs(tcx.local_def_id_to_hir_id(id.def_id)),
+                sym::automatically_derived,
+            )
+        })
 }
 
 /// Matches a function call with the given path and returns the arguments.
@@ -2472,6 +2504,17 @@ pub fn peel_hir_ty_refs<'a>(mut ty: &'a hir::Ty<'a>) -> (&'a hir::Ty<'a>, usize)
     }
 }
 
+/// Peels off all references on the type. Returns the underlying type and the number of references
+/// removed.
+pub fn peel_middle_ty_refs(mut ty: Ty<'_>) -> (Ty<'_>, usize) {
+    let mut count = 0;
+    while let rustc_ty::Ref(_, dest_ty, _) = ty.kind() {
+        ty = *dest_ty;
+        count += 1;
+    }
+    (ty, count)
+}
+
 /// Removes `AddrOf` operators (`&`) or deref operators (`*`), but only if a reference type is
 /// dereferenced. An overloaded deref such as `Vec` to slice would not be removed.
 pub fn peel_ref_operators<'hir>(cx: &LateContext<'_>, mut expr: &'hir Expr<'hir>) -> &'hir Expr<'hir> {
@@ -2594,16 +2637,6 @@ pub fn inherits_cfg(tcx: TyCtxt<'_>, def_id: LocalDefId) -> bool {
             .any(|attr| attr.has_name(sym::cfg))
 }
 
-/// Checks whether item either has `test` attribute applied, or
-/// is a module with `test` in its name.
-///
-/// Note: Add `//@compile-flags: --test` to UI tests with a `#[test]` function
-pub fn is_test_module_or_function(tcx: TyCtxt<'_>, item: &Item<'_>) -> bool {
-    is_in_test_function(tcx, item.hir_id())
-        || matches!(item.kind, ItemKind::Mod(..))
-            && item.ident.name.as_str().split('_').any(|a| a == "test" || a == "tests")
-}
-
 /// Walks up the HIR tree from the given expression in an attempt to find where the value is
 /// consumed.
 ///
diff --git a/src/tools/clippy/clippy_utils/src/paths.rs b/src/tools/clippy/clippy_utils/src/paths.rs
index 3f66813801d..d5a3d8b9e5a 100644
--- a/src/tools/clippy/clippy_utils/src/paths.rs
+++ b/src/tools/clippy/clippy_utils/src/paths.rs
@@ -88,6 +88,7 @@ pub const SYMBOL_INTERN: [&str; 4] = ["rustc_span", "symbol", "Symbol", "intern"
 pub const SYMBOL_TO_IDENT_STRING: [&str; 4] = ["rustc_span", "symbol", "Symbol", "to_ident_string"];
 pub const SYM_MODULE: [&str; 3] = ["rustc_span", "symbol", "sym"];
 pub const SYNTAX_CONTEXT: [&str; 3] = ["rustc_span", "hygiene", "SyntaxContext"];
+pub const STRING_FROM_UTF8: [&str; 4] = ["alloc", "string", "String", "from_utf8"];
 #[expect(clippy::invalid_paths)] // internal lints do not know about all external crates
 pub const TOKIO_FILE_OPTIONS: [&str; 5] = ["tokio", "fs", "file", "File", "options"];
 #[expect(clippy::invalid_paths)] // internal lints do not know about all external crates
diff --git a/src/tools/clippy/clippy_utils/src/ty.rs b/src/tools/clippy/clippy_utils/src/ty.rs
index acaeb93f44a..fc02b974ee1 100644
--- a/src/tools/clippy/clippy_utils/src/ty.rs
+++ b/src/tools/clippy/clippy_utils/src/ty.rs
@@ -96,11 +96,7 @@ pub fn contains_ty_adt_constructor_opaque<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'
                         return false;
                     }
 
-                    for (predicate, _span) in cx
-                        .tcx
-                        .explicit_item_super_predicates(def_id)
-                        .iter_identity_copied()
-                    {
+                    for (predicate, _span) in cx.tcx.explicit_item_super_predicates(def_id).iter_identity_copied() {
                         match predicate.kind().skip_binder() {
                             // For `impl Trait<U>`, it will register a predicate of `T: Trait<U>`, so we go through
                             // and check substitutions to find `U`.
@@ -1332,19 +1328,13 @@ pub fn deref_chain<'cx, 'tcx>(cx: &'cx LateContext<'tcx>, ty: Ty<'tcx>) -> impl
 /// If you need this, you should wrap this call in `clippy_utils::ty::deref_chain().any(...)`.
 pub fn get_adt_inherent_method<'a>(cx: &'a LateContext<'_>, ty: Ty<'_>, method_name: Symbol) -> Option<&'a AssocItem> {
     if let Some(ty_did) = ty.ty_adt_def().map(AdtDef::did) {
-        cx.tcx
-            .inherent_impls(ty_did)
-            .into_iter()
-            .flatten()
-            .map(|&did| {
-                cx.tcx
-                    .associated_items(did)
-                    .filter_by_name_unhygienic(method_name)
-                    .next()
-                    .filter(|item| item.kind == AssocKind::Fn)
-            })
-            .next()
-            .flatten()
+        cx.tcx.inherent_impls(ty_did).into_iter().flatten().find_map(|&did| {
+            cx.tcx
+                .associated_items(did)
+                .filter_by_name_unhygienic(method_name)
+                .next()
+                .filter(|item| item.kind == AssocKind::Fn)
+        })
     } else {
         None
     }
diff --git a/src/tools/clippy/lintcheck/Cargo.toml b/src/tools/clippy/lintcheck/Cargo.toml
index ae9e77b8eed..3c86dfe324f 100644
--- a/src/tools/clippy/lintcheck/Cargo.toml
+++ b/src/tools/clippy/lintcheck/Cargo.toml
@@ -16,6 +16,7 @@ clap = { version = "4.4", features = ["derive", "env"] }
 crossbeam-channel = "0.5.6"
 diff = "0.1.13"
 flate2 = "1.0"
+itertools = "0.12"
 rayon = "1.5.1"
 serde = { version = "1.0", features = ["derive"] }
 serde_json = "1.0.85"
diff --git a/src/tools/clippy/lintcheck/README.md b/src/tools/clippy/lintcheck/README.md
index 2d6039caeef..47a96e0a03c 100644
--- a/src/tools/clippy/lintcheck/README.md
+++ b/src/tools/clippy/lintcheck/README.md
@@ -7,13 +7,13 @@ repo.  We can then check the diff and spot new or disappearing warnings.
 From the repo root, run:
 
 ```
-cargo run --target-dir lintcheck/target --manifest-path lintcheck/Cargo.toml
+cargo lintcheck
 ```
 
 or
 
 ```
-cargo lintcheck
+cargo run --target-dir lintcheck/target --manifest-path lintcheck/Cargo.toml
 ```
 
 By default, the logs will be saved into
@@ -33,6 +33,8 @@ the 200 recently most downloaded crates:
 cargo lintcheck popular -n 200 custom.toml
 ```
 
+> Note: Lintcheck isn't sandboxed. Only use it to check crates that you trust or
+> sandbox it manually.
 
 ### Configuring the Crate Sources
 
@@ -65,17 +67,11 @@ sources.
 #### Command Line Options (optional)
 
 ```toml
-bitflags = {name = "bitflags", versions = ['1.2.1'], options = ['-Wclippy::pedantic', '-Wclippy::cargo']}
+clap = {name = "clap", versions = ['4.5.8'], options = ['-Fderive']}
 ```
 
 It is possible to specify command line options for each crate. This makes it
-possible to only check a crate for certain lint groups. If no options are
-specified, the lint groups `clippy::all`, `clippy::pedantic`, and
-`clippy::cargo` are checked. If an empty array is specified only `clippy::all`
-is checked.
-
-**Note:** `-Wclippy::all` is always enabled by default, unless `-Aclippy::all`
-is explicitly specified in the options.
+possible to enable or disable features.
 
 ### Fix mode
 You can run `cargo lintcheck --fix` which will run Clippy with `--fix` and
diff --git a/src/tools/clippy/lintcheck/lintcheck_crates.toml b/src/tools/clippy/lintcheck/lintcheck_crates.toml
index 52f7fee47b6..ff608e6f935 100644
--- a/src/tools/clippy/lintcheck/lintcheck_crates.toml
+++ b/src/tools/clippy/lintcheck/lintcheck_crates.toml
@@ -1,38 +1,38 @@
 [crates]
 # some of these are from cargotest
-cargo = {name = "cargo", versions = ['0.64.0']}
-iron = {name = "iron", versions = ['0.6.1']}
-ripgrep = {name = "ripgrep", versions = ['12.1.1']}
-xsv = {name = "xsv", versions = ['0.13.0']}
+cargo = {name = "cargo", version = '0.64.0'}
+iron = {name = "iron", version = '0.6.1'}
+ripgrep = {name = "ripgrep", version = '12.1.1'}
+xsv = {name = "xsv", version = '0.13.0'}
 # commented out because of 173K clippy::match_same_arms msgs in language_type.rs
-#tokei = { name = "tokei", versions = ['12.0.4']}
-rayon = {name = "rayon", versions = ['1.5.0']}
-serde = {name = "serde", versions = ['1.0.118']}
+#tokei = { name = "tokei", version = '12.0.4'}
+rayon = {name = "rayon", version = '1.5.0'}
+serde = {name = "serde", version = '1.0.118'}
 # top 10 crates.io dls
-bitflags = {name = "bitflags", versions = ['1.2.1']}
+bitflags = {name = "bitflags", version = '1.2.1'}
 # crash = {name = "clippy_crash", path = "/tmp/clippy_crash"}
-libc = {name = "libc", versions = ['0.2.81']}
-log = {name = "log", versions = ['0.4.11']}
-proc-macro2 = {name = "proc-macro2", versions = ['1.0.24']}
-quote = {name = "quote", versions = ['1.0.7']}
-rand = {name = "rand", versions = ['0.7.3']}
-rand_core = {name = "rand_core", versions = ['0.6.0']}
-regex = {name = "regex", versions = ['1.3.2']}
-syn = {name = "syn", versions = ['1.0.54']}
-unicode-xid = {name = "unicode-xid", versions = ['0.2.1']}
+libc = {name = "libc", version = '0.2.81'}
+log = {name = "log", version = '0.4.11'}
+proc-macro2 = {name = "proc-macro2", version = '1.0.24'}
+quote = {name = "quote", version = '1.0.7'}
+rand = {name = "rand", version = '0.7.3'}
+rand_core = {name = "rand_core", version = '0.6.0'}
+regex = {name = "regex", version = '1.3.2'}
+syn = {name = "syn", version = '1.0.54'}
+unicode-xid = {name = "unicode-xid", version = '0.2.1'}
 # some more of dtolnays crates
-anyhow = {name = "anyhow", versions = ['1.0.38']}
-async-trait = {name = "async-trait", versions = ['0.1.42']}
-cxx = {name = "cxx", versions = ['1.0.32']}
-ryu = {name = "ryu", versions = ['1.0.5']}
-serde_yaml = {name = "serde_yaml", versions = ['0.8.17']}
-thiserror = {name = "thiserror", versions = ['1.0.24']}
+anyhow = {name = "anyhow", version = '1.0.38'}
+async-trait = {name = "async-trait", version = '0.1.42'}
+cxx = {name = "cxx", version = '1.0.32'}
+ryu = {name = "ryu", version = '1.0.5'}
+serde_yaml = {name = "serde_yaml", version = '0.8.17'}
+thiserror = {name = "thiserror", version = '1.0.24'}
 # some embark crates, there are other interesting crates but
 # unfortunately adding them increases lintcheck runtime drastically
-cfg-expr = {name = "cfg-expr", versions = ['0.7.1']}
+cfg-expr = {name = "cfg-expr", version = '0.7.1'}
 puffin = {name = "puffin", git_url = "https://github.com/EmbarkStudios/puffin", git_hash = "02dd4a3"}
-rpmalloc = {name = "rpmalloc", versions = ['0.2.0']}
-tame-oidc = {name = "tame-oidc", versions = ['0.1.0']}
+rpmalloc = {name = "rpmalloc", version = '0.2.0'}
+tame-oidc = {name = "tame-oidc", version = '0.1.0'}
 
 [recursive]
 ignore = [
diff --git a/src/tools/clippy/lintcheck/src/config.rs b/src/tools/clippy/lintcheck/src/config.rs
index e6cd7c9fdc2..b35a62eed44 100644
--- a/src/tools/clippy/lintcheck/src/config.rs
+++ b/src/tools/clippy/lintcheck/src/config.rs
@@ -36,6 +36,10 @@ pub(crate) struct LintcheckConfig {
     /// Apply a filter to only collect specified lints, this also overrides `allow` attributes
     #[clap(long = "filter", value_name = "clippy_lint_name", use_value_delimiter = true)]
     pub lint_filter: Vec<String>,
+    /// Set all lints to the "warn" lint level, even resitriction ones. Usually,
+    /// it's better to use `--filter` instead
+    #[clap(long, conflicts_with("lint_filter"))]
+    pub warn_all: bool,
     /// Set the output format of the log file
     #[clap(long, short, default_value = "text")]
     pub format: OutputFormat,
diff --git a/src/tools/clippy/lintcheck/src/driver.rs b/src/tools/clippy/lintcheck/src/driver.rs
index 47724a2fedb..041be5081f2 100644
--- a/src/tools/clippy/lintcheck/src/driver.rs
+++ b/src/tools/clippy/lintcheck/src/driver.rs
@@ -11,8 +11,6 @@ use std::{env, mem};
 fn run_clippy(addr: &str) -> Option<i32> {
     let driver_info = DriverInfo {
         package_name: env::var("CARGO_PKG_NAME").ok()?,
-        crate_name: env::var("CARGO_CRATE_NAME").ok()?,
-        version: env::var("CARGO_PKG_VERSION").ok()?,
     };
 
     let mut stream = BufReader::new(TcpStream::connect(addr).unwrap());
diff --git a/src/tools/clippy/lintcheck/src/input.rs b/src/tools/clippy/lintcheck/src/input.rs
new file mode 100644
index 00000000000..3d034391c28
--- /dev/null
+++ b/src/tools/clippy/lintcheck/src/input.rs
@@ -0,0 +1,288 @@
+use std::collections::{HashMap, HashSet};
+use std::fs::{self};
+use std::io::{self, ErrorKind};
+use std::path::{Path, PathBuf};
+use std::process::Command;
+use std::time::Duration;
+
+use serde::Deserialize;
+use walkdir::{DirEntry, WalkDir};
+
+use crate::{Crate, LINTCHECK_DOWNLOADS, LINTCHECK_SOURCES};
+
+/// List of sources to check, loaded from a .toml file
+#[derive(Debug, Deserialize)]
+pub struct SourceList {
+    crates: HashMap<String, TomlCrate>,
+    #[serde(default)]
+    recursive: RecursiveOptions,
+}
+
+#[derive(Debug, Deserialize, Default)]
+pub struct RecursiveOptions {
+    pub ignore: HashSet<String>,
+}
+
+/// A crate source stored inside the .toml
+/// will be translated into on one of the `CrateSource` variants
+#[derive(Debug, Deserialize)]
+struct TomlCrate {
+    name: String,
+    version: Option<String>,
+    git_url: Option<String>,
+    git_hash: Option<String>,
+    path: Option<String>,
+    options: Option<Vec<String>>,
+}
+
+/// Represents an archive we download from crates.io, or a git repo, or a local repo/folder
+/// Once processed (downloaded/extracted/cloned/copied...), this will be translated into a `Crate`
+#[derive(Debug, Deserialize, Eq, Hash, PartialEq, Ord, PartialOrd)]
+pub enum CrateSource {
+    CratesIo {
+        name: String,
+        version: String,
+        options: Option<Vec<String>>,
+    },
+    Git {
+        name: String,
+        url: String,
+        commit: String,
+        options: Option<Vec<String>>,
+    },
+    Path {
+        name: String,
+        path: PathBuf,
+        options: Option<Vec<String>>,
+    },
+}
+
+/// Read a `lintcheck_crates.toml` file
+pub fn read_crates(toml_path: &Path) -> (Vec<CrateSource>, RecursiveOptions) {
+    let toml_content: String =
+        fs::read_to_string(toml_path).unwrap_or_else(|_| panic!("Failed to read {}", toml_path.display()));
+    let crate_list: SourceList =
+        toml::from_str(&toml_content).unwrap_or_else(|e| panic!("Failed to parse {}: \n{e}", toml_path.display()));
+    // parse the hashmap of the toml file into a list of crates
+    let tomlcrates: Vec<TomlCrate> = crate_list.crates.into_values().collect();
+
+    // flatten TomlCrates into CrateSources (one TomlCrates may represent several versions of a crate =>
+    // multiple Cratesources)
+    let mut crate_sources = Vec::new();
+    for tk in tomlcrates {
+        if let Some(ref path) = tk.path {
+            crate_sources.push(CrateSource::Path {
+                name: tk.name.clone(),
+                path: PathBuf::from(path),
+                options: tk.options.clone(),
+            });
+        } else if let Some(ref version) = tk.version {
+            crate_sources.push(CrateSource::CratesIo {
+                name: tk.name.clone(),
+                version: version.to_string(),
+                options: tk.options.clone(),
+            });
+        } else if tk.git_url.is_some() && tk.git_hash.is_some() {
+            // otherwise, we should have a git source
+            crate_sources.push(CrateSource::Git {
+                name: tk.name.clone(),
+                url: tk.git_url.clone().unwrap(),
+                commit: tk.git_hash.clone().unwrap(),
+                options: tk.options.clone(),
+            });
+        } else {
+            panic!("Invalid crate source: {tk:?}");
+        }
+
+        // if we have a version as well as a git data OR only one git data, something is funky
+        if tk.version.is_some() && (tk.git_url.is_some() || tk.git_hash.is_some())
+            || tk.git_hash.is_some() != tk.git_url.is_some()
+        {
+            eprintln!("tomlkrate: {tk:?}");
+            assert_eq!(
+                tk.git_hash.is_some(),
+                tk.git_url.is_some(),
+                "Error: Encountered TomlCrate with only one of git_hash and git_url!"
+            );
+            assert!(
+                tk.path.is_none() || (tk.git_hash.is_none() && tk.version.is_none()),
+                "Error: TomlCrate can only have one of 'git_.*', 'version' or 'path' fields"
+            );
+            unreachable!("Failed to translate TomlCrate into CrateSource!");
+        }
+    }
+    // sort the crates
+    crate_sources.sort();
+
+    (crate_sources, crate_list.recursive)
+}
+
+impl CrateSource {
+    /// Makes the sources available on the disk for clippy to check.
+    /// Clones a git repo and checks out the specified commit or downloads a crate from crates.io or
+    /// copies a local folder
+    #[expect(clippy::too_many_lines)]
+    pub fn download_and_extract(&self) -> Crate {
+        #[allow(clippy::result_large_err)]
+        fn get(path: &str) -> Result<ureq::Response, ureq::Error> {
+            const MAX_RETRIES: u8 = 4;
+            let mut retries = 0;
+            loop {
+                match ureq::get(path).call() {
+                    Ok(res) => return Ok(res),
+                    Err(e) if retries >= MAX_RETRIES => return Err(e),
+                    Err(ureq::Error::Transport(e)) => eprintln!("Error: {e}"),
+                    Err(e) => return Err(e),
+                }
+                eprintln!("retrying in {retries} seconds...");
+                std::thread::sleep(Duration::from_secs(u64::from(retries)));
+                retries += 1;
+            }
+        }
+        match self {
+            CrateSource::CratesIo { name, version, options } => {
+                let extract_dir = PathBuf::from(LINTCHECK_SOURCES);
+                let krate_download_dir = PathBuf::from(LINTCHECK_DOWNLOADS);
+
+                // url to download the crate from crates.io
+                let url = format!("https://crates.io/api/v1/crates/{name}/{version}/download");
+                println!("Downloading and extracting {name} {version} from {url}");
+                create_dirs(&krate_download_dir, &extract_dir);
+
+                let krate_file_path = krate_download_dir.join(format!("{name}-{version}.crate.tar.gz"));
+                // don't download/extract if we already have done so
+                if !krate_file_path.is_file() {
+                    // create a file path to download and write the crate data into
+                    let mut krate_dest = fs::File::create(&krate_file_path).unwrap();
+                    let mut krate_req = get(&url).unwrap().into_reader();
+                    // copy the crate into the file
+                    io::copy(&mut krate_req, &mut krate_dest).unwrap();
+
+                    // unzip the tarball
+                    let ungz_tar = flate2::read::GzDecoder::new(fs::File::open(&krate_file_path).unwrap());
+                    // extract the tar archive
+                    let mut archive = tar::Archive::new(ungz_tar);
+                    archive.unpack(&extract_dir).expect("Failed to extract!");
+                }
+                // crate is extracted, return a new Krate object which contains the path to the extracted
+                // sources that clippy can check
+                Crate {
+                    version: version.clone(),
+                    name: name.clone(),
+                    path: extract_dir.join(format!("{name}-{version}/")),
+                    options: options.clone(),
+                }
+            },
+            CrateSource::Git {
+                name,
+                url,
+                commit,
+                options,
+            } => {
+                let repo_path = {
+                    let mut repo_path = PathBuf::from(LINTCHECK_SOURCES);
+                    // add a -git suffix in case we have the same crate from crates.io and a git repo
+                    repo_path.push(format!("{name}-git"));
+                    repo_path
+                };
+                // clone the repo if we have not done so
+                if !repo_path.is_dir() {
+                    println!("Cloning {url} and checking out {commit}");
+                    if !Command::new("git")
+                        .arg("clone")
+                        .arg(url)
+                        .arg(&repo_path)
+                        .status()
+                        .expect("Failed to clone git repo!")
+                        .success()
+                    {
+                        eprintln!("Failed to clone {url} into {}", repo_path.display());
+                    }
+                }
+                // check out the commit/branch/whatever
+                if !Command::new("git")
+                    .args(["-c", "advice.detachedHead=false"])
+                    .arg("checkout")
+                    .arg(commit)
+                    .current_dir(&repo_path)
+                    .status()
+                    .expect("Failed to check out commit")
+                    .success()
+                {
+                    eprintln!("Failed to checkout {commit} of repo at {}", repo_path.display());
+                }
+
+                Crate {
+                    version: commit.clone(),
+                    name: name.clone(),
+                    path: repo_path,
+                    options: options.clone(),
+                }
+            },
+            CrateSource::Path { name, path, options } => {
+                fn is_cache_dir(entry: &DirEntry) -> bool {
+                    fs::read(entry.path().join("CACHEDIR.TAG"))
+                        .map(|x| x.starts_with(b"Signature: 8a477f597d28d172789f06886806bc55"))
+                        .unwrap_or(false)
+                }
+
+                // copy path into the dest_crate_root but skip directories that contain a CACHEDIR.TAG file.
+                // The target/ directory contains a CACHEDIR.TAG file so it is the most commonly skipped directory
+                // as a result of this filter.
+                let dest_crate_root = PathBuf::from(LINTCHECK_SOURCES).join(name);
+                if dest_crate_root.exists() {
+                    println!("Deleting existing directory at {dest_crate_root:?}");
+                    fs::remove_dir_all(&dest_crate_root).unwrap();
+                }
+
+                println!("Copying {path:?} to {dest_crate_root:?}");
+
+                for entry in WalkDir::new(path).into_iter().filter_entry(|e| !is_cache_dir(e)) {
+                    let entry = entry.unwrap();
+                    let entry_path = entry.path();
+                    let relative_entry_path = entry_path.strip_prefix(path).unwrap();
+                    let dest_path = dest_crate_root.join(relative_entry_path);
+                    let metadata = entry_path.symlink_metadata().unwrap();
+
+                    if metadata.is_dir() {
+                        fs::create_dir(dest_path).unwrap();
+                    } else if metadata.is_file() {
+                        fs::copy(entry_path, dest_path).unwrap();
+                    }
+                }
+
+                Crate {
+                    version: String::from("local"),
+                    name: name.clone(),
+                    path: dest_crate_root,
+                    options: options.clone(),
+                }
+            },
+        }
+    }
+}
+
+/// Create necessary directories to run the lintcheck tool.
+///
+/// # Panics
+///
+/// This function panics if creating one of the dirs fails.
+fn create_dirs(krate_download_dir: &Path, extract_dir: &Path) {
+    fs::create_dir("target/lintcheck/").unwrap_or_else(|err| {
+        assert_eq!(
+            err.kind(),
+            ErrorKind::AlreadyExists,
+            "cannot create lintcheck target dir"
+        );
+    });
+    fs::create_dir(krate_download_dir).unwrap_or_else(|err| {
+        assert_eq!(err.kind(), ErrorKind::AlreadyExists, "cannot create crate download dir");
+    });
+    fs::create_dir(extract_dir).unwrap_or_else(|err| {
+        assert_eq!(
+            err.kind(),
+            ErrorKind::AlreadyExists,
+            "cannot create crate extraction dir"
+        );
+    });
+}
diff --git a/src/tools/clippy/lintcheck/src/json.rs b/src/tools/clippy/lintcheck/src/json.rs
index 43d0413c7ce..1a652927988 100644
--- a/src/tools/clippy/lintcheck/src/json.rs
+++ b/src/tools/clippy/lintcheck/src/json.rs
@@ -1,37 +1,50 @@
-use std::collections::HashMap;
-use std::fmt::Write;
 use std::fs;
-use std::hash::Hash;
 use std::path::Path;
 
+use itertools::EitherOrBoth;
+use serde::{Deserialize, Serialize};
+
 use crate::ClippyWarning;
 
-/// Creates the log file output for [`crate::config::OutputFormat::Json`]
-pub(crate) fn output(clippy_warnings: &[ClippyWarning]) -> String {
-    serde_json::to_string(&clippy_warnings).unwrap()
+#[derive(Deserialize, Serialize)]
+struct LintJson {
+    lint: String,
+    file_name: String,
+    byte_pos: (u32, u32),
+    rendered: String,
 }
 
-fn load_warnings(path: &Path) -> Vec<ClippyWarning> {
-    let file = fs::read(path).unwrap_or_else(|e| panic!("failed to read {}: {e}", path.display()));
-
-    serde_json::from_slice(&file).unwrap_or_else(|e| panic!("failed to deserialize {}: {e}", path.display()))
+impl LintJson {
+    fn key(&self) -> impl Ord + '_ {
+        (self.file_name.as_str(), self.byte_pos, self.lint.as_str())
+    }
 }
 
-/// Group warnings by their primary span location + lint name
-fn create_map(warnings: &[ClippyWarning]) -> HashMap<impl Eq + Hash + '_, Vec<&ClippyWarning>> {
-    let mut map = HashMap::<_, Vec<_>>::with_capacity(warnings.len());
-
-    for warning in warnings {
-        let span = warning.span();
-        let key = (&warning.lint_type, &span.file_name, span.byte_start, span.byte_end);
+/// Creates the log file output for [`crate::config::OutputFormat::Json`]
+pub(crate) fn output(clippy_warnings: Vec<ClippyWarning>) -> String {
+    let mut lints: Vec<LintJson> = clippy_warnings
+        .into_iter()
+        .map(|warning| {
+            let span = warning.span();
+            LintJson {
+                file_name: span.file_name.clone(),
+                byte_pos: (span.byte_start, span.byte_end),
+                lint: warning.lint,
+                rendered: warning.diag.rendered.unwrap(),
+            }
+        })
+        .collect();
+    lints.sort_by(|a, b| a.key().cmp(&b.key()));
+    serde_json::to_string(&lints).unwrap()
+}
 
-        map.entry(key).or_default().push(warning);
-    }
+fn load_warnings(path: &Path) -> Vec<LintJson> {
+    let file = fs::read(path).unwrap_or_else(|e| panic!("failed to read {}: {e}", path.display()));
 
-    map
+    serde_json::from_slice(&file).unwrap_or_else(|e| panic!("failed to deserialize {}: {e}", path.display()))
 }
 
-fn print_warnings(title: &str, warnings: &[&ClippyWarning]) {
+fn print_warnings(title: &str, warnings: &[LintJson]) {
     if warnings.is_empty() {
         return;
     }
@@ -39,31 +52,20 @@ fn print_warnings(title: &str, warnings: &[&ClippyWarning]) {
     println!("### {title}");
     println!("```");
     for warning in warnings {
-        print!("{}", warning.diag);
+        print!("{}", warning.rendered);
     }
     println!("```");
 }
 
-fn print_changed_diff(changed: &[(&[&ClippyWarning], &[&ClippyWarning])]) {
-    fn render(warnings: &[&ClippyWarning]) -> String {
-        let mut rendered = String::new();
-        for warning in warnings {
-            write!(&mut rendered, "{}", warning.diag).unwrap();
-        }
-        rendered
-    }
-
+fn print_changed_diff(changed: &[(LintJson, LintJson)]) {
     if changed.is_empty() {
         return;
     }
 
     println!("### Changed");
     println!("```diff");
-    for &(old, new) in changed {
-        let old_rendered = render(old);
-        let new_rendered = render(new);
-
-        for change in diff::lines(&old_rendered, &new_rendered) {
+    for (old, new) in changed {
+        for change in diff::lines(&old.rendered, &new.rendered) {
             use diff::Result::{Both, Left, Right};
 
             match change {
@@ -86,26 +88,19 @@ pub(crate) fn diff(old_path: &Path, new_path: &Path) {
     let old_warnings = load_warnings(old_path);
     let new_warnings = load_warnings(new_path);
 
-    let old_map = create_map(&old_warnings);
-    let new_map = create_map(&new_warnings);
-
     let mut added = Vec::new();
     let mut removed = Vec::new();
     let mut changed = Vec::new();
 
-    for (key, new) in &new_map {
-        if let Some(old) = old_map.get(key) {
-            if old != new {
-                changed.push((old.as_slice(), new.as_slice()));
-            }
-        } else {
-            added.extend(new);
-        }
-    }
-
-    for (key, old) in &old_map {
-        if !new_map.contains_key(key) {
-            removed.extend(old);
+    for change in itertools::merge_join_by(old_warnings, new_warnings, |old, new| old.key().cmp(&new.key())) {
+        match change {
+            EitherOrBoth::Both(old, new) => {
+                if old.rendered != new.rendered {
+                    changed.push((old, new));
+                }
+            },
+            EitherOrBoth::Left(old) => removed.push(old),
+            EitherOrBoth::Right(new) => added.push(new),
         }
     }
 
diff --git a/src/tools/clippy/lintcheck/src/main.rs b/src/tools/clippy/lintcheck/src/main.rs
index ec72e0eb5dc..e37ffab13ac 100644
--- a/src/tools/clippy/lintcheck/src/main.rs
+++ b/src/tools/clippy/lintcheck/src/main.rs
@@ -5,6 +5,7 @@
 // When a new lint is introduced, we can search the results for new warnings and check for false
 // positives.
 
+#![feature(iter_collect_into)]
 #![warn(
     trivial_casts,
     trivial_numeric_casts,
@@ -12,84 +13,38 @@
     unused_lifetimes,
     unused_qualifications
 )]
-#![allow(clippy::collapsible_else_if, clippy::needless_borrows_for_generic_args)]
+#![allow(
+    clippy::collapsible_else_if,
+    clippy::needless_borrows_for_generic_args,
+    clippy::module_name_repetitions
+)]
 
 mod config;
 mod driver;
+mod input;
 mod json;
+mod output;
 mod popular_crates;
 mod recursive;
 
 use crate::config::{Commands, LintcheckConfig, OutputFormat};
 use crate::recursive::LintcheckServer;
 
-use std::collections::{HashMap, HashSet};
 use std::env::consts::EXE_SUFFIX;
-use std::fmt::{self, Display, Write as _};
-use std::hash::Hash;
-use std::io::{self, ErrorKind};
+use std::io::{self};
 use std::path::{Path, PathBuf};
-use std::process::{Command, ExitStatus, Stdio};
+use std::process::{Command, Stdio};
 use std::sync::atomic::{AtomicUsize, Ordering};
-use std::time::Duration;
-use std::{env, fs, thread};
+use std::{env, fs};
 
-use cargo_metadata::diagnostic::{Diagnostic, DiagnosticSpan};
 use cargo_metadata::Message;
+use input::{read_crates, CrateSource};
+use output::{ClippyCheckOutput, ClippyWarning, RustcIce};
 use rayon::prelude::*;
-use serde::{Deserialize, Serialize};
-use walkdir::{DirEntry, WalkDir};
 
 const LINTCHECK_DOWNLOADS: &str = "target/lintcheck/downloads";
 const LINTCHECK_SOURCES: &str = "target/lintcheck/sources";
 
-/// List of sources to check, loaded from a .toml file
-#[derive(Debug, Deserialize)]
-struct SourceList {
-    crates: HashMap<String, TomlCrate>,
-    #[serde(default)]
-    recursive: RecursiveOptions,
-}
-
-#[derive(Debug, Deserialize, Default)]
-struct RecursiveOptions {
-    ignore: HashSet<String>,
-}
-
-/// A crate source stored inside the .toml
-/// will be translated into on one of the `CrateSource` variants
-#[derive(Debug, Deserialize)]
-struct TomlCrate {
-    name: String,
-    versions: Option<Vec<String>>,
-    git_url: Option<String>,
-    git_hash: Option<String>,
-    path: Option<String>,
-    options: Option<Vec<String>>,
-}
-
-/// Represents an archive we download from crates.io, or a git repo, or a local repo/folder
-/// Once processed (downloaded/extracted/cloned/copied...), this will be translated into a `Crate`
-#[derive(Debug, Deserialize, Eq, Hash, PartialEq, Ord, PartialOrd)]
-enum CrateSource {
-    CratesIo {
-        name: String,
-        version: String,
-        options: Option<Vec<String>>,
-    },
-    Git {
-        name: String,
-        url: String,
-        commit: String,
-        options: Option<Vec<String>>,
-    },
-    Path {
-        name: String,
-        path: PathBuf,
-        options: Option<Vec<String>>,
-    },
-}
-
 /// Represents the actual source code of a crate that we ran "cargo clippy" on
 #[derive(Debug)]
 struct Crate {
@@ -100,248 +55,6 @@ struct Crate {
     options: Option<Vec<String>>,
 }
 
-/// A single emitted output from clippy being executed on a crate. It may either be a
-/// `ClippyWarning`, or a `RustcIce` caused by a panic within clippy. A crate may have many
-/// `ClippyWarning`s but a maximum of one `RustcIce` (at which point clippy halts execution).
-#[derive(Debug)]
-enum ClippyCheckOutput {
-    ClippyWarning(ClippyWarning),
-    RustcIce(RustcIce),
-}
-
-#[derive(Debug)]
-struct RustcIce {
-    pub crate_name: String,
-    pub ice_content: String,
-}
-
-impl Display for RustcIce {
-    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        write!(
-            f,
-            "{}:\n{}\n========================================\n",
-            self.crate_name, self.ice_content
-        )
-    }
-}
-
-impl RustcIce {
-    pub fn from_stderr_and_status(crate_name: &str, status: ExitStatus, stderr: &str) -> Option<Self> {
-        if status.code().unwrap_or(0) == 101
-        /* ice exit status */
-        {
-            Some(Self {
-                crate_name: crate_name.to_owned(),
-                ice_content: stderr.to_owned(),
-            })
-        } else {
-            None
-        }
-    }
-}
-
-/// A single warning that clippy issued while checking a `Crate`
-#[derive(Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
-struct ClippyWarning {
-    crate_name: String,
-    crate_version: String,
-    lint_type: String,
-    diag: Diagnostic,
-}
-
-#[allow(unused)]
-impl ClippyWarning {
-    fn new(mut diag: Diagnostic, crate_name: &str, crate_version: &str) -> Option<Self> {
-        let lint_type = diag.code.clone()?.code;
-        if !(lint_type.contains("clippy") || diag.message.contains("clippy"))
-            || diag.message.contains("could not read cargo metadata")
-        {
-            return None;
-        }
-
-        // --recursive bypasses cargo so we have to strip the rendered output ourselves
-        let rendered = diag.rendered.as_mut().unwrap();
-        *rendered = strip_ansi_escapes::strip_str(&rendered);
-
-        Some(Self {
-            crate_name: crate_name.to_owned(),
-            crate_version: crate_version.to_owned(),
-            lint_type,
-            diag,
-        })
-    }
-
-    fn span(&self) -> &DiagnosticSpan {
-        self.diag.spans.iter().find(|span| span.is_primary).unwrap()
-    }
-
-    fn to_output(&self, format: OutputFormat) -> String {
-        let span = self.span();
-        let mut file = span.file_name.clone();
-        let file_with_pos = format!("{file}:{}:{}", span.line_start, span.line_end);
-        match format {
-            OutputFormat::Text => format!("{file_with_pos} {} \"{}\"\n", self.lint_type, self.diag.message),
-            OutputFormat::Markdown => {
-                if file.starts_with("target") {
-                    file.insert_str(0, "../");
-                }
-
-                let mut output = String::from("| ");
-                write!(output, "[`{file_with_pos}`]({file}#L{})", span.line_start).unwrap();
-                write!(output, r#" | `{:<50}` | "{}" |"#, self.lint_type, self.diag.message).unwrap();
-                output.push('\n');
-                output
-            },
-            OutputFormat::Json => unreachable!("JSON output is handled via serde"),
-        }
-    }
-}
-
-#[allow(clippy::result_large_err)]
-fn get(path: &str) -> Result<ureq::Response, ureq::Error> {
-    const MAX_RETRIES: u8 = 4;
-    let mut retries = 0;
-    loop {
-        match ureq::get(path).call() {
-            Ok(res) => return Ok(res),
-            Err(e) if retries >= MAX_RETRIES => return Err(e),
-            Err(ureq::Error::Transport(e)) => eprintln!("Error: {e}"),
-            Err(e) => return Err(e),
-        }
-        eprintln!("retrying in {retries} seconds...");
-        thread::sleep(Duration::from_secs(u64::from(retries)));
-        retries += 1;
-    }
-}
-
-impl CrateSource {
-    /// Makes the sources available on the disk for clippy to check.
-    /// Clones a git repo and checks out the specified commit or downloads a crate from crates.io or
-    /// copies a local folder
-    fn download_and_extract(&self) -> Crate {
-        match self {
-            CrateSource::CratesIo { name, version, options } => {
-                let extract_dir = PathBuf::from(LINTCHECK_SOURCES);
-                let krate_download_dir = PathBuf::from(LINTCHECK_DOWNLOADS);
-
-                // url to download the crate from crates.io
-                let url = format!("https://crates.io/api/v1/crates/{name}/{version}/download");
-                println!("Downloading and extracting {name} {version} from {url}");
-                create_dirs(&krate_download_dir, &extract_dir);
-
-                let krate_file_path = krate_download_dir.join(format!("{name}-{version}.crate.tar.gz"));
-                // don't download/extract if we already have done so
-                if !krate_file_path.is_file() {
-                    // create a file path to download and write the crate data into
-                    let mut krate_dest = fs::File::create(&krate_file_path).unwrap();
-                    let mut krate_req = get(&url).unwrap().into_reader();
-                    // copy the crate into the file
-                    io::copy(&mut krate_req, &mut krate_dest).unwrap();
-
-                    // unzip the tarball
-                    let ungz_tar = flate2::read::GzDecoder::new(fs::File::open(&krate_file_path).unwrap());
-                    // extract the tar archive
-                    let mut archive = tar::Archive::new(ungz_tar);
-                    archive.unpack(&extract_dir).expect("Failed to extract!");
-                }
-                // crate is extracted, return a new Krate object which contains the path to the extracted
-                // sources that clippy can check
-                Crate {
-                    version: version.clone(),
-                    name: name.clone(),
-                    path: extract_dir.join(format!("{name}-{version}/")),
-                    options: options.clone(),
-                }
-            },
-            CrateSource::Git {
-                name,
-                url,
-                commit,
-                options,
-            } => {
-                let repo_path = {
-                    let mut repo_path = PathBuf::from(LINTCHECK_SOURCES);
-                    // add a -git suffix in case we have the same crate from crates.io and a git repo
-                    repo_path.push(format!("{name}-git"));
-                    repo_path
-                };
-                // clone the repo if we have not done so
-                if !repo_path.is_dir() {
-                    println!("Cloning {url} and checking out {commit}");
-                    if !Command::new("git")
-                        .arg("clone")
-                        .arg(url)
-                        .arg(&repo_path)
-                        .status()
-                        .expect("Failed to clone git repo!")
-                        .success()
-                    {
-                        eprintln!("Failed to clone {url} into {}", repo_path.display());
-                    }
-                }
-                // check out the commit/branch/whatever
-                if !Command::new("git")
-                    .args(["-c", "advice.detachedHead=false"])
-                    .arg("checkout")
-                    .arg(commit)
-                    .current_dir(&repo_path)
-                    .status()
-                    .expect("Failed to check out commit")
-                    .success()
-                {
-                    eprintln!("Failed to checkout {commit} of repo at {}", repo_path.display());
-                }
-
-                Crate {
-                    version: commit.clone(),
-                    name: name.clone(),
-                    path: repo_path,
-                    options: options.clone(),
-                }
-            },
-            CrateSource::Path { name, path, options } => {
-                fn is_cache_dir(entry: &DirEntry) -> bool {
-                    fs::read(entry.path().join("CACHEDIR.TAG"))
-                        .map(|x| x.starts_with(b"Signature: 8a477f597d28d172789f06886806bc55"))
-                        .unwrap_or(false)
-                }
-
-                // copy path into the dest_crate_root but skip directories that contain a CACHEDIR.TAG file.
-                // The target/ directory contains a CACHEDIR.TAG file so it is the most commonly skipped directory
-                // as a result of this filter.
-                let dest_crate_root = PathBuf::from(LINTCHECK_SOURCES).join(name);
-                if dest_crate_root.exists() {
-                    println!("Deleting existing directory at {dest_crate_root:?}");
-                    fs::remove_dir_all(&dest_crate_root).unwrap();
-                }
-
-                println!("Copying {path:?} to {dest_crate_root:?}");
-
-                for entry in WalkDir::new(path).into_iter().filter_entry(|e| !is_cache_dir(e)) {
-                    let entry = entry.unwrap();
-                    let entry_path = entry.path();
-                    let relative_entry_path = entry_path.strip_prefix(path).unwrap();
-                    let dest_path = dest_crate_root.join(relative_entry_path);
-                    let metadata = entry_path.symlink_metadata().unwrap();
-
-                    if metadata.is_dir() {
-                        fs::create_dir(dest_path).unwrap();
-                    } else if metadata.is_file() {
-                        fs::copy(entry_path, dest_path).unwrap();
-                    }
-                }
-
-                Crate {
-                    version: String::from("local"),
-                    name: name.clone(),
-                    path: dest_crate_root,
-                    options: options.clone(),
-                }
-            },
-        }
-    }
-}
-
 impl Crate {
     /// Run `cargo clippy` on the `Crate` and collect and return all the lint warnings that clippy
     /// issued
@@ -352,7 +65,7 @@ impl Crate {
         target_dir_index: &AtomicUsize,
         total_crates_to_lint: usize,
         config: &LintcheckConfig,
-        lint_filter: &[String],
+        lint_levels_args: &[String],
         server: &Option<LintcheckServer>,
     ) -> Vec<ClippyCheckOutput> {
         // advance the atomic index by one
@@ -398,16 +111,9 @@ impl Crate {
             for opt in options {
                 clippy_args.push(opt);
             }
-        } else {
-            clippy_args.extend(["-Wclippy::pedantic", "-Wclippy::cargo"]);
         }
 
-        if lint_filter.is_empty() {
-            clippy_args.push("--cap-lints=warn");
-        } else {
-            clippy_args.push("--cap-lints=allow");
-            clippy_args.extend(lint_filter.iter().map(String::as_str));
-        }
+        clippy_args.extend(lint_levels_args.iter().map(String::as_str));
 
         let mut cmd = Command::new("cargo");
         cmd.arg(if config.fix { "fix" } else { "check" })
@@ -479,7 +185,7 @@ impl Crate {
         // get all clippy warnings and ICEs
         let mut entries: Vec<ClippyCheckOutput> = Message::parse_stream(stdout.as_bytes())
             .filter_map(|msg| match msg {
-                Ok(Message::CompilerMessage(message)) => ClippyWarning::new(message.message, &self.name, &self.version),
+                Ok(Message::CompilerMessage(message)) => ClippyWarning::new(message.message),
                 _ => None,
             })
             .map(ClippyCheckOutput::ClippyWarning)
@@ -509,96 +215,6 @@ fn build_clippy() -> String {
     String::from_utf8_lossy(&output.stdout).into_owned()
 }
 
-/// Read a `lintcheck_crates.toml` file
-fn read_crates(toml_path: &Path) -> (Vec<CrateSource>, RecursiveOptions) {
-    let toml_content: String =
-        fs::read_to_string(toml_path).unwrap_or_else(|_| panic!("Failed to read {}", toml_path.display()));
-    let crate_list: SourceList =
-        toml::from_str(&toml_content).unwrap_or_else(|e| panic!("Failed to parse {}: \n{e}", toml_path.display()));
-    // parse the hashmap of the toml file into a list of crates
-    let tomlcrates: Vec<TomlCrate> = crate_list.crates.into_values().collect();
-
-    // flatten TomlCrates into CrateSources (one TomlCrates may represent several versions of a crate =>
-    // multiple Cratesources)
-    let mut crate_sources = Vec::new();
-    for tk in tomlcrates {
-        if let Some(ref path) = tk.path {
-            crate_sources.push(CrateSource::Path {
-                name: tk.name.clone(),
-                path: PathBuf::from(path),
-                options: tk.options.clone(),
-            });
-        } else if let Some(ref versions) = tk.versions {
-            // if we have multiple versions, save each one
-            for ver in versions {
-                crate_sources.push(CrateSource::CratesIo {
-                    name: tk.name.clone(),
-                    version: ver.to_string(),
-                    options: tk.options.clone(),
-                });
-            }
-        } else if tk.git_url.is_some() && tk.git_hash.is_some() {
-            // otherwise, we should have a git source
-            crate_sources.push(CrateSource::Git {
-                name: tk.name.clone(),
-                url: tk.git_url.clone().unwrap(),
-                commit: tk.git_hash.clone().unwrap(),
-                options: tk.options.clone(),
-            });
-        } else {
-            panic!("Invalid crate source: {tk:?}");
-        }
-
-        // if we have a version as well as a git data OR only one git data, something is funky
-        if tk.versions.is_some() && (tk.git_url.is_some() || tk.git_hash.is_some())
-            || tk.git_hash.is_some() != tk.git_url.is_some()
-        {
-            eprintln!("tomlkrate: {tk:?}");
-            assert_eq!(
-                tk.git_hash.is_some(),
-                tk.git_url.is_some(),
-                "Error: Encountered TomlCrate with only one of git_hash and git_url!"
-            );
-            assert!(
-                tk.path.is_none() || (tk.git_hash.is_none() && tk.versions.is_none()),
-                "Error: TomlCrate can only have one of 'git_.*', 'version' or 'path' fields"
-            );
-            unreachable!("Failed to translate TomlCrate into CrateSource!");
-        }
-    }
-    // sort the crates
-    crate_sources.sort();
-
-    (crate_sources, crate_list.recursive)
-}
-
-/// Generate a short list of occurring lints-types and their count
-fn gather_stats(warnings: &[ClippyWarning]) -> (String, HashMap<&String, usize>) {
-    // count lint type occurrences
-    let mut counter: HashMap<&String, usize> = HashMap::new();
-    warnings
-        .iter()
-        .for_each(|wrn| *counter.entry(&wrn.lint_type).or_insert(0) += 1);
-
-    // collect into a tupled list for sorting
-    let mut stats: Vec<(&&String, &usize)> = counter.iter().collect();
-    // sort by "000{count} {clippy::lintname}"
-    // to not have a lint with 200 and 2 warnings take the same spot
-    stats.sort_by_key(|(lint, count)| format!("{count:0>4}, {lint}"));
-
-    let mut header = String::from("| lint                                               | count |\n");
-    header.push_str("| -------------------------------------------------- | ----- |\n");
-    let stats_string = stats
-        .iter()
-        .map(|(lint, count)| format!("| {lint:<50} |  {count:>4} |\n"))
-        .fold(header, |mut table, line| {
-            table.push_str(&line);
-            table
-        });
-
-    (stats_string, counter)
-}
-
 fn main() {
     // We're being executed as a `RUSTC_WRAPPER` as part of `--recursive`
     if let Ok(addr) = env::var("LINTCHECK_SERVER") {
@@ -638,15 +254,39 @@ fn lintcheck(config: LintcheckConfig) {
     let (crates, recursive_options) = read_crates(&config.sources_toml_path);
 
     let counter = AtomicUsize::new(1);
-    let lint_filter: Vec<String> = config
-        .lint_filter
-        .iter()
-        .map(|filter| {
-            let mut filter = filter.clone();
-            filter.insert_str(0, "--force-warn=");
-            filter
-        })
-        .collect();
+    let mut lint_level_args: Vec<String> = vec![];
+    if config.lint_filter.is_empty() {
+        lint_level_args.push("--cap-lints=warn".to_string());
+
+        // Set allow-by-default to warn
+        if config.warn_all {
+            [
+                "clippy::cargo",
+                "clippy::nursery",
+                "clippy::pedantic",
+                "clippy::restriction",
+            ]
+            .iter()
+            .map(|group| format!("--warn={group}"))
+            .collect_into(&mut lint_level_args);
+        } else {
+            ["clippy::cargo", "clippy::pedantic"]
+                .iter()
+                .map(|group| format!("--warn={group}"))
+                .collect_into(&mut lint_level_args);
+        }
+    } else {
+        lint_level_args.push("--cap-lints=allow".to_string());
+        config
+            .lint_filter
+            .iter()
+            .map(|filter| {
+                let mut filter = filter.clone();
+                filter.insert_str(0, "--force-warn=");
+                filter
+            })
+            .collect_into(&mut lint_level_args);
+    };
 
     let crates: Vec<Crate> = crates
         .into_iter()
@@ -698,7 +338,7 @@ fn lintcheck(config: LintcheckConfig) {
                 &counter,
                 crates.len(),
                 &config,
-                &lint_filter,
+                &lint_level_args,
                 &server,
             )
         })
@@ -727,7 +367,9 @@ fn lintcheck(config: LintcheckConfig) {
     }
 
     let text = match config.format {
-        OutputFormat::Text | OutputFormat::Markdown => output(&warnings, &raw_ices, clippy_ver, &config),
+        OutputFormat::Text | OutputFormat::Markdown => {
+            output::summarize_and_print_changes(&warnings, &raw_ices, clippy_ver, &config)
+        },
         OutputFormat::Json => {
             if !raw_ices.is_empty() {
                 for ice in raw_ices {
@@ -736,7 +378,7 @@ fn lintcheck(config: LintcheckConfig) {
                 panic!("Some crates ICEd");
             }
 
-            json::output(&warnings)
+            json::output(warnings)
         },
     };
 
@@ -745,135 +387,6 @@ fn lintcheck(config: LintcheckConfig) {
     fs::write(&config.lintcheck_results_path, text).unwrap();
 }
 
-/// Creates the log file output for [`OutputFormat::Text`] and [`OutputFormat::Markdown`]
-fn output(warnings: &[ClippyWarning], ices: &[RustcIce], clippy_ver: String, config: &LintcheckConfig) -> String {
-    // generate some stats
-    let (stats_formatted, new_stats) = gather_stats(warnings);
-    let old_stats = read_stats_from_file(&config.lintcheck_results_path);
-
-    let mut all_msgs: Vec<String> = warnings.iter().map(|warn| warn.to_output(config.format)).collect();
-    all_msgs.sort();
-    all_msgs.push("\n\n### Stats:\n\n".into());
-    all_msgs.push(stats_formatted);
-
-    let mut text = clippy_ver; // clippy version number on top
-    text.push_str("\n### Reports\n\n");
-    if config.format == OutputFormat::Markdown {
-        text.push_str("| file | lint | message |\n");
-        text.push_str("| --- | --- | --- |\n");
-    }
-    write!(text, "{}", all_msgs.join("")).unwrap();
-    text.push_str("\n\n### ICEs:\n");
-    for ice in ices {
-        writeln!(text, "{ice}").unwrap();
-    }
-
-    print_stats(old_stats, new_stats, &config.lint_filter);
-
-    text
-}
-
-/// read the previous stats from the lintcheck-log file
-fn read_stats_from_file(file_path: &Path) -> HashMap<String, usize> {
-    let file_content: String = match fs::read_to_string(file_path).ok() {
-        Some(content) => content,
-        None => {
-            return HashMap::new();
-        },
-    };
-
-    let lines: Vec<String> = file_content.lines().map(ToString::to_string).collect();
-
-    lines
-        .iter()
-        .skip_while(|line| line.as_str() != "### Stats:")
-        // Skipping the table header and the `Stats:` label
-        .skip(4)
-        .take_while(|line| line.starts_with("| "))
-        .filter_map(|line| {
-            let mut spl = line.split('|');
-            // Skip the first `|` symbol
-            spl.next();
-            if let (Some(lint), Some(count)) = (spl.next(), spl.next()) {
-                Some((lint.trim().to_string(), count.trim().parse::<usize>().unwrap()))
-            } else {
-                None
-            }
-        })
-        .collect::<HashMap<String, usize>>()
-}
-
-/// print how lint counts changed between runs
-fn print_stats(old_stats: HashMap<String, usize>, new_stats: HashMap<&String, usize>, lint_filter: &[String]) {
-    let same_in_both_hashmaps = old_stats
-        .iter()
-        .filter(|(old_key, old_val)| new_stats.get::<&String>(old_key) == Some(old_val))
-        .map(|(k, v)| (k.to_string(), *v))
-        .collect::<Vec<(String, usize)>>();
-
-    let mut old_stats_deduped = old_stats;
-    let mut new_stats_deduped = new_stats;
-
-    // remove duplicates from both hashmaps
-    for (k, v) in &same_in_both_hashmaps {
-        assert!(old_stats_deduped.remove(k) == Some(*v));
-        assert!(new_stats_deduped.remove(k) == Some(*v));
-    }
-
-    println!("\nStats:");
-
-    // list all new counts  (key is in new stats but not in old stats)
-    new_stats_deduped
-        .iter()
-        .filter(|(new_key, _)| !old_stats_deduped.contains_key::<str>(new_key))
-        .for_each(|(new_key, new_value)| {
-            println!("{new_key} 0 => {new_value}");
-        });
-
-    // list all changed counts (key is in both maps but value differs)
-    new_stats_deduped
-        .iter()
-        .filter(|(new_key, _new_val)| old_stats_deduped.contains_key::<str>(new_key))
-        .for_each(|(new_key, new_val)| {
-            let old_val = old_stats_deduped.get::<str>(new_key).unwrap();
-            println!("{new_key} {old_val} => {new_val}");
-        });
-
-    // list all gone counts (key is in old status but not in new stats)
-    old_stats_deduped
-        .iter()
-        .filter(|(old_key, _)| !new_stats_deduped.contains_key::<&String>(old_key))
-        .filter(|(old_key, _)| lint_filter.is_empty() || lint_filter.contains(old_key))
-        .for_each(|(old_key, old_value)| {
-            println!("{old_key} {old_value} => 0");
-        });
-}
-
-/// Create necessary directories to run the lintcheck tool.
-///
-/// # Panics
-///
-/// This function panics if creating one of the dirs fails.
-fn create_dirs(krate_download_dir: &Path, extract_dir: &Path) {
-    fs::create_dir("target/lintcheck/").unwrap_or_else(|err| {
-        assert_eq!(
-            err.kind(),
-            ErrorKind::AlreadyExists,
-            "cannot create lintcheck target dir"
-        );
-    });
-    fs::create_dir(krate_download_dir).unwrap_or_else(|err| {
-        assert_eq!(err.kind(), ErrorKind::AlreadyExists, "cannot create crate download dir");
-    });
-    fs::create_dir(extract_dir).unwrap_or_else(|err| {
-        assert_eq!(
-            err.kind(),
-            ErrorKind::AlreadyExists,
-            "cannot create crate extraction dir"
-        );
-    });
-}
-
 /// Returns the path to the Clippy project directory
 #[must_use]
 fn clippy_project_root() -> &'static Path {
diff --git a/src/tools/clippy/lintcheck/src/output.rs b/src/tools/clippy/lintcheck/src/output.rs
new file mode 100644
index 00000000000..4bfc554ef9e
--- /dev/null
+++ b/src/tools/clippy/lintcheck/src/output.rs
@@ -0,0 +1,235 @@
+use cargo_metadata::diagnostic::{Diagnostic, DiagnosticSpan};
+use serde::{Deserialize, Serialize};
+use std::collections::HashMap;
+use std::fmt::{self, Write as _};
+use std::fs;
+use std::path::Path;
+use std::process::ExitStatus;
+
+use crate::config::{LintcheckConfig, OutputFormat};
+
+/// A single emitted output from clippy being executed on a crate. It may either be a
+/// `ClippyWarning`, or a `RustcIce` caused by a panic within clippy. A crate may have many
+/// `ClippyWarning`s but a maximum of one `RustcIce` (at which point clippy halts execution).
+#[derive(Debug)]
+pub enum ClippyCheckOutput {
+    ClippyWarning(ClippyWarning),
+    RustcIce(RustcIce),
+}
+
+#[derive(Debug)]
+pub struct RustcIce {
+    pub crate_name: String,
+    pub ice_content: String,
+}
+
+impl fmt::Display for RustcIce {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        write!(
+            f,
+            "{}:\n{}\n========================================\n",
+            self.crate_name, self.ice_content
+        )
+    }
+}
+
+impl RustcIce {
+    pub fn from_stderr_and_status(crate_name: &str, status: ExitStatus, stderr: &str) -> Option<Self> {
+        if status.code().unwrap_or(0) == 101
+        /* ice exit status */
+        {
+            Some(Self {
+                crate_name: crate_name.to_owned(),
+                ice_content: stderr.to_owned(),
+            })
+        } else {
+            None
+        }
+    }
+}
+
+/// A single warning that clippy issued while checking a `Crate`
+#[derive(Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
+pub struct ClippyWarning {
+    pub lint: String,
+    pub diag: Diagnostic,
+}
+
+#[allow(unused)]
+impl ClippyWarning {
+    pub fn new(mut diag: Diagnostic) -> Option<Self> {
+        let lint = diag.code.clone()?.code;
+        if !(lint.contains("clippy") || diag.message.contains("clippy"))
+            || diag.message.contains("could not read cargo metadata")
+        {
+            return None;
+        }
+
+        // --recursive bypasses cargo so we have to strip the rendered output ourselves
+        let rendered = diag.rendered.as_mut().unwrap();
+        *rendered = strip_ansi_escapes::strip_str(&rendered);
+
+        Some(Self { lint, diag })
+    }
+
+    pub fn span(&self) -> &DiagnosticSpan {
+        self.diag.spans.iter().find(|span| span.is_primary).unwrap()
+    }
+
+    pub fn to_output(&self, format: OutputFormat) -> String {
+        let span = self.span();
+        let mut file = span.file_name.clone();
+        let file_with_pos = format!("{file}:{}:{}", span.line_start, span.line_end);
+        match format {
+            OutputFormat::Text => format!("{file_with_pos} {} \"{}\"\n", self.lint, self.diag.message),
+            OutputFormat::Markdown => {
+                if file.starts_with("target") {
+                    file.insert_str(0, "../");
+                }
+
+                let mut output = String::from("| ");
+                write!(output, "[`{file_with_pos}`]({file}#L{})", span.line_start).unwrap();
+                write!(output, r#" | `{:<50}` | "{}" |"#, self.lint, self.diag.message).unwrap();
+                output.push('\n');
+                output
+            },
+            OutputFormat::Json => unreachable!("JSON output is handled via serde"),
+        }
+    }
+}
+
+/// Creates the log file output for [`OutputFormat::Text`] and [`OutputFormat::Markdown`]
+pub fn summarize_and_print_changes(
+    warnings: &[ClippyWarning],
+    ices: &[RustcIce],
+    clippy_ver: String,
+    config: &LintcheckConfig,
+) -> String {
+    // generate some stats
+    let (stats_formatted, new_stats) = gather_stats(warnings);
+    let old_stats = read_stats_from_file(&config.lintcheck_results_path);
+
+    let mut all_msgs: Vec<String> = warnings.iter().map(|warn| warn.to_output(config.format)).collect();
+    all_msgs.sort();
+    all_msgs.push("\n\n### Stats:\n\n".into());
+    all_msgs.push(stats_formatted);
+
+    let mut text = clippy_ver; // clippy version number on top
+    text.push_str("\n### Reports\n\n");
+    if config.format == OutputFormat::Markdown {
+        text.push_str("| file | lint | message |\n");
+        text.push_str("| --- | --- | --- |\n");
+    }
+    write!(text, "{}", all_msgs.join("")).unwrap();
+    text.push_str("\n\n### ICEs:\n");
+    for ice in ices {
+        writeln!(text, "{ice}").unwrap();
+    }
+
+    print_stats(old_stats, new_stats, &config.lint_filter);
+
+    text
+}
+
+/// Generate a short list of occurring lints-types and their count
+fn gather_stats(warnings: &[ClippyWarning]) -> (String, HashMap<&String, usize>) {
+    // count lint type occurrences
+    let mut counter: HashMap<&String, usize> = HashMap::new();
+    warnings
+        .iter()
+        .for_each(|wrn| *counter.entry(&wrn.lint).or_insert(0) += 1);
+
+    // collect into a tupled list for sorting
+    let mut stats: Vec<(&&String, &usize)> = counter.iter().collect();
+    // sort by "000{count} {clippy::lintname}"
+    // to not have a lint with 200 and 2 warnings take the same spot
+    stats.sort_by_key(|(lint, count)| format!("{count:0>4}, {lint}"));
+
+    let mut header = String::from("| lint                                               | count |\n");
+    header.push_str("| -------------------------------------------------- | ----- |\n");
+    let stats_string = stats
+        .iter()
+        .map(|(lint, count)| format!("| {lint:<50} |  {count:>4} |\n"))
+        .fold(header, |mut table, line| {
+            table.push_str(&line);
+            table
+        });
+
+    (stats_string, counter)
+}
+
+/// read the previous stats from the lintcheck-log file
+fn read_stats_from_file(file_path: &Path) -> HashMap<String, usize> {
+    let file_content: String = match fs::read_to_string(file_path).ok() {
+        Some(content) => content,
+        None => {
+            return HashMap::new();
+        },
+    };
+
+    let lines: Vec<String> = file_content.lines().map(ToString::to_string).collect();
+
+    lines
+        .iter()
+        .skip_while(|line| line.as_str() != "### Stats:")
+        // Skipping the table header and the `Stats:` label
+        .skip(4)
+        .take_while(|line| line.starts_with("| "))
+        .filter_map(|line| {
+            let mut spl = line.split('|');
+            // Skip the first `|` symbol
+            spl.next();
+            if let (Some(lint), Some(count)) = (spl.next(), spl.next()) {
+                Some((lint.trim().to_string(), count.trim().parse::<usize>().unwrap()))
+            } else {
+                None
+            }
+        })
+        .collect::<HashMap<String, usize>>()
+}
+
+/// print how lint counts changed between runs
+fn print_stats(old_stats: HashMap<String, usize>, new_stats: HashMap<&String, usize>, lint_filter: &[String]) {
+    let same_in_both_hashmaps = old_stats
+        .iter()
+        .filter(|(old_key, old_val)| new_stats.get::<&String>(old_key) == Some(old_val))
+        .map(|(k, v)| (k.to_string(), *v))
+        .collect::<Vec<(String, usize)>>();
+
+    let mut old_stats_deduped = old_stats;
+    let mut new_stats_deduped = new_stats;
+
+    // remove duplicates from both hashmaps
+    for (k, v) in &same_in_both_hashmaps {
+        assert!(old_stats_deduped.remove(k) == Some(*v));
+        assert!(new_stats_deduped.remove(k) == Some(*v));
+    }
+
+    println!("\nStats:");
+
+    // list all new counts  (key is in new stats but not in old stats)
+    new_stats_deduped
+        .iter()
+        .filter(|(new_key, _)| !old_stats_deduped.contains_key::<str>(new_key))
+        .for_each(|(new_key, new_value)| {
+            println!("{new_key} 0 => {new_value}");
+        });
+
+    // list all changed counts (key is in both maps but value differs)
+    new_stats_deduped
+        .iter()
+        .filter(|(new_key, _new_val)| old_stats_deduped.contains_key::<str>(new_key))
+        .for_each(|(new_key, new_val)| {
+            let old_val = old_stats_deduped.get::<str>(new_key).unwrap();
+            println!("{new_key} {old_val} => {new_val}");
+        });
+
+    // list all gone counts (key is in old status but not in new stats)
+    old_stats_deduped
+        .iter()
+        .filter(|(old_key, _)| !new_stats_deduped.contains_key::<&String>(old_key))
+        .filter(|(old_key, _)| lint_filter.is_empty() || lint_filter.contains(old_key))
+        .for_each(|(old_key, old_value)| {
+            println!("{old_key} {old_value} => 0");
+        });
+}
diff --git a/src/tools/clippy/lintcheck/src/popular_crates.rs b/src/tools/clippy/lintcheck/src/popular_crates.rs
index 880a8bd81f0..ad8fc440c42 100644
--- a/src/tools/clippy/lintcheck/src/popular_crates.rs
+++ b/src/tools/clippy/lintcheck/src/popular_crates.rs
@@ -44,7 +44,7 @@ pub(crate) fn fetch(output: PathBuf, number: usize) -> Result<(), Box<dyn Error>
 
     let mut out = "[crates]\n".to_string();
     for Crate { name, max_version } in crates {
-        writeln!(out, "{name} = {{ name = '{name}', versions = ['{max_version}'] }}").unwrap();
+        writeln!(out, "{name} = {{ name = '{name}', version = '{max_version}' }}").unwrap();
     }
     fs::write(output, out)?;
 
diff --git a/src/tools/clippy/lintcheck/src/recursive.rs b/src/tools/clippy/lintcheck/src/recursive.rs
index 994fa3c3b23..373ca6f9918 100644
--- a/src/tools/clippy/lintcheck/src/recursive.rs
+++ b/src/tools/clippy/lintcheck/src/recursive.rs
@@ -3,7 +3,8 @@
 //! [`LintcheckServer`] to ask if it should be skipped, and if not sends the stderr of running
 //! clippy on the crate to the server
 
-use crate::{ClippyWarning, RecursiveOptions};
+use crate::input::RecursiveOptions;
+use crate::ClippyWarning;
 
 use std::collections::HashSet;
 use std::io::{BufRead, BufReader, Read, Write};
@@ -19,8 +20,6 @@ use serde::{Deserialize, Serialize};
 #[derive(Debug, Eq, Hash, PartialEq, Clone, Serialize, Deserialize)]
 pub(crate) struct DriverInfo {
     pub package_name: String,
-    pub crate_name: String,
-    pub version: String,
 }
 
 pub(crate) fn serialize_line<T, W>(value: &T, writer: &mut W)
@@ -65,7 +64,7 @@ fn process_stream(
     let messages = stderr
         .lines()
         .filter_map(|json_msg| serde_json::from_str::<Diagnostic>(json_msg).ok())
-        .filter_map(|diag| ClippyWarning::new(diag, &driver_info.package_name, &driver_info.version));
+        .filter_map(ClippyWarning::new);
 
     for message in messages {
         sender.send(message).unwrap();
diff --git a/src/tools/clippy/rust-toolchain b/src/tools/clippy/rust-toolchain
index 72b50d59f7e..a61c22c59f9 100644
--- a/src/tools/clippy/rust-toolchain
+++ b/src/tools/clippy/rust-toolchain
@@ -1,3 +1,4 @@
 [toolchain]
-channel = "nightly-2024-06-27"
+channel = "nightly-2024-07-11"
 components = ["cargo", "llvm-tools", "rust-src", "rust-std", "rustc", "rustc-dev", "rustfmt"]
+profile = "minimal"
diff --git a/src/tools/clippy/tests/ui-internal/disallow_span_lint.stderr b/src/tools/clippy/tests/ui-internal/disallow_span_lint.stderr
index 1be4b665bcb..66eda44f745 100644
--- a/src/tools/clippy/tests/ui-internal/disallow_span_lint.stderr
+++ b/src/tools/clippy/tests/ui-internal/disallow_span_lint.stderr
@@ -1,22 +1,18 @@
 error: use of a disallowed method `rustc_lint::context::LintContext::span_lint`
-  --> tests/ui-internal/disallow_span_lint.rs:14:5
+  --> tests/ui-internal/disallow_span_lint.rs:14:8
    |
-LL | /     cx.span_lint(lint, span, |lint| {
-LL | |         lint.primary_message(msg);
-LL | |     });
-   | |______^
+LL |     cx.span_lint(lint, span, |lint| {
+   |        ^^^^^^^^^
    |
    = note: this function does not add a link to our documentation, please use the `clippy_utils::diagnostics::span_lint*` functions instead (from clippy.toml)
    = note: `-D clippy::disallowed-methods` implied by `-D warnings`
    = help: to override `-D warnings` add `#[allow(clippy::disallowed_methods)]`
 
 error: use of a disallowed method `rustc_middle::ty::context::TyCtxt::node_span_lint`
-  --> tests/ui-internal/disallow_span_lint.rs:20:5
+  --> tests/ui-internal/disallow_span_lint.rs:20:9
    |
-LL | /     tcx.node_span_lint(lint, hir_id, span, |lint| {
-LL | |         lint.primary_message(msg);
-LL | |     });
-   | |______^
+LL |     tcx.node_span_lint(lint, hir_id, span, |lint| {
+   |         ^^^^^^^^^^^^^^
    |
    = note: this function does not add a link to our documentation, please use the `clippy_utils::diagnostics::span_lint_hir*` functions instead (from clippy.toml)
 
diff --git a/src/tools/clippy/tests/ui-toml/await_holding_invalid_type/await_holding_invalid_type.stderr b/src/tools/clippy/tests/ui-toml/await_holding_invalid_type/await_holding_invalid_type.stderr
index a74d8757e4a..016ee502c24 100644
--- a/src/tools/clippy/tests/ui-toml/await_holding_invalid_type/await_holding_invalid_type.stderr
+++ b/src/tools/clippy/tests/ui-toml/await_holding_invalid_type/await_holding_invalid_type.stderr
@@ -1,4 +1,4 @@
-error: `std::string::String` may not be held across an `await` point per `clippy.toml`
+error: `std::string::String` may not be held across an await point per `clippy.toml`
   --> tests/ui-toml/await_holding_invalid_type/await_holding_invalid_type.rs:5:9
    |
 LL |     let _x = String::from("hello");
@@ -8,13 +8,13 @@ LL |     let _x = String::from("hello");
    = note: `-D clippy::await-holding-invalid-type` implied by `-D warnings`
    = help: to override `-D warnings` add `#[allow(clippy::await_holding_invalid_type)]`
 
-error: `std::net::Ipv4Addr` may not be held across an `await` point per `clippy.toml`
+error: `std::net::Ipv4Addr` may not be held across an await point per `clippy.toml`
   --> tests/ui-toml/await_holding_invalid_type/await_holding_invalid_type.rs:10:9
    |
 LL |     let x = Ipv4Addr::new(127, 0, 0, 1);
    |         ^
 
-error: `std::string::String` may not be held across an `await` point per `clippy.toml`
+error: `std::string::String` may not be held across an await point per `clippy.toml`
   --> tests/ui-toml/await_holding_invalid_type/await_holding_invalid_type.rs:33:13
    |
 LL |         let _x = String::from("hi!");
diff --git a/src/tools/clippy/tests/ui-toml/needless_pass_by_ref_mut/clippy.toml b/src/tools/clippy/tests/ui-toml/needless_pass_by_ref_mut/clippy.toml
new file mode 100644
index 00000000000..cda8d17eed4
--- /dev/null
+++ b/src/tools/clippy/tests/ui-toml/needless_pass_by_ref_mut/clippy.toml
@@ -0,0 +1 @@
+avoid-breaking-exported-api = false
diff --git a/src/tools/clippy/tests/ui-toml/needless_pass_by_ref_mut/needless_pass_by_ref_mut.fixed b/src/tools/clippy/tests/ui-toml/needless_pass_by_ref_mut/needless_pass_by_ref_mut.fixed
new file mode 100644
index 00000000000..40556ca5410
--- /dev/null
+++ b/src/tools/clippy/tests/ui-toml/needless_pass_by_ref_mut/needless_pass_by_ref_mut.fixed
@@ -0,0 +1,10 @@
+#![warn(clippy::needless_pass_by_ref_mut)]
+#![allow(clippy::ptr_arg)]
+
+// Should warn
+pub fn pub_foo(s: &Vec<u32>, b: &u32, x: &mut u32) {
+    //~^ ERROR: this argument is a mutable reference, but not used mutably
+    *x += *b + s.len() as u32;
+}
+
+fn main() {}
diff --git a/src/tools/clippy/tests/ui-toml/needless_pass_by_ref_mut/needless_pass_by_ref_mut.rs b/src/tools/clippy/tests/ui-toml/needless_pass_by_ref_mut/needless_pass_by_ref_mut.rs
new file mode 100644
index 00000000000..bbc63ceb15a
--- /dev/null
+++ b/src/tools/clippy/tests/ui-toml/needless_pass_by_ref_mut/needless_pass_by_ref_mut.rs
@@ -0,0 +1,10 @@
+#![warn(clippy::needless_pass_by_ref_mut)]
+#![allow(clippy::ptr_arg)]
+
+// Should warn
+pub fn pub_foo(s: &mut Vec<u32>, b: &u32, x: &mut u32) {
+    //~^ ERROR: this argument is a mutable reference, but not used mutably
+    *x += *b + s.len() as u32;
+}
+
+fn main() {}
diff --git a/src/tools/clippy/tests/ui-toml/needless_pass_by_ref_mut/needless_pass_by_ref_mut.stderr b/src/tools/clippy/tests/ui-toml/needless_pass_by_ref_mut/needless_pass_by_ref_mut.stderr
new file mode 100644
index 00000000000..c10607bf4ba
--- /dev/null
+++ b/src/tools/clippy/tests/ui-toml/needless_pass_by_ref_mut/needless_pass_by_ref_mut.stderr
@@ -0,0 +1,12 @@
+error: this argument is a mutable reference, but not used mutably
+  --> tests/ui-toml/needless_pass_by_ref_mut/needless_pass_by_ref_mut.rs:5:19
+   |
+LL | pub fn pub_foo(s: &mut Vec<u32>, b: &u32, x: &mut u32) {
+   |                   ^^^^^^^^^^^^^ help: consider changing to: `&Vec<u32>`
+   |
+   = 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: aborting due to 1 previous error
+
diff --git a/src/tools/clippy/tests/ui-toml/toml_disallowed_methods/conf_disallowed_methods.stderr b/src/tools/clippy/tests/ui-toml/toml_disallowed_methods/conf_disallowed_methods.stderr
index 4afbbf5f807..f661e76cc74 100644
--- a/src/tools/clippy/tests/ui-toml/toml_disallowed_methods/conf_disallowed_methods.stderr
+++ b/src/tools/clippy/tests/ui-toml/toml_disallowed_methods/conf_disallowed_methods.stderr
@@ -2,36 +2,36 @@ error: use of a disallowed method `regex::Regex::new`
   --> tests/ui-toml/toml_disallowed_methods/conf_disallowed_methods.rs:35:14
    |
 LL |     let re = Regex::new(r"ab.*c").unwrap();
-   |              ^^^^^^^^^^^^^^^^^^^^
+   |              ^^^^^^^^^^
    |
    = note: `-D clippy::disallowed-methods` implied by `-D warnings`
    = help: to override `-D warnings` add `#[allow(clippy::disallowed_methods)]`
 
 error: use of a disallowed method `regex::Regex::is_match`
-  --> tests/ui-toml/toml_disallowed_methods/conf_disallowed_methods.rs:36:5
+  --> tests/ui-toml/toml_disallowed_methods/conf_disallowed_methods.rs:36:8
    |
 LL |     re.is_match("abc");
-   |     ^^^^^^^^^^^^^^^^^^
+   |        ^^^^^^^^
    |
    = note: no matching allowed (from clippy.toml)
 
 error: use of a disallowed method `std::iter::Iterator::sum`
-  --> tests/ui-toml/toml_disallowed_methods/conf_disallowed_methods.rs:39:5
+  --> tests/ui-toml/toml_disallowed_methods/conf_disallowed_methods.rs:39:14
    |
 LL |     a.iter().sum::<i32>();
-   |     ^^^^^^^^^^^^^^^^^^^^^
+   |              ^^^
 
 error: use of a disallowed method `slice::sort_unstable`
-  --> tests/ui-toml/toml_disallowed_methods/conf_disallowed_methods.rs:41:5
+  --> tests/ui-toml/toml_disallowed_methods/conf_disallowed_methods.rs:41:7
    |
 LL |     a.sort_unstable();
-   |     ^^^^^^^^^^^^^^^^^
+   |       ^^^^^^^^^^^^^
 
 error: use of a disallowed method `f32::clamp`
-  --> tests/ui-toml/toml_disallowed_methods/conf_disallowed_methods.rs:44:13
+  --> tests/ui-toml/toml_disallowed_methods/conf_disallowed_methods.rs:44:20
    |
 LL |     let _ = 2.0f32.clamp(3.0f32, 4.0f32);
-   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |                    ^^^^^
 
 error: use of a disallowed method `regex::Regex::new`
   --> tests/ui-toml/toml_disallowed_methods/conf_disallowed_methods.rs:47:61
@@ -55,37 +55,37 @@ error: use of a disallowed method `futures::stream::select_all`
   --> tests/ui-toml/toml_disallowed_methods/conf_disallowed_methods.rs:54:31
    |
 LL |     let same_name_as_module = select_all(vec![empty::<()>()]);
-   |                               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |                               ^^^^^^^^^^
 
 error: use of a disallowed method `conf_disallowed_methods::local_fn`
   --> tests/ui-toml/toml_disallowed_methods/conf_disallowed_methods.rs:56:5
    |
 LL |     local_fn();
-   |     ^^^^^^^^^^
+   |     ^^^^^^^^
 
 error: use of a disallowed method `conf_disallowed_methods::local_mod::f`
   --> tests/ui-toml/toml_disallowed_methods/conf_disallowed_methods.rs:57:5
    |
 LL |     local_mod::f();
-   |     ^^^^^^^^^^^^^^
+   |     ^^^^^^^^^^^^
 
 error: use of a disallowed method `conf_disallowed_methods::Struct::method`
-  --> tests/ui-toml/toml_disallowed_methods/conf_disallowed_methods.rs:59:5
+  --> tests/ui-toml/toml_disallowed_methods/conf_disallowed_methods.rs:59:7
    |
 LL |     s.method();
-   |     ^^^^^^^^^^
+   |       ^^^^^^
 
 error: use of a disallowed method `conf_disallowed_methods::Trait::provided_method`
-  --> tests/ui-toml/toml_disallowed_methods/conf_disallowed_methods.rs:60:5
+  --> tests/ui-toml/toml_disallowed_methods/conf_disallowed_methods.rs:60:7
    |
 LL |     s.provided_method();
-   |     ^^^^^^^^^^^^^^^^^^^
+   |       ^^^^^^^^^^^^^^^
 
 error: use of a disallowed method `conf_disallowed_methods::Trait::implemented_method`
-  --> tests/ui-toml/toml_disallowed_methods/conf_disallowed_methods.rs:61:5
+  --> tests/ui-toml/toml_disallowed_methods/conf_disallowed_methods.rs:61:7
    |
 LL |     s.implemented_method();
-   |     ^^^^^^^^^^^^^^^^^^^^^^
+   |       ^^^^^^^^^^^^^^^^^^
 
 error: aborting due to 14 previous errors
 
diff --git a/src/tools/clippy/tests/ui/assertions_on_constants.rs b/src/tools/clippy/tests/ui/assertions_on_constants.rs
index 1309ae45d0a..957154e60de 100644
--- a/src/tools/clippy/tests/ui/assertions_on_constants.rs
+++ b/src/tools/clippy/tests/ui/assertions_on_constants.rs
@@ -1,4 +1,4 @@
-#![allow(non_fmt_panics, clippy::needless_bool)]
+#![allow(non_fmt_panics, clippy::needless_bool, clippy::eq_op)]
 
 macro_rules! assert_const {
     ($len:expr) => {
@@ -49,7 +49,16 @@ fn main() {
     const _: () = assert!(true);
     //~^ ERROR: `assert!(true)` will be optimized out by the compiler
 
+    assert!(8 == (7 + 1));
+    //~^ ERROR: `assert!(true)` will be optimized out by the compiler
+
     // Don't lint if the value is dependent on a defined constant:
     const N: usize = 1024;
     const _: () = assert!(N.is_power_of_two());
 }
+
+const _: () = {
+    assert!(true);
+    //~^ ERROR: `assert!(true)` will be optimized out by the compiler
+    assert!(8 == (7 + 1));
+};
diff --git a/src/tools/clippy/tests/ui/assertions_on_constants.stderr b/src/tools/clippy/tests/ui/assertions_on_constants.stderr
index 00f117c9492..e164a999c43 100644
--- a/src/tools/clippy/tests/ui/assertions_on_constants.stderr
+++ b/src/tools/clippy/tests/ui/assertions_on_constants.stderr
@@ -80,5 +80,21 @@ LL |     const _: () = assert!(true);
    |
    = help: remove it
 
-error: aborting due to 10 previous errors
+error: `assert!(true)` will be optimized out by the compiler
+  --> tests/ui/assertions_on_constants.rs:52:5
+   |
+LL |     assert!(8 == (7 + 1));
+   |     ^^^^^^^^^^^^^^^^^^^^^
+   |
+   = help: remove it
+
+error: `assert!(true)` will be optimized out by the compiler
+  --> tests/ui/assertions_on_constants.rs:61:5
+   |
+LL |     assert!(true);
+   |     ^^^^^^^^^^^^^
+   |
+   = help: remove it
+
+error: aborting due to 12 previous errors
 
diff --git a/src/tools/clippy/tests/ui/await_holding_lock.rs b/src/tools/clippy/tests/ui/await_holding_lock.rs
index 8e5510e6cd0..cecf00c934f 100644
--- a/src/tools/clippy/tests/ui/await_holding_lock.rs
+++ b/src/tools/clippy/tests/ui/await_holding_lock.rs
@@ -8,7 +8,7 @@ mod std_mutex {
 
     pub async fn bad(x: &Mutex<u32>) -> u32 {
         let guard = x.lock().unwrap();
-        //~^ ERROR: this `MutexGuard` is held across an `await` point
+        //~^ ERROR: this `MutexGuard` is held across an await point
         baz().await
     }
 
@@ -24,13 +24,13 @@ mod std_mutex {
 
     pub async fn bad_rw(x: &RwLock<u32>) -> u32 {
         let guard = x.read().unwrap();
-        //~^ ERROR: this `MutexGuard` is held across an `await` point
+        //~^ ERROR: this `MutexGuard` is held across an await point
         baz().await
     }
 
     pub async fn bad_rw_write(x: &RwLock<u32>) -> u32 {
         let mut guard = x.write().unwrap();
-        //~^ ERROR: this `MutexGuard` is held across an `await` point
+        //~^ ERROR: this `MutexGuard` is held across an await point
         baz().await
     }
 
@@ -52,7 +52,7 @@ mod std_mutex {
         let first = baz().await;
 
         let guard = x.lock().unwrap();
-        //~^ ERROR: this `MutexGuard` is held across an `await` point
+        //~^ ERROR: this `MutexGuard` is held across an await point
 
         let second = baz().await;
 
@@ -66,7 +66,7 @@ mod std_mutex {
 
         let second = {
             let guard = x.lock().unwrap();
-            //~^ ERROR: this `MutexGuard` is held across an `await` point
+            //~^ ERROR: this `MutexGuard` is held across an await point
             baz().await
         };
 
@@ -79,7 +79,7 @@ mod std_mutex {
     pub fn block_bad(x: &Mutex<u32>) -> impl std::future::Future<Output = u32> + '_ {
         async move {
             let guard = x.lock().unwrap();
-            //~^ ERROR: this `MutexGuard` is held across an `await` point
+            //~^ ERROR: this `MutexGuard` is held across an await point
             baz().await
         }
     }
@@ -92,7 +92,7 @@ mod parking_lot_mutex {
 
     pub async fn bad(x: &Mutex<u32>) -> u32 {
         let guard = x.lock();
-        //~^ ERROR: this `MutexGuard` is held across an `await` point
+        //~^ ERROR: this `MutexGuard` is held across an await point
         baz().await
     }
 
@@ -108,13 +108,13 @@ mod parking_lot_mutex {
 
     pub async fn bad_rw(x: &RwLock<u32>) -> u32 {
         let guard = x.read();
-        //~^ ERROR: this `MutexGuard` is held across an `await` point
+        //~^ ERROR: this `MutexGuard` is held across an await point
         baz().await
     }
 
     pub async fn bad_rw_write(x: &RwLock<u32>) -> u32 {
         let mut guard = x.write();
-        //~^ ERROR: this `MutexGuard` is held across an `await` point
+        //~^ ERROR: this `MutexGuard` is held across an await point
         baz().await
     }
 
@@ -136,7 +136,7 @@ mod parking_lot_mutex {
         let first = baz().await;
 
         let guard = x.lock();
-        //~^ ERROR: this `MutexGuard` is held across an `await` point
+        //~^ ERROR: this `MutexGuard` is held across an await point
 
         let second = baz().await;
 
@@ -150,7 +150,7 @@ mod parking_lot_mutex {
 
         let second = {
             let guard = x.lock();
-            //~^ ERROR: this `MutexGuard` is held across an `await` point
+            //~^ ERROR: this `MutexGuard` is held across an await point
             baz().await
         };
 
@@ -163,7 +163,7 @@ mod parking_lot_mutex {
     pub fn block_bad(x: &Mutex<u32>) -> impl std::future::Future<Output = u32> + '_ {
         async move {
             let guard = x.lock();
-            //~^ ERROR: this `MutexGuard` is held across an `await` point
+            //~^ ERROR: this `MutexGuard` is held across an await point
             baz().await
         }
     }
@@ -184,7 +184,7 @@ async fn no_await(x: std::sync::Mutex<u32>) {
 // `*guard += 1` is removed it is picked up.
 async fn dropped_before_await(x: std::sync::Mutex<u32>) {
     let mut guard = x.lock().unwrap();
-    //~^ ERROR: this `MutexGuard` is held across an `await` point
+    //~^ ERROR: this `MutexGuard` is held across an await point
     *guard += 1;
     drop(guard);
     baz().await;
diff --git a/src/tools/clippy/tests/ui/await_holding_lock.stderr b/src/tools/clippy/tests/ui/await_holding_lock.stderr
index 0af48a36acc..af61d893948 100644
--- a/src/tools/clippy/tests/ui/await_holding_lock.stderr
+++ b/src/tools/clippy/tests/ui/await_holding_lock.stderr
@@ -1,11 +1,11 @@
-error: this `MutexGuard` is held across an `await` point
+error: this `MutexGuard` is held across an await point
   --> tests/ui/await_holding_lock.rs:10:13
    |
 LL |         let guard = x.lock().unwrap();
    |             ^^^^^
    |
-   = help: consider using an async-aware `Mutex` type or ensuring the `MutexGuard` is dropped before calling await
-note: these are all the `await` points this lock is held through
+   = help: consider using an async-aware `Mutex` type or ensuring the `MutexGuard` is dropped before calling `await`
+note: these are all the await points this lock is held through
   --> tests/ui/await_holding_lock.rs:12:15
    |
 LL |         baz().await
@@ -13,40 +13,40 @@ LL |         baz().await
    = note: `-D clippy::await-holding-lock` implied by `-D warnings`
    = help: to override `-D warnings` add `#[allow(clippy::await_holding_lock)]`
 
-error: this `MutexGuard` is held across an `await` point
+error: this `MutexGuard` is held across an await point
   --> tests/ui/await_holding_lock.rs:26:13
    |
 LL |         let guard = x.read().unwrap();
    |             ^^^^^
    |
-   = help: consider using an async-aware `Mutex` type or ensuring the `MutexGuard` is dropped before calling await
-note: these are all the `await` points this lock is held through
+   = help: consider using an async-aware `Mutex` type or ensuring the `MutexGuard` is dropped before calling `await`
+note: these are all the await points this lock is held through
   --> tests/ui/await_holding_lock.rs:28:15
    |
 LL |         baz().await
    |               ^^^^^
 
-error: this `MutexGuard` is held across an `await` point
+error: this `MutexGuard` is held across an await point
   --> tests/ui/await_holding_lock.rs:32:13
    |
 LL |         let mut guard = x.write().unwrap();
    |             ^^^^^^^^^
    |
-   = help: consider using an async-aware `Mutex` type or ensuring the `MutexGuard` is dropped before calling await
-note: these are all the `await` points this lock is held through
+   = help: consider using an async-aware `Mutex` type or ensuring the `MutexGuard` is dropped before calling `await`
+note: these are all the await points this lock is held through
   --> tests/ui/await_holding_lock.rs:34:15
    |
 LL |         baz().await
    |               ^^^^^
 
-error: this `MutexGuard` is held across an `await` point
+error: this `MutexGuard` is held across an await point
   --> tests/ui/await_holding_lock.rs:54:13
    |
 LL |         let guard = x.lock().unwrap();
    |             ^^^^^
    |
-   = help: consider using an async-aware `Mutex` type or ensuring the `MutexGuard` is dropped before calling await
-note: these are all the `await` points this lock is held through
+   = help: consider using an async-aware `Mutex` type or ensuring the `MutexGuard` is dropped before calling `await`
+note: these are all the await points this lock is held through
   --> tests/ui/await_holding_lock.rs:57:28
    |
 LL |         let second = baz().await;
@@ -55,79 +55,79 @@ LL |
 LL |         let third = baz().await;
    |                           ^^^^^
 
-error: this `MutexGuard` is held across an `await` point
+error: this `MutexGuard` is held across an await point
   --> tests/ui/await_holding_lock.rs:68:17
    |
 LL |             let guard = x.lock().unwrap();
    |                 ^^^^^
    |
-   = help: consider using an async-aware `Mutex` type or ensuring the `MutexGuard` is dropped before calling await
-note: these are all the `await` points this lock is held through
+   = help: consider using an async-aware `Mutex` type or ensuring the `MutexGuard` is dropped before calling `await`
+note: these are all the await points this lock is held through
   --> tests/ui/await_holding_lock.rs:70:19
    |
 LL |             baz().await
    |                   ^^^^^
 
-error: this `MutexGuard` is held across an `await` point
+error: this `MutexGuard` is held across an await point
   --> tests/ui/await_holding_lock.rs:81:17
    |
 LL |             let guard = x.lock().unwrap();
    |                 ^^^^^
    |
-   = help: consider using an async-aware `Mutex` type or ensuring the `MutexGuard` is dropped before calling await
-note: these are all the `await` points this lock is held through
+   = help: consider using an async-aware `Mutex` type or ensuring the `MutexGuard` is dropped before calling `await`
+note: these are all the await points this lock is held through
   --> tests/ui/await_holding_lock.rs:83:19
    |
 LL |             baz().await
    |                   ^^^^^
 
-error: this `MutexGuard` is held across an `await` point
+error: this `MutexGuard` is held across an await point
   --> tests/ui/await_holding_lock.rs:94:13
    |
 LL |         let guard = x.lock();
    |             ^^^^^
    |
-   = help: consider using an async-aware `Mutex` type or ensuring the `MutexGuard` is dropped before calling await
-note: these are all the `await` points this lock is held through
+   = help: consider using an async-aware `Mutex` type or ensuring the `MutexGuard` is dropped before calling `await`
+note: these are all the await points this lock is held through
   --> tests/ui/await_holding_lock.rs:96:15
    |
 LL |         baz().await
    |               ^^^^^
 
-error: this `MutexGuard` is held across an `await` point
+error: this `MutexGuard` is held across an await point
   --> tests/ui/await_holding_lock.rs:110:13
    |
 LL |         let guard = x.read();
    |             ^^^^^
    |
-   = help: consider using an async-aware `Mutex` type or ensuring the `MutexGuard` is dropped before calling await
-note: these are all the `await` points this lock is held through
+   = help: consider using an async-aware `Mutex` type or ensuring the `MutexGuard` is dropped before calling `await`
+note: these are all the await points this lock is held through
   --> tests/ui/await_holding_lock.rs:112:15
    |
 LL |         baz().await
    |               ^^^^^
 
-error: this `MutexGuard` is held across an `await` point
+error: this `MutexGuard` is held across an await point
   --> tests/ui/await_holding_lock.rs:116:13
    |
 LL |         let mut guard = x.write();
    |             ^^^^^^^^^
    |
-   = help: consider using an async-aware `Mutex` type or ensuring the `MutexGuard` is dropped before calling await
-note: these are all the `await` points this lock is held through
+   = help: consider using an async-aware `Mutex` type or ensuring the `MutexGuard` is dropped before calling `await`
+note: these are all the await points this lock is held through
   --> tests/ui/await_holding_lock.rs:118:15
    |
 LL |         baz().await
    |               ^^^^^
 
-error: this `MutexGuard` is held across an `await` point
+error: this `MutexGuard` is held across an await point
   --> tests/ui/await_holding_lock.rs:138:13
    |
 LL |         let guard = x.lock();
    |             ^^^^^
    |
-   = help: consider using an async-aware `Mutex` type or ensuring the `MutexGuard` is dropped before calling await
-note: these are all the `await` points this lock is held through
+   = help: consider using an async-aware `Mutex` type or ensuring the `MutexGuard` is dropped before calling `await`
+note: these are all the await points this lock is held through
   --> tests/ui/await_holding_lock.rs:141:28
    |
 LL |         let second = baz().await;
@@ -136,40 +136,40 @@ LL |
 LL |         let third = baz().await;
    |                           ^^^^^
 
-error: this `MutexGuard` is held across an `await` point
+error: this `MutexGuard` is held across an await point
   --> tests/ui/await_holding_lock.rs:152:17
    |
 LL |             let guard = x.lock();
    |                 ^^^^^
    |
-   = help: consider using an async-aware `Mutex` type or ensuring the `MutexGuard` is dropped before calling await
-note: these are all the `await` points this lock is held through
+   = help: consider using an async-aware `Mutex` type or ensuring the `MutexGuard` is dropped before calling `await`
+note: these are all the await points this lock is held through
   --> tests/ui/await_holding_lock.rs:154:19
    |
 LL |             baz().await
    |                   ^^^^^
 
-error: this `MutexGuard` is held across an `await` point
+error: this `MutexGuard` is held across an await point
   --> tests/ui/await_holding_lock.rs:165:17
    |
 LL |             let guard = x.lock();
    |                 ^^^^^
    |
-   = help: consider using an async-aware `Mutex` type or ensuring the `MutexGuard` is dropped before calling await
-note: these are all the `await` points this lock is held through
+   = help: consider using an async-aware `Mutex` type or ensuring the `MutexGuard` is dropped before calling `await`
+note: these are all the await points this lock is held through
   --> tests/ui/await_holding_lock.rs:167:19
    |
 LL |             baz().await
    |                   ^^^^^
 
-error: this `MutexGuard` is held across an `await` point
+error: this `MutexGuard` is held across an await point
   --> tests/ui/await_holding_lock.rs:186:9
    |
 LL |     let mut guard = x.lock().unwrap();
    |         ^^^^^^^^^
    |
-   = help: consider using an async-aware `Mutex` type or ensuring the `MutexGuard` is dropped before calling await
-note: these are all the `await` points this lock is held through
+   = help: consider using an async-aware `Mutex` type or ensuring the `MutexGuard` is dropped before calling `await`
+note: these are all the await points this lock is held through
   --> tests/ui/await_holding_lock.rs:190:11
    |
 LL |     baz().await;
diff --git a/src/tools/clippy/tests/ui/await_holding_refcell_ref.rs b/src/tools/clippy/tests/ui/await_holding_refcell_ref.rs
index 5bd26c62836..b0c92d8c1f6 100644
--- a/src/tools/clippy/tests/ui/await_holding_refcell_ref.rs
+++ b/src/tools/clippy/tests/ui/await_holding_refcell_ref.rs
@@ -4,13 +4,13 @@ use std::cell::RefCell;
 
 async fn bad(x: &RefCell<u32>) -> u32 {
     let b = x.borrow();
-    //~^ ERROR: this `RefCell` reference is held across an `await` point
+    //~^ ERROR: this `RefCell` reference is held across an await point
     baz().await
 }
 
 async fn bad_mut(x: &RefCell<u32>) -> u32 {
     let b = x.borrow_mut();
-    //~^ ERROR: this `RefCell` reference is held across an `await` point
+    //~^ ERROR: this `RefCell` reference is held across an await point
     baz().await
 }
 
@@ -32,7 +32,7 @@ async fn also_bad(x: &RefCell<u32>) -> u32 {
     let first = baz().await;
 
     let b = x.borrow_mut();
-    //~^ ERROR: this `RefCell` reference is held across an `await` point
+    //~^ ERROR: this `RefCell` reference is held across an await point
 
     let second = baz().await;
 
@@ -45,7 +45,7 @@ async fn less_bad(x: &RefCell<u32>) -> u32 {
     let first = baz().await;
 
     let b = x.borrow_mut();
-    //~^ ERROR: this `RefCell` reference is held across an `await` point
+    //~^ ERROR: this `RefCell` reference is held across an await point
 
     let second = baz().await;
 
@@ -61,7 +61,7 @@ async fn not_good(x: &RefCell<u32>) -> u32 {
 
     let second = {
         let b = x.borrow_mut();
-        //~^ ERROR: this `RefCell` reference is held across an `await` point
+        //~^ ERROR: this `RefCell` reference is held across an await point
         baz().await
     };
 
@@ -74,7 +74,7 @@ async fn not_good(x: &RefCell<u32>) -> u32 {
 fn block_bad(x: &RefCell<u32>) -> impl std::future::Future<Output = u32> + '_ {
     async move {
         let b = x.borrow_mut();
-        //~^ ERROR: this `RefCell` reference is held across an `await` point
+        //~^ ERROR: this `RefCell` reference is held across an await point
         baz().await
     }
 }
diff --git a/src/tools/clippy/tests/ui/await_holding_refcell_ref.stderr b/src/tools/clippy/tests/ui/await_holding_refcell_ref.stderr
index 6b474c27ddc..6c7209c9ff9 100644
--- a/src/tools/clippy/tests/ui/await_holding_refcell_ref.stderr
+++ b/src/tools/clippy/tests/ui/await_holding_refcell_ref.stderr
@@ -1,11 +1,11 @@
-error: this `RefCell` reference is held across an `await` point
+error: this `RefCell` reference is held across an await point
   --> tests/ui/await_holding_refcell_ref.rs:6:9
    |
 LL |     let b = x.borrow();
    |         ^
    |
    = help: ensure the reference is dropped before calling `await`
-note: these are all the `await` points this reference is held through
+note: these are all the await points this reference is held through
   --> tests/ui/await_holding_refcell_ref.rs:8:11
    |
 LL |     baz().await
@@ -13,27 +13,27 @@ LL |     baz().await
    = note: `-D clippy::await-holding-refcell-ref` implied by `-D warnings`
    = help: to override `-D warnings` add `#[allow(clippy::await_holding_refcell_ref)]`
 
-error: this `RefCell` reference is held across an `await` point
+error: this `RefCell` reference is held across an await point
   --> tests/ui/await_holding_refcell_ref.rs:12:9
    |
 LL |     let b = x.borrow_mut();
    |         ^
    |
    = help: ensure the reference is dropped before calling `await`
-note: these are all the `await` points this reference is held through
+note: these are all the await points this reference is held through
   --> tests/ui/await_holding_refcell_ref.rs:14:11
    |
 LL |     baz().await
    |           ^^^^^
 
-error: this `RefCell` reference is held across an `await` point
+error: this `RefCell` reference is held across an await point
   --> tests/ui/await_holding_refcell_ref.rs:34:9
    |
 LL |     let b = x.borrow_mut();
    |         ^
    |
    = help: ensure the reference is dropped before calling `await`
-note: these are all the `await` points this reference is held through
+note: these are all the await points this reference is held through
   --> tests/ui/await_holding_refcell_ref.rs:37:24
    |
 LL |     let second = baz().await;
@@ -42,40 +42,40 @@ LL |
 LL |     let third = baz().await;
    |                       ^^^^^
 
-error: this `RefCell` reference is held across an `await` point
+error: this `RefCell` reference is held across an await point
   --> tests/ui/await_holding_refcell_ref.rs:47:9
    |
 LL |     let b = x.borrow_mut();
    |         ^
    |
    = help: ensure the reference is dropped before calling `await`
-note: these are all the `await` points this reference is held through
+note: these are all the await points this reference is held through
   --> tests/ui/await_holding_refcell_ref.rs:50:24
    |
 LL |     let second = baz().await;
    |                        ^^^^^
 
-error: this `RefCell` reference is held across an `await` point
+error: this `RefCell` reference is held across an await point
   --> tests/ui/await_holding_refcell_ref.rs:63:13
    |
 LL |         let b = x.borrow_mut();
    |             ^
    |
    = help: ensure the reference is dropped before calling `await`
-note: these are all the `await` points this reference is held through
+note: these are all the await points this reference is held through
   --> tests/ui/await_holding_refcell_ref.rs:65:15
    |
 LL |         baz().await
    |               ^^^^^
 
-error: this `RefCell` reference is held across an `await` point
+error: this `RefCell` reference is held across an await point
   --> tests/ui/await_holding_refcell_ref.rs:76:13
    |
 LL |         let b = x.borrow_mut();
    |             ^
    |
    = help: ensure the reference is dropped before calling `await`
-note: these are all the `await` points this reference is held through
+note: these are all the await points this reference is held through
   --> tests/ui/await_holding_refcell_ref.rs:78:15
    |
 LL |         baz().await
diff --git a/src/tools/clippy/tests/ui/byte_char_slices.fixed b/src/tools/clippy/tests/ui/byte_char_slices.fixed
new file mode 100644
index 00000000000..d1db58f9363
--- /dev/null
+++ b/src/tools/clippy/tests/ui/byte_char_slices.fixed
@@ -0,0 +1,13 @@
+#![allow(unused)]
+#![warn(clippy::byte_char_slices)]
+
+fn main() {
+    let bad = b"abc";
+    let quotes = b"\"Hi";
+    let quotes = b"'Sup";
+    let escapes = b"\x42Esc";
+
+    let good = &[b'a', 0x42];
+    let good = [b'a', b'a'];
+    let good: u8 = [b'a', b'c'].into_iter().sum();
+}
diff --git a/src/tools/clippy/tests/ui/byte_char_slices.rs b/src/tools/clippy/tests/ui/byte_char_slices.rs
new file mode 100644
index 00000000000..18648fffceb
--- /dev/null
+++ b/src/tools/clippy/tests/ui/byte_char_slices.rs
@@ -0,0 +1,13 @@
+#![allow(unused)]
+#![warn(clippy::byte_char_slices)]
+
+fn main() {
+    let bad = &[b'a', b'b', b'c'];
+    let quotes = &[b'"', b'H', b'i'];
+    let quotes = &[b'\'', b'S', b'u', b'p'];
+    let escapes = &[b'\x42', b'E', b's', b'c'];
+
+    let good = &[b'a', 0x42];
+    let good = vec![b'a', b'a'];
+    let good: u8 = [b'a', b'c'].into_iter().sum();
+}
diff --git a/src/tools/clippy/tests/ui/byte_char_slices.stderr b/src/tools/clippy/tests/ui/byte_char_slices.stderr
new file mode 100644
index 00000000000..4e2b5d8a732
--- /dev/null
+++ b/src/tools/clippy/tests/ui/byte_char_slices.stderr
@@ -0,0 +1,38 @@
+error: can be more succinctly written as a byte str
+  --> tests/ui/byte_char_slices.rs:5:15
+   |
+LL |     let bad = &[b'a', b'b', b'c'];
+   |               ^^^^^^^^^^^^^^^^^^^ help: try: `b"abc"`
+   |
+   = note: `-D clippy::byte-char-slices` implied by `-D warnings`
+   = help: to override `-D warnings` add `#[allow(clippy::byte_char_slices)]`
+
+error: can be more succinctly written as a byte str
+  --> tests/ui/byte_char_slices.rs:6:18
+   |
+LL |     let quotes = &[b'"', b'H', b'i'];
+   |                  ^^^^^^^^^^^^^^^^^^^ help: try: `b"\"Hi"`
+
+error: can be more succinctly written as a byte str
+  --> tests/ui/byte_char_slices.rs:7:18
+   |
+LL |     let quotes = &[b'\'', b'S', b'u', b'p'];
+   |                  ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `b"'Sup"`
+
+error: can be more succinctly written as a byte str
+  --> tests/ui/byte_char_slices.rs:8:19
+   |
+LL |     let escapes = &[b'\x42', b'E', b's', b'c'];
+   |                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `b"\x42Esc"`
+
+error: useless use of `vec!`
+  --> tests/ui/byte_char_slices.rs:11:16
+   |
+LL |     let good = vec![b'a', b'a'];
+   |                ^^^^^^^^^^^^^^^^ help: you can use an array directly: `[b'a', b'a']`
+   |
+   = note: `-D clippy::useless-vec` implied by `-D warnings`
+   = help: to override `-D warnings` add `#[allow(clippy::useless_vec)]`
+
+error: aborting due to 5 previous errors
+
diff --git a/src/tools/clippy/tests/ui/cfg_not_test.rs b/src/tools/clippy/tests/ui/cfg_not_test.rs
new file mode 100644
index 00000000000..da3e29d2896
--- /dev/null
+++ b/src/tools/clippy/tests/ui/cfg_not_test.rs
@@ -0,0 +1,32 @@
+#![allow(unused)]
+#![warn(clippy::cfg_not_test)]
+
+fn important_check() {}
+
+fn main() {
+    // Statement
+    #[cfg(not(test))]
+    let answer = 42;
+
+    // Expression
+    #[cfg(not(test))]
+    important_check();
+
+    // Make sure only not(test) are checked, not other attributes
+    #[cfg(not(foo))]
+    important_check();
+}
+
+#[cfg(not(not(test)))]
+struct CfgNotTest;
+
+// Deeply nested `not(test)`
+#[cfg(not(test))]
+fn foo() {}
+#[cfg(all(debug_assertions, not(test)))]
+fn bar() {}
+#[cfg(not(any(not(debug_assertions), test)))]
+fn baz() {}
+
+#[cfg(test)]
+mod tests {}
diff --git a/src/tools/clippy/tests/ui/cfg_not_test.stderr b/src/tools/clippy/tests/ui/cfg_not_test.stderr
new file mode 100644
index 00000000000..c1bf626887a
--- /dev/null
+++ b/src/tools/clippy/tests/ui/cfg_not_test.stderr
@@ -0,0 +1,45 @@
+error: code is excluded from test builds
+  --> tests/ui/cfg_not_test.rs:8:5
+   |
+LL |     #[cfg(not(test))]
+   |     ^^^^^^^^^^^^^^^^^
+   |
+   = help: consider not excluding any code from test builds
+   = note: this could increase code coverage despite not actually being tested
+   = note: `-D clippy::cfg-not-test` implied by `-D warnings`
+   = help: to override `-D warnings` add `#[allow(clippy::cfg_not_test)]`
+
+error: code is excluded from test builds
+  --> tests/ui/cfg_not_test.rs:12:5
+   |
+LL |     #[cfg(not(test))]
+   |     ^^^^^^^^^^^^^^^^^
+   |
+   = help: consider not excluding any code from test builds
+
+error: code is excluded from test builds
+  --> tests/ui/cfg_not_test.rs:24:1
+   |
+LL | #[cfg(not(test))]
+   | ^^^^^^^^^^^^^^^^^
+   |
+   = help: consider not excluding any code from test builds
+
+error: code is excluded from test builds
+  --> tests/ui/cfg_not_test.rs:26:1
+   |
+LL | #[cfg(all(debug_assertions, not(test)))]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = help: consider not excluding any code from test builds
+
+error: code is excluded from test builds
+  --> tests/ui/cfg_not_test.rs:28:1
+   |
+LL | #[cfg(not(any(not(debug_assertions), test)))]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = help: consider not excluding any code from test builds
+
+error: aborting due to 5 previous errors
+
diff --git a/src/tools/clippy/tests/ui/crashes/ice-12616.stderr b/src/tools/clippy/tests/ui/crashes/ice-12616.stderr
index c7cf5cf5483..a84a945a429 100644
--- a/src/tools/clippy/tests/ui/crashes/ice-12616.stderr
+++ b/src/tools/clippy/tests/ui/crashes/ice-12616.stderr
@@ -1,4 +1,4 @@
-error: `as` casting between raw pointers without changing its mutability
+error: `as` casting between raw pointers without changing their constness
   --> tests/ui/crashes/ice-12616.rs:6:5
    |
 LL |     s() as *const ();
diff --git a/src/tools/clippy/tests/ui/disallowed_names.rs b/src/tools/clippy/tests/ui/disallowed_names.rs
index 13c883409bf..96531bf8d88 100644
--- a/src/tools/clippy/tests/ui/disallowed_names.rs
+++ b/src/tools/clippy/tests/ui/disallowed_names.rs
@@ -60,6 +60,7 @@ fn issue_1647_ref_mut() {
     //~^ ERROR: use of a disallowed/placeholder name `quux`
 }
 
+#[cfg(test)]
 mod tests {
     fn issue_7305() {
         // `disallowed_names` lint should not be triggered inside of the test code.
diff --git a/src/tools/clippy/tests/ui/doc/doc_lazy_blank_line.fixed b/src/tools/clippy/tests/ui/doc/doc_lazy_blank_line.fixed
new file mode 100644
index 00000000000..1aaa26afe7f
--- /dev/null
+++ b/src/tools/clippy/tests/ui/doc/doc_lazy_blank_line.fixed
@@ -0,0 +1,47 @@
+// https://github.com/rust-lang/rust-clippy/issues/12917
+#![warn(clippy::doc_lazy_continuation)]
+
+/// This is a constant.
+///
+/// The meaning of which should not be explained.
+pub const A: i32 = 42;
+
+/// This is another constant, no longer used.
+///
+/// This block of documentation has a long
+/// explanation and derivation to explain
+/// why it is what it is, and how it's used.
+///
+/// It is left here for historical reasons, and
+/// for reference.
+///
+/// Reasons it's great:
+///  - First reason
+///  - Second reason
+///
+//pub const B: i32 = 1337;
+
+/// This is yet another constant.
+///
+/// This has a similar fate as `B`.
+///
+/// Reasons it's useful:
+///  1. First reason
+///  2. Second reason
+///
+//pub const C: i32 = 8008;
+
+/// This is still in use.
+pub const D: i32 = 20;
+
+/// > blockquote code path
+///
+
+/// bottom text
+pub const E: i32 = 20;
+
+/// > blockquote code path
+///
+#[repr(C)]
+/// bottom text
+pub struct Foo(i32);
diff --git a/src/tools/clippy/tests/ui/doc/doc_lazy_blank_line.rs b/src/tools/clippy/tests/ui/doc/doc_lazy_blank_line.rs
new file mode 100644
index 00000000000..e1ab8fc8389
--- /dev/null
+++ b/src/tools/clippy/tests/ui/doc/doc_lazy_blank_line.rs
@@ -0,0 +1,43 @@
+// https://github.com/rust-lang/rust-clippy/issues/12917
+#![warn(clippy::doc_lazy_continuation)]
+
+/// This is a constant.
+///
+/// The meaning of which should not be explained.
+pub const A: i32 = 42;
+
+/// This is another constant, no longer used.
+///
+/// This block of documentation has a long
+/// explanation and derivation to explain
+/// why it is what it is, and how it's used.
+///
+/// It is left here for historical reasons, and
+/// for reference.
+///
+/// Reasons it's great:
+///  - First reason
+///  - Second reason
+//pub const B: i32 = 1337;
+
+/// This is yet another constant.
+///
+/// This has a similar fate as `B`.
+///
+/// Reasons it's useful:
+///  1. First reason
+///  2. Second reason
+//pub const C: i32 = 8008;
+
+/// This is still in use.
+pub const D: i32 = 20;
+
+/// > blockquote code path
+
+/// bottom text
+pub const E: i32 = 20;
+
+/// > blockquote code path
+#[repr(C)]
+/// bottom text
+pub struct Foo(i32);
diff --git a/src/tools/clippy/tests/ui/doc/doc_lazy_blank_line.stderr b/src/tools/clippy/tests/ui/doc/doc_lazy_blank_line.stderr
new file mode 100644
index 00000000000..854906a7474
--- /dev/null
+++ b/src/tools/clippy/tests/ui/doc/doc_lazy_blank_line.stderr
@@ -0,0 +1,56 @@
+error: doc list item without indentation
+  --> tests/ui/doc/doc_lazy_blank_line.rs:23:5
+   |
+LL | /// This is yet another constant.
+   |     ^
+   |
+   = help: if this is intended to be part of the list, indent 3 spaces
+   = note: `-D clippy::doc-lazy-continuation` implied by `-D warnings`
+   = help: to override `-D warnings` add `#[allow(clippy::doc_lazy_continuation)]`
+help: if this should be its own paragraph, add a blank doc comment line
+   |
+LL ~ ///  - Second reason
+LL + ///
+   |
+
+error: doc list item without indentation
+  --> tests/ui/doc/doc_lazy_blank_line.rs:32:5
+   |
+LL | /// This is still in use.
+   |     ^
+   |
+   = help: if this is intended to be part of the list, indent 4 spaces
+help: if this should be its own paragraph, add a blank doc comment line
+   |
+LL ~ ///  2. Second reason
+LL + ///
+   |
+
+error: doc quote line without `>` marker
+  --> tests/ui/doc/doc_lazy_blank_line.rs:37:5
+   |
+LL | /// bottom text
+   |     ^
+   |
+   = help: if this not intended to be a quote at all, escape it with `\>`
+help: if this should be its own paragraph, add a blank doc comment line
+   |
+LL ~ /// > blockquote code path
+LL + ///
+   |
+
+error: doc quote line without `>` marker
+  --> tests/ui/doc/doc_lazy_blank_line.rs:42:5
+   |
+LL | /// bottom text
+   |     ^
+   |
+   = help: if this not intended to be a quote at all, escape it with `\>`
+help: if this should be its own paragraph, add a blank doc comment line
+   |
+LL ~ /// > blockquote code path
+LL + ///
+   |
+
+error: aborting due to 4 previous errors
+
diff --git a/src/tools/clippy/tests/ui/doc/doc_lazy_blockquote.fixed b/src/tools/clippy/tests/ui/doc/doc_lazy_blockquote.fixed
index 9877991f183..9d6e8637608 100644
--- a/src/tools/clippy/tests/ui/doc/doc_lazy_blockquote.fixed
+++ b/src/tools/clippy/tests/ui/doc/doc_lazy_blockquote.fixed
@@ -2,7 +2,7 @@
 
 /// > blockquote with
 /// > lazy continuation
-//~^ ERROR: doc quote missing `>` marker
+//~^ ERROR: doc quote line without `>` marker
 fn first() {}
 
 /// > blockquote with no
@@ -18,24 +18,24 @@ fn two_nowarn() {}
 /// >
 /// > > nest here
 /// > > lazy continuation
-//~^ ERROR: doc quote missing `>` marker
+//~^ ERROR: doc quote line without `>` marker
 fn two() {}
 
 /// > nest here
 /// >
 /// > > nest here
 /// > > lazy continuation
-//~^ ERROR: doc quote missing `>` marker
+//~^ ERROR: doc quote line without `>` marker
 fn three() {}
 
 /// >   * > nest here
 /// >     > lazy continuation
-//~^ ERROR: doc quote missing `>` marker
+//~^ ERROR: doc quote line without `>` marker
 fn four() {}
 
 /// > * > nest here
 /// >   > lazy continuation
-//~^ ERROR: doc quote missing `>` marker
+//~^ ERROR: doc quote line without `>` marker
 fn four_point_1() {}
 
 /// * > nest here lazy continuation
@@ -43,5 +43,5 @@ fn five() {}
 
 /// 1. > nest here
 ///    > lazy continuation (this results in strange indentation, but still works)
-//~^ ERROR: doc quote missing `>` marker
+//~^ ERROR: doc quote line without `>` marker
 fn six() {}
diff --git a/src/tools/clippy/tests/ui/doc/doc_lazy_blockquote.rs b/src/tools/clippy/tests/ui/doc/doc_lazy_blockquote.rs
index 587b2fdd533..0323a1b44e7 100644
--- a/src/tools/clippy/tests/ui/doc/doc_lazy_blockquote.rs
+++ b/src/tools/clippy/tests/ui/doc/doc_lazy_blockquote.rs
@@ -2,7 +2,7 @@
 
 /// > blockquote with
 /// lazy continuation
-//~^ ERROR: doc quote missing `>` marker
+//~^ ERROR: doc quote line without `>` marker
 fn first() {}
 
 /// > blockquote with no
@@ -18,24 +18,24 @@ fn two_nowarn() {}
 /// >
 /// > > nest here
 /// > lazy continuation
-//~^ ERROR: doc quote missing `>` marker
+//~^ ERROR: doc quote line without `>` marker
 fn two() {}
 
 /// > nest here
 /// >
 /// > > nest here
 /// lazy continuation
-//~^ ERROR: doc quote missing `>` marker
+//~^ ERROR: doc quote line without `>` marker
 fn three() {}
 
 /// >   * > nest here
 /// lazy continuation
-//~^ ERROR: doc quote missing `>` marker
+//~^ ERROR: doc quote line without `>` marker
 fn four() {}
 
 /// > * > nest here
 /// lazy continuation
-//~^ ERROR: doc quote missing `>` marker
+//~^ ERROR: doc quote line without `>` marker
 fn four_point_1() {}
 
 /// * > nest here lazy continuation
@@ -43,5 +43,5 @@ fn five() {}
 
 /// 1. > nest here
 ///  lazy continuation (this results in strange indentation, but still works)
-//~^ ERROR: doc quote missing `>` marker
+//~^ ERROR: doc quote line without `>` marker
 fn six() {}
diff --git a/src/tools/clippy/tests/ui/doc/doc_lazy_blockquote.stderr b/src/tools/clippy/tests/ui/doc/doc_lazy_blockquote.stderr
index 975184a01c3..d3390efdff3 100644
--- a/src/tools/clippy/tests/ui/doc/doc_lazy_blockquote.stderr
+++ b/src/tools/clippy/tests/ui/doc/doc_lazy_blockquote.stderr
@@ -1,4 +1,4 @@
-error: doc quote missing `>` marker
+error: doc quote line without `>` marker
   --> tests/ui/doc/doc_lazy_blockquote.rs:4:5
    |
 LL | /// lazy continuation
@@ -12,7 +12,7 @@ help: add markers to start of line
 LL | /// > lazy continuation
    |     +
 
-error: doc quote missing `>` marker
+error: doc quote line without `>` marker
   --> tests/ui/doc/doc_lazy_blockquote.rs:20:5
    |
 LL | /// > lazy continuation
@@ -24,7 +24,7 @@ help: add markers to start of line
 LL | /// > > lazy continuation
    |       +
 
-error: doc quote missing `>` marker
+error: doc quote line without `>` marker
   --> tests/ui/doc/doc_lazy_blockquote.rs:27:5
    |
 LL | /// lazy continuation
@@ -36,7 +36,7 @@ help: add markers to start of line
 LL | /// > > lazy continuation
    |     +++
 
-error: doc quote missing `>` marker
+error: doc quote line without `>` marker
   --> tests/ui/doc/doc_lazy_blockquote.rs:32:5
    |
 LL | /// lazy continuation
@@ -48,7 +48,7 @@ help: add markers to start of line
 LL | /// >     > lazy continuation
    |     +++++++
 
-error: doc quote missing `>` marker
+error: doc quote line without `>` marker
   --> tests/ui/doc/doc_lazy_blockquote.rs:37:5
    |
 LL | /// lazy continuation
@@ -60,7 +60,7 @@ help: add markers to start of line
 LL | /// >   > lazy continuation
    |     +++++
 
-error: doc quote missing `>` marker
+error: doc quote line without `>` marker
   --> tests/ui/doc/doc_lazy_blockquote.rs:45:5
    |
 LL | ///  lazy continuation (this results in strange indentation, but still works)
diff --git a/src/tools/clippy/tests/ui/doc/doc_lazy_list.fixed b/src/tools/clippy/tests/ui/doc/doc_lazy_list.fixed
index 409e6b0bc22..ea59ae4c01c 100644
--- a/src/tools/clippy/tests/ui/doc/doc_lazy_list.fixed
+++ b/src/tools/clippy/tests/ui/doc/doc_lazy_list.fixed
@@ -2,38 +2,41 @@
 
 /// 1. nest here
 ///    lazy continuation
-//~^ ERROR: doc list item missing indentation
+//~^ ERROR: doc list item without indentation
 fn one() {}
 
 /// 1. first line
 ///    lazy list continuations don't make warnings with this lint
-//~^ ERROR: doc list item missing indentation
-///    because they don't have the
-//~^ ERROR: doc list item missing indentation
+///
+//~^ ERROR: doc list item without indentation
+/// because they don't have the
+//~^ ERROR: doc list item without indentation
 fn two() {}
 
 ///   - nest here
 ///     lazy continuation
-//~^ ERROR: doc list item missing indentation
+//~^ ERROR: doc list item without indentation
 fn three() {}
 
 ///   - first line
 ///     lazy list continuations don't make warnings with this lint
-//~^ ERROR: doc list item missing indentation
-///     because they don't have the
-//~^ ERROR: doc list item missing indentation
+///
+//~^ ERROR: doc list item without indentation
+/// because they don't have the
+//~^ ERROR: doc list item without indentation
 fn four() {}
 
 ///   - nest here
 ///     lazy continuation
-//~^ ERROR: doc list item missing indentation
+//~^ ERROR: doc list item without indentation
 fn five() {}
 
 ///   - - first line
 ///       this will warn on the lazy continuation
-//~^ ERROR: doc list item missing indentation
-///       and so should this
-//~^ ERROR: doc list item missing indentation
+///
+//~^ ERROR: doc list item without indentation
+///     and so should this
+//~^ ERROR: doc list item without indentation
 fn six() {}
 
 ///   - - first line
@@ -54,7 +57,7 @@ fn seven() {}
 /// * `protocol_descriptors`: A Json Representation of the ProtocolDescriptors
 ///     to set up. Example:
 ///   'protocol_descriptors': [
-//~^ ERROR: doc list item missing indentation
+//~^ ERROR: doc list item without indentation
 ///      {
 ///          'protocol': 25,  # u64 Representation of ProtocolIdentifier::AVDTP
 ///          'params': [
@@ -73,5 +76,5 @@ fn seven() {}
 ///          }]
 ///      }
 ///   ]
-//~^ ERROR: doc list item missing indentation
+//~^ ERROR: doc list item without indentation
 fn eight() {}
diff --git a/src/tools/clippy/tests/ui/doc/doc_lazy_list.rs b/src/tools/clippy/tests/ui/doc/doc_lazy_list.rs
index 30ab448a113..3cc18e35780 100644
--- a/src/tools/clippy/tests/ui/doc/doc_lazy_list.rs
+++ b/src/tools/clippy/tests/ui/doc/doc_lazy_list.rs
@@ -2,38 +2,38 @@
 
 /// 1. nest here
 /// lazy continuation
-//~^ ERROR: doc list item missing indentation
+//~^ ERROR: doc list item without indentation
 fn one() {}
 
 /// 1. first line
 /// lazy list continuations don't make warnings with this lint
-//~^ ERROR: doc list item missing indentation
+//~^ ERROR: doc list item without indentation
 /// because they don't have the
-//~^ ERROR: doc list item missing indentation
+//~^ ERROR: doc list item without indentation
 fn two() {}
 
 ///   - nest here
 /// lazy continuation
-//~^ ERROR: doc list item missing indentation
+//~^ ERROR: doc list item without indentation
 fn three() {}
 
 ///   - first line
 /// lazy list continuations don't make warnings with this lint
-//~^ ERROR: doc list item missing indentation
+//~^ ERROR: doc list item without indentation
 /// because they don't have the
-//~^ ERROR: doc list item missing indentation
+//~^ ERROR: doc list item without indentation
 fn four() {}
 
 ///   - nest here
 /// lazy continuation
-//~^ ERROR: doc list item missing indentation
+//~^ ERROR: doc list item without indentation
 fn five() {}
 
 ///   - - first line
 /// this will warn on the lazy continuation
-//~^ ERROR: doc list item missing indentation
+//~^ ERROR: doc list item without indentation
 ///     and so should this
-//~^ ERROR: doc list item missing indentation
+//~^ ERROR: doc list item without indentation
 fn six() {}
 
 ///   - - first line
@@ -54,7 +54,7 @@ fn seven() {}
 /// * `protocol_descriptors`: A Json Representation of the ProtocolDescriptors
 ///     to set up. Example:
 ///  'protocol_descriptors': [
-//~^ ERROR: doc list item missing indentation
+//~^ ERROR: doc list item without indentation
 ///      {
 ///          'protocol': 25,  # u64 Representation of ProtocolIdentifier::AVDTP
 ///          'params': [
@@ -73,5 +73,5 @@ fn seven() {}
 ///          }]
 ///      }
 ///  ]
-//~^ ERROR: doc list item missing indentation
+//~^ ERROR: doc list item without indentation
 fn eight() {}
diff --git a/src/tools/clippy/tests/ui/doc/doc_lazy_list.stderr b/src/tools/clippy/tests/ui/doc/doc_lazy_list.stderr
index ddfdc49340c..52aa74df894 100644
--- a/src/tools/clippy/tests/ui/doc/doc_lazy_list.stderr
+++ b/src/tools/clippy/tests/ui/doc/doc_lazy_list.stderr
@@ -1,4 +1,4 @@
-error: doc list item missing indentation
+error: doc list item without indentation
   --> tests/ui/doc/doc_lazy_list.rs:4:5
    |
 LL | /// lazy continuation
@@ -12,7 +12,7 @@ help: indent this line
 LL | ///    lazy continuation
    |     +++
 
-error: doc list item missing indentation
+error: doc list item without indentation
   --> tests/ui/doc/doc_lazy_list.rs:9:5
    |
 LL | /// lazy list continuations don't make warnings with this lint
@@ -24,19 +24,20 @@ help: indent this line
 LL | ///    lazy list continuations don't make warnings with this lint
    |     +++
 
-error: doc list item missing indentation
+error: doc list item without indentation
   --> tests/ui/doc/doc_lazy_list.rs:11:5
    |
 LL | /// because they don't have the
    |     ^
    |
-   = help: if this is supposed to be its own paragraph, add a blank line
-help: indent this line
+   = help: if this is intended to be part of the list, indent 3 spaces
+help: if this should be its own paragraph, add a blank doc comment line
+   |
+LL ~ /// lazy list continuations don't make warnings with this lint
+LL + ///
    |
-LL | ///    because they don't have the
-   |     +++
 
-error: doc list item missing indentation
+error: doc list item without indentation
   --> tests/ui/doc/doc_lazy_list.rs:16:5
    |
 LL | /// lazy continuation
@@ -48,7 +49,7 @@ help: indent this line
 LL | ///     lazy continuation
    |     ++++
 
-error: doc list item missing indentation
+error: doc list item without indentation
   --> tests/ui/doc/doc_lazy_list.rs:21:5
    |
 LL | /// lazy list continuations don't make warnings with this lint
@@ -60,19 +61,20 @@ help: indent this line
 LL | ///     lazy list continuations don't make warnings with this lint
    |     ++++
 
-error: doc list item missing indentation
+error: doc list item without indentation
   --> tests/ui/doc/doc_lazy_list.rs:23:5
    |
 LL | /// because they don't have the
    |     ^
    |
-   = help: if this is supposed to be its own paragraph, add a blank line
-help: indent this line
+   = help: if this is intended to be part of the list, indent 4 spaces
+help: if this should be its own paragraph, add a blank doc comment line
+   |
+LL ~ /// lazy list continuations don't make warnings with this lint
+LL + ///
    |
-LL | ///     because they don't have the
-   |     ++++
 
-error: doc list item missing indentation
+error: doc list item without indentation
   --> tests/ui/doc/doc_lazy_list.rs:28:5
    |
 LL | /// lazy continuation
@@ -84,7 +86,7 @@ help: indent this line
 LL | ///     lazy continuation
    |     ++++
 
-error: doc list item missing indentation
+error: doc list item without indentation
   --> tests/ui/doc/doc_lazy_list.rs:33:5
    |
 LL | /// this will warn on the lazy continuation
@@ -96,19 +98,20 @@ help: indent this line
 LL | ///       this will warn on the lazy continuation
    |     ++++++
 
-error: doc list item missing indentation
+error: doc list item without indentation
   --> tests/ui/doc/doc_lazy_list.rs:35:5
    |
 LL | ///     and so should this
    |     ^^^^
    |
-   = help: if this is supposed to be its own paragraph, add a blank line
-help: indent this line
+   = help: if this is intended to be part of the list, indent 2 spaces
+help: if this should be its own paragraph, add a blank doc comment line
+   |
+LL ~ /// this will warn on the lazy continuation
+LL + ///
    |
-LL | ///       and so should this
-   |         ++
 
-error: doc list item missing indentation
+error: doc list item without indentation
   --> tests/ui/doc/doc_lazy_list.rs:56:5
    |
 LL | ///  'protocol_descriptors': [
@@ -120,7 +123,7 @@ help: indent this line
 LL | ///   'protocol_descriptors': [
    |      +
 
-error: doc list item missing indentation
+error: doc list item without indentation
   --> tests/ui/doc/doc_lazy_list.rs:75:5
    |
 LL | ///  ]
diff --git a/src/tools/clippy/tests/ui/doc/unbalanced_ticks.rs b/src/tools/clippy/tests/ui/doc/unbalanced_ticks.rs
index 6f7bab72040..04446787b6c 100644
--- a/src/tools/clippy/tests/ui/doc/unbalanced_ticks.rs
+++ b/src/tools/clippy/tests/ui/doc/unbalanced_ticks.rs
@@ -49,3 +49,20 @@ fn other_markdown() {}
 ///   pub struct Struct;
 ///   ```
 fn issue_7421() {}
+
+/// `
+//~^ ERROR: backticks are unbalanced
+fn escape_0() {}
+
+/// Escaped \` backticks don't count.
+fn escape_1() {}
+
+/// Escaped \` \` backticks don't count.
+fn escape_2() {}
+
+/// Escaped \` ` backticks don't count, but unescaped backticks do.
+//~^ ERROR: backticks are unbalanced
+fn escape_3() {}
+
+/// Backslashes ` \` within code blocks don't count.
+fn escape_4() {}
diff --git a/src/tools/clippy/tests/ui/doc/unbalanced_ticks.stderr b/src/tools/clippy/tests/ui/doc/unbalanced_ticks.stderr
index 56ef2913623..50324010e97 100644
--- a/src/tools/clippy/tests/ui/doc/unbalanced_ticks.stderr
+++ b/src/tools/clippy/tests/ui/doc/unbalanced_ticks.stderr
@@ -78,5 +78,21 @@ help: try
 LL | /// - This item needs `backticks_here`
    |                       ~~~~~~~~~~~~~~~~
 
-error: aborting due to 8 previous errors
+error: backticks are unbalanced
+  --> tests/ui/doc/unbalanced_ticks.rs:53:5
+   |
+LL | /// `
+   |     ^
+   |
+   = help: a backtick may be missing a pair
+
+error: backticks are unbalanced
+  --> tests/ui/doc/unbalanced_ticks.rs:63:5
+   |
+LL | /// Escaped \` ` backticks don't count, but unescaped backticks do.
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = help: a backtick may be missing a pair
+
+error: aborting due to 10 previous errors
 
diff --git a/src/tools/clippy/tests/ui/explicit_auto_deref.fixed b/src/tools/clippy/tests/ui/explicit_auto_deref.fixed
index e6ca4bb66cc..255b2c5a220 100644
--- a/src/tools/clippy/tests/ui/explicit_auto_deref.fixed
+++ b/src/tools/clippy/tests/ui/explicit_auto_deref.fixed
@@ -345,3 +345,39 @@ fn main() {
         let _ = &mut ({ *x.u }).x;
     }
 }
+
+mod issue_12969 {
+    use std::ops::Deref;
+
+    struct Wrapper<T>(T);
+
+    impl<T> Deref for Wrapper<T> {
+        type Target = T;
+
+        fn deref(&self) -> &T {
+            &self.0
+        }
+    }
+
+    fn foo(_bar: &str) {}
+
+    fn bar() {
+        let wrapped_bar = Wrapper("");
+
+        foo(&wrapped_bar);
+    }
+}
+
+mod issue_9841 {
+    fn takes_array_ref<T, const N: usize>(array: &&[T; N]) {
+        takes_slice(*array)
+    }
+
+    fn takes_array_ref_ref<T, const N: usize>(array: &&&[T; N]) {
+        takes_slice(**array)
+    }
+
+    fn takes_slice<T>(slice: &[T]) {
+        todo!()
+    }
+}
diff --git a/src/tools/clippy/tests/ui/explicit_auto_deref.rs b/src/tools/clippy/tests/ui/explicit_auto_deref.rs
index 7531e1f87b7..99906999f01 100644
--- a/src/tools/clippy/tests/ui/explicit_auto_deref.rs
+++ b/src/tools/clippy/tests/ui/explicit_auto_deref.rs
@@ -345,3 +345,39 @@ fn main() {
         let _ = &mut ({ *x.u }).x;
     }
 }
+
+mod issue_12969 {
+    use std::ops::Deref;
+
+    struct Wrapper<T>(T);
+
+    impl<T> Deref for Wrapper<T> {
+        type Target = T;
+
+        fn deref(&self) -> &T {
+            &self.0
+        }
+    }
+
+    fn foo(_bar: &str) {}
+
+    fn bar() {
+        let wrapped_bar = Wrapper("");
+
+        foo(&*wrapped_bar);
+    }
+}
+
+mod issue_9841 {
+    fn takes_array_ref<T, const N: usize>(array: &&[T; N]) {
+        takes_slice(*array)
+    }
+
+    fn takes_array_ref_ref<T, const N: usize>(array: &&&[T; N]) {
+        takes_slice(**array)
+    }
+
+    fn takes_slice<T>(slice: &[T]) {
+        todo!()
+    }
+}
diff --git a/src/tools/clippy/tests/ui/explicit_auto_deref.stderr b/src/tools/clippy/tests/ui/explicit_auto_deref.stderr
index 56a183de348..53784934f63 100644
--- a/src/tools/clippy/tests/ui/explicit_auto_deref.stderr
+++ b/src/tools/clippy/tests/ui/explicit_auto_deref.stderr
@@ -271,5 +271,11 @@ error: deref which would be done by auto-deref
 LL |         let _ = &mut (*{ x.u }).x;
    |                      ^^^^^^^^^^ help: try: `{ x.u }`
 
-error: aborting due to 45 previous errors
+error: deref which would be done by auto-deref
+  --> tests/ui/explicit_auto_deref.rs:367:13
+   |
+LL |         foo(&*wrapped_bar);
+   |             ^^^^^^^^^^^^^ help: try: `&wrapped_bar`
+
+error: aborting due to 46 previous errors
 
diff --git a/src/tools/clippy/tests/ui/float_cmp.rs b/src/tools/clippy/tests/ui/float_cmp.rs
index 1923ad7c677..78dd2c6c01c 100644
--- a/src/tools/clippy/tests/ui/float_cmp.rs
+++ b/src/tools/clippy/tests/ui/float_cmp.rs
@@ -71,19 +71,16 @@ fn main() {
     twice(ONE) != ONE;
     ONE as f64 != 2.0;
     //~^ ERROR: strict comparison of `f32` or `f64`
-    //~| NOTE: `f32::EPSILON` and `f64::EPSILON` are available for the `error_margin`
     ONE as f64 != 0.0; // no error, comparison with zero is ok
 
     let x: f64 = 1.0;
 
     x == 1.0;
     //~^ ERROR: strict comparison of `f32` or `f64`
-    //~| NOTE: `f32::EPSILON` and `f64::EPSILON` are available for the `error_margin`
     x != 0f64; // no error, comparison with zero is ok
 
     twice(x) != twice(ONE as f64);
     //~^ ERROR: strict comparison of `f32` or `f64`
-    //~| NOTE: `f32::EPSILON` and `f64::EPSILON` are available for the `error_margin`
 
     x < 0.0; // no errors, lower or greater comparisons need no fuzzyness
     x > 0.0;
@@ -105,17 +102,14 @@ fn main() {
     ZERO_ARRAY[i] == NON_ZERO_ARRAY[j]; // ok, because lhs is zero regardless of i
     NON_ZERO_ARRAY[i] == NON_ZERO_ARRAY[j];
     //~^ ERROR: strict comparison of `f32` or `f64`
-    //~| NOTE: `f32::EPSILON` and `f64::EPSILON` are available for the `error_margin`
 
     let a1: [f32; 1] = [0.0];
     let a2: [f32; 1] = [1.1];
 
     a1 == a2;
     //~^ ERROR: strict comparison of `f32` or `f64` arrays
-    //~| NOTE: `f32::EPSILON` and `f64::EPSILON` are available for the `error_margin`
     a1[0] == a2[0];
     //~^ ERROR: strict comparison of `f32` or `f64`
-    //~| NOTE: `f32::EPSILON` and `f64::EPSILON` are available for the `error_margin`
 
     // no errors - comparing signums is ok
     let x32 = 3.21f32;
diff --git a/src/tools/clippy/tests/ui/float_cmp.stderr b/src/tools/clippy/tests/ui/float_cmp.stderr
index c8a0bde6e63..d10da8a99a9 100644
--- a/src/tools/clippy/tests/ui/float_cmp.stderr
+++ b/src/tools/clippy/tests/ui/float_cmp.stderr
@@ -4,49 +4,38 @@ error: strict comparison of `f32` or `f64`
 LL |     ONE as f64 != 2.0;
    |     ^^^^^^^^^^^^^^^^^ help: consider comparing them within some margin of error: `(ONE as f64 - 2.0).abs() > error_margin`
    |
-   = note: `f32::EPSILON` and `f64::EPSILON` are available for the `error_margin`
    = note: `-D clippy::float-cmp` implied by `-D warnings`
    = help: to override `-D warnings` add `#[allow(clippy::float_cmp)]`
 
 error: strict comparison of `f32` or `f64`
-  --> tests/ui/float_cmp.rs:79:5
+  --> tests/ui/float_cmp.rs:78:5
    |
 LL |     x == 1.0;
    |     ^^^^^^^^ help: consider comparing them within some margin of error: `(x - 1.0).abs() < error_margin`
-   |
-   = note: `f32::EPSILON` and `f64::EPSILON` are available for the `error_margin`
 
 error: strict comparison of `f32` or `f64`
-  --> tests/ui/float_cmp.rs:84:5
+  --> tests/ui/float_cmp.rs:82:5
    |
 LL |     twice(x) != twice(ONE as f64);
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider comparing them within some margin of error: `(twice(x) - twice(ONE as f64)).abs() > error_margin`
-   |
-   = note: `f32::EPSILON` and `f64::EPSILON` are available for the `error_margin`
 
 error: strict comparison of `f32` or `f64`
-  --> tests/ui/float_cmp.rs:106:5
+  --> tests/ui/float_cmp.rs:103:5
    |
 LL |     NON_ZERO_ARRAY[i] == NON_ZERO_ARRAY[j];
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider comparing them within some margin of error: `(NON_ZERO_ARRAY[i] - NON_ZERO_ARRAY[j]).abs() < error_margin`
-   |
-   = note: `f32::EPSILON` and `f64::EPSILON` are available for the `error_margin`
 
 error: strict comparison of `f32` or `f64` arrays
-  --> tests/ui/float_cmp.rs:113:5
+  --> tests/ui/float_cmp.rs:109:5
    |
 LL |     a1 == a2;
    |     ^^^^^^^^
-   |
-   = note: `f32::EPSILON` and `f64::EPSILON` are available for the `error_margin`
 
 error: strict comparison of `f32` or `f64`
-  --> tests/ui/float_cmp.rs:116:5
+  --> tests/ui/float_cmp.rs:111:5
    |
 LL |     a1[0] == a2[0];
    |     ^^^^^^^^^^^^^^ help: consider comparing them within some margin of error: `(a1[0] - a2[0]).abs() < error_margin`
-   |
-   = note: `f32::EPSILON` and `f64::EPSILON` are available for the `error_margin`
 
 error: aborting due to 6 previous errors
 
diff --git a/src/tools/clippy/tests/ui/float_cmp_const.rs b/src/tools/clippy/tests/ui/float_cmp_const.rs
index 47ea0e19c68..08180556437 100644
--- a/src/tools/clippy/tests/ui/float_cmp_const.rs
+++ b/src/tools/clippy/tests/ui/float_cmp_const.rs
@@ -15,28 +15,21 @@ fn main() {
     // has errors
     1f32 == ONE;
     //~^ ERROR: strict comparison of `f32` or `f64` constant
-    //~| NOTE: `f32::EPSILON` and `f64::EPSILON` are available for the `error_margin`
     TWO == ONE;
     //~^ ERROR: strict comparison of `f32` or `f64` constant
-    //~| NOTE: `f32::EPSILON` and `f64::EPSILON` are available for the `error_margin`
     TWO != ONE;
     //~^ ERROR: strict comparison of `f32` or `f64` constant
-    //~| NOTE: `f32::EPSILON` and `f64::EPSILON` are available for the `error_margin`
     ONE + ONE == TWO;
     //~^ ERROR: strict comparison of `f32` or `f64` constant
-    //~| NOTE: `f32::EPSILON` and `f64::EPSILON` are available for the `error_margin`
     let x = 1;
     x as f32 == ONE;
     //~^ ERROR: strict comparison of `f32` or `f64` constant
-    //~| NOTE: `f32::EPSILON` and `f64::EPSILON` are available for the `error_margin`
 
     let v = 0.9;
     v == ONE;
     //~^ ERROR: strict comparison of `f32` or `f64` constant
-    //~| NOTE: `f32::EPSILON` and `f64::EPSILON` are available for the `error_margin`
     v != ONE;
     //~^ ERROR: strict comparison of `f32` or `f64` constant
-    //~| NOTE: `f32::EPSILON` and `f64::EPSILON` are available for the `error_margin`
 
     // no errors, lower than or greater than comparisons
     v < ONE;
@@ -70,5 +63,4 @@ fn main() {
     // has errors
     NON_ZERO_ARRAY == NON_ZERO_ARRAY2;
     //~^ ERROR: strict comparison of `f32` or `f64` constant arrays
-    //~| NOTE: `f32::EPSILON` and `f64::EPSILON` are available for the `error_margin`
 }
diff --git a/src/tools/clippy/tests/ui/float_cmp_const.stderr b/src/tools/clippy/tests/ui/float_cmp_const.stderr
index bffd2acc2e0..4f88746e958 100644
--- a/src/tools/clippy/tests/ui/float_cmp_const.stderr
+++ b/src/tools/clippy/tests/ui/float_cmp_const.stderr
@@ -4,65 +4,50 @@ error: strict comparison of `f32` or `f64` constant
 LL |     1f32 == ONE;
    |     ^^^^^^^^^^^ help: consider comparing them within some margin of error: `(1f32 - ONE).abs() < error_margin`
    |
-   = note: `f32::EPSILON` and `f64::EPSILON` are available for the `error_margin`
    = note: `-D clippy::float-cmp-const` implied by `-D warnings`
    = help: to override `-D warnings` add `#[allow(clippy::float_cmp_const)]`
 
 error: strict comparison of `f32` or `f64` constant
-  --> tests/ui/float_cmp_const.rs:19:5
+  --> tests/ui/float_cmp_const.rs:18:5
    |
 LL |     TWO == ONE;
    |     ^^^^^^^^^^ help: consider comparing them within some margin of error: `(TWO - ONE).abs() < error_margin`
-   |
-   = note: `f32::EPSILON` and `f64::EPSILON` are available for the `error_margin`
 
 error: strict comparison of `f32` or `f64` constant
-  --> tests/ui/float_cmp_const.rs:22:5
+  --> tests/ui/float_cmp_const.rs:20:5
    |
 LL |     TWO != ONE;
    |     ^^^^^^^^^^ help: consider comparing them within some margin of error: `(TWO - ONE).abs() > error_margin`
-   |
-   = note: `f32::EPSILON` and `f64::EPSILON` are available for the `error_margin`
 
 error: strict comparison of `f32` or `f64` constant
-  --> tests/ui/float_cmp_const.rs:25:5
+  --> tests/ui/float_cmp_const.rs:22:5
    |
 LL |     ONE + ONE == TWO;
    |     ^^^^^^^^^^^^^^^^ help: consider comparing them within some margin of error: `(ONE + ONE - TWO).abs() < error_margin`
-   |
-   = note: `f32::EPSILON` and `f64::EPSILON` are available for the `error_margin`
 
 error: strict comparison of `f32` or `f64` constant
-  --> tests/ui/float_cmp_const.rs:29:5
+  --> tests/ui/float_cmp_const.rs:25:5
    |
 LL |     x as f32 == ONE;
    |     ^^^^^^^^^^^^^^^ help: consider comparing them within some margin of error: `(x as f32 - ONE).abs() < error_margin`
-   |
-   = note: `f32::EPSILON` and `f64::EPSILON` are available for the `error_margin`
 
 error: strict comparison of `f32` or `f64` constant
-  --> tests/ui/float_cmp_const.rs:34:5
+  --> tests/ui/float_cmp_const.rs:29:5
    |
 LL |     v == ONE;
    |     ^^^^^^^^ help: consider comparing them within some margin of error: `(v - ONE).abs() < error_margin`
-   |
-   = note: `f32::EPSILON` and `f64::EPSILON` are available for the `error_margin`
 
 error: strict comparison of `f32` or `f64` constant
-  --> tests/ui/float_cmp_const.rs:37:5
+  --> tests/ui/float_cmp_const.rs:31:5
    |
 LL |     v != ONE;
    |     ^^^^^^^^ help: consider comparing them within some margin of error: `(v - ONE).abs() > error_margin`
-   |
-   = note: `f32::EPSILON` and `f64::EPSILON` are available for the `error_margin`
 
 error: strict comparison of `f32` or `f64` constant arrays
-  --> tests/ui/float_cmp_const.rs:71:5
+  --> tests/ui/float_cmp_const.rs:64:5
    |
 LL |     NON_ZERO_ARRAY == NON_ZERO_ARRAY2;
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = note: `f32::EPSILON` and `f64::EPSILON` are available for the `error_margin`
 
 error: aborting due to 8 previous errors
 
diff --git a/src/tools/clippy/tests/ui/numbered_fields.fixed b/src/tools/clippy/tests/ui/init_numbered_fields.fixed
index 108520eed38..dca4e8da4d2 100644
--- a/src/tools/clippy/tests/ui/numbered_fields.fixed
+++ b/src/tools/clippy/tests/ui/init_numbered_fields.fixed
@@ -39,4 +39,13 @@ fn main() {
     struct TupleStructVec(Vec<usize>);
 
     let _ = TupleStructVec(vec![0, 1, 2, 3]);
+
+    {
+        struct S(i32, i32);
+        let mut iter = [1i32, 1i32].into_iter();
+        let _ = S {
+            1: iter.next().unwrap(),
+            0: iter.next().unwrap(),
+        };
+    }
 }
diff --git a/src/tools/clippy/tests/ui/numbered_fields.rs b/src/tools/clippy/tests/ui/init_numbered_fields.rs
index c718661a682..8cb34705b4f 100644
--- a/src/tools/clippy/tests/ui/numbered_fields.rs
+++ b/src/tools/clippy/tests/ui/init_numbered_fields.rs
@@ -47,4 +47,13 @@ fn main() {
     struct TupleStructVec(Vec<usize>);
 
     let _ = TupleStructVec { 0: vec![0, 1, 2, 3] };
+
+    {
+        struct S(i32, i32);
+        let mut iter = [1i32, 1i32].into_iter();
+        let _ = S {
+            1: iter.next().unwrap(),
+            0: iter.next().unwrap(),
+        };
+    }
 }
diff --git a/src/tools/clippy/tests/ui/numbered_fields.stderr b/src/tools/clippy/tests/ui/init_numbered_fields.stderr
index 9d3f59cd376..f176e0c2ff3 100644
--- a/src/tools/clippy/tests/ui/numbered_fields.stderr
+++ b/src/tools/clippy/tests/ui/init_numbered_fields.stderr
@@ -1,5 +1,5 @@
 error: used a field initializer for a tuple struct
-  --> tests/ui/numbered_fields.rs:17:13
+  --> tests/ui/init_numbered_fields.rs:17:13
    |
 LL |       let _ = TupleStruct {
    |  _____________^
@@ -7,13 +7,13 @@ LL | |         0: 1u32,
 LL | |         1: 42,
 LL | |         2: 23u8,
 LL | |     };
-   | |_____^ help: try: `TupleStruct(1u32, 42, 23u8)`
+   | |_____^ help: use tuple initialization: `TupleStruct(1u32, 42, 23u8)`
    |
    = note: `-D clippy::init-numbered-fields` implied by `-D warnings`
    = help: to override `-D warnings` add `#[allow(clippy::init_numbered_fields)]`
 
 error: used a field initializer for a tuple struct
-  --> tests/ui/numbered_fields.rs:24:13
+  --> tests/ui/init_numbered_fields.rs:24:13
    |
 LL |       let _ = TupleStruct {
    |  _____________^
@@ -21,13 +21,13 @@ LL | |         0: 1u32,
 LL | |         2: 2u8,
 LL | |         1: 3u32,
 LL | |     };
-   | |_____^ help: try: `TupleStruct(1u32, 3u32, 2u8)`
+   | |_____^ help: use tuple initialization: `TupleStruct(1u32, 3u32, 2u8)`
 
 error: used a field initializer for a tuple struct
-  --> tests/ui/numbered_fields.rs:49:13
+  --> tests/ui/init_numbered_fields.rs:49:13
    |
 LL |     let _ = TupleStructVec { 0: vec![0, 1, 2, 3] };
-   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `TupleStructVec(vec![0, 1, 2, 3])`
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use tuple initialization: `TupleStructVec(vec![0, 1, 2, 3])`
 
 error: aborting due to 3 previous errors
 
diff --git a/src/tools/clippy/tests/ui/into_iter_without_iter.rs b/src/tools/clippy/tests/ui/into_iter_without_iter.rs
index c8b9076041a..109259d6975 100644
--- a/src/tools/clippy/tests/ui/into_iter_without_iter.rs
+++ b/src/tools/clippy/tests/ui/into_iter_without_iter.rs
@@ -185,3 +185,42 @@ pub mod issue11635 {
         }
     }
 }
+
+pub mod issue12964 {
+    pub struct MyIter<'a, T: 'a> {
+        iter: std::slice::Iter<'a, T>,
+    }
+
+    impl<'a, T> Iterator for MyIter<'a, T> {
+        type Item = &'a T;
+
+        fn next(&mut self) -> Option<Self::Item> {
+            self.iter.next()
+        }
+    }
+
+    pub struct MyContainer<T> {
+        inner: Vec<T>,
+    }
+
+    impl<T> MyContainer<T> {}
+
+    impl<T> MyContainer<T> {
+        #[must_use]
+        pub fn iter(&self) -> MyIter<'_, T> {
+            <&Self as IntoIterator>::into_iter(self)
+        }
+    }
+
+    impl<'a, T> IntoIterator for &'a MyContainer<T> {
+        type Item = &'a T;
+
+        type IntoIter = MyIter<'a, T>;
+
+        fn into_iter(self) -> Self::IntoIter {
+            Self::IntoIter {
+                iter: self.inner.as_slice().iter(),
+            }
+        }
+    }
+}
diff --git a/src/tools/clippy/tests/ui/iter_next_loop.rs b/src/tools/clippy/tests/ui/iter_next_loop.rs
index 548b799de44..d425f4da0e8 100644
--- a/src/tools/clippy/tests/ui/iter_next_loop.rs
+++ b/src/tools/clippy/tests/ui/iter_next_loop.rs
@@ -3,7 +3,7 @@
 
 fn main() {
     let x = [1, 2, 3, 4];
-    for _ in vec.iter().next() {}
+    for _ in x.iter().next() {}
 
     struct Unrelated(&'static [u8]);
     impl Unrelated {
diff --git a/src/tools/clippy/tests/ui/iter_next_loop.stderr b/src/tools/clippy/tests/ui/iter_next_loop.stderr
index 85c23f4e709..acc55031c3b 100644
--- a/src/tools/clippy/tests/ui/iter_next_loop.stderr
+++ b/src/tools/clippy/tests/ui/iter_next_loop.stderr
@@ -1,9 +1,11 @@
-error[E0423]: expected value, found macro `vec`
+error: you are iterating over `Iterator::next()` which is an Option; this will compile but is probably not what you want
   --> tests/ui/iter_next_loop.rs:6:14
    |
-LL |     for _ in vec.iter().next() {}
-   |              ^^^ not a value
+LL |     for _ in x.iter().next() {}
+   |              ^^^^^^^^^^^^^^^
+   |
+   = note: `-D clippy::iter-next-loop` implied by `-D warnings`
+   = help: to override `-D warnings` add `#[allow(clippy::iter_next_loop)]`
 
 error: aborting due to 1 previous error
 
-For more information about this error, try `rustc --explain E0423`.
diff --git a/src/tools/clippy/tests/ui/manual_inspect.stderr b/src/tools/clippy/tests/ui/manual_inspect.stderr
index 8548c0cd294..0559b3bd661 100644
--- a/src/tools/clippy/tests/ui/manual_inspect.stderr
+++ b/src/tools/clippy/tests/ui/manual_inspect.stderr
@@ -1,4 +1,4 @@
-error: 
+error: using `map` over `inspect`
   --> tests/ui/manual_inspect.rs:5:21
    |
 LL |     let _ = Some(0).map(|x| {
@@ -12,7 +12,7 @@ LL ~     let _ = Some(0).inspect(|&x| {
 LL ~         println!("{}", x);
    |
 
-error: 
+error: using `map` over `inspect`
   --> tests/ui/manual_inspect.rs:10:21
    |
 LL |     let _ = Some(0).map(|x| {
@@ -24,7 +24,7 @@ LL ~     let _ = Some(0).inspect(|&x| {
 LL ~         println!("{x}");
    |
 
-error: 
+error: using `map` over `inspect`
   --> tests/ui/manual_inspect.rs:15:21
    |
 LL |     let _ = Some(0).map(|x| {
@@ -36,7 +36,7 @@ LL ~     let _ = Some(0).inspect(|&x| {
 LL ~         println!("{}", x * 5 + 1);
    |
 
-error: 
+error: using `map` over `inspect`
   --> tests/ui/manual_inspect.rs:20:21
    |
 LL |     let _ = Some(0).map(|x| {
@@ -50,7 +50,7 @@ LL |             panic!();
 LL ~         }
    |
 
-error: 
+error: using `map` over `inspect`
   --> tests/ui/manual_inspect.rs:27:21
    |
 LL |     let _ = Some(0).map(|x| {
@@ -65,7 +65,7 @@ LL |             panic!();
 LL ~         }
    |
 
-error: 
+error: using `map` over `inspect`
   --> tests/ui/manual_inspect.rs:78:41
    |
 LL |     let _ = Some((String::new(), 0u32)).map(|x| {
@@ -80,7 +80,7 @@ LL |             panic!();
 LL ~         }
    |
 
-error: 
+error: using `map` over `inspect`
   --> tests/ui/manual_inspect.rs:104:33
    |
 LL |     let _ = Some(String::new()).map(|x| {
@@ -98,7 +98,7 @@ LL |         }
 LL ~         println!("test");
    |
 
-error: 
+error: using `map` over `inspect`
   --> tests/ui/manual_inspect.rs:115:21
    |
 LL |     let _ = Some(0).map(|x| {
@@ -113,7 +113,7 @@ LL |             panic!();
 LL ~         }
    |
 
-error: 
+error: using `map` over `inspect`
   --> tests/ui/manual_inspect.rs:130:46
    |
 LL |         let _ = Some(Cell2(Cell::new(0u32))).map(|x| {
@@ -125,7 +125,7 @@ LL ~         let _ = Some(Cell2(Cell::new(0u32))).inspect(|x| {
 LL ~             x.0.set(1);
    |
 
-error: 
+error: using `map` over `inspect`
   --> tests/ui/manual_inspect.rs:146:34
    |
 LL |     let _: Result<_, ()> = Ok(0).map(|x| {
@@ -137,7 +137,7 @@ LL ~     let _: Result<_, ()> = Ok(0).inspect(|&x| {
 LL ~         println!("{}", x);
    |
 
-error: 
+error: using `map_err` over `inspect_err`
   --> tests/ui/manual_inspect.rs:151:35
    |
 LL |     let _: Result<(), _> = Err(0).map_err(|x| {
@@ -166,7 +166,7 @@ LL | |         .count();
    = note: `-D clippy::suspicious-map` implied by `-D warnings`
    = help: to override `-D warnings` add `#[allow(clippy::suspicious_map)]`
 
-error: 
+error: using `map` over `inspect`
   --> tests/ui/manual_inspect.rs:158:10
    |
 LL |         .map(|x| {
diff --git a/src/tools/clippy/tests/ui/manual_rotate.fixed b/src/tools/clippy/tests/ui/manual_rotate.fixed
new file mode 100644
index 00000000000..5d33838a318
--- /dev/null
+++ b/src/tools/clippy/tests/ui/manual_rotate.fixed
@@ -0,0 +1,31 @@
+#![warn(clippy::manual_rotate)]
+#![allow(unused)]
+fn main() {
+    let (x_u8, x_u16, x_u32, x_u64) = (1u8, 1u16, 1u32, 1u64);
+    let (x_i8, x_i16, x_i32, x_i64) = (1i8, 1i16, 1i32, 1i64);
+    let a_u32 = 1u32;
+    // True positives
+    let y_u8 = x_u8.rotate_right(3);
+    let y_u16 = x_u16.rotate_right(7);
+    let y_u32 = x_u32.rotate_right(8);
+    let y_u64 = x_u64.rotate_right(9);
+    let y_i8 = x_i8.rotate_right(3);
+    let y_i16 = x_i16.rotate_right(7);
+    let y_i32 = x_i32.rotate_right(8);
+    let y_i64 = x_i64.rotate_right(9);
+    // Plus also works instead of |
+    let y_u32_plus = x_u32.rotate_right(8);
+    // Complex expression
+    let y_u32_complex = (x_u32 | 3256).rotate_right(8);
+    let y_u64_as = (x_u32 as u64).rotate_right(8);
+
+    // False positives - can't be replaced with a rotation
+    let y_u8_false = (x_u8 >> 6) | (x_u8 << 3);
+    let y_u32_false = (x_u32 >> 8) | (x_u32 >> 24);
+    let y_u64_false2 = (x_u64 >> 9) & (x_u64 << 55);
+    // Variable mismatch
+    let y_u32_wrong_vars = (x_u32 >> 8) | (a_u32 << 24);
+    // Has side effects and therefore should not be matched
+    let mut l = vec![12_u8, 34];
+    let y = (l.pop().unwrap() << 3) + (l.pop().unwrap() >> 5);
+}
diff --git a/src/tools/clippy/tests/ui/manual_rotate.rs b/src/tools/clippy/tests/ui/manual_rotate.rs
new file mode 100644
index 00000000000..5377491fb1a
--- /dev/null
+++ b/src/tools/clippy/tests/ui/manual_rotate.rs
@@ -0,0 +1,31 @@
+#![warn(clippy::manual_rotate)]
+#![allow(unused)]
+fn main() {
+    let (x_u8, x_u16, x_u32, x_u64) = (1u8, 1u16, 1u32, 1u64);
+    let (x_i8, x_i16, x_i32, x_i64) = (1i8, 1i16, 1i32, 1i64);
+    let a_u32 = 1u32;
+    // True positives
+    let y_u8 = (x_u8 >> 3) | (x_u8 << 5);
+    let y_u16 = (x_u16 >> 7) | (x_u16 << 9);
+    let y_u32 = (x_u32 >> 8) | (x_u32 << 24);
+    let y_u64 = (x_u64 >> 9) | (x_u64 << 55);
+    let y_i8 = (x_i8 >> 3) | (x_i8 << 5);
+    let y_i16 = (x_i16 >> 7) | (x_i16 << 9);
+    let y_i32 = (x_i32 >> 8) | (x_i32 << 24);
+    let y_i64 = (x_i64 >> 9) | (x_i64 << 55);
+    // Plus also works instead of |
+    let y_u32_plus = (x_u32 >> 8) + (x_u32 << 24);
+    // Complex expression
+    let y_u32_complex = ((x_u32 | 3256) >> 8) | ((x_u32 | 3256) << 24);
+    let y_u64_as = (x_u32 as u64 >> 8) | ((x_u32 as u64) << 56);
+
+    // False positives - can't be replaced with a rotation
+    let y_u8_false = (x_u8 >> 6) | (x_u8 << 3);
+    let y_u32_false = (x_u32 >> 8) | (x_u32 >> 24);
+    let y_u64_false2 = (x_u64 >> 9) & (x_u64 << 55);
+    // Variable mismatch
+    let y_u32_wrong_vars = (x_u32 >> 8) | (a_u32 << 24);
+    // Has side effects and therefore should not be matched
+    let mut l = vec![12_u8, 34];
+    let y = (l.pop().unwrap() << 3) + (l.pop().unwrap() >> 5);
+}
diff --git a/src/tools/clippy/tests/ui/manual_rotate.stderr b/src/tools/clippy/tests/ui/manual_rotate.stderr
new file mode 100644
index 00000000000..52da0861f70
--- /dev/null
+++ b/src/tools/clippy/tests/ui/manual_rotate.stderr
@@ -0,0 +1,71 @@
+error: there is no need to manually implement bit rotation
+  --> tests/ui/manual_rotate.rs:8:16
+   |
+LL |     let y_u8 = (x_u8 >> 3) | (x_u8 << 5);
+   |                ^^^^^^^^^^^^^^^^^^^^^^^^^ help: this expression can be rewritten as: `x_u8.rotate_right(3)`
+   |
+   = note: `-D clippy::manual-rotate` implied by `-D warnings`
+   = help: to override `-D warnings` add `#[allow(clippy::manual_rotate)]`
+
+error: there is no need to manually implement bit rotation
+  --> tests/ui/manual_rotate.rs:9:17
+   |
+LL |     let y_u16 = (x_u16 >> 7) | (x_u16 << 9);
+   |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: this expression can be rewritten as: `x_u16.rotate_right(7)`
+
+error: there is no need to manually implement bit rotation
+  --> tests/ui/manual_rotate.rs:10:17
+   |
+LL |     let y_u32 = (x_u32 >> 8) | (x_u32 << 24);
+   |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: this expression can be rewritten as: `x_u32.rotate_right(8)`
+
+error: there is no need to manually implement bit rotation
+  --> tests/ui/manual_rotate.rs:11:17
+   |
+LL |     let y_u64 = (x_u64 >> 9) | (x_u64 << 55);
+   |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: this expression can be rewritten as: `x_u64.rotate_right(9)`
+
+error: there is no need to manually implement bit rotation
+  --> tests/ui/manual_rotate.rs:12:16
+   |
+LL |     let y_i8 = (x_i8 >> 3) | (x_i8 << 5);
+   |                ^^^^^^^^^^^^^^^^^^^^^^^^^ help: this expression can be rewritten as: `x_i8.rotate_right(3)`
+
+error: there is no need to manually implement bit rotation
+  --> tests/ui/manual_rotate.rs:13:17
+   |
+LL |     let y_i16 = (x_i16 >> 7) | (x_i16 << 9);
+   |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: this expression can be rewritten as: `x_i16.rotate_right(7)`
+
+error: there is no need to manually implement bit rotation
+  --> tests/ui/manual_rotate.rs:14:17
+   |
+LL |     let y_i32 = (x_i32 >> 8) | (x_i32 << 24);
+   |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: this expression can be rewritten as: `x_i32.rotate_right(8)`
+
+error: there is no need to manually implement bit rotation
+  --> tests/ui/manual_rotate.rs:15:17
+   |
+LL |     let y_i64 = (x_i64 >> 9) | (x_i64 << 55);
+   |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: this expression can be rewritten as: `x_i64.rotate_right(9)`
+
+error: there is no need to manually implement bit rotation
+  --> tests/ui/manual_rotate.rs:17:22
+   |
+LL |     let y_u32_plus = (x_u32 >> 8) + (x_u32 << 24);
+   |                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: this expression can be rewritten as: `x_u32.rotate_right(8)`
+
+error: there is no need to manually implement bit rotation
+  --> tests/ui/manual_rotate.rs:19:25
+   |
+LL |     let y_u32_complex = ((x_u32 | 3256) >> 8) | ((x_u32 | 3256) << 24);
+   |                         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: this expression can be rewritten as: `(x_u32 | 3256).rotate_right(8)`
+
+error: there is no need to manually implement bit rotation
+  --> tests/ui/manual_rotate.rs:20:20
+   |
+LL |     let y_u64_as = (x_u32 as u64 >> 8) | ((x_u32 as u64) << 56);
+   |                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: this expression can be rewritten as: `(x_u32 as u64).rotate_right(8)`
+
+error: aborting due to 11 previous errors
+
diff --git a/src/tools/clippy/tests/ui/missing_const_for_fn/cant_be_const.rs b/src/tools/clippy/tests/ui/missing_const_for_fn/cant_be_const.rs
index 2750e0cdf3f..2c6e1e92da0 100644
--- a/src/tools/clippy/tests/ui/missing_const_for_fn/cant_be_const.rs
+++ b/src/tools/clippy/tests/ui/missing_const_for_fn/cant_be_const.rs
@@ -7,6 +7,7 @@
 
 #![warn(clippy::missing_const_for_fn)]
 #![feature(start)]
+#![feature(type_alias_impl_trait)]
 
 extern crate helper;
 extern crate proc_macros;
@@ -180,4 +181,21 @@ mod msrv {
             unsafe { *self.1 as usize }
         }
     }
+
+    #[clippy::msrv = "1.61"]
+    extern "C" fn c() {}
+}
+
+mod with_extern {
+    extern "C-unwind" fn c_unwind() {}
+    extern "system" fn system() {}
+    extern "system-unwind" fn system_unwind() {}
+}
+
+mod with_ty_alias {
+    type Foo = impl std::fmt::Debug;
+
+    fn foo(_: Foo) {
+        let _: Foo = 1;
+    }
 }
diff --git a/src/tools/clippy/tests/ui/missing_const_for_fn/could_be_const.fixed b/src/tools/clippy/tests/ui/missing_const_for_fn/could_be_const.fixed
index f8fc935f367..dbd739eee13 100644
--- a/src/tools/clippy/tests/ui/missing_const_for_fn/could_be_const.fixed
+++ b/src/tools/clippy/tests/ui/missing_const_for_fn/could_be_const.fixed
@@ -143,6 +143,21 @@ mod msrv {
         let bar = Bar { val: 1 };
         let _ = unsafe { bar.val };
     }
+
+    #[clippy::msrv = "1.62"]
+    mod with_extern {
+        const extern "C" fn c() {}
+        //~^ ERROR: this could be a `const fn`
+
+        #[rustfmt::skip]
+        const extern fn implicit_c() {}
+        //~^ ERROR: this could be a `const fn`
+
+        // any item functions in extern block won't trigger this lint
+        extern "C" {
+            fn c_in_block();
+        }
+    }
 }
 
 mod issue12677 {
@@ -174,3 +189,18 @@ mod issue12677 {
         }
     }
 }
+
+mod with_ty_alias {
+    trait FooTrait {
+        type Foo: std::fmt::Debug;
+        fn bar(_: Self::Foo) {}
+    }
+    impl FooTrait for () {
+        type Foo = i32;
+    }
+    // NOTE: When checking the type of a function param, make sure it is not an alias with
+    // `AliasTyKind::Projection` before calling `TyCtxt::type_of` to find out what the actual type
+    // is. Because the associate ty could have no default, therefore would cause ICE, as demostrated
+    // in this test.
+    const fn alias_ty_is_projection(bar: <() as FooTrait>::Foo) {}
+}
diff --git a/src/tools/clippy/tests/ui/missing_const_for_fn/could_be_const.rs b/src/tools/clippy/tests/ui/missing_const_for_fn/could_be_const.rs
index 5e4e2c58e5a..4ac56f4c803 100644
--- a/src/tools/clippy/tests/ui/missing_const_for_fn/could_be_const.rs
+++ b/src/tools/clippy/tests/ui/missing_const_for_fn/could_be_const.rs
@@ -143,6 +143,21 @@ mod msrv {
         let bar = Bar { val: 1 };
         let _ = unsafe { bar.val };
     }
+
+    #[clippy::msrv = "1.62"]
+    mod with_extern {
+        extern "C" fn c() {}
+        //~^ ERROR: this could be a `const fn`
+
+        #[rustfmt::skip]
+        extern fn implicit_c() {}
+        //~^ ERROR: this could be a `const fn`
+
+        // any item functions in extern block won't trigger this lint
+        extern "C" {
+            fn c_in_block();
+        }
+    }
 }
 
 mod issue12677 {
@@ -174,3 +189,18 @@ mod issue12677 {
         }
     }
 }
+
+mod with_ty_alias {
+    trait FooTrait {
+        type Foo: std::fmt::Debug;
+        fn bar(_: Self::Foo) {}
+    }
+    impl FooTrait for () {
+        type Foo = i32;
+    }
+    // NOTE: When checking the type of a function param, make sure it is not an alias with
+    // `AliasTyKind::Projection` before calling `TyCtxt::type_of` to find out what the actual type
+    // is. Because the associate ty could have no default, therefore would cause ICE, as demostrated
+    // in this test.
+    fn alias_ty_is_projection(bar: <() as FooTrait>::Foo) {}
+}
diff --git a/src/tools/clippy/tests/ui/missing_const_for_fn/could_be_const.stderr b/src/tools/clippy/tests/ui/missing_const_for_fn/could_be_const.stderr
index 8302b074127..fb4db703103 100644
--- a/src/tools/clippy/tests/ui/missing_const_for_fn/could_be_const.stderr
+++ b/src/tools/clippy/tests/ui/missing_const_for_fn/could_be_const.stderr
@@ -211,7 +211,29 @@ LL |     const fn union_access_can_be_const() {
    |     +++++
 
 error: this could be a `const fn`
-  --> tests/ui/missing_const_for_fn/could_be_const.rs:155:9
+  --> tests/ui/missing_const_for_fn/could_be_const.rs:149:9
+   |
+LL |         extern "C" fn c() {}
+   |         ^^^^^^^^^^^^^^^^^^^^
+   |
+help: make the function `const`
+   |
+LL |         const extern "C" fn c() {}
+   |         +++++
+
+error: this could be a `const fn`
+  --> tests/ui/missing_const_for_fn/could_be_const.rs:153:9
+   |
+LL |         extern fn implicit_c() {}
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: make the function `const`
+   |
+LL |         const extern fn implicit_c() {}
+   |         +++++
+
+error: this could be a `const fn`
+  --> tests/ui/missing_const_for_fn/could_be_const.rs:170:9
    |
 LL | /         pub fn new(strings: Vec<String>) -> Self {
 LL | |             Self { strings }
@@ -224,7 +246,7 @@ LL |         pub const fn new(strings: Vec<String>) -> Self {
    |             +++++
 
 error: this could be a `const fn`
-  --> tests/ui/missing_const_for_fn/could_be_const.rs:160:9
+  --> tests/ui/missing_const_for_fn/could_be_const.rs:175:9
    |
 LL | /         pub fn empty() -> Self {
 LL | |             Self { strings: Vec::new() }
@@ -237,7 +259,7 @@ LL |         pub const fn empty() -> Self {
    |             +++++
 
 error: this could be a `const fn`
-  --> tests/ui/missing_const_for_fn/could_be_const.rs:171:9
+  --> tests/ui/missing_const_for_fn/could_be_const.rs:186:9
    |
 LL | /         pub fn new(text: String) -> Self {
 LL | |             let vec = Vec::new();
@@ -250,5 +272,16 @@ help: make the function `const`
 LL |         pub const fn new(text: String) -> Self {
    |             +++++
 
-error: aborting due to 18 previous errors
+error: this could be a `const fn`
+  --> tests/ui/missing_const_for_fn/could_be_const.rs:205:5
+   |
+LL |     fn alias_ty_is_projection(bar: <() as FooTrait>::Foo) {}
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: make the function `const`
+   |
+LL |     const fn alias_ty_is_projection(bar: <() as FooTrait>::Foo) {}
+   |     +++++
+
+error: aborting due to 21 previous errors
 
diff --git a/src/tools/clippy/tests/ui/missing_const_for_fn/could_be_const_with_const_extern_fn.fixed b/src/tools/clippy/tests/ui/missing_const_for_fn/could_be_const_with_const_extern_fn.fixed
new file mode 100644
index 00000000000..c103db536ab
--- /dev/null
+++ b/src/tools/clippy/tests/ui/missing_const_for_fn/could_be_const_with_const_extern_fn.fixed
@@ -0,0 +1,14 @@
+#![warn(clippy::missing_const_for_fn)]
+#![allow(unsupported_calling_conventions)]
+#![feature(const_extern_fn)]
+
+const extern "C-unwind" fn c_unwind() {}
+//~^ ERROR: this could be a `const fn`
+const extern "system" fn system() {}
+//~^ ERROR: this could be a `const fn`
+const extern "system-unwind" fn system_unwind() {}
+//~^ ERROR: this could be a `const fn`
+pub const extern "stdcall" fn std_call() {}
+//~^ ERROR: this could be a `const fn`
+pub const extern "stdcall-unwind" fn std_call_unwind() {}
+//~^ ERROR: this could be a `const fn`
diff --git a/src/tools/clippy/tests/ui/missing_const_for_fn/could_be_const_with_const_extern_fn.rs b/src/tools/clippy/tests/ui/missing_const_for_fn/could_be_const_with_const_extern_fn.rs
new file mode 100644
index 00000000000..0f7020ae559
--- /dev/null
+++ b/src/tools/clippy/tests/ui/missing_const_for_fn/could_be_const_with_const_extern_fn.rs
@@ -0,0 +1,14 @@
+#![warn(clippy::missing_const_for_fn)]
+#![allow(unsupported_calling_conventions)]
+#![feature(const_extern_fn)]
+
+extern "C-unwind" fn c_unwind() {}
+//~^ ERROR: this could be a `const fn`
+extern "system" fn system() {}
+//~^ ERROR: this could be a `const fn`
+extern "system-unwind" fn system_unwind() {}
+//~^ ERROR: this could be a `const fn`
+pub extern "stdcall" fn std_call() {}
+//~^ ERROR: this could be a `const fn`
+pub extern "stdcall-unwind" fn std_call_unwind() {}
+//~^ ERROR: this could be a `const fn`
diff --git a/src/tools/clippy/tests/ui/missing_const_for_fn/could_be_const_with_const_extern_fn.stderr b/src/tools/clippy/tests/ui/missing_const_for_fn/could_be_const_with_const_extern_fn.stderr
new file mode 100644
index 00000000000..036094a367b
--- /dev/null
+++ b/src/tools/clippy/tests/ui/missing_const_for_fn/could_be_const_with_const_extern_fn.stderr
@@ -0,0 +1,59 @@
+error: this could be a `const fn`
+  --> tests/ui/missing_const_for_fn/could_be_const_with_const_extern_fn.rs:5:1
+   |
+LL | extern "C-unwind" fn c_unwind() {}
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: `-D clippy::missing-const-for-fn` implied by `-D warnings`
+   = help: to override `-D warnings` add `#[allow(clippy::missing_const_for_fn)]`
+help: make the function `const`
+   |
+LL | const extern "C-unwind" fn c_unwind() {}
+   | +++++
+
+error: this could be a `const fn`
+  --> tests/ui/missing_const_for_fn/could_be_const_with_const_extern_fn.rs:7:1
+   |
+LL | extern "system" fn system() {}
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: make the function `const`
+   |
+LL | const extern "system" fn system() {}
+   | +++++
+
+error: this could be a `const fn`
+  --> tests/ui/missing_const_for_fn/could_be_const_with_const_extern_fn.rs:9:1
+   |
+LL | extern "system-unwind" fn system_unwind() {}
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: make the function `const`
+   |
+LL | const extern "system-unwind" fn system_unwind() {}
+   | +++++
+
+error: this could be a `const fn`
+  --> tests/ui/missing_const_for_fn/could_be_const_with_const_extern_fn.rs:11:1
+   |
+LL | pub extern "stdcall" fn std_call() {}
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: make the function `const`
+   |
+LL | pub const extern "stdcall" fn std_call() {}
+   |     +++++
+
+error: this could be a `const fn`
+  --> tests/ui/missing_const_for_fn/could_be_const_with_const_extern_fn.rs:13:1
+   |
+LL | pub extern "stdcall-unwind" fn std_call_unwind() {}
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: make the function `const`
+   |
+LL | pub const extern "stdcall-unwind" fn std_call_unwind() {}
+   |     +++++
+
+error: aborting due to 5 previous errors
+
diff --git a/src/tools/clippy/tests/ui/thread_local_initializer_can_be_made_const.fixed b/src/tools/clippy/tests/ui/missing_const_for_thread_local.fixed
index 4c9bd0bd863..90b31b9b5d2 100644
--- a/src/tools/clippy/tests/ui/thread_local_initializer_can_be_made_const.fixed
+++ b/src/tools/clippy/tests/ui/missing_const_for_thread_local.fixed
@@ -1,4 +1,4 @@
-#![warn(clippy::thread_local_initializer_can_be_made_const)]
+#![warn(clippy::missing_const_for_thread_local)]
 
 use std::cell::{Cell, RefCell};
 
diff --git a/src/tools/clippy/tests/ui/thread_local_initializer_can_be_made_const.rs b/src/tools/clippy/tests/ui/missing_const_for_thread_local.rs
index eb336f0dd19..f97e4848fd7 100644
--- a/src/tools/clippy/tests/ui/thread_local_initializer_can_be_made_const.rs
+++ b/src/tools/clippy/tests/ui/missing_const_for_thread_local.rs
@@ -1,4 +1,4 @@
-#![warn(clippy::thread_local_initializer_can_be_made_const)]
+#![warn(clippy::missing_const_for_thread_local)]
 
 use std::cell::{Cell, RefCell};
 
diff --git a/src/tools/clippy/tests/ui/thread_local_initializer_can_be_made_const.stderr b/src/tools/clippy/tests/ui/missing_const_for_thread_local.stderr
index b4f8bd822b0..c143a37454f 100644
--- a/src/tools/clippy/tests/ui/thread_local_initializer_can_be_made_const.stderr
+++ b/src/tools/clippy/tests/ui/missing_const_for_thread_local.stderr
@@ -1,38 +1,38 @@
 error: initializer for `thread_local` value can be made `const`
-  --> tests/ui/thread_local_initializer_can_be_made_const.rs:8:41
+  --> tests/ui/missing_const_for_thread_local.rs:8:41
    |
 LL |         static BUF_1: RefCell<String> = RefCell::new(String::new());
    |                                         ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `const { RefCell::new(String::new()) }`
    |
-   = note: `-D clippy::thread-local-initializer-can-be-made-const` implied by `-D warnings`
-   = help: to override `-D warnings` add `#[allow(clippy::thread_local_initializer_can_be_made_const)]`
+   = note: `-D clippy::missing-const-for-thread-local` implied by `-D warnings`
+   = help: to override `-D warnings` add `#[allow(clippy::missing_const_for_thread_local)]`
 
 error: initializer for `thread_local` value can be made `const`
-  --> tests/ui/thread_local_initializer_can_be_made_const.rs:18:29
+  --> tests/ui/missing_const_for_thread_local.rs:18:29
    |
 LL |         static SIMPLE:i32 = 1;
    |                             ^ help: replace with: `const { 1 }`
 
 error: initializer for `thread_local` value can be made `const`
-  --> tests/ui/thread_local_initializer_can_be_made_const.rs:24:59
+  --> tests/ui/missing_const_for_thread_local.rs:24:59
    |
 LL |         static BUF_3_CAN_BE_MADE_CONST: RefCell<String> = RefCell::new(String::new());
    |                                                           ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `const { RefCell::new(String::new()) }`
 
 error: initializer for `thread_local` value can be made `const`
-  --> tests/ui/thread_local_initializer_can_be_made_const.rs:26:59
+  --> tests/ui/missing_const_for_thread_local.rs:26:59
    |
 LL |         static BUF_4_CAN_BE_MADE_CONST: RefCell<String> = RefCell::new(String::new());
    |                                                           ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `const { RefCell::new(String::new()) }`
 
 error: initializer for `thread_local` value can be made `const`
-  --> tests/ui/thread_local_initializer_can_be_made_const.rs:32:31
+  --> tests/ui/missing_const_for_thread_local.rs:32:31
    |
 LL |         static PEEL_ME: i32 = { 1 };
    |                               ^^^^^ help: replace with: `const { 1 }`
 
 error: initializer for `thread_local` value can be made `const`
-  --> tests/ui/thread_local_initializer_can_be_made_const.rs:34:36
+  --> tests/ui/missing_const_for_thread_local.rs:34:36
    |
 LL |         static PEEL_ME_MANY: i32 = { let x = 1; x * x };
    |                                    ^^^^^^^^^^^^^^^^^^^^ help: replace with: `const { { let x = 1; x * x } }`
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 eee62122fdf..162ec82aede 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
@@ -232,43 +232,48 @@ async fn async_vec2(b: &mut Vec<bool>) {
 }
 fn non_mut(n: &str) {}
 //Should warn
-pub async fn call_in_closure1(n: &mut str) {
+async fn call_in_closure1(n: &mut str) {
     (|| non_mut(n))()
 }
 fn str_mut(str: &mut String) -> bool {
     str.pop().is_some()
 }
 //Should not warn
-pub async fn call_in_closure2(str: &mut String) {
+async fn call_in_closure2(str: &mut String) {
     (|| str_mut(str))();
 }
 
 // Should not warn.
-pub async fn closure(n: &mut usize) -> impl '_ + FnMut() {
+async fn closure(n: &mut usize) -> impl '_ + FnMut() {
     || {
         *n += 1;
     }
 }
 
 // Should warn.
-pub fn closure2(n: &mut usize) -> impl '_ + FnMut() -> usize {
+fn closure2(n: &mut usize) -> impl '_ + FnMut() -> usize {
     //~^ ERROR: this argument is a mutable reference, but not used mutably
     || *n + 1
 }
 
 // Should not warn.
-pub async fn closure3(n: &mut usize) {
+async fn closure3(n: &mut usize) {
     (|| *n += 1)();
 }
 
 // Should warn.
-pub async fn closure4(n: &mut usize) {
+async fn closure4(n: &mut usize) {
     //~^ ERROR: this argument is a mutable reference, but not used mutably
     (|| {
         let _x = *n + 1;
     })();
 }
 
+// Should not warn: pub
+pub fn pub_foo(s: &mut Vec<u32>, b: &u32, x: &mut u32) {
+    *x += *b + s.len() as u32;
+}
+
 // Should not warn.
 async fn _f(v: &mut Vec<()>) {
     let x = || v.pop();
@@ -365,4 +370,5 @@ fn main() {
     used_as_path;
     let _: fn(&mut u32) = passed_as_local;
     let _ = if v[0] == 0 { ty_unify_1 } else { ty_unify_2 };
+    pub_foo(&mut v, &0, &mut u);
 }
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 51e3ba37ded..f462fa9099e 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
@@ -108,109 +108,103 @@ 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:235:34
+  --> tests/ui/needless_pass_by_ref_mut.rs:235:30
    |
-LL | pub async fn call_in_closure1(n: &mut str) {
-   |                                  ^^^^^^^^ help: consider changing to: `&str`
-   |
-   = warning: changing this function will impact semver compatibility
+LL | async fn call_in_closure1(n: &mut str) {
+   |                              ^^^^^^^^ help: consider changing to: `&str`
 
 error: this argument is a mutable reference, but not used mutably
-  --> tests/ui/needless_pass_by_ref_mut.rs:254:20
-   |
-LL | pub fn closure2(n: &mut usize) -> impl '_ + FnMut() -> usize {
-   |                    ^^^^^^^^^^ help: consider changing to: `&usize`
+  --> tests/ui/needless_pass_by_ref_mut.rs:254:16
    |
-   = warning: changing this function will impact semver compatibility
+LL | fn closure2(n: &mut usize) -> impl '_ + FnMut() -> usize {
+   |                ^^^^^^^^^^ help: consider changing to: `&usize`
 
 error: this argument is a mutable reference, but not used mutably
-  --> tests/ui/needless_pass_by_ref_mut.rs:265:26
-   |
-LL | pub async fn closure4(n: &mut usize) {
-   |                          ^^^^^^^^^^ help: consider changing to: `&usize`
+  --> tests/ui/needless_pass_by_ref_mut.rs:265:22
    |
-   = warning: changing this function will impact semver compatibility
+LL | async fn closure4(n: &mut usize) {
+   |                      ^^^^^^^^^^ help: consider changing to: `&usize`
 
 error: this argument is a mutable reference, but not used mutably
-  --> tests/ui/needless_pass_by_ref_mut.rs:314:12
+  --> tests/ui/needless_pass_by_ref_mut.rs:319: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:316:18
+  --> tests/ui/needless_pass_by_ref_mut.rs:321: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:316:45
+  --> tests/ui/needless_pass_by_ref_mut.rs:321: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:324:46
+  --> tests/ui/needless_pass_by_ref_mut.rs:329: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:340:18
+  --> tests/ui/needless_pass_by_ref_mut.rs:345: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:341:19
+  --> tests/ui/needless_pass_by_ref_mut.rs:346: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:342:18
+  --> tests/ui/needless_pass_by_ref_mut.rs:347: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:343:11
+  --> tests/ui/needless_pass_by_ref_mut.rs:348: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:345:23
+  --> tests/ui/needless_pass_by_ref_mut.rs:350: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:346:20
+  --> tests/ui/needless_pass_by_ref_mut.rs:351: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:347:18
+  --> tests/ui/needless_pass_by_ref_mut.rs:352: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:348:25
+  --> tests/ui/needless_pass_by_ref_mut.rs:353: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:349:20
+  --> tests/ui/needless_pass_by_ref_mut.rs:354: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:350:20
+  --> tests/ui/needless_pass_by_ref_mut.rs:355:20
    |
 LL | fn _fn_with_ret(x: &mut unsafe extern "C" fn() -> (i32)) {}
    |                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider changing to: `&unsafe extern "C" fn() -> (i32)`
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
index 3c2576213cd..f26b39ea6a1 100644
--- a/src/tools/clippy/tests/ui/needless_pass_by_ref_mut2.fixed
+++ b/src/tools/clippy/tests/ui/needless_pass_by_ref_mut2.fixed
@@ -5,7 +5,7 @@
 #![allow(clippy::redundant_closure_call)]
 #![warn(clippy::needless_pass_by_ref_mut)]
 
-pub async fn inner_async3(x: &i32, y: &mut u32) {
+async fn inner_async3(x: &i32, y: &mut u32) {
     //~^ ERROR: this argument is a mutable reference, but not used mutably
     async {
         *y += 1;
@@ -13,7 +13,7 @@ pub async fn inner_async3(x: &i32, y: &mut u32) {
     .await;
 }
 
-pub async fn inner_async4(u: &mut i32, v: &u32) {
+async fn inner_async4(u: &mut i32, v: &u32) {
     //~^ ERROR: this argument is a mutable reference, but not used mutably
     async {
         *u += 1;
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
index 34b0b564deb..4220215b1fe 100644
--- a/src/tools/clippy/tests/ui/needless_pass_by_ref_mut2.rs
+++ b/src/tools/clippy/tests/ui/needless_pass_by_ref_mut2.rs
@@ -5,7 +5,7 @@
 #![allow(clippy::redundant_closure_call)]
 #![warn(clippy::needless_pass_by_ref_mut)]
 
-pub async fn inner_async3(x: &mut i32, y: &mut u32) {
+async fn inner_async3(x: &mut i32, y: &mut u32) {
     //~^ ERROR: this argument is a mutable reference, but not used mutably
     async {
         *y += 1;
@@ -13,7 +13,7 @@ pub async fn inner_async3(x: &mut i32, y: &mut u32) {
     .await;
 }
 
-pub async fn inner_async4(u: &mut i32, v: &mut u32) {
+async fn inner_async4(u: &mut i32, v: &mut u32) {
     //~^ ERROR: this argument is a mutable reference, but not used mutably
     async {
         *u += 1;
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
index c8753603225..1c0136cf5d5 100644
--- a/src/tools/clippy/tests/ui/needless_pass_by_ref_mut2.stderr
+++ b/src/tools/clippy/tests/ui/needless_pass_by_ref_mut2.stderr
@@ -1,20 +1,17 @@
 error: this argument is a mutable reference, but not used mutably
-  --> tests/ui/needless_pass_by_ref_mut2.rs:8:30
+  --> tests/ui/needless_pass_by_ref_mut2.rs:8:26
    |
-LL | pub async fn inner_async3(x: &mut i32, y: &mut u32) {
-   |                              ^^^^^^^^ help: consider changing to: `&i32`
+LL | 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
+  --> tests/ui/needless_pass_by_ref_mut2.rs:16:39
    |
-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
+LL | async fn inner_async4(u: &mut i32, v: &mut u32) {
+   |                                       ^^^^^^^^ help: consider changing to: `&u32`
 
 error: aborting due to 2 previous errors
 
diff --git a/src/tools/clippy/tests/ui/needless_return.fixed b/src/tools/clippy/tests/ui/needless_return.fixed
index 853f685f04c..fc4129e1db8 100644
--- a/src/tools/clippy/tests/ui/needless_return.fixed
+++ b/src/tools/clippy/tests/ui/needless_return.fixed
@@ -228,12 +228,41 @@ fn needless_return_macro() -> String {
     format!("Hello {}", "world!")
 }
 
-fn issue_9361() -> i32 {
-    let n = 1;
-    #[allow(clippy::arithmetic_side_effects)]
+fn issue_9361(n: i32) -> i32 {
+    #[expect(clippy::arithmetic_side_effects)]
     return n + n;
 }
 
+mod issue_12998 {
+    fn expect_lint() -> i32 {
+        let x = 1;
+
+        #[expect(clippy::needless_return)]
+        return x;
+    }
+
+    fn expect_group() -> i32 {
+        let x = 1;
+
+        #[expect(clippy::style)]
+        return x;
+    }
+
+    fn expect_all() -> i32 {
+        let x = 1;
+
+        #[expect(clippy::all)]
+        return x;
+    }
+
+    fn expect_warnings() -> i32 {
+        let x = 1;
+
+        #[expect(warnings)]
+        return x;
+    }
+}
+
 fn issue8336(x: i32) -> bool {
     if x > 0 {
         println!("something");
diff --git a/src/tools/clippy/tests/ui/needless_return.rs b/src/tools/clippy/tests/ui/needless_return.rs
index e9c1e0e8ae8..61c7a02008f 100644
--- a/src/tools/clippy/tests/ui/needless_return.rs
+++ b/src/tools/clippy/tests/ui/needless_return.rs
@@ -236,12 +236,41 @@ fn needless_return_macro() -> String {
     return format!("Hello {}", "world!");
 }
 
-fn issue_9361() -> i32 {
-    let n = 1;
-    #[allow(clippy::arithmetic_side_effects)]
+fn issue_9361(n: i32) -> i32 {
+    #[expect(clippy::arithmetic_side_effects)]
     return n + n;
 }
 
+mod issue_12998 {
+    fn expect_lint() -> i32 {
+        let x = 1;
+
+        #[expect(clippy::needless_return)]
+        return x;
+    }
+
+    fn expect_group() -> i32 {
+        let x = 1;
+
+        #[expect(clippy::style)]
+        return x;
+    }
+
+    fn expect_all() -> i32 {
+        let x = 1;
+
+        #[expect(clippy::all)]
+        return x;
+    }
+
+    fn expect_warnings() -> i32 {
+        let x = 1;
+
+        #[expect(warnings)]
+        return x;
+    }
+}
+
 fn issue8336(x: i32) -> bool {
     if x > 0 {
         println!("something");
diff --git a/src/tools/clippy/tests/ui/needless_return.stderr b/src/tools/clippy/tests/ui/needless_return.stderr
index 6c891fe7ad3..ea9c230eafd 100644
--- a/src/tools/clippy/tests/ui/needless_return.stderr
+++ b/src/tools/clippy/tests/ui/needless_return.stderr
@@ -483,7 +483,7 @@ LL +     format!("Hello {}", "world!")
    |
 
 error: unneeded `return` statement
-  --> tests/ui/needless_return.rs:248:9
+  --> tests/ui/needless_return.rs:277:9
    |
 LL |         return true;
    |         ^^^^^^^^^^^
@@ -497,7 +497,7 @@ LL ~     }
    |
 
 error: unneeded `return` statement
-  --> tests/ui/needless_return.rs:250:9
+  --> tests/ui/needless_return.rs:279:9
    |
 LL |         return false;
    |         ^^^^^^^^^^^^
@@ -509,7 +509,7 @@ LL ~     }
    |
 
 error: unneeded `return` statement
-  --> tests/ui/needless_return.rs:257:13
+  --> tests/ui/needless_return.rs:286:13
    |
 LL |             return 10;
    |             ^^^^^^^^^
@@ -524,7 +524,7 @@ LL ~     }
    |
 
 error: unneeded `return` statement
-  --> tests/ui/needless_return.rs:260:13
+  --> tests/ui/needless_return.rs:289:13
    |
 LL |             return 100;
    |             ^^^^^^^^^^
@@ -537,7 +537,7 @@ LL ~     }
    |
 
 error: unneeded `return` statement
-  --> tests/ui/needless_return.rs:268:9
+  --> tests/ui/needless_return.rs:297:9
    |
 LL |         return 0;
    |         ^^^^^^^^
@@ -549,7 +549,7 @@ LL ~     }
    |
 
 error: unneeded `return` statement
-  --> tests/ui/needless_return.rs:275:13
+  --> tests/ui/needless_return.rs:304:13
    |
 LL |             return *(x as *const isize);
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -564,7 +564,7 @@ LL ~     }
    |
 
 error: unneeded `return` statement
-  --> tests/ui/needless_return.rs:277:13
+  --> tests/ui/needless_return.rs:306:13
    |
 LL |             return !*(x as *const isize);
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -577,7 +577,7 @@ LL ~     }
    |
 
 error: unneeded `return` statement
-  --> tests/ui/needless_return.rs:284:20
+  --> tests/ui/needless_return.rs:313:20
    |
 LL |           let _ = 42;
    |  ____________________^
@@ -594,7 +594,7 @@ LL +         let _ = 42;
    |
 
 error: unneeded `return` statement
-  --> tests/ui/needless_return.rs:291:20
+  --> tests/ui/needless_return.rs:320:20
    |
 LL |         let _ = 42; return;
    |                    ^^^^^^^
@@ -606,7 +606,7 @@ LL +         let _ = 42;
    |
 
 error: unneeded `return` statement
-  --> tests/ui/needless_return.rs:303:9
+  --> tests/ui/needless_return.rs:332:9
    |
 LL |         return Ok(format!("ok!"));
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -618,7 +618,7 @@ LL +         Ok(format!("ok!"))
    |
 
 error: unneeded `return` statement
-  --> tests/ui/needless_return.rs:305:9
+  --> tests/ui/needless_return.rs:334:9
    |
 LL |         return Err(format!("err!"));
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -630,7 +630,7 @@ LL +         Err(format!("err!"))
    |
 
 error: unneeded `return` statement
-  --> tests/ui/needless_return.rs:311:9
+  --> tests/ui/needless_return.rs:340:9
    |
 LL |         return if true { 1 } else { 2 };
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -642,7 +642,7 @@ LL +         if true { 1 } else { 2 }
    |
 
 error: unneeded `return` statement
-  --> tests/ui/needless_return.rs:315:9
+  --> tests/ui/needless_return.rs:344:9
    |
 LL |         return if b1 { 0 } else { 1 } | if b2 { 2 } else { 3 } | if b3 { 4 } else { 5 };
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -654,7 +654,7 @@ LL +         (if b1 { 0 } else { 1 } | if b2 { 2 } else { 3 } | if b3 { 4 } else
    |
 
 error: unneeded `return` statement
-  --> tests/ui/needless_return.rs:336:5
+  --> tests/ui/needless_return.rs:365:5
    |
 LL |     return { "a".to_string() } + "b" + { "c" };
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
diff --git a/src/tools/clippy/tests/ui/overflow_check_conditional.rs b/src/tools/clippy/tests/ui/overflow_check_conditional.rs
deleted file mode 100644
index a70bb3bc47b..00000000000
--- a/src/tools/clippy/tests/ui/overflow_check_conditional.rs
+++ /dev/null
@@ -1,36 +0,0 @@
-#![warn(clippy::overflow_check_conditional)]
-#![allow(clippy::needless_if)]
-
-fn test(a: u32, b: u32, c: u32) {
-    if a + b < a {}
-    //~^ ERROR: you are trying to use classic C overflow conditions that will fail in Rust
-    //~| NOTE: `-D clippy::overflow-check-conditional` implied by `-D warnings`
-    if a > a + b {}
-    //~^ ERROR: you are trying to use classic C overflow conditions that will fail in Rust
-    if a + b < b {}
-    //~^ ERROR: you are trying to use classic C overflow conditions that will fail in Rust
-    if b > a + b {}
-    //~^ ERROR: you are trying to use classic C overflow conditions that will fail in Rust
-    if a - b > b {}
-    //~^ ERROR: you are trying to use classic C underflow conditions that will fail in Rus
-    if b < a - b {}
-    //~^ ERROR: you are trying to use classic C underflow conditions that will fail in Rus
-    if a - b > a {}
-    //~^ ERROR: you are trying to use classic C underflow conditions that will fail in Rus
-    if a < a - b {}
-    //~^ ERROR: you are trying to use classic C underflow conditions that will fail in Rus
-    if a + b < c {}
-    if c > a + b {}
-    if a - b < c {}
-    if c > a - b {}
-    let i = 1.1;
-    let j = 2.2;
-    if i + j < i {}
-    if i - j < i {}
-    if i > i + j {}
-    if i - j < i {}
-}
-
-fn main() {
-    test(1, 2, 3)
-}
diff --git a/src/tools/clippy/tests/ui/overflow_check_conditional.stderr b/src/tools/clippy/tests/ui/overflow_check_conditional.stderr
deleted file mode 100644
index c14532bad5a..00000000000
--- a/src/tools/clippy/tests/ui/overflow_check_conditional.stderr
+++ /dev/null
@@ -1,53 +0,0 @@
-error: you are trying to use classic C overflow conditions that will fail in Rust
-  --> tests/ui/overflow_check_conditional.rs:5:8
-   |
-LL |     if a + b < a {}
-   |        ^^^^^^^^^
-   |
-   = note: `-D clippy::overflow-check-conditional` implied by `-D warnings`
-   = help: to override `-D warnings` add `#[allow(clippy::overflow_check_conditional)]`
-
-error: you are trying to use classic C overflow conditions that will fail in Rust
-  --> tests/ui/overflow_check_conditional.rs:8:8
-   |
-LL |     if a > a + b {}
-   |        ^^^^^^^^^
-
-error: you are trying to use classic C overflow conditions that will fail in Rust
-  --> tests/ui/overflow_check_conditional.rs:10:8
-   |
-LL |     if a + b < b {}
-   |        ^^^^^^^^^
-
-error: you are trying to use classic C overflow conditions that will fail in Rust
-  --> tests/ui/overflow_check_conditional.rs:12:8
-   |
-LL |     if b > a + b {}
-   |        ^^^^^^^^^
-
-error: you are trying to use classic C underflow conditions that will fail in Rust
-  --> tests/ui/overflow_check_conditional.rs:14:8
-   |
-LL |     if a - b > b {}
-   |        ^^^^^^^^^
-
-error: you are trying to use classic C underflow conditions that will fail in Rust
-  --> tests/ui/overflow_check_conditional.rs:16:8
-   |
-LL |     if b < a - b {}
-   |        ^^^^^^^^^
-
-error: you are trying to use classic C underflow conditions that will fail in Rust
-  --> tests/ui/overflow_check_conditional.rs:18:8
-   |
-LL |     if a - b > a {}
-   |        ^^^^^^^^^
-
-error: you are trying to use classic C underflow conditions that will fail in Rust
-  --> tests/ui/overflow_check_conditional.rs:20:8
-   |
-LL |     if a < a - b {}
-   |        ^^^^^^^^^
-
-error: aborting due to 8 previous errors
-
diff --git a/src/tools/clippy/tests/ui/panicking_overflow_checks.rs b/src/tools/clippy/tests/ui/panicking_overflow_checks.rs
new file mode 100644
index 00000000000..dc2ddeada1e
--- /dev/null
+++ b/src/tools/clippy/tests/ui/panicking_overflow_checks.rs
@@ -0,0 +1,27 @@
+#![warn(clippy::panicking_overflow_checks)]
+#![allow(clippy::needless_if)]
+
+fn test(a: u32, b: u32, c: u32) {
+    if a + b < a {} //~ panicking_overflow_checks
+    if a > a + b {} //~ panicking_overflow_checks
+    if a + b < b {} //~ panicking_overflow_checks
+    if b > a + b {} //~ panicking_overflow_checks
+    if a - b > b {}
+    if b < a - b {}
+    if a - b > a {} //~ panicking_overflow_checks
+    if a < a - b {} //~ panicking_overflow_checks
+    if a + b < c {}
+    if c > a + b {}
+    if a - b < c {}
+    if c > a - b {}
+    let i = 1.1;
+    let j = 2.2;
+    if i + j < i {}
+    if i - j < i {}
+    if i > i + j {}
+    if i - j < i {}
+}
+
+fn main() {
+    test(1, 2, 3)
+}
diff --git a/src/tools/clippy/tests/ui/panicking_overflow_checks.stderr b/src/tools/clippy/tests/ui/panicking_overflow_checks.stderr
new file mode 100644
index 00000000000..1fae0457889
--- /dev/null
+++ b/src/tools/clippy/tests/ui/panicking_overflow_checks.stderr
@@ -0,0 +1,41 @@
+error: you are trying to use classic C overflow conditions that will fail in Rust
+  --> tests/ui/panicking_overflow_checks.rs:5:8
+   |
+LL |     if a + b < a {}
+   |        ^^^^^^^^^
+   |
+   = note: `-D clippy::panicking-overflow-checks` implied by `-D warnings`
+   = help: to override `-D warnings` add `#[allow(clippy::panicking_overflow_checks)]`
+
+error: you are trying to use classic C overflow conditions that will fail in Rust
+  --> tests/ui/panicking_overflow_checks.rs:6:8
+   |
+LL |     if a > a + b {}
+   |        ^^^^^^^^^
+
+error: you are trying to use classic C overflow conditions that will fail in Rust
+  --> tests/ui/panicking_overflow_checks.rs:7:8
+   |
+LL |     if a + b < b {}
+   |        ^^^^^^^^^
+
+error: you are trying to use classic C overflow conditions that will fail in Rust
+  --> tests/ui/panicking_overflow_checks.rs:8:8
+   |
+LL |     if b > a + b {}
+   |        ^^^^^^^^^
+
+error: you are trying to use classic C overflow conditions that will fail in Rust
+  --> tests/ui/panicking_overflow_checks.rs:11:8
+   |
+LL |     if a - b > a {}
+   |        ^^^^^^^^^
+
+error: you are trying to use classic C overflow conditions that will fail in Rust
+  --> tests/ui/panicking_overflow_checks.rs:12:8
+   |
+LL |     if a < a - b {}
+   |        ^^^^^^^^^
+
+error: aborting due to 6 previous errors
+
diff --git a/src/tools/clippy/tests/ui/ptr_as_ptr.stderr b/src/tools/clippy/tests/ui/ptr_as_ptr.stderr
index e162f35baf5..18462620b0a 100644
--- a/src/tools/clippy/tests/ui/ptr_as_ptr.stderr
+++ b/src/tools/clippy/tests/ui/ptr_as_ptr.stderr
@@ -1,4 +1,4 @@
-error: `as` casting between raw pointers without changing its mutability
+error: `as` casting between raw pointers without changing their constness
   --> tests/ui/ptr_as_ptr.rs:18:33
    |
 LL |         *unsafe { Box::from_raw(Box::into_raw(Box::new(o)) as *mut super::issue_11278_a::T<String>) }
@@ -7,37 +7,37 @@ LL |         *unsafe { Box::from_raw(Box::into_raw(Box::new(o)) as *mut super::i
    = note: `-D clippy::ptr-as-ptr` implied by `-D warnings`
    = help: to override `-D warnings` add `#[allow(clippy::ptr_as_ptr)]`
 
-error: `as` casting between raw pointers without changing its mutability
+error: `as` casting between raw pointers without changing their constness
   --> tests/ui/ptr_as_ptr.rs:27:13
    |
 LL |     let _ = ptr as *const i32;
    |             ^^^^^^^^^^^^^^^^^ help: try `pointer::cast`, a safer alternative: `ptr.cast::<i32>()`
 
-error: `as` casting between raw pointers without changing its mutability
+error: `as` casting between raw pointers without changing their constness
   --> tests/ui/ptr_as_ptr.rs:28:13
    |
 LL |     let _ = mut_ptr as *mut i32;
    |             ^^^^^^^^^^^^^^^^^^^ help: try `pointer::cast`, a safer alternative: `mut_ptr.cast::<i32>()`
 
-error: `as` casting between raw pointers without changing its mutability
+error: `as` casting between raw pointers without changing their constness
   --> tests/ui/ptr_as_ptr.rs:33:17
    |
 LL |         let _ = *ptr_ptr as *const i32;
    |                 ^^^^^^^^^^^^^^^^^^^^^^ help: try `pointer::cast`, a safer alternative: `(*ptr_ptr).cast::<i32>()`
 
-error: `as` casting between raw pointers without changing its mutability
+error: `as` casting between raw pointers without changing their constness
   --> tests/ui/ptr_as_ptr.rs:46:25
    |
 LL |     let _: *const i32 = ptr as *const _;
    |                         ^^^^^^^^^^^^^^^ help: try `pointer::cast`, a safer alternative: `ptr.cast()`
 
-error: `as` casting between raw pointers without changing its mutability
+error: `as` casting between raw pointers without changing their constness
   --> tests/ui/ptr_as_ptr.rs:47:23
    |
 LL |     let _: *mut i32 = mut_ptr as _;
    |                       ^^^^^^^^^^^^ help: try `pointer::cast`, a safer alternative: `mut_ptr.cast()`
 
-error: `as` casting between raw pointers without changing its mutability
+error: `as` casting between raw pointers without changing their constness
   --> tests/ui/ptr_as_ptr.rs:50:21
    |
 LL |     let _ = inline!($ptr as *const i32);
@@ -45,157 +45,157 @@ LL |     let _ = inline!($ptr as *const i32);
    |
    = note: this error originates in the macro `__inline_mac_fn_main` (in Nightly builds, run with -Z macro-backtrace for more info)
 
-error: `as` casting between raw pointers without changing its mutability
+error: `as` casting between raw pointers without changing their constness
   --> tests/ui/ptr_as_ptr.rs:71:13
    |
 LL |     let _ = ptr as *const i32;
    |             ^^^^^^^^^^^^^^^^^ help: try `pointer::cast`, a safer alternative: `ptr.cast::<i32>()`
 
-error: `as` casting between raw pointers without changing its mutability
+error: `as` casting between raw pointers without changing their constness
   --> tests/ui/ptr_as_ptr.rs:72:13
    |
 LL |     let _ = mut_ptr as *mut i32;
    |             ^^^^^^^^^^^^^^^^^^^ help: try `pointer::cast`, a safer alternative: `mut_ptr.cast::<i32>()`
 
-error: `as` casting between raw pointers without changing its mutability
+error: `as` casting between raw pointers without changing their constness
   --> tests/ui/ptr_as_ptr.rs:79:9
    |
 LL |         ptr::null_mut() as *mut u32
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try call directly: `ptr::null_mut::<u32>()`
 
-error: `as` casting between raw pointers without changing its mutability
+error: `as` casting between raw pointers without changing their constness
   --> tests/ui/ptr_as_ptr.rs:83:9
    |
 LL |         std::ptr::null_mut() as *mut u32
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try call directly: `std::ptr::null_mut::<u32>()`
 
-error: `as` casting between raw pointers without changing its mutability
+error: `as` casting between raw pointers without changing their constness
   --> tests/ui/ptr_as_ptr.rs:88:9
    |
 LL |         ptr::null_mut() as *mut u32
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try call directly: `ptr::null_mut::<u32>()`
 
-error: `as` casting between raw pointers without changing its mutability
+error: `as` casting between raw pointers without changing their constness
   --> tests/ui/ptr_as_ptr.rs:92:9
    |
 LL |         core::ptr::null_mut() as *mut u32
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try call directly: `core::ptr::null_mut::<u32>()`
 
-error: `as` casting between raw pointers without changing its mutability
+error: `as` casting between raw pointers without changing their constness
   --> tests/ui/ptr_as_ptr.rs:97:9
    |
 LL |         ptr::null() as *const u32
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^ help: try call directly: `ptr::null::<u32>()`
 
-error: `as` casting between raw pointers without changing its mutability
+error: `as` casting between raw pointers without changing their constness
   --> tests/ui/ptr_as_ptr.rs:101:9
    |
 LL |         std::ptr::null() as *const u32
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try call directly: `std::ptr::null::<u32>()`
 
-error: `as` casting between raw pointers without changing its mutability
+error: `as` casting between raw pointers without changing their constness
   --> tests/ui/ptr_as_ptr.rs:106:9
    |
 LL |         ptr::null() as *const u32
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^ help: try call directly: `ptr::null::<u32>()`
 
-error: `as` casting between raw pointers without changing its mutability
+error: `as` casting between raw pointers without changing their constness
   --> tests/ui/ptr_as_ptr.rs:110:9
    |
 LL |         core::ptr::null() as *const u32
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try call directly: `core::ptr::null::<u32>()`
 
-error: `as` casting between raw pointers without changing its mutability
+error: `as` casting between raw pointers without changing their constness
   --> tests/ui/ptr_as_ptr.rs:117:9
    |
 LL |         ptr::null_mut() as *mut _
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^ help: try call directly: `ptr::null_mut()`
 
-error: `as` casting between raw pointers without changing its mutability
+error: `as` casting between raw pointers without changing their constness
   --> tests/ui/ptr_as_ptr.rs:121:9
    |
 LL |         std::ptr::null_mut() as *mut _
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try call directly: `std::ptr::null_mut()`
 
-error: `as` casting between raw pointers without changing its mutability
+error: `as` casting between raw pointers without changing their constness
   --> tests/ui/ptr_as_ptr.rs:126:9
    |
 LL |         ptr::null_mut() as *mut _
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^ help: try call directly: `ptr::null_mut()`
 
-error: `as` casting between raw pointers without changing its mutability
+error: `as` casting between raw pointers without changing their constness
   --> tests/ui/ptr_as_ptr.rs:130:9
    |
 LL |         core::ptr::null_mut() as *mut _
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try call directly: `core::ptr::null_mut()`
 
-error: `as` casting between raw pointers without changing its mutability
+error: `as` casting between raw pointers without changing their constness
   --> tests/ui/ptr_as_ptr.rs:135:9
    |
 LL |         ptr::null() as *const _
    |         ^^^^^^^^^^^^^^^^^^^^^^^ help: try call directly: `ptr::null()`
 
-error: `as` casting between raw pointers without changing its mutability
+error: `as` casting between raw pointers without changing their constness
   --> tests/ui/ptr_as_ptr.rs:139:9
    |
 LL |         std::ptr::null() as *const _
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try call directly: `std::ptr::null()`
 
-error: `as` casting between raw pointers without changing its mutability
+error: `as` casting between raw pointers without changing their constness
   --> tests/ui/ptr_as_ptr.rs:144:9
    |
 LL |         ptr::null() as *const _
    |         ^^^^^^^^^^^^^^^^^^^^^^^ help: try call directly: `ptr::null()`
 
-error: `as` casting between raw pointers without changing its mutability
+error: `as` casting between raw pointers without changing their constness
   --> tests/ui/ptr_as_ptr.rs:148:9
    |
 LL |         core::ptr::null() as *const _
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try call directly: `core::ptr::null()`
 
-error: `as` casting between raw pointers without changing its mutability
+error: `as` casting between raw pointers without changing their constness
   --> tests/ui/ptr_as_ptr.rs:155:9
    |
 LL |         ptr::null_mut() as _
    |         ^^^^^^^^^^^^^^^^^^^^ help: try call directly: `ptr::null_mut()`
 
-error: `as` casting between raw pointers without changing its mutability
+error: `as` casting between raw pointers without changing their constness
   --> tests/ui/ptr_as_ptr.rs:159:9
    |
 LL |         std::ptr::null_mut() as _
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^ help: try call directly: `std::ptr::null_mut()`
 
-error: `as` casting between raw pointers without changing its mutability
+error: `as` casting between raw pointers without changing their constness
   --> tests/ui/ptr_as_ptr.rs:164:9
    |
 LL |         ptr::null_mut() as _
    |         ^^^^^^^^^^^^^^^^^^^^ help: try call directly: `ptr::null_mut()`
 
-error: `as` casting between raw pointers without changing its mutability
+error: `as` casting between raw pointers without changing their constness
   --> tests/ui/ptr_as_ptr.rs:168:9
    |
 LL |         core::ptr::null_mut() as _
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try call directly: `core::ptr::null_mut()`
 
-error: `as` casting between raw pointers without changing its mutability
+error: `as` casting between raw pointers without changing their constness
   --> tests/ui/ptr_as_ptr.rs:173:9
    |
 LL |         ptr::null() as _
    |         ^^^^^^^^^^^^^^^^ help: try call directly: `ptr::null()`
 
-error: `as` casting between raw pointers without changing its mutability
+error: `as` casting between raw pointers without changing their constness
   --> tests/ui/ptr_as_ptr.rs:177:9
    |
 LL |         std::ptr::null() as _
    |         ^^^^^^^^^^^^^^^^^^^^^ help: try call directly: `std::ptr::null()`
 
-error: `as` casting between raw pointers without changing its mutability
+error: `as` casting between raw pointers without changing their constness
   --> tests/ui/ptr_as_ptr.rs:182:9
    |
 LL |         ptr::null() as _
    |         ^^^^^^^^^^^^^^^^ help: try call directly: `ptr::null()`
 
-error: `as` casting between raw pointers without changing its mutability
+error: `as` casting between raw pointers without changing their constness
   --> tests/ui/ptr_as_ptr.rs:186:9
    |
 LL |         core::ptr::null() as _
diff --git a/src/tools/clippy/tests/ui/rename.fixed b/src/tools/clippy/tests/ui/rename.fixed
index 24d0f797542..d70c9f8d06c 100644
--- a/src/tools/clippy/tests/ui/rename.fixed
+++ b/src/tools/clippy/tests/ui/rename.fixed
@@ -24,9 +24,11 @@
 #![allow(clippy::expect_used)]
 #![allow(clippy::map_unwrap_or)]
 #![allow(clippy::unwrap_used)]
+#![allow(clippy::panicking_overflow_checks)]
 #![allow(clippy::needless_borrow)]
 #![allow(clippy::single_char_add_str)]
 #![allow(clippy::module_name_repetitions)]
+#![allow(clippy::missing_const_for_thread_local)]
 #![allow(clippy::recursive_format_impl)]
 #![allow(clippy::unwrap_or_default)]
 #![allow(clippy::invisible_characters)]
@@ -77,12 +79,14 @@
 #![warn(clippy::map_unwrap_or)]
 #![warn(clippy::map_unwrap_or)]
 #![warn(clippy::unwrap_used)]
+#![warn(clippy::panicking_overflow_checks)]
 #![warn(clippy::needless_borrow)]
 #![warn(clippy::expect_used)]
 #![warn(clippy::map_unwrap_or)]
 #![warn(clippy::unwrap_used)]
 #![warn(clippy::single_char_add_str)]
 #![warn(clippy::module_name_repetitions)]
+#![warn(clippy::missing_const_for_thread_local)]
 #![warn(clippy::recursive_format_impl)]
 #![warn(clippy::unwrap_or_default)]
 #![warn(clippy::invisible_characters)]
diff --git a/src/tools/clippy/tests/ui/rename.rs b/src/tools/clippy/tests/ui/rename.rs
index be8da2fa1a3..8d0ac3c8f95 100644
--- a/src/tools/clippy/tests/ui/rename.rs
+++ b/src/tools/clippy/tests/ui/rename.rs
@@ -24,9 +24,11 @@
 #![allow(clippy::expect_used)]
 #![allow(clippy::map_unwrap_or)]
 #![allow(clippy::unwrap_used)]
+#![allow(clippy::panicking_overflow_checks)]
 #![allow(clippy::needless_borrow)]
 #![allow(clippy::single_char_add_str)]
 #![allow(clippy::module_name_repetitions)]
+#![allow(clippy::missing_const_for_thread_local)]
 #![allow(clippy::recursive_format_impl)]
 #![allow(clippy::unwrap_or_default)]
 #![allow(clippy::invisible_characters)]
@@ -77,12 +79,14 @@
 #![warn(clippy::option_map_unwrap_or)]
 #![warn(clippy::option_map_unwrap_or_else)]
 #![warn(clippy::option_unwrap_used)]
+#![warn(clippy::overflow_check_conditional)]
 #![warn(clippy::ref_in_deref)]
 #![warn(clippy::result_expect_used)]
 #![warn(clippy::result_map_unwrap_or_else)]
 #![warn(clippy::result_unwrap_used)]
 #![warn(clippy::single_char_push_str)]
 #![warn(clippy::stutter)]
+#![warn(clippy::thread_local_initializer_can_be_made_const)]
 #![warn(clippy::to_string_in_display)]
 #![warn(clippy::unwrap_or_else_default)]
 #![warn(clippy::zero_width_space)]
diff --git a/src/tools/clippy/tests/ui/rename.stderr b/src/tools/clippy/tests/ui/rename.stderr
index 777ac20153d..d6637324a03 100644
--- a/src/tools/clippy/tests/ui/rename.stderr
+++ b/src/tools/clippy/tests/ui/rename.stderr
@@ -1,5 +1,5 @@
 error: lint `clippy::almost_complete_letter_range` has been renamed to `clippy::almost_complete_range`
-  --> tests/ui/rename.rs:56:9
+  --> tests/ui/rename.rs:58:9
    |
 LL | #![warn(clippy::almost_complete_letter_range)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::almost_complete_range`
@@ -8,346 +8,358 @@ LL | #![warn(clippy::almost_complete_letter_range)]
    = help: to override `-D warnings` add `#[allow(renamed_and_removed_lints)]`
 
 error: lint `clippy::blacklisted_name` has been renamed to `clippy::disallowed_names`
-  --> tests/ui/rename.rs:57:9
+  --> tests/ui/rename.rs:59:9
    |
 LL | #![warn(clippy::blacklisted_name)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::disallowed_names`
 
 error: lint `clippy::block_in_if_condition_expr` has been renamed to `clippy::blocks_in_conditions`
-  --> tests/ui/rename.rs:58:9
+  --> tests/ui/rename.rs:60:9
    |
 LL | #![warn(clippy::block_in_if_condition_expr)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::blocks_in_conditions`
 
 error: lint `clippy::block_in_if_condition_stmt` has been renamed to `clippy::blocks_in_conditions`
-  --> tests/ui/rename.rs:59:9
+  --> tests/ui/rename.rs:61:9
    |
 LL | #![warn(clippy::block_in_if_condition_stmt)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::blocks_in_conditions`
 
 error: lint `clippy::blocks_in_if_conditions` has been renamed to `clippy::blocks_in_conditions`
-  --> tests/ui/rename.rs:60:9
+  --> tests/ui/rename.rs:62:9
    |
 LL | #![warn(clippy::blocks_in_if_conditions)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::blocks_in_conditions`
 
 error: lint `clippy::box_vec` has been renamed to `clippy::box_collection`
-  --> tests/ui/rename.rs:61:9
+  --> tests/ui/rename.rs:63:9
    |
 LL | #![warn(clippy::box_vec)]
    |         ^^^^^^^^^^^^^^^ help: use the new name: `clippy::box_collection`
 
 error: lint `clippy::const_static_lifetime` has been renamed to `clippy::redundant_static_lifetimes`
-  --> tests/ui/rename.rs:62:9
+  --> tests/ui/rename.rs:64:9
    |
 LL | #![warn(clippy::const_static_lifetime)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::redundant_static_lifetimes`
 
 error: lint `clippy::cyclomatic_complexity` has been renamed to `clippy::cognitive_complexity`
-  --> tests/ui/rename.rs:63:9
+  --> tests/ui/rename.rs:65:9
    |
 LL | #![warn(clippy::cyclomatic_complexity)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::cognitive_complexity`
 
 error: lint `clippy::derive_hash_xor_eq` has been renamed to `clippy::derived_hash_with_manual_eq`
-  --> tests/ui/rename.rs:64:9
+  --> tests/ui/rename.rs:66:9
    |
 LL | #![warn(clippy::derive_hash_xor_eq)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::derived_hash_with_manual_eq`
 
 error: lint `clippy::disallowed_method` has been renamed to `clippy::disallowed_methods`
-  --> tests/ui/rename.rs:65:9
+  --> tests/ui/rename.rs:67:9
    |
 LL | #![warn(clippy::disallowed_method)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::disallowed_methods`
 
 error: lint `clippy::disallowed_type` has been renamed to `clippy::disallowed_types`
-  --> tests/ui/rename.rs:66:9
+  --> tests/ui/rename.rs:68:9
    |
 LL | #![warn(clippy::disallowed_type)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::disallowed_types`
 
 error: lint `clippy::eval_order_dependence` has been renamed to `clippy::mixed_read_write_in_expression`
-  --> tests/ui/rename.rs:67:9
+  --> tests/ui/rename.rs:69:9
    |
 LL | #![warn(clippy::eval_order_dependence)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::mixed_read_write_in_expression`
 
 error: lint `clippy::identity_conversion` has been renamed to `clippy::useless_conversion`
-  --> tests/ui/rename.rs:68:9
+  --> tests/ui/rename.rs:70:9
    |
 LL | #![warn(clippy::identity_conversion)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::useless_conversion`
 
 error: lint `clippy::if_let_some_result` has been renamed to `clippy::match_result_ok`
-  --> tests/ui/rename.rs:69:9
+  --> tests/ui/rename.rs:71:9
    |
 LL | #![warn(clippy::if_let_some_result)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::match_result_ok`
 
 error: lint `clippy::incorrect_clone_impl_on_copy_type` has been renamed to `clippy::non_canonical_clone_impl`
-  --> tests/ui/rename.rs:70:9
+  --> tests/ui/rename.rs:72:9
    |
 LL | #![warn(clippy::incorrect_clone_impl_on_copy_type)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::non_canonical_clone_impl`
 
 error: lint `clippy::incorrect_partial_ord_impl_on_ord_type` has been renamed to `clippy::non_canonical_partial_ord_impl`
-  --> tests/ui/rename.rs:71:9
+  --> tests/ui/rename.rs:73:9
    |
 LL | #![warn(clippy::incorrect_partial_ord_impl_on_ord_type)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::non_canonical_partial_ord_impl`
 
 error: lint `clippy::integer_arithmetic` has been renamed to `clippy::arithmetic_side_effects`
-  --> tests/ui/rename.rs:72:9
+  --> tests/ui/rename.rs:74:9
    |
 LL | #![warn(clippy::integer_arithmetic)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::arithmetic_side_effects`
 
 error: lint `clippy::logic_bug` has been renamed to `clippy::overly_complex_bool_expr`
-  --> tests/ui/rename.rs:73:9
+  --> tests/ui/rename.rs:75:9
    |
 LL | #![warn(clippy::logic_bug)]
    |         ^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::overly_complex_bool_expr`
 
 error: lint `clippy::new_without_default_derive` has been renamed to `clippy::new_without_default`
-  --> tests/ui/rename.rs:74:9
+  --> tests/ui/rename.rs:76:9
    |
 LL | #![warn(clippy::new_without_default_derive)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::new_without_default`
 
 error: lint `clippy::option_and_then_some` has been renamed to `clippy::bind_instead_of_map`
-  --> tests/ui/rename.rs:75:9
+  --> tests/ui/rename.rs:77:9
    |
 LL | #![warn(clippy::option_and_then_some)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::bind_instead_of_map`
 
 error: lint `clippy::option_expect_used` has been renamed to `clippy::expect_used`
-  --> tests/ui/rename.rs:76:9
+  --> tests/ui/rename.rs:78:9
    |
 LL | #![warn(clippy::option_expect_used)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::expect_used`
 
 error: lint `clippy::option_map_unwrap_or` has been renamed to `clippy::map_unwrap_or`
-  --> tests/ui/rename.rs:77:9
+  --> tests/ui/rename.rs:79:9
    |
 LL | #![warn(clippy::option_map_unwrap_or)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::map_unwrap_or`
 
 error: lint `clippy::option_map_unwrap_or_else` has been renamed to `clippy::map_unwrap_or`
-  --> tests/ui/rename.rs:78:9
+  --> tests/ui/rename.rs:80:9
    |
 LL | #![warn(clippy::option_map_unwrap_or_else)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::map_unwrap_or`
 
 error: lint `clippy::option_unwrap_used` has been renamed to `clippy::unwrap_used`
-  --> tests/ui/rename.rs:79:9
+  --> tests/ui/rename.rs:81:9
    |
 LL | #![warn(clippy::option_unwrap_used)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::unwrap_used`
 
+error: lint `clippy::overflow_check_conditional` has been renamed to `clippy::panicking_overflow_checks`
+  --> tests/ui/rename.rs:82:9
+   |
+LL | #![warn(clippy::overflow_check_conditional)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::panicking_overflow_checks`
+
 error: lint `clippy::ref_in_deref` has been renamed to `clippy::needless_borrow`
-  --> tests/ui/rename.rs:80:9
+  --> tests/ui/rename.rs:83:9
    |
 LL | #![warn(clippy::ref_in_deref)]
    |         ^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::needless_borrow`
 
 error: lint `clippy::result_expect_used` has been renamed to `clippy::expect_used`
-  --> tests/ui/rename.rs:81:9
+  --> tests/ui/rename.rs:84:9
    |
 LL | #![warn(clippy::result_expect_used)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::expect_used`
 
 error: lint `clippy::result_map_unwrap_or_else` has been renamed to `clippy::map_unwrap_or`
-  --> tests/ui/rename.rs:82:9
+  --> tests/ui/rename.rs:85:9
    |
 LL | #![warn(clippy::result_map_unwrap_or_else)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::map_unwrap_or`
 
 error: lint `clippy::result_unwrap_used` has been renamed to `clippy::unwrap_used`
-  --> tests/ui/rename.rs:83:9
+  --> tests/ui/rename.rs:86:9
    |
 LL | #![warn(clippy::result_unwrap_used)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::unwrap_used`
 
 error: lint `clippy::single_char_push_str` has been renamed to `clippy::single_char_add_str`
-  --> tests/ui/rename.rs:84:9
+  --> tests/ui/rename.rs:87:9
    |
 LL | #![warn(clippy::single_char_push_str)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::single_char_add_str`
 
 error: lint `clippy::stutter` has been renamed to `clippy::module_name_repetitions`
-  --> tests/ui/rename.rs:85:9
+  --> tests/ui/rename.rs:88:9
    |
 LL | #![warn(clippy::stutter)]
    |         ^^^^^^^^^^^^^^^ help: use the new name: `clippy::module_name_repetitions`
 
+error: lint `clippy::thread_local_initializer_can_be_made_const` has been renamed to `clippy::missing_const_for_thread_local`
+  --> tests/ui/rename.rs:89:9
+   |
+LL | #![warn(clippy::thread_local_initializer_can_be_made_const)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::missing_const_for_thread_local`
+
 error: lint `clippy::to_string_in_display` has been renamed to `clippy::recursive_format_impl`
-  --> tests/ui/rename.rs:86:9
+  --> tests/ui/rename.rs:90:9
    |
 LL | #![warn(clippy::to_string_in_display)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::recursive_format_impl`
 
 error: lint `clippy::unwrap_or_else_default` has been renamed to `clippy::unwrap_or_default`
-  --> tests/ui/rename.rs:87:9
+  --> tests/ui/rename.rs:91:9
    |
 LL | #![warn(clippy::unwrap_or_else_default)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::unwrap_or_default`
 
 error: lint `clippy::zero_width_space` has been renamed to `clippy::invisible_characters`
-  --> tests/ui/rename.rs:88:9
+  --> tests/ui/rename.rs:92:9
    |
 LL | #![warn(clippy::zero_width_space)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::invisible_characters`
 
 error: lint `clippy::cast_ref_to_mut` has been renamed to `invalid_reference_casting`
-  --> tests/ui/rename.rs:89:9
+  --> tests/ui/rename.rs:93:9
    |
 LL | #![warn(clippy::cast_ref_to_mut)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `invalid_reference_casting`
 
 error: lint `clippy::clone_double_ref` has been renamed to `suspicious_double_ref_op`
-  --> tests/ui/rename.rs:90:9
+  --> tests/ui/rename.rs:94:9
    |
 LL | #![warn(clippy::clone_double_ref)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `suspicious_double_ref_op`
 
 error: lint `clippy::cmp_nan` has been renamed to `invalid_nan_comparisons`
-  --> tests/ui/rename.rs:91:9
+  --> tests/ui/rename.rs:95:9
    |
 LL | #![warn(clippy::cmp_nan)]
    |         ^^^^^^^^^^^^^^^ help: use the new name: `invalid_nan_comparisons`
 
 error: lint `clippy::drop_bounds` has been renamed to `drop_bounds`
-  --> tests/ui/rename.rs:92:9
+  --> tests/ui/rename.rs:96:9
    |
 LL | #![warn(clippy::drop_bounds)]
    |         ^^^^^^^^^^^^^^^^^^^ help: use the new name: `drop_bounds`
 
 error: lint `clippy::drop_copy` has been renamed to `dropping_copy_types`
-  --> tests/ui/rename.rs:93:9
+  --> tests/ui/rename.rs:97:9
    |
 LL | #![warn(clippy::drop_copy)]
    |         ^^^^^^^^^^^^^^^^^ help: use the new name: `dropping_copy_types`
 
 error: lint `clippy::drop_ref` has been renamed to `dropping_references`
-  --> tests/ui/rename.rs:94:9
+  --> tests/ui/rename.rs:98:9
    |
 LL | #![warn(clippy::drop_ref)]
    |         ^^^^^^^^^^^^^^^^ help: use the new name: `dropping_references`
 
 error: lint `clippy::fn_null_check` has been renamed to `useless_ptr_null_checks`
-  --> tests/ui/rename.rs:95:9
+  --> tests/ui/rename.rs:99:9
    |
 LL | #![warn(clippy::fn_null_check)]
    |         ^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `useless_ptr_null_checks`
 
 error: lint `clippy::for_loop_over_option` has been renamed to `for_loops_over_fallibles`
-  --> tests/ui/rename.rs:96:9
+  --> tests/ui/rename.rs:100:9
    |
 LL | #![warn(clippy::for_loop_over_option)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `for_loops_over_fallibles`
 
 error: lint `clippy::for_loop_over_result` has been renamed to `for_loops_over_fallibles`
-  --> tests/ui/rename.rs:97:9
+  --> tests/ui/rename.rs:101:9
    |
 LL | #![warn(clippy::for_loop_over_result)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `for_loops_over_fallibles`
 
 error: lint `clippy::for_loops_over_fallibles` has been renamed to `for_loops_over_fallibles`
-  --> tests/ui/rename.rs:98:9
+  --> tests/ui/rename.rs:102:9
    |
 LL | #![warn(clippy::for_loops_over_fallibles)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `for_loops_over_fallibles`
 
 error: lint `clippy::forget_copy` has been renamed to `forgetting_copy_types`
-  --> tests/ui/rename.rs:99:9
+  --> tests/ui/rename.rs:103:9
    |
 LL | #![warn(clippy::forget_copy)]
    |         ^^^^^^^^^^^^^^^^^^^ help: use the new name: `forgetting_copy_types`
 
 error: lint `clippy::forget_ref` has been renamed to `forgetting_references`
-  --> tests/ui/rename.rs:100:9
+  --> tests/ui/rename.rs:104:9
    |
 LL | #![warn(clippy::forget_ref)]
    |         ^^^^^^^^^^^^^^^^^^ help: use the new name: `forgetting_references`
 
 error: lint `clippy::into_iter_on_array` has been renamed to `array_into_iter`
-  --> tests/ui/rename.rs:101:9
+  --> tests/ui/rename.rs:105:9
    |
 LL | #![warn(clippy::into_iter_on_array)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `array_into_iter`
 
 error: lint `clippy::invalid_atomic_ordering` has been renamed to `invalid_atomic_ordering`
-  --> tests/ui/rename.rs:102:9
+  --> tests/ui/rename.rs:106:9
    |
 LL | #![warn(clippy::invalid_atomic_ordering)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `invalid_atomic_ordering`
 
 error: lint `clippy::invalid_ref` has been renamed to `invalid_value`
-  --> tests/ui/rename.rs:103:9
+  --> tests/ui/rename.rs:107:9
    |
 LL | #![warn(clippy::invalid_ref)]
    |         ^^^^^^^^^^^^^^^^^^^ help: use the new name: `invalid_value`
 
 error: lint `clippy::invalid_utf8_in_unchecked` has been renamed to `invalid_from_utf8_unchecked`
-  --> tests/ui/rename.rs:104:9
+  --> tests/ui/rename.rs:108:9
    |
 LL | #![warn(clippy::invalid_utf8_in_unchecked)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `invalid_from_utf8_unchecked`
 
 error: lint `clippy::let_underscore_drop` has been renamed to `let_underscore_drop`
-  --> tests/ui/rename.rs:105:9
+  --> tests/ui/rename.rs:109:9
    |
 LL | #![warn(clippy::let_underscore_drop)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `let_underscore_drop`
 
 error: lint `clippy::mem_discriminant_non_enum` has been renamed to `enum_intrinsics_non_enums`
-  --> tests/ui/rename.rs:106:9
+  --> tests/ui/rename.rs:110:9
    |
 LL | #![warn(clippy::mem_discriminant_non_enum)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `enum_intrinsics_non_enums`
 
 error: lint `clippy::panic_params` has been renamed to `non_fmt_panics`
-  --> tests/ui/rename.rs:107:9
+  --> tests/ui/rename.rs:111:9
    |
 LL | #![warn(clippy::panic_params)]
    |         ^^^^^^^^^^^^^^^^^^^^ help: use the new name: `non_fmt_panics`
 
 error: lint `clippy::positional_named_format_parameters` has been renamed to `named_arguments_used_positionally`
-  --> tests/ui/rename.rs:108:9
+  --> tests/ui/rename.rs:112:9
    |
 LL | #![warn(clippy::positional_named_format_parameters)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `named_arguments_used_positionally`
 
 error: lint `clippy::temporary_cstring_as_ptr` has been renamed to `temporary_cstring_as_ptr`
-  --> tests/ui/rename.rs:109:9
+  --> tests/ui/rename.rs:113:9
    |
 LL | #![warn(clippy::temporary_cstring_as_ptr)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `temporary_cstring_as_ptr`
 
 error: lint `clippy::undropped_manually_drops` has been renamed to `undropped_manually_drops`
-  --> tests/ui/rename.rs:110:9
+  --> tests/ui/rename.rs:114:9
    |
 LL | #![warn(clippy::undropped_manually_drops)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `undropped_manually_drops`
 
 error: lint `clippy::unknown_clippy_lints` has been renamed to `unknown_lints`
-  --> tests/ui/rename.rs:111:9
+  --> tests/ui/rename.rs:115:9
    |
 LL | #![warn(clippy::unknown_clippy_lints)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `unknown_lints`
 
 error: lint `clippy::unused_label` has been renamed to `unused_labels`
-  --> tests/ui/rename.rs:112:9
+  --> tests/ui/rename.rs:116:9
    |
 LL | #![warn(clippy::unused_label)]
    |         ^^^^^^^^^^^^^^^^^^^^ help: use the new name: `unused_labels`
 
 error: lint `clippy::vtable_address_comparisons` has been renamed to `ambiguous_wide_pointer_comparisons`
-  --> tests/ui/rename.rs:113:9
+  --> tests/ui/rename.rs:117:9
    |
 LL | #![warn(clippy::vtable_address_comparisons)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `ambiguous_wide_pointer_comparisons`
 
-error: aborting due to 58 previous errors
+error: aborting due to 60 previous errors
 
diff --git a/src/tools/clippy/tests/ui/set_contains_or_insert.rs b/src/tools/clippy/tests/ui/set_contains_or_insert.rs
new file mode 100644
index 00000000000..8465007402a
--- /dev/null
+++ b/src/tools/clippy/tests/ui/set_contains_or_insert.rs
@@ -0,0 +1,83 @@
+#![allow(unused)]
+#![allow(clippy::nonminimal_bool)]
+#![allow(clippy::needless_borrow)]
+#![warn(clippy::set_contains_or_insert)]
+
+use std::collections::HashSet;
+
+fn main() {
+    should_warn_cases();
+
+    should_not_warn_cases();
+}
+
+fn should_warn_cases() {
+    let mut set = HashSet::new();
+    let value = 5;
+
+    if !set.contains(&value) {
+        set.insert(value);
+        println!("Just a comment");
+    }
+
+    if set.contains(&value) {
+        set.insert(value);
+        println!("Just a comment");
+    }
+
+    if !set.contains(&value) {
+        set.insert(value);
+    }
+
+    if !!set.contains(&value) {
+        set.insert(value);
+        println!("Just a comment");
+    }
+
+    if (&set).contains(&value) {
+        set.insert(value);
+    }
+
+    let borrow_value = &6;
+    if !set.contains(borrow_value) {
+        set.insert(*borrow_value);
+    }
+
+    let borrow_set = &mut set;
+    if !borrow_set.contains(&value) {
+        borrow_set.insert(value);
+    }
+}
+
+fn should_not_warn_cases() {
+    let mut set = HashSet::new();
+    let value = 5;
+    let another_value = 6;
+
+    if !set.contains(&value) {
+        set.insert(another_value);
+    }
+
+    if !set.contains(&value) {
+        println!("Just a comment");
+    }
+
+    if simply_true() {
+        set.insert(value);
+    }
+
+    if !set.contains(&value) {
+        set.replace(value); //it is not insert
+        println!("Just a comment");
+    }
+
+    if set.contains(&value) {
+        println!("value is already in set");
+    } else {
+        set.insert(value);
+    }
+}
+
+fn simply_true() -> bool {
+    true
+}
diff --git a/src/tools/clippy/tests/ui/set_contains_or_insert.stderr b/src/tools/clippy/tests/ui/set_contains_or_insert.stderr
new file mode 100644
index 00000000000..507e20964fc
--- /dev/null
+++ b/src/tools/clippy/tests/ui/set_contains_or_insert.stderr
@@ -0,0 +1,61 @@
+error: usage of `HashSet::insert` after `HashSet::contains`
+  --> tests/ui/set_contains_or_insert.rs:18:13
+   |
+LL |     if !set.contains(&value) {
+   |             ^^^^^^^^^^^^^^^^
+LL |         set.insert(value);
+   |             ^^^^^^^^^^^^^
+   |
+   = note: `-D clippy::set-contains-or-insert` implied by `-D warnings`
+   = help: to override `-D warnings` add `#[allow(clippy::set_contains_or_insert)]`
+
+error: usage of `HashSet::insert` after `HashSet::contains`
+  --> tests/ui/set_contains_or_insert.rs:23:12
+   |
+LL |     if set.contains(&value) {
+   |            ^^^^^^^^^^^^^^^^
+LL |         set.insert(value);
+   |             ^^^^^^^^^^^^^
+
+error: usage of `HashSet::insert` after `HashSet::contains`
+  --> tests/ui/set_contains_or_insert.rs:28:13
+   |
+LL |     if !set.contains(&value) {
+   |             ^^^^^^^^^^^^^^^^
+LL |         set.insert(value);
+   |             ^^^^^^^^^^^^^
+
+error: usage of `HashSet::insert` after `HashSet::contains`
+  --> tests/ui/set_contains_or_insert.rs:32:14
+   |
+LL |     if !!set.contains(&value) {
+   |              ^^^^^^^^^^^^^^^^
+LL |         set.insert(value);
+   |             ^^^^^^^^^^^^^
+
+error: usage of `HashSet::insert` after `HashSet::contains`
+  --> tests/ui/set_contains_or_insert.rs:37:15
+   |
+LL |     if (&set).contains(&value) {
+   |               ^^^^^^^^^^^^^^^^
+LL |         set.insert(value);
+   |             ^^^^^^^^^^^^^
+
+error: usage of `HashSet::insert` after `HashSet::contains`
+  --> tests/ui/set_contains_or_insert.rs:42:13
+   |
+LL |     if !set.contains(borrow_value) {
+   |             ^^^^^^^^^^^^^^^^^^^^^^
+LL |         set.insert(*borrow_value);
+   |             ^^^^^^^^^^^^^^^^^^^^^
+
+error: usage of `HashSet::insert` after `HashSet::contains`
+  --> tests/ui/set_contains_or_insert.rs:47:20
+   |
+LL |     if !borrow_set.contains(&value) {
+   |                    ^^^^^^^^^^^^^^^^
+LL |         borrow_set.insert(value);
+   |                    ^^^^^^^^^^^^^
+
+error: aborting due to 7 previous errors
+
diff --git a/src/tools/clippy/tests/ui/significant_drop_in_scrutinee.rs b/src/tools/clippy/tests/ui/significant_drop_in_scrutinee.rs
index 8ee15440ccf..0db6fbfb7be 100644
--- a/src/tools/clippy/tests/ui/significant_drop_in_scrutinee.rs
+++ b/src/tools/clippy/tests/ui/significant_drop_in_scrutinee.rs
@@ -801,4 +801,30 @@ fn should_not_trigger_lint_with_explicit_drop() {
     }
 }
 
+fn should_trigger_lint_in_if_let() {
+    let mutex = Mutex::new(vec![1]);
+
+    if let Some(val) = mutex.lock().unwrap().first().copied() {
+        //~^ ERROR: temporary with significant `Drop` in `if let` scrutinee will live until the
+        //~| NOTE: this might lead to deadlocks or other unexpected behavior
+        println!("{}", val);
+    }
+
+    // Should not trigger lint without the final `copied()`, because we actually hold a reference
+    // (i.e., the `val`) to the locked data.
+    if let Some(val) = mutex.lock().unwrap().first() {
+        println!("{}", val);
+    };
+}
+
+fn should_trigger_lint_in_while_let() {
+    let mutex = Mutex::new(vec![1]);
+
+    while let Some(val) = mutex.lock().unwrap().pop() {
+        //~^ ERROR: temporary with significant `Drop` in `while let` scrutinee will live until the
+        //~| NOTE: this might lead to deadlocks or other unexpected behavior
+        println!("{}", val);
+    }
+}
+
 fn main() {}
diff --git a/src/tools/clippy/tests/ui/significant_drop_in_scrutinee.stderr b/src/tools/clippy/tests/ui/significant_drop_in_scrutinee.stderr
index 4a483e79d8a..c0c93cd10c0 100644
--- a/src/tools/clippy/tests/ui/significant_drop_in_scrutinee.stderr
+++ b/src/tools/clippy/tests/ui/significant_drop_in_scrutinee.stderr
@@ -541,5 +541,32 @@ LL ~     let value = mutex.lock().unwrap()[0];
 LL ~     for val in [value, 2] {
    |
 
-error: aborting due to 27 previous errors
+error: temporary with significant `Drop` in `if let` scrutinee will live until the end of the `if let` expression
+  --> tests/ui/significant_drop_in_scrutinee.rs:807:24
+   |
+LL |     if let Some(val) = mutex.lock().unwrap().first().copied() {
+   |                        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+...
+LL |     }
+   |      - temporary lives until here
+   |
+   = note: this might lead to deadlocks or other unexpected behavior
+help: try moving the temporary above the match
+   |
+LL ~     let value = mutex.lock().unwrap().first().copied();
+LL ~     if let Some(val) = value {
+   |
+
+error: temporary with significant `Drop` in `while let` scrutinee will live until the end of the `while let` expression
+  --> tests/ui/significant_drop_in_scrutinee.rs:823:27
+   |
+LL |     while let Some(val) = mutex.lock().unwrap().pop() {
+   |                           ^^^^^^^^^^^^^^^^^^^^^^^^^^^
+...
+LL |     }
+   |      - temporary lives until here
+   |
+   = note: this might lead to deadlocks or other unexpected behavior
+
+error: aborting due to 29 previous errors
 
diff --git a/src/tools/clippy/tests/ui/unnecessary_operation.fixed b/src/tools/clippy/tests/ui/unnecessary_operation.fixed
index 11761c6c90e..006f123cbcd 100644
--- a/src/tools/clippy/tests/ui/unnecessary_operation.fixed
+++ b/src/tools/clippy/tests/ui/unnecessary_operation.fixed
@@ -43,7 +43,7 @@ fn get_number() -> i32 {
     0
 }
 
-fn get_usize() -> usize {
+const fn get_usize() -> usize {
     0
 }
 fn get_struct() -> Struct {
@@ -113,4 +113,16 @@ fn main() {
     'label: {
         break 'label
     };
+    let () = const {
+        [42, 55][get_usize()];
+    };
+}
+
+const _: () = {
+    [42, 55][get_usize()];
+};
+
+const fn foo() {
+    assert!([42, 55].len() > get_usize());
+    //~^ ERROR: unnecessary operation
 }
diff --git a/src/tools/clippy/tests/ui/unnecessary_operation.rs b/src/tools/clippy/tests/ui/unnecessary_operation.rs
index de0081289ac..b4067c74074 100644
--- a/src/tools/clippy/tests/ui/unnecessary_operation.rs
+++ b/src/tools/clippy/tests/ui/unnecessary_operation.rs
@@ -43,7 +43,7 @@ fn get_number() -> i32 {
     0
 }
 
-fn get_usize() -> usize {
+const fn get_usize() -> usize {
     0
 }
 fn get_struct() -> Struct {
@@ -117,4 +117,16 @@ fn main() {
     'label: {
         break 'label
     };
+    let () = const {
+        [42, 55][get_usize()];
+    };
+}
+
+const _: () = {
+    [42, 55][get_usize()];
+};
+
+const fn foo() {
+    [42, 55][get_usize()];
+    //~^ ERROR: unnecessary operation
 }
diff --git a/src/tools/clippy/tests/ui/unnecessary_operation.stderr b/src/tools/clippy/tests/ui/unnecessary_operation.stderr
index 27be5e6f4b9..036a9a44bba 100644
--- a/src/tools/clippy/tests/ui/unnecessary_operation.stderr
+++ b/src/tools/clippy/tests/ui/unnecessary_operation.stderr
@@ -119,5 +119,11 @@ LL | |         s: String::from("blah"),
 LL | |     };
    | |______^ help: statement can be reduced to: `String::from("blah");`
 
-error: aborting due to 19 previous errors
+error: unnecessary operation
+  --> tests/ui/unnecessary_operation.rs:130:5
+   |
+LL |     [42, 55][get_usize()];
+   |     ^^^^^^^^^^^^^^^^^^^^^^ help: statement can be written as: `assert!([42, 55].len() > get_usize());`
+
+error: aborting due to 20 previous errors
 
diff --git a/src/tools/clippy/tests/ui/unnecessary_to_owned.fixed b/src/tools/clippy/tests/ui/unnecessary_to_owned.fixed
index 1afa5ab54c4..fdcac8fb08d 100644
--- a/src/tools/clippy/tests/ui/unnecessary_to_owned.fixed
+++ b/src/tools/clippy/tests/ui/unnecessary_to_owned.fixed
@@ -157,6 +157,25 @@ fn main() {
     require_path(&std::path::PathBuf::from("x"));
     require_str(&String::from("x"));
     require_slice(&[String::from("x")]);
+
+    let slice = [0u8; 1024];
+    let _ref_str: &str = core::str::from_utf8(&slice).expect("not UTF-8");
+    let _ref_str: &str = core::str::from_utf8(b"foo").unwrap();
+    let _ref_str: &str = core::str::from_utf8(b"foo".as_slice()).unwrap();
+    // Expression is of type `&String`, can't suggest `str::from_utf8` here
+    let _ref_string = &String::from_utf8(b"foo".to_vec()).unwrap();
+    macro_rules! arg_from_macro {
+        () => {
+            b"foo".to_vec()
+        };
+    }
+    macro_rules! string_from_utf8_from_macro {
+        () => {
+            &String::from_utf8(b"foo".to_vec()).unwrap()
+        };
+    }
+    let _ref_str: &str = &String::from_utf8(arg_from_macro!()).unwrap();
+    let _ref_str: &str = string_from_utf8_from_macro!();
 }
 
 fn require_c_str(_: &CStr) {}
diff --git a/src/tools/clippy/tests/ui/unnecessary_to_owned.rs b/src/tools/clippy/tests/ui/unnecessary_to_owned.rs
index aa88dde43bf..10a9727a9a7 100644
--- a/src/tools/clippy/tests/ui/unnecessary_to_owned.rs
+++ b/src/tools/clippy/tests/ui/unnecessary_to_owned.rs
@@ -157,6 +157,25 @@ fn main() {
     require_path(&std::path::PathBuf::from("x").to_path_buf());
     require_str(&String::from("x").to_string());
     require_slice(&[String::from("x")].to_owned());
+
+    let slice = [0u8; 1024];
+    let _ref_str: &str = &String::from_utf8(slice.to_vec()).expect("not UTF-8");
+    let _ref_str: &str = &String::from_utf8(b"foo".to_vec()).unwrap();
+    let _ref_str: &str = &String::from_utf8(b"foo".as_slice().to_owned()).unwrap();
+    // Expression is of type `&String`, can't suggest `str::from_utf8` here
+    let _ref_string = &String::from_utf8(b"foo".to_vec()).unwrap();
+    macro_rules! arg_from_macro {
+        () => {
+            b"foo".to_vec()
+        };
+    }
+    macro_rules! string_from_utf8_from_macro {
+        () => {
+            &String::from_utf8(b"foo".to_vec()).unwrap()
+        };
+    }
+    let _ref_str: &str = &String::from_utf8(arg_from_macro!()).unwrap();
+    let _ref_str: &str = string_from_utf8_from_macro!();
 }
 
 fn require_c_str(_: &CStr) {}
diff --git a/src/tools/clippy/tests/ui/unnecessary_to_owned.stderr b/src/tools/clippy/tests/ui/unnecessary_to_owned.stderr
index 2829f3cd6e9..511b4ae119f 100644
--- a/src/tools/clippy/tests/ui/unnecessary_to_owned.stderr
+++ b/src/tools/clippy/tests/ui/unnecessary_to_owned.stderr
@@ -477,8 +477,44 @@ error: unnecessary use of `to_owned`
 LL |     let _ = IntoIterator::into_iter([std::path::PathBuf::new()][..].to_owned());
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use: `[std::path::PathBuf::new()][..].iter().cloned()`
 
+error: allocating a new `String` only to create a temporary `&str` from it
+  --> tests/ui/unnecessary_to_owned.rs:162:26
+   |
+LL |     let _ref_str: &str = &String::from_utf8(slice.to_vec()).expect("not UTF-8");
+   |                          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: convert from `&[u8]` to `&str` directly
+   |
+LL -     let _ref_str: &str = &String::from_utf8(slice.to_vec()).expect("not UTF-8");
+LL +     let _ref_str: &str = core::str::from_utf8(&slice).expect("not UTF-8");
+   |
+
+error: allocating a new `String` only to create a temporary `&str` from it
+  --> tests/ui/unnecessary_to_owned.rs:163:26
+   |
+LL |     let _ref_str: &str = &String::from_utf8(b"foo".to_vec()).unwrap();
+   |                          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: convert from `&[u8]` to `&str` directly
+   |
+LL -     let _ref_str: &str = &String::from_utf8(b"foo".to_vec()).unwrap();
+LL +     let _ref_str: &str = core::str::from_utf8(b"foo").unwrap();
+   |
+
+error: allocating a new `String` only to create a temporary `&str` from it
+  --> tests/ui/unnecessary_to_owned.rs:164:26
+   |
+LL |     let _ref_str: &str = &String::from_utf8(b"foo".as_slice().to_owned()).unwrap();
+   |                          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: convert from `&[u8]` to `&str` directly
+   |
+LL -     let _ref_str: &str = &String::from_utf8(b"foo".as_slice().to_owned()).unwrap();
+LL +     let _ref_str: &str = core::str::from_utf8(b"foo".as_slice()).unwrap();
+   |
+
 error: unnecessary use of `to_vec`
-  --> tests/ui/unnecessary_to_owned.rs:202:14
+  --> tests/ui/unnecessary_to_owned.rs:221:14
    |
 LL |     for t in file_types.to_vec() {
    |              ^^^^^^^^^^^^^^^^^^^
@@ -494,64 +530,64 @@ LL +         let path = match get_file_path(t) {
    |
 
 error: unnecessary use of `to_vec`
-  --> tests/ui/unnecessary_to_owned.rs:225:14
+  --> tests/ui/unnecessary_to_owned.rs:244:14
    |
 LL |     let _ = &["x"][..].to_vec().into_iter();
    |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use: `["x"][..].iter().cloned()`
 
 error: unnecessary use of `to_vec`
-  --> tests/ui/unnecessary_to_owned.rs:230:14
+  --> tests/ui/unnecessary_to_owned.rs:249:14
    |
 LL |     let _ = &["x"][..].to_vec().into_iter();
    |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use: `["x"][..].iter().copied()`
 
 error: unnecessary use of `to_string`
-  --> tests/ui/unnecessary_to_owned.rs:278:24
+  --> tests/ui/unnecessary_to_owned.rs:297:24
    |
 LL |         Box::new(build(y.to_string()))
    |                        ^^^^^^^^^^^^^ help: use: `y`
 
 error: unnecessary use of `to_string`
-  --> tests/ui/unnecessary_to_owned.rs:387:12
+  --> tests/ui/unnecessary_to_owned.rs:406:12
    |
 LL |         id("abc".to_string())
    |            ^^^^^^^^^^^^^^^^^ help: use: `"abc"`
 
 error: unnecessary use of `to_vec`
-  --> tests/ui/unnecessary_to_owned.rs:530:37
+  --> tests/ui/unnecessary_to_owned.rs:549:37
    |
 LL |         IntoFuture::into_future(foo([].to_vec(), &0));
    |                                     ^^^^^^^^^^^ help: use: `[]`
 
 error: unnecessary use of `to_vec`
-  --> tests/ui/unnecessary_to_owned.rs:540:18
+  --> tests/ui/unnecessary_to_owned.rs:559:18
    |
 LL |         s.remove(&a.to_vec());
    |                  ^^^^^^^^^^^ help: replace it with: `a`
 
 error: unnecessary use of `to_owned`
-  --> tests/ui/unnecessary_to_owned.rs:544:14
+  --> tests/ui/unnecessary_to_owned.rs:563:14
    |
 LL |     s.remove(&"b".to_owned());
    |              ^^^^^^^^^^^^^^^ help: replace it with: `"b"`
 
 error: unnecessary use of `to_string`
-  --> tests/ui/unnecessary_to_owned.rs:545:14
+  --> tests/ui/unnecessary_to_owned.rs:564:14
    |
 LL |     s.remove(&"b".to_string());
    |              ^^^^^^^^^^^^^^^^ help: replace it with: `"b"`
 
 error: unnecessary use of `to_vec`
-  --> tests/ui/unnecessary_to_owned.rs:550:14
+  --> tests/ui/unnecessary_to_owned.rs:569:14
    |
 LL |     s.remove(&["b"].to_vec());
    |              ^^^^^^^^^^^^^^^ help: replace it with: `["b"].as_slice()`
 
 error: unnecessary use of `to_vec`
-  --> tests/ui/unnecessary_to_owned.rs:551:14
+  --> tests/ui/unnecessary_to_owned.rs:570:14
    |
 LL |     s.remove(&(&["b"]).to_vec());
    |              ^^^^^^^^^^^^^^^^^^ help: replace it with: `(&["b"]).as_slice()`
 
-error: aborting due to 85 previous errors
+error: aborting due to 88 previous errors
 
diff --git a/src/tools/clippy/tests/ui/wildcard_imports.fixed b/src/tools/clippy/tests/ui/wildcard_imports.fixed
index 6fdd728b9b7..46890ee9213 100644
--- a/src/tools/clippy/tests/ui/wildcard_imports.fixed
+++ b/src/tools/clippy/tests/ui/wildcard_imports.fixed
@@ -204,6 +204,7 @@ mod super_imports {
         }
     }
 
+    #[cfg(test)]
     mod test_should_pass {
         use super::*;
 
@@ -212,6 +213,7 @@ mod super_imports {
         }
     }
 
+    #[cfg(test)]
     mod test_should_pass_inside_function {
         fn with_super_inside_function() {
             use super::*;
@@ -219,6 +221,7 @@ mod super_imports {
         }
     }
 
+    #[cfg(test)]
     mod test_should_pass_further_inside {
         fn insidefoo() {}
         mod inner {
diff --git a/src/tools/clippy/tests/ui/wildcard_imports.rs b/src/tools/clippy/tests/ui/wildcard_imports.rs
index 20e06d4b366..1a5586cbb88 100644
--- a/src/tools/clippy/tests/ui/wildcard_imports.rs
+++ b/src/tools/clippy/tests/ui/wildcard_imports.rs
@@ -205,6 +205,7 @@ mod super_imports {
         }
     }
 
+    #[cfg(test)]
     mod test_should_pass {
         use super::*;
 
@@ -213,6 +214,7 @@ mod super_imports {
         }
     }
 
+    #[cfg(test)]
     mod test_should_pass_inside_function {
         fn with_super_inside_function() {
             use super::*;
@@ -220,6 +222,7 @@ mod super_imports {
         }
     }
 
+    #[cfg(test)]
     mod test_should_pass_further_inside {
         fn insidefoo() {}
         mod inner {
diff --git a/src/tools/clippy/tests/ui/wildcard_imports.stderr b/src/tools/clippy/tests/ui/wildcard_imports.stderr
index 0c69d5262c2..8e88f216394 100644
--- a/src/tools/clippy/tests/ui/wildcard_imports.stderr
+++ b/src/tools/clippy/tests/ui/wildcard_imports.stderr
@@ -106,31 +106,31 @@ LL |         use super::*;
    |             ^^^^^^^^ help: try: `super::foofoo`
 
 error: usage of wildcard import
-  --> tests/ui/wildcard_imports.rs:236:17
+  --> tests/ui/wildcard_imports.rs:239:17
    |
 LL |             use super::*;
    |                 ^^^^^^^^ help: try: `super::insidefoo`
 
 error: usage of wildcard import
-  --> tests/ui/wildcard_imports.rs:244:13
+  --> tests/ui/wildcard_imports.rs:247:13
    |
 LL |         use crate::super_imports::*;
    |             ^^^^^^^^^^^^^^^^^^^^^^^ help: try: `crate::super_imports::foofoo`
 
 error: usage of wildcard import
-  --> tests/ui/wildcard_imports.rs:253:17
+  --> tests/ui/wildcard_imports.rs:256:17
    |
 LL |             use super::super::*;
    |                 ^^^^^^^^^^^^^^^ help: try: `super::super::foofoo`
 
 error: usage of wildcard import
-  --> tests/ui/wildcard_imports.rs:262:13
+  --> tests/ui/wildcard_imports.rs:265:13
    |
 LL |         use super::super::super_imports::*;
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `super::super::super_imports::foofoo`
 
 error: usage of wildcard import
-  --> tests/ui/wildcard_imports.rs:270:13
+  --> tests/ui/wildcard_imports.rs:273:13
    |
 LL |         use super::*;
    |             ^^^^^^^^ help: try: `super::foofoo`
diff --git a/src/tools/clippy/tests/ui/wildcard_imports_2021.edition2018.fixed b/src/tools/clippy/tests/ui/wildcard_imports_2021.edition2018.fixed
index 6a9fe007d65..197dd3b94df 100644
--- a/src/tools/clippy/tests/ui/wildcard_imports_2021.edition2018.fixed
+++ b/src/tools/clippy/tests/ui/wildcard_imports_2021.edition2018.fixed
@@ -198,6 +198,7 @@ mod super_imports {
         }
     }
 
+    #[cfg(test)]
     mod test_should_pass {
         use super::*;
 
@@ -206,6 +207,7 @@ mod super_imports {
         }
     }
 
+    #[cfg(test)]
     mod test_should_pass_inside_function {
         fn with_super_inside_function() {
             use super::*;
@@ -213,6 +215,7 @@ mod super_imports {
         }
     }
 
+    #[cfg(test)]
     mod test_should_pass_further_inside {
         fn insidefoo() {}
         mod inner {
diff --git a/src/tools/clippy/tests/ui/wildcard_imports_2021.edition2018.stderr b/src/tools/clippy/tests/ui/wildcard_imports_2021.edition2018.stderr
index 11e0bd37769..66adacd95dc 100644
--- a/src/tools/clippy/tests/ui/wildcard_imports_2021.edition2018.stderr
+++ b/src/tools/clippy/tests/ui/wildcard_imports_2021.edition2018.stderr
@@ -106,31 +106,31 @@ LL |         use super::*;
    |             ^^^^^^^^ help: try: `super::foofoo`
 
 error: usage of wildcard import
-  --> tests/ui/wildcard_imports_2021.rs:230:17
+  --> tests/ui/wildcard_imports_2021.rs:233:17
    |
 LL |             use super::*;
    |                 ^^^^^^^^ help: try: `super::insidefoo`
 
 error: usage of wildcard import
-  --> tests/ui/wildcard_imports_2021.rs:238:13
+  --> tests/ui/wildcard_imports_2021.rs:241:13
    |
 LL |         use crate::super_imports::*;
    |             ^^^^^^^^^^^^^^^^^^^^^^^ help: try: `crate::super_imports::foofoo`
 
 error: usage of wildcard import
-  --> tests/ui/wildcard_imports_2021.rs:247:17
+  --> tests/ui/wildcard_imports_2021.rs:250:17
    |
 LL |             use super::super::*;
    |                 ^^^^^^^^^^^^^^^ help: try: `super::super::foofoo`
 
 error: usage of wildcard import
-  --> tests/ui/wildcard_imports_2021.rs:256:13
+  --> tests/ui/wildcard_imports_2021.rs:259:13
    |
 LL |         use super::super::super_imports::*;
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `super::super::super_imports::foofoo`
 
 error: usage of wildcard import
-  --> tests/ui/wildcard_imports_2021.rs:264:13
+  --> tests/ui/wildcard_imports_2021.rs:267:13
    |
 LL |         use super::*;
    |             ^^^^^^^^ help: try: `super::foofoo`
diff --git a/src/tools/clippy/tests/ui/wildcard_imports_2021.edition2021.fixed b/src/tools/clippy/tests/ui/wildcard_imports_2021.edition2021.fixed
index 6a9fe007d65..197dd3b94df 100644
--- a/src/tools/clippy/tests/ui/wildcard_imports_2021.edition2021.fixed
+++ b/src/tools/clippy/tests/ui/wildcard_imports_2021.edition2021.fixed
@@ -198,6 +198,7 @@ mod super_imports {
         }
     }
 
+    #[cfg(test)]
     mod test_should_pass {
         use super::*;
 
@@ -206,6 +207,7 @@ mod super_imports {
         }
     }
 
+    #[cfg(test)]
     mod test_should_pass_inside_function {
         fn with_super_inside_function() {
             use super::*;
@@ -213,6 +215,7 @@ mod super_imports {
         }
     }
 
+    #[cfg(test)]
     mod test_should_pass_further_inside {
         fn insidefoo() {}
         mod inner {
diff --git a/src/tools/clippy/tests/ui/wildcard_imports_2021.edition2021.stderr b/src/tools/clippy/tests/ui/wildcard_imports_2021.edition2021.stderr
index 11e0bd37769..66adacd95dc 100644
--- a/src/tools/clippy/tests/ui/wildcard_imports_2021.edition2021.stderr
+++ b/src/tools/clippy/tests/ui/wildcard_imports_2021.edition2021.stderr
@@ -106,31 +106,31 @@ LL |         use super::*;
    |             ^^^^^^^^ help: try: `super::foofoo`
 
 error: usage of wildcard import
-  --> tests/ui/wildcard_imports_2021.rs:230:17
+  --> tests/ui/wildcard_imports_2021.rs:233:17
    |
 LL |             use super::*;
    |                 ^^^^^^^^ help: try: `super::insidefoo`
 
 error: usage of wildcard import
-  --> tests/ui/wildcard_imports_2021.rs:238:13
+  --> tests/ui/wildcard_imports_2021.rs:241:13
    |
 LL |         use crate::super_imports::*;
    |             ^^^^^^^^^^^^^^^^^^^^^^^ help: try: `crate::super_imports::foofoo`
 
 error: usage of wildcard import
-  --> tests/ui/wildcard_imports_2021.rs:247:17
+  --> tests/ui/wildcard_imports_2021.rs:250:17
    |
 LL |             use super::super::*;
    |                 ^^^^^^^^^^^^^^^ help: try: `super::super::foofoo`
 
 error: usage of wildcard import
-  --> tests/ui/wildcard_imports_2021.rs:256:13
+  --> tests/ui/wildcard_imports_2021.rs:259:13
    |
 LL |         use super::super::super_imports::*;
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `super::super::super_imports::foofoo`
 
 error: usage of wildcard import
-  --> tests/ui/wildcard_imports_2021.rs:264:13
+  --> tests/ui/wildcard_imports_2021.rs:267:13
    |
 LL |         use super::*;
    |             ^^^^^^^^ help: try: `super::foofoo`
diff --git a/src/tools/clippy/tests/ui/wildcard_imports_2021.rs b/src/tools/clippy/tests/ui/wildcard_imports_2021.rs
index 18ebc0f5127..606ff080e77 100644
--- a/src/tools/clippy/tests/ui/wildcard_imports_2021.rs
+++ b/src/tools/clippy/tests/ui/wildcard_imports_2021.rs
@@ -199,6 +199,7 @@ mod super_imports {
         }
     }
 
+    #[cfg(test)]
     mod test_should_pass {
         use super::*;
 
@@ -207,6 +208,7 @@ mod super_imports {
         }
     }
 
+    #[cfg(test)]
     mod test_should_pass_inside_function {
         fn with_super_inside_function() {
             use super::*;
@@ -214,6 +216,7 @@ mod super_imports {
         }
     }
 
+    #[cfg(test)]
     mod test_should_pass_further_inside {
         fn insidefoo() {}
         mod inner {