about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
authorMatthias Krüger <matthias.krueger@famsik.de>2024-02-09 19:21:17 +0100
committerGitHub <noreply@github.com>2024-02-09 19:21:17 +0100
commit5250abaeb84df7407bf9a2d887cbd30e1b2f96d0 (patch)
tree369412322fc24f7eb2ab3098a5fe63290d10c64a /src
parentc874b1a42435e2a7ec249861271aad18350d7af6 (diff)
parent4ec9eec9e83fb6a19b899247357e3d5dabfebc78 (diff)
downloadrust-5250abaeb84df7407bf9a2d887cbd30e1b2f96d0.tar.gz
rust-5250abaeb84df7407bf9a2d887cbd30e1b2f96d0.zip
Rollup merge of #120806 - flip1995:clippy-subtree-update, r=Manishearth
Clippy subtree update

r? `@Manishearth`
Diffstat (limited to 'src')
-rwxr-xr-x[-rw-r--r--]src/tools/clippy/.github/driver.sh15
-rw-r--r--src/tools/clippy/CHANGELOG.md66
-rw-r--r--src/tools/clippy/Cargo.toml2
-rw-r--r--src/tools/clippy/book/src/lint_configuration.md33
-rw-r--r--src/tools/clippy/clippy_config/Cargo.toml2
-rw-r--r--src/tools/clippy/clippy_config/src/conf.rs22
-rw-r--r--src/tools/clippy/clippy_config/src/msrvs.rs13
-rw-r--r--src/tools/clippy/clippy_lints/Cargo.toml2
-rw-r--r--src/tools/clippy/clippy_lints/src/booleans.rs1
-rw-r--r--src/tools/clippy/clippy_lints/src/cargo/lint_groups_priority.rs168
-rw-r--r--src/tools/clippy/clippy_lints/src/cargo/mod.rs43
-rw-r--r--src/tools/clippy/clippy_lints/src/casts/mod.rs30
-rw-r--r--src/tools/clippy/clippy_lints/src/casts/ref_as_ptr.rs55
-rw-r--r--src/tools/clippy/clippy_lints/src/declared_lints.rs6
-rw-r--r--src/tools/clippy/clippy_lints/src/doc/mod.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/eta_reduction.rs50
-rw-r--r--src/tools/clippy/clippy_lints/src/incompatible_msrv.rs133
-rw-r--r--src/tools/clippy/clippy_lints/src/iter_over_hash_type.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/lib.rs21
-rw-r--r--src/tools/clippy/clippy_lints/src/loops/mod.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/loops/never_loop.rs6
-rw-r--r--src/tools/clippy/clippy_lints/src/manual_retain.rs141
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/manual_c_str_literals.rs197
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/map_unwrap_or.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/mod.rs65
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/unnecessary_fold.rs1
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/unnecessary_result_map_or_else.rs95
-rw-r--r--src/tools/clippy/clippy_lints/src/no_effect.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/only_used_in_recursion.rs5
-rw-r--r--src/tools/clippy/clippy_lints/src/operators/mod.rs15
-rw-r--r--src/tools/clippy/clippy_lints/src/operators/modulo_arithmetic.rs27
-rw-r--r--src/tools/clippy/clippy_lints/src/redundant_closure_call.rs14
-rw-r--r--src/tools/clippy/clippy_lints/src/redundant_locals.rs26
-rw-r--r--src/tools/clippy/clippy_lints/src/redundant_type_annotations.rs11
-rw-r--r--src/tools/clippy/clippy_lints/src/repeat_vec_with_capacity.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/returns.rs31
-rw-r--r--src/tools/clippy/clippy_lints/src/to_string_trait_impl.rs67
-rw-r--r--src/tools/clippy/clippy_lints/src/unconditional_recursion.rs86
-rw-r--r--src/tools/clippy/clippy_lints/src/unused_io_amount.rs101
-rw-r--r--src/tools/clippy/clippy_lints/src/utils/author.rs6
-rw-r--r--src/tools/clippy/clippy_lints/src/wildcard_imports.rs16
-rw-r--r--src/tools/clippy/clippy_utils/Cargo.toml2
-rw-r--r--src/tools/clippy/clippy_utils/src/lib.rs359
-rw-r--r--src/tools/clippy/clippy_utils/src/ty.rs29
-rw-r--r--src/tools/clippy/declare_clippy_lint/Cargo.toml2
-rw-r--r--src/tools/clippy/rust-toolchain2
-rw-r--r--src/tools/clippy/src/driver.rs25
-rw-r--r--src/tools/clippy/tests/ui-cargo/lint_groups_priority/fail/Cargo.stderr45
-rw-r--r--src/tools/clippy/tests/ui-cargo/lint_groups_priority/fail/Cargo.toml20
-rw-r--r--src/tools/clippy/tests/ui-cargo/lint_groups_priority/fail/src/lib.rs1
-rw-r--r--src/tools/clippy/tests/ui-cargo/lint_groups_priority/pass/Cargo.toml10
-rw-r--r--src/tools/clippy/tests/ui-cargo/lint_groups_priority/pass/src/lib.rs1
-rw-r--r--src/tools/clippy/tests/ui-toml/min_rust_version/min_rust_version.fixed2
-rw-r--r--src/tools/clippy/tests/ui-toml/min_rust_version/min_rust_version.rs2
-rw-r--r--src/tools/clippy/tests/ui-toml/modulo_arithmetic/clippy.toml1
-rw-r--r--src/tools/clippy/tests/ui-toml/modulo_arithmetic/modulo_arithmetic.rs10
-rw-r--r--src/tools/clippy/tests/ui-toml/modulo_arithmetic/modulo_arithmetic.stderr40
-rw-r--r--src/tools/clippy/tests/ui-toml/toml_unknown_key/conf_unknown_key.stderr6
-rw-r--r--src/tools/clippy/tests/ui-toml/wildcard_imports/clippy.toml3
-rw-r--r--src/tools/clippy/tests/ui-toml/wildcard_imports/wildcard_imports.fixed19
-rw-r--r--src/tools/clippy/tests/ui-toml/wildcard_imports/wildcard_imports.rs19
-rw-r--r--src/tools/clippy/tests/ui-toml/wildcard_imports/wildcard_imports.stderr20
-rw-r--r--src/tools/clippy/tests/ui-toml/wildcard_imports_whitelist/clippy.toml1
-rw-r--r--src/tools/clippy/tests/ui-toml/wildcard_imports_whitelist/wildcard_imports.fixed26
-rw-r--r--src/tools/clippy/tests/ui-toml/wildcard_imports_whitelist/wildcard_imports.rs26
-rw-r--r--src/tools/clippy/tests/ui-toml/wildcard_imports_whitelist/wildcard_imports.stderr11
-rw-r--r--src/tools/clippy/tests/ui/borrow_as_ptr.fixed1
-rw-r--r--src/tools/clippy/tests/ui/borrow_as_ptr.rs1
-rw-r--r--src/tools/clippy/tests/ui/borrow_as_ptr.stderr4
-rw-r--r--src/tools/clippy/tests/ui/borrow_as_ptr_no_std.fixed1
-rw-r--r--src/tools/clippy/tests/ui/borrow_as_ptr_no_std.rs1
-rw-r--r--src/tools/clippy/tests/ui/borrow_as_ptr_no_std.stderr4
-rw-r--r--src/tools/clippy/tests/ui/eta.fixed71
-rw-r--r--src/tools/clippy/tests/ui/eta.rs71
-rw-r--r--src/tools/clippy/tests/ui/eta.stderr28
-rw-r--r--src/tools/clippy/tests/ui/format_args.fixed1
-rw-r--r--src/tools/clippy/tests/ui/format_args.rs1
-rw-r--r--src/tools/clippy/tests/ui/format_args.stderr50
-rw-r--r--src/tools/clippy/tests/ui/ignored_unit_patterns.fixed7
-rw-r--r--src/tools/clippy/tests/ui/ignored_unit_patterns.rs7
-rw-r--r--src/tools/clippy/tests/ui/ignored_unit_patterns.stderr18
-rw-r--r--src/tools/clippy/tests/ui/incompatible_msrv.rs23
-rw-r--r--src/tools/clippy/tests/ui/incompatible_msrv.stderr23
-rw-r--r--src/tools/clippy/tests/ui/manual_c_str_literals.fixed60
-rw-r--r--src/tools/clippy/tests/ui/manual_c_str_literals.rs60
-rw-r--r--src/tools/clippy/tests/ui/manual_c_str_literals.stderr83
-rw-r--r--src/tools/clippy/tests/ui/manual_retain.fixed63
-rw-r--r--src/tools/clippy/tests/ui/manual_retain.rs63
-rw-r--r--src/tools/clippy/tests/ui/manual_retain.stderr142
-rw-r--r--src/tools/clippy/tests/ui/modulo_arithmetic_integral.rs8
-rw-r--r--src/tools/clippy/tests/ui/needless_borrow.fixed3
-rw-r--r--src/tools/clippy/tests/ui/needless_borrow.rs3
-rw-r--r--src/tools/clippy/tests/ui/needless_borrow.stderr20
-rw-r--r--src/tools/clippy/tests/ui/needless_return_with_question_mark.fixed50
-rw-r--r--src/tools/clippy/tests/ui/needless_return_with_question_mark.rs50
-rw-r--r--src/tools/clippy/tests/ui/never_loop.rs11
-rw-r--r--src/tools/clippy/tests/ui/nonminimal_bool.rs11
-rw-r--r--src/tools/clippy/tests/ui/redundant_closure_call_fixable.fixed9
-rw-r--r--src/tools/clippy/tests/ui/redundant_closure_call_fixable.rs9
-rw-r--r--src/tools/clippy/tests/ui/redundant_locals.rs46
-rw-r--r--src/tools/clippy/tests/ui/redundant_locals.stderr56
-rw-r--r--src/tools/clippy/tests/ui/redundant_type_annotations.rs7
-rw-r--r--src/tools/clippy/tests/ui/redundant_type_annotations.stderr4
-rw-r--r--src/tools/clippy/tests/ui/ref_as_ptr.fixed110
-rw-r--r--src/tools/clippy/tests/ui/ref_as_ptr.rs110
-rw-r--r--src/tools/clippy/tests/ui/ref_as_ptr.stderr269
-rw-r--r--src/tools/clippy/tests/ui/strlen_on_c_strings.fixed2
-rw-r--r--src/tools/clippy/tests/ui/strlen_on_c_strings.rs2
-rw-r--r--src/tools/clippy/tests/ui/to_string_trait_impl.rs31
-rw-r--r--src/tools/clippy/tests/ui/to_string_trait_impl.stderr16
-rw-r--r--src/tools/clippy/tests/ui/unconditional_recursion.rs62
-rw-r--r--src/tools/clippy/tests/ui/unconditional_recursion.stderr14
-rw-r--r--src/tools/clippy/tests/ui/unnecessary_fold.fixed6
-rw-r--r--src/tools/clippy/tests/ui/unnecessary_fold.rs6
-rw-r--r--src/tools/clippy/tests/ui/unnecessary_fold.stderr41
-rw-r--r--src/tools/clippy/tests/ui/unnecessary_operation.fixed7
-rw-r--r--src/tools/clippy/tests/ui/unnecessary_operation.rs7
-rw-r--r--src/tools/clippy/tests/ui/unnecessary_result_map_or_else.fixed61
-rw-r--r--src/tools/clippy/tests/ui/unnecessary_result_map_or_else.rs69
-rw-r--r--src/tools/clippy/tests/ui/unnecessary_result_map_or_else.stderr35
-rw-r--r--src/tools/clippy/tests/ui/unnecessary_to_owned.fixed3
-rw-r--r--src/tools/clippy/tests/ui/unnecessary_to_owned.rs3
-rw-r--r--src/tools/clippy/tests/ui/unnecessary_to_owned.stderr170
-rw-r--r--src/tools/clippy/tests/ui/unnecessary_to_owned_on_split.fixed1
-rw-r--r--src/tools/clippy/tests/ui/unnecessary_to_owned_on_split.rs1
-rw-r--r--src/tools/clippy/tests/ui/unnecessary_to_owned_on_split.stderr18
-rw-r--r--src/tools/clippy/tests/ui/unused_io_amount.rs43
-rw-r--r--src/tools/clippy/tests/ui/unused_io_amount.stderr8
-rw-r--r--src/tools/clippy/tests/ui/while_let_on_iterator.fixed16
-rw-r--r--src/tools/clippy/tests/ui/while_let_on_iterator.rs14
-rw-r--r--src/tools/clippy/tests/ui/while_let_on_iterator.stderr12
131 files changed, 3869 insertions, 604 deletions
diff --git a/src/tools/clippy/.github/driver.sh b/src/tools/clippy/.github/driver.sh
index c05c6ecc115..40a2aad0f53 100644..100755
--- a/src/tools/clippy/.github/driver.sh
+++ b/src/tools/clippy/.github/driver.sh
@@ -11,9 +11,16 @@ if [[ ${OS} == "Windows" ]]; then
 else
 	desired_sysroot=/tmp
 fi
+# Set --sysroot in command line
 sysroot=$(./target/debug/clippy-driver --sysroot $desired_sysroot --print sysroot)
 test "$sysroot" = $desired_sysroot
 
+# Set --sysroot in arg_file.txt and pass @arg_file.txt to command line
+echo "--sysroot=$desired_sysroot" > arg_file.txt
+sysroot=$(./target/debug/clippy-driver @arg_file.txt --print sysroot)
+test "$sysroot" = $desired_sysroot
+
+# Setting SYSROOT in command line
 sysroot=$(SYSROOT=$desired_sysroot ./target/debug/clippy-driver --print sysroot)
 test "$sysroot" = $desired_sysroot
 
@@ -24,6 +31,14 @@ test "$sysroot" = $desired_sysroot
     SYSROOT=/tmp RUSTFLAGS="--sysroot=$(rustc --print sysroot)" ../target/debug/cargo-clippy clippy --verbose
 )
 
+# Check that the --sysroot argument is only passed once via arg_file.txt (SYSROOT is ignored)
+(  
+    echo "fn main() {}" > target/driver_test.rs
+    echo "--sysroot="$(./target/debug/clippy-driver --print sysroot)"" > arg_file.txt
+    echo "--verbose" >> arg_file.txt
+    SYSROOT=/tmp ./target/debug/clippy-driver @arg_file.txt ./target/driver_test.rs
+)
+
 # Make sure this isn't set - clippy-driver should cope without it
 unset CARGO_MANIFEST_DIR
 
diff --git a/src/tools/clippy/CHANGELOG.md b/src/tools/clippy/CHANGELOG.md
index 5fa45ceeb39..9b853567219 100644
--- a/src/tools/clippy/CHANGELOG.md
+++ b/src/tools/clippy/CHANGELOG.md
@@ -6,11 +6,65 @@ document.
 
 ## Unreleased / Beta / In Rust Nightly
 
-[09ac14c9...master](https://github.com/rust-lang/rust-clippy/compare/09ac14c9...master)
+[a859e5cc...master](https://github.com/rust-lang/rust-clippy/compare/a859e5cc...master)
+
+## Rust 1.76
+
+Current stable, released 2024-02-08
+
+[View all 85 merged pull requests](https://github.com/rust-lang/rust-clippy/pulls?q=merged%3A2023-11-02T20%3A23%3A40Z..2023-12-16T13%3A11%3A08Z+base%3Amaster)
+
+### New Lints
+
+- [`infinite_loop`]
+  [#11829](https://github.com/rust-lang/rust-clippy/pull/11829)
+- [`ineffective_open_options`]
+  [#11902](https://github.com/rust-lang/rust-clippy/pull/11902)
+- [`uninhabited_references`]
+  [#11878](https://github.com/rust-lang/rust-clippy/pull/11878)
+- [`repeat_vec_with_capacity`]
+  [#11597](https://github.com/rust-lang/rust-clippy/pull/11597)
+- [`test_attr_in_doctest`]
+  [#11872](https://github.com/rust-lang/rust-clippy/pull/11872)
+- [`option_map_or_err_ok`]
+  [#11864](https://github.com/rust-lang/rust-clippy/pull/11864)
+- [`join_absolute_paths`]
+  [#11453](https://github.com/rust-lang/rust-clippy/pull/11453)
+- [`impl_hash_borrow_with_str_and_bytes`]
+  [#11781](https://github.com/rust-lang/rust-clippy/pull/11781)
+- [`iter_over_hash_type`]
+  [#11791](https://github.com/rust-lang/rust-clippy/pull/11791)
+
+### Moves and Deprecations
+
+- Renamed `blocks_in_if_conditions` to [`blocks_in_conditions`]
+  [#11853](https://github.com/rust-lang/rust-clippy/pull/11853)
+- Moved [`implied_bounds_in_impls`] to `complexity` (Now warn-by-default)
+  [#11867](https://github.com/rust-lang/rust-clippy/pull/11867)
+- Moved [`if_same_then_else`] to `style` (Now warn-by-default)
+  [#11809](https://github.com/rust-lang/rust-clippy/pull/11809)
+
+### Enhancements
+
+- [`missing_safety_doc`], [`unnecessary_safety_doc`], [`missing_panics_doc`], [`missing_errors_doc`]:
+  Added the [`check-private-items`] configuration to enable lints on private items
+  [#11842](https://github.com/rust-lang/rust-clippy/pull/11842)
+
+### ICE Fixes
+
+- [`impl_trait_in_params`]: No longer crashes when a function has generics but no function parameters
+  [#11804](https://github.com/rust-lang/rust-clippy/pull/11804)
+- [`unused_enumerate_index`]: No longer crashes on empty tuples
+  [#11756](https://github.com/rust-lang/rust-clippy/pull/11756)
+
+### Others
+
+- Clippy now respects the `CARGO` environment value
+  [#11944](https://github.com/rust-lang/rust-clippy/pull/11944)
 
 ## Rust 1.75
 
-Current stable, released 2023-12-28
+Released 2023-12-28
 
 [View all 69 merged pull requests](https://github.com/rust-lang/rust-clippy/pulls?q=merged%3A2023-09-25T11%3A47%3A47Z..2023-11-02T16%3A41%3A59Z+base%3Amaster)
 
@@ -5198,6 +5252,7 @@ Released 2018-09-13
 [`implied_bounds_in_impls`]: https://rust-lang.github.io/rust-clippy/master/index.html#implied_bounds_in_impls
 [`impossible_comparisons`]: https://rust-lang.github.io/rust-clippy/master/index.html#impossible_comparisons
 [`imprecise_flops`]: https://rust-lang.github.io/rust-clippy/master/index.html#imprecise_flops
+[`incompatible_msrv`]: https://rust-lang.github.io/rust-clippy/master/index.html#incompatible_msrv
 [`inconsistent_digit_grouping`]: https://rust-lang.github.io/rust-clippy/master/index.html#inconsistent_digit_grouping
 [`inconsistent_struct_constructor`]: https://rust-lang.github.io/rust-clippy/master/index.html#inconsistent_struct_constructor
 [`incorrect_clone_impl_on_copy_type`]: https://rust-lang.github.io/rust-clippy/master/index.html#incorrect_clone_impl_on_copy_type
@@ -5276,6 +5331,7 @@ Released 2018-09-13
 [`let_with_type_underscore`]: https://rust-lang.github.io/rust-clippy/master/index.html#let_with_type_underscore
 [`lines_filter_map_ok`]: https://rust-lang.github.io/rust-clippy/master/index.html#lines_filter_map_ok
 [`linkedlist`]: https://rust-lang.github.io/rust-clippy/master/index.html#linkedlist
+[`lint_groups_priority`]: https://rust-lang.github.io/rust-clippy/master/index.html#lint_groups_priority
 [`little_endian_bytes`]: https://rust-lang.github.io/rust-clippy/master/index.html#little_endian_bytes
 [`logic_bug`]: https://rust-lang.github.io/rust-clippy/master/index.html#logic_bug
 [`lossy_float_literal`]: https://rust-lang.github.io/rust-clippy/master/index.html#lossy_float_literal
@@ -5284,6 +5340,7 @@ Released 2018-09-13
 [`manual_assert`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_assert
 [`manual_async_fn`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_async_fn
 [`manual_bits`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_bits
+[`manual_c_str_literals`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_c_str_literals
 [`manual_clamp`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_clamp
 [`manual_filter`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_filter
 [`manual_filter_map`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_filter_map
@@ -5523,6 +5580,7 @@ Released 2018-09-13
 [`redundant_slicing`]: https://rust-lang.github.io/rust-clippy/master/index.html#redundant_slicing
 [`redundant_static_lifetimes`]: https://rust-lang.github.io/rust-clippy/master/index.html#redundant_static_lifetimes
 [`redundant_type_annotations`]: https://rust-lang.github.io/rust-clippy/master/index.html#redundant_type_annotations
+[`ref_as_ptr`]: https://rust-lang.github.io/rust-clippy/master/index.html#ref_as_ptr
 [`ref_binding_to_reference`]: https://rust-lang.github.io/rust-clippy/master/index.html#ref_binding_to_reference
 [`ref_in_deref`]: https://rust-lang.github.io/rust-clippy/master/index.html#ref_in_deref
 [`ref_option_ref`]: https://rust-lang.github.io/rust-clippy/master/index.html#ref_option_ref
@@ -5622,6 +5680,7 @@ Released 2018-09-13
 [`to_digit_is_some`]: https://rust-lang.github.io/rust-clippy/master/index.html#to_digit_is_some
 [`to_string_in_display`]: https://rust-lang.github.io/rust-clippy/master/index.html#to_string_in_display
 [`to_string_in_format_args`]: https://rust-lang.github.io/rust-clippy/master/index.html#to_string_in_format_args
+[`to_string_trait_impl`]: https://rust-lang.github.io/rust-clippy/master/index.html#to_string_trait_impl
 [`todo`]: https://rust-lang.github.io/rust-clippy/master/index.html#todo
 [`too_many_arguments`]: https://rust-lang.github.io/rust-clippy/master/index.html#too_many_arguments
 [`too_many_lines`]: https://rust-lang.github.io/rust-clippy/master/index.html#too_many_lines
@@ -5677,6 +5736,7 @@ Released 2018-09-13
 [`unnecessary_mut_passed`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_mut_passed
 [`unnecessary_operation`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_operation
 [`unnecessary_owned_empty_strings`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_owned_empty_strings
+[`unnecessary_result_map_or_else`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_result_map_or_else
 [`unnecessary_safety_comment`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_safety_comment
 [`unnecessary_safety_doc`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_safety_doc
 [`unnecessary_self_imports`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_self_imports
@@ -5819,4 +5879,6 @@ Released 2018-09-13
 [`enforce-iter-loop-reborrow`]: https://doc.rust-lang.org/clippy/lint_configuration.html#enforce-iter-loop-reborrow
 [`check-private-items`]: https://doc.rust-lang.org/clippy/lint_configuration.html#check-private-items
 [`pub-underscore-fields-behavior`]: https://doc.rust-lang.org/clippy/lint_configuration.html#pub-underscore-fields-behavior
+[`allow-comparison-to-zero`]: https://doc.rust-lang.org/clippy/lint_configuration.html#allow-comparison-to-zero
+[`allowed-wildcard-imports`]: https://doc.rust-lang.org/clippy/lint_configuration.html#allowed-wildcard-imports
 <!-- end autogenerated links to configuration documentation -->
diff --git a/src/tools/clippy/Cargo.toml b/src/tools/clippy/Cargo.toml
index eda20531e40..321424880d1 100644
--- a/src/tools/clippy/Cargo.toml
+++ b/src/tools/clippy/Cargo.toml
@@ -1,6 +1,6 @@
 [package]
 name = "clippy"
-version = "0.1.77"
+version = "0.1.78"
 description = "A bunch of helpful lints to avoid common pitfalls in Rust"
 repository = "https://github.com/rust-lang/rust-clippy"
 readme = "README.md"
diff --git a/src/tools/clippy/book/src/lint_configuration.md b/src/tools/clippy/book/src/lint_configuration.md
index 7f7aff92bf1..f2357e2b5de 100644
--- a/src/tools/clippy/book/src/lint_configuration.md
+++ b/src/tools/clippy/book/src/lint_configuration.md
@@ -151,6 +151,7 @@ The minimum rust version that the project supports. Defaults to the `rust-versio
 * [`manual_try_fold`](https://rust-lang.github.io/rust-clippy/master/index.html#manual_try_fold)
 * [`manual_hash_one`](https://rust-lang.github.io/rust-clippy/master/index.html#manual_hash_one)
 * [`iter_kv_map`](https://rust-lang.github.io/rust-clippy/master/index.html#iter_kv_map)
+* [`manual_c_str_literals`](https://rust-lang.github.io/rust-clippy/master/index.html#manual_c_str_literals)
 
 
 ## `cognitive-complexity-threshold`
@@ -828,3 +829,35 @@ exported visibility, or whether they are marked as "pub".
 * [`pub_underscore_fields`](https://rust-lang.github.io/rust-clippy/master/index.html#pub_underscore_fields)
 
 
+## `allow-comparison-to-zero`
+Don't lint when comparing the result of a modulo operation to zero.
+
+**Default Value:** `true`
+
+---
+**Affected lints:**
+* [`modulo_arithmetic`](https://rust-lang.github.io/rust-clippy/master/index.html#modulo_arithmetic)
+
+
+## `allowed-wildcard-imports`
+List of path segments allowed to have wildcard imports.
+
+#### Example
+
+```toml
+allowed-wildcard-imports = [ "utils", "common" ]
+```
+
+#### Noteworthy
+
+1. This configuration has no effects if used with `warn_on_all_wildcard_imports = true`.
+2. Paths with any segment that containing the word 'prelude'
+are already allowed by default.
+
+**Default Value:** `[]`
+
+---
+**Affected lints:**
+* [`wildcard_imports`](https://rust-lang.github.io/rust-clippy/master/index.html#wildcard_imports)
+
+
diff --git a/src/tools/clippy/clippy_config/Cargo.toml b/src/tools/clippy/clippy_config/Cargo.toml
index 74b8e5eaa1c..2edc5ed592c 100644
--- a/src/tools/clippy/clippy_config/Cargo.toml
+++ b/src/tools/clippy/clippy_config/Cargo.toml
@@ -1,6 +1,6 @@
 [package]
 name = "clippy_config"
-version = "0.1.77"
+version = "0.1.78"
 edition = "2021"
 
 # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
diff --git a/src/tools/clippy/clippy_config/src/conf.rs b/src/tools/clippy/clippy_config/src/conf.rs
index 4e9ddbf8259..9741b94d504 100644
--- a/src/tools/clippy/clippy_config/src/conf.rs
+++ b/src/tools/clippy/clippy_config/src/conf.rs
@@ -260,7 +260,7 @@ define_Conf! {
     ///
     /// Suppress lints whenever the suggested change would cause breakage for other crates.
     (avoid_breaking_exported_api: bool = true),
-    /// Lint: MANUAL_SPLIT_ONCE, MANUAL_STR_REPEAT, CLONED_INSTEAD_OF_COPIED, REDUNDANT_FIELD_NAMES, OPTION_MAP_UNWRAP_OR, REDUNDANT_STATIC_LIFETIMES, FILTER_MAP_NEXT, CHECKED_CONVERSIONS, MANUAL_RANGE_CONTAINS, USE_SELF, MEM_REPLACE_WITH_DEFAULT, MANUAL_NON_EXHAUSTIVE, OPTION_AS_REF_DEREF, MAP_UNWRAP_OR, MATCH_LIKE_MATCHES_MACRO, MANUAL_STRIP, MISSING_CONST_FOR_FN, UNNESTED_OR_PATTERNS, FROM_OVER_INTO, PTR_AS_PTR, IF_THEN_SOME_ELSE_NONE, APPROX_CONSTANT, DEPRECATED_CFG_ATTR, INDEX_REFUTABLE_SLICE, MAP_CLONE, BORROW_AS_PTR, MANUAL_BITS, ERR_EXPECT, CAST_ABS_TO_UNSIGNED, UNINLINED_FORMAT_ARGS, MANUAL_CLAMP, MANUAL_LET_ELSE, UNCHECKED_DURATION_SUBTRACTION, COLLAPSIBLE_STR_REPLACE, SEEK_FROM_CURRENT, SEEK_REWIND, UNNECESSARY_LAZY_EVALUATIONS, TRANSMUTE_PTR_TO_REF, ALMOST_COMPLETE_RANGE, NEEDLESS_BORROW, DERIVABLE_IMPLS, MANUAL_IS_ASCII_CHECK, MANUAL_REM_EUCLID, MANUAL_RETAIN, TYPE_REPETITION_IN_BOUNDS, TUPLE_ARRAY_CONVERSIONS, MANUAL_TRY_FOLD, MANUAL_HASH_ONE, ITER_KV_MAP.
+    /// Lint: MANUAL_SPLIT_ONCE, MANUAL_STR_REPEAT, CLONED_INSTEAD_OF_COPIED, REDUNDANT_FIELD_NAMES, OPTION_MAP_UNWRAP_OR, REDUNDANT_STATIC_LIFETIMES, FILTER_MAP_NEXT, CHECKED_CONVERSIONS, MANUAL_RANGE_CONTAINS, USE_SELF, MEM_REPLACE_WITH_DEFAULT, MANUAL_NON_EXHAUSTIVE, OPTION_AS_REF_DEREF, MAP_UNWRAP_OR, MATCH_LIKE_MATCHES_MACRO, MANUAL_STRIP, MISSING_CONST_FOR_FN, UNNESTED_OR_PATTERNS, FROM_OVER_INTO, PTR_AS_PTR, IF_THEN_SOME_ELSE_NONE, APPROX_CONSTANT, DEPRECATED_CFG_ATTR, INDEX_REFUTABLE_SLICE, MAP_CLONE, BORROW_AS_PTR, MANUAL_BITS, ERR_EXPECT, CAST_ABS_TO_UNSIGNED, UNINLINED_FORMAT_ARGS, MANUAL_CLAMP, MANUAL_LET_ELSE, UNCHECKED_DURATION_SUBTRACTION, COLLAPSIBLE_STR_REPLACE, SEEK_FROM_CURRENT, SEEK_REWIND, UNNECESSARY_LAZY_EVALUATIONS, TRANSMUTE_PTR_TO_REF, ALMOST_COMPLETE_RANGE, NEEDLESS_BORROW, DERIVABLE_IMPLS, MANUAL_IS_ASCII_CHECK, MANUAL_REM_EUCLID, MANUAL_RETAIN, TYPE_REPETITION_IN_BOUNDS, TUPLE_ARRAY_CONVERSIONS, MANUAL_TRY_FOLD, MANUAL_HASH_ONE, ITER_KV_MAP, MANUAL_C_STR_LITERALS.
     ///
     /// The minimum rust version that the project supports. Defaults to the `rust-version` field in `Cargo.toml`
     #[default_text = ""]
@@ -567,6 +567,26 @@ define_Conf! {
     /// Lint "public" fields in a struct that are prefixed with an underscore based on their
     /// exported visibility, or whether they are marked as "pub".
     (pub_underscore_fields_behavior: PubUnderscoreFieldsBehaviour = PubUnderscoreFieldsBehaviour::PubliclyExported),
+    /// Lint: MODULO_ARITHMETIC.
+    ///
+    /// Don't lint when comparing the result of a modulo operation to zero.
+    (allow_comparison_to_zero: bool = true),
+    /// Lint: WILDCARD_IMPORTS.
+    ///
+    /// List of path segments allowed to have wildcard imports.
+    ///
+    /// #### Example
+    ///
+    /// ```toml
+    /// allowed-wildcard-imports = [ "utils", "common" ]
+    /// ```
+    ///
+    /// #### Noteworthy
+    ///
+    /// 1. This configuration has no effects if used with `warn_on_all_wildcard_imports = true`.
+    /// 2. Paths with any segment that containing the word 'prelude'
+    /// are already allowed by default.
+    (allowed_wildcard_imports: FxHashSet<String> = FxHashSet::default()),
 }
 
 /// Search for the configuration file.
diff --git a/src/tools/clippy/clippy_config/src/msrvs.rs b/src/tools/clippy/clippy_config/src/msrvs.rs
index 72d5b9aff28..f4389db627d 100644
--- a/src/tools/clippy/clippy_config/src/msrvs.rs
+++ b/src/tools/clippy/clippy_config/src/msrvs.rs
@@ -3,6 +3,7 @@ use rustc_semver::RustcVersion;
 use rustc_session::Session;
 use rustc_span::{sym, Symbol};
 use serde::Deserialize;
+use std::fmt;
 
 macro_rules! msrv_aliases {
     ($($major:literal,$minor:literal,$patch:literal {
@@ -16,6 +17,8 @@ macro_rules! msrv_aliases {
 
 // names may refer to stabilized feature flags or library items
 msrv_aliases! {
+    1,77,0 { C_STR_LITERALS }
+    1,76,0 { PTR_FROM_REF }
     1,71,0 { TUPLE_ARRAY_CONVERSIONS, BUILD_HASHER_HASH_ONE }
     1,70,0 { OPTION_RESULT_IS_VARIANT_AND, BINARY_HEAP_RETAIN }
     1,68,0 { PATH_MAIN_SEPARATOR_STR }
@@ -58,6 +61,16 @@ pub struct Msrv {
     stack: Vec<RustcVersion>,
 }
 
+impl fmt::Display for Msrv {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        if let Some(msrv) = self.current() {
+            write!(f, "{msrv}")
+        } else {
+            f.write_str("1.0.0")
+        }
+    }
+}
+
 impl<'de> Deserialize<'de> for Msrv {
     fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
     where
diff --git a/src/tools/clippy/clippy_lints/Cargo.toml b/src/tools/clippy/clippy_lints/Cargo.toml
index 416e9a680dd..6e6e315bb65 100644
--- a/src/tools/clippy/clippy_lints/Cargo.toml
+++ b/src/tools/clippy/clippy_lints/Cargo.toml
@@ -1,6 +1,6 @@
 [package]
 name = "clippy_lints"
-version = "0.1.77"
+version = "0.1.78"
 description = "A bunch of helpful lints to avoid common pitfalls in Rust"
 repository = "https://github.com/rust-lang/rust-clippy"
 readme = "README.md"
diff --git a/src/tools/clippy/clippy_lints/src/booleans.rs b/src/tools/clippy/clippy_lints/src/booleans.rs
index e11f83f2260..2d1c250ace9 100644
--- a/src/tools/clippy/clippy_lints/src/booleans.rs
+++ b/src/tools/clippy/clippy_lints/src/booleans.rs
@@ -499,6 +499,7 @@ struct NotSimplificationVisitor<'a, 'tcx> {
 impl<'a, 'tcx> Visitor<'tcx> for NotSimplificationVisitor<'a, 'tcx> {
     fn visit_expr(&mut self, expr: &'tcx Expr<'_>) {
         if let ExprKind::Unary(UnOp::Not, inner) = &expr.kind
+            && !expr.span.from_expansion()
             && !inner.span.from_expansion()
             && let Some(suggestion) = simplify_not(self.cx, inner)
             && self.cx.tcx.lint_level_at_node(NONMINIMAL_BOOL, expr.hir_id).0 != Level::Allow
diff --git a/src/tools/clippy/clippy_lints/src/cargo/lint_groups_priority.rs b/src/tools/clippy/clippy_lints/src/cargo/lint_groups_priority.rs
new file mode 100644
index 00000000000..a39b972b56a
--- /dev/null
+++ b/src/tools/clippy/clippy_lints/src/cargo/lint_groups_priority.rs
@@ -0,0 +1,168 @@
+use super::LINT_GROUPS_PRIORITY;
+use clippy_utils::diagnostics::span_lint_and_then;
+use rustc_data_structures::fx::FxHashSet;
+use rustc_errors::Applicability;
+use rustc_lint::{unerased_lint_store, LateContext};
+use rustc_span::{BytePos, Pos, SourceFile, Span, SyntaxContext};
+use serde::{Deserialize, Serialize};
+use std::collections::BTreeMap;
+use std::ops::Range;
+use std::path::Path;
+use toml::Spanned;
+
+#[derive(Deserialize, Serialize, Debug)]
+struct LintConfigTable {
+    level: String,
+    priority: Option<i64>,
+}
+
+#[derive(Deserialize, Debug)]
+#[serde(untagged)]
+enum LintConfig {
+    Level(String),
+    Table(LintConfigTable),
+}
+
+impl LintConfig {
+    fn level(&self) -> &str {
+        match self {
+            LintConfig::Level(level) => level,
+            LintConfig::Table(table) => &table.level,
+        }
+    }
+
+    fn priority(&self) -> i64 {
+        match self {
+            LintConfig::Level(_) => 0,
+            LintConfig::Table(table) => table.priority.unwrap_or(0),
+        }
+    }
+
+    fn is_implicit(&self) -> bool {
+        if let LintConfig::Table(table) = self {
+            table.priority.is_none()
+        } else {
+            true
+        }
+    }
+}
+
+type LintTable = BTreeMap<Spanned<String>, Spanned<LintConfig>>;
+
+#[derive(Deserialize, Debug)]
+struct Lints {
+    #[serde(default)]
+    rust: LintTable,
+    #[serde(default)]
+    clippy: LintTable,
+}
+
+#[derive(Deserialize, Debug)]
+struct CargoToml {
+    lints: Lints,
+}
+
+#[derive(Default, Debug)]
+struct LintsAndGroups {
+    lints: Vec<Spanned<String>>,
+    groups: Vec<(Spanned<String>, Spanned<LintConfig>)>,
+}
+
+fn toml_span(range: Range<usize>, file: &SourceFile) -> Span {
+    Span::new(
+        file.start_pos + BytePos::from_usize(range.start),
+        file.start_pos + BytePos::from_usize(range.end),
+        SyntaxContext::root(),
+        None,
+    )
+}
+
+fn check_table(cx: &LateContext<'_>, table: LintTable, groups: &FxHashSet<&str>, file: &SourceFile) {
+    let mut by_priority = BTreeMap::<_, LintsAndGroups>::new();
+    for (name, config) in table {
+        let lints_and_groups = by_priority.entry(config.as_ref().priority()).or_default();
+        if groups.contains(name.get_ref().as_str()) {
+            lints_and_groups.groups.push((name, config));
+        } else {
+            lints_and_groups.lints.push(name);
+        }
+    }
+    let low_priority = by_priority
+        .iter()
+        .find(|(_, lints_and_groups)| !lints_and_groups.lints.is_empty())
+        .map_or(-1, |(&lowest_lint_priority, _)| lowest_lint_priority - 1);
+
+    for (priority, LintsAndGroups { lints, groups }) in by_priority {
+        let Some(last_lint_alphabetically) = lints.last() else {
+            continue;
+        };
+
+        for (group, config) in groups {
+            span_lint_and_then(
+                cx,
+                LINT_GROUPS_PRIORITY,
+                toml_span(group.span(), file),
+                &format!(
+                    "lint group `{}` has the same priority ({priority}) as a lint",
+                    group.as_ref()
+                ),
+                |diag| {
+                    let config_span = toml_span(config.span(), file);
+                    if config.as_ref().is_implicit() {
+                        diag.span_label(config_span, "has an implicit priority of 0");
+                    }
+                    // add the label to next lint after this group that has the same priority
+                    let lint = lints
+                        .iter()
+                        .filter(|lint| lint.span().start > group.span().start)
+                        .min_by_key(|lint| lint.span().start)
+                        .unwrap_or(last_lint_alphabetically);
+                    diag.span_label(toml_span(lint.span(), file), "has the same priority as this lint");
+                    diag.note("the order of the lints in the table is ignored by Cargo");
+                    let mut suggestion = String::new();
+                    Serialize::serialize(
+                        &LintConfigTable {
+                            level: config.as_ref().level().into(),
+                            priority: Some(low_priority),
+                        },
+                        toml::ser::ValueSerializer::new(&mut suggestion),
+                    )
+                    .unwrap();
+                    diag.span_suggestion_verbose(
+                        config_span,
+                        format!(
+                            "to have lints override the group set `{}` to a lower priority",
+                            group.as_ref()
+                        ),
+                        suggestion,
+                        Applicability::MaybeIncorrect,
+                    );
+                },
+            );
+        }
+    }
+}
+
+pub fn check(cx: &LateContext<'_>) {
+    if let Ok(file) = cx.tcx.sess.source_map().load_file(Path::new("Cargo.toml"))
+        && let Some(src) = file.src.as_deref()
+        && let Ok(cargo_toml) = toml::from_str::<CargoToml>(src)
+    {
+        let mut rustc_groups = FxHashSet::default();
+        let mut clippy_groups = FxHashSet::default();
+        for (group, ..) in unerased_lint_store(cx.tcx.sess).get_lint_groups() {
+            match group.split_once("::") {
+                None => {
+                    rustc_groups.insert(group);
+                },
+                Some(("clippy", group)) => {
+                    clippy_groups.insert(group);
+                },
+                _ => {},
+            }
+        }
+
+        check_table(cx, cargo_toml.lints.rust, &rustc_groups, &file);
+        check_table(cx, cargo_toml.lints.clippy, &clippy_groups, &file);
+    }
+}
diff --git a/src/tools/clippy/clippy_lints/src/cargo/mod.rs b/src/tools/clippy/clippy_lints/src/cargo/mod.rs
index d8107f61f37..95d5449781b 100644
--- a/src/tools/clippy/clippy_lints/src/cargo/mod.rs
+++ b/src/tools/clippy/clippy_lints/src/cargo/mod.rs
@@ -1,5 +1,6 @@
 mod common_metadata;
 mod feature_name;
+mod lint_groups_priority;
 mod multiple_crate_versions;
 mod wildcard_dependencies;
 
@@ -165,6 +166,43 @@ declare_clippy_lint! {
     "wildcard dependencies being used"
 }
 
+declare_clippy_lint! {
+    /// ### What it does
+    /// Checks for lint groups with the same priority as lints in the `Cargo.toml`
+    /// [`[lints]` table](https://doc.rust-lang.org/cargo/reference/manifest.html#the-lints-section).
+    ///
+    /// This lint will be removed once [cargo#12918](https://github.com/rust-lang/cargo/issues/12918)
+    /// is resolved.
+    ///
+    /// ### Why is this bad?
+    /// The order of lints in the `[lints]` is ignored, to have a lint override a group the
+    /// `priority` field needs to be used, otherwise the sort order is undefined.
+    ///
+    /// ### Known problems
+    /// Does not check lints inherited using `lints.workspace = true`
+    ///
+    /// ### Example
+    /// ```toml
+    /// # Passed as `--allow=clippy::similar_names --warn=clippy::pedantic`
+    /// # which results in `similar_names` being `warn`
+    /// [lints.clippy]
+    /// pedantic = "warn"
+    /// similar_names = "allow"
+    /// ```
+    /// Use instead:
+    /// ```toml
+    /// # Passed as `--warn=clippy::pedantic --allow=clippy::similar_names`
+    /// # which results in `similar_names` being `allow`
+    /// [lints.clippy]
+    /// pedantic = { level = "warn", priority = -1 }
+    /// similar_names = "allow"
+    /// ```
+    #[clippy::version = "1.76.0"]
+    pub LINT_GROUPS_PRIORITY,
+    correctness,
+    "a lint group in `Cargo.toml` at the same priority as a lint"
+}
+
 pub struct Cargo {
     pub allowed_duplicate_crates: FxHashSet<String>,
     pub ignore_publish: bool,
@@ -175,7 +213,8 @@ impl_lint_pass!(Cargo => [
     REDUNDANT_FEATURE_NAMES,
     NEGATIVE_FEATURE_NAMES,
     MULTIPLE_CRATE_VERSIONS,
-    WILDCARD_DEPENDENCIES
+    WILDCARD_DEPENDENCIES,
+    LINT_GROUPS_PRIORITY,
 ]);
 
 impl LateLintPass<'_> for Cargo {
@@ -188,6 +227,8 @@ impl LateLintPass<'_> for Cargo {
         ];
         static WITH_DEPS_LINTS: &[&Lint] = &[MULTIPLE_CRATE_VERSIONS];
 
+        lint_groups_priority::check(cx);
+
         if !NO_DEPS_LINTS
             .iter()
             .all(|&lint| is_lint_allowed(cx, lint, CRATE_HIR_ID))
diff --git a/src/tools/clippy/clippy_lints/src/casts/mod.rs b/src/tools/clippy/clippy_lints/src/casts/mod.rs
index e05b8f66d86..14f2f4a7f59 100644
--- a/src/tools/clippy/clippy_lints/src/casts/mod.rs
+++ b/src/tools/clippy/clippy_lints/src/casts/mod.rs
@@ -18,6 +18,7 @@ mod fn_to_numeric_cast_any;
 mod fn_to_numeric_cast_with_truncation;
 mod ptr_as_ptr;
 mod ptr_cast_constness;
+mod ref_as_ptr;
 mod unnecessary_cast;
 mod utils;
 mod zero_ptr;
@@ -689,6 +690,30 @@ declare_clippy_lint! {
     "using `0 as *{const, mut} T`"
 }
 
+declare_clippy_lint! {
+    /// ### What it does
+    /// Checks for casts of references to pointer using `as`
+    /// and suggests `std::ptr::from_ref` and `std::ptr::from_mut` instead.
+    ///
+    /// ### Why is this bad?
+    /// Using `as` casts may result in silently changing mutability or type.
+    ///
+    /// ### Example
+    /// ```no_run
+    /// let a_ref = &1;
+    /// let a_ptr = a_ref as *const _;
+    /// ```
+    /// Use instead:
+    /// ```no_run
+    /// let a_ref = &1;
+    /// let a_ptr = std::ptr::from_ref(a_ref);
+    /// ```
+    #[clippy::version = "1.77.0"]
+    pub REF_AS_PTR,
+    pedantic,
+    "using `as` to cast a reference to pointer"
+}
+
 pub struct Casts {
     msrv: Msrv,
 }
@@ -724,6 +749,7 @@ impl_lint_pass!(Casts => [
     AS_PTR_CAST_MUT,
     CAST_NAN_TO_INT,
     ZERO_PTR,
+    REF_AS_PTR,
 ]);
 
 impl<'tcx> LateLintPass<'tcx> for Casts {
@@ -771,7 +797,9 @@ impl<'tcx> LateLintPass<'tcx> for Casts {
 
             as_underscore::check(cx, expr, cast_to_hir);
 
-            if self.msrv.meets(msrvs::BORROW_AS_PTR) {
+            if self.msrv.meets(msrvs::PTR_FROM_REF) {
+                ref_as_ptr::check(cx, expr, cast_expr, cast_to_hir);
+            } else if self.msrv.meets(msrvs::BORROW_AS_PTR) {
                 borrow_as_ptr::check(cx, expr, cast_expr, cast_to_hir);
             }
         }
diff --git a/src/tools/clippy/clippy_lints/src/casts/ref_as_ptr.rs b/src/tools/clippy/clippy_lints/src/casts/ref_as_ptr.rs
new file mode 100644
index 00000000000..d600d2aec1b
--- /dev/null
+++ b/src/tools/clippy/clippy_lints/src/casts/ref_as_ptr.rs
@@ -0,0 +1,55 @@
+use clippy_utils::diagnostics::span_lint_and_sugg;
+use clippy_utils::is_no_std_crate;
+use clippy_utils::source::snippet_with_applicability;
+use clippy_utils::sugg::Sugg;
+use rustc_errors::Applicability;
+use rustc_hir::{Expr, Mutability, Ty, TyKind};
+use rustc_lint::LateContext;
+use rustc_middle::ty::{self, TypeAndMut};
+
+use super::REF_AS_PTR;
+
+pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, cast_expr: &Expr<'_>, cast_to_hir_ty: &Ty<'_>) {
+    let (cast_from, cast_to) = (
+        cx.typeck_results().expr_ty(cast_expr),
+        cx.typeck_results().expr_ty(expr),
+    );
+
+    if matches!(cast_from.kind(), ty::Ref(..))
+        && let ty::RawPtr(TypeAndMut { mutbl: to_mutbl, .. }) = cast_to.kind()
+    {
+        let core_or_std = if is_no_std_crate(cx) { "core" } else { "std" };
+        let fn_name = match to_mutbl {
+            Mutability::Not => "from_ref",
+            Mutability::Mut => "from_mut",
+        };
+
+        let mut app = Applicability::MachineApplicable;
+        let turbofish = match &cast_to_hir_ty.kind {
+            TyKind::Infer => String::new(),
+            TyKind::Ptr(mut_ty) => {
+                if matches!(mut_ty.ty.kind, TyKind::Infer) {
+                    String::new()
+                } else {
+                    format!(
+                        "::<{}>",
+                        snippet_with_applicability(cx, mut_ty.ty.span, "/* type */", &mut app)
+                    )
+                }
+            },
+            _ => return,
+        };
+
+        let cast_expr_sugg = Sugg::hir_with_applicability(cx, cast_expr, "_", &mut app);
+
+        span_lint_and_sugg(
+            cx,
+            REF_AS_PTR,
+            expr.span,
+            "reference as raw pointer",
+            "try",
+            format!("{core_or_std}::ptr::{fn_name}{turbofish}({cast_expr_sugg})"),
+            app,
+        );
+    }
+}
diff --git a/src/tools/clippy/clippy_lints/src/declared_lints.rs b/src/tools/clippy/clippy_lints/src/declared_lints.rs
index 639edd8da30..0a5baabd973 100644
--- a/src/tools/clippy/clippy_lints/src/declared_lints.rs
+++ b/src/tools/clippy/clippy_lints/src/declared_lints.rs
@@ -71,6 +71,7 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[
     crate::borrow_deref_ref::BORROW_DEREF_REF_INFO,
     crate::box_default::BOX_DEFAULT_INFO,
     crate::cargo::CARGO_COMMON_METADATA_INFO,
+    crate::cargo::LINT_GROUPS_PRIORITY_INFO,
     crate::cargo::MULTIPLE_CRATE_VERSIONS_INFO,
     crate::cargo::NEGATIVE_FEATURE_NAMES_INFO,
     crate::cargo::REDUNDANT_FEATURE_NAMES_INFO,
@@ -96,6 +97,7 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[
     crate::casts::FN_TO_NUMERIC_CAST_WITH_TRUNCATION_INFO,
     crate::casts::PTR_AS_PTR_INFO,
     crate::casts::PTR_CAST_CONSTNESS_INFO,
+    crate::casts::REF_AS_PTR_INFO,
     crate::casts::UNNECESSARY_CAST_INFO,
     crate::casts::ZERO_PTR_INFO,
     crate::checked_conversions::CHECKED_CONVERSIONS_INFO,
@@ -212,6 +214,7 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[
     crate::implicit_saturating_add::IMPLICIT_SATURATING_ADD_INFO,
     crate::implicit_saturating_sub::IMPLICIT_SATURATING_SUB_INFO,
     crate::implied_bounds_in_impls::IMPLIED_BOUNDS_IN_IMPLS_INFO,
+    crate::incompatible_msrv::INCOMPATIBLE_MSRV_INFO,
     crate::inconsistent_struct_constructor::INCONSISTENT_STRUCT_CONSTRUCTOR_INFO,
     crate::index_refutable_slice::INDEX_REFUTABLE_SLICE_INFO,
     crate::indexing_slicing::INDEXING_SLICING_INFO,
@@ -384,6 +387,7 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[
     crate::methods::ITER_SKIP_ZERO_INFO,
     crate::methods::ITER_WITH_DRAIN_INFO,
     crate::methods::JOIN_ABSOLUTE_PATHS_INFO,
+    crate::methods::MANUAL_C_STR_LITERALS_INFO,
     crate::methods::MANUAL_FILTER_MAP_INFO,
     crate::methods::MANUAL_FIND_MAP_INFO,
     crate::methods::MANUAL_IS_VARIANT_AND_INFO,
@@ -452,6 +456,7 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[
     crate::methods::UNNECESSARY_JOIN_INFO,
     crate::methods::UNNECESSARY_LAZY_EVALUATIONS_INFO,
     crate::methods::UNNECESSARY_LITERAL_UNWRAP_INFO,
+    crate::methods::UNNECESSARY_RESULT_MAP_OR_ELSE_INFO,
     crate::methods::UNNECESSARY_SORT_BY_INFO,
     crate::methods::UNNECESSARY_TO_OWNED_INFO,
     crate::methods::UNWRAP_OR_DEFAULT_INFO,
@@ -656,6 +661,7 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[
     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,
     crate::trait_bounds::TRAIT_DUPLICATION_IN_BOUNDS_INFO,
     crate::trait_bounds::TYPE_REPETITION_IN_BOUNDS_INFO,
diff --git a/src/tools/clippy/clippy_lints/src/doc/mod.rs b/src/tools/clippy/clippy_lints/src/doc/mod.rs
index ba452775015..2b4ce6ddfaa 100644
--- a/src/tools/clippy/clippy_lints/src/doc/mod.rs
+++ b/src/tools/clippy/clippy_lints/src/doc/mod.rs
@@ -226,7 +226,7 @@ declare_clippy_lint! {
     ///     unimplemented!();
     /// }
     /// ```
-    #[clippy::version = "1.40.0"]
+    #[clippy::version = "1.76.0"]
     pub TEST_ATTR_IN_DOCTEST,
     suspicious,
     "presence of `#[test]` in code examples"
diff --git a/src/tools/clippy/clippy_lints/src/eta_reduction.rs b/src/tools/clippy/clippy_lints/src/eta_reduction.rs
index 450cee4007c..40be71a0e5d 100644
--- a/src/tools/clippy/clippy_lints/src/eta_reduction.rs
+++ b/src/tools/clippy/clippy_lints/src/eta_reduction.rs
@@ -3,15 +3,14 @@ use clippy_utils::higher::VecArgs;
 use clippy_utils::source::snippet_opt;
 use clippy_utils::ty::type_diagnostic_name;
 use clippy_utils::usage::{local_used_after_expr, local_used_in};
-use clippy_utils::{higher, is_adjusted, path_to_local, path_to_local_id};
+use clippy_utils::{get_path_from_caller_to_method_type, higher, is_adjusted, path_to_local, path_to_local_id};
 use rustc_errors::Applicability;
-use rustc_hir::def_id::DefId;
 use rustc_hir::{BindingAnnotation, Expr, ExprKind, FnRetTy, Param, PatKind, QPath, TyKind, Unsafety};
 use rustc_infer::infer::TyCtxtInferExt;
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_middle::ty::{
-    self, Binder, ClosureArgs, ClosureKind, EarlyBinder, FnSig, GenericArg, GenericArgKind, GenericArgsRef,
-    ImplPolarity, List, Region, RegionKind, Ty, TypeVisitableExt, TypeckResults,
+    self, Binder, ClosureArgs, ClosureKind, FnSig, GenericArg, GenericArgKind, ImplPolarity, List, Region, RegionKind,
+    Ty, TypeVisitableExt, TypeckResults,
 };
 use rustc_session::declare_lint_pass;
 use rustc_span::symbol::sym;
@@ -21,8 +20,8 @@ use rustc_trait_selection::traits::error_reporting::InferCtxtExt as _;
 declare_clippy_lint! {
     /// ### What it does
     /// Checks for closures which just call another function where
-    /// the function can be called directly. `unsafe` functions or calls where types
-    /// get adjusted are ignored.
+    /// the function can be called directly. `unsafe` functions, calls where types
+    /// get adjusted or where the callee is marked `#[track_caller]` are ignored.
     ///
     /// ### Why is this bad?
     /// Needlessly creating a closure adds code for no benefit
@@ -136,7 +135,14 @@ impl<'tcx> LateLintPass<'tcx> for EtaReduction {
                     .map_or(callee_ty, |a| a.target.peel_refs());
 
                 let sig = match callee_ty_adjusted.kind() {
-                    ty::FnDef(def, _) => cx.tcx.fn_sig(def).skip_binder().skip_binder(),
+                    ty::FnDef(def, _) => {
+                        // Rewriting `x(|| f())` to `x(f)` where f is marked `#[track_caller]` moves the `Location`
+                        if cx.tcx.has_attr(*def, sym::track_caller) {
+                            return;
+                        }
+
+                        cx.tcx.fn_sig(def).skip_binder().skip_binder()
+                    },
                     ty::FnPtr(sig) => sig.skip_binder(),
                     ty::Closure(_, subs) => cx
                         .tcx
@@ -186,6 +192,7 @@ impl<'tcx> LateLintPass<'tcx> for EtaReduction {
             },
             ExprKind::MethodCall(path, self_, args, _) if check_inputs(typeck, body.params, Some(self_), args) => {
                 if let Some(method_def_id) = typeck.type_dependent_def_id(body.value.hir_id)
+                    && !cx.tcx.has_attr(method_def_id, sym::track_caller)
                     && check_sig(cx, closure, cx.tcx.fn_sig(method_def_id).skip_binder().skip_binder())
                 {
                     span_lint_and_then(
@@ -195,11 +202,12 @@ impl<'tcx> LateLintPass<'tcx> for EtaReduction {
                         "redundant closure",
                         |diag| {
                             let args = typeck.node_args(body.value.hir_id);
-                            let name = get_ufcs_type_name(cx, method_def_id, args);
+                            let caller = self_.hir_id.owner.def_id;
+                            let type_name = get_path_from_caller_to_method_type(cx.tcx, caller, method_def_id, args);
                             diag.span_suggestion(
                                 expr.span,
                                 "replace the closure with the method itself",
-                                format!("{}::{}", name, path.ident.name),
+                                format!("{}::{}", type_name, path.ident.name),
                                 Applicability::MachineApplicable,
                             );
                         },
@@ -301,27 +309,3 @@ fn has_late_bound_to_non_late_bound_regions(from_sig: FnSig<'_>, to_sig: FnSig<'
         .zip(to_sig.inputs_and_output)
         .any(|(from_ty, to_ty)| check_ty(from_ty, to_ty))
 }
-
-fn get_ufcs_type_name<'tcx>(cx: &LateContext<'tcx>, method_def_id: DefId, args: GenericArgsRef<'tcx>) -> String {
-    let assoc_item = cx.tcx.associated_item(method_def_id);
-    let def_id = assoc_item.container_id(cx.tcx);
-    match assoc_item.container {
-        ty::TraitContainer => cx.tcx.def_path_str(def_id),
-        ty::ImplContainer => {
-            let ty = cx.tcx.type_of(def_id).instantiate_identity();
-            match ty.kind() {
-                ty::Adt(adt, _) => cx.tcx.def_path_str(adt.did()),
-                ty::Array(..)
-                | ty::Dynamic(..)
-                | ty::Never
-                | ty::RawPtr(_)
-                | ty::Ref(..)
-                | ty::Slice(_)
-                | ty::Tuple(_) => {
-                    format!("<{}>", EarlyBinder::bind(ty).instantiate(cx.tcx, args))
-                },
-                _ => ty.to_string(),
-            }
-        },
-    }
-}
diff --git a/src/tools/clippy/clippy_lints/src/incompatible_msrv.rs b/src/tools/clippy/clippy_lints/src/incompatible_msrv.rs
new file mode 100644
index 00000000000..f2f0e7d4266
--- /dev/null
+++ b/src/tools/clippy/clippy_lints/src/incompatible_msrv.rs
@@ -0,0 +1,133 @@
+use clippy_config::msrvs::Msrv;
+use clippy_utils::diagnostics::span_lint;
+use rustc_attr::{StabilityLevel, StableSince};
+use rustc_data_structures::fx::FxHashMap;
+use rustc_hir::{Expr, ExprKind};
+use rustc_lint::{LateContext, LateLintPass};
+use rustc_middle::ty::TyCtxt;
+use rustc_semver::RustcVersion;
+use rustc_session::impl_lint_pass;
+use rustc_span::def_id::DefId;
+use rustc_span::Span;
+
+declare_clippy_lint! {
+    /// ### What it does
+    ///
+    /// This lint checks that no function newer than the defined MSRV (minimum
+    /// supported rust version) is used in the crate.
+    ///
+    /// ### Why is this bad?
+    ///
+    /// It would prevent the crate to be actually used with the specified MSRV.
+    ///
+    /// ### Example
+    /// ```no_run
+    /// // MSRV of 1.3.0
+    /// use std::thread::sleep;
+    /// use std::time::Duration;
+    ///
+    /// // Sleep was defined in `1.4.0`.
+    /// sleep(Duration::new(1, 0));
+    /// ```
+    ///
+    /// To fix this problem, either increase your MSRV or use another item
+    /// available in your current MSRV.
+    #[clippy::version = "1.77.0"]
+    pub INCOMPATIBLE_MSRV,
+    suspicious,
+    "ensures that all items used in the crate are available for the current MSRV"
+}
+
+pub struct IncompatibleMsrv {
+    msrv: Msrv,
+    is_above_msrv: FxHashMap<DefId, RustcVersion>,
+}
+
+impl_lint_pass!(IncompatibleMsrv => [INCOMPATIBLE_MSRV]);
+
+impl IncompatibleMsrv {
+    pub fn new(msrv: Msrv) -> Self {
+        Self {
+            msrv,
+            is_above_msrv: FxHashMap::default(),
+        }
+    }
+
+    #[allow(clippy::cast_lossless)]
+    fn get_def_id_version(&mut self, tcx: TyCtxt<'_>, def_id: DefId) -> RustcVersion {
+        if let Some(version) = self.is_above_msrv.get(&def_id) {
+            return *version;
+        }
+        let version = if let Some(version) = tcx
+            .lookup_stability(def_id)
+            .and_then(|stability| match stability.level {
+                StabilityLevel::Stable {
+                    since: StableSince::Version(version),
+                    ..
+                } => Some(RustcVersion::new(
+                    version.major as _,
+                    version.minor as _,
+                    version.patch as _,
+                )),
+                _ => None,
+            }) {
+            version
+        } else if let Some(parent_def_id) = tcx.opt_parent(def_id) {
+            self.get_def_id_version(tcx, parent_def_id)
+        } else {
+            RustcVersion::new(1, 0, 0)
+        };
+        self.is_above_msrv.insert(def_id, version);
+        version
+    }
+
+    fn emit_lint_if_under_msrv(&mut self, cx: &LateContext<'_>, def_id: DefId, span: Span) {
+        if def_id.is_local() {
+            // We don't check local items since their MSRV is supposed to always be valid.
+            return;
+        }
+        let version = self.get_def_id_version(cx.tcx, def_id);
+        if self.msrv.meets(version) {
+            return;
+        }
+        self.emit_lint_for(cx, span, version);
+    }
+
+    fn emit_lint_for(&self, cx: &LateContext<'_>, span: Span, version: RustcVersion) {
+        span_lint(
+            cx,
+            INCOMPATIBLE_MSRV,
+            span,
+            &format!(
+                "current MSRV (Minimum Supported Rust Version) is `{}` but this item is stable since `{version}`",
+                self.msrv
+            ),
+        );
+    }
+}
+
+impl<'tcx> LateLintPass<'tcx> for IncompatibleMsrv {
+    extract_msrv_attr!(LateContext);
+
+    fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) {
+        if self.msrv.current().is_none() {
+            // If there is no MSRV, then no need to check anything...
+            return;
+        }
+        match expr.kind {
+            ExprKind::MethodCall(_, _, _, span) => {
+                if let Some(method_did) = cx.typeck_results().type_dependent_def_id(expr.hir_id) {
+                    self.emit_lint_if_under_msrv(cx, method_did, span);
+                }
+            },
+            ExprKind::Call(call, [_]) => {
+                if let ExprKind::Path(qpath) = call.kind
+                    && let Some(path_def_id) = cx.qpath_res(&qpath, call.hir_id).opt_def_id()
+                {
+                    self.emit_lint_if_under_msrv(cx, path_def_id, call.span);
+                }
+            },
+            _ => {},
+        }
+    }
+}
diff --git a/src/tools/clippy/clippy_lints/src/iter_over_hash_type.rs b/src/tools/clippy/clippy_lints/src/iter_over_hash_type.rs
index 8110c1970d9..6c6eff9ba48 100644
--- a/src/tools/clippy/clippy_lints/src/iter_over_hash_type.rs
+++ b/src/tools/clippy/clippy_lints/src/iter_over_hash_type.rs
@@ -34,7 +34,7 @@ declare_clippy_lint! {
     ///         let value = &my_map[key];
     ///     }
     /// ```
-    #[clippy::version = "1.75.0"]
+    #[clippy::version = "1.76.0"]
     pub ITER_OVER_HASH_TYPE,
     restriction,
     "iterating over unordered hash-based types (`HashMap` and `HashSet`)"
diff --git a/src/tools/clippy/clippy_lints/src/lib.rs b/src/tools/clippy/clippy_lints/src/lib.rs
index f6608b22953..14bd82f9c97 100644
--- a/src/tools/clippy/clippy_lints/src/lib.rs
+++ b/src/tools/clippy/clippy_lints/src/lib.rs
@@ -31,6 +31,7 @@ extern crate rustc_abi;
 extern crate rustc_arena;
 extern crate rustc_ast;
 extern crate rustc_ast_pretty;
+extern crate rustc_attr;
 extern crate rustc_data_structures;
 extern crate rustc_driver;
 extern crate rustc_errors;
@@ -158,6 +159,7 @@ mod implicit_return;
 mod implicit_saturating_add;
 mod implicit_saturating_sub;
 mod implied_bounds_in_impls;
+mod incompatible_msrv;
 mod inconsistent_struct_constructor;
 mod index_refutable_slice;
 mod indexing_slicing;
@@ -330,6 +332,7 @@ 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;
 mod trait_bounds;
 mod transmute;
@@ -526,6 +529,7 @@ pub fn register_lints(store: &mut rustc_lint::LintStore, conf: &'static Conf) {
         ref allowed_dotfiles,
         ref allowed_idents_below_min_chars,
         ref allowed_scripts,
+        ref allowed_wildcard_imports,
         ref arithmetic_side_effects_allowed_binary,
         ref arithmetic_side_effects_allowed_unary,
         ref arithmetic_side_effects_allowed,
@@ -580,6 +584,7 @@ pub fn register_lints(store: &mut rustc_lint::LintStore, conf: &'static Conf) {
         check_private_items,
         pub_underscore_fields_behavior,
         ref allowed_duplicate_crates,
+        allow_comparison_to_zero,
 
         blacklisted_names: _,
         cyclomatic_complexity_threshold: _,
@@ -877,7 +882,12 @@ pub fn register_lints(store: &mut rustc_lint::LintStore, conf: &'static Conf) {
         ))
     });
     store.register_early_pass(|| Box::new(option_env_unwrap::OptionEnvUnwrap));
-    store.register_late_pass(move |_| Box::new(wildcard_imports::WildcardImports::new(warn_on_all_wildcard_imports)));
+    store.register_late_pass(move |_| {
+        Box::new(wildcard_imports::WildcardImports::new(
+            warn_on_all_wildcard_imports,
+            allowed_wildcard_imports.clone(),
+        ))
+    });
     store.register_late_pass(|_| Box::<redundant_pub_crate::RedundantPubCrate>::default());
     store.register_late_pass(|_| Box::new(unnamed_address::UnnamedAddress));
     store.register_late_pass(|_| Box::<dereference::Dereferencing<'_>>::default());
@@ -973,7 +983,12 @@ 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(operators::Operators::new(verbose_bit_mask_threshold)));
+    store.register_late_pass(move |_| {
+        Box::new(operators::Operators::new(
+            verbose_bit_mask_threshold,
+            allow_comparison_to_zero,
+        ))
+    });
     store.register_late_pass(|_| Box::<std_instead_of_core::StdReexports>::default());
     store.register_late_pass(move |_| Box::new(instant_subtraction::InstantSubtraction::new(msrv())));
     store.register_late_pass(|_| Box::new(partialeq_to_none::PartialeqToNone));
@@ -1099,6 +1114,8 @@ pub fn register_lints(store: &mut rustc_lint::LintStore, conf: &'static Conf) {
     store.register_late_pass(move |_| {
         Box::new(thread_local_initializer_can_be_made_const::ThreadLocalInitializerCanBeMadeConst::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));
     // add lints here, do not remove this comment, it's used in `new_lint`
 }
 
diff --git a/src/tools/clippy/clippy_lints/src/loops/mod.rs b/src/tools/clippy/clippy_lints/src/loops/mod.rs
index 3c9bde86bb6..b5e39b33c6a 100644
--- a/src/tools/clippy/clippy_lints/src/loops/mod.rs
+++ b/src/tools/clippy/clippy_lints/src/loops/mod.rs
@@ -672,7 +672,7 @@ declare_clippy_lint! {
     ///     }
     /// }
     /// ```
-    #[clippy::version = "1.75.0"]
+    #[clippy::version = "1.76.0"]
     pub INFINITE_LOOP,
     restriction,
     "possibly unintended infinite loop"
diff --git a/src/tools/clippy/clippy_lints/src/loops/never_loop.rs b/src/tools/clippy/clippy_lints/src/loops/never_loop.rs
index 62bc663191f..245a903f998 100644
--- a/src/tools/clippy/clippy_lints/src/loops/never_loop.rs
+++ b/src/tools/clippy/clippy_lints/src/loops/never_loop.rs
@@ -201,12 +201,12 @@ fn never_loop_expr<'tcx>(
                 })
             })
         },
-        ExprKind::Block(b, l) => {
-            if l.is_some() {
+        ExprKind::Block(b, _) => {
+            if b.targeted_by_break {
                 local_labels.push((b.hir_id, false));
             }
             let ret = never_loop_block(cx, b, local_labels, main_loop_id);
-            let jumped_to = l.is_some() && local_labels.pop().unwrap().1;
+            let jumped_to = b.targeted_by_break && local_labels.pop().unwrap().1;
             match ret {
                 NeverLoopResult::Diverging if jumped_to => NeverLoopResult::Normal,
                 _ => ret,
diff --git a/src/tools/clippy/clippy_lints/src/manual_retain.rs b/src/tools/clippy/clippy_lints/src/manual_retain.rs
index 1fe247dacb9..6f15fca089e 100644
--- a/src/tools/clippy/clippy_lints/src/manual_retain.rs
+++ b/src/tools/clippy/clippy_lints/src/manual_retain.rs
@@ -11,6 +11,7 @@ use rustc_lint::{LateContext, LateLintPass};
 use rustc_semver::RustcVersion;
 use rustc_session::impl_lint_pass;
 use rustc_span::symbol::sym;
+use rustc_span::Span;
 
 const ACCEPTABLE_METHODS: [&[&str]; 5] = [
     &paths::BINARYHEAP_ITER,
@@ -28,6 +29,7 @@ const ACCEPTABLE_TYPES: [(rustc_span::Symbol, Option<RustcVersion>); 7] = [
     (sym::Vec, None),
     (sym::VecDeque, None),
 ];
+const MAP_TYPES: [rustc_span::Symbol; 2] = [sym::BTreeMap, sym::HashMap];
 
 declare_clippy_lint! {
     /// ### What it does
@@ -44,6 +46,7 @@ declare_clippy_lint! {
     /// ```no_run
     /// let mut vec = vec![0, 1, 2];
     /// vec.retain(|x| x % 2 == 0);
+    /// vec.retain(|x| x % 2 == 0);
     /// ```
     #[clippy::version = "1.64.0"]
     pub MANUAL_RETAIN,
@@ -74,9 +77,9 @@ impl<'tcx> LateLintPass<'tcx> for ManualRetain {
             && 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)
         {
-            check_into_iter(cx, parent_expr, left_expr, target_expr, &self.msrv);
-            check_iter(cx, parent_expr, left_expr, target_expr, &self.msrv);
-            check_to_owned(cx, parent_expr, left_expr, target_expr, &self.msrv);
+            check_into_iter(cx, left_expr, target_expr, parent_expr.span, &self.msrv);
+            check_iter(cx, left_expr, target_expr, parent_expr.span, &self.msrv);
+            check_to_owned(cx, left_expr, target_expr, parent_expr.span, &self.msrv);
         }
     }
 
@@ -85,9 +88,9 @@ impl<'tcx> LateLintPass<'tcx> for ManualRetain {
 
 fn check_into_iter(
     cx: &LateContext<'_>,
-    parent_expr: &hir::Expr<'_>,
     left_expr: &hir::Expr<'_>,
     target_expr: &hir::Expr<'_>,
+    parent_expr_span: Span,
     msrv: &Msrv,
 ) {
     if let hir::ExprKind::MethodCall(_, into_iter_expr, [_], _) = &target_expr.kind
@@ -98,16 +101,39 @@ fn check_into_iter(
         && Some(into_iter_def_id) == cx.tcx.lang_items().into_iter_fn()
         && match_acceptable_type(cx, left_expr, msrv)
         && SpanlessEq::new(cx).eq_expr(left_expr, struct_expr)
+        && let hir::ExprKind::MethodCall(_, _, [closure_expr], _) = target_expr.kind
+        && let hir::ExprKind::Closure(closure) = closure_expr.kind
+        && let filter_body = cx.tcx.hir().body(closure.body)
+        && let [filter_params] = filter_body.params
     {
-        suggest(cx, parent_expr, left_expr, target_expr);
+        if match_map_type(cx, left_expr) {
+            if let hir::PatKind::Tuple([key_pat, value_pat], _) = filter_params.pat.kind {
+                if let Some(sugg) = make_sugg(cx, key_pat, value_pat, left_expr, filter_body) {
+                    make_span_lint_and_sugg(cx, parent_expr_span, sugg);
+                }
+            }
+            // Cannot lint other cases because `retain` requires two parameters
+        } else {
+            // Can always move because `retain` and `filter` have the same bound on the predicate
+            // for other types
+            make_span_lint_and_sugg(
+                cx,
+                parent_expr_span,
+                format!(
+                    "{}.retain({})",
+                    snippet(cx, left_expr.span, ".."),
+                    snippet(cx, closure_expr.span, "..")
+                ),
+            );
+        }
     }
 }
 
 fn check_iter(
     cx: &LateContext<'_>,
-    parent_expr: &hir::Expr<'_>,
     left_expr: &hir::Expr<'_>,
     target_expr: &hir::Expr<'_>,
+    parent_expr_span: Span,
     msrv: &Msrv,
 ) {
     if let hir::ExprKind::MethodCall(_, filter_expr, [], _) = &target_expr.kind
@@ -122,16 +148,50 @@ fn check_iter(
         && match_acceptable_def_path(cx, iter_expr_def_id)
         && match_acceptable_type(cx, left_expr, msrv)
         && SpanlessEq::new(cx).eq_expr(left_expr, struct_expr)
+        && let hir::ExprKind::MethodCall(_, _, [closure_expr], _) = filter_expr.kind
+        && let hir::ExprKind::Closure(closure) = closure_expr.kind
+        && let filter_body = cx.tcx.hir().body(closure.body)
+        && let [filter_params] = filter_body.params
     {
-        suggest(cx, parent_expr, left_expr, filter_expr);
+        match filter_params.pat.kind {
+            // hir::PatKind::Binding(_, _, _, None) => {
+            //     // Be conservative now. Do nothing here.
+            //     // TODO: Ideally, we can rewrite the lambda by stripping one level of reference
+            // },
+            hir::PatKind::Tuple([_, _], _) => {
+                // the `&&` reference for the `filter` method will be auto derefed to `ref`
+                // so, we can directly use the lambda
+                // https://doc.rust-lang.org/reference/patterns.html#binding-modes
+                make_span_lint_and_sugg(
+                    cx,
+                    parent_expr_span,
+                    format!(
+                        "{}.retain({})",
+                        snippet(cx, left_expr.span, ".."),
+                        snippet(cx, closure_expr.span, "..")
+                    ),
+                );
+            },
+            hir::PatKind::Ref(pat, _) => make_span_lint_and_sugg(
+                cx,
+                parent_expr_span,
+                format!(
+                    "{}.retain(|{}| {})",
+                    snippet(cx, left_expr.span, ".."),
+                    snippet(cx, pat.span, ".."),
+                    snippet(cx, filter_body.value.span, "..")
+                ),
+            ),
+            _ => {},
+        }
     }
 }
 
 fn check_to_owned(
     cx: &LateContext<'_>,
-    parent_expr: &hir::Expr<'_>,
     left_expr: &hir::Expr<'_>,
     target_expr: &hir::Expr<'_>,
+    parent_expr_span: Span,
     msrv: &Msrv,
 ) {
     if msrv.meets(msrvs::STRING_RETAIN)
@@ -147,43 +207,25 @@ fn check_to_owned(
         && let ty = cx.typeck_results().expr_ty(str_expr).peel_refs()
         && is_type_lang_item(cx, ty, hir::LangItem::String)
         && SpanlessEq::new(cx).eq_expr(left_expr, str_expr)
-    {
-        suggest(cx, parent_expr, left_expr, filter_expr);
-    }
-}
-
-fn suggest(cx: &LateContext<'_>, parent_expr: &hir::Expr<'_>, left_expr: &hir::Expr<'_>, filter_expr: &hir::Expr<'_>) {
-    if let hir::ExprKind::MethodCall(_, _, [closure], _) = filter_expr.kind
-        && let hir::ExprKind::Closure(&hir::Closure { body, .. }) = closure.kind
-        && let filter_body = cx.tcx.hir().body(body)
+        && let hir::ExprKind::MethodCall(_, _, [closure_expr], _) = filter_expr.kind
+        && let hir::ExprKind::Closure(closure) = closure_expr.kind
+        && let filter_body = cx.tcx.hir().body(closure.body)
         && let [filter_params] = filter_body.params
-        && let Some(sugg) = match filter_params.pat.kind {
-            hir::PatKind::Binding(_, _, filter_param_ident, None) => Some(format!(
-                "{}.retain(|{filter_param_ident}| {})",
-                snippet(cx, left_expr.span, ".."),
-                snippet(cx, filter_body.value.span, "..")
-            )),
-            hir::PatKind::Tuple([key_pat, value_pat], _) => make_sugg(cx, key_pat, value_pat, left_expr, filter_body),
-            hir::PatKind::Ref(pat, _) => match pat.kind {
-                hir::PatKind::Binding(_, _, filter_param_ident, None) => Some(format!(
-                    "{}.retain(|{filter_param_ident}| {})",
+    {
+        if let hir::PatKind::Ref(pat, _) = filter_params.pat.kind {
+            make_span_lint_and_sugg(
+                cx,
+                parent_expr_span,
+                format!(
+                    "{}.retain(|{}| {})",
                     snippet(cx, left_expr.span, ".."),
+                    snippet(cx, pat.span, ".."),
                     snippet(cx, filter_body.value.span, "..")
-                )),
-                _ => None,
-            },
-            _ => None,
+                ),
+            );
         }
-    {
-        span_lint_and_sugg(
-            cx,
-            MANUAL_RETAIN,
-            parent_expr.span,
-            "this expression can be written more simply using `.retain()`",
-            "consider calling `.retain()` instead",
-            sugg,
-            Applicability::MachineApplicable,
-        );
+        // Be conservative now. Do nothing for the `Binding` case.
+        // TODO: Ideally, we can rewrite the lambda by stripping one level of reference
     }
 }
 
@@ -229,3 +271,20 @@ fn match_acceptable_type(cx: &LateContext<'_>, expr: &hir::Expr<'_>, msrv: &Msrv
             && acceptable_msrv.map_or(true, |acceptable_msrv| msrv.meets(acceptable_msrv))
     })
 }
+
+fn match_map_type(cx: &LateContext<'_>, expr: &hir::Expr<'_>) -> bool {
+    let expr_ty = cx.typeck_results().expr_ty(expr).peel_refs();
+    MAP_TYPES.iter().any(|ty| is_type_diagnostic_item(cx, expr_ty, *ty))
+}
+
+fn make_span_lint_and_sugg(cx: &LateContext<'_>, span: Span, sugg: String) {
+    span_lint_and_sugg(
+        cx,
+        MANUAL_RETAIN,
+        span,
+        "this expression can be written more simply using `.retain()`",
+        "consider calling `.retain()` instead",
+        sugg,
+        Applicability::MachineApplicable,
+    );
+}
diff --git a/src/tools/clippy/clippy_lints/src/methods/manual_c_str_literals.rs b/src/tools/clippy/clippy_lints/src/methods/manual_c_str_literals.rs
new file mode 100644
index 00000000000..cb9fb373c10
--- /dev/null
+++ b/src/tools/clippy/clippy_lints/src/methods/manual_c_str_literals.rs
@@ -0,0 +1,197 @@
+use clippy_config::msrvs::{self, Msrv};
+use clippy_utils::diagnostics::span_lint_and_sugg;
+use clippy_utils::get_parent_expr;
+use clippy_utils::source::snippet;
+use rustc_ast::{LitKind, StrStyle};
+use rustc_errors::Applicability;
+use rustc_hir::{Expr, ExprKind, Node, QPath, TyKind};
+use rustc_lint::LateContext;
+use rustc_span::{sym, Span, Symbol};
+
+use super::MANUAL_C_STR_LITERALS;
+
+/// Checks:
+/// - `b"...".as_ptr()`
+/// - `b"...".as_ptr().cast()`
+/// - `"...".as_ptr()`
+/// - `"...".as_ptr().cast()`
+///
+/// Iff the parent call of `.cast()` isn't `CStr::from_ptr`, to avoid linting twice.
+pub(super) fn check_as_ptr<'tcx>(
+    cx: &LateContext<'tcx>,
+    expr: &'tcx Expr<'tcx>,
+    receiver: &'tcx Expr<'tcx>,
+    msrv: &Msrv,
+) {
+    if let ExprKind::Lit(lit) = receiver.kind
+        && let LitKind::ByteStr(_, StrStyle::Cooked) | LitKind::Str(_, StrStyle::Cooked) = lit.node
+        && let casts_removed = peel_ptr_cast_ancestors(cx, expr)
+        && !get_parent_expr(cx, casts_removed).is_some_and(
+            |parent| matches!(parent.kind, ExprKind::Call(func, _) if is_c_str_function(cx, func).is_some()),
+        )
+        && let Some(sugg) = rewrite_as_cstr(cx, lit.span)
+        && msrv.meets(msrvs::C_STR_LITERALS)
+    {
+        span_lint_and_sugg(
+            cx,
+            MANUAL_C_STR_LITERALS,
+            receiver.span,
+            "manually constructing a nul-terminated string",
+            r#"use a `c""` literal"#,
+            sugg,
+            // an additional cast may be needed, since the type of `CStr::as_ptr` and
+            // `"".as_ptr()` can differ and is platform dependent
+            Applicability::HasPlaceholders,
+        );
+    }
+}
+
+/// Checks if the callee is a "relevant" `CStr` function considered by this lint.
+/// Returns the function name.
+fn is_c_str_function(cx: &LateContext<'_>, func: &Expr<'_>) -> Option<Symbol> {
+    if let ExprKind::Path(QPath::TypeRelative(cstr, fn_name)) = &func.kind
+        && let TyKind::Path(QPath::Resolved(_, ty_path)) = &cstr.kind
+        && cx.tcx.lang_items().c_str() == ty_path.res.opt_def_id()
+    {
+        Some(fn_name.ident.name)
+    } else {
+        None
+    }
+}
+
+/// Checks calls to the `CStr` constructor functions:
+/// - `CStr::from_bytes_with_nul(..)`
+/// - `CStr::from_bytes_with_nul_unchecked(..)`
+/// - `CStr::from_ptr(..)`
+pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, func: &Expr<'_>, args: &[Expr<'_>], msrv: &Msrv) {
+    if let Some(fn_name) = is_c_str_function(cx, func)
+        && let [arg] = args
+        && msrv.meets(msrvs::C_STR_LITERALS)
+    {
+        match fn_name.as_str() {
+            name @ ("from_bytes_with_nul" | "from_bytes_with_nul_unchecked")
+                if !arg.span.from_expansion()
+                    && let ExprKind::Lit(lit) = arg.kind
+                    && let LitKind::ByteStr(_, StrStyle::Cooked) | LitKind::Str(_, StrStyle::Cooked) = lit.node =>
+            {
+                check_from_bytes(cx, expr, arg, name);
+            },
+            "from_ptr" => check_from_ptr(cx, expr, arg),
+            _ => {},
+        }
+    }
+}
+
+/// Checks `CStr::from_ptr(b"foo\0".as_ptr().cast())`
+fn check_from_ptr(cx: &LateContext<'_>, expr: &Expr<'_>, arg: &Expr<'_>) {
+    if let ExprKind::MethodCall(method, lit, ..) = peel_ptr_cast(arg).kind
+        && method.ident.name == sym::as_ptr
+        && !lit.span.from_expansion()
+        && let ExprKind::Lit(lit) = lit.kind
+        && let LitKind::ByteStr(_, StrStyle::Cooked) = lit.node
+        && let Some(sugg) = rewrite_as_cstr(cx, lit.span)
+    {
+        span_lint_and_sugg(
+            cx,
+            MANUAL_C_STR_LITERALS,
+            expr.span,
+            "calling `CStr::from_ptr` with a byte string literal",
+            r#"use a `c""` literal"#,
+            sugg,
+            Applicability::MachineApplicable,
+        );
+    }
+}
+/// Checks `CStr::from_bytes_with_nul(b"foo\0")`
+fn check_from_bytes(cx: &LateContext<'_>, expr: &Expr<'_>, arg: &Expr<'_>, method: &str) {
+    let (span, applicability) = if let Some(parent) = get_parent_expr(cx, expr)
+        && let ExprKind::MethodCall(method, ..) = parent.kind
+        && [sym::unwrap, sym::expect].contains(&method.ident.name)
+    {
+        (parent.span, Applicability::MachineApplicable)
+    } else if method == "from_bytes_with_nul_unchecked" {
+        // `*_unchecked` returns `&CStr` directly, nothing needs to be changed
+        (expr.span, Applicability::MachineApplicable)
+    } else {
+        // User needs to remove error handling, can't be machine applicable
+        (expr.span, Applicability::HasPlaceholders)
+    };
+
+    let Some(sugg) = rewrite_as_cstr(cx, arg.span) else {
+        return;
+    };
+
+    span_lint_and_sugg(
+        cx,
+        MANUAL_C_STR_LITERALS,
+        span,
+        "calling `CStr::new` with a byte string literal",
+        r#"use a `c""` literal"#,
+        sugg,
+        applicability,
+    );
+}
+
+/// Rewrites a byte string literal to a c-str literal.
+/// `b"foo\0"` -> `c"foo"`
+///
+/// Returns `None` if it doesn't end in a NUL byte.
+fn rewrite_as_cstr(cx: &LateContext<'_>, span: Span) -> Option<String> {
+    let mut sugg = String::from("c") + snippet(cx, span.source_callsite(), "..").trim_start_matches('b');
+
+    // NUL byte should always be right before the closing quote.
+    if let Some(quote_pos) = sugg.rfind('"') {
+        // Possible values right before the quote:
+        // - literal NUL value
+        if sugg.as_bytes()[quote_pos - 1] == b'\0' {
+            sugg.remove(quote_pos - 1);
+        }
+        // - \x00
+        else if sugg[..quote_pos].ends_with("\\x00") {
+            sugg.replace_range(quote_pos - 4..quote_pos, "");
+        }
+        // - \0
+        else if sugg[..quote_pos].ends_with("\\0") {
+            sugg.replace_range(quote_pos - 2..quote_pos, "");
+        }
+        // No known suffix, so assume it's not a C-string.
+        else {
+            return None;
+        }
+    }
+
+    Some(sugg)
+}
+
+fn get_cast_target<'tcx>(e: &'tcx Expr<'tcx>) -> Option<&'tcx Expr<'tcx>> {
+    match &e.kind {
+        ExprKind::MethodCall(method, receiver, [], _) if method.ident.as_str() == "cast" => Some(receiver),
+        ExprKind::Cast(expr, _) => Some(expr),
+        _ => None,
+    }
+}
+
+/// `x.cast()` -> `x`
+/// `x as *const _` -> `x`
+/// `x` -> `x` (returns the same expression for non-cast exprs)
+fn peel_ptr_cast<'tcx>(e: &'tcx Expr<'tcx>) -> &'tcx Expr<'tcx> {
+    get_cast_target(e).map_or(e, peel_ptr_cast)
+}
+
+/// Same as `peel_ptr_cast`, but the other way around, by walking up the ancestor cast expressions:
+///
+/// `foo(x.cast() as *const _)`
+///      ^ given this `x` expression, returns the `foo(...)` expression
+fn peel_ptr_cast_ancestors<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'tcx>) -> &'tcx Expr<'tcx> {
+    let mut prev = e;
+    for (_, node) in cx.tcx.hir().parent_iter(e.hir_id) {
+        if let Node::Expr(e) = node
+            && get_cast_target(e).is_some()
+        {
+            prev = e;
+        } else {
+            break;
+        }
+    }
+    prev
+}
diff --git a/src/tools/clippy/clippy_lints/src/methods/map_unwrap_or.rs b/src/tools/clippy/clippy_lints/src/methods/map_unwrap_or.rs
index 52ea584a2c8..3226fa9cd3f 100644
--- a/src/tools/clippy/clippy_lints/src/methods/map_unwrap_or.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/map_unwrap_or.rs
@@ -21,7 +21,7 @@ pub(super) fn check<'tcx>(
     unwrap_arg: &'tcx hir::Expr<'_>,
     msrv: &Msrv,
 ) -> bool {
-    // lint if the caller of `map()` is an `Option`
+    // lint if the caller of `map()` is an `Option` or a `Result`.
     let is_option = is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(recv), sym::Option);
     let is_result = is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(recv), sym::Result);
 
diff --git a/src/tools/clippy/clippy_lints/src/methods/mod.rs b/src/tools/clippy/clippy_lints/src/methods/mod.rs
index 03bcf108914..e8a7a321bf4 100644
--- a/src/tools/clippy/clippy_lints/src/methods/mod.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/mod.rs
@@ -51,6 +51,7 @@ mod iter_skip_zero;
 mod iter_with_drain;
 mod iterator_step_by_zero;
 mod join_absolute_paths;
+mod manual_c_str_literals;
 mod manual_is_variant_and;
 mod manual_next_back;
 mod manual_ok_or;
@@ -113,6 +114,7 @@ mod unnecessary_iter_cloned;
 mod unnecessary_join;
 mod unnecessary_lazy_eval;
 mod unnecessary_literal_unwrap;
+mod unnecessary_result_map_or_else;
 mod unnecessary_sort_by;
 mod unnecessary_to_owned;
 mod unwrap_expect_used;
@@ -3951,6 +3953,64 @@ declare_clippy_lint! {
     "cloning an `Option` via `as_ref().cloned()`"
 }
 
+declare_clippy_lint! {
+    /// ### What it does
+    /// Checks for usage of `.map_or_else()` "map closure" for `Result` type.
+    ///
+    /// ### Why is this bad?
+    /// This can be written more concisely by using `unwrap_or_else()`.
+    ///
+    /// ### Example
+    /// ```no_run
+    /// # fn handle_error(_: ()) -> u32 { 0 }
+    /// let x: Result<u32, ()> = Ok(0);
+    /// let y = x.map_or_else(|err| handle_error(err), |n| n);
+    /// ```
+    /// Use instead:
+    /// ```no_run
+    /// # fn handle_error(_: ()) -> u32 { 0 }
+    /// let x: Result<u32, ()> = Ok(0);
+    /// let y = x.unwrap_or_else(|err| handle_error(err));
+    /// ```
+    #[clippy::version = "1.77.0"]
+    pub UNNECESSARY_RESULT_MAP_OR_ELSE,
+    suspicious,
+    "making no use of the \"map closure\" when calling `.map_or_else(|err| handle_error(err), |n| n)`"
+}
+
+declare_clippy_lint! {
+    /// Checks for the manual creation of C strings (a string with a `NUL` byte at the end), either
+    /// through one of the `CStr` constructor functions, or more plainly by calling `.as_ptr()`
+    /// on a (byte) string literal with a hardcoded `\0` byte at the end.
+    ///
+    /// ### Why is this bad?
+    /// This can be written more concisely using `c"str"` literals and is also less error-prone,
+    /// because the compiler checks for interior `NUL` bytes and the terminating `NUL` byte is inserted automatically.
+    ///
+    /// ### Example
+    /// ```no_run
+    /// # use std::ffi::CStr;
+    /// # mod libc { pub unsafe fn puts(_: *const i8) {} }
+    /// fn needs_cstr(_: &CStr) {}
+    ///
+    /// needs_cstr(CStr::from_bytes_with_nul(b"Hello\0").unwrap());
+    /// unsafe { libc::puts("World\0".as_ptr().cast()) }
+    /// ```
+    /// Use instead:
+    /// ```no_run
+    /// # use std::ffi::CStr;
+    /// # mod libc { pub unsafe fn puts(_: *const i8) {} }
+    /// fn needs_cstr(_: &CStr) {}
+    ///
+    /// needs_cstr(c"Hello");
+    /// unsafe { libc::puts(c"World".as_ptr()) }
+    /// ```
+    #[clippy::version = "1.76.0"]
+    pub MANUAL_C_STR_LITERALS,
+    pedantic,
+    r#"creating a `CStr` through functions when `c""` literals can be used"#
+}
+
 pub struct Methods {
     avoid_breaking_exported_api: bool,
     msrv: Msrv,
@@ -4109,6 +4169,8 @@ impl_lint_pass!(Methods => [
     MANUAL_IS_VARIANT_AND,
     STR_SPLIT_AT_NEWLINE,
     OPTION_AS_REF_CLONED,
+    UNNECESSARY_RESULT_MAP_OR_ELSE,
+    MANUAL_C_STR_LITERALS,
 ]);
 
 /// Extracts a method call name, args, and `Span` of the method name.
@@ -4136,6 +4198,7 @@ impl<'tcx> LateLintPass<'tcx> for Methods {
             hir::ExprKind::Call(func, args) => {
                 from_iter_instead_of_collect::check(cx, expr, args, func);
                 unnecessary_fallible_conversions::check_function(cx, expr, func);
+                manual_c_str_literals::check(cx, expr, func, args, &self.msrv);
             },
             hir::ExprKind::MethodCall(method_call, receiver, args, _) => {
                 let method_span = method_call.ident.span;
@@ -4354,6 +4417,7 @@ impl Methods {
                     }
                 },
                 ("as_mut", []) => useless_asref::check(cx, expr, "as_mut", recv),
+                ("as_ptr", []) => manual_c_str_literals::check_as_ptr(cx, expr, recv, &self.msrv),
                 ("as_ref", []) => useless_asref::check(cx, expr, "as_ref", recv),
                 ("assume_init", []) => uninit_assumed_init::check(cx, expr, recv),
                 ("cloned", []) => {
@@ -4592,6 +4656,7 @@ impl Methods {
                 },
                 ("map_or_else", [def, map]) => {
                     result_map_or_else_none::check(cx, expr, recv, def, map);
+                    unnecessary_result_map_or_else::check(cx, expr, recv, def, map);
                 },
                 ("next", []) => {
                     if let Some((name2, recv2, args2, _, _)) = method_call(recv) {
diff --git a/src/tools/clippy/clippy_lints/src/methods/unnecessary_fold.rs b/src/tools/clippy/clippy_lints/src/methods/unnecessary_fold.rs
index f3577ef6082..2046692bbd0 100644
--- a/src/tools/clippy/clippy_lints/src/methods/unnecessary_fold.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/unnecessary_fold.rs
@@ -99,7 +99,6 @@ fn check_fold_with_op(
             cx,
             UNNECESSARY_FOLD,
             fold_span.with_hi(expr.span.hi()),
-            // TODO #2371 don't suggest e.g., .any(|x| f(x)) if we can suggest .any(f)
             "this `.fold` can be written more succinctly using another method",
             "try",
             sugg,
diff --git a/src/tools/clippy/clippy_lints/src/methods/unnecessary_result_map_or_else.rs b/src/tools/clippy/clippy_lints/src/methods/unnecessary_result_map_or_else.rs
new file mode 100644
index 00000000000..7b0cf48ac43
--- /dev/null
+++ b/src/tools/clippy/clippy_lints/src/methods/unnecessary_result_map_or_else.rs
@@ -0,0 +1,95 @@
+use clippy_utils::diagnostics::span_lint_and_sugg;
+use clippy_utils::peel_blocks;
+use clippy_utils::source::snippet;
+use clippy_utils::ty::is_type_diagnostic_item;
+use rustc_errors::Applicability;
+use rustc_hir as hir;
+use rustc_hir::{Closure, Expr, ExprKind, HirId, QPath, Stmt, StmtKind};
+use rustc_lint::LateContext;
+use rustc_span::symbol::sym;
+
+use super::UNNECESSARY_RESULT_MAP_OR_ELSE;
+
+fn emit_lint(cx: &LateContext<'_>, expr: &Expr<'_>, recv: &Expr<'_>, def_arg: &Expr<'_>) {
+    let msg = "unused \"map closure\" when calling `Result::map_or_else` value";
+    let self_snippet = snippet(cx, recv.span, "..");
+    let err_snippet = snippet(cx, def_arg.span, "..");
+    span_lint_and_sugg(
+        cx,
+        UNNECESSARY_RESULT_MAP_OR_ELSE,
+        expr.span,
+        msg,
+        "consider using `unwrap_or_else`",
+        format!("{self_snippet}.unwrap_or_else({err_snippet})"),
+        Applicability::MachineApplicable,
+    );
+}
+
+fn get_last_chain_binding_hir_id(mut hir_id: HirId, statements: &[Stmt<'_>]) -> Option<HirId> {
+    for stmt in statements {
+        if let StmtKind::Local(local) = stmt.kind
+            && let Some(init) = local.init
+            && let ExprKind::Path(QPath::Resolved(_, path)) = init.kind
+            && let hir::def::Res::Local(local_hir_id) = path.res
+            && local_hir_id == hir_id
+        {
+            hir_id = local.pat.hir_id;
+        } else {
+            return None;
+        }
+    }
+    Some(hir_id)
+}
+
+fn handle_qpath(
+    cx: &LateContext<'_>,
+    expr: &Expr<'_>,
+    recv: &Expr<'_>,
+    def_arg: &Expr<'_>,
+    expected_hir_id: HirId,
+    qpath: QPath<'_>,
+) {
+    if let QPath::Resolved(_, path) = qpath
+        && let hir::def::Res::Local(hir_id) = path.res
+        && expected_hir_id == hir_id
+    {
+        emit_lint(cx, expr, recv, def_arg);
+    }
+}
+
+/// lint use of `_.map_or_else(|err| err, |n| n)` for `Result`s.
+pub(super) fn check<'tcx>(
+    cx: &LateContext<'tcx>,
+    expr: &'tcx Expr<'_>,
+    recv: &'tcx Expr<'_>,
+    def_arg: &'tcx Expr<'_>,
+    map_arg: &'tcx Expr<'_>,
+) {
+    // lint if the caller of `map_or_else()` is a `Result`
+    if is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(recv), sym::Result)
+        && let ExprKind::Closure(&Closure { body, .. }) = map_arg.kind
+        && let body = cx.tcx.hir().body(body)
+        && let Some(first_param) = body.params.first()
+    {
+        let body_expr = peel_blocks(body.value);
+
+        match body_expr.kind {
+            ExprKind::Path(qpath) => {
+                handle_qpath(cx, expr, recv, def_arg, first_param.pat.hir_id, qpath);
+            },
+            // If this is a block (that wasn't peeled off), then it means there are statements.
+            ExprKind::Block(block, _) => {
+                if let Some(block_expr) = block.expr
+                    // First we ensure that this is a "binding chain" (each statement is a binding
+                    // of the previous one) and that it is a binding of the closure argument.
+                    && let Some(last_chain_binding_id) =
+                        get_last_chain_binding_hir_id(first_param.pat.hir_id, block.stmts)
+                    && let ExprKind::Path(qpath) = block_expr.kind
+                {
+                    handle_qpath(cx, expr, recv, def_arg, last_chain_binding_id, qpath);
+                }
+            },
+            _ => {},
+        }
+    }
+}
diff --git a/src/tools/clippy/clippy_lints/src/no_effect.rs b/src/tools/clippy/clippy_lints/src/no_effect.rs
index 0d234f7f9b5..580160efeb7 100644
--- a/src/tools/clippy/clippy_lints/src/no_effect.rs
+++ b/src/tools/clippy/clippy_lints/src/no_effect.rs
@@ -357,7 +357,7 @@ fn reduce_expression<'a>(cx: &LateContext<'_>, expr: &'a Expr<'a>) -> Option<Vec
             }
         },
         ExprKind::Block(block, _) => {
-            if block.stmts.is_empty() {
+            if block.stmts.is_empty() && !block.targeted_by_break {
                 block.expr.as_ref().and_then(|e| {
                     match block.rules {
                         BlockCheckMode::UnsafeBlock(UnsafeSource::UserProvided) => None,
diff --git a/src/tools/clippy/clippy_lints/src/only_used_in_recursion.rs b/src/tools/clippy/clippy_lints/src/only_used_in_recursion.rs
index d621051ef16..ae14016f482 100644
--- a/src/tools/clippy/clippy_lints/src/only_used_in_recursion.rs
+++ b/src/tools/clippy/clippy_lints/src/only_used_in_recursion.rs
@@ -252,7 +252,7 @@ impl<'tcx> LateLintPass<'tcx> for OnlyUsedInRecursion {
                 {
                     (
                         trait_item_id,
-                        FnKind::ImplTraitFn(cx.tcx.erase_regions(trait_ref.args) as *const _ as usize),
+                        FnKind::ImplTraitFn(std::ptr::from_ref(cx.tcx.erase_regions(trait_ref.args)) as usize),
                         usize::from(sig.decl.implicit_self.has_implicit_self()),
                     )
                 } else {
@@ -390,7 +390,6 @@ fn has_matching_args(kind: FnKind, args: GenericArgsRef<'_>) -> bool {
             GenericArgKind::Type(ty) => matches!(*ty.kind(), ty::Param(ty) if ty.index as usize == idx),
             GenericArgKind::Const(c) => matches!(c.kind(), ConstKind::Param(c) if c.index as usize == idx),
         }),
-        #[allow(trivial_casts)]
-        FnKind::ImplTraitFn(expected_args) => args as *const _ as usize == expected_args,
+        FnKind::ImplTraitFn(expected_args) => std::ptr::from_ref(args) as usize == expected_args,
     }
 }
diff --git a/src/tools/clippy/clippy_lints/src/operators/mod.rs b/src/tools/clippy/clippy_lints/src/operators/mod.rs
index 4c09c4eea58..e002429e3a4 100644
--- a/src/tools/clippy/clippy_lints/src/operators/mod.rs
+++ b/src/tools/clippy/clippy_lints/src/operators/mod.rs
@@ -771,6 +771,7 @@ declare_clippy_lint! {
 pub struct Operators {
     arithmetic_context: numeric_arithmetic::Context,
     verbose_bit_mask_threshold: u64,
+    modulo_arithmetic_allow_comparison_to_zero: bool,
 }
 impl_lint_pass!(Operators => [
     ABSURD_EXTREME_COMPARISONS,
@@ -801,10 +802,11 @@ impl_lint_pass!(Operators => [
     SELF_ASSIGNMENT,
 ]);
 impl Operators {
-    pub fn new(verbose_bit_mask_threshold: u64) -> Self {
+    pub fn new(verbose_bit_mask_threshold: u64, modulo_arithmetic_allow_comparison_to_zero: bool) -> Self {
         Self {
             arithmetic_context: numeric_arithmetic::Context::default(),
             verbose_bit_mask_threshold,
+            modulo_arithmetic_allow_comparison_to_zero,
         }
     }
 }
@@ -835,12 +837,19 @@ impl<'tcx> LateLintPass<'tcx> for Operators {
                 cmp_owned::check(cx, op.node, lhs, rhs);
                 float_cmp::check(cx, e, op.node, lhs, rhs);
                 modulo_one::check(cx, e, op.node, rhs);
-                modulo_arithmetic::check(cx, e, op.node, lhs, rhs);
+                modulo_arithmetic::check(
+                    cx,
+                    e,
+                    op.node,
+                    lhs,
+                    rhs,
+                    self.modulo_arithmetic_allow_comparison_to_zero,
+                );
             },
             ExprKind::AssignOp(op, lhs, rhs) => {
                 self.arithmetic_context.check_binary(cx, e, op.node, lhs, rhs);
                 misrefactored_assign_op::check(cx, e, op.node, lhs, rhs);
-                modulo_arithmetic::check(cx, e, op.node, lhs, rhs);
+                modulo_arithmetic::check(cx, e, op.node, lhs, rhs, false);
             },
             ExprKind::Assign(lhs, rhs, _) => {
                 assign_op_pattern::check(cx, e, lhs, rhs);
diff --git a/src/tools/clippy/clippy_lints/src/operators/modulo_arithmetic.rs b/src/tools/clippy/clippy_lints/src/operators/modulo_arithmetic.rs
index cb3916484c1..40d4a842bef 100644
--- a/src/tools/clippy/clippy_lints/src/operators/modulo_arithmetic.rs
+++ b/src/tools/clippy/clippy_lints/src/operators/modulo_arithmetic.rs
@@ -1,7 +1,7 @@
 use clippy_utils::consts::{constant, Constant};
 use clippy_utils::diagnostics::span_lint_and_then;
 use clippy_utils::sext;
-use rustc_hir::{BinOpKind, Expr};
+use rustc_hir::{BinOpKind, Expr, ExprKind, Node};
 use rustc_lint::LateContext;
 use rustc_middle::ty::{self, Ty};
 use std::fmt::Display;
@@ -14,8 +14,13 @@ pub(super) fn check<'tcx>(
     op: BinOpKind,
     lhs: &'tcx Expr<'_>,
     rhs: &'tcx Expr<'_>,
+    allow_comparison_to_zero: bool,
 ) {
     if op == BinOpKind::Rem {
+        if allow_comparison_to_zero && used_in_comparison_with_zero(cx, e) {
+            return;
+        }
+
         let lhs_operand = analyze_operand(lhs, cx, e);
         let rhs_operand = analyze_operand(rhs, cx, e);
         if let Some(lhs_operand) = lhs_operand
@@ -28,6 +33,26 @@ pub(super) fn check<'tcx>(
     };
 }
 
+fn used_in_comparison_with_zero(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
+    let Some(Node::Expr(parent_expr)) = cx.tcx.hir().find_parent(expr.hir_id) else {
+        return false;
+    };
+    let ExprKind::Binary(op, lhs, rhs) = parent_expr.kind else {
+        return false;
+    };
+
+    if op.node == BinOpKind::Eq || op.node == BinOpKind::Ne {
+        if let Some(Constant::Int(0)) = constant(cx, cx.typeck_results(), rhs) {
+            return true;
+        }
+        if let Some(Constant::Int(0)) = constant(cx, cx.typeck_results(), lhs) {
+            return true;
+        }
+    }
+
+    false
+}
+
 struct OperandInfo {
     string_representation: Option<String>,
     is_negative: bool,
diff --git a/src/tools/clippy/clippy_lints/src/redundant_closure_call.rs b/src/tools/clippy/clippy_lints/src/redundant_closure_call.rs
index 334e6770ae4..915da18aafe 100644
--- a/src/tools/clippy/clippy_lints/src/redundant_closure_call.rs
+++ b/src/tools/clippy/clippy_lints/src/redundant_closure_call.rs
@@ -2,6 +2,7 @@ use crate::rustc_lint::LintContext;
 use clippy_utils::diagnostics::{span_lint, span_lint_and_then};
 use clippy_utils::get_parent_expr;
 use clippy_utils::sugg::Sugg;
+use hir::Param;
 use rustc_errors::Applicability;
 use rustc_hir as hir;
 use rustc_hir::intravisit::{Visitor as HirVisitor, Visitor};
@@ -13,6 +14,7 @@ use rustc_middle::hir::nested_filter;
 use rustc_middle::lint::in_external_macro;
 use rustc_middle::ty;
 use rustc_session::declare_lint_pass;
+use rustc_span::ExpnKind;
 
 declare_clippy_lint! {
     /// ### What it does
@@ -89,7 +91,12 @@ fn find_innermost_closure<'tcx>(
     cx: &LateContext<'tcx>,
     mut expr: &'tcx hir::Expr<'tcx>,
     mut steps: usize,
-) -> Option<(&'tcx hir::Expr<'tcx>, &'tcx hir::FnDecl<'tcx>, ty::Asyncness)> {
+) -> Option<(
+    &'tcx hir::Expr<'tcx>,
+    &'tcx hir::FnDecl<'tcx>,
+    ty::Asyncness,
+    &'tcx [Param<'tcx>],
+)> {
     let mut data = None;
 
     while let hir::ExprKind::Closure(closure) = expr.kind
@@ -110,6 +117,7 @@ fn find_innermost_closure<'tcx>(
             } else {
                 ty::Asyncness::No
             },
+            body.params,
         ));
         steps -= 1;
     }
@@ -152,7 +160,9 @@ impl<'tcx> LateLintPass<'tcx> for RedundantClosureCall {
             // without this check, we'd end up linting twice.
             && !matches!(recv.kind, hir::ExprKind::Call(..))
             && let (full_expr, call_depth) = get_parent_call_exprs(cx, expr)
-            && let Some((body, fn_decl, coroutine_kind)) = find_innermost_closure(cx, recv, call_depth)
+            && let Some((body, fn_decl, coroutine_kind, params)) = find_innermost_closure(cx, recv, call_depth)
+            // outside macros we lint properly. Inside macros, we lint only ||() style closures.
+            && (!matches!(expr.span.ctxt().outer_expn_data().kind, ExpnKind::Macro(_, _)) || params.is_empty())
         {
             span_lint_and_then(
                 cx,
diff --git a/src/tools/clippy/clippy_lints/src/redundant_locals.rs b/src/tools/clippy/clippy_lints/src/redundant_locals.rs
index 2c511ee0bc0..700a5dd4a85 100644
--- a/src/tools/clippy/clippy_lints/src/redundant_locals.rs
+++ b/src/tools/clippy/clippy_lints/src/redundant_locals.rs
@@ -4,8 +4,10 @@ use clippy_utils::ty::needs_ordered_drop;
 use rustc_ast::Mutability;
 use rustc_hir::def::Res;
 use rustc_hir::{BindingAnnotation, ByRef, ExprKind, HirId, Local, Node, Pat, PatKind, QPath};
+use rustc_hir_typeck::expr_use_visitor::PlaceBase;
 use rustc_lint::{LateContext, LateLintPass, LintContext};
 use rustc_middle::lint::in_external_macro;
+use rustc_middle::ty::UpvarCapture;
 use rustc_session::declare_lint_pass;
 use rustc_span::symbol::Ident;
 use rustc_span::DesugaringKind;
@@ -69,6 +71,7 @@ impl<'tcx> LateLintPass<'tcx> for RedundantLocals {
             // the local is user-controlled
             && !in_external_macro(cx.sess(), local.span)
             && !is_from_proc_macro(cx, expr)
+            && !is_by_value_closure_capture(cx, local.hir_id, binding_id)
         {
             span_lint_and_help(
                 cx,
@@ -82,6 +85,29 @@ impl<'tcx> LateLintPass<'tcx> for RedundantLocals {
     }
 }
 
+/// Checks if the enclosing body is a closure and if the given local is captured by value.
+///
+/// In those cases, the redefinition may be necessary to force a move:
+/// ```
+/// fn assert_static<T: 'static>(_: T) {}
+///
+/// let v = String::new();
+/// let closure = || {
+///   let v = v; // <- removing this redefinition makes `closure` no longer `'static`
+///   dbg!(&v);
+/// };
+/// assert_static(closure);
+/// ```
+fn is_by_value_closure_capture(cx: &LateContext<'_>, redefinition: HirId, root_variable: HirId) -> bool {
+    let closure_def_id = cx.tcx.hir().enclosing_body_owner(redefinition);
+
+    cx.tcx.is_closure_or_coroutine(closure_def_id.to_def_id())
+        && cx.tcx.closure_captures(closure_def_id).iter().any(|c| {
+            matches!(c.info.capture_kind, UpvarCapture::ByValue)
+                && matches!(c.place.base, PlaceBase::Upvar(upvar) if upvar.var_path.hir_id == root_variable)
+        })
+}
+
 /// Find the annotation of a binding introduced by a pattern, or `None` if it's not introduced.
 fn find_binding(pat: &Pat<'_>, name: Ident) -> Option<BindingAnnotation> {
     let mut ret = None;
diff --git a/src/tools/clippy/clippy_lints/src/redundant_type_annotations.rs b/src/tools/clippy/clippy_lints/src/redundant_type_annotations.rs
index 07fcb69afbc..c8352c05265 100644
--- a/src/tools/clippy/clippy_lints/src/redundant_type_annotations.rs
+++ b/src/tools/clippy/clippy_lints/src/redundant_type_annotations.rs
@@ -188,7 +188,6 @@ impl LateLintPass<'_> for RedundantTypeAnnotations {
                     match init_lit.node {
                         // In these cases the annotation is redundant
                         LitKind::Str(..)
-                        | LitKind::ByteStr(..)
                         | LitKind::Byte(..)
                         | LitKind::Char(..)
                         | LitKind::Bool(..)
@@ -202,6 +201,16 @@ impl LateLintPass<'_> for RedundantTypeAnnotations {
                             }
                         },
                         LitKind::Err => (),
+                        LitKind::ByteStr(..) => {
+                            // We only lint if the type annotation is an array type (e.g. &[u8; 4]).
+                            // If instead it is a slice (e.g. &[u8]) it may not be redundant, so we
+                            // don't lint.
+                            if let hir::TyKind::Ref(_, mut_ty) = ty.kind
+                                && matches!(mut_ty.ty.kind, hir::TyKind::Array(..))
+                            {
+                                span_lint(cx, REDUNDANT_TYPE_ANNOTATIONS, local.span, "redundant type annotation");
+                            }
+                        },
                     }
                 },
                 _ => (),
diff --git a/src/tools/clippy/clippy_lints/src/repeat_vec_with_capacity.rs b/src/tools/clippy/clippy_lints/src/repeat_vec_with_capacity.rs
index 5a4933a3fce..fcb79f6d694 100644
--- a/src/tools/clippy/clippy_lints/src/repeat_vec_with_capacity.rs
+++ b/src/tools/clippy/clippy_lints/src/repeat_vec_with_capacity.rs
@@ -42,7 +42,7 @@ declare_clippy_lint! {
     /// //                                      ^^^ this closure executes 123 times
     /// //                                          and the vecs will have the expected capacity
     /// ```
-    #[clippy::version = "1.74.0"]
+    #[clippy::version = "1.76.0"]
     pub REPEAT_VEC_WITH_CAPACITY,
     suspicious,
     "repeating a `Vec::with_capacity` expression which does not retain capacity"
diff --git a/src/tools/clippy/clippy_lints/src/returns.rs b/src/tools/clippy/clippy_lints/src/returns.rs
index e0175046587..2af466d3f51 100644
--- a/src/tools/clippy/clippy_lints/src/returns.rs
+++ b/src/tools/clippy/clippy_lints/src/returns.rs
@@ -2,10 +2,14 @@ use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_and_then, span_lin
 use clippy_utils::source::{snippet_opt, snippet_with_context};
 use clippy_utils::sugg::has_enclosing_paren;
 use clippy_utils::visitors::{for_each_expr_with_closures, Descend};
-use clippy_utils::{fn_def_id, is_from_proc_macro, is_inside_let_else, path_to_local_id, span_find_starting_semi};
+use clippy_utils::{
+    fn_def_id, is_from_proc_macro, is_inside_let_else, is_res_lang_ctor, path_res, path_to_local_id,
+    span_find_starting_semi,
+};
 use core::ops::ControlFlow;
 use rustc_errors::Applicability;
 use rustc_hir::intravisit::FnKind;
+use rustc_hir::LangItem::ResultErr;
 use rustc_hir::{
     Block, Body, Expr, ExprKind, FnDecl, HirId, ItemKind, LangItem, MatchSource, Node, OwnerNode, PatKind, QPath, Stmt,
     StmtKind,
@@ -18,6 +22,7 @@ use rustc_session::declare_lint_pass;
 use rustc_span::def_id::LocalDefId;
 use rustc_span::{BytePos, Pos, Span};
 use std::borrow::Cow;
+use std::fmt::Display;
 
 declare_clippy_lint! {
     /// ### What it does
@@ -146,14 +151,14 @@ impl<'tcx> RetReplacement<'tcx> {
     }
 }
 
-impl<'tcx> ToString for RetReplacement<'tcx> {
-    fn to_string(&self) -> String {
+impl<'tcx> Display for RetReplacement<'tcx> {
+    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
         match self {
-            Self::Empty => String::new(),
-            Self::Block => "{}".to_string(),
-            Self::Unit => "()".to_string(),
-            Self::IfSequence(inner, _) => format!("({inner})"),
-            Self::Expr(inner, _) => inner.to_string(),
+            Self::Empty => write!(f, ""),
+            Self::Block => write!(f, "{{}}"),
+            Self::Unit => write!(f, "()"),
+            Self::IfSequence(inner, _) => write!(f, "({inner})"),
+            Self::Expr(inner, _) => write!(f, "{inner}"),
         }
     }
 }
@@ -181,7 +186,15 @@ impl<'tcx> LateLintPass<'tcx> for Return {
         if !in_external_macro(cx.sess(), stmt.span)
             && let StmtKind::Semi(expr) = stmt.kind
             && let ExprKind::Ret(Some(ret)) = expr.kind
-            && let ExprKind::Match(.., MatchSource::TryDesugar(_)) = ret.kind
+            // return Err(...)? desugars to a match
+            // over a Err(...).branch()
+            // which breaks down to a branch call, with the callee being
+            // the constructor of the Err variant
+            && let ExprKind::Match(maybe_cons, _, MatchSource::TryDesugar(_)) = ret.kind
+            && let ExprKind::Call(_, [maybe_result_err]) = maybe_cons.kind
+            && let ExprKind::Call(maybe_constr, _) = maybe_result_err.kind
+            && is_res_lang_ctor(cx, path_res(cx, maybe_constr), ResultErr)
+
             // Ensure this is not the final stmt, otherwise removing it would cause a compile error
             && let OwnerNode::Item(item) = cx.tcx.hir_owner_node(cx.tcx.hir().get_parent_item(expr.hir_id))
             && let ItemKind::Fn(_, _, body) = item.kind
diff --git a/src/tools/clippy/clippy_lints/src/to_string_trait_impl.rs b/src/tools/clippy/clippy_lints/src/to_string_trait_impl.rs
new file mode 100644
index 00000000000..e1cea99085f
--- /dev/null
+++ b/src/tools/clippy/clippy_lints/src/to_string_trait_impl.rs
@@ -0,0 +1,67 @@
+use clippy_utils::diagnostics::span_lint_and_help;
+use rustc_hir::{Impl, Item, ItemKind};
+use rustc_lint::{LateContext, LateLintPass};
+use rustc_session::declare_lint_pass;
+use rustc_span::sym;
+
+declare_clippy_lint! {
+    /// ### What it does
+    /// Checks for direct implementations of `ToString`.
+    /// ### Why is this bad?
+    /// This trait is automatically implemented for any type which implements the `Display` trait.
+    /// As such, `ToString` shouldn’t be implemented directly: `Display` should be implemented instead,
+    /// and you get the `ToString` implementation for free.
+    /// ### Example
+    /// ```no_run
+    /// struct Point {
+    ///   x: usize,
+    ///   y: usize,
+    /// }
+    ///
+    /// impl ToString for Point {
+    ///   fn to_string(&self) -> String {
+    ///     format!("({}, {})", self.x, self.y)
+    ///   }
+    /// }
+    /// ```
+    /// Use instead:
+    /// ```no_run
+    /// struct Point {
+    ///   x: usize,
+    ///   y: usize,
+    /// }
+    ///
+    /// impl std::fmt::Display for Point {
+    ///   fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+    ///     write!(f, "({}, {})", self.x, self.y)
+    ///   }
+    /// }
+    /// ```
+    #[clippy::version = "1.77.0"]
+    pub TO_STRING_TRAIT_IMPL,
+    style,
+    "check for direct implementations of `ToString`"
+}
+
+declare_lint_pass!(ToStringTraitImpl => [TO_STRING_TRAIT_IMPL]);
+
+impl<'tcx> LateLintPass<'tcx> for ToStringTraitImpl {
+    fn check_item(&mut self, cx: &LateContext<'tcx>, it: &'tcx Item<'tcx>) {
+        if let ItemKind::Impl(Impl {
+            of_trait: Some(trait_ref),
+            ..
+        }) = it.kind
+            && let Some(trait_did) = trait_ref.trait_def_id()
+            && cx.tcx.is_diagnostic_item(sym::ToString, trait_did)
+        {
+            span_lint_and_help(
+                cx,
+                TO_STRING_TRAIT_IMPL,
+                it.span,
+                "direct implementation of `ToString`",
+                None,
+                "prefer implementing `Display` instead",
+            );
+        }
+    }
+}
diff --git a/src/tools/clippy/clippy_lints/src/unconditional_recursion.rs b/src/tools/clippy/clippy_lints/src/unconditional_recursion.rs
index 209035804e4..224ec475c51 100644
--- a/src/tools/clippy/clippy_lints/src/unconditional_recursion.rs
+++ b/src/tools/clippy/clippy_lints/src/unconditional_recursion.rs
@@ -69,14 +69,6 @@ fn span_error(cx: &LateContext<'_>, method_span: Span, expr: &Expr<'_>) {
     );
 }
 
-fn get_ty_def_id(ty: Ty<'_>) -> Option<DefId> {
-    match ty.peel_refs().kind() {
-        ty::Adt(adt, _) => Some(adt.did()),
-        ty::Foreign(def_id) => Some(*def_id),
-        _ => None,
-    }
-}
-
 fn get_hir_ty_def_id<'tcx>(tcx: TyCtxt<'tcx>, hir_ty: rustc_hir::Ty<'tcx>) -> Option<DefId> {
     let TyKind::Path(qpath) = hir_ty.kind else { return None };
     match qpath {
@@ -131,21 +123,49 @@ fn get_impl_trait_def_id(cx: &LateContext<'_>, method_def_id: LocalDefId) -> Opt
     }
 }
 
-#[allow(clippy::unnecessary_def_path)]
+/// When we have `x == y` where `x = &T` and `y = &T`, then that resolves to
+/// `<&T as PartialEq<&T>>::eq`, which is not the same as `<T as PartialEq<T>>::eq`,
+/// however we still would want to treat it the same, because we know that it's a blanket impl
+/// that simply delegates to the `PartialEq` impl with one reference removed.
+///
+/// Still, we can't just do `lty.peel_refs() == rty.peel_refs()` because when we have `x = &T` and
+/// `y = &&T`, this is not necessarily the same as `<T as PartialEq<T>>::eq`
+///
+/// So to avoid these FNs and FPs, we keep removing a layer of references from *both* sides
+/// until both sides match the expected LHS and RHS type (or they don't).
+fn matches_ty<'tcx>(
+    mut left: Ty<'tcx>,
+    mut right: Ty<'tcx>,
+    expected_left: Ty<'tcx>,
+    expected_right: Ty<'tcx>,
+) -> bool {
+    while let (&ty::Ref(_, lty, _), &ty::Ref(_, rty, _)) = (left.kind(), right.kind()) {
+        if lty == expected_left && rty == expected_right {
+            return true;
+        }
+        left = lty;
+        right = rty;
+    }
+    false
+}
+
 fn check_partial_eq(cx: &LateContext<'_>, method_span: Span, method_def_id: LocalDefId, name: Ident, expr: &Expr<'_>) {
-    let args = cx
-        .tcx
-        .instantiate_bound_regions_with_erased(cx.tcx.fn_sig(method_def_id).skip_binder())
-        .inputs();
+    let Some(sig) = cx
+        .typeck_results()
+        .liberated_fn_sigs()
+        .get(cx.tcx.local_def_id_to_hir_id(method_def_id))
+    else {
+        return;
+    };
+
     // That has two arguments.
-    if let [self_arg, other_arg] = args
-        && let Some(self_arg) = get_ty_def_id(*self_arg)
-        && let Some(other_arg) = get_ty_def_id(*other_arg)
+    if let [self_arg, other_arg] = sig.inputs()
+        && let &ty::Ref(_, self_arg, _) = self_arg.kind()
+        && let &ty::Ref(_, other_arg, _) = other_arg.kind()
         // The two arguments are of the same type.
-        && self_arg == other_arg
         && let Some(trait_def_id) = get_impl_trait_def_id(cx, method_def_id)
         // The trait is `PartialEq`.
-        && Some(trait_def_id) == get_trait_def_id(cx, &["core", "cmp", "PartialEq"])
+        && cx.tcx.is_diagnostic_item(sym::PartialEq, trait_def_id)
     {
         let to_check_op = if name.name == sym::eq {
             BinOpKind::Eq
@@ -154,31 +174,19 @@ fn check_partial_eq(cx: &LateContext<'_>, method_span: Span, method_def_id: Loca
         };
         let is_bad = match expr.kind {
             ExprKind::Binary(op, left, right) if op.node == to_check_op => {
-                // Then we check if the left-hand element is of the same type as `self`.
-                if let Some(left_ty) = cx.typeck_results().expr_ty_opt(left)
-                    && let Some(left_id) = get_ty_def_id(left_ty)
-                    && self_arg == left_id
-                    && let Some(right_ty) = cx.typeck_results().expr_ty_opt(right)
-                    && let Some(right_id) = get_ty_def_id(right_ty)
-                    && other_arg == right_id
-                {
-                    true
-                } else {
-                    false
-                }
+                // Then we check if the LHS matches self_arg and RHS matches other_arg
+                let left_ty = cx.typeck_results().expr_ty_adjusted(left);
+                let right_ty = cx.typeck_results().expr_ty_adjusted(right);
+                matches_ty(left_ty, right_ty, self_arg, other_arg)
             },
-            ExprKind::MethodCall(segment, receiver, &[_arg], _) if segment.ident.name == name.name => {
-                if let Some(ty) = cx.typeck_results().expr_ty_opt(receiver)
-                    && let Some(ty_id) = get_ty_def_id(ty)
-                    && self_arg != ty_id
-                {
-                    // Since this called on a different type, the lint should not be
-                    // triggered here.
-                    return;
-                }
+            ExprKind::MethodCall(segment, receiver, [arg], _) if segment.ident.name == name.name => {
+                let receiver_ty = cx.typeck_results().expr_ty_adjusted(receiver);
+                let arg_ty = cx.typeck_results().expr_ty_adjusted(arg);
+
                 if let Some(fn_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id)
                     && let Some(trait_id) = cx.tcx.trait_of_item(fn_id)
                     && trait_id == trait_def_id
+                    && matches_ty(receiver_ty, arg_ty, self_arg, other_arg)
                 {
                     true
                 } else {
diff --git a/src/tools/clippy/clippy_lints/src/unused_io_amount.rs b/src/tools/clippy/clippy_lints/src/unused_io_amount.rs
index adc66e15ff5..6b3ea7700b7 100644
--- a/src/tools/clippy/clippy_lints/src/unused_io_amount.rs
+++ b/src/tools/clippy/clippy_lints/src/unused_io_amount.rs
@@ -1,5 +1,6 @@
 use clippy_utils::diagnostics::span_lint_and_then;
-use clippy_utils::{is_res_lang_ctor, is_trait_method, match_trait_method, paths};
+use clippy_utils::macros::{is_panic, root_macro_call_first_node};
+use clippy_utils::{is_res_lang_ctor, is_trait_method, match_trait_method, paths, peel_blocks};
 use hir::{ExprKind, PatKind};
 use rustc_hir as hir;
 use rustc_lint::{LateContext, LateLintPass};
@@ -82,37 +83,72 @@ impl<'tcx> LateLintPass<'tcx> for UnusedIoAmount {
         }
 
         if let Some(exp) = block.expr
-            && matches!(exp.kind, hir::ExprKind::If(_, _, _) | hir::ExprKind::Match(_, _, _))
+            && matches!(
+                exp.kind,
+                hir::ExprKind::If(_, _, _) | hir::ExprKind::Match(_, _, hir::MatchSource::Normal)
+            )
         {
             check_expr(cx, exp);
         }
     }
 }
 
+fn non_consuming_err_arm<'a>(cx: &LateContext<'a>, arm: &hir::Arm<'a>) -> bool {
+    // if there is a guard, we consider the result to be consumed
+    if arm.guard.is_some() {
+        return false;
+    }
+    if is_unreachable_or_panic(cx, arm.body) {
+        // if the body is unreachable or there is a panic,
+        // we consider the result to be consumed
+        return false;
+    }
+
+    if let PatKind::TupleStruct(ref path, [inner_pat], _) = arm.pat.kind {
+        return is_res_lang_ctor(cx, cx.qpath_res(path, inner_pat.hir_id), hir::LangItem::ResultErr);
+    }
+
+    false
+}
+
+fn non_consuming_ok_arm<'a>(cx: &LateContext<'a>, arm: &hir::Arm<'a>) -> bool {
+    // if there is a guard, we consider the result to be consumed
+    if arm.guard.is_some() {
+        return false;
+    }
+    if is_unreachable_or_panic(cx, arm.body) {
+        // if the body is unreachable or there is a panic,
+        // we consider the result to be consumed
+        return false;
+    }
+
+    if is_ok_wild_or_dotdot_pattern(cx, arm.pat) {
+        return true;
+    }
+    false
+}
+
 fn check_expr<'a>(cx: &LateContext<'a>, expr: &'a hir::Expr<'a>) {
     match expr.kind {
         hir::ExprKind::If(cond, _, _)
             if let ExprKind::Let(hir::Let { pat, init, .. }) = cond.kind
-                && pattern_is_ignored_ok(cx, pat)
+                && is_ok_wild_or_dotdot_pattern(cx, pat)
                 && let Some(op) = should_lint(cx, init) =>
         {
             emit_lint(cx, cond.span, op, &[pat.span]);
         },
-        hir::ExprKind::Match(expr, arms, hir::MatchSource::Normal) if let Some(op) = should_lint(cx, expr) => {
-            let found_arms: Vec<_> = arms
-                .iter()
-                .filter_map(|arm| {
-                    if pattern_is_ignored_ok(cx, arm.pat) {
-                        Some(arm.span)
-                    } else {
-                        None
-                    }
-                })
-                .collect();
-            if !found_arms.is_empty() {
-                emit_lint(cx, expr.span, op, found_arms.as_slice());
+        // we will capture only the case where the match is Ok( ) or Err( )
+        // prefer to match the minimum possible, and expand later if needed
+        // to avoid false positives on something as used as this
+        hir::ExprKind::Match(expr, [arm1, arm2], hir::MatchSource::Normal) if let Some(op) = should_lint(cx, expr) => {
+            if non_consuming_ok_arm(cx, arm1) && non_consuming_err_arm(cx, arm2) {
+                emit_lint(cx, expr.span, op, &[arm1.pat.span]);
+            }
+            if non_consuming_ok_arm(cx, arm2) && non_consuming_err_arm(cx, arm1) {
+                emit_lint(cx, expr.span, op, &[arm2.pat.span]);
             }
         },
+        hir::ExprKind::Match(_, _, hir::MatchSource::Normal) => {},
         _ if let Some(op) = should_lint(cx, expr) => {
             emit_lint(cx, expr.span, op, &[]);
         },
@@ -130,25 +166,40 @@ fn should_lint<'a>(cx: &LateContext<'a>, mut inner: &'a hir::Expr<'a>) -> Option
     check_io_mode(cx, inner)
 }
 
-fn pattern_is_ignored_ok(cx: &LateContext<'_>, pat: &hir::Pat<'_>) -> bool {
+fn is_ok_wild_or_dotdot_pattern<'a>(cx: &LateContext<'a>, pat: &hir::Pat<'a>) -> bool {
     // the if checks whether we are in a result Ok( ) pattern
     // and the return checks whether it is unhandled
 
-    if let PatKind::TupleStruct(ref path, inner_pat, ddp) = pat.kind
+    if let PatKind::TupleStruct(ref path, inner_pat, _) = pat.kind
         // we check against Result::Ok to avoid linting on Err(_) or something else.
         && is_res_lang_ctor(cx, cx.qpath_res(path, pat.hir_id), hir::LangItem::ResultOk)
     {
-        return match (inner_pat, ddp.as_opt_usize()) {
-            // Ok(_) pattern
-            ([inner_pat], None) if matches!(inner_pat.kind, PatKind::Wild) => true,
-            // Ok(..) pattern
-            ([], Some(0)) => true,
-            _ => false,
-        };
+        if matches!(inner_pat, []) {
+            return true;
+        }
+
+        if let [cons_pat] = inner_pat
+            && matches!(cons_pat.kind, PatKind::Wild)
+        {
+            return true;
+        }
+        return false;
     }
     false
 }
 
+// this is partially taken from panic_unimplemented
+fn is_unreachable_or_panic(cx: &LateContext<'_>, expr: &hir::Expr<'_>) -> bool {
+    let expr = peel_blocks(expr);
+    let Some(macro_call) = root_macro_call_first_node(cx, expr) else {
+        return false;
+    };
+    if is_panic(cx, macro_call.def_id) {
+        return !cx.tcx.hir().is_inside_const_context(expr.hir_id);
+    }
+    matches!(cx.tcx.item_name(macro_call.def_id).as_str(), "unreachable")
+}
+
 fn unpack_call_chain<'a>(mut expr: &'a hir::Expr<'a>) -> &'a hir::Expr<'a> {
     while let hir::ExprKind::MethodCall(path, receiver, ..) = expr.kind {
         if matches!(
diff --git a/src/tools/clippy/clippy_lints/src/utils/author.rs b/src/tools/clippy/clippy_lints/src/utils/author.rs
index 288df0fd663..29c67341a46 100644
--- a/src/tools/clippy/clippy_lints/src/utils/author.rs
+++ b/src/tools/clippy/clippy_lints/src/utils/author.rs
@@ -490,9 +490,9 @@ impl<'a, 'tcx> PrintVisitor<'a, 'tcx> {
                             format!("ClosureKind::Coroutine(CoroutineKind::Coroutine(Movability::{movability:?})")
                         },
                     },
-                    ClosureKind::CoroutineClosure(desugaring) => format!(
-                        "ClosureKind::CoroutineClosure(CoroutineDesugaring::{desugaring:?})"
-                    ),
+                    ClosureKind::CoroutineClosure(desugaring) => {
+                        format!("ClosureKind::CoroutineClosure(CoroutineDesugaring::{desugaring:?})")
+                    },
                 };
 
                 let ret_ty = match fn_decl.output {
diff --git a/src/tools/clippy/clippy_lints/src/wildcard_imports.rs b/src/tools/clippy/clippy_lints/src/wildcard_imports.rs
index b82bd1d7e7c..5410e8ac117 100644
--- a/src/tools/clippy/clippy_lints/src/wildcard_imports.rs
+++ b/src/tools/clippy/clippy_lints/src/wildcard_imports.rs
@@ -1,6 +1,7 @@
 use clippy_utils::diagnostics::span_lint_and_sugg;
 use clippy_utils::is_test_module_or_function;
 use clippy_utils::source::{snippet, snippet_with_applicability};
+use rustc_data_structures::fx::FxHashSet;
 use rustc_errors::Applicability;
 use rustc_hir::def::{DefKind, Res};
 use rustc_hir::{Item, ItemKind, PathSegment, UseKind};
@@ -100,13 +101,15 @@ declare_clippy_lint! {
 pub struct WildcardImports {
     warn_on_all: bool,
     test_modules_deep: u32,
+    allowed_segments: FxHashSet<String>,
 }
 
 impl WildcardImports {
-    pub fn new(warn_on_all: bool) -> Self {
+    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,
         }
     }
 }
@@ -190,6 +193,7 @@ impl WildcardImports {
         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)
     }
 }
 
@@ -198,10 +202,18 @@ impl WildcardImports {
 fn is_prelude_import(segments: &[PathSegment<'_>]) -> bool {
     segments
         .iter()
-        .any(|ps| ps.ident.name.as_str().contains(sym::prelude.as_str()))
+        .any(|ps| ps.ident.as_str().contains(sym::prelude.as_str()))
 }
 
 // Allow "super::*" imports in tests.
 fn is_super_only_import(segments: &[PathSegment<'_>]) -> bool {
     segments.len() == 1 && segments[0].ident.name == kw::Super
 }
+
+// Allow skipping imports containing user configured segments,
+// i.e. "...::utils::...::*" if user put `allowed-wildcard-imports = ["utils"]` in `Clippy.toml`
+fn is_allowed_via_config(segments: &[PathSegment<'_>], allowed_segments: &FxHashSet<String>) -> bool {
+    // segment matching need to be exact instead of using 'contains', in case user unintentionaly put
+    // a single character in the config thus skipping most of the warnings.
+    segments.iter().any(|seg| allowed_segments.contains(seg.ident.as_str()))
+}
diff --git a/src/tools/clippy/clippy_utils/Cargo.toml b/src/tools/clippy/clippy_utils/Cargo.toml
index b8869eedf52..c7454fa3328 100644
--- a/src/tools/clippy/clippy_utils/Cargo.toml
+++ b/src/tools/clippy/clippy_utils/Cargo.toml
@@ -1,6 +1,6 @@
 [package]
 name = "clippy_utils"
-version = "0.1.77"
+version = "0.1.78"
 edition = "2021"
 publish = false
 
diff --git a/src/tools/clippy/clippy_utils/src/lib.rs b/src/tools/clippy/clippy_utils/src/lib.rs
index d2bc49d1e29..6a33e11be46 100644
--- a/src/tools/clippy/clippy_utils/src/lib.rs
+++ b/src/tools/clippy/clippy_utils/src/lib.rs
@@ -1,5 +1,6 @@
 #![feature(array_chunks)]
 #![feature(box_patterns)]
+#![feature(control_flow_enum)]
 #![feature(if_let_guard)]
 #![feature(let_chains)]
 #![feature(lint_reasons)]
@@ -81,6 +82,7 @@ use core::mem;
 use core::ops::ControlFlow;
 use std::collections::hash_map::Entry;
 use std::hash::BuildHasherDefault;
+use std::iter::{once, repeat};
 use std::sync::{Mutex, MutexGuard, OnceLock};
 
 use itertools::Itertools;
@@ -90,6 +92,7 @@ use rustc_data_structures::packed::Pu128;
 use rustc_data_structures::unhash::UnhashMap;
 use rustc_hir::def::{DefKind, Res};
 use rustc_hir::def_id::{CrateNum, DefId, LocalDefId, LocalModDefId, LOCAL_CRATE};
+use rustc_hir::definitions::{DefPath, DefPathData};
 use rustc_hir::hir_id::{HirIdMap, HirIdSet};
 use rustc_hir::intravisit::{walk_expr, FnKind, Visitor};
 use rustc_hir::LangItem::{OptionNone, OptionSome, ResultErr, ResultOk};
@@ -108,8 +111,8 @@ use rustc_middle::ty::binding::BindingMode;
 use rustc_middle::ty::fast_reject::SimplifiedType;
 use rustc_middle::ty::layout::IntegerExt;
 use rustc_middle::ty::{
-    self as rustc_ty, Binder, BorrowKind, ClosureKind, FloatTy, IntTy, ParamEnv, ParamEnvAnd, Ty, TyCtxt, TypeAndMut,
-    TypeVisitableExt, UintTy, UpvarCapture,
+    self as rustc_ty, Binder, BorrowKind, ClosureKind, EarlyBinder, FloatTy, GenericArgsRef, IntTy, ParamEnv,
+    ParamEnvAnd, Ty, TyCtxt, TypeAndMut, TypeVisitableExt, UintTy, UpvarCapture,
 };
 use rustc_span::hygiene::{ExpnKind, MacroKind};
 use rustc_span::source_map::SourceMap;
@@ -120,10 +123,7 @@ use visitors::Visitable;
 
 use crate::consts::{constant, mir_to_const, Constant};
 use crate::higher::Range;
-use crate::ty::{
-    adt_and_variant_of_res, can_partially_move_ty, expr_sig, is_copy, is_recursively_primitive_type,
-    ty_is_fn_once_param,
-};
+use crate::ty::{adt_and_variant_of_res, can_partially_move_ty, expr_sig, is_copy, is_recursively_primitive_type};
 use crate::visitors::for_each_expr;
 
 use rustc_middle::hir::nested_filter;
@@ -1359,46 +1359,12 @@ pub fn get_enclosing_loop_or_multi_call_closure<'tcx>(
     for (_, node) in cx.tcx.hir().parent_iter(expr.hir_id) {
         match node {
             Node::Expr(e) => match e.kind {
-                ExprKind::Closure { .. } => {
+                ExprKind::Closure { .. }
                     if let rustc_ty::Closure(_, subs) = cx.typeck_results().expr_ty(e).kind()
-                        && subs.as_closure().kind() == ClosureKind::FnOnce
-                    {
-                        continue;
-                    }
-                    let is_once = walk_to_expr_usage(cx, e, |node, id| {
-                        let Node::Expr(e) = node else {
-                            return None;
-                        };
-                        match e.kind {
-                            ExprKind::Call(f, _) if f.hir_id == id => Some(()),
-                            ExprKind::Call(f, args) => {
-                                let i = args.iter().position(|arg| arg.hir_id == id)?;
-                                let sig = expr_sig(cx, f)?;
-                                let predicates = sig
-                                    .predicates_id()
-                                    .map_or(cx.param_env, |id| cx.tcx.param_env(id))
-                                    .caller_bounds();
-                                sig.input(i).and_then(|ty| {
-                                    ty_is_fn_once_param(cx.tcx, ty.skip_binder(), predicates).then_some(())
-                                })
-                            },
-                            ExprKind::MethodCall(_, receiver, args, _) => {
-                                let i = std::iter::once(receiver)
-                                    .chain(args.iter())
-                                    .position(|arg| arg.hir_id == id)?;
-                                let id = cx.typeck_results().type_dependent_def_id(e.hir_id)?;
-                                let ty = cx.tcx.fn_sig(id).instantiate_identity().skip_binder().inputs()[i];
-                                ty_is_fn_once_param(cx.tcx, ty, cx.tcx.param_env(id).caller_bounds()).then_some(())
-                            },
-                            _ => None,
-                        }
-                    })
-                    .is_some();
-                    if !is_once {
-                        return Some(e);
-                    }
-                },
-                ExprKind::Loop(..) => return Some(e),
+                        && subs.as_closure().kind() == ClosureKind::FnOnce => {},
+
+                // Note: A closure's kind is determined by how it's used, not it's captures.
+                ExprKind::Closure { .. } | ExprKind::Loop(..) => return Some(e),
                 _ => (),
             },
             Node::Stmt(_) | Node::Block(_) | Node::Local(_) | Node::Arm(_) => (),
@@ -2596,26 +2562,30 @@ pub fn is_test_module_or_function(tcx: TyCtxt<'_>, item: &Item<'_>) -> bool {
             && item.ident.name.as_str().split('_').any(|a| a == "test" || a == "tests")
 }
 
-/// Walks the HIR tree from the given expression, up to the node where the value produced by the
-/// expression is consumed. Calls the function for every node encountered this way until it returns
-/// `Some`.
+/// Walks up the HIR tree from the given expression in an attempt to find where the value is
+/// consumed.
+///
+/// Termination has three conditions:
+/// - The given function returns `Break`. This function will return the value.
+/// - The consuming node is found. This function will return `Continue(use_node, child_id)`.
+/// - No further parent nodes are found. This will trigger a debug assert or return `None`.
 ///
-/// This allows walking through `if`, `match`, `break`, block expressions to find where the value
-/// produced by the expression is consumed.
+/// This allows walking through `if`, `match`, `break`, and block expressions to find where the
+/// value produced by the expression is consumed.
 pub fn walk_to_expr_usage<'tcx, T>(
     cx: &LateContext<'tcx>,
     e: &Expr<'tcx>,
-    mut f: impl FnMut(Node<'tcx>, HirId) -> Option<T>,
-) -> Option<T> {
+    mut f: impl FnMut(HirId, Node<'tcx>, HirId) -> ControlFlow<T>,
+) -> Option<ControlFlow<T, (Node<'tcx>, HirId)>> {
     let map = cx.tcx.hir();
     let mut iter = map.parent_iter(e.hir_id);
     let mut child_id = e.hir_id;
 
     while let Some((parent_id, parent)) = iter.next() {
-        if let Some(x) = f(parent, child_id) {
-            return Some(x);
+        if let ControlFlow::Break(x) = f(parent_id, parent, child_id) {
+            return Some(ControlFlow::Break(x));
         }
-        let parent = match parent {
+        let parent_expr = match parent {
             Node::Expr(e) => e,
             Node::Block(Block { expr: Some(body), .. }) | Node::Arm(Arm { body, .. }) if body.hir_id == child_id => {
                 child_id = parent_id;
@@ -2625,18 +2595,19 @@ pub fn walk_to_expr_usage<'tcx, T>(
                 child_id = parent_id;
                 continue;
             },
-            _ => return None,
+            _ => return Some(ControlFlow::Continue((parent, child_id))),
         };
-        match parent.kind {
+        match parent_expr.kind {
             ExprKind::If(child, ..) | ExprKind::Match(child, ..) if child.hir_id != child_id => child_id = parent_id,
             ExprKind::Break(Destination { target_id: Ok(id), .. }, _) => {
                 child_id = id;
                 iter = map.parent_iter(id);
             },
-            ExprKind::Block(..) => child_id = parent_id,
-            _ => return None,
+            ExprKind::Block(..) | ExprKind::DropTemps(_) => child_id = parent_id,
+            _ => return Some(ControlFlow::Continue((parent, child_id))),
         }
     }
+    debug_assert!(false, "no parent node found for `{child_id:?}`");
     None
 }
 
@@ -2680,6 +2651,8 @@ pub enum ExprUseNode<'tcx> {
     Callee,
     /// Access of a field.
     FieldAccess(Ident),
+    Expr,
+    Other,
 }
 impl<'tcx> ExprUseNode<'tcx> {
     /// Checks if the value is returned from the function.
@@ -2756,144 +2729,104 @@ impl<'tcx> ExprUseNode<'tcx> {
                 let sig = cx.tcx.fn_sig(id).skip_binder();
                 Some(DefinedTy::Mir(cx.tcx.param_env(id).and(sig.input(i))))
             },
-            Self::Local(_) | Self::FieldAccess(..) | Self::Callee => None,
+            Self::Local(_) | Self::FieldAccess(..) | Self::Callee | Self::Expr | Self::Other => None,
         }
     }
 }
 
 /// Gets the context an expression's value is used in.
-#[expect(clippy::too_many_lines)]
 pub fn expr_use_ctxt<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'tcx>) -> Option<ExprUseCtxt<'tcx>> {
     let mut adjustments = [].as_slice();
     let mut is_ty_unified = false;
     let mut moved_before_use = false;
     let ctxt = e.span.ctxt();
-    walk_to_expr_usage(cx, e, &mut |parent, child_id| {
-        // LocalTableInContext returns the wrong lifetime, so go use `expr_adjustments` instead.
+    walk_to_expr_usage(cx, e, &mut |parent_id, parent, child_id| {
         if adjustments.is_empty()
             && let Node::Expr(e) = cx.tcx.hir_node(child_id)
         {
             adjustments = cx.typeck_results().expr_adjustments(e);
         }
-        match parent {
-            Node::Local(l) if l.span.ctxt() == ctxt => Some(ExprUseCtxt {
-                node: ExprUseNode::Local(l),
-                adjustments,
-                is_ty_unified,
-                moved_before_use,
-            }),
+        if cx.tcx.hir().span(parent_id).ctxt() != ctxt {
+            return ControlFlow::Break(());
+        }
+        if let Node::Expr(e) = parent {
+            match e.kind {
+                ExprKind::If(e, _, _) | ExprKind::Match(e, _, _) if e.hir_id != child_id => {
+                    is_ty_unified = true;
+                    moved_before_use = true;
+                },
+                ExprKind::Block(_, Some(_)) | ExprKind::Break(..) => {
+                    is_ty_unified = true;
+                    moved_before_use = true;
+                },
+                ExprKind::Block(..) => moved_before_use = true,
+                _ => {},
+            }
+        }
+        ControlFlow::Continue(())
+    })?
+    .continue_value()
+    .map(|(use_node, child_id)| {
+        let node = match use_node {
+            Node::Local(l) => ExprUseNode::Local(l),
+            Node::ExprField(field) => ExprUseNode::Field(field),
+
             Node::Item(&Item {
                 kind: ItemKind::Static(..) | ItemKind::Const(..),
                 owner_id,
-                span,
                 ..
             })
             | Node::TraitItem(&TraitItem {
                 kind: TraitItemKind::Const(..),
                 owner_id,
-                span,
                 ..
             })
             | Node::ImplItem(&ImplItem {
                 kind: ImplItemKind::Const(..),
                 owner_id,
-                span,
                 ..
-            }) if span.ctxt() == ctxt => Some(ExprUseCtxt {
-                node: ExprUseNode::ConstStatic(owner_id),
-                adjustments,
-                is_ty_unified,
-                moved_before_use,
-            }),
+            }) => ExprUseNode::ConstStatic(owner_id),
 
             Node::Item(&Item {
                 kind: ItemKind::Fn(..),
                 owner_id,
-                span,
                 ..
             })
             | Node::TraitItem(&TraitItem {
                 kind: TraitItemKind::Fn(..),
                 owner_id,
-                span,
                 ..
             })
             | Node::ImplItem(&ImplItem {
                 kind: ImplItemKind::Fn(..),
                 owner_id,
-                span,
                 ..
-            }) if span.ctxt() == ctxt => Some(ExprUseCtxt {
-                node: ExprUseNode::Return(owner_id),
-                adjustments,
-                is_ty_unified,
-                moved_before_use,
-            }),
-
-            Node::ExprField(field) if field.span.ctxt() == ctxt => Some(ExprUseCtxt {
-                node: ExprUseNode::Field(field),
-                adjustments,
-                is_ty_unified,
-                moved_before_use,
-            }),
+            }) => ExprUseNode::Return(owner_id),
 
-            Node::Expr(parent) if parent.span.ctxt() == ctxt => match parent.kind {
-                ExprKind::Ret(_) => Some(ExprUseCtxt {
-                    node: ExprUseNode::Return(OwnerId {
-                        def_id: cx.tcx.hir().body_owner_def_id(cx.enclosing_body.unwrap()),
-                    }),
-                    adjustments,
-                    is_ty_unified,
-                    moved_before_use,
-                }),
-                ExprKind::Closure(closure) => Some(ExprUseCtxt {
-                    node: ExprUseNode::Return(OwnerId { def_id: closure.def_id }),
-                    adjustments,
-                    is_ty_unified,
-                    moved_before_use,
-                }),
-                ExprKind::Call(func, args) => Some(ExprUseCtxt {
-                    node: match args.iter().position(|arg| arg.hir_id == child_id) {
-                        Some(i) => ExprUseNode::FnArg(func, i),
-                        None => ExprUseNode::Callee,
-                    },
-                    adjustments,
-                    is_ty_unified,
-                    moved_before_use,
-                }),
-                ExprKind::MethodCall(name, _, args, _) => Some(ExprUseCtxt {
-                    node: ExprUseNode::MethodArg(
-                        parent.hir_id,
-                        name.args,
-                        args.iter().position(|arg| arg.hir_id == child_id).map_or(0, |i| i + 1),
-                    ),
-                    adjustments,
-                    is_ty_unified,
-                    moved_before_use,
-                }),
-                ExprKind::Field(child, name) if child.hir_id == e.hir_id => Some(ExprUseCtxt {
-                    node: ExprUseNode::FieldAccess(name),
-                    adjustments,
-                    is_ty_unified,
-                    moved_before_use,
+            Node::Expr(use_expr) => match use_expr.kind {
+                ExprKind::Ret(_) => ExprUseNode::Return(OwnerId {
+                    def_id: cx.tcx.hir().body_owner_def_id(cx.enclosing_body.unwrap()),
                 }),
-                ExprKind::If(e, _, _) | ExprKind::Match(e, _, _) if e.hir_id != child_id => {
-                    is_ty_unified = true;
-                    moved_before_use = true;
-                    None
-                },
-                ExprKind::Block(_, Some(_)) | ExprKind::Break(..) => {
-                    is_ty_unified = true;
-                    moved_before_use = true;
-                    None
+                ExprKind::Closure(closure) => ExprUseNode::Return(OwnerId { def_id: closure.def_id }),
+                ExprKind::Call(func, args) => match args.iter().position(|arg| arg.hir_id == child_id) {
+                    Some(i) => ExprUseNode::FnArg(func, i),
+                    None => ExprUseNode::Callee,
                 },
-                ExprKind::Block(..) => {
-                    moved_before_use = true;
-                    None
-                },
-                _ => None,
+                ExprKind::MethodCall(name, _, args, _) => ExprUseNode::MethodArg(
+                    use_expr.hir_id,
+                    name.args,
+                    args.iter().position(|arg| arg.hir_id == child_id).map_or(0, |i| i + 1),
+                ),
+                ExprKind::Field(child, name) if child.hir_id == e.hir_id => ExprUseNode::FieldAccess(name),
+                _ => ExprUseNode::Expr,
             },
-            _ => None,
+            _ => ExprUseNode::Other,
+        };
+        ExprUseCtxt {
+            node,
+            adjustments,
+            is_ty_unified,
+            moved_before_use,
         }
     })
 }
@@ -3270,3 +3203,131 @@ pub fn is_never_expr<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) -> Option<
             })
     }
 }
+
+/// Produces a path from a local caller to the type of the called method. Suitable for user
+/// output/suggestions.
+///
+/// Returned path can be either absolute (for methods defined non-locally), or relative (for local
+/// methods).
+pub fn get_path_from_caller_to_method_type<'tcx>(
+    tcx: TyCtxt<'tcx>,
+    from: LocalDefId,
+    method: DefId,
+    args: GenericArgsRef<'tcx>,
+) -> String {
+    let assoc_item = tcx.associated_item(method);
+    let def_id = assoc_item.container_id(tcx);
+    match assoc_item.container {
+        rustc_ty::TraitContainer => get_path_to_callee(tcx, from, def_id),
+        rustc_ty::ImplContainer => {
+            let ty = tcx.type_of(def_id).instantiate_identity();
+            get_path_to_ty(tcx, from, ty, args)
+        },
+    }
+}
+
+fn get_path_to_ty<'tcx>(tcx: TyCtxt<'tcx>, from: LocalDefId, ty: Ty<'tcx>, args: GenericArgsRef<'tcx>) -> String {
+    match ty.kind() {
+        rustc_ty::Adt(adt, _) => get_path_to_callee(tcx, from, adt.did()),
+        // TODO these types need to be recursively resolved as well
+        rustc_ty::Array(..)
+        | rustc_ty::Dynamic(..)
+        | rustc_ty::Never
+        | rustc_ty::RawPtr(_)
+        | rustc_ty::Ref(..)
+        | rustc_ty::Slice(_)
+        | rustc_ty::Tuple(_) => format!("<{}>", EarlyBinder::bind(ty).instantiate(tcx, args)),
+        _ => ty.to_string(),
+    }
+}
+
+/// Produce a path from some local caller to the callee. Suitable for user output/suggestions.
+fn get_path_to_callee(tcx: TyCtxt<'_>, from: LocalDefId, callee: DefId) -> String {
+    // only search for a relative path if the call is fully local
+    if callee.is_local() {
+        let callee_path = tcx.def_path(callee);
+        let caller_path = tcx.def_path(from.to_def_id());
+        maybe_get_relative_path(&caller_path, &callee_path, 2)
+    } else {
+        tcx.def_path_str(callee)
+    }
+}
+
+/// Tries to produce a relative path from `from` to `to`; if such a path would contain more than
+/// `max_super` `super` items, produces an absolute path instead. Both `from` and `to` should be in
+/// the local crate.
+///
+/// Suitable for user output/suggestions.
+///
+/// This ignores use items, and assumes that the target path is visible from the source
+/// path (which _should_ be a reasonable assumption since we in order to be able to use an object of
+/// certain type T, T is required to be visible).
+///
+/// TODO make use of `use` items. Maybe we should have something more sophisticated like
+/// rust-analyzer does? <https://docs.rs/ra_ap_hir_def/0.0.169/src/ra_ap_hir_def/find_path.rs.html#19-27>
+fn maybe_get_relative_path(from: &DefPath, to: &DefPath, max_super: usize) -> String {
+    use itertools::EitherOrBoth::{Both, Left, Right};
+
+    // 1. skip the segments common for both paths (regardless of their type)
+    let unique_parts = to
+        .data
+        .iter()
+        .zip_longest(from.data.iter())
+        .skip_while(|el| matches!(el, Both(l, r) if l == r))
+        .map(|el| match el {
+            Both(l, r) => Both(l.data, r.data),
+            Left(l) => Left(l.data),
+            Right(r) => Right(r.data),
+        });
+
+    // 2. for the remaning segments, construct relative path using only mod names and `super`
+    let mut go_up_by = 0;
+    let mut path = Vec::new();
+    for el in unique_parts {
+        match el {
+            Both(l, r) => {
+                // consider:
+                // a::b::sym:: ::    refers to
+                // c::d::e  ::f::sym
+                // result should be super::super::c::d::e::f
+                //
+                // alternatively:
+                // a::b::c  ::d::sym refers to
+                // e::f::sym:: ::
+                // result should be super::super::super::super::e::f
+                if let DefPathData::TypeNs(s) = l {
+                    path.push(s.to_string());
+                }
+                if let DefPathData::TypeNs(_) = r {
+                    go_up_by += 1;
+                }
+            },
+            // consider:
+            // a::b::sym:: ::    refers to
+            // c::d::e  ::f::sym
+            // when looking at `f`
+            Left(DefPathData::TypeNs(sym)) => path.push(sym.to_string()),
+            // consider:
+            // a::b::c  ::d::sym refers to
+            // e::f::sym:: ::
+            // when looking at `d`
+            Right(DefPathData::TypeNs(_)) => go_up_by += 1,
+            _ => {},
+        }
+    }
+
+    if go_up_by > max_super {
+        // `super` chain would be too long, just use the absolute path instead
+        once(String::from("crate"))
+            .chain(to.data.iter().filter_map(|el| {
+                if let DefPathData::TypeNs(sym) = el.data {
+                    Some(sym.to_string())
+                } else {
+                    None
+                }
+            }))
+            .join("::")
+    } else {
+        repeat(String::from("super")).take(go_up_by).chain(path).join("::")
+    }
+}
diff --git a/src/tools/clippy/clippy_utils/src/ty.rs b/src/tools/clippy/clippy_utils/src/ty.rs
index 11bb16ff6c5..6762c883005 100644
--- a/src/tools/clippy/clippy_utils/src/ty.rs
+++ b/src/tools/clippy/clippy_utils/src/ty.rs
@@ -1000,35 +1000,6 @@ pub fn adt_and_variant_of_res<'tcx>(cx: &LateContext<'tcx>, res: Res) -> Option<
     }
 }
 
-/// Checks if the type is a type parameter implementing `FnOnce`, but not `FnMut`.
-pub fn ty_is_fn_once_param<'tcx>(tcx: TyCtxt<'_>, ty: Ty<'tcx>, predicates: &'tcx [ty::Clause<'_>]) -> bool {
-    let ty::Param(ty) = *ty.kind() else {
-        return false;
-    };
-    let lang = tcx.lang_items();
-    let (Some(fn_once_id), Some(fn_mut_id), Some(fn_id)) = (lang.fn_once_trait(), lang.fn_mut_trait(), lang.fn_trait())
-    else {
-        return false;
-    };
-    predicates
-        .iter()
-        .try_fold(false, |found, p| {
-            if let ty::ClauseKind::Trait(p) = p.kind().skip_binder()
-                && let ty::Param(self_ty) = p.trait_ref.self_ty().kind()
-                && ty.index == self_ty.index
-            {
-                // This should use `super_traits_of`, but that's a private function.
-                if p.trait_ref.def_id == fn_once_id {
-                    return Some(true);
-                } else if p.trait_ref.def_id == fn_mut_id || p.trait_ref.def_id == fn_id {
-                    return None;
-                }
-            }
-            Some(found)
-        })
-        .unwrap_or(false)
-}
-
 /// Comes up with an "at least" guesstimate for the type's size, not taking into
 /// account the layout of type parameters.
 pub fn approx_ty_size<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> u64 {
diff --git a/src/tools/clippy/declare_clippy_lint/Cargo.toml b/src/tools/clippy/declare_clippy_lint/Cargo.toml
index 5aaafb41721..0f90cef5cdd 100644
--- a/src/tools/clippy/declare_clippy_lint/Cargo.toml
+++ b/src/tools/clippy/declare_clippy_lint/Cargo.toml
@@ -1,6 +1,6 @@
 [package]
 name = "declare_clippy_lint"
-version = "0.1.77"
+version = "0.1.78"
 edition = "2021"
 publish = false
 
diff --git a/src/tools/clippy/rust-toolchain b/src/tools/clippy/rust-toolchain
index d2d56e59ee3..fcf5c456270 100644
--- a/src/tools/clippy/rust-toolchain
+++ b/src/tools/clippy/rust-toolchain
@@ -1,3 +1,3 @@
 [toolchain]
-channel = "nightly-2024-01-25"
+channel = "nightly-2024-02-08"
 components = ["cargo", "llvm-tools", "rust-src", "rust-std", "rustc", "rustc-dev", "rustfmt"]
diff --git a/src/tools/clippy/src/driver.rs b/src/tools/clippy/src/driver.rs
index 1b159f5937a..bdf1cf0a224 100644
--- a/src/tools/clippy/src/driver.rs
+++ b/src/tools/clippy/src/driver.rs
@@ -24,9 +24,11 @@ use rustc_session::EarlyDiagCtxt;
 use rustc_span::symbol::Symbol;
 
 use std::env;
+use std::fs::read_to_string;
 use std::ops::Deref;
 use std::path::Path;
 use std::process::exit;
+use std::string::ToString;
 
 use anstream::println;
 
@@ -190,12 +192,31 @@ pub fn main() {
 
     exit(rustc_driver::catch_with_exit_code(move || {
         let mut orig_args: Vec<String> = env::args().collect();
-        let has_sysroot_arg = arg_value(&orig_args, "--sysroot", |_| true).is_some();
+
+        let has_sysroot_arg = |args: &mut [String]| -> bool {
+            if arg_value(args, "--sysroot", |_| true).is_some() {
+                return true;
+            }
+            // https://doc.rust-lang.org/rustc/command-line-arguments.html#path-load-command-line-flags-from-a-path
+            // Beside checking for existence of `--sysroot` on the command line, we need to
+            // check for the arg files that are prefixed with @ as well to be consistent with rustc
+            for arg in args.iter() {
+                if let Some(arg_file_path) = arg.strip_prefix('@') {
+                    if let Ok(arg_file) = read_to_string(arg_file_path) {
+                        let split_arg_file: Vec<String> = arg_file.lines().map(ToString::to_string).collect();
+                        if arg_value(&split_arg_file, "--sysroot", |_| true).is_some() {
+                            return true;
+                        }
+                    }
+                }
+            }
+            false
+        };
 
         let sys_root_env = std::env::var("SYSROOT").ok();
         let pass_sysroot_env_if_given = |args: &mut Vec<String>, sys_root_env| {
             if let Some(sys_root) = sys_root_env {
-                if !has_sysroot_arg {
+                if !has_sysroot_arg(args) {
                     args.extend(vec!["--sysroot".into(), sys_root]);
                 }
             };
diff --git a/src/tools/clippy/tests/ui-cargo/lint_groups_priority/fail/Cargo.stderr b/src/tools/clippy/tests/ui-cargo/lint_groups_priority/fail/Cargo.stderr
new file mode 100644
index 00000000000..103e60d8484
--- /dev/null
+++ b/src/tools/clippy/tests/ui-cargo/lint_groups_priority/fail/Cargo.stderr
@@ -0,0 +1,45 @@
+error: lint group `rust_2018_idioms` has the same priority (0) as a lint
+ --> Cargo.toml:7:1
+  |
+7 | rust_2018_idioms = "warn"
+  | ^^^^^^^^^^^^^^^^   ------ has an implicit priority of 0
+8 | bare_trait_objects = "allow"
+  | ------------------ has the same priority as this lint
+  |
+  = note: the order of the lints in the table is ignored by Cargo
+  = note: `#[deny(clippy::lint_groups_priority)]` on by default
+help: to have lints override the group set `rust_2018_idioms` to a lower priority
+  |
+7 | rust_2018_idioms = { level = "warn", priority = -1 }
+  |                    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+error: lint group `unused` has the same priority (0) as a lint
+  --> Cargo.toml:10:1
+   |
+10 | unused = { level = "deny" }
+   | ^^^^^^   ------------------ has an implicit priority of 0
+11 | unused_braces = { level = "allow", priority = 1 }
+12 | unused_attributes = { level = "allow" }
+   | ----------------- has the same priority as this lint
+   |
+   = note: the order of the lints in the table is ignored by Cargo
+help: to have lints override the group set `unused` to a lower priority
+   |
+10 | unused = { level = "deny", priority = -1 }
+   |          ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+error: lint group `pedantic` has the same priority (-1) as a lint
+  --> Cargo.toml:19:1
+   |
+19 | pedantic = { level = "warn", priority = -1 }
+   | ^^^^^^^^
+20 | similar_names = { level = "allow", priority = -1 }
+   | ------------- has the same priority as this lint
+   |
+   = note: the order of the lints in the table is ignored by Cargo
+help: to have lints override the group set `pedantic` to a lower priority
+   |
+19 | pedantic = { level = "warn", priority = -2 }
+   |            ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+error: could not compile `fail` (lib) due to 3 previous errors
diff --git a/src/tools/clippy/tests/ui-cargo/lint_groups_priority/fail/Cargo.toml b/src/tools/clippy/tests/ui-cargo/lint_groups_priority/fail/Cargo.toml
new file mode 100644
index 00000000000..4ce41f78171
--- /dev/null
+++ b/src/tools/clippy/tests/ui-cargo/lint_groups_priority/fail/Cargo.toml
@@ -0,0 +1,20 @@
+[package]
+name = "fail"
+version = "0.1.0"
+publish = false
+
+[lints.rust]
+rust_2018_idioms = "warn"
+bare_trait_objects = "allow"
+
+unused = { level = "deny" }
+unused_braces = { level = "allow", priority = 1 }
+unused_attributes = { level = "allow" }
+
+# `warnings` is not a group so the order it is passed does not matter
+warnings = "deny"
+deprecated  = "allow"
+
+[lints.clippy]
+pedantic = { level = "warn", priority = -1 }
+similar_names = { level = "allow", priority = -1 }
diff --git a/src/tools/clippy/tests/ui-cargo/lint_groups_priority/fail/src/lib.rs b/src/tools/clippy/tests/ui-cargo/lint_groups_priority/fail/src/lib.rs
new file mode 100644
index 00000000000..8b137891791
--- /dev/null
+++ b/src/tools/clippy/tests/ui-cargo/lint_groups_priority/fail/src/lib.rs
@@ -0,0 +1 @@
+
diff --git a/src/tools/clippy/tests/ui-cargo/lint_groups_priority/pass/Cargo.toml b/src/tools/clippy/tests/ui-cargo/lint_groups_priority/pass/Cargo.toml
new file mode 100644
index 00000000000..e9fcf803d93
--- /dev/null
+++ b/src/tools/clippy/tests/ui-cargo/lint_groups_priority/pass/Cargo.toml
@@ -0,0 +1,10 @@
+[package]
+name = "pass"
+version = "0.1.0"
+publish = false
+
+[lints.clippy]
+pedantic = { level = "warn", priority = -1 }
+style = { level = "warn", priority = 1 }
+similar_names = "allow"
+dbg_macro = { level = "warn", priority = 2 }
diff --git a/src/tools/clippy/tests/ui-cargo/lint_groups_priority/pass/src/lib.rs b/src/tools/clippy/tests/ui-cargo/lint_groups_priority/pass/src/lib.rs
new file mode 100644
index 00000000000..8b137891791
--- /dev/null
+++ b/src/tools/clippy/tests/ui-cargo/lint_groups_priority/pass/src/lib.rs
@@ -0,0 +1 @@
+
diff --git a/src/tools/clippy/tests/ui-toml/min_rust_version/min_rust_version.fixed b/src/tools/clippy/tests/ui-toml/min_rust_version/min_rust_version.fixed
index 6c58e07d846..497f783087a 100644
--- a/src/tools/clippy/tests/ui-toml/min_rust_version/min_rust_version.fixed
+++ b/src/tools/clippy/tests/ui-toml/min_rust_version/min_rust_version.fixed
@@ -1,4 +1,4 @@
-#![allow(clippy::redundant_clone, clippy::unnecessary_operation)]
+#![allow(clippy::redundant_clone, clippy::unnecessary_operation, clippy::incompatible_msrv)]
 #![warn(clippy::manual_non_exhaustive, clippy::borrow_as_ptr, clippy::manual_bits)]
 
 use std::mem::{size_of, size_of_val};
diff --git a/src/tools/clippy/tests/ui-toml/min_rust_version/min_rust_version.rs b/src/tools/clippy/tests/ui-toml/min_rust_version/min_rust_version.rs
index e1dc3f4389c..6e7874108a3 100644
--- a/src/tools/clippy/tests/ui-toml/min_rust_version/min_rust_version.rs
+++ b/src/tools/clippy/tests/ui-toml/min_rust_version/min_rust_version.rs
@@ -1,4 +1,4 @@
-#![allow(clippy::redundant_clone, clippy::unnecessary_operation)]
+#![allow(clippy::redundant_clone, clippy::unnecessary_operation, clippy::incompatible_msrv)]
 #![warn(clippy::manual_non_exhaustive, clippy::borrow_as_ptr, clippy::manual_bits)]
 
 use std::mem::{size_of, size_of_val};
diff --git a/src/tools/clippy/tests/ui-toml/modulo_arithmetic/clippy.toml b/src/tools/clippy/tests/ui-toml/modulo_arithmetic/clippy.toml
new file mode 100644
index 00000000000..de80f4ae598
--- /dev/null
+++ b/src/tools/clippy/tests/ui-toml/modulo_arithmetic/clippy.toml
@@ -0,0 +1 @@
+allow-comparison-to-zero = false
diff --git a/src/tools/clippy/tests/ui-toml/modulo_arithmetic/modulo_arithmetic.rs b/src/tools/clippy/tests/ui-toml/modulo_arithmetic/modulo_arithmetic.rs
new file mode 100644
index 00000000000..27d27564baf
--- /dev/null
+++ b/src/tools/clippy/tests/ui-toml/modulo_arithmetic/modulo_arithmetic.rs
@@ -0,0 +1,10 @@
+#![warn(clippy::modulo_arithmetic)]
+
+fn main() {
+    let a = -1;
+    let b = 2;
+    let c = a % b == 0;
+    let c = a % b != 0;
+    let c = 0 == a % b;
+    let c = 0 != a % b;
+}
diff --git a/src/tools/clippy/tests/ui-toml/modulo_arithmetic/modulo_arithmetic.stderr b/src/tools/clippy/tests/ui-toml/modulo_arithmetic/modulo_arithmetic.stderr
new file mode 100644
index 00000000000..da644b05a11
--- /dev/null
+++ b/src/tools/clippy/tests/ui-toml/modulo_arithmetic/modulo_arithmetic.stderr
@@ -0,0 +1,40 @@
+error: you are using modulo operator on types that might have different signs
+  --> $DIR/modulo_arithmetic.rs:6:13
+   |
+LL |     let c = a % b == 0;
+   |             ^^^^^
+   |
+   = note: double check for expected result especially when interoperating with different languages
+   = note: or consider using `rem_euclid` or similar function
+   = note: `-D clippy::modulo-arithmetic` implied by `-D warnings`
+   = help: to override `-D warnings` add `#[allow(clippy::modulo_arithmetic)]`
+
+error: you are using modulo operator on types that might have different signs
+  --> $DIR/modulo_arithmetic.rs:7:13
+   |
+LL |     let c = a % b != 0;
+   |             ^^^^^
+   |
+   = note: double check for expected result especially when interoperating with different languages
+   = note: or consider using `rem_euclid` or similar function
+
+error: you are using modulo operator on types that might have different signs
+  --> $DIR/modulo_arithmetic.rs:8:18
+   |
+LL |     let c = 0 == a % b;
+   |                  ^^^^^
+   |
+   = note: double check for expected result especially when interoperating with different languages
+   = note: or consider using `rem_euclid` or similar function
+
+error: you are using modulo operator on types that might have different signs
+  --> $DIR/modulo_arithmetic.rs:9:18
+   |
+LL |     let c = 0 != a % b;
+   |                  ^^^^^
+   |
+   = note: double check for expected result especially when interoperating with different languages
+   = note: or consider using `rem_euclid` or similar function
+
+error: aborting due to 4 previous errors
+
diff --git a/src/tools/clippy/tests/ui-toml/toml_unknown_key/conf_unknown_key.stderr b/src/tools/clippy/tests/ui-toml/toml_unknown_key/conf_unknown_key.stderr
index fc683e514ba..f097d2503e1 100644
--- a/src/tools/clippy/tests/ui-toml/toml_unknown_key/conf_unknown_key.stderr
+++ b/src/tools/clippy/tests/ui-toml/toml_unknown_key/conf_unknown_key.stderr
@@ -3,6 +3,7 @@ error: error reading Clippy's configuration file: unknown field `foobar`, expect
            absolute-paths-max-segments
            accept-comment-above-attributes
            accept-comment-above-statement
+           allow-comparison-to-zero
            allow-dbg-in-tests
            allow-expect-in-tests
            allow-mixed-uninlined-format-args
@@ -14,6 +15,7 @@ error: error reading Clippy's configuration file: unknown field `foobar`, expect
            allowed-duplicate-crates
            allowed-idents-below-min-chars
            allowed-scripts
+           allowed-wildcard-imports
            arithmetic-side-effects-allowed
            arithmetic-side-effects-allowed-binary
            arithmetic-side-effects-allowed-unary
@@ -80,6 +82,7 @@ error: error reading Clippy's configuration file: unknown field `barfoo`, expect
            absolute-paths-max-segments
            accept-comment-above-attributes
            accept-comment-above-statement
+           allow-comparison-to-zero
            allow-dbg-in-tests
            allow-expect-in-tests
            allow-mixed-uninlined-format-args
@@ -91,6 +94,7 @@ error: error reading Clippy's configuration file: unknown field `barfoo`, expect
            allowed-duplicate-crates
            allowed-idents-below-min-chars
            allowed-scripts
+           allowed-wildcard-imports
            arithmetic-side-effects-allowed
            arithmetic-side-effects-allowed-binary
            arithmetic-side-effects-allowed-unary
@@ -157,6 +161,7 @@ error: error reading Clippy's configuration file: unknown field `allow_mixed_uni
            absolute-paths-max-segments
            accept-comment-above-attributes
            accept-comment-above-statement
+           allow-comparison-to-zero
            allow-dbg-in-tests
            allow-expect-in-tests
            allow-mixed-uninlined-format-args
@@ -168,6 +173,7 @@ error: error reading Clippy's configuration file: unknown field `allow_mixed_uni
            allowed-duplicate-crates
            allowed-idents-below-min-chars
            allowed-scripts
+           allowed-wildcard-imports
            arithmetic-side-effects-allowed
            arithmetic-side-effects-allowed-binary
            arithmetic-side-effects-allowed-unary
diff --git a/src/tools/clippy/tests/ui-toml/wildcard_imports/clippy.toml b/src/tools/clippy/tests/ui-toml/wildcard_imports/clippy.toml
index 875aaeef6c9..68815c1756a 100644
--- a/src/tools/clippy/tests/ui-toml/wildcard_imports/clippy.toml
+++ b/src/tools/clippy/tests/ui-toml/wildcard_imports/clippy.toml
@@ -1 +1,4 @@
 warn-on-all-wildcard-imports = true
+
+# This should be ignored since `warn-on-all-wildcard-imports` has higher precedence
+allowed-wildcard-imports = ["utils"]
diff --git a/src/tools/clippy/tests/ui-toml/wildcard_imports/wildcard_imports.fixed b/src/tools/clippy/tests/ui-toml/wildcard_imports/wildcard_imports.fixed
index 1752f48856c..af72d6be0e0 100644
--- a/src/tools/clippy/tests/ui-toml/wildcard_imports/wildcard_imports.fixed
+++ b/src/tools/clippy/tests/ui-toml/wildcard_imports/wildcard_imports.fixed
@@ -3,9 +3,28 @@
 mod prelude {
     pub const FOO: u8 = 1;
 }
+
+mod utils {
+    pub const BAR: u8 = 1;
+    pub fn print() {}
+}
+
+mod my_crate {
+    pub mod utils {
+        pub fn my_util_fn() {}
+    }
+}
+
+use utils::{BAR, print};
+//~^ ERROR: usage of wildcard import
+use my_crate::utils::my_util_fn;
+//~^ ERROR: usage of wildcard import
 use prelude::FOO;
 //~^ ERROR: usage of wildcard import
 
 fn main() {
     let _ = FOO;
+    let _ = BAR;
+    print();
+    my_util_fn();
 }
diff --git a/src/tools/clippy/tests/ui-toml/wildcard_imports/wildcard_imports.rs b/src/tools/clippy/tests/ui-toml/wildcard_imports/wildcard_imports.rs
index 331c2c59c22..91009dd8835 100644
--- a/src/tools/clippy/tests/ui-toml/wildcard_imports/wildcard_imports.rs
+++ b/src/tools/clippy/tests/ui-toml/wildcard_imports/wildcard_imports.rs
@@ -3,9 +3,28 @@
 mod prelude {
     pub const FOO: u8 = 1;
 }
+
+mod utils {
+    pub const BAR: u8 = 1;
+    pub fn print() {}
+}
+
+mod my_crate {
+    pub mod utils {
+        pub fn my_util_fn() {}
+    }
+}
+
+use utils::*;
+//~^ ERROR: usage of wildcard import
+use my_crate::utils::*;
+//~^ ERROR: usage of wildcard import
 use prelude::*;
 //~^ ERROR: usage of wildcard import
 
 fn main() {
     let _ = FOO;
+    let _ = BAR;
+    print();
+    my_util_fn();
 }
diff --git a/src/tools/clippy/tests/ui-toml/wildcard_imports/wildcard_imports.stderr b/src/tools/clippy/tests/ui-toml/wildcard_imports/wildcard_imports.stderr
index f11fda6a0c6..a733d786d0e 100644
--- a/src/tools/clippy/tests/ui-toml/wildcard_imports/wildcard_imports.stderr
+++ b/src/tools/clippy/tests/ui-toml/wildcard_imports/wildcard_imports.stderr
@@ -1,11 +1,23 @@
 error: usage of wildcard import
-  --> $DIR/wildcard_imports.rs:6:5
+  --> $DIR/wildcard_imports.rs:18:5
    |
-LL | use prelude::*;
-   |     ^^^^^^^^^^ help: try: `prelude::FOO`
+LL | use utils::*;
+   |     ^^^^^^^^ help: try: `utils::{BAR, print}`
    |
    = note: `-D clippy::wildcard-imports` implied by `-D warnings`
    = help: to override `-D warnings` add `#[allow(clippy::wildcard_imports)]`
 
-error: aborting due to 1 previous error
+error: usage of wildcard import
+  --> $DIR/wildcard_imports.rs:20:5
+   |
+LL | use my_crate::utils::*;
+   |     ^^^^^^^^^^^^^^^^^^ help: try: `my_crate::utils::my_util_fn`
+
+error: usage of wildcard import
+  --> $DIR/wildcard_imports.rs:22:5
+   |
+LL | use prelude::*;
+   |     ^^^^^^^^^^ help: try: `prelude::FOO`
+
+error: aborting due to 3 previous errors
 
diff --git a/src/tools/clippy/tests/ui-toml/wildcard_imports_whitelist/clippy.toml b/src/tools/clippy/tests/ui-toml/wildcard_imports_whitelist/clippy.toml
new file mode 100644
index 00000000000..6b7882e64a8
--- /dev/null
+++ b/src/tools/clippy/tests/ui-toml/wildcard_imports_whitelist/clippy.toml
@@ -0,0 +1 @@
+allowed-wildcard-imports = ["utils"]
diff --git a/src/tools/clippy/tests/ui-toml/wildcard_imports_whitelist/wildcard_imports.fixed b/src/tools/clippy/tests/ui-toml/wildcard_imports_whitelist/wildcard_imports.fixed
new file mode 100644
index 00000000000..d539525c45e
--- /dev/null
+++ b/src/tools/clippy/tests/ui-toml/wildcard_imports_whitelist/wildcard_imports.fixed
@@ -0,0 +1,26 @@
+#![warn(clippy::wildcard_imports)]
+
+mod utils {
+    pub fn print() {}
+}
+
+mod utils_plus {
+    pub fn do_something() {}
+}
+
+mod my_crate {
+    pub mod utils {
+        pub fn my_util_fn() {}
+    }
+}
+
+use my_crate::utils::*;
+use utils::*;
+use utils_plus::do_something;
+//~^ ERROR: usage of wildcard import
+
+fn main() {
+    print();
+    my_util_fn();
+    do_something();
+}
diff --git a/src/tools/clippy/tests/ui-toml/wildcard_imports_whitelist/wildcard_imports.rs b/src/tools/clippy/tests/ui-toml/wildcard_imports_whitelist/wildcard_imports.rs
new file mode 100644
index 00000000000..9169d16a08b
--- /dev/null
+++ b/src/tools/clippy/tests/ui-toml/wildcard_imports_whitelist/wildcard_imports.rs
@@ -0,0 +1,26 @@
+#![warn(clippy::wildcard_imports)]
+
+mod utils {
+    pub fn print() {}
+}
+
+mod utils_plus {
+    pub fn do_something() {}
+}
+
+mod my_crate {
+    pub mod utils {
+        pub fn my_util_fn() {}
+    }
+}
+
+use my_crate::utils::*;
+use utils::*;
+use utils_plus::*;
+//~^ ERROR: usage of wildcard import
+
+fn main() {
+    print();
+    my_util_fn();
+    do_something();
+}
diff --git a/src/tools/clippy/tests/ui-toml/wildcard_imports_whitelist/wildcard_imports.stderr b/src/tools/clippy/tests/ui-toml/wildcard_imports_whitelist/wildcard_imports.stderr
new file mode 100644
index 00000000000..12c2f9cbada
--- /dev/null
+++ b/src/tools/clippy/tests/ui-toml/wildcard_imports_whitelist/wildcard_imports.stderr
@@ -0,0 +1,11 @@
+error: usage of wildcard import
+  --> $DIR/wildcard_imports.rs:19:5
+   |
+LL | use utils_plus::*;
+   |     ^^^^^^^^^^^^^ help: try: `utils_plus::do_something`
+   |
+   = note: `-D clippy::wildcard-imports` implied by `-D warnings`
+   = help: to override `-D warnings` add `#[allow(clippy::wildcard_imports)]`
+
+error: aborting due to 1 previous error
+
diff --git a/src/tools/clippy/tests/ui/borrow_as_ptr.fixed b/src/tools/clippy/tests/ui/borrow_as_ptr.fixed
index 6c0de96d65e..289a5ef38b8 100644
--- a/src/tools/clippy/tests/ui/borrow_as_ptr.fixed
+++ b/src/tools/clippy/tests/ui/borrow_as_ptr.fixed
@@ -5,6 +5,7 @@ fn a() -> i32 {
     0
 }
 
+#[clippy::msrv = "1.75"]
 fn main() {
     let val = 1;
     let _p = std::ptr::addr_of!(val);
diff --git a/src/tools/clippy/tests/ui/borrow_as_ptr.rs b/src/tools/clippy/tests/ui/borrow_as_ptr.rs
index c37c5357c82..b5328cb22dc 100644
--- a/src/tools/clippy/tests/ui/borrow_as_ptr.rs
+++ b/src/tools/clippy/tests/ui/borrow_as_ptr.rs
@@ -5,6 +5,7 @@ fn a() -> i32 {
     0
 }
 
+#[clippy::msrv = "1.75"]
 fn main() {
     let val = 1;
     let _p = &val as *const i32;
diff --git a/src/tools/clippy/tests/ui/borrow_as_ptr.stderr b/src/tools/clippy/tests/ui/borrow_as_ptr.stderr
index 43a7a6bf5b5..b9861805905 100644
--- a/src/tools/clippy/tests/ui/borrow_as_ptr.stderr
+++ b/src/tools/clippy/tests/ui/borrow_as_ptr.stderr
@@ -1,5 +1,5 @@
 error: borrow as raw pointer
-  --> $DIR/borrow_as_ptr.rs:10:14
+  --> $DIR/borrow_as_ptr.rs:11:14
    |
 LL |     let _p = &val as *const i32;
    |              ^^^^^^^^^^^^^^^^^^ help: try: `std::ptr::addr_of!(val)`
@@ -8,7 +8,7 @@ LL |     let _p = &val as *const i32;
    = help: to override `-D warnings` add `#[allow(clippy::borrow_as_ptr)]`
 
 error: borrow as raw pointer
-  --> $DIR/borrow_as_ptr.rs:17:18
+  --> $DIR/borrow_as_ptr.rs:18:18
    |
 LL |     let _p_mut = &mut val_mut as *mut i32;
    |                  ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `std::ptr::addr_of_mut!(val_mut)`
diff --git a/src/tools/clippy/tests/ui/borrow_as_ptr_no_std.fixed b/src/tools/clippy/tests/ui/borrow_as_ptr_no_std.fixed
index a361a36474d..f66554de300 100644
--- a/src/tools/clippy/tests/ui/borrow_as_ptr_no_std.fixed
+++ b/src/tools/clippy/tests/ui/borrow_as_ptr_no_std.fixed
@@ -2,6 +2,7 @@
 #![feature(lang_items, start, libc)]
 #![no_std]
 
+#[clippy::msrv = "1.75"]
 #[start]
 fn main(_argc: isize, _argv: *const *const u8) -> isize {
     let val = 1;
diff --git a/src/tools/clippy/tests/ui/borrow_as_ptr_no_std.rs b/src/tools/clippy/tests/ui/borrow_as_ptr_no_std.rs
index b3fe01442b7..1fc254aafa7 100644
--- a/src/tools/clippy/tests/ui/borrow_as_ptr_no_std.rs
+++ b/src/tools/clippy/tests/ui/borrow_as_ptr_no_std.rs
@@ -2,6 +2,7 @@
 #![feature(lang_items, start, libc)]
 #![no_std]
 
+#[clippy::msrv = "1.75"]
 #[start]
 fn main(_argc: isize, _argv: *const *const u8) -> isize {
     let val = 1;
diff --git a/src/tools/clippy/tests/ui/borrow_as_ptr_no_std.stderr b/src/tools/clippy/tests/ui/borrow_as_ptr_no_std.stderr
index 2f258bcf966..1ef0a948a32 100644
--- a/src/tools/clippy/tests/ui/borrow_as_ptr_no_std.stderr
+++ b/src/tools/clippy/tests/ui/borrow_as_ptr_no_std.stderr
@@ -1,5 +1,5 @@
 error: borrow as raw pointer
-  --> $DIR/borrow_as_ptr_no_std.rs:8:14
+  --> $DIR/borrow_as_ptr_no_std.rs:9:14
    |
 LL |     let _p = &val as *const i32;
    |              ^^^^^^^^^^^^^^^^^^ help: try: `core::ptr::addr_of!(val)`
@@ -8,7 +8,7 @@ LL |     let _p = &val as *const i32;
    = help: to override `-D warnings` add `#[allow(clippy::borrow_as_ptr)]`
 
 error: borrow as raw pointer
-  --> $DIR/borrow_as_ptr_no_std.rs:11:18
+  --> $DIR/borrow_as_ptr_no_std.rs:12:18
    |
 LL |     let _p_mut = &mut val_mut as *mut i32;
    |                  ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `core::ptr::addr_of_mut!(val_mut)`
diff --git a/src/tools/clippy/tests/ui/eta.fixed b/src/tools/clippy/tests/ui/eta.fixed
index 32c7499bf73..da28ec2e653 100644
--- a/src/tools/clippy/tests/ui/eta.fixed
+++ b/src/tools/clippy/tests/ui/eta.fixed
@@ -346,6 +346,23 @@ fn angle_brackets_and_args() {
     dyn_opt.map(<dyn TestTrait>::method_on_dyn);
 }
 
+// https://github.com/rust-lang/rust-clippy/issues/12199
+fn track_caller_fp() {
+    struct S;
+    impl S {
+        #[track_caller]
+        fn add_location(self) {}
+    }
+
+    #[track_caller]
+    fn add_location() {}
+
+    fn foo(_: fn()) {}
+    fn foo2(_: fn(S)) {}
+    foo(|| add_location());
+    foo2(|s| s.add_location());
+}
+
 fn _late_bound_to_early_bound_regions() {
     struct Foo<'a>(&'a u32);
     impl<'a> Foo<'a> {
@@ -400,3 +417,57 @@ fn _closure_with_types() {
     let _ = f2(|x: u32| f(x));
     let _ = f2(|x| -> u32 { f(x) });
 }
+
+/// https://github.com/rust-lang/rust-clippy/issues/10854
+/// This is to verify that redundant_closure_for_method_calls resolves suggested paths to relative.
+mod issue_10854 {
+    pub mod test_mod {
+        pub struct Test;
+
+        impl Test {
+            pub fn method(self) -> i32 {
+                0
+            }
+        }
+
+        pub fn calls_test(test: Option<Test>) -> Option<i32> {
+            test.map(Test::method)
+        }
+
+        pub fn calls_outer(test: Option<super::Outer>) -> Option<i32> {
+            test.map(super::Outer::method)
+        }
+    }
+
+    pub struct Outer;
+
+    impl Outer {
+        pub fn method(self) -> i32 {
+            0
+        }
+    }
+
+    pub fn calls_into_mod(test: Option<test_mod::Test>) -> Option<i32> {
+        test.map(test_mod::Test::method)
+    }
+
+    mod a {
+        pub mod b {
+            pub mod c {
+                pub fn extreme_nesting(test: Option<super::super::super::d::Test>) -> Option<i32> {
+                    test.map(crate::issue_10854::d::Test::method)
+                }
+            }
+        }
+    }
+
+    mod d {
+        pub struct Test;
+
+        impl Test {
+            pub fn method(self) -> i32 {
+                0
+            }
+        }
+    }
+}
diff --git a/src/tools/clippy/tests/ui/eta.rs b/src/tools/clippy/tests/ui/eta.rs
index 25b7431ba8c..f924100f8f4 100644
--- a/src/tools/clippy/tests/ui/eta.rs
+++ b/src/tools/clippy/tests/ui/eta.rs
@@ -346,6 +346,23 @@ fn angle_brackets_and_args() {
     dyn_opt.map(|d| d.method_on_dyn());
 }
 
+// https://github.com/rust-lang/rust-clippy/issues/12199
+fn track_caller_fp() {
+    struct S;
+    impl S {
+        #[track_caller]
+        fn add_location(self) {}
+    }
+
+    #[track_caller]
+    fn add_location() {}
+
+    fn foo(_: fn()) {}
+    fn foo2(_: fn(S)) {}
+    foo(|| add_location());
+    foo2(|s| s.add_location());
+}
+
 fn _late_bound_to_early_bound_regions() {
     struct Foo<'a>(&'a u32);
     impl<'a> Foo<'a> {
@@ -400,3 +417,57 @@ fn _closure_with_types() {
     let _ = f2(|x: u32| f(x));
     let _ = f2(|x| -> u32 { f(x) });
 }
+
+/// https://github.com/rust-lang/rust-clippy/issues/10854
+/// This is to verify that redundant_closure_for_method_calls resolves suggested paths to relative.
+mod issue_10854 {
+    pub mod test_mod {
+        pub struct Test;
+
+        impl Test {
+            pub fn method(self) -> i32 {
+                0
+            }
+        }
+
+        pub fn calls_test(test: Option<Test>) -> Option<i32> {
+            test.map(|t| t.method())
+        }
+
+        pub fn calls_outer(test: Option<super::Outer>) -> Option<i32> {
+            test.map(|t| t.method())
+        }
+    }
+
+    pub struct Outer;
+
+    impl Outer {
+        pub fn method(self) -> i32 {
+            0
+        }
+    }
+
+    pub fn calls_into_mod(test: Option<test_mod::Test>) -> Option<i32> {
+        test.map(|t| t.method())
+    }
+
+    mod a {
+        pub mod b {
+            pub mod c {
+                pub fn extreme_nesting(test: Option<super::super::super::d::Test>) -> Option<i32> {
+                    test.map(|t| t.method())
+                }
+            }
+        }
+    }
+
+    mod d {
+        pub struct Test;
+
+        impl Test {
+            pub fn method(self) -> i32 {
+                0
+            }
+        }
+    }
+}
diff --git a/src/tools/clippy/tests/ui/eta.stderr b/src/tools/clippy/tests/ui/eta.stderr
index 951e4ac749c..945de466d83 100644
--- a/src/tools/clippy/tests/ui/eta.stderr
+++ b/src/tools/clippy/tests/ui/eta.stderr
@@ -161,10 +161,34 @@ LL |     dyn_opt.map(|d| d.method_on_dyn());
    |                 ^^^^^^^^^^^^^^^^^^^^^ help: replace the closure with the method itself: `<dyn TestTrait>::method_on_dyn`
 
 error: redundant closure
-  --> $DIR/eta.rs:389:19
+  --> $DIR/eta.rs:406:19
    |
 LL |     let _ = f(&0, |x, y| f2(x, y));
    |                   ^^^^^^^^^^^^^^^ help: replace the closure with the function itself: `f2`
 
-error: aborting due to 27 previous errors
+error: redundant closure
+  --> $DIR/eta.rs:434:22
+   |
+LL |             test.map(|t| t.method())
+   |                      ^^^^^^^^^^^^^^ help: replace the closure with the method itself: `Test::method`
+
+error: redundant closure
+  --> $DIR/eta.rs:438:22
+   |
+LL |             test.map(|t| t.method())
+   |                      ^^^^^^^^^^^^^^ help: replace the closure with the method itself: `super::Outer::method`
+
+error: redundant closure
+  --> $DIR/eta.rs:451:18
+   |
+LL |         test.map(|t| t.method())
+   |                  ^^^^^^^^^^^^^^ help: replace the closure with the method itself: `test_mod::Test::method`
+
+error: redundant closure
+  --> $DIR/eta.rs:458:30
+   |
+LL |                     test.map(|t| t.method())
+   |                              ^^^^^^^^^^^^^^ help: replace the closure with the method itself: `crate::issue_10854::d::Test::method`
+
+error: aborting due to 31 previous errors
 
diff --git a/src/tools/clippy/tests/ui/format_args.fixed b/src/tools/clippy/tests/ui/format_args.fixed
index ddd5976c408..cab20b11e07 100644
--- a/src/tools/clippy/tests/ui/format_args.fixed
+++ b/src/tools/clippy/tests/ui/format_args.fixed
@@ -14,6 +14,7 @@ use std::panic::Location;
 
 struct Somewhere;
 
+#[allow(clippy::to_string_trait_impl)]
 impl ToString for Somewhere {
     fn to_string(&self) -> String {
         String::from("somewhere")
diff --git a/src/tools/clippy/tests/ui/format_args.rs b/src/tools/clippy/tests/ui/format_args.rs
index 18e1bc1af67..bc3645cb2c2 100644
--- a/src/tools/clippy/tests/ui/format_args.rs
+++ b/src/tools/clippy/tests/ui/format_args.rs
@@ -14,6 +14,7 @@ use std::panic::Location;
 
 struct Somewhere;
 
+#[allow(clippy::to_string_trait_impl)]
 impl ToString for Somewhere {
     fn to_string(&self) -> String {
         String::from("somewhere")
diff --git a/src/tools/clippy/tests/ui/format_args.stderr b/src/tools/clippy/tests/ui/format_args.stderr
index dcdfa668aff..2f1714296d6 100644
--- a/src/tools/clippy/tests/ui/format_args.stderr
+++ b/src/tools/clippy/tests/ui/format_args.stderr
@@ -1,5 +1,5 @@
 error: `to_string` applied to a type that implements `Display` in `format!` args
-  --> $DIR/format_args.rs:76:72
+  --> $DIR/format_args.rs:77:72
    |
 LL |     let _ = format!("error: something failed at {}", Location::caller().to_string());
    |                                                                        ^^^^^^^^^^^^ help: remove this
@@ -8,145 +8,145 @@ LL |     let _ = format!("error: something failed at {}", Location::caller().to_
    = help: to override `-D warnings` add `#[allow(clippy::to_string_in_format_args)]`
 
 error: `to_string` applied to a type that implements `Display` in `write!` args
-  --> $DIR/format_args.rs:80:27
+  --> $DIR/format_args.rs:81:27
    |
 LL |         Location::caller().to_string()
    |                           ^^^^^^^^^^^^ help: remove this
 
 error: `to_string` applied to a type that implements `Display` in `writeln!` args
-  --> $DIR/format_args.rs:85:27
+  --> $DIR/format_args.rs:86:27
    |
 LL |         Location::caller().to_string()
    |                           ^^^^^^^^^^^^ help: remove this
 
 error: `to_string` applied to a type that implements `Display` in `print!` args
-  --> $DIR/format_args.rs:87:63
+  --> $DIR/format_args.rs:88:63
    |
 LL |     print!("error: something failed at {}", Location::caller().to_string());
    |                                                               ^^^^^^^^^^^^ help: remove this
 
 error: `to_string` applied to a type that implements `Display` in `println!` args
-  --> $DIR/format_args.rs:88:65
+  --> $DIR/format_args.rs:89:65
    |
 LL |     println!("error: something failed at {}", Location::caller().to_string());
    |                                                                 ^^^^^^^^^^^^ help: remove this
 
 error: `to_string` applied to a type that implements `Display` in `eprint!` args
-  --> $DIR/format_args.rs:89:64
+  --> $DIR/format_args.rs:90:64
    |
 LL |     eprint!("error: something failed at {}", Location::caller().to_string());
    |                                                                ^^^^^^^^^^^^ help: remove this
 
 error: `to_string` applied to a type that implements `Display` in `eprintln!` args
-  --> $DIR/format_args.rs:90:66
+  --> $DIR/format_args.rs:91:66
    |
 LL |     eprintln!("error: something failed at {}", Location::caller().to_string());
    |                                                                  ^^^^^^^^^^^^ help: remove this
 
 error: `to_string` applied to a type that implements `Display` in `format_args!` args
-  --> $DIR/format_args.rs:91:77
+  --> $DIR/format_args.rs:92:77
    |
 LL |     let _ = format_args!("error: something failed at {}", Location::caller().to_string());
    |                                                                             ^^^^^^^^^^^^ help: remove this
 
 error: `to_string` applied to a type that implements `Display` in `assert!` args
-  --> $DIR/format_args.rs:92:70
+  --> $DIR/format_args.rs:93:70
    |
 LL |     assert!(true, "error: something failed at {}", Location::caller().to_string());
    |                                                                      ^^^^^^^^^^^^ help: remove this
 
 error: `to_string` applied to a type that implements `Display` in `assert_eq!` args
-  --> $DIR/format_args.rs:93:73
+  --> $DIR/format_args.rs:94:73
    |
 LL |     assert_eq!(0, 0, "error: something failed at {}", Location::caller().to_string());
    |                                                                         ^^^^^^^^^^^^ help: remove this
 
 error: `to_string` applied to a type that implements `Display` in `assert_ne!` args
-  --> $DIR/format_args.rs:94:73
+  --> $DIR/format_args.rs:95:73
    |
 LL |     assert_ne!(0, 0, "error: something failed at {}", Location::caller().to_string());
    |                                                                         ^^^^^^^^^^^^ help: remove this
 
 error: `to_string` applied to a type that implements `Display` in `panic!` args
-  --> $DIR/format_args.rs:95:63
+  --> $DIR/format_args.rs:96:63
    |
 LL |     panic!("error: something failed at {}", Location::caller().to_string());
    |                                                               ^^^^^^^^^^^^ help: remove this
 
 error: `to_string` applied to a type that implements `Display` in `println!` args
-  --> $DIR/format_args.rs:96:20
+  --> $DIR/format_args.rs:97:20
    |
 LL |     println!("{}", X(1).to_string());
    |                    ^^^^^^^^^^^^^^^^ help: use this: `*X(1)`
 
 error: `to_string` applied to a type that implements `Display` in `println!` args
-  --> $DIR/format_args.rs:97:20
+  --> $DIR/format_args.rs:98:20
    |
 LL |     println!("{}", Y(&X(1)).to_string());
    |                    ^^^^^^^^^^^^^^^^^^^^ help: use this: `***Y(&X(1))`
 
 error: `to_string` applied to a type that implements `Display` in `println!` args
-  --> $DIR/format_args.rs:98:24
+  --> $DIR/format_args.rs:99:24
    |
 LL |     println!("{}", Z(1).to_string());
    |                        ^^^^^^^^^^^^ help: remove this
 
 error: `to_string` applied to a type that implements `Display` in `println!` args
-  --> $DIR/format_args.rs:99:20
+  --> $DIR/format_args.rs:100:20
    |
 LL |     println!("{}", x.to_string());
    |                    ^^^^^^^^^^^^^ help: use this: `**x`
 
 error: `to_string` applied to a type that implements `Display` in `println!` args
-  --> $DIR/format_args.rs:100:20
+  --> $DIR/format_args.rs:101:20
    |
 LL |     println!("{}", x_ref.to_string());
    |                    ^^^^^^^^^^^^^^^^^ help: use this: `***x_ref`
 
 error: `to_string` applied to a type that implements `Display` in `println!` args
-  --> $DIR/format_args.rs:102:39
+  --> $DIR/format_args.rs:103:39
    |
 LL |     println!("{foo}{bar}", foo = "foo".to_string(), bar = "bar");
    |                                       ^^^^^^^^^^^^ help: remove this
 
 error: `to_string` applied to a type that implements `Display` in `println!` args
-  --> $DIR/format_args.rs:103:52
+  --> $DIR/format_args.rs:104:52
    |
 LL |     println!("{foo}{bar}", foo = "foo", bar = "bar".to_string());
    |                                                    ^^^^^^^^^^^^ help: remove this
 
 error: `to_string` applied to a type that implements `Display` in `println!` args
-  --> $DIR/format_args.rs:104:39
+  --> $DIR/format_args.rs:105:39
    |
 LL |     println!("{foo}{bar}", bar = "bar".to_string(), foo = "foo");
    |                                       ^^^^^^^^^^^^ help: remove this
 
 error: `to_string` applied to a type that implements `Display` in `println!` args
-  --> $DIR/format_args.rs:105:52
+  --> $DIR/format_args.rs:106:52
    |
 LL |     println!("{foo}{bar}", bar = "bar", foo = "foo".to_string());
    |                                                    ^^^^^^^^^^^^ help: remove this
 
 error: `to_string` applied to a type that implements `Display` in `print!` args
-  --> $DIR/format_args.rs:117:37
+  --> $DIR/format_args.rs:118:37
    |
 LL |     print!("{}", (Location::caller().to_string()));
    |                                     ^^^^^^^^^^^^ help: remove this
 
 error: `to_string` applied to a type that implements `Display` in `print!` args
-  --> $DIR/format_args.rs:118:39
+  --> $DIR/format_args.rs:119:39
    |
 LL |     print!("{}", ((Location::caller()).to_string()));
    |                                       ^^^^^^^^^^^^ help: remove this
 
 error: `to_string` applied to a type that implements `Display` in `format!` args
-  --> $DIR/format_args.rs:146:38
+  --> $DIR/format_args.rs:147:38
    |
 LL |         let x = format!("{} {}", a, b.to_string());
    |                                      ^^^^^^^^^^^^ help: remove this
 
 error: `to_string` applied to a type that implements `Display` in `println!` args
-  --> $DIR/format_args.rs:160:24
+  --> $DIR/format_args.rs:161:24
    |
 LL |         println!("{}", original[..10].to_string());
    |                        ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use this: `&original[..10]`
diff --git a/src/tools/clippy/tests/ui/ignored_unit_patterns.fixed b/src/tools/clippy/tests/ui/ignored_unit_patterns.fixed
index 707a0e76e4e..118f0b48895 100644
--- a/src/tools/clippy/tests/ui/ignored_unit_patterns.fixed
+++ b/src/tools/clippy/tests/ui/ignored_unit_patterns.fixed
@@ -1,6 +1,11 @@
 //@aux-build:proc_macro_derive.rs
 #![warn(clippy::ignored_unit_patterns)]
-#![allow(clippy::let_unit_value, clippy::redundant_pattern_matching, clippy::single_match)]
+#![allow(
+    clippy::let_unit_value,
+    clippy::redundant_pattern_matching,
+    clippy::single_match,
+    clippy::needless_borrow
+)]
 
 fn foo() -> Result<(), ()> {
     unimplemented!()
diff --git a/src/tools/clippy/tests/ui/ignored_unit_patterns.rs b/src/tools/clippy/tests/ui/ignored_unit_patterns.rs
index 544f2b8f692..92feb9e6c28 100644
--- a/src/tools/clippy/tests/ui/ignored_unit_patterns.rs
+++ b/src/tools/clippy/tests/ui/ignored_unit_patterns.rs
@@ -1,6 +1,11 @@
 //@aux-build:proc_macro_derive.rs
 #![warn(clippy::ignored_unit_patterns)]
-#![allow(clippy::let_unit_value, clippy::redundant_pattern_matching, clippy::single_match)]
+#![allow(
+    clippy::let_unit_value,
+    clippy::redundant_pattern_matching,
+    clippy::single_match,
+    clippy::needless_borrow
+)]
 
 fn foo() -> Result<(), ()> {
     unimplemented!()
diff --git a/src/tools/clippy/tests/ui/ignored_unit_patterns.stderr b/src/tools/clippy/tests/ui/ignored_unit_patterns.stderr
index 05c8f281e55..18ca7ebbcf2 100644
--- a/src/tools/clippy/tests/ui/ignored_unit_patterns.stderr
+++ b/src/tools/clippy/tests/ui/ignored_unit_patterns.stderr
@@ -1,5 +1,5 @@
 error: matching over `()` is more explicit
-  --> $DIR/ignored_unit_patterns.rs:11:12
+  --> $DIR/ignored_unit_patterns.rs:16:12
    |
 LL |         Ok(_) => {},
    |            ^ help: use `()` instead of `_`: `()`
@@ -8,49 +8,49 @@ LL |         Ok(_) => {},
    = help: to override `-D warnings` add `#[allow(clippy::ignored_unit_patterns)]`
 
 error: matching over `()` is more explicit
-  --> $DIR/ignored_unit_patterns.rs:12:13
+  --> $DIR/ignored_unit_patterns.rs:17:13
    |
 LL |         Err(_) => {},
    |             ^ help: use `()` instead of `_`: `()`
 
 error: matching over `()` is more explicit
-  --> $DIR/ignored_unit_patterns.rs:14:15
+  --> $DIR/ignored_unit_patterns.rs:19:15
    |
 LL |     if let Ok(_) = foo() {}
    |               ^ help: use `()` instead of `_`: `()`
 
 error: matching over `()` is more explicit
-  --> $DIR/ignored_unit_patterns.rs:16:28
+  --> $DIR/ignored_unit_patterns.rs:21:28
    |
 LL |     let _ = foo().map_err(|_| todo!());
    |                            ^ help: use `()` instead of `_`: `()`
 
 error: matching over `()` is more explicit
-  --> $DIR/ignored_unit_patterns.rs:22:16
+  --> $DIR/ignored_unit_patterns.rs:27:16
    |
 LL |             Ok(_) => {},
    |                ^ help: use `()` instead of `_`: `()`
 
 error: matching over `()` is more explicit
-  --> $DIR/ignored_unit_patterns.rs:24:17
+  --> $DIR/ignored_unit_patterns.rs:29:17
    |
 LL |             Err(_) => {},
    |                 ^ help: use `()` instead of `_`: `()`
 
 error: matching over `()` is more explicit
-  --> $DIR/ignored_unit_patterns.rs:36:9
+  --> $DIR/ignored_unit_patterns.rs:41:9
    |
 LL |     let _ = foo().unwrap();
    |         ^ help: use `()` instead of `_`: `()`
 
 error: matching over `()` is more explicit
-  --> $DIR/ignored_unit_patterns.rs:45:13
+  --> $DIR/ignored_unit_patterns.rs:50:13
    |
 LL |         (1, _) => unimplemented!(),
    |             ^ help: use `()` instead of `_`: `()`
 
 error: matching over `()` is more explicit
-  --> $DIR/ignored_unit_patterns.rs:52:13
+  --> $DIR/ignored_unit_patterns.rs:57:13
    |
 LL |     for (x, _) in v {
    |             ^ help: use `()` instead of `_`: `()`
diff --git a/src/tools/clippy/tests/ui/incompatible_msrv.rs b/src/tools/clippy/tests/ui/incompatible_msrv.rs
new file mode 100644
index 00000000000..a92017fb0f6
--- /dev/null
+++ b/src/tools/clippy/tests/ui/incompatible_msrv.rs
@@ -0,0 +1,23 @@
+#![warn(clippy::incompatible_msrv)]
+#![feature(custom_inner_attributes)]
+#![clippy::msrv = "1.3.0"]
+
+use std::collections::hash_map::Entry;
+use std::collections::HashMap;
+use std::thread::sleep;
+use std::time::Duration;
+
+fn foo() {
+    let mut map: HashMap<&str, u32> = HashMap::new();
+    assert_eq!(map.entry("poneyland").key(), &"poneyland");
+    //~^ ERROR: is `1.3.0` but this item is stable since `1.10.0`
+    if let Entry::Vacant(v) = map.entry("poneyland") {
+        v.into_key();
+        //~^ ERROR: is `1.3.0` but this item is stable since `1.12.0`
+    }
+    // Should warn for `sleep` but not for `Duration` (which was added in `1.3.0`).
+    sleep(Duration::new(1, 0));
+    //~^ ERROR: is `1.3.0` but this item is stable since `1.4.0`
+}
+
+fn main() {}
diff --git a/src/tools/clippy/tests/ui/incompatible_msrv.stderr b/src/tools/clippy/tests/ui/incompatible_msrv.stderr
new file mode 100644
index 00000000000..bd5ecd6ed2f
--- /dev/null
+++ b/src/tools/clippy/tests/ui/incompatible_msrv.stderr
@@ -0,0 +1,23 @@
+error: current MSRV (Minimum Supported Rust Version) is `1.3.0` but this item is stable since `1.10.0`
+  --> $DIR/incompatible_msrv.rs:12:39
+   |
+LL |     assert_eq!(map.entry("poneyland").key(), &"poneyland");
+   |                                       ^^^^^
+   |
+   = note: `-D clippy::incompatible-msrv` implied by `-D warnings`
+   = help: to override `-D warnings` add `#[allow(clippy::incompatible_msrv)]`
+
+error: current MSRV (Minimum Supported Rust Version) is `1.3.0` but this item is stable since `1.12.0`
+  --> $DIR/incompatible_msrv.rs:15:11
+   |
+LL |         v.into_key();
+   |           ^^^^^^^^^^
+
+error: current MSRV (Minimum Supported Rust Version) is `1.3.0` but this item is stable since `1.4.0`
+  --> $DIR/incompatible_msrv.rs:19:5
+   |
+LL |     sleep(Duration::new(1, 0));
+   |     ^^^^^
+
+error: aborting due to 3 previous errors
+
diff --git a/src/tools/clippy/tests/ui/manual_c_str_literals.fixed b/src/tools/clippy/tests/ui/manual_c_str_literals.fixed
new file mode 100644
index 00000000000..a24d7088c88
--- /dev/null
+++ b/src/tools/clippy/tests/ui/manual_c_str_literals.fixed
@@ -0,0 +1,60 @@
+#![warn(clippy::manual_c_str_literals)]
+#![allow(clippy::no_effect)]
+
+use std::ffi::CStr;
+
+macro_rules! cstr {
+    ($s:literal) => {
+        CStr::from_bytes_with_nul(concat!($s, "\0").as_bytes()).unwrap()
+    };
+}
+
+macro_rules! macro_returns_c_str {
+    () => {
+        CStr::from_bytes_with_nul(b"foo\0").unwrap();
+    };
+}
+
+macro_rules! macro_returns_byte_string {
+    () => {
+        b"foo\0"
+    };
+}
+
+#[clippy::msrv = "1.76.0"]
+fn pre_stabilization() {
+    CStr::from_bytes_with_nul(b"foo\0");
+}
+
+#[clippy::msrv = "1.77.0"]
+fn post_stabilization() {
+    c"foo";
+}
+
+fn main() {
+    c"foo";
+    c"foo";
+    c"foo";
+    c"foo\\0sdsd";
+    CStr::from_bytes_with_nul(br"foo\\0sdsd\0").unwrap();
+    CStr::from_bytes_with_nul(br"foo\x00").unwrap();
+    CStr::from_bytes_with_nul(br##"foo#a\0"##).unwrap();
+
+    unsafe { c"foo" };
+    unsafe { c"foo" };
+    let _: *const _ = c"foo".as_ptr();
+    let _: *const _ = c"foo".as_ptr();
+    let _: *const _ = "foo".as_ptr(); // not a C-string
+    let _: *const _ = "".as_ptr();
+    let _: *const _ = c"foo".as_ptr().cast::<i8>();
+    let _ = "电脑".as_ptr();
+    let _ = "电脑\\".as_ptr();
+    let _ = c"电脑\\".as_ptr();
+    let _ = c"电脑".as_ptr();
+    let _ = c"电脑".as_ptr();
+
+    // Macro cases, don't lint:
+    cstr!("foo");
+    macro_returns_c_str!();
+    CStr::from_bytes_with_nul(macro_returns_byte_string!()).unwrap();
+}
diff --git a/src/tools/clippy/tests/ui/manual_c_str_literals.rs b/src/tools/clippy/tests/ui/manual_c_str_literals.rs
new file mode 100644
index 00000000000..0a007786720
--- /dev/null
+++ b/src/tools/clippy/tests/ui/manual_c_str_literals.rs
@@ -0,0 +1,60 @@
+#![warn(clippy::manual_c_str_literals)]
+#![allow(clippy::no_effect)]
+
+use std::ffi::CStr;
+
+macro_rules! cstr {
+    ($s:literal) => {
+        CStr::from_bytes_with_nul(concat!($s, "\0").as_bytes()).unwrap()
+    };
+}
+
+macro_rules! macro_returns_c_str {
+    () => {
+        CStr::from_bytes_with_nul(b"foo\0").unwrap();
+    };
+}
+
+macro_rules! macro_returns_byte_string {
+    () => {
+        b"foo\0"
+    };
+}
+
+#[clippy::msrv = "1.76.0"]
+fn pre_stabilization() {
+    CStr::from_bytes_with_nul(b"foo\0");
+}
+
+#[clippy::msrv = "1.77.0"]
+fn post_stabilization() {
+    CStr::from_bytes_with_nul(b"foo\0");
+}
+
+fn main() {
+    CStr::from_bytes_with_nul(b"foo\0");
+    CStr::from_bytes_with_nul(b"foo\x00");
+    CStr::from_bytes_with_nul(b"foo\0").unwrap();
+    CStr::from_bytes_with_nul(b"foo\\0sdsd\0").unwrap();
+    CStr::from_bytes_with_nul(br"foo\\0sdsd\0").unwrap();
+    CStr::from_bytes_with_nul(br"foo\x00").unwrap();
+    CStr::from_bytes_with_nul(br##"foo#a\0"##).unwrap();
+
+    unsafe { CStr::from_ptr(b"foo\0".as_ptr().cast()) };
+    unsafe { CStr::from_ptr(b"foo\0".as_ptr() as *const _) };
+    let _: *const _ = b"foo\0".as_ptr();
+    let _: *const _ = "foo\0".as_ptr();
+    let _: *const _ = "foo".as_ptr(); // not a C-string
+    let _: *const _ = "".as_ptr();
+    let _: *const _ = b"foo\0".as_ptr().cast::<i8>();
+    let _ = "电脑".as_ptr();
+    let _ = "电脑\\".as_ptr();
+    let _ = "电脑\\\0".as_ptr();
+    let _ = "电脑\0".as_ptr();
+    let _ = "电脑\x00".as_ptr();
+
+    // Macro cases, don't lint:
+    cstr!("foo");
+    macro_returns_c_str!();
+    CStr::from_bytes_with_nul(macro_returns_byte_string!()).unwrap();
+}
diff --git a/src/tools/clippy/tests/ui/manual_c_str_literals.stderr b/src/tools/clippy/tests/ui/manual_c_str_literals.stderr
new file mode 100644
index 00000000000..8de4e16f010
--- /dev/null
+++ b/src/tools/clippy/tests/ui/manual_c_str_literals.stderr
@@ -0,0 +1,83 @@
+error: calling `CStr::new` with a byte string literal
+  --> $DIR/manual_c_str_literals.rs:31:5
+   |
+LL |     CStr::from_bytes_with_nul(b"foo\0");
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use a `c""` literal: `c"foo"`
+   |
+   = note: `-D clippy::manual-c-str-literals` implied by `-D warnings`
+   = help: to override `-D warnings` add `#[allow(clippy::manual_c_str_literals)]`
+
+error: calling `CStr::new` with a byte string literal
+  --> $DIR/manual_c_str_literals.rs:35:5
+   |
+LL |     CStr::from_bytes_with_nul(b"foo\0");
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use a `c""` literal: `c"foo"`
+
+error: calling `CStr::new` with a byte string literal
+  --> $DIR/manual_c_str_literals.rs:36:5
+   |
+LL |     CStr::from_bytes_with_nul(b"foo\x00");
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use a `c""` literal: `c"foo"`
+
+error: calling `CStr::new` with a byte string literal
+  --> $DIR/manual_c_str_literals.rs:37:5
+   |
+LL |     CStr::from_bytes_with_nul(b"foo\0").unwrap();
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use a `c""` literal: `c"foo"`
+
+error: calling `CStr::new` with a byte string literal
+  --> $DIR/manual_c_str_literals.rs:38:5
+   |
+LL |     CStr::from_bytes_with_nul(b"foo\\0sdsd\0").unwrap();
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use a `c""` literal: `c"foo\\0sdsd"`
+
+error: calling `CStr::from_ptr` with a byte string literal
+  --> $DIR/manual_c_str_literals.rs:43:14
+   |
+LL |     unsafe { CStr::from_ptr(b"foo\0".as_ptr().cast()) };
+   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use a `c""` literal: `c"foo"`
+
+error: calling `CStr::from_ptr` with a byte string literal
+  --> $DIR/manual_c_str_literals.rs:44:14
+   |
+LL |     unsafe { CStr::from_ptr(b"foo\0".as_ptr() as *const _) };
+   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use a `c""` literal: `c"foo"`
+
+error: manually constructing a nul-terminated string
+  --> $DIR/manual_c_str_literals.rs:45:23
+   |
+LL |     let _: *const _ = b"foo\0".as_ptr();
+   |                       ^^^^^^^^ help: use a `c""` literal: `c"foo"`
+
+error: manually constructing a nul-terminated string
+  --> $DIR/manual_c_str_literals.rs:46:23
+   |
+LL |     let _: *const _ = "foo\0".as_ptr();
+   |                       ^^^^^^^ help: use a `c""` literal: `c"foo"`
+
+error: manually constructing a nul-terminated string
+  --> $DIR/manual_c_str_literals.rs:49:23
+   |
+LL |     let _: *const _ = b"foo\0".as_ptr().cast::<i8>();
+   |                       ^^^^^^^^ help: use a `c""` literal: `c"foo"`
+
+error: manually constructing a nul-terminated string
+  --> $DIR/manual_c_str_literals.rs:52:13
+   |
+LL |     let _ = "电脑\\\0".as_ptr();
+   |             ^^^^^^^^^^ help: use a `c""` literal: `c"电脑\\"`
+
+error: manually constructing a nul-terminated string
+  --> $DIR/manual_c_str_literals.rs:53:13
+   |
+LL |     let _ = "电脑\0".as_ptr();
+   |             ^^^^^^^^ help: use a `c""` literal: `c"电脑"`
+
+error: manually constructing a nul-terminated string
+  --> $DIR/manual_c_str_literals.rs:54:13
+   |
+LL |     let _ = "电脑\x00".as_ptr();
+   |             ^^^^^^^^^^ help: use a `c""` literal: `c"电脑"`
+
+error: aborting due to 13 previous errors
+
diff --git a/src/tools/clippy/tests/ui/manual_retain.fixed b/src/tools/clippy/tests/ui/manual_retain.fixed
index 4dea3e8bfe6..5540029bf6b 100644
--- a/src/tools/clippy/tests/ui/manual_retain.fixed
+++ b/src/tools/clippy/tests/ui/manual_retain.fixed
@@ -14,6 +14,9 @@ fn main() {
     _msrv_153();
     _msrv_126();
     _msrv_118();
+
+    issue_10393();
+    issue_12081();
 }
 
 fn binary_heap_retain() {
@@ -23,6 +26,11 @@ fn binary_heap_retain() {
     binary_heap.retain(|x| x % 2 == 0);
     binary_heap.retain(|x| x % 2 == 0);
 
+    // Do lint, because we use pattern matching
+    let mut tuples = BinaryHeap::from([(0, 1), (1, 2), (2, 3)]);
+    tuples.retain(|(ref x, ref y)| *x == 0);
+    tuples.retain(|(x, y)| *x == 0);
+
     // Do not lint, because type conversion is performed
     binary_heap = binary_heap
         .into_iter()
@@ -55,6 +63,9 @@ fn btree_map_retain() {
     btree_map.retain(|_, &mut v| v % 2 == 0);
     btree_map.retain(|k, &mut v| (k % 2 == 0) && (v % 2 == 0));
 
+    // Do not lint, because the parameters are not matched in tuple pattern
+    btree_map = btree_map.into_iter().filter(|t| t.0 % 2 == 0).collect();
+
     // Do not lint.
     btree_map = btree_map
         .into_iter()
@@ -76,6 +87,11 @@ fn btree_set_retain() {
     btree_set.retain(|x| x % 2 == 0);
     btree_set.retain(|x| x % 2 == 0);
 
+    // Do lint, because we use pattern matching
+    let mut tuples = BTreeSet::from([(0, 1), (1, 2), (2, 3)]);
+    tuples.retain(|(ref x, ref y)| *x == 0);
+    tuples.retain(|(x, y)| *x == 0);
+
     // Do not lint, because type conversion is performed
     btree_set = btree_set
         .iter()
@@ -108,6 +124,9 @@ fn hash_map_retain() {
     hash_map.retain(|_, &mut v| v % 2 == 0);
     hash_map.retain(|k, &mut v| (k % 2 == 0) && (v % 2 == 0));
 
+    // Do not lint, because the parameters are not matched in tuple pattern
+    hash_map = hash_map.into_iter().filter(|t| t.0 % 2 == 0).collect();
+
     // Do not lint.
     hash_map = hash_map
         .into_iter()
@@ -128,6 +147,11 @@ fn hash_set_retain() {
     hash_set.retain(|x| x % 2 == 0);
     hash_set.retain(|x| x % 2 == 0);
 
+    // Do lint, because we use pattern matching
+    let mut tuples = HashSet::from([(0, 1), (1, 2), (2, 3)]);
+    tuples.retain(|(ref x, ref y)| *x == 0);
+    tuples.retain(|(x, y)| *x == 0);
+
     // Do not lint, because type conversion is performed
     hash_set = hash_set.into_iter().filter(|x| x % 2 == 0).collect::<HashSet<i8>>();
     hash_set = hash_set
@@ -171,6 +195,11 @@ fn vec_retain() {
     vec.retain(|x| x % 2 == 0);
     vec.retain(|x| x % 2 == 0);
 
+    // Do lint, because we use pattern matching
+    let mut tuples = vec![(0, 1), (1, 2), (2, 3)];
+    tuples.retain(|(ref x, ref y)| *x == 0);
+    tuples.retain(|(x, y)| *x == 0);
+
     // Do not lint, because type conversion is performed
     vec = vec.into_iter().filter(|x| x % 2 == 0).collect::<Vec<i8>>();
     vec = vec.iter().filter(|&x| x % 2 == 0).copied().collect::<Vec<i8>>();
@@ -246,3 +275,37 @@ fn _msrv_118() {
     let mut hash_map: HashMap<i8, i8> = (0..8).map(|x| (x, x * 10)).collect();
     hash_map = hash_map.into_iter().filter(|(k, _)| k % 2 == 0).collect();
 }
+
+fn issue_10393() {
+    // Do lint
+    let mut vec = vec![(0, 1), (1, 2), (2, 3)];
+    vec.retain(|(x, y)| *x == 0);
+
+    // Do lint
+    let mut tuples = vec![(true, -2), (false, 3)];
+    tuples.retain(|(_, n)| *n > 0);
+}
+
+fn issue_11457() {
+    // Do not lint, as we need to modify the closure
+    let mut vals = vec![1, 2, 3, 4];
+    vals = vals.iter().filter(|v| **v != 1).cloned().collect();
+
+    // Do not lint, as we need to modify the closure
+    let mut s = String::from("foobar");
+    s = s.chars().filter(|c| *c != 'o').to_owned().collect();
+}
+
+fn issue_12081() {
+    let mut vec = vec![0, 1, 2];
+
+    // Do lint
+    vec.retain(|&x| x == 0);
+    vec.retain(|&x| x == 0);
+    vec.retain(|&x| x == 0);
+
+    // Do lint
+    vec.retain(|x| *x == 0);
+    vec.retain(|x| *x == 0);
+    vec.retain(|x| *x == 0);
+}
diff --git a/src/tools/clippy/tests/ui/manual_retain.rs b/src/tools/clippy/tests/ui/manual_retain.rs
index d839550f33a..cee641d9d65 100644
--- a/src/tools/clippy/tests/ui/manual_retain.rs
+++ b/src/tools/clippy/tests/ui/manual_retain.rs
@@ -14,6 +14,9 @@ fn main() {
     _msrv_153();
     _msrv_126();
     _msrv_118();
+
+    issue_10393();
+    issue_12081();
 }
 
 fn binary_heap_retain() {
@@ -23,6 +26,11 @@ fn binary_heap_retain() {
     binary_heap = binary_heap.iter().filter(|&x| x % 2 == 0).copied().collect();
     binary_heap = binary_heap.iter().filter(|&x| x % 2 == 0).cloned().collect();
 
+    // Do lint, because we use pattern matching
+    let mut tuples = BinaryHeap::from([(0, 1), (1, 2), (2, 3)]);
+    tuples = tuples.iter().filter(|(ref x, ref y)| *x == 0).copied().collect();
+    tuples = tuples.iter().filter(|(x, y)| *x == 0).copied().collect();
+
     // Do not lint, because type conversion is performed
     binary_heap = binary_heap
         .into_iter()
@@ -58,6 +66,9 @@ fn btree_map_retain() {
         .filter(|(k, v)| (k % 2 == 0) && (v % 2 == 0))
         .collect();
 
+    // Do not lint, because the parameters are not matched in tuple pattern
+    btree_map = btree_map.into_iter().filter(|t| t.0 % 2 == 0).collect();
+
     // Do not lint.
     btree_map = btree_map
         .into_iter()
@@ -79,6 +90,11 @@ fn btree_set_retain() {
     btree_set = btree_set.iter().filter(|&x| x % 2 == 0).cloned().collect();
     btree_set = btree_set.into_iter().filter(|x| x % 2 == 0).collect();
 
+    // Do lint, because we use pattern matching
+    let mut tuples = BTreeSet::from([(0, 1), (1, 2), (2, 3)]);
+    tuples = tuples.iter().filter(|(ref x, ref y)| *x == 0).copied().collect();
+    tuples = tuples.iter().filter(|(x, y)| *x == 0).copied().collect();
+
     // Do not lint, because type conversion is performed
     btree_set = btree_set
         .iter()
@@ -114,6 +130,9 @@ fn hash_map_retain() {
         .filter(|(k, v)| (k % 2 == 0) && (v % 2 == 0))
         .collect();
 
+    // Do not lint, because the parameters are not matched in tuple pattern
+    hash_map = hash_map.into_iter().filter(|t| t.0 % 2 == 0).collect();
+
     // Do not lint.
     hash_map = hash_map
         .into_iter()
@@ -134,6 +153,11 @@ fn hash_set_retain() {
     hash_set = hash_set.iter().filter(|&x| x % 2 == 0).copied().collect();
     hash_set = hash_set.iter().filter(|&x| x % 2 == 0).cloned().collect();
 
+    // Do lint, because we use pattern matching
+    let mut tuples = HashSet::from([(0, 1), (1, 2), (2, 3)]);
+    tuples = tuples.iter().filter(|(ref x, ref y)| *x == 0).copied().collect();
+    tuples = tuples.iter().filter(|(x, y)| *x == 0).copied().collect();
+
     // Do not lint, because type conversion is performed
     hash_set = hash_set.into_iter().filter(|x| x % 2 == 0).collect::<HashSet<i8>>();
     hash_set = hash_set
@@ -177,6 +201,11 @@ fn vec_retain() {
     vec = vec.iter().filter(|&x| x % 2 == 0).cloned().collect();
     vec = vec.into_iter().filter(|x| x % 2 == 0).collect();
 
+    // Do lint, because we use pattern matching
+    let mut tuples = vec![(0, 1), (1, 2), (2, 3)];
+    tuples = tuples.iter().filter(|(ref x, ref y)| *x == 0).copied().collect();
+    tuples = tuples.iter().filter(|(x, y)| *x == 0).copied().collect();
+
     // Do not lint, because type conversion is performed
     vec = vec.into_iter().filter(|x| x % 2 == 0).collect::<Vec<i8>>();
     vec = vec.iter().filter(|&x| x % 2 == 0).copied().collect::<Vec<i8>>();
@@ -252,3 +281,37 @@ fn _msrv_118() {
     let mut hash_map: HashMap<i8, i8> = (0..8).map(|x| (x, x * 10)).collect();
     hash_map = hash_map.into_iter().filter(|(k, _)| k % 2 == 0).collect();
 }
+
+fn issue_10393() {
+    // Do lint
+    let mut vec = vec![(0, 1), (1, 2), (2, 3)];
+    vec = vec.into_iter().filter(|(x, y)| *x == 0).collect();
+
+    // Do lint
+    let mut tuples = vec![(true, -2), (false, 3)];
+    tuples = tuples.into_iter().filter(|(_, n)| *n > 0).collect();
+}
+
+fn issue_11457() {
+    // Do not lint, as we need to modify the closure
+    let mut vals = vec![1, 2, 3, 4];
+    vals = vals.iter().filter(|v| **v != 1).cloned().collect();
+
+    // Do not lint, as we need to modify the closure
+    let mut s = String::from("foobar");
+    s = s.chars().filter(|c| *c != 'o').to_owned().collect();
+}
+
+fn issue_12081() {
+    let mut vec = vec![0, 1, 2];
+
+    // Do lint
+    vec = vec.iter().filter(|&&x| x == 0).copied().collect();
+    vec = vec.iter().filter(|&&x| x == 0).cloned().collect();
+    vec = vec.into_iter().filter(|&x| x == 0).collect();
+
+    // Do lint
+    vec = vec.iter().filter(|&x| *x == 0).copied().collect();
+    vec = vec.iter().filter(|&x| *x == 0).cloned().collect();
+    vec = vec.into_iter().filter(|x| *x == 0).collect();
+}
diff --git a/src/tools/clippy/tests/ui/manual_retain.stderr b/src/tools/clippy/tests/ui/manual_retain.stderr
index 0c5b1383b6a..2c872f3b430 100644
--- a/src/tools/clippy/tests/ui/manual_retain.stderr
+++ b/src/tools/clippy/tests/ui/manual_retain.stderr
@@ -1,5 +1,5 @@
 error: this expression can be written more simply using `.retain()`
-  --> $DIR/manual_retain.rs:22:5
+  --> $DIR/manual_retain.rs:25:5
    |
 LL |     binary_heap = binary_heap.into_iter().filter(|x| x % 2 == 0).collect();
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider calling `.retain()` instead: `binary_heap.retain(|x| x % 2 == 0)`
@@ -8,31 +8,43 @@ LL |     binary_heap = binary_heap.into_iter().filter(|x| x % 2 == 0).collect();
    = help: to override `-D warnings` add `#[allow(clippy::manual_retain)]`
 
 error: this expression can be written more simply using `.retain()`
-  --> $DIR/manual_retain.rs:23:5
+  --> $DIR/manual_retain.rs:26:5
    |
 LL |     binary_heap = binary_heap.iter().filter(|&x| x % 2 == 0).copied().collect();
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider calling `.retain()` instead: `binary_heap.retain(|x| x % 2 == 0)`
 
 error: this expression can be written more simply using `.retain()`
-  --> $DIR/manual_retain.rs:24:5
+  --> $DIR/manual_retain.rs:27:5
    |
 LL |     binary_heap = binary_heap.iter().filter(|&x| x % 2 == 0).cloned().collect();
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider calling `.retain()` instead: `binary_heap.retain(|x| x % 2 == 0)`
 
 error: this expression can be written more simply using `.retain()`
-  --> $DIR/manual_retain.rs:54:5
+  --> $DIR/manual_retain.rs:31:5
+   |
+LL |     tuples = tuples.iter().filter(|(ref x, ref y)| *x == 0).copied().collect();
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider calling `.retain()` instead: `tuples.retain(|(ref x, ref y)| *x == 0)`
+
+error: this expression can be written more simply using `.retain()`
+  --> $DIR/manual_retain.rs:32:5
+   |
+LL |     tuples = tuples.iter().filter(|(x, y)| *x == 0).copied().collect();
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider calling `.retain()` instead: `tuples.retain(|(x, y)| *x == 0)`
+
+error: this expression can be written more simply using `.retain()`
+  --> $DIR/manual_retain.rs:62:5
    |
 LL |     btree_map = btree_map.into_iter().filter(|(k, _)| k % 2 == 0).collect();
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider calling `.retain()` instead: `btree_map.retain(|k, _| k % 2 == 0)`
 
 error: this expression can be written more simply using `.retain()`
-  --> $DIR/manual_retain.rs:55:5
+  --> $DIR/manual_retain.rs:63:5
    |
 LL |     btree_map = btree_map.into_iter().filter(|(_, v)| v % 2 == 0).collect();
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider calling `.retain()` instead: `btree_map.retain(|_, &mut v| v % 2 == 0)`
 
 error: this expression can be written more simply using `.retain()`
-  --> $DIR/manual_retain.rs:56:5
+  --> $DIR/manual_retain.rs:64:5
    |
 LL | /     btree_map = btree_map
 LL | |         .into_iter()
@@ -41,37 +53,49 @@ LL | |         .collect();
    | |__________________^ help: consider calling `.retain()` instead: `btree_map.retain(|k, &mut v| (k % 2 == 0) && (v % 2 == 0))`
 
 error: this expression can be written more simply using `.retain()`
-  --> $DIR/manual_retain.rs:78:5
+  --> $DIR/manual_retain.rs:89:5
    |
 LL |     btree_set = btree_set.iter().filter(|&x| x % 2 == 0).copied().collect();
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider calling `.retain()` instead: `btree_set.retain(|x| x % 2 == 0)`
 
 error: this expression can be written more simply using `.retain()`
-  --> $DIR/manual_retain.rs:79:5
+  --> $DIR/manual_retain.rs:90:5
    |
 LL |     btree_set = btree_set.iter().filter(|&x| x % 2 == 0).cloned().collect();
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider calling `.retain()` instead: `btree_set.retain(|x| x % 2 == 0)`
 
 error: this expression can be written more simply using `.retain()`
-  --> $DIR/manual_retain.rs:80:5
+  --> $DIR/manual_retain.rs:91:5
    |
 LL |     btree_set = btree_set.into_iter().filter(|x| x % 2 == 0).collect();
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider calling `.retain()` instead: `btree_set.retain(|x| x % 2 == 0)`
 
 error: this expression can be written more simply using `.retain()`
-  --> $DIR/manual_retain.rs:110:5
+  --> $DIR/manual_retain.rs:95:5
+   |
+LL |     tuples = tuples.iter().filter(|(ref x, ref y)| *x == 0).copied().collect();
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider calling `.retain()` instead: `tuples.retain(|(ref x, ref y)| *x == 0)`
+
+error: this expression can be written more simply using `.retain()`
+  --> $DIR/manual_retain.rs:96:5
+   |
+LL |     tuples = tuples.iter().filter(|(x, y)| *x == 0).copied().collect();
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider calling `.retain()` instead: `tuples.retain(|(x, y)| *x == 0)`
+
+error: this expression can be written more simply using `.retain()`
+  --> $DIR/manual_retain.rs:126:5
    |
 LL |     hash_map = hash_map.into_iter().filter(|(k, _)| k % 2 == 0).collect();
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider calling `.retain()` instead: `hash_map.retain(|k, _| k % 2 == 0)`
 
 error: this expression can be written more simply using `.retain()`
-  --> $DIR/manual_retain.rs:111:5
+  --> $DIR/manual_retain.rs:127:5
    |
 LL |     hash_map = hash_map.into_iter().filter(|(_, v)| v % 2 == 0).collect();
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider calling `.retain()` instead: `hash_map.retain(|_, &mut v| v % 2 == 0)`
 
 error: this expression can be written more simply using `.retain()`
-  --> $DIR/manual_retain.rs:112:5
+  --> $DIR/manual_retain.rs:128:5
    |
 LL | /     hash_map = hash_map
 LL | |         .into_iter()
@@ -80,64 +104,136 @@ LL | |         .collect();
    | |__________________^ help: consider calling `.retain()` instead: `hash_map.retain(|k, &mut v| (k % 2 == 0) && (v % 2 == 0))`
 
 error: this expression can be written more simply using `.retain()`
-  --> $DIR/manual_retain.rs:133:5
+  --> $DIR/manual_retain.rs:152:5
    |
 LL |     hash_set = hash_set.into_iter().filter(|x| x % 2 == 0).collect();
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider calling `.retain()` instead: `hash_set.retain(|x| x % 2 == 0)`
 
 error: this expression can be written more simply using `.retain()`
-  --> $DIR/manual_retain.rs:134:5
+  --> $DIR/manual_retain.rs:153:5
    |
 LL |     hash_set = hash_set.iter().filter(|&x| x % 2 == 0).copied().collect();
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider calling `.retain()` instead: `hash_set.retain(|x| x % 2 == 0)`
 
 error: this expression can be written more simply using `.retain()`
-  --> $DIR/manual_retain.rs:135:5
+  --> $DIR/manual_retain.rs:154:5
    |
 LL |     hash_set = hash_set.iter().filter(|&x| x % 2 == 0).cloned().collect();
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider calling `.retain()` instead: `hash_set.retain(|x| x % 2 == 0)`
 
 error: this expression can be written more simply using `.retain()`
-  --> $DIR/manual_retain.rs:164:5
+  --> $DIR/manual_retain.rs:158:5
+   |
+LL |     tuples = tuples.iter().filter(|(ref x, ref y)| *x == 0).copied().collect();
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider calling `.retain()` instead: `tuples.retain(|(ref x, ref y)| *x == 0)`
+
+error: this expression can be written more simply using `.retain()`
+  --> $DIR/manual_retain.rs:159:5
+   |
+LL |     tuples = tuples.iter().filter(|(x, y)| *x == 0).copied().collect();
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider calling `.retain()` instead: `tuples.retain(|(x, y)| *x == 0)`
+
+error: this expression can be written more simply using `.retain()`
+  --> $DIR/manual_retain.rs:188:5
    |
 LL |     s = s.chars().filter(|&c| c != 'o').to_owned().collect();
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider calling `.retain()` instead: `s.retain(|c| c != 'o')`
 
 error: this expression can be written more simply using `.retain()`
-  --> $DIR/manual_retain.rs:176:5
+  --> $DIR/manual_retain.rs:200:5
    |
 LL |     vec = vec.iter().filter(|&x| x % 2 == 0).copied().collect();
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider calling `.retain()` instead: `vec.retain(|x| x % 2 == 0)`
 
 error: this expression can be written more simply using `.retain()`
-  --> $DIR/manual_retain.rs:177:5
+  --> $DIR/manual_retain.rs:201:5
    |
 LL |     vec = vec.iter().filter(|&x| x % 2 == 0).cloned().collect();
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider calling `.retain()` instead: `vec.retain(|x| x % 2 == 0)`
 
 error: this expression can be written more simply using `.retain()`
-  --> $DIR/manual_retain.rs:178:5
+  --> $DIR/manual_retain.rs:202:5
    |
 LL |     vec = vec.into_iter().filter(|x| x % 2 == 0).collect();
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider calling `.retain()` instead: `vec.retain(|x| x % 2 == 0)`
 
 error: this expression can be written more simply using `.retain()`
-  --> $DIR/manual_retain.rs:200:5
+  --> $DIR/manual_retain.rs:206:5
+   |
+LL |     tuples = tuples.iter().filter(|(ref x, ref y)| *x == 0).copied().collect();
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider calling `.retain()` instead: `tuples.retain(|(ref x, ref y)| *x == 0)`
+
+error: this expression can be written more simply using `.retain()`
+  --> $DIR/manual_retain.rs:207:5
+   |
+LL |     tuples = tuples.iter().filter(|(x, y)| *x == 0).copied().collect();
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider calling `.retain()` instead: `tuples.retain(|(x, y)| *x == 0)`
+
+error: this expression can be written more simply using `.retain()`
+  --> $DIR/manual_retain.rs:229:5
    |
 LL |     vec_deque = vec_deque.iter().filter(|&x| x % 2 == 0).copied().collect();
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider calling `.retain()` instead: `vec_deque.retain(|x| x % 2 == 0)`
 
 error: this expression can be written more simply using `.retain()`
-  --> $DIR/manual_retain.rs:201:5
+  --> $DIR/manual_retain.rs:230:5
    |
 LL |     vec_deque = vec_deque.iter().filter(|&x| x % 2 == 0).cloned().collect();
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider calling `.retain()` instead: `vec_deque.retain(|x| x % 2 == 0)`
 
 error: this expression can be written more simply using `.retain()`
-  --> $DIR/manual_retain.rs:202:5
+  --> $DIR/manual_retain.rs:231:5
    |
 LL |     vec_deque = vec_deque.into_iter().filter(|x| x % 2 == 0).collect();
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider calling `.retain()` instead: `vec_deque.retain(|x| x % 2 == 0)`
 
-error: aborting due to 22 previous errors
+error: this expression can be written more simply using `.retain()`
+  --> $DIR/manual_retain.rs:288:5
+   |
+LL |     vec = vec.into_iter().filter(|(x, y)| *x == 0).collect();
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider calling `.retain()` instead: `vec.retain(|(x, y)| *x == 0)`
+
+error: this expression can be written more simply using `.retain()`
+  --> $DIR/manual_retain.rs:292:5
+   |
+LL |     tuples = tuples.into_iter().filter(|(_, n)| *n > 0).collect();
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider calling `.retain()` instead: `tuples.retain(|(_, n)| *n > 0)`
+
+error: this expression can be written more simply using `.retain()`
+  --> $DIR/manual_retain.rs:309:5
+   |
+LL |     vec = vec.iter().filter(|&&x| x == 0).copied().collect();
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider calling `.retain()` instead: `vec.retain(|&x| x == 0)`
+
+error: this expression can be written more simply using `.retain()`
+  --> $DIR/manual_retain.rs:310:5
+   |
+LL |     vec = vec.iter().filter(|&&x| x == 0).cloned().collect();
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider calling `.retain()` instead: `vec.retain(|&x| x == 0)`
+
+error: this expression can be written more simply using `.retain()`
+  --> $DIR/manual_retain.rs:311:5
+   |
+LL |     vec = vec.into_iter().filter(|&x| x == 0).collect();
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider calling `.retain()` instead: `vec.retain(|&x| x == 0)`
+
+error: this expression can be written more simply using `.retain()`
+  --> $DIR/manual_retain.rs:314:5
+   |
+LL |     vec = vec.iter().filter(|&x| *x == 0).copied().collect();
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider calling `.retain()` instead: `vec.retain(|x| *x == 0)`
+
+error: this expression can be written more simply using `.retain()`
+  --> $DIR/manual_retain.rs:315:5
+   |
+LL |     vec = vec.iter().filter(|&x| *x == 0).cloned().collect();
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider calling `.retain()` instead: `vec.retain(|x| *x == 0)`
+
+error: this expression can be written more simply using `.retain()`
+  --> $DIR/manual_retain.rs:316:5
+   |
+LL |     vec = vec.into_iter().filter(|x| *x == 0).collect();
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider calling `.retain()` instead: `vec.retain(|x| *x == 0)`
+
+error: aborting due to 38 previous errors
 
diff --git a/src/tools/clippy/tests/ui/modulo_arithmetic_integral.rs b/src/tools/clippy/tests/ui/modulo_arithmetic_integral.rs
index 4dbed24026c..c427b8580e1 100644
--- a/src/tools/clippy/tests/ui/modulo_arithmetic_integral.rs
+++ b/src/tools/clippy/tests/ui/modulo_arithmetic_integral.rs
@@ -114,4 +114,12 @@ fn main() {
     a_usize % b_usize;
     let mut a_usize: usize = 1;
     a_usize %= 2;
+
+    // No lint when comparing to zero
+    let a = -1;
+    let mut b = 2;
+    let c = a % b == 0;
+    let c = 0 == a % b;
+    let c = a % b != 0;
+    let c = 0 != a % b;
 }
diff --git a/src/tools/clippy/tests/ui/needless_borrow.fixed b/src/tools/clippy/tests/ui/needless_borrow.fixed
index ff1e2dc8875..23e8bf8a468 100644
--- a/src/tools/clippy/tests/ui/needless_borrow.fixed
+++ b/src/tools/clippy/tests/ui/needless_borrow.fixed
@@ -131,6 +131,9 @@ fn main() {
             0
         }
     }
+
+    // issue #11786
+    let x: (&str,) = ("",);
 }
 
 #[allow(clippy::needless_borrowed_reference)]
diff --git a/src/tools/clippy/tests/ui/needless_borrow.rs b/src/tools/clippy/tests/ui/needless_borrow.rs
index 597021539ac..27771a8f15b 100644
--- a/src/tools/clippy/tests/ui/needless_borrow.rs
+++ b/src/tools/clippy/tests/ui/needless_borrow.rs
@@ -131,6 +131,9 @@ fn main() {
             0
         }
     }
+
+    // issue #11786
+    let x: (&str,) = (&"",);
 }
 
 #[allow(clippy::needless_borrowed_reference)]
diff --git a/src/tools/clippy/tests/ui/needless_borrow.stderr b/src/tools/clippy/tests/ui/needless_borrow.stderr
index 44552ee6abe..a21ed8382c1 100644
--- a/src/tools/clippy/tests/ui/needless_borrow.stderr
+++ b/src/tools/clippy/tests/ui/needless_borrow.stderr
@@ -121,41 +121,47 @@ error: this expression creates a reference which is immediately dereferenced by
 LL |     (&&5).foo();
    |     ^^^^^ help: change this to: `(&5)`
 
+error: this expression creates a reference which is immediately dereferenced by the compiler
+  --> $DIR/needless_borrow.rs:136:23
+   |
+LL |     let x: (&str,) = (&"",);
+   |                       ^^^ help: change this to: `""`
+
 error: this expression borrows a value the compiler would automatically borrow
-  --> $DIR/needless_borrow.rs:175:13
+  --> $DIR/needless_borrow.rs:178:13
    |
 LL |             (&self.f)()
    |             ^^^^^^^^^ help: change this to: `(self.f)`
 
 error: this expression borrows a value the compiler would automatically borrow
-  --> $DIR/needless_borrow.rs:184:13
+  --> $DIR/needless_borrow.rs:187:13
    |
 LL |             (&mut self.f)()
    |             ^^^^^^^^^^^^^ help: change this to: `(self.f)`
 
 error: this expression borrows a value the compiler would automatically borrow
-  --> $DIR/needless_borrow.rs:221:22
+  --> $DIR/needless_borrow.rs:224:22
    |
 LL |         let _ = &mut (&mut { x.u }).x;
    |                      ^^^^^^^^^^^^^^ help: change this to: `{ x.u }`
 
 error: this expression borrows a value the compiler would automatically borrow
-  --> $DIR/needless_borrow.rs:228:22
+  --> $DIR/needless_borrow.rs:231:22
    |
 LL |         let _ = &mut (&mut { x.u }).x;
    |                      ^^^^^^^^^^^^^^ help: change this to: `{ x.u }`
 
 error: this expression borrows a value the compiler would automatically borrow
-  --> $DIR/needless_borrow.rs:232:22
+  --> $DIR/needless_borrow.rs:235:22
    |
 LL |         let _ = &mut (&mut x.u).x;
    |                      ^^^^^^^^^^ help: change this to: `x.u`
 
 error: this expression borrows a value the compiler would automatically borrow
-  --> $DIR/needless_borrow.rs:233:22
+  --> $DIR/needless_borrow.rs:236:22
    |
 LL |         let _ = &mut (&mut { x.u }).x;
    |                      ^^^^^^^^^^^^^^ help: change this to: `{ x.u }`
 
-error: aborting due to 26 previous errors
+error: aborting due to 27 previous errors
 
diff --git a/src/tools/clippy/tests/ui/needless_return_with_question_mark.fixed b/src/tools/clippy/tests/ui/needless_return_with_question_mark.fixed
index 0147c73a94b..9b7da852663 100644
--- a/src/tools/clippy/tests/ui/needless_return_with_question_mark.fixed
+++ b/src/tools/clippy/tests/ui/needless_return_with_question_mark.fixed
@@ -77,3 +77,53 @@ fn issue11616() -> Result<(), ()> {
     };
     Ok(())
 }
+
+fn issue11982() {
+    mod bar {
+        pub struct Error;
+        pub fn foo(_: bool) -> Result<(), Error> {
+            Ok(())
+        }
+    }
+
+    pub struct Error;
+
+    impl From<bar::Error> for Error {
+        fn from(_: bar::Error) -> Self {
+            Error
+        }
+    }
+
+    fn foo(ok: bool) -> Result<(), Error> {
+        if !ok {
+            return bar::foo(ok).map(|_| Ok::<(), Error>(()))?;
+        };
+        Ok(())
+    }
+}
+
+fn issue11982_no_conversion() {
+    mod bar {
+        pub struct Error;
+        pub fn foo(_: bool) -> Result<(), Error> {
+            Ok(())
+        }
+    }
+
+    fn foo(ok: bool) -> Result<(), bar::Error> {
+        if !ok {
+            return bar::foo(ok).map(|_| Ok::<(), bar::Error>(()))?;
+        };
+        Ok(())
+    }
+}
+
+fn general_return() {
+    fn foo(ok: bool) -> Result<(), ()> {
+        let bar = Result::Ok(Result::<(), ()>::Ok(()));
+        if !ok {
+            return bar?;
+        };
+        Ok(())
+    }
+}
diff --git a/src/tools/clippy/tests/ui/needless_return_with_question_mark.rs b/src/tools/clippy/tests/ui/needless_return_with_question_mark.rs
index 66e1f438f8c..68e76d2b640 100644
--- a/src/tools/clippy/tests/ui/needless_return_with_question_mark.rs
+++ b/src/tools/clippy/tests/ui/needless_return_with_question_mark.rs
@@ -77,3 +77,53 @@ fn issue11616() -> Result<(), ()> {
     };
     Ok(())
 }
+
+fn issue11982() {
+    mod bar {
+        pub struct Error;
+        pub fn foo(_: bool) -> Result<(), Error> {
+            Ok(())
+        }
+    }
+
+    pub struct Error;
+
+    impl From<bar::Error> for Error {
+        fn from(_: bar::Error) -> Self {
+            Error
+        }
+    }
+
+    fn foo(ok: bool) -> Result<(), Error> {
+        if !ok {
+            return bar::foo(ok).map(|_| Ok::<(), Error>(()))?;
+        };
+        Ok(())
+    }
+}
+
+fn issue11982_no_conversion() {
+    mod bar {
+        pub struct Error;
+        pub fn foo(_: bool) -> Result<(), Error> {
+            Ok(())
+        }
+    }
+
+    fn foo(ok: bool) -> Result<(), bar::Error> {
+        if !ok {
+            return bar::foo(ok).map(|_| Ok::<(), bar::Error>(()))?;
+        };
+        Ok(())
+    }
+}
+
+fn general_return() {
+    fn foo(ok: bool) -> Result<(), ()> {
+        let bar = Result::Ok(Result::<(), ()>::Ok(()));
+        if !ok {
+            return bar?;
+        };
+        Ok(())
+    }
+}
diff --git a/src/tools/clippy/tests/ui/never_loop.rs b/src/tools/clippy/tests/ui/never_loop.rs
index c67a6d4494e..92f173d9db4 100644
--- a/src/tools/clippy/tests/ui/never_loop.rs
+++ b/src/tools/clippy/tests/ui/never_loop.rs
@@ -1,4 +1,4 @@
-#![feature(inline_const)]
+#![feature(inline_const, try_blocks)]
 #![allow(
     clippy::eq_op,
     clippy::single_match,
@@ -400,6 +400,15 @@ pub fn test32() {
     }
 }
 
+pub fn issue12205() -> Option<()> {
+    loop {
+        let _: Option<_> = try {
+            None?;
+            return Some(());
+        };
+    }
+}
+
 fn main() {
     test1();
     test2();
diff --git a/src/tools/clippy/tests/ui/nonminimal_bool.rs b/src/tools/clippy/tests/ui/nonminimal_bool.rs
index 4d48ef14d31..f7c3df7066f 100644
--- a/src/tools/clippy/tests/ui/nonminimal_bool.rs
+++ b/src/tools/clippy/tests/ui/nonminimal_bool.rs
@@ -145,3 +145,14 @@ fn issue10836() {
     // Should not lint
     let _: bool = !!Foo(true);
 }
+
+fn issue11932() {
+    let x: i32 = unimplemented!();
+
+    #[allow(clippy::nonminimal_bool)]
+    let _ = x % 2 == 0 || {
+        // Should not lint
+        assert!(x > 0);
+        x % 3 == 0
+    };
+}
diff --git a/src/tools/clippy/tests/ui/redundant_closure_call_fixable.fixed b/src/tools/clippy/tests/ui/redundant_closure_call_fixable.fixed
index f272d8359a3..ce5c7f2600b 100644
--- a/src/tools/clippy/tests/ui/redundant_closure_call_fixable.fixed
+++ b/src/tools/clippy/tests/ui/redundant_closure_call_fixable.fixed
@@ -102,3 +102,12 @@ mod issue11707 {
 fn avoid_double_parens() {
     std::convert::identity(13_i32 + 36_i32).leading_zeros();
 }
+
+fn fp_11274() {
+    macro_rules! m {
+        ($closure:expr) => {
+            $closure(1)
+        };
+    }
+    m!(|x| println!("{x}"));
+}
diff --git a/src/tools/clippy/tests/ui/redundant_closure_call_fixable.rs b/src/tools/clippy/tests/ui/redundant_closure_call_fixable.rs
index f45db8c9cff..ac09390e6ea 100644
--- a/src/tools/clippy/tests/ui/redundant_closure_call_fixable.rs
+++ b/src/tools/clippy/tests/ui/redundant_closure_call_fixable.rs
@@ -102,3 +102,12 @@ mod issue11707 {
 fn avoid_double_parens() {
     std::convert::identity((|| 13_i32 + 36_i32)()).leading_zeros();
 }
+
+fn fp_11274() {
+    macro_rules! m {
+        ($closure:expr) => {
+            $closure(1)
+        };
+    }
+    m!(|x| println!("{x}"));
+}
diff --git a/src/tools/clippy/tests/ui/redundant_locals.rs b/src/tools/clippy/tests/ui/redundant_locals.rs
index 182d067a5e9..f6909828aa9 100644
--- a/src/tools/clippy/tests/ui/redundant_locals.rs
+++ b/src/tools/clippy/tests/ui/redundant_locals.rs
@@ -1,6 +1,7 @@
 //@aux-build:proc_macros.rs
 #![allow(unused, clippy::no_effect, clippy::needless_pass_by_ref_mut)]
 #![warn(clippy::redundant_locals)]
+#![feature(async_closure, coroutines)]
 
 extern crate proc_macros;
 use proc_macros::{external, with_span};
@@ -163,3 +164,48 @@ fn drop_compose() {
     let b = ComposeDrop { d: WithDrop(1) };
     let a = a;
 }
+
+fn issue12225() {
+    fn assert_static<T: 'static>(_: T) {}
+
+    let v1 = String::new();
+    let v2 = String::new();
+    let v3 = String::new();
+    let v4 = String::new();
+    let v5 = String::new();
+    let v6 = String::new();
+
+    assert_static(|| {
+        let v1 = v1;
+        dbg!(&v1);
+    });
+    assert_static(async {
+        let v2 = v2;
+        dbg!(&v2);
+    });
+    assert_static(|| async {
+        let v3 = v3;
+        dbg!(&v3);
+    });
+    assert_static(async || {
+        let v4 = v4;
+        dbg!(&v4);
+    });
+    assert_static(static || {
+        let v5 = v5;
+        yield;
+    });
+    assert_static(|| {
+        let v6 = v6;
+        yield;
+    });
+
+    fn foo(a: &str, b: &str) {}
+
+    let do_not_move = String::new();
+    let things_to_move = vec!["a".to_string(), "b".to_string()];
+    let futures = things_to_move.into_iter().map(|move_me| async {
+        let move_me = move_me;
+        foo(&do_not_move, &move_me)
+    });
+}
diff --git a/src/tools/clippy/tests/ui/redundant_locals.stderr b/src/tools/clippy/tests/ui/redundant_locals.stderr
index 30ab4aa2ea9..610d587ddad 100644
--- a/src/tools/clippy/tests/ui/redundant_locals.stderr
+++ b/src/tools/clippy/tests/ui/redundant_locals.stderr
@@ -1,11 +1,11 @@
 error: redundant redefinition of a binding `x`
-  --> $DIR/redundant_locals.rs:12:5
+  --> $DIR/redundant_locals.rs:13:5
    |
 LL |     let x = x;
    |     ^^^^^^^^^^
    |
 help: `x` is initially defined here
-  --> $DIR/redundant_locals.rs:11:9
+  --> $DIR/redundant_locals.rs:12:9
    |
 LL |     let x = 1;
    |         ^
@@ -13,157 +13,157 @@ LL |     let x = 1;
    = help: to override `-D warnings` add `#[allow(clippy::redundant_locals)]`
 
 error: redundant redefinition of a binding `x`
-  --> $DIR/redundant_locals.rs:17:5
+  --> $DIR/redundant_locals.rs:18:5
    |
 LL |     let mut x = x;
    |     ^^^^^^^^^^^^^^
    |
 help: `x` is initially defined here
-  --> $DIR/redundant_locals.rs:16:9
+  --> $DIR/redundant_locals.rs:17:9
    |
 LL |     let mut x = 1;
    |         ^^^^^
 
 error: redundant redefinition of a binding `x`
-  --> $DIR/redundant_locals.rs:47:5
+  --> $DIR/redundant_locals.rs:48:5
    |
 LL |     let x = x;
    |     ^^^^^^^^^^
    |
 help: `x` is initially defined here
-  --> $DIR/redundant_locals.rs:46:14
+  --> $DIR/redundant_locals.rs:47:14
    |
 LL | fn parameter(x: i32) {
    |              ^
 
 error: redundant redefinition of a binding `x`
-  --> $DIR/redundant_locals.rs:52:5
+  --> $DIR/redundant_locals.rs:53:5
    |
 LL |     let x = x;
    |     ^^^^^^^^^^
    |
 help: `x` is initially defined here
-  --> $DIR/redundant_locals.rs:51:9
+  --> $DIR/redundant_locals.rs:52:9
    |
 LL |     let x = 1;
    |         ^
 
 error: redundant redefinition of a binding `x`
-  --> $DIR/redundant_locals.rs:53:5
+  --> $DIR/redundant_locals.rs:54:5
    |
 LL |     let x = x;
    |     ^^^^^^^^^^
    |
 help: `x` is initially defined here
-  --> $DIR/redundant_locals.rs:52:9
+  --> $DIR/redundant_locals.rs:53:9
    |
 LL |     let x = x;
    |         ^
 
 error: redundant redefinition of a binding `x`
-  --> $DIR/redundant_locals.rs:54:5
+  --> $DIR/redundant_locals.rs:55:5
    |
 LL |     let x = x;
    |     ^^^^^^^^^^
    |
 help: `x` is initially defined here
-  --> $DIR/redundant_locals.rs:53:9
+  --> $DIR/redundant_locals.rs:54:9
    |
 LL |     let x = x;
    |         ^
 
 error: redundant redefinition of a binding `x`
-  --> $DIR/redundant_locals.rs:55:5
+  --> $DIR/redundant_locals.rs:56:5
    |
 LL |     let x = x;
    |     ^^^^^^^^^^
    |
 help: `x` is initially defined here
-  --> $DIR/redundant_locals.rs:54:9
+  --> $DIR/redundant_locals.rs:55:9
    |
 LL |     let x = x;
    |         ^
 
 error: redundant redefinition of a binding `a`
-  --> $DIR/redundant_locals.rs:61:5
+  --> $DIR/redundant_locals.rs:62:5
    |
 LL |     let a = a;
    |     ^^^^^^^^^^
    |
 help: `a` is initially defined here
-  --> $DIR/redundant_locals.rs:59:9
+  --> $DIR/redundant_locals.rs:60:9
    |
 LL |     let a = 1;
    |         ^
 
 error: redundant redefinition of a binding `b`
-  --> $DIR/redundant_locals.rs:62:5
+  --> $DIR/redundant_locals.rs:63:5
    |
 LL |     let b = b;
    |     ^^^^^^^^^^
    |
 help: `b` is initially defined here
-  --> $DIR/redundant_locals.rs:60:9
+  --> $DIR/redundant_locals.rs:61:9
    |
 LL |     let b = 2;
    |         ^
 
 error: redundant redefinition of a binding `x`
-  --> $DIR/redundant_locals.rs:68:9
+  --> $DIR/redundant_locals.rs:69:9
    |
 LL |         let x = x;
    |         ^^^^^^^^^^
    |
 help: `x` is initially defined here
-  --> $DIR/redundant_locals.rs:67:13
+  --> $DIR/redundant_locals.rs:68:13
    |
 LL |         let x = 1;
    |             ^
 
 error: redundant redefinition of a binding `x`
-  --> $DIR/redundant_locals.rs:75:9
+  --> $DIR/redundant_locals.rs:76:9
    |
 LL |         let x = x;
    |         ^^^^^^^^^^
    |
 help: `x` is initially defined here
-  --> $DIR/redundant_locals.rs:74:13
+  --> $DIR/redundant_locals.rs:75:13
    |
 LL |         let x = 1;
    |             ^
 
 error: redundant redefinition of a binding `x`
-  --> $DIR/redundant_locals.rs:78:9
+  --> $DIR/redundant_locals.rs:79:9
    |
 LL |         let x = x;
    |         ^^^^^^^^^^
    |
 help: `x` is initially defined here
-  --> $DIR/redundant_locals.rs:77:6
+  --> $DIR/redundant_locals.rs:78:6
    |
 LL |     |x: i32| {
    |      ^
 
 error: redundant redefinition of a binding `x`
-  --> $DIR/redundant_locals.rs:97:9
+  --> $DIR/redundant_locals.rs:98:9
    |
 LL |         let x = x;
    |         ^^^^^^^^^^
    |
 help: `x` is initially defined here
-  --> $DIR/redundant_locals.rs:94:9
+  --> $DIR/redundant_locals.rs:95:9
    |
 LL |     let x = 1;
    |         ^
 
 error: redundant redefinition of a binding `a`
-  --> $DIR/redundant_locals.rs:152:5
+  --> $DIR/redundant_locals.rs:153:5
    |
 LL |     let a = a;
    |     ^^^^^^^^^^
    |
 help: `a` is initially defined here
-  --> $DIR/redundant_locals.rs:150:9
+  --> $DIR/redundant_locals.rs:151:9
    |
 LL |     let a = WithoutDrop(1);
    |         ^
diff --git a/src/tools/clippy/tests/ui/redundant_type_annotations.rs b/src/tools/clippy/tests/ui/redundant_type_annotations.rs
index acf53fea2bb..dc9b073ffba 100644
--- a/src/tools/clippy/tests/ui/redundant_type_annotations.rs
+++ b/src/tools/clippy/tests/ui/redundant_type_annotations.rs
@@ -196,13 +196,18 @@ fn test_simple_types() {
     let _var: &str = "test";
     //~^ ERROR: redundant type annotation
 
-    let _var: &[u8] = b"test";
+    let _var: &[u8; 4] = b"test";
     //~^ ERROR: redundant type annotation
 
     let _var: bool = false;
     //~^ ERROR: redundant type annotation
 }
 
+fn issue12212() {
+    // This should not be linted
+    let _var: &[u8] = b"test";
+}
+
 fn issue11190() {}
 
 fn main() {}
diff --git a/src/tools/clippy/tests/ui/redundant_type_annotations.stderr b/src/tools/clippy/tests/ui/redundant_type_annotations.stderr
index d1f26f1832e..48df465ad49 100644
--- a/src/tools/clippy/tests/ui/redundant_type_annotations.stderr
+++ b/src/tools/clippy/tests/ui/redundant_type_annotations.stderr
@@ -94,8 +94,8 @@ LL |     let _var: &str = "test";
 error: redundant type annotation
   --> $DIR/redundant_type_annotations.rs:199:5
    |
-LL |     let _var: &[u8] = b"test";
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL |     let _var: &[u8; 4] = b"test";
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: redundant type annotation
   --> $DIR/redundant_type_annotations.rs:202:5
diff --git a/src/tools/clippy/tests/ui/ref_as_ptr.fixed b/src/tools/clippy/tests/ui/ref_as_ptr.fixed
new file mode 100644
index 00000000000..7a946393f25
--- /dev/null
+++ b/src/tools/clippy/tests/ui/ref_as_ptr.fixed
@@ -0,0 +1,110 @@
+#![warn(clippy::ref_as_ptr)]
+#![allow(clippy::unnecessary_mut_passed)]
+
+fn main() {
+    let _ = std::ptr::from_ref(&1u8);
+    let _ = std::ptr::from_ref::<u32>(&2u32);
+    let _ = std::ptr::from_ref::<f64>(&3.0f64);
+
+    let _ = std::ptr::from_ref(&4) as *const f32;
+    let _ = std::ptr::from_ref::<f32>(&5.0f32) as *const u32;
+
+    let _ = std::ptr::from_ref(&mut 6u8);
+    let _ = std::ptr::from_ref::<u32>(&mut 7u32);
+    let _ = std::ptr::from_ref::<f64>(&mut 8.0f64);
+
+    let _ = std::ptr::from_ref(&mut 9) as *const f32;
+    let _ = std::ptr::from_ref::<f32>(&mut 10.0f32) as *const u32;
+
+    let _ = std::ptr::from_mut(&mut 11u8);
+    let _ = std::ptr::from_mut::<u32>(&mut 12u32);
+    let _ = std::ptr::from_mut::<f64>(&mut 13.0f64);
+
+    let _ = std::ptr::from_mut(&mut 14) as *const f32;
+    let _ = std::ptr::from_mut::<f32>(&mut 15.0f32) as *const u32;
+
+    let _ = std::ptr::from_ref(&1u8);
+    let _ = std::ptr::from_ref::<u32>(&2u32);
+    let _ = std::ptr::from_ref::<f64>(&3.0f64);
+
+    let _ = std::ptr::from_ref(&4) as *const f32;
+    let _ = std::ptr::from_ref::<f32>(&5.0f32) as *const u32;
+
+    let val = 1;
+    let _ = std::ptr::from_ref(&val);
+    let _ = std::ptr::from_ref::<i32>(&val);
+
+    let _ = std::ptr::from_ref(&val) as *const f32;
+    let _ = std::ptr::from_ref::<i32>(&val) as *const f64;
+
+    let mut val: u8 = 2;
+    let _ = std::ptr::from_mut::<u8>(&mut val);
+    let _ = std::ptr::from_mut(&mut val);
+
+    let _ = std::ptr::from_ref::<u8>(&mut val);
+    let _ = std::ptr::from_ref(&mut val);
+
+    let _ = std::ptr::from_ref::<u8>(&mut val) as *const f64;
+    let _: *const Option<u8> = std::ptr::from_ref(&mut val) as *const _;
+
+    let _ = std::ptr::from_ref::<[usize; 7]>(&std::array::from_fn(|i| i * i));
+    let _ = std::ptr::from_ref::<[usize; 8]>(&mut std::array::from_fn(|i| i * i));
+    let _ = std::ptr::from_mut::<[usize; 9]>(&mut std::array::from_fn(|i| i * i));
+}
+
+#[clippy::msrv = "1.75"]
+fn _msrv_1_75() {
+    let val = &42_i32;
+    let mut_val = &mut 42_i32;
+
+    // `std::ptr::from_{ref, mut}` was stabilized in 1.76. Do not lint this
+    let _ = val as *const i32;
+    let _ = mut_val as *mut i32;
+}
+
+#[clippy::msrv = "1.76"]
+fn _msrv_1_76() {
+    let val = &42_i32;
+    let mut_val = &mut 42_i32;
+
+    let _ = std::ptr::from_ref::<i32>(val);
+    let _ = std::ptr::from_mut::<i32>(mut_val);
+}
+
+fn foo(val: &[u8]) {
+    let _ = std::ptr::from_ref(val);
+    let _ = std::ptr::from_ref::<[u8]>(val);
+}
+
+fn bar(val: &mut str) {
+    let _ = std::ptr::from_mut(val);
+    let _ = std::ptr::from_mut::<str>(val);
+}
+
+struct X<'a>(&'a i32);
+
+impl<'a> X<'a> {
+    fn foo(&self) -> *const i64 {
+        std::ptr::from_ref(self.0) as *const _
+    }
+
+    fn bar(&mut self) -> *const i64 {
+        std::ptr::from_ref(self.0) as *const _
+    }
+}
+
+struct Y<'a>(&'a mut i32);
+
+impl<'a> Y<'a> {
+    fn foo(&self) -> *const i64 {
+        std::ptr::from_ref(self.0) as *const _
+    }
+
+    fn bar(&mut self) -> *const i64 {
+        std::ptr::from_ref(self.0) as *const _
+    }
+
+    fn baz(&mut self) -> *const i64 {
+        std::ptr::from_mut(self.0) as *mut _
+    }
+}
diff --git a/src/tools/clippy/tests/ui/ref_as_ptr.rs b/src/tools/clippy/tests/ui/ref_as_ptr.rs
new file mode 100644
index 00000000000..6f745505b46
--- /dev/null
+++ b/src/tools/clippy/tests/ui/ref_as_ptr.rs
@@ -0,0 +1,110 @@
+#![warn(clippy::ref_as_ptr)]
+#![allow(clippy::unnecessary_mut_passed)]
+
+fn main() {
+    let _ = &1u8 as *const _;
+    let _ = &2u32 as *const u32;
+    let _ = &3.0f64 as *const f64;
+
+    let _ = &4 as *const _ as *const f32;
+    let _ = &5.0f32 as *const f32 as *const u32;
+
+    let _ = &mut 6u8 as *const _;
+    let _ = &mut 7u32 as *const u32;
+    let _ = &mut 8.0f64 as *const f64;
+
+    let _ = &mut 9 as *const _ as *const f32;
+    let _ = &mut 10.0f32 as *const f32 as *const u32;
+
+    let _ = &mut 11u8 as *mut _;
+    let _ = &mut 12u32 as *mut u32;
+    let _ = &mut 13.0f64 as *mut f64;
+
+    let _ = &mut 14 as *mut _ as *const f32;
+    let _ = &mut 15.0f32 as *mut f32 as *const u32;
+
+    let _ = &1u8 as *const _;
+    let _ = &2u32 as *const u32;
+    let _ = &3.0f64 as *const f64;
+
+    let _ = &4 as *const _ as *const f32;
+    let _ = &5.0f32 as *const f32 as *const u32;
+
+    let val = 1;
+    let _ = &val as *const _;
+    let _ = &val as *const i32;
+
+    let _ = &val as *const _ as *const f32;
+    let _ = &val as *const i32 as *const f64;
+
+    let mut val: u8 = 2;
+    let _ = &mut val as *mut u8;
+    let _ = &mut val as *mut _;
+
+    let _ = &mut val as *const u8;
+    let _ = &mut val as *const _;
+
+    let _ = &mut val as *const u8 as *const f64;
+    let _: *const Option<u8> = &mut val as *const _ as *const _;
+
+    let _ = &std::array::from_fn(|i| i * i) as *const [usize; 7];
+    let _ = &mut std::array::from_fn(|i| i * i) as *const [usize; 8];
+    let _ = &mut std::array::from_fn(|i| i * i) as *mut [usize; 9];
+}
+
+#[clippy::msrv = "1.75"]
+fn _msrv_1_75() {
+    let val = &42_i32;
+    let mut_val = &mut 42_i32;
+
+    // `std::ptr::from_{ref, mut}` was stabilized in 1.76. Do not lint this
+    let _ = val as *const i32;
+    let _ = mut_val as *mut i32;
+}
+
+#[clippy::msrv = "1.76"]
+fn _msrv_1_76() {
+    let val = &42_i32;
+    let mut_val = &mut 42_i32;
+
+    let _ = val as *const i32;
+    let _ = mut_val as *mut i32;
+}
+
+fn foo(val: &[u8]) {
+    let _ = val as *const _;
+    let _ = val as *const [u8];
+}
+
+fn bar(val: &mut str) {
+    let _ = val as *mut _;
+    let _ = val as *mut str;
+}
+
+struct X<'a>(&'a i32);
+
+impl<'a> X<'a> {
+    fn foo(&self) -> *const i64 {
+        self.0 as *const _ as *const _
+    }
+
+    fn bar(&mut self) -> *const i64 {
+        self.0 as *const _ as *const _
+    }
+}
+
+struct Y<'a>(&'a mut i32);
+
+impl<'a> Y<'a> {
+    fn foo(&self) -> *const i64 {
+        self.0 as *const _ as *const _
+    }
+
+    fn bar(&mut self) -> *const i64 {
+        self.0 as *const _ as *const _
+    }
+
+    fn baz(&mut self) -> *const i64 {
+        self.0 as *mut _ as *mut _
+    }
+}
diff --git a/src/tools/clippy/tests/ui/ref_as_ptr.stderr b/src/tools/clippy/tests/ui/ref_as_ptr.stderr
new file mode 100644
index 00000000000..371d42df528
--- /dev/null
+++ b/src/tools/clippy/tests/ui/ref_as_ptr.stderr
@@ -0,0 +1,269 @@
+error: reference as raw pointer
+  --> $DIR/ref_as_ptr.rs:5:13
+   |
+LL |     let _ = &1u8 as *const _;
+   |             ^^^^^^^^^^^^^^^^ help: try: `std::ptr::from_ref(&1u8)`
+   |
+   = note: `-D clippy::ref-as-ptr` implied by `-D warnings`
+   = help: to override `-D warnings` add `#[allow(clippy::ref_as_ptr)]`
+
+error: reference as raw pointer
+  --> $DIR/ref_as_ptr.rs:6:13
+   |
+LL |     let _ = &2u32 as *const u32;
+   |             ^^^^^^^^^^^^^^^^^^^ help: try: `std::ptr::from_ref::<u32>(&2u32)`
+
+error: reference as raw pointer
+  --> $DIR/ref_as_ptr.rs:7:13
+   |
+LL |     let _ = &3.0f64 as *const f64;
+   |             ^^^^^^^^^^^^^^^^^^^^^ help: try: `std::ptr::from_ref::<f64>(&3.0f64)`
+
+error: reference as raw pointer
+  --> $DIR/ref_as_ptr.rs:9:13
+   |
+LL |     let _ = &4 as *const _ as *const f32;
+   |             ^^^^^^^^^^^^^^ help: try: `std::ptr::from_ref(&4)`
+
+error: reference as raw pointer
+  --> $DIR/ref_as_ptr.rs:10:13
+   |
+LL |     let _ = &5.0f32 as *const f32 as *const u32;
+   |             ^^^^^^^^^^^^^^^^^^^^^ help: try: `std::ptr::from_ref::<f32>(&5.0f32)`
+
+error: reference as raw pointer
+  --> $DIR/ref_as_ptr.rs:12:13
+   |
+LL |     let _ = &mut 6u8 as *const _;
+   |             ^^^^^^^^^^^^^^^^^^^^ help: try: `std::ptr::from_ref(&mut 6u8)`
+
+error: reference as raw pointer
+  --> $DIR/ref_as_ptr.rs:13:13
+   |
+LL |     let _ = &mut 7u32 as *const u32;
+   |             ^^^^^^^^^^^^^^^^^^^^^^^ help: try: `std::ptr::from_ref::<u32>(&mut 7u32)`
+
+error: reference as raw pointer
+  --> $DIR/ref_as_ptr.rs:14:13
+   |
+LL |     let _ = &mut 8.0f64 as *const f64;
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `std::ptr::from_ref::<f64>(&mut 8.0f64)`
+
+error: reference as raw pointer
+  --> $DIR/ref_as_ptr.rs:16:13
+   |
+LL |     let _ = &mut 9 as *const _ as *const f32;
+   |             ^^^^^^^^^^^^^^^^^^ help: try: `std::ptr::from_ref(&mut 9)`
+
+error: reference as raw pointer
+  --> $DIR/ref_as_ptr.rs:17:13
+   |
+LL |     let _ = &mut 10.0f32 as *const f32 as *const u32;
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `std::ptr::from_ref::<f32>(&mut 10.0f32)`
+
+error: reference as raw pointer
+  --> $DIR/ref_as_ptr.rs:19:13
+   |
+LL |     let _ = &mut 11u8 as *mut _;
+   |             ^^^^^^^^^^^^^^^^^^^ help: try: `std::ptr::from_mut(&mut 11u8)`
+
+error: reference as raw pointer
+  --> $DIR/ref_as_ptr.rs:20:13
+   |
+LL |     let _ = &mut 12u32 as *mut u32;
+   |             ^^^^^^^^^^^^^^^^^^^^^^ help: try: `std::ptr::from_mut::<u32>(&mut 12u32)`
+
+error: reference as raw pointer
+  --> $DIR/ref_as_ptr.rs:21:13
+   |
+LL |     let _ = &mut 13.0f64 as *mut f64;
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `std::ptr::from_mut::<f64>(&mut 13.0f64)`
+
+error: reference as raw pointer
+  --> $DIR/ref_as_ptr.rs:23:13
+   |
+LL |     let _ = &mut 14 as *mut _ as *const f32;
+   |             ^^^^^^^^^^^^^^^^^ help: try: `std::ptr::from_mut(&mut 14)`
+
+error: reference as raw pointer
+  --> $DIR/ref_as_ptr.rs:24:13
+   |
+LL |     let _ = &mut 15.0f32 as *mut f32 as *const u32;
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `std::ptr::from_mut::<f32>(&mut 15.0f32)`
+
+error: reference as raw pointer
+  --> $DIR/ref_as_ptr.rs:26:13
+   |
+LL |     let _ = &1u8 as *const _;
+   |             ^^^^^^^^^^^^^^^^ help: try: `std::ptr::from_ref(&1u8)`
+
+error: reference as raw pointer
+  --> $DIR/ref_as_ptr.rs:27:13
+   |
+LL |     let _ = &2u32 as *const u32;
+   |             ^^^^^^^^^^^^^^^^^^^ help: try: `std::ptr::from_ref::<u32>(&2u32)`
+
+error: reference as raw pointer
+  --> $DIR/ref_as_ptr.rs:28:13
+   |
+LL |     let _ = &3.0f64 as *const f64;
+   |             ^^^^^^^^^^^^^^^^^^^^^ help: try: `std::ptr::from_ref::<f64>(&3.0f64)`
+
+error: reference as raw pointer
+  --> $DIR/ref_as_ptr.rs:30:13
+   |
+LL |     let _ = &4 as *const _ as *const f32;
+   |             ^^^^^^^^^^^^^^ help: try: `std::ptr::from_ref(&4)`
+
+error: reference as raw pointer
+  --> $DIR/ref_as_ptr.rs:31:13
+   |
+LL |     let _ = &5.0f32 as *const f32 as *const u32;
+   |             ^^^^^^^^^^^^^^^^^^^^^ help: try: `std::ptr::from_ref::<f32>(&5.0f32)`
+
+error: reference as raw pointer
+  --> $DIR/ref_as_ptr.rs:34:13
+   |
+LL |     let _ = &val as *const _;
+   |             ^^^^^^^^^^^^^^^^ help: try: `std::ptr::from_ref(&val)`
+
+error: reference as raw pointer
+  --> $DIR/ref_as_ptr.rs:35:13
+   |
+LL |     let _ = &val as *const i32;
+   |             ^^^^^^^^^^^^^^^^^^ help: try: `std::ptr::from_ref::<i32>(&val)`
+
+error: reference as raw pointer
+  --> $DIR/ref_as_ptr.rs:37:13
+   |
+LL |     let _ = &val as *const _ as *const f32;
+   |             ^^^^^^^^^^^^^^^^ help: try: `std::ptr::from_ref(&val)`
+
+error: reference as raw pointer
+  --> $DIR/ref_as_ptr.rs:38:13
+   |
+LL |     let _ = &val as *const i32 as *const f64;
+   |             ^^^^^^^^^^^^^^^^^^ help: try: `std::ptr::from_ref::<i32>(&val)`
+
+error: reference as raw pointer
+  --> $DIR/ref_as_ptr.rs:41:13
+   |
+LL |     let _ = &mut val as *mut u8;
+   |             ^^^^^^^^^^^^^^^^^^^ help: try: `std::ptr::from_mut::<u8>(&mut val)`
+
+error: reference as raw pointer
+  --> $DIR/ref_as_ptr.rs:42:13
+   |
+LL |     let _ = &mut val as *mut _;
+   |             ^^^^^^^^^^^^^^^^^^ help: try: `std::ptr::from_mut(&mut val)`
+
+error: reference as raw pointer
+  --> $DIR/ref_as_ptr.rs:44:13
+   |
+LL |     let _ = &mut val as *const u8;
+   |             ^^^^^^^^^^^^^^^^^^^^^ help: try: `std::ptr::from_ref::<u8>(&mut val)`
+
+error: reference as raw pointer
+  --> $DIR/ref_as_ptr.rs:45:13
+   |
+LL |     let _ = &mut val as *const _;
+   |             ^^^^^^^^^^^^^^^^^^^^ help: try: `std::ptr::from_ref(&mut val)`
+
+error: reference as raw pointer
+  --> $DIR/ref_as_ptr.rs:47:13
+   |
+LL |     let _ = &mut val as *const u8 as *const f64;
+   |             ^^^^^^^^^^^^^^^^^^^^^ help: try: `std::ptr::from_ref::<u8>(&mut val)`
+
+error: reference as raw pointer
+  --> $DIR/ref_as_ptr.rs:48:32
+   |
+LL |     let _: *const Option<u8> = &mut val as *const _ as *const _;
+   |                                ^^^^^^^^^^^^^^^^^^^^ help: try: `std::ptr::from_ref(&mut val)`
+
+error: reference as raw pointer
+  --> $DIR/ref_as_ptr.rs:50:13
+   |
+LL |     let _ = &std::array::from_fn(|i| i * i) as *const [usize; 7];
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `std::ptr::from_ref::<[usize; 7]>(&std::array::from_fn(|i| i * i))`
+
+error: reference as raw pointer
+  --> $DIR/ref_as_ptr.rs:51:13
+   |
+LL |     let _ = &mut std::array::from_fn(|i| i * i) as *const [usize; 8];
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `std::ptr::from_ref::<[usize; 8]>(&mut std::array::from_fn(|i| i * i))`
+
+error: reference as raw pointer
+  --> $DIR/ref_as_ptr.rs:52:13
+   |
+LL |     let _ = &mut std::array::from_fn(|i| i * i) as *mut [usize; 9];
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `std::ptr::from_mut::<[usize; 9]>(&mut std::array::from_fn(|i| i * i))`
+
+error: reference as raw pointer
+  --> $DIR/ref_as_ptr.rs:70:13
+   |
+LL |     let _ = val as *const i32;
+   |             ^^^^^^^^^^^^^^^^^ help: try: `std::ptr::from_ref::<i32>(val)`
+
+error: reference as raw pointer
+  --> $DIR/ref_as_ptr.rs:71:13
+   |
+LL |     let _ = mut_val as *mut i32;
+   |             ^^^^^^^^^^^^^^^^^^^ help: try: `std::ptr::from_mut::<i32>(mut_val)`
+
+error: reference as raw pointer
+  --> $DIR/ref_as_ptr.rs:75:13
+   |
+LL |     let _ = val as *const _;
+   |             ^^^^^^^^^^^^^^^ help: try: `std::ptr::from_ref(val)`
+
+error: reference as raw pointer
+  --> $DIR/ref_as_ptr.rs:76:13
+   |
+LL |     let _ = val as *const [u8];
+   |             ^^^^^^^^^^^^^^^^^^ help: try: `std::ptr::from_ref::<[u8]>(val)`
+
+error: reference as raw pointer
+  --> $DIR/ref_as_ptr.rs:80:13
+   |
+LL |     let _ = val as *mut _;
+   |             ^^^^^^^^^^^^^ help: try: `std::ptr::from_mut(val)`
+
+error: reference as raw pointer
+  --> $DIR/ref_as_ptr.rs:81:13
+   |
+LL |     let _ = val as *mut str;
+   |             ^^^^^^^^^^^^^^^ help: try: `std::ptr::from_mut::<str>(val)`
+
+error: reference as raw pointer
+  --> $DIR/ref_as_ptr.rs:88:9
+   |
+LL |         self.0 as *const _ as *const _
+   |         ^^^^^^^^^^^^^^^^^^ help: try: `std::ptr::from_ref(self.0)`
+
+error: reference as raw pointer
+  --> $DIR/ref_as_ptr.rs:92:9
+   |
+LL |         self.0 as *const _ as *const _
+   |         ^^^^^^^^^^^^^^^^^^ help: try: `std::ptr::from_ref(self.0)`
+
+error: reference as raw pointer
+  --> $DIR/ref_as_ptr.rs:100:9
+   |
+LL |         self.0 as *const _ as *const _
+   |         ^^^^^^^^^^^^^^^^^^ help: try: `std::ptr::from_ref(self.0)`
+
+error: reference as raw pointer
+  --> $DIR/ref_as_ptr.rs:104:9
+   |
+LL |         self.0 as *const _ as *const _
+   |         ^^^^^^^^^^^^^^^^^^ help: try: `std::ptr::from_ref(self.0)`
+
+error: reference as raw pointer
+  --> $DIR/ref_as_ptr.rs:108:9
+   |
+LL |         self.0 as *mut _ as *mut _
+   |         ^^^^^^^^^^^^^^^^ help: try: `std::ptr::from_mut(self.0)`
+
+error: aborting due to 44 previous errors
+
diff --git a/src/tools/clippy/tests/ui/strlen_on_c_strings.fixed b/src/tools/clippy/tests/ui/strlen_on_c_strings.fixed
index 8304e2afd8b..1e7d04ffb9d 100644
--- a/src/tools/clippy/tests/ui/strlen_on_c_strings.fixed
+++ b/src/tools/clippy/tests/ui/strlen_on_c_strings.fixed
@@ -1,5 +1,5 @@
 #![warn(clippy::strlen_on_c_strings)]
-#![allow(dead_code)]
+#![allow(dead_code, clippy::manual_c_str_literals)]
 #![feature(rustc_private)]
 extern crate libc;
 
diff --git a/src/tools/clippy/tests/ui/strlen_on_c_strings.rs b/src/tools/clippy/tests/ui/strlen_on_c_strings.rs
index deba40a9ea5..c3ad03591d4 100644
--- a/src/tools/clippy/tests/ui/strlen_on_c_strings.rs
+++ b/src/tools/clippy/tests/ui/strlen_on_c_strings.rs
@@ -1,5 +1,5 @@
 #![warn(clippy::strlen_on_c_strings)]
-#![allow(dead_code)]
+#![allow(dead_code, clippy::manual_c_str_literals)]
 #![feature(rustc_private)]
 extern crate libc;
 
diff --git a/src/tools/clippy/tests/ui/to_string_trait_impl.rs b/src/tools/clippy/tests/ui/to_string_trait_impl.rs
new file mode 100644
index 00000000000..b0731632d45
--- /dev/null
+++ b/src/tools/clippy/tests/ui/to_string_trait_impl.rs
@@ -0,0 +1,31 @@
+#![warn(clippy::to_string_trait_impl)]
+
+use std::fmt::{self, Display};
+
+struct Point {
+    x: usize,
+    y: usize,
+}
+
+impl ToString for Point {
+    fn to_string(&self) -> String {
+        format!("({}, {})", self.x, self.y)
+    }
+}
+
+struct Foo;
+
+impl Display for Foo {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        write!(f, "Foo")
+    }
+}
+
+struct Bar;
+
+impl Bar {
+    #[allow(clippy::inherent_to_string)]
+    fn to_string(&self) -> String {
+        String::from("Bar")
+    }
+}
diff --git a/src/tools/clippy/tests/ui/to_string_trait_impl.stderr b/src/tools/clippy/tests/ui/to_string_trait_impl.stderr
new file mode 100644
index 00000000000..55fa9f12c0e
--- /dev/null
+++ b/src/tools/clippy/tests/ui/to_string_trait_impl.stderr
@@ -0,0 +1,16 @@
+error: direct implementation of `ToString`
+  --> $DIR/to_string_trait_impl.rs:10:1
+   |
+LL | / impl ToString for Point {
+LL | |     fn to_string(&self) -> String {
+LL | |         format!("({}, {})", self.x, self.y)
+LL | |     }
+LL | | }
+   | |_^
+   |
+   = help: prefer implementing `Display` instead
+   = note: `-D clippy::to-string-trait-impl` implied by `-D warnings`
+   = help: to override `-D warnings` add `#[allow(clippy::to_string_trait_impl)]`
+
+error: aborting due to 1 previous error
+
diff --git a/src/tools/clippy/tests/ui/unconditional_recursion.rs b/src/tools/clippy/tests/ui/unconditional_recursion.rs
index 7b898a6e0e7..6ad3bde51cd 100644
--- a/src/tools/clippy/tests/ui/unconditional_recursion.rs
+++ b/src/tools/clippy/tests/ui/unconditional_recursion.rs
@@ -206,6 +206,7 @@ impl PartialEq for S8 {
 
 struct S9;
 
+#[allow(clippy::to_string_trait_impl)]
 impl std::string::ToString for S9 {
     fn to_string(&self) -> String {
         //~^ ERROR: function cannot return without recursing
@@ -215,6 +216,7 @@ impl std::string::ToString for S9 {
 
 struct S10;
 
+#[allow(clippy::to_string_trait_impl)]
 impl std::string::ToString for S10 {
     fn to_string(&self) -> String {
         //~^ ERROR: function cannot return without recursing
@@ -225,6 +227,7 @@ impl std::string::ToString for S10 {
 
 struct S11;
 
+#[allow(clippy::to_string_trait_impl)]
 impl std::string::ToString for S11 {
     fn to_string(&self) -> String {
         //~^ ERROR: function cannot return without recursing
@@ -288,4 +291,63 @@ impl PartialEq for S15<'_> {
     }
 }
 
+mod issue12154 {
+    struct MyBox<T>(T);
+
+    impl<T> std::ops::Deref for MyBox<T> {
+        type Target = T;
+        fn deref(&self) -> &T {
+            &self.0
+        }
+    }
+
+    impl<T: PartialEq> PartialEq for MyBox<T> {
+        fn eq(&self, other: &Self) -> bool {
+            (**self).eq(&**other)
+        }
+    }
+
+    // Not necessarily related to the issue but another FP from the http crate that was fixed with it:
+    // https://docs.rs/http/latest/src/http/header/name.rs.html#1424
+    // We used to simply peel refs from the LHS and RHS, so we couldn't differentiate
+    // between `PartialEq<T> for &T` and `PartialEq<&T> for T` impls.
+    #[derive(PartialEq)]
+    struct HeaderName;
+    impl<'a> PartialEq<&'a HeaderName> for HeaderName {
+        fn eq(&self, other: &&'a HeaderName) -> bool {
+            *self == **other
+        }
+    }
+
+    impl<'a> PartialEq<HeaderName> for &'a HeaderName {
+        fn eq(&self, other: &HeaderName) -> bool {
+            *other == *self
+        }
+    }
+
+    // Issue #12181 but also fixed by the same PR
+    struct Foo;
+
+    impl Foo {
+        fn as_str(&self) -> &str {
+            "Foo"
+        }
+    }
+
+    impl PartialEq for Foo {
+        fn eq(&self, other: &Self) -> bool {
+            self.as_str().eq(other.as_str())
+        }
+    }
+
+    impl<T> PartialEq<T> for Foo
+    where
+        for<'a> &'a str: PartialEq<T>,
+    {
+        fn eq(&self, other: &T) -> bool {
+            (&self.as_str()).eq(other)
+        }
+    }
+}
+
 fn main() {}
diff --git a/src/tools/clippy/tests/ui/unconditional_recursion.stderr b/src/tools/clippy/tests/ui/unconditional_recursion.stderr
index 094b80d4586..93a5eac91d8 100644
--- a/src/tools/clippy/tests/ui/unconditional_recursion.stderr
+++ b/src/tools/clippy/tests/ui/unconditional_recursion.stderr
@@ -23,7 +23,7 @@ LL |         self.eq(other)
    = help: a `loop` may express intention better if this is on purpose
 
 error: function cannot return without recursing
-  --> $DIR/unconditional_recursion.rs:210:5
+  --> $DIR/unconditional_recursion.rs:211:5
    |
 LL |     fn to_string(&self) -> String {
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot return without recursing
@@ -34,7 +34,7 @@ LL |         self.to_string()
    = help: a `loop` may express intention better if this is on purpose
 
 error: function cannot return without recursing
-  --> $DIR/unconditional_recursion.rs:219:5
+  --> $DIR/unconditional_recursion.rs:221:5
    |
 LL |     fn to_string(&self) -> String {
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot return without recursing
@@ -45,7 +45,7 @@ LL |         x.to_string()
    = help: a `loop` may express intention better if this is on purpose
 
 error: function cannot return without recursing
-  --> $DIR/unconditional_recursion.rs:229:5
+  --> $DIR/unconditional_recursion.rs:232:5
    |
 LL |     fn to_string(&self) -> String {
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot return without recursing
@@ -326,7 +326,7 @@ LL |         mine == theirs
    |         ^^^^^^^^^^^^^^
 
 error: function cannot return without recursing
-  --> $DIR/unconditional_recursion.rs:244:5
+  --> $DIR/unconditional_recursion.rs:247:5
    |
 LL | /     fn new() -> Self {
 LL | |
@@ -335,13 +335,13 @@ LL | |     }
    | |_____^
    |
 note: recursive call site
-  --> $DIR/unconditional_recursion.rs:246:9
+  --> $DIR/unconditional_recursion.rs:249:9
    |
 LL |         Self::default()
    |         ^^^^^^^^^^^^^^^
 
 error: function cannot return without recursing
-  --> $DIR/unconditional_recursion.rs:283:5
+  --> $DIR/unconditional_recursion.rs:286:5
    |
 LL | /     fn eq(&self, other: &Self) -> bool {
 LL | |
@@ -352,7 +352,7 @@ LL | |     }
    | |_____^
    |
 note: recursive call site
-  --> $DIR/unconditional_recursion.rs:287:9
+  --> $DIR/unconditional_recursion.rs:290:9
    |
 LL |         mine.eq(theirs)
    |         ^^^^^^^^^^^^^^^
diff --git a/src/tools/clippy/tests/ui/unnecessary_fold.fixed b/src/tools/clippy/tests/ui/unnecessary_fold.fixed
index c884d26eb61..c5bc11b55ab 100644
--- a/src/tools/clippy/tests/ui/unnecessary_fold.fixed
+++ b/src/tools/clippy/tests/ui/unnecessary_fold.fixed
@@ -1,9 +1,15 @@
 #![allow(dead_code)]
 
+fn is_any(acc: bool, x: usize) -> bool {
+    acc || x > 2
+}
+
 /// Calls which should trigger the `UNNECESSARY_FOLD` lint
 fn unnecessary_fold() {
     // Can be replaced by .any
     let _ = (0..3).any(|x| x > 2);
+    // Can be replaced by .any (checking suggestion)
+    let _ = (0..3).fold(false, is_any);
     // Can be replaced by .all
     let _ = (0..3).all(|x| x > 2);
     // Can be replaced by .sum
diff --git a/src/tools/clippy/tests/ui/unnecessary_fold.rs b/src/tools/clippy/tests/ui/unnecessary_fold.rs
index 2e6d6ba52eb..3a5136eeeae 100644
--- a/src/tools/clippy/tests/ui/unnecessary_fold.rs
+++ b/src/tools/clippy/tests/ui/unnecessary_fold.rs
@@ -1,9 +1,15 @@
 #![allow(dead_code)]
 
+fn is_any(acc: bool, x: usize) -> bool {
+    acc || x > 2
+}
+
 /// Calls which should trigger the `UNNECESSARY_FOLD` lint
 fn unnecessary_fold() {
     // Can be replaced by .any
     let _ = (0..3).fold(false, |acc, x| acc || x > 2);
+    // Can be replaced by .any (checking suggestion)
+    let _ = (0..3).fold(false, |acc, x| is_any(acc, x));
     // Can be replaced by .all
     let _ = (0..3).fold(true, |acc, x| acc && x > 2);
     // Can be replaced by .sum
diff --git a/src/tools/clippy/tests/ui/unnecessary_fold.stderr b/src/tools/clippy/tests/ui/unnecessary_fold.stderr
index f0d03963842..123d4a3be75 100644
--- a/src/tools/clippy/tests/ui/unnecessary_fold.stderr
+++ b/src/tools/clippy/tests/ui/unnecessary_fold.stderr
@@ -1,5 +1,5 @@
 error: this `.fold` can be written more succinctly using another method
-  --> $DIR/unnecessary_fold.rs:6:20
+  --> $DIR/unnecessary_fold.rs:10:20
    |
 LL |     let _ = (0..3).fold(false, |acc, x| acc || x > 2);
    |                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `any(|x| x > 2)`
@@ -7,89 +7,98 @@ LL |     let _ = (0..3).fold(false, |acc, x| acc || x > 2);
    = note: `-D clippy::unnecessary-fold` implied by `-D warnings`
    = help: to override `-D warnings` add `#[allow(clippy::unnecessary_fold)]`
 
+error: redundant closure
+  --> $DIR/unnecessary_fold.rs:12:32
+   |
+LL |     let _ = (0..3).fold(false, |acc, x| is_any(acc, x));
+   |                                ^^^^^^^^^^^^^^^^^^^^^^^ help: replace the closure with the function itself: `is_any`
+   |
+   = note: `-D clippy::redundant-closure` implied by `-D warnings`
+   = help: to override `-D warnings` add `#[allow(clippy::redundant_closure)]`
+
 error: this `.fold` can be written more succinctly using another method
-  --> $DIR/unnecessary_fold.rs:8:20
+  --> $DIR/unnecessary_fold.rs:14:20
    |
 LL |     let _ = (0..3).fold(true, |acc, x| acc && x > 2);
    |                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `all(|x| x > 2)`
 
 error: this `.fold` can be written more succinctly using another method
-  --> $DIR/unnecessary_fold.rs:10:25
+  --> $DIR/unnecessary_fold.rs:16:25
    |
 LL |     let _: i32 = (0..3).fold(0, |acc, x| acc + x);
    |                         ^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `sum()`
 
 error: this `.fold` can be written more succinctly using another method
-  --> $DIR/unnecessary_fold.rs:12:25
+  --> $DIR/unnecessary_fold.rs:18:25
    |
 LL |     let _: i32 = (0..3).fold(1, |acc, x| acc * x);
    |                         ^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `product()`
 
 error: this `.fold` can be written more succinctly using another method
-  --> $DIR/unnecessary_fold.rs:17:41
+  --> $DIR/unnecessary_fold.rs:23:41
    |
 LL |     let _: bool = (0..3).map(|x| 2 * x).fold(false, |acc, x| acc || x > 2);
    |                                         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `any(|x| x > 2)`
 
 error: this `.fold` can be written more succinctly using another method
-  --> $DIR/unnecessary_fold.rs:47:10
+  --> $DIR/unnecessary_fold.rs:53:10
    |
 LL |         .fold(false, |acc, x| acc || x > 2);
    |          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `any(|x| x > 2)`
 
 error: this `.fold` can be written more succinctly using another method
-  --> $DIR/unnecessary_fold.rs:58:33
+  --> $DIR/unnecessary_fold.rs:64:33
    |
 LL |         assert_eq!(map.values().fold(0, |x, y| x + y), 0);
    |                                 ^^^^^^^^^^^^^^^^^^^^^ help: try: `sum::<i32>()`
 
 error: this `.fold` can be written more succinctly using another method
-  --> $DIR/unnecessary_fold.rs:61:30
+  --> $DIR/unnecessary_fold.rs:67:30
    |
 LL |         let _ = map.values().fold(0, |x, y| x + y);
    |                              ^^^^^^^^^^^^^^^^^^^^^ help: try: `sum::<i32>()`
 
 error: this `.fold` can be written more succinctly using another method
-  --> $DIR/unnecessary_fold.rs:62:30
+  --> $DIR/unnecessary_fold.rs:68:30
    |
 LL |         let _ = map.values().fold(1, |x, y| x * y);
    |                              ^^^^^^^^^^^^^^^^^^^^^ help: try: `product::<i32>()`
 
 error: this `.fold` can be written more succinctly using another method
-  --> $DIR/unnecessary_fold.rs:63:35
+  --> $DIR/unnecessary_fold.rs:69:35
    |
 LL |         let _: i32 = map.values().fold(0, |x, y| x + y);
    |                                   ^^^^^^^^^^^^^^^^^^^^^ help: try: `sum()`
 
 error: this `.fold` can be written more succinctly using another method
-  --> $DIR/unnecessary_fold.rs:64:35
+  --> $DIR/unnecessary_fold.rs:70:35
    |
 LL |         let _: i32 = map.values().fold(1, |x, y| x * y);
    |                                   ^^^^^^^^^^^^^^^^^^^^^ help: try: `product()`
 
 error: this `.fold` can be written more succinctly using another method
-  --> $DIR/unnecessary_fold.rs:65:31
+  --> $DIR/unnecessary_fold.rs:71:31
    |
 LL |         anything(map.values().fold(0, |x, y| x + y));
    |                               ^^^^^^^^^^^^^^^^^^^^^ help: try: `sum::<i32>()`
 
 error: this `.fold` can be written more succinctly using another method
-  --> $DIR/unnecessary_fold.rs:66:31
+  --> $DIR/unnecessary_fold.rs:72:31
    |
 LL |         anything(map.values().fold(1, |x, y| x * y));
    |                               ^^^^^^^^^^^^^^^^^^^^^ help: try: `product::<i32>()`
 
 error: this `.fold` can be written more succinctly using another method
-  --> $DIR/unnecessary_fold.rs:67:26
+  --> $DIR/unnecessary_fold.rs:73:26
    |
 LL |         num(map.values().fold(0, |x, y| x + y));
    |                          ^^^^^^^^^^^^^^^^^^^^^ help: try: `sum()`
 
 error: this `.fold` can be written more succinctly using another method
-  --> $DIR/unnecessary_fold.rs:68:26
+  --> $DIR/unnecessary_fold.rs:74:26
    |
 LL |         num(map.values().fold(1, |x, y| x * y));
    |                          ^^^^^^^^^^^^^^^^^^^^^ help: try: `product()`
 
-error: aborting due to 15 previous errors
+error: aborting due to 16 previous errors
 
diff --git a/src/tools/clippy/tests/ui/unnecessary_operation.fixed b/src/tools/clippy/tests/ui/unnecessary_operation.fixed
index 463412daec0..11761c6c90e 100644
--- a/src/tools/clippy/tests/ui/unnecessary_operation.fixed
+++ b/src/tools/clippy/tests/ui/unnecessary_operation.fixed
@@ -106,4 +106,11 @@ fn main() {
 
     // Issue #11885
     Cout << 16;
+
+    // Issue #11575
+    // Bad formatting is required to trigger the bug
+    #[rustfmt::skip]
+    'label: {
+        break 'label
+    };
 }
diff --git a/src/tools/clippy/tests/ui/unnecessary_operation.rs b/src/tools/clippy/tests/ui/unnecessary_operation.rs
index f0d28e28902..de0081289ac 100644
--- a/src/tools/clippy/tests/ui/unnecessary_operation.rs
+++ b/src/tools/clippy/tests/ui/unnecessary_operation.rs
@@ -110,4 +110,11 @@ fn main() {
 
     // Issue #11885
     Cout << 16;
+
+    // Issue #11575
+    // Bad formatting is required to trigger the bug
+    #[rustfmt::skip]
+    'label: {
+        break 'label
+    };
 }
diff --git a/src/tools/clippy/tests/ui/unnecessary_result_map_or_else.fixed b/src/tools/clippy/tests/ui/unnecessary_result_map_or_else.fixed
new file mode 100644
index 00000000000..224e0b52d75
--- /dev/null
+++ b/src/tools/clippy/tests/ui/unnecessary_result_map_or_else.fixed
@@ -0,0 +1,61 @@
+#![warn(clippy::unnecessary_result_map_or_else)]
+#![allow(clippy::unnecessary_literal_unwrap, clippy::let_and_return, clippy::let_unit_value)]
+
+fn main() {
+    let x: Result<(), ()> = Ok(());
+    x.unwrap_or_else(|err| err); //~ ERROR: unused "map closure" when calling
+
+    // Type ascribtion.
+    let x: Result<(), ()> = Ok(());
+    x.unwrap_or_else(|err: ()| err); //~ ERROR: unused "map closure" when calling
+
+    // Auto-deref.
+    let y = String::new();
+    let x: Result<&String, &String> = Ok(&y);
+    let y: &str = x.unwrap_or_else(|err| err); //~ ERROR: unused "map closure" when calling
+
+    // Temporary variable.
+    let x: Result<(), ()> = Ok(());
+    x.unwrap_or_else(|err| err);
+
+    // Should not warn.
+    let x: Result<usize, usize> = Ok(0);
+    x.map_or_else(|err| err, |n| n + 1);
+
+    // Should not warn.
+    let y = ();
+    let x: Result<(), ()> = Ok(());
+    x.map_or_else(|err| err, |_| y);
+
+    // Should not warn.
+    let y = ();
+    let x: Result<(), ()> = Ok(());
+    x.map_or_else(
+        |err| err,
+        |_| {
+            let tmp = y;
+            tmp
+        },
+    );
+
+    // Should not warn.
+    let x: Result<usize, usize> = Ok(1);
+    x.map_or_else(
+        |err| err,
+        |n| {
+            let tmp = n + 1;
+            tmp
+        },
+    );
+
+    // Should not warn.
+    let y = 0;
+    let x: Result<usize, usize> = Ok(1);
+    x.map_or_else(
+        |err| err,
+        |n| {
+            let tmp = n;
+            y
+        },
+    );
+}
diff --git a/src/tools/clippy/tests/ui/unnecessary_result_map_or_else.rs b/src/tools/clippy/tests/ui/unnecessary_result_map_or_else.rs
new file mode 100644
index 00000000000..4fe950a4cfa
--- /dev/null
+++ b/src/tools/clippy/tests/ui/unnecessary_result_map_or_else.rs
@@ -0,0 +1,69 @@
+#![warn(clippy::unnecessary_result_map_or_else)]
+#![allow(clippy::unnecessary_literal_unwrap, clippy::let_and_return, clippy::let_unit_value)]
+
+fn main() {
+    let x: Result<(), ()> = Ok(());
+    x.map_or_else(|err| err, |n| n); //~ ERROR: unused "map closure" when calling
+
+    // Type ascribtion.
+    let x: Result<(), ()> = Ok(());
+    x.map_or_else(|err: ()| err, |n: ()| n); //~ ERROR: unused "map closure" when calling
+
+    // Auto-deref.
+    let y = String::new();
+    let x: Result<&String, &String> = Ok(&y);
+    let y: &str = x.map_or_else(|err| err, |n| n); //~ ERROR: unused "map closure" when calling
+
+    // Temporary variable.
+    let x: Result<(), ()> = Ok(());
+    x.map_or_else(
+        //~^ ERROR: unused "map closure" when calling
+        |err| err,
+        |n| {
+            let tmp = n;
+            let tmp2 = tmp;
+            tmp2
+        },
+    );
+
+    // Should not warn.
+    let x: Result<usize, usize> = Ok(0);
+    x.map_or_else(|err| err, |n| n + 1);
+
+    // Should not warn.
+    let y = ();
+    let x: Result<(), ()> = Ok(());
+    x.map_or_else(|err| err, |_| y);
+
+    // Should not warn.
+    let y = ();
+    let x: Result<(), ()> = Ok(());
+    x.map_or_else(
+        |err| err,
+        |_| {
+            let tmp = y;
+            tmp
+        },
+    );
+
+    // Should not warn.
+    let x: Result<usize, usize> = Ok(1);
+    x.map_or_else(
+        |err| err,
+        |n| {
+            let tmp = n + 1;
+            tmp
+        },
+    );
+
+    // Should not warn.
+    let y = 0;
+    let x: Result<usize, usize> = Ok(1);
+    x.map_or_else(
+        |err| err,
+        |n| {
+            let tmp = n;
+            y
+        },
+    );
+}
diff --git a/src/tools/clippy/tests/ui/unnecessary_result_map_or_else.stderr b/src/tools/clippy/tests/ui/unnecessary_result_map_or_else.stderr
new file mode 100644
index 00000000000..0f83be5d556
--- /dev/null
+++ b/src/tools/clippy/tests/ui/unnecessary_result_map_or_else.stderr
@@ -0,0 +1,35 @@
+error: unused "map closure" when calling `Result::map_or_else` value
+  --> $DIR/unnecessary_result_map_or_else.rs:6:5
+   |
+LL |     x.map_or_else(|err| err, |n| n);
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `unwrap_or_else`: `x.unwrap_or_else(|err| err)`
+   |
+   = note: `-D clippy::unnecessary-result-map-or-else` implied by `-D warnings`
+   = help: to override `-D warnings` add `#[allow(clippy::unnecessary_result_map_or_else)]`
+
+error: unused "map closure" when calling `Result::map_or_else` value
+  --> $DIR/unnecessary_result_map_or_else.rs:10:5
+   |
+LL |     x.map_or_else(|err: ()| err, |n: ()| n);
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `unwrap_or_else`: `x.unwrap_or_else(|err: ()| err)`
+
+error: unused "map closure" when calling `Result::map_or_else` value
+  --> $DIR/unnecessary_result_map_or_else.rs:15:19
+   |
+LL |     let y: &str = x.map_or_else(|err| err, |n| n);
+   |                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `unwrap_or_else`: `x.unwrap_or_else(|err| err)`
+
+error: unused "map closure" when calling `Result::map_or_else` value
+  --> $DIR/unnecessary_result_map_or_else.rs:19:5
+   |
+LL | /     x.map_or_else(
+LL | |
+LL | |         |err| err,
+LL | |         |n| {
+...  |
+LL | |         },
+LL | |     );
+   | |_____^ help: consider using `unwrap_or_else`: `x.unwrap_or_else(|err| err)`
+
+error: aborting due to 4 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 2dd1d746626..7f01c981a93 100644
--- a/src/tools/clippy/tests/ui/unnecessary_to_owned.fixed
+++ b/src/tools/clippy/tests/ui/unnecessary_to_owned.fixed
@@ -27,6 +27,7 @@ impl AsRef<str> for X {
     }
 }
 
+#[allow(clippy::to_string_trait_impl)]
 impl ToString for X {
     fn to_string(&self) -> String {
         self.0.to_string()
@@ -265,6 +266,7 @@ mod issue_8507 {
         }
     }
 
+    #[allow(clippy::to_string_trait_impl)]
     impl ToString for Y {
         fn to_string(&self) -> String {
             self.0.to_string()
@@ -338,6 +340,7 @@ mod issue_9317 {
 
     struct Bytes {}
 
+    #[allow(clippy::to_string_trait_impl)]
     impl ToString for Bytes {
         fn to_string(&self) -> String {
             "123".to_string()
diff --git a/src/tools/clippy/tests/ui/unnecessary_to_owned.rs b/src/tools/clippy/tests/ui/unnecessary_to_owned.rs
index 17fad33402b..a270ed1e1c2 100644
--- a/src/tools/clippy/tests/ui/unnecessary_to_owned.rs
+++ b/src/tools/clippy/tests/ui/unnecessary_to_owned.rs
@@ -27,6 +27,7 @@ impl AsRef<str> for X {
     }
 }
 
+#[allow(clippy::to_string_trait_impl)]
 impl ToString for X {
     fn to_string(&self) -> String {
         self.0.to_string()
@@ -265,6 +266,7 @@ mod issue_8507 {
         }
     }
 
+    #[allow(clippy::to_string_trait_impl)]
     impl ToString for Y {
         fn to_string(&self) -> String {
             self.0.to_string()
@@ -338,6 +340,7 @@ mod issue_9317 {
 
     struct Bytes {}
 
+    #[allow(clippy::to_string_trait_impl)]
     impl ToString for Bytes {
         fn to_string(&self) -> String {
             "123".to_string()
diff --git a/src/tools/clippy/tests/ui/unnecessary_to_owned.stderr b/src/tools/clippy/tests/ui/unnecessary_to_owned.stderr
index ad6fa422b8c..95ff5f2ec2c 100644
--- a/src/tools/clippy/tests/ui/unnecessary_to_owned.stderr
+++ b/src/tools/clippy/tests/ui/unnecessary_to_owned.stderr
@@ -1,11 +1,11 @@
 error: redundant clone
-  --> $DIR/unnecessary_to_owned.rs:154:64
+  --> $DIR/unnecessary_to_owned.rs:155:64
    |
 LL |     require_c_str(&CString::from_vec_with_nul(vec![0]).unwrap().to_owned());
    |                                                                ^^^^^^^^^^^ help: remove this
    |
 note: this value is dropped without further use
-  --> $DIR/unnecessary_to_owned.rs:154:20
+  --> $DIR/unnecessary_to_owned.rs:155:20
    |
 LL |     require_c_str(&CString::from_vec_with_nul(vec![0]).unwrap().to_owned());
    |                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -13,55 +13,55 @@ LL |     require_c_str(&CString::from_vec_with_nul(vec![0]).unwrap().to_owned())
    = help: to override `-D warnings` add `#[allow(clippy::redundant_clone)]`
 
 error: redundant clone
-  --> $DIR/unnecessary_to_owned.rs:155:40
+  --> $DIR/unnecessary_to_owned.rs:156:40
    |
 LL |     require_os_str(&OsString::from("x").to_os_string());
    |                                        ^^^^^^^^^^^^^^^ help: remove this
    |
 note: this value is dropped without further use
-  --> $DIR/unnecessary_to_owned.rs:155:21
+  --> $DIR/unnecessary_to_owned.rs:156:21
    |
 LL |     require_os_str(&OsString::from("x").to_os_string());
    |                     ^^^^^^^^^^^^^^^^^^^
 
 error: redundant clone
-  --> $DIR/unnecessary_to_owned.rs:156:48
+  --> $DIR/unnecessary_to_owned.rs:157:48
    |
 LL |     require_path(&std::path::PathBuf::from("x").to_path_buf());
    |                                                ^^^^^^^^^^^^^^ help: remove this
    |
 note: this value is dropped without further use
-  --> $DIR/unnecessary_to_owned.rs:156:19
+  --> $DIR/unnecessary_to_owned.rs:157:19
    |
 LL |     require_path(&std::path::PathBuf::from("x").to_path_buf());
    |                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: redundant clone
-  --> $DIR/unnecessary_to_owned.rs:157:35
+  --> $DIR/unnecessary_to_owned.rs:158:35
    |
 LL |     require_str(&String::from("x").to_string());
    |                                   ^^^^^^^^^^^^ help: remove this
    |
 note: this value is dropped without further use
-  --> $DIR/unnecessary_to_owned.rs:157:18
+  --> $DIR/unnecessary_to_owned.rs:158:18
    |
 LL |     require_str(&String::from("x").to_string());
    |                  ^^^^^^^^^^^^^^^^^
 
 error: redundant clone
-  --> $DIR/unnecessary_to_owned.rs:158:39
+  --> $DIR/unnecessary_to_owned.rs:159:39
    |
 LL |     require_slice(&[String::from("x")].to_owned());
    |                                       ^^^^^^^^^^^ help: remove this
    |
 note: this value is dropped without further use
-  --> $DIR/unnecessary_to_owned.rs:158:20
+  --> $DIR/unnecessary_to_owned.rs:159:20
    |
 LL |     require_slice(&[String::from("x")].to_owned());
    |                    ^^^^^^^^^^^^^^^^^^^
 
 error: unnecessary use of `into_owned`
-  --> $DIR/unnecessary_to_owned.rs:63:36
+  --> $DIR/unnecessary_to_owned.rs:64:36
    |
 LL |     require_c_str(&Cow::from(c_str).into_owned());
    |                                    ^^^^^^^^^^^^^ help: remove this
@@ -70,415 +70,415 @@ LL |     require_c_str(&Cow::from(c_str).into_owned());
    = help: to override `-D warnings` add `#[allow(clippy::unnecessary_to_owned)]`
 
 error: unnecessary use of `to_owned`
-  --> $DIR/unnecessary_to_owned.rs:64:19
+  --> $DIR/unnecessary_to_owned.rs:65:19
    |
 LL |     require_c_str(&c_str.to_owned());
    |                   ^^^^^^^^^^^^^^^^^ help: use: `c_str`
 
 error: unnecessary use of `to_os_string`
-  --> $DIR/unnecessary_to_owned.rs:66:20
+  --> $DIR/unnecessary_to_owned.rs:67:20
    |
 LL |     require_os_str(&os_str.to_os_string());
    |                    ^^^^^^^^^^^^^^^^^^^^^^ help: use: `os_str`
 
 error: unnecessary use of `into_owned`
-  --> $DIR/unnecessary_to_owned.rs:67:38
+  --> $DIR/unnecessary_to_owned.rs:68:38
    |
 LL |     require_os_str(&Cow::from(os_str).into_owned());
    |                                      ^^^^^^^^^^^^^ help: remove this
 
 error: unnecessary use of `to_owned`
-  --> $DIR/unnecessary_to_owned.rs:68:20
+  --> $DIR/unnecessary_to_owned.rs:69:20
    |
 LL |     require_os_str(&os_str.to_owned());
    |                    ^^^^^^^^^^^^^^^^^^ help: use: `os_str`
 
 error: unnecessary use of `to_path_buf`
-  --> $DIR/unnecessary_to_owned.rs:70:18
+  --> $DIR/unnecessary_to_owned.rs:71:18
    |
 LL |     require_path(&path.to_path_buf());
    |                  ^^^^^^^^^^^^^^^^^^^ help: use: `path`
 
 error: unnecessary use of `into_owned`
-  --> $DIR/unnecessary_to_owned.rs:71:34
+  --> $DIR/unnecessary_to_owned.rs:72:34
    |
 LL |     require_path(&Cow::from(path).into_owned());
    |                                  ^^^^^^^^^^^^^ help: remove this
 
 error: unnecessary use of `to_owned`
-  --> $DIR/unnecessary_to_owned.rs:72:18
+  --> $DIR/unnecessary_to_owned.rs:73:18
    |
 LL |     require_path(&path.to_owned());
    |                  ^^^^^^^^^^^^^^^^ help: use: `path`
 
 error: unnecessary use of `to_string`
-  --> $DIR/unnecessary_to_owned.rs:74:17
+  --> $DIR/unnecessary_to_owned.rs:75:17
    |
 LL |     require_str(&s.to_string());
    |                 ^^^^^^^^^^^^^^ help: use: `s`
 
 error: unnecessary use of `into_owned`
-  --> $DIR/unnecessary_to_owned.rs:75:30
+  --> $DIR/unnecessary_to_owned.rs:76:30
    |
 LL |     require_str(&Cow::from(s).into_owned());
    |                              ^^^^^^^^^^^^^ help: remove this
 
 error: unnecessary use of `to_owned`
-  --> $DIR/unnecessary_to_owned.rs:76:17
+  --> $DIR/unnecessary_to_owned.rs:77:17
    |
 LL |     require_str(&s.to_owned());
    |                 ^^^^^^^^^^^^^ help: use: `s`
 
 error: unnecessary use of `to_string`
-  --> $DIR/unnecessary_to_owned.rs:77:17
+  --> $DIR/unnecessary_to_owned.rs:78:17
    |
 LL |     require_str(&x_ref.to_string());
    |                 ^^^^^^^^^^^^^^^^^^ help: use: `x_ref.as_ref()`
 
 error: unnecessary use of `to_vec`
-  --> $DIR/unnecessary_to_owned.rs:79:19
+  --> $DIR/unnecessary_to_owned.rs:80:19
    |
 LL |     require_slice(&slice.to_vec());
    |                   ^^^^^^^^^^^^^^^ help: use: `slice`
 
 error: unnecessary use of `into_owned`
-  --> $DIR/unnecessary_to_owned.rs:80:36
+  --> $DIR/unnecessary_to_owned.rs:81:36
    |
 LL |     require_slice(&Cow::from(slice).into_owned());
    |                                    ^^^^^^^^^^^^^ help: remove this
 
 error: unnecessary use of `to_owned`
-  --> $DIR/unnecessary_to_owned.rs:81:19
+  --> $DIR/unnecessary_to_owned.rs:82:19
    |
 LL |     require_slice(&array.to_owned());
    |                   ^^^^^^^^^^^^^^^^^ help: use: `array.as_ref()`
 
 error: unnecessary use of `to_owned`
-  --> $DIR/unnecessary_to_owned.rs:82:19
+  --> $DIR/unnecessary_to_owned.rs:83:19
    |
 LL |     require_slice(&array_ref.to_owned());
    |                   ^^^^^^^^^^^^^^^^^^^^^ help: use: `array_ref.as_ref()`
 
 error: unnecessary use of `to_owned`
-  --> $DIR/unnecessary_to_owned.rs:83:19
+  --> $DIR/unnecessary_to_owned.rs:84:19
    |
 LL |     require_slice(&slice.to_owned());
    |                   ^^^^^^^^^^^^^^^^^ help: use: `slice`
 
 error: unnecessary use of `into_owned`
-  --> $DIR/unnecessary_to_owned.rs:86:42
+  --> $DIR/unnecessary_to_owned.rs:87:42
    |
 LL |     require_x(&Cow::<X>::Owned(x.clone()).into_owned());
    |                                          ^^^^^^^^^^^^^ help: remove this
 
 error: unnecessary use of `to_owned`
-  --> $DIR/unnecessary_to_owned.rs:89:25
+  --> $DIR/unnecessary_to_owned.rs:90:25
    |
 LL |     require_deref_c_str(c_str.to_owned());
    |                         ^^^^^^^^^^^^^^^^ help: use: `c_str`
 
 error: unnecessary use of `to_owned`
-  --> $DIR/unnecessary_to_owned.rs:90:26
+  --> $DIR/unnecessary_to_owned.rs:91:26
    |
 LL |     require_deref_os_str(os_str.to_owned());
    |                          ^^^^^^^^^^^^^^^^^ help: use: `os_str`
 
 error: unnecessary use of `to_owned`
-  --> $DIR/unnecessary_to_owned.rs:91:24
+  --> $DIR/unnecessary_to_owned.rs:92:24
    |
 LL |     require_deref_path(path.to_owned());
    |                        ^^^^^^^^^^^^^^^ help: use: `path`
 
 error: unnecessary use of `to_owned`
-  --> $DIR/unnecessary_to_owned.rs:92:23
+  --> $DIR/unnecessary_to_owned.rs:93:23
    |
 LL |     require_deref_str(s.to_owned());
    |                       ^^^^^^^^^^^^ help: use: `s`
 
 error: unnecessary use of `to_owned`
-  --> $DIR/unnecessary_to_owned.rs:93:25
+  --> $DIR/unnecessary_to_owned.rs:94:25
    |
 LL |     require_deref_slice(slice.to_owned());
    |                         ^^^^^^^^^^^^^^^^ help: use: `slice`
 
 error: unnecessary use of `to_owned`
-  --> $DIR/unnecessary_to_owned.rs:95:30
+  --> $DIR/unnecessary_to_owned.rs:96:30
    |
 LL |     require_impl_deref_c_str(c_str.to_owned());
    |                              ^^^^^^^^^^^^^^^^ help: use: `c_str`
 
 error: unnecessary use of `to_owned`
-  --> $DIR/unnecessary_to_owned.rs:96:31
+  --> $DIR/unnecessary_to_owned.rs:97:31
    |
 LL |     require_impl_deref_os_str(os_str.to_owned());
    |                               ^^^^^^^^^^^^^^^^^ help: use: `os_str`
 
 error: unnecessary use of `to_owned`
-  --> $DIR/unnecessary_to_owned.rs:97:29
+  --> $DIR/unnecessary_to_owned.rs:98:29
    |
 LL |     require_impl_deref_path(path.to_owned());
    |                             ^^^^^^^^^^^^^^^ help: use: `path`
 
 error: unnecessary use of `to_owned`
-  --> $DIR/unnecessary_to_owned.rs:98:28
+  --> $DIR/unnecessary_to_owned.rs:99:28
    |
 LL |     require_impl_deref_str(s.to_owned());
    |                            ^^^^^^^^^^^^ help: use: `s`
 
 error: unnecessary use of `to_owned`
-  --> $DIR/unnecessary_to_owned.rs:99:30
+  --> $DIR/unnecessary_to_owned.rs:100:30
    |
 LL |     require_impl_deref_slice(slice.to_owned());
    |                              ^^^^^^^^^^^^^^^^ help: use: `slice`
 
 error: unnecessary use of `to_owned`
-  --> $DIR/unnecessary_to_owned.rs:101:29
+  --> $DIR/unnecessary_to_owned.rs:102:29
    |
 LL |     require_deref_str_slice(s.to_owned(), slice.to_owned());
    |                             ^^^^^^^^^^^^ help: use: `s`
 
 error: unnecessary use of `to_owned`
-  --> $DIR/unnecessary_to_owned.rs:101:43
+  --> $DIR/unnecessary_to_owned.rs:102:43
    |
 LL |     require_deref_str_slice(s.to_owned(), slice.to_owned());
    |                                           ^^^^^^^^^^^^^^^^ help: use: `slice`
 
 error: unnecessary use of `to_owned`
-  --> $DIR/unnecessary_to_owned.rs:102:29
+  --> $DIR/unnecessary_to_owned.rs:103:29
    |
 LL |     require_deref_slice_str(slice.to_owned(), s.to_owned());
    |                             ^^^^^^^^^^^^^^^^ help: use: `slice`
 
 error: unnecessary use of `to_owned`
-  --> $DIR/unnecessary_to_owned.rs:102:47
+  --> $DIR/unnecessary_to_owned.rs:103:47
    |
 LL |     require_deref_slice_str(slice.to_owned(), s.to_owned());
    |                                               ^^^^^^^^^^^^ help: use: `s`
 
 error: unnecessary use of `to_owned`
-  --> $DIR/unnecessary_to_owned.rs:104:26
+  --> $DIR/unnecessary_to_owned.rs:105:26
    |
 LL |     require_as_ref_c_str(c_str.to_owned());
    |                          ^^^^^^^^^^^^^^^^ help: use: `c_str`
 
 error: unnecessary use of `to_owned`
-  --> $DIR/unnecessary_to_owned.rs:105:27
+  --> $DIR/unnecessary_to_owned.rs:106:27
    |
 LL |     require_as_ref_os_str(os_str.to_owned());
    |                           ^^^^^^^^^^^^^^^^^ help: use: `os_str`
 
 error: unnecessary use of `to_owned`
-  --> $DIR/unnecessary_to_owned.rs:106:25
+  --> $DIR/unnecessary_to_owned.rs:107:25
    |
 LL |     require_as_ref_path(path.to_owned());
    |                         ^^^^^^^^^^^^^^^ help: use: `path`
 
 error: unnecessary use of `to_owned`
-  --> $DIR/unnecessary_to_owned.rs:107:24
+  --> $DIR/unnecessary_to_owned.rs:108:24
    |
 LL |     require_as_ref_str(s.to_owned());
    |                        ^^^^^^^^^^^^ help: use: `s`
 
 error: unnecessary use of `to_owned`
-  --> $DIR/unnecessary_to_owned.rs:108:24
+  --> $DIR/unnecessary_to_owned.rs:109:24
    |
 LL |     require_as_ref_str(x.to_owned());
    |                        ^^^^^^^^^^^^ help: use: `&x`
 
 error: unnecessary use of `to_owned`
-  --> $DIR/unnecessary_to_owned.rs:109:26
+  --> $DIR/unnecessary_to_owned.rs:110:26
    |
 LL |     require_as_ref_slice(array.to_owned());
    |                          ^^^^^^^^^^^^^^^^ help: use: `array`
 
 error: unnecessary use of `to_owned`
-  --> $DIR/unnecessary_to_owned.rs:110:26
+  --> $DIR/unnecessary_to_owned.rs:111:26
    |
 LL |     require_as_ref_slice(array_ref.to_owned());
    |                          ^^^^^^^^^^^^^^^^^^^^ help: use: `array_ref`
 
 error: unnecessary use of `to_owned`
-  --> $DIR/unnecessary_to_owned.rs:111:26
+  --> $DIR/unnecessary_to_owned.rs:112:26
    |
 LL |     require_as_ref_slice(slice.to_owned());
    |                          ^^^^^^^^^^^^^^^^ help: use: `slice`
 
 error: unnecessary use of `to_owned`
-  --> $DIR/unnecessary_to_owned.rs:113:31
+  --> $DIR/unnecessary_to_owned.rs:114:31
    |
 LL |     require_impl_as_ref_c_str(c_str.to_owned());
    |                               ^^^^^^^^^^^^^^^^ help: use: `c_str`
 
 error: unnecessary use of `to_owned`
-  --> $DIR/unnecessary_to_owned.rs:114:32
+  --> $DIR/unnecessary_to_owned.rs:115:32
    |
 LL |     require_impl_as_ref_os_str(os_str.to_owned());
    |                                ^^^^^^^^^^^^^^^^^ help: use: `os_str`
 
 error: unnecessary use of `to_owned`
-  --> $DIR/unnecessary_to_owned.rs:115:30
+  --> $DIR/unnecessary_to_owned.rs:116:30
    |
 LL |     require_impl_as_ref_path(path.to_owned());
    |                              ^^^^^^^^^^^^^^^ help: use: `path`
 
 error: unnecessary use of `to_owned`
-  --> $DIR/unnecessary_to_owned.rs:116:29
+  --> $DIR/unnecessary_to_owned.rs:117:29
    |
 LL |     require_impl_as_ref_str(s.to_owned());
    |                             ^^^^^^^^^^^^ help: use: `s`
 
 error: unnecessary use of `to_owned`
-  --> $DIR/unnecessary_to_owned.rs:117:29
+  --> $DIR/unnecessary_to_owned.rs:118:29
    |
 LL |     require_impl_as_ref_str(x.to_owned());
    |                             ^^^^^^^^^^^^ help: use: `&x`
 
 error: unnecessary use of `to_owned`
-  --> $DIR/unnecessary_to_owned.rs:118:31
+  --> $DIR/unnecessary_to_owned.rs:119:31
    |
 LL |     require_impl_as_ref_slice(array.to_owned());
    |                               ^^^^^^^^^^^^^^^^ help: use: `array`
 
 error: unnecessary use of `to_owned`
-  --> $DIR/unnecessary_to_owned.rs:119:31
+  --> $DIR/unnecessary_to_owned.rs:120:31
    |
 LL |     require_impl_as_ref_slice(array_ref.to_owned());
    |                               ^^^^^^^^^^^^^^^^^^^^ help: use: `array_ref`
 
 error: unnecessary use of `to_owned`
-  --> $DIR/unnecessary_to_owned.rs:120:31
+  --> $DIR/unnecessary_to_owned.rs:121:31
    |
 LL |     require_impl_as_ref_slice(slice.to_owned());
    |                               ^^^^^^^^^^^^^^^^ help: use: `slice`
 
 error: unnecessary use of `to_owned`
-  --> $DIR/unnecessary_to_owned.rs:122:30
+  --> $DIR/unnecessary_to_owned.rs:123:30
    |
 LL |     require_as_ref_str_slice(s.to_owned(), array.to_owned());
    |                              ^^^^^^^^^^^^ help: use: `s`
 
 error: unnecessary use of `to_owned`
-  --> $DIR/unnecessary_to_owned.rs:122:44
+  --> $DIR/unnecessary_to_owned.rs:123:44
    |
 LL |     require_as_ref_str_slice(s.to_owned(), array.to_owned());
    |                                            ^^^^^^^^^^^^^^^^ help: use: `array`
 
 error: unnecessary use of `to_owned`
-  --> $DIR/unnecessary_to_owned.rs:123:30
+  --> $DIR/unnecessary_to_owned.rs:124:30
    |
 LL |     require_as_ref_str_slice(s.to_owned(), array_ref.to_owned());
    |                              ^^^^^^^^^^^^ help: use: `s`
 
 error: unnecessary use of `to_owned`
-  --> $DIR/unnecessary_to_owned.rs:123:44
+  --> $DIR/unnecessary_to_owned.rs:124:44
    |
 LL |     require_as_ref_str_slice(s.to_owned(), array_ref.to_owned());
    |                                            ^^^^^^^^^^^^^^^^^^^^ help: use: `array_ref`
 
 error: unnecessary use of `to_owned`
-  --> $DIR/unnecessary_to_owned.rs:124:30
+  --> $DIR/unnecessary_to_owned.rs:125:30
    |
 LL |     require_as_ref_str_slice(s.to_owned(), slice.to_owned());
    |                              ^^^^^^^^^^^^ help: use: `s`
 
 error: unnecessary use of `to_owned`
-  --> $DIR/unnecessary_to_owned.rs:124:44
+  --> $DIR/unnecessary_to_owned.rs:125:44
    |
 LL |     require_as_ref_str_slice(s.to_owned(), slice.to_owned());
    |                                            ^^^^^^^^^^^^^^^^ help: use: `slice`
 
 error: unnecessary use of `to_owned`
-  --> $DIR/unnecessary_to_owned.rs:125:30
+  --> $DIR/unnecessary_to_owned.rs:126:30
    |
 LL |     require_as_ref_slice_str(array.to_owned(), s.to_owned());
    |                              ^^^^^^^^^^^^^^^^ help: use: `array`
 
 error: unnecessary use of `to_owned`
-  --> $DIR/unnecessary_to_owned.rs:125:48
+  --> $DIR/unnecessary_to_owned.rs:126:48
    |
 LL |     require_as_ref_slice_str(array.to_owned(), s.to_owned());
    |                                                ^^^^^^^^^^^^ help: use: `s`
 
 error: unnecessary use of `to_owned`
-  --> $DIR/unnecessary_to_owned.rs:126:30
+  --> $DIR/unnecessary_to_owned.rs:127:30
    |
 LL |     require_as_ref_slice_str(array_ref.to_owned(), s.to_owned());
    |                              ^^^^^^^^^^^^^^^^^^^^ help: use: `array_ref`
 
 error: unnecessary use of `to_owned`
-  --> $DIR/unnecessary_to_owned.rs:126:52
+  --> $DIR/unnecessary_to_owned.rs:127:52
    |
 LL |     require_as_ref_slice_str(array_ref.to_owned(), s.to_owned());
    |                                                    ^^^^^^^^^^^^ help: use: `s`
 
 error: unnecessary use of `to_owned`
-  --> $DIR/unnecessary_to_owned.rs:127:30
+  --> $DIR/unnecessary_to_owned.rs:128:30
    |
 LL |     require_as_ref_slice_str(slice.to_owned(), s.to_owned());
    |                              ^^^^^^^^^^^^^^^^ help: use: `slice`
 
 error: unnecessary use of `to_owned`
-  --> $DIR/unnecessary_to_owned.rs:127:48
+  --> $DIR/unnecessary_to_owned.rs:128:48
    |
 LL |     require_as_ref_slice_str(slice.to_owned(), s.to_owned());
    |                                                ^^^^^^^^^^^^ help: use: `s`
 
 error: unnecessary use of `to_string`
-  --> $DIR/unnecessary_to_owned.rs:129:20
+  --> $DIR/unnecessary_to_owned.rs:130:20
    |
 LL |     let _ = x.join(&x_ref.to_string());
    |                    ^^^^^^^^^^^^^^^^^^ help: use: `x_ref`
 
 error: unnecessary use of `to_vec`
-  --> $DIR/unnecessary_to_owned.rs:131:13
+  --> $DIR/unnecessary_to_owned.rs:132:13
    |
 LL |     let _ = slice.to_vec().into_iter();
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use: `slice.iter().copied()`
 
 error: unnecessary use of `to_owned`
-  --> $DIR/unnecessary_to_owned.rs:132:13
+  --> $DIR/unnecessary_to_owned.rs:133:13
    |
 LL |     let _ = slice.to_owned().into_iter();
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use: `slice.iter().copied()`
 
 error: unnecessary use of `to_vec`
-  --> $DIR/unnecessary_to_owned.rs:133:13
+  --> $DIR/unnecessary_to_owned.rs:134:13
    |
 LL |     let _ = [std::path::PathBuf::new()][..].to_vec().into_iter();
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use: `[std::path::PathBuf::new()][..].iter().cloned()`
 
 error: unnecessary use of `to_owned`
-  --> $DIR/unnecessary_to_owned.rs:134:13
+  --> $DIR/unnecessary_to_owned.rs:135:13
    |
 LL |     let _ = [std::path::PathBuf::new()][..].to_owned().into_iter();
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use: `[std::path::PathBuf::new()][..].iter().cloned()`
 
 error: unnecessary use of `to_vec`
-  --> $DIR/unnecessary_to_owned.rs:136:13
+  --> $DIR/unnecessary_to_owned.rs:137:13
    |
 LL |     let _ = IntoIterator::into_iter(slice.to_vec());
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use: `slice.iter().copied()`
 
 error: unnecessary use of `to_owned`
-  --> $DIR/unnecessary_to_owned.rs:137:13
+  --> $DIR/unnecessary_to_owned.rs:138:13
    |
 LL |     let _ = IntoIterator::into_iter(slice.to_owned());
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use: `slice.iter().copied()`
 
 error: unnecessary use of `to_vec`
-  --> $DIR/unnecessary_to_owned.rs:138:13
+  --> $DIR/unnecessary_to_owned.rs:139:13
    |
 LL |     let _ = IntoIterator::into_iter([std::path::PathBuf::new()][..].to_vec());
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use: `[std::path::PathBuf::new()][..].iter().cloned()`
 
 error: unnecessary use of `to_owned`
-  --> $DIR/unnecessary_to_owned.rs:139:13
+  --> $DIR/unnecessary_to_owned.rs:140:13
    |
 LL |     let _ = IntoIterator::into_iter([std::path::PathBuf::new()][..].to_owned());
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use: `[std::path::PathBuf::new()][..].iter().cloned()`
 
 error: unnecessary use of `to_vec`
-  --> $DIR/unnecessary_to_owned.rs:201:14
+  --> $DIR/unnecessary_to_owned.rs:202:14
    |
 LL |     for t in file_types.to_vec() {
    |              ^^^^^^^^^^^^^^^^^^^
@@ -494,31 +494,31 @@ LL +         let path = match get_file_path(t) {
    |
 
 error: unnecessary use of `to_vec`
-  --> $DIR/unnecessary_to_owned.rs:224:14
+  --> $DIR/unnecessary_to_owned.rs:225:14
    |
 LL |     let _ = &["x"][..].to_vec().into_iter();
    |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use: `["x"][..].iter().cloned()`
 
 error: unnecessary use of `to_vec`
-  --> $DIR/unnecessary_to_owned.rs:229:14
+  --> $DIR/unnecessary_to_owned.rs:230:14
    |
 LL |     let _ = &["x"][..].to_vec().into_iter();
    |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use: `["x"][..].iter().copied()`
 
 error: unnecessary use of `to_string`
-  --> $DIR/unnecessary_to_owned.rs:276:24
+  --> $DIR/unnecessary_to_owned.rs:278:24
    |
 LL |         Box::new(build(y.to_string()))
    |                        ^^^^^^^^^^^^^ help: use: `y`
 
 error: unnecessary use of `to_string`
-  --> $DIR/unnecessary_to_owned.rs:384:12
+  --> $DIR/unnecessary_to_owned.rs:387:12
    |
 LL |         id("abc".to_string())
    |            ^^^^^^^^^^^^^^^^^ help: use: `"abc"`
 
 error: unnecessary use of `to_vec`
-  --> $DIR/unnecessary_to_owned.rs:527:37
+  --> $DIR/unnecessary_to_owned.rs:530:37
    |
 LL |         IntoFuture::into_future(foo([].to_vec(), &0));
    |                                     ^^^^^^^^^^^ help: use: `[]`
diff --git a/src/tools/clippy/tests/ui/unnecessary_to_owned_on_split.fixed b/src/tools/clippy/tests/ui/unnecessary_to_owned_on_split.fixed
index f87c898f9b7..e0ba216f41b 100644
--- a/src/tools/clippy/tests/ui/unnecessary_to_owned_on_split.fixed
+++ b/src/tools/clippy/tests/ui/unnecessary_to_owned_on_split.fixed
@@ -8,6 +8,7 @@ impl AsRef<str> for Issue12068 {
     }
 }
 
+#[allow(clippy::to_string_trait_impl)]
 impl ToString for Issue12068 {
     fn to_string(&self) -> String {
         String::new()
diff --git a/src/tools/clippy/tests/ui/unnecessary_to_owned_on_split.rs b/src/tools/clippy/tests/ui/unnecessary_to_owned_on_split.rs
index db5719e5880..70efc6ebba5 100644
--- a/src/tools/clippy/tests/ui/unnecessary_to_owned_on_split.rs
+++ b/src/tools/clippy/tests/ui/unnecessary_to_owned_on_split.rs
@@ -8,6 +8,7 @@ impl AsRef<str> for Issue12068 {
     }
 }
 
+#[allow(clippy::to_string_trait_impl)]
 impl ToString for Issue12068 {
     fn to_string(&self) -> String {
         String::new()
diff --git a/src/tools/clippy/tests/ui/unnecessary_to_owned_on_split.stderr b/src/tools/clippy/tests/ui/unnecessary_to_owned_on_split.stderr
index 4cfaeed3384..9aea15b48bf 100644
--- a/src/tools/clippy/tests/ui/unnecessary_to_owned_on_split.stderr
+++ b/src/tools/clippy/tests/ui/unnecessary_to_owned_on_split.stderr
@@ -1,5 +1,5 @@
 error: unnecessary use of `to_string`
-  --> $DIR/unnecessary_to_owned_on_split.rs:18:13
+  --> $DIR/unnecessary_to_owned_on_split.rs:19:13
    |
 LL |     let _ = "a".to_string().split('a').next().unwrap();
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use: `"a".split('a')`
@@ -8,49 +8,49 @@ LL |     let _ = "a".to_string().split('a').next().unwrap();
    = help: to override `-D warnings` add `#[allow(clippy::unnecessary_to_owned)]`
 
 error: unnecessary use of `to_string`
-  --> $DIR/unnecessary_to_owned_on_split.rs:20:13
+  --> $DIR/unnecessary_to_owned_on_split.rs:21:13
    |
 LL |     let _ = "a".to_string().split("a").next().unwrap();
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use: `"a".split("a")`
 
 error: unnecessary use of `to_owned`
-  --> $DIR/unnecessary_to_owned_on_split.rs:22:13
+  --> $DIR/unnecessary_to_owned_on_split.rs:23:13
    |
 LL |     let _ = "a".to_owned().split('a').next().unwrap();
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^ help: use: `"a".split('a')`
 
 error: unnecessary use of `to_owned`
-  --> $DIR/unnecessary_to_owned_on_split.rs:24:13
+  --> $DIR/unnecessary_to_owned_on_split.rs:25:13
    |
 LL |     let _ = "a".to_owned().split("a").next().unwrap();
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^ help: use: `"a".split("a")`
 
 error: unnecessary use of `to_string`
-  --> $DIR/unnecessary_to_owned_on_split.rs:26:13
+  --> $DIR/unnecessary_to_owned_on_split.rs:27:13
    |
 LL |     let _ = Issue12068.to_string().split('a').next().unwrap();
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use: `Issue12068.as_ref().split('a')`
 
 error: unnecessary use of `to_vec`
-  --> $DIR/unnecessary_to_owned_on_split.rs:29:13
+  --> $DIR/unnecessary_to_owned_on_split.rs:30:13
    |
 LL |     let _ = [1].to_vec().split(|x| *x == 2).next().unwrap();
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use: `[1].split(|x| *x == 2)`
 
 error: unnecessary use of `to_vec`
-  --> $DIR/unnecessary_to_owned_on_split.rs:31:13
+  --> $DIR/unnecessary_to_owned_on_split.rs:32:13
    |
 LL |     let _ = [1].to_vec().split(|x| *x == 2).next().unwrap();
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use: `[1].split(|x| *x == 2)`
 
 error: unnecessary use of `to_owned`
-  --> $DIR/unnecessary_to_owned_on_split.rs:33:13
+  --> $DIR/unnecessary_to_owned_on_split.rs:34:13
    |
 LL |     let _ = [1].to_owned().split(|x| *x == 2).next().unwrap();
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use: `[1].split(|x| *x == 2)`
 
 error: unnecessary use of `to_owned`
-  --> $DIR/unnecessary_to_owned_on_split.rs:35:13
+  --> $DIR/unnecessary_to_owned_on_split.rs:36:13
    |
 LL |     let _ = [1].to_owned().split(|x| *x == 2).next().unwrap();
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use: `[1].split(|x| *x == 2)`
diff --git a/src/tools/clippy/tests/ui/unused_io_amount.rs b/src/tools/clippy/tests/ui/unused_io_amount.rs
index 9974600dad5..7e5a10c911b 100644
--- a/src/tools/clippy/tests/ui/unused_io_amount.rs
+++ b/src/tools/clippy/tests/ui/unused_io_amount.rs
@@ -229,4 +229,47 @@ fn on_return_should_not_raise<T: io::Read + io::Write>(s: &mut T) -> io::Result<
     s.read(&mut buf)
 }
 
+pub fn unwrap_in_block(rdr: &mut dyn std::io::Read) -> std::io::Result<usize> {
+    let read = { rdr.read(&mut [0])? };
+    Ok(read)
+}
+
+pub fn consumed_example(rdr: &mut dyn std::io::Read) {
+    match rdr.read(&mut [0]) {
+        Ok(0) => println!("EOF"),
+        Ok(_) => println!("fully read"),
+        Err(_) => println!("fail"),
+    };
+    match rdr.read(&mut [0]) {
+        Ok(0) => println!("EOF"),
+        Ok(_) => println!("fully read"),
+        Err(_) => println!("fail"),
+    }
+}
+
+pub fn unreachable_or_panic(rdr: &mut dyn std::io::Read) {
+    {
+        match rdr.read(&mut [0]) {
+            Ok(_) => unreachable!(),
+            Err(_) => println!("expected"),
+        }
+    }
+
+    {
+        match rdr.read(&mut [0]) {
+            Ok(_) => panic!(),
+            Err(_) => println!("expected"),
+        }
+    }
+}
+
+pub fn wildcards(rdr: &mut dyn std::io::Read) {
+    {
+        match rdr.read(&mut [0]) {
+            Ok(1) => todo!(),
+            _ => todo!(),
+        }
+    }
+}
+
 fn main() {}
diff --git a/src/tools/clippy/tests/ui/unused_io_amount.stderr b/src/tools/clippy/tests/ui/unused_io_amount.stderr
index 4af56d264bf..1aab56966a8 100644
--- a/src/tools/clippy/tests/ui/unused_io_amount.stderr
+++ b/src/tools/clippy/tests/ui/unused_io_amount.stderr
@@ -180,7 +180,7 @@ note: the result is consumed here, but the amount of I/O bytes remains unhandled
   --> $DIR/unused_io_amount.rs:149:9
    |
 LL |         Ok(_) => todo!(),
-   |         ^^^^^^^^^^^^^^^^
+   |         ^^^^^
 
 error: read amount is not handled
   --> $DIR/unused_io_amount.rs:155:11
@@ -193,7 +193,7 @@ note: the result is consumed here, but the amount of I/O bytes remains unhandled
   --> $DIR/unused_io_amount.rs:157:9
    |
 LL |         Ok(_) => todo!(),
-   |         ^^^^^^^^^^^^^^^^
+   |         ^^^^^
 
 error: read amount is not handled
   --> $DIR/unused_io_amount.rs:164:11
@@ -206,7 +206,7 @@ note: the result is consumed here, but the amount of I/O bytes remains unhandled
   --> $DIR/unused_io_amount.rs:166:9
    |
 LL |         Ok(_) => todo!(),
-   |         ^^^^^^^^^^^^^^^^
+   |         ^^^^^
 
 error: written amount is not handled
   --> $DIR/unused_io_amount.rs:173:11
@@ -219,7 +219,7 @@ note: the result is consumed here, but the amount of I/O bytes remains unhandled
   --> $DIR/unused_io_amount.rs:175:9
    |
 LL |         Ok(_) => todo!(),
-   |         ^^^^^^^^^^^^^^^^
+   |         ^^^^^
 
 error: read amount is not handled
   --> $DIR/unused_io_amount.rs:186:8
diff --git a/src/tools/clippy/tests/ui/while_let_on_iterator.fixed b/src/tools/clippy/tests/ui/while_let_on_iterator.fixed
index d628d2227b7..59b5c858d04 100644
--- a/src/tools/clippy/tests/ui/while_let_on_iterator.fixed
+++ b/src/tools/clippy/tests/ui/while_let_on_iterator.fixed
@@ -406,7 +406,7 @@ fn issue_8113() {
 fn fn_once_closure() {
     let mut it = 0..10;
     (|| {
-        for x in it {
+        for x in it.by_ref() {
             if x % 2 == 0 {
                 break;
             }
@@ -441,7 +441,19 @@ fn fn_once_closure() {
                 break;
             }
         }
-    })
+    });
+
+    trait MySpecialFnMut: FnOnce() {}
+    impl<T: FnOnce()> MySpecialFnMut for T {}
+    fn f4(_: impl MySpecialFnMut) {}
+    let mut it = 0..10;
+    f4(|| {
+        for x in it {
+            if x % 2 == 0 {
+                break;
+            }
+        }
+    });
 }
 
 fn main() {
diff --git a/src/tools/clippy/tests/ui/while_let_on_iterator.rs b/src/tools/clippy/tests/ui/while_let_on_iterator.rs
index 525dbbaaab6..559513d5694 100644
--- a/src/tools/clippy/tests/ui/while_let_on_iterator.rs
+++ b/src/tools/clippy/tests/ui/while_let_on_iterator.rs
@@ -441,7 +441,19 @@ fn fn_once_closure() {
                 break;
             }
         }
-    })
+    });
+
+    trait MySpecialFnMut: FnOnce() {}
+    impl<T: FnOnce()> MySpecialFnMut for T {}
+    fn f4(_: impl MySpecialFnMut) {}
+    let mut it = 0..10;
+    f4(|| {
+        while let Some(x) = it.next() {
+            if x % 2 == 0 {
+                break;
+            }
+        }
+    });
 }
 
 fn main() {
diff --git a/src/tools/clippy/tests/ui/while_let_on_iterator.stderr b/src/tools/clippy/tests/ui/while_let_on_iterator.stderr
index cdc83b81667..7b9a9dc049a 100644
--- a/src/tools/clippy/tests/ui/while_let_on_iterator.stderr
+++ b/src/tools/clippy/tests/ui/while_let_on_iterator.stderr
@@ -131,7 +131,7 @@ error: this loop could be written as a `for` loop
   --> $DIR/while_let_on_iterator.rs:409:9
    |
 LL |         while let Some(x) = it.next() {
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `for x in it`
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `for x in it.by_ref()`
 
 error: this loop could be written as a `for` loop
   --> $DIR/while_let_on_iterator.rs:419:9
@@ -152,10 +152,16 @@ LL |         while let Some(x) = it.next() {
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `for x in it`
 
 error: this loop could be written as a `for` loop
-  --> $DIR/while_let_on_iterator.rs:449:5
+  --> $DIR/while_let_on_iterator.rs:451:9
+   |
+LL |         while let Some(x) = it.next() {
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `for x in it`
+
+error: this loop could be written as a `for` loop
+  --> $DIR/while_let_on_iterator.rs:461:5
    |
 LL |     while let Some(..) = it.next() {
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `for _ in it`
 
-error: aborting due to 26 previous errors
+error: aborting due to 27 previous errors