diff --git a/Cargo.lock b/Cargo.lock
index 21902888e88..9fa6e1d51d2 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -627,7 +627,7 @@ dependencies = [
 
 [[package]]
 name = "clippy"
-version = "0.1.62"
+version = "0.1.63"
 dependencies = [
  "clippy_lints",
  "clippy_utils",
@@ -647,6 +647,7 @@ dependencies = [
  "serde",
  "syn",
  "tempfile",
+ "termize",
  "tester",
  "tokio",
 ]
@@ -667,7 +668,7 @@ dependencies = [
 
 [[package]]
 name = "clippy_lints"
-version = "0.1.62"
+version = "0.1.63"
 dependencies = [
  "cargo_metadata",
  "clippy_utils",
@@ -688,7 +689,7 @@ dependencies = [
 
 [[package]]
 name = "clippy_utils"
-version = "0.1.62"
+version = "0.1.63"
 dependencies = [
  "arrayvec",
  "if_chain",
diff --git a/src/tools/clippy/.github/deploy.sh b/src/tools/clippy/.github/deploy.sh
index 34225a54029..5a59f94ec91 100644
--- a/src/tools/clippy/.github/deploy.sh
+++ b/src/tools/clippy/.github/deploy.sh
@@ -8,6 +8,7 @@ rm -rf out/master/ || exit 0
 echo "Making the docs for master"
 mkdir out/master/
 cp util/gh-pages/index.html out/master
+cp util/gh-pages/script.js out/master
 cp util/gh-pages/lints.json out/master
 
 if [[ -n $TAG_NAME ]]; then
diff --git a/src/tools/clippy/CHANGELOG.md b/src/tools/clippy/CHANGELOG.md
index d25ad0ac6fa..10ef00fcbaf 100644
--- a/src/tools/clippy/CHANGELOG.md
+++ b/src/tools/clippy/CHANGELOG.md
@@ -8,9 +8,9 @@ document.
 
 [d0cf3481...master](https://github.com/rust-lang/rust-clippy/compare/d0cf3481...master)
 
-## Rust 1.61 (beta)
+## Rust 1.61
 
-Current beta, released 2022-05-19
+Current stable, released 2022-05-19
 
 [57b3c4b...d0cf3481](https://github.com/rust-lang/rust-clippy/compare/57b3c4b...d0cf3481)
 
@@ -111,7 +111,7 @@ Current beta, released 2022-05-19
 
 ## Rust 1.60
 
-Current stable, released 2022-04-07
+Released 2022-04-07
 
 [0eff589...57b3c4b](https://github.com/rust-lang/rust-clippy/compare/0eff589...57b3c4b)
 
@@ -3290,6 +3290,8 @@ Released 2018-09-13
 [`bind_instead_of_map`]: https://rust-lang.github.io/rust-clippy/master/index.html#bind_instead_of_map
 [`blacklisted_name`]: https://rust-lang.github.io/rust-clippy/master/index.html#blacklisted_name
 [`blanket_clippy_restriction_lints`]: https://rust-lang.github.io/rust-clippy/master/index.html#blanket_clippy_restriction_lints
+[`block_in_if_condition_expr`]: https://rust-lang.github.io/rust-clippy/master/index.html#block_in_if_condition_expr
+[`block_in_if_condition_stmt`]: https://rust-lang.github.io/rust-clippy/master/index.html#block_in_if_condition_stmt
 [`blocks_in_if_conditions`]: https://rust-lang.github.io/rust-clippy/master/index.html#blocks_in_if_conditions
 [`bool_assert_comparison`]: https://rust-lang.github.io/rust-clippy/master/index.html#bool_assert_comparison
 [`bool_comparison`]: https://rust-lang.github.io/rust-clippy/master/index.html#bool_comparison
@@ -3297,6 +3299,7 @@ Released 2018-09-13
 [`borrow_interior_mutable_const`]: https://rust-lang.github.io/rust-clippy/master/index.html#borrow_interior_mutable_const
 [`borrowed_box`]: https://rust-lang.github.io/rust-clippy/master/index.html#borrowed_box
 [`box_collection`]: https://rust-lang.github.io/rust-clippy/master/index.html#box_collection
+[`box_vec`]: https://rust-lang.github.io/rust-clippy/master/index.html#box_vec
 [`boxed_local`]: https://rust-lang.github.io/rust-clippy/master/index.html#boxed_local
 [`branches_sharing_code`]: https://rust-lang.github.io/rust-clippy/master/index.html#branches_sharing_code
 [`builtin_type_shadow`]: https://rust-lang.github.io/rust-clippy/master/index.html#builtin_type_shadow
@@ -3332,10 +3335,12 @@ Released 2018-09-13
 [`collapsible_match`]: https://rust-lang.github.io/rust-clippy/master/index.html#collapsible_match
 [`comparison_chain`]: https://rust-lang.github.io/rust-clippy/master/index.html#comparison_chain
 [`comparison_to_empty`]: https://rust-lang.github.io/rust-clippy/master/index.html#comparison_to_empty
+[`const_static_lifetime`]: https://rust-lang.github.io/rust-clippy/master/index.html#const_static_lifetime
 [`copy_iterator`]: https://rust-lang.github.io/rust-clippy/master/index.html#copy_iterator
 [`crate_in_macro_def`]: https://rust-lang.github.io/rust-clippy/master/index.html#crate_in_macro_def
 [`create_dir`]: https://rust-lang.github.io/rust-clippy/master/index.html#create_dir
 [`crosspointer_transmute`]: https://rust-lang.github.io/rust-clippy/master/index.html#crosspointer_transmute
+[`cyclomatic_complexity`]: https://rust-lang.github.io/rust-clippy/master/index.html#cyclomatic_complexity
 [`dbg_macro`]: https://rust-lang.github.io/rust-clippy/master/index.html#dbg_macro
 [`debug_assert_with_mut_call`]: https://rust-lang.github.io/rust-clippy/master/index.html#debug_assert_with_mut_call
 [`decimal_literal_representation`]: https://rust-lang.github.io/rust-clippy/master/index.html#decimal_literal_representation
@@ -3350,8 +3355,11 @@ Released 2018-09-13
 [`derivable_impls`]: https://rust-lang.github.io/rust-clippy/master/index.html#derivable_impls
 [`derive_hash_xor_eq`]: https://rust-lang.github.io/rust-clippy/master/index.html#derive_hash_xor_eq
 [`derive_ord_xor_partial_ord`]: https://rust-lang.github.io/rust-clippy/master/index.html#derive_ord_xor_partial_ord
+[`derive_partial_eq_without_eq`]: https://rust-lang.github.io/rust-clippy/master/index.html#derive_partial_eq_without_eq
+[`disallowed_method`]: https://rust-lang.github.io/rust-clippy/master/index.html#disallowed_method
 [`disallowed_methods`]: https://rust-lang.github.io/rust-clippy/master/index.html#disallowed_methods
 [`disallowed_script_idents`]: https://rust-lang.github.io/rust-clippy/master/index.html#disallowed_script_idents
+[`disallowed_type`]: https://rust-lang.github.io/rust-clippy/master/index.html#disallowed_type
 [`disallowed_types`]: https://rust-lang.github.io/rust-clippy/master/index.html#disallowed_types
 [`diverging_sub_expression`]: https://rust-lang.github.io/rust-clippy/master/index.html#diverging_sub_expression
 [`doc_markdown`]: https://rust-lang.github.io/rust-clippy/master/index.html#doc_markdown
@@ -3359,9 +3367,11 @@ Released 2018-09-13
 [`double_must_use`]: https://rust-lang.github.io/rust-clippy/master/index.html#double_must_use
 [`double_neg`]: https://rust-lang.github.io/rust-clippy/master/index.html#double_neg
 [`double_parens`]: https://rust-lang.github.io/rust-clippy/master/index.html#double_parens
+[`drop_bounds`]: https://rust-lang.github.io/rust-clippy/master/index.html#drop_bounds
 [`drop_copy`]: https://rust-lang.github.io/rust-clippy/master/index.html#drop_copy
 [`drop_non_drop`]: https://rust-lang.github.io/rust-clippy/master/index.html#drop_non_drop
 [`drop_ref`]: https://rust-lang.github.io/rust-clippy/master/index.html#drop_ref
+[`duplicate_mod`]: https://rust-lang.github.io/rust-clippy/master/index.html#duplicate_mod
 [`duplicate_underscore_argument`]: https://rust-lang.github.io/rust-clippy/master/index.html#duplicate_underscore_argument
 [`duration_subsec`]: https://rust-lang.github.io/rust-clippy/master/index.html#duration_subsec
 [`else_if_without_else`]: https://rust-lang.github.io/rust-clippy/master/index.html#else_if_without_else
@@ -3413,6 +3423,8 @@ Released 2018-09-13
 [`fn_to_numeric_cast_any`]: https://rust-lang.github.io/rust-clippy/master/index.html#fn_to_numeric_cast_any
 [`fn_to_numeric_cast_with_truncation`]: https://rust-lang.github.io/rust-clippy/master/index.html#fn_to_numeric_cast_with_truncation
 [`for_kv_map`]: https://rust-lang.github.io/rust-clippy/master/index.html#for_kv_map
+[`for_loop_over_option`]: https://rust-lang.github.io/rust-clippy/master/index.html#for_loop_over_option
+[`for_loop_over_result`]: https://rust-lang.github.io/rust-clippy/master/index.html#for_loop_over_result
 [`for_loops_over_fallibles`]: https://rust-lang.github.io/rust-clippy/master/index.html#for_loops_over_fallibles
 [`forget_copy`]: https://rust-lang.github.io/rust-clippy/master/index.html#forget_copy
 [`forget_non_drop`]: https://rust-lang.github.io/rust-clippy/master/index.html#forget_non_drop
@@ -3425,9 +3437,11 @@ Released 2018-09-13
 [`future_not_send`]: https://rust-lang.github.io/rust-clippy/master/index.html#future_not_send
 [`get_last_with_len`]: https://rust-lang.github.io/rust-clippy/master/index.html#get_last_with_len
 [`get_unwrap`]: https://rust-lang.github.io/rust-clippy/master/index.html#get_unwrap
+[`identity_conversion`]: https://rust-lang.github.io/rust-clippy/master/index.html#identity_conversion
 [`identity_op`]: https://rust-lang.github.io/rust-clippy/master/index.html#identity_op
 [`if_let_mutex`]: https://rust-lang.github.io/rust-clippy/master/index.html#if_let_mutex
 [`if_let_redundant_pattern_matching`]: https://rust-lang.github.io/rust-clippy/master/index.html#if_let_redundant_pattern_matching
+[`if_let_some_result`]: https://rust-lang.github.io/rust-clippy/master/index.html#if_let_some_result
 [`if_not_else`]: https://rust-lang.github.io/rust-clippy/master/index.html#if_not_else
 [`if_same_then_else`]: https://rust-lang.github.io/rust-clippy/master/index.html#if_same_then_else
 [`if_then_some_else_none`]: https://rust-lang.github.io/rust-clippy/master/index.html#if_then_some_else_none
@@ -3456,8 +3470,11 @@ Released 2018-09-13
 [`int_plus_one`]: https://rust-lang.github.io/rust-clippy/master/index.html#int_plus_one
 [`integer_arithmetic`]: https://rust-lang.github.io/rust-clippy/master/index.html#integer_arithmetic
 [`integer_division`]: https://rust-lang.github.io/rust-clippy/master/index.html#integer_division
+[`into_iter_on_array`]: https://rust-lang.github.io/rust-clippy/master/index.html#into_iter_on_array
 [`into_iter_on_ref`]: https://rust-lang.github.io/rust-clippy/master/index.html#into_iter_on_ref
+[`invalid_atomic_ordering`]: https://rust-lang.github.io/rust-clippy/master/index.html#invalid_atomic_ordering
 [`invalid_null_ptr_usage`]: https://rust-lang.github.io/rust-clippy/master/index.html#invalid_null_ptr_usage
+[`invalid_ref`]: https://rust-lang.github.io/rust-clippy/master/index.html#invalid_ref
 [`invalid_regex`]: https://rust-lang.github.io/rust-clippy/master/index.html#invalid_regex
 [`invalid_upcast_comparisons`]: https://rust-lang.github.io/rust-clippy/master/index.html#invalid_upcast_comparisons
 [`invisible_characters`]: https://rust-lang.github.io/rust-clippy/master/index.html#invisible_characters
@@ -3531,6 +3548,7 @@ Released 2018-09-13
 [`match_wild_err_arm`]: https://rust-lang.github.io/rust-clippy/master/index.html#match_wild_err_arm
 [`match_wildcard_for_single_variants`]: https://rust-lang.github.io/rust-clippy/master/index.html#match_wildcard_for_single_variants
 [`maybe_infinite_iter`]: https://rust-lang.github.io/rust-clippy/master/index.html#maybe_infinite_iter
+[`mem_discriminant_non_enum`]: https://rust-lang.github.io/rust-clippy/master/index.html#mem_discriminant_non_enum
 [`mem_forget`]: https://rust-lang.github.io/rust-clippy/master/index.html#mem_forget
 [`mem_replace_option_with_none`]: https://rust-lang.github.io/rust-clippy/master/index.html#mem_replace_option_with_none
 [`mem_replace_with_default`]: https://rust-lang.github.io/rust-clippy/master/index.html#mem_replace_with_default
@@ -3549,6 +3567,7 @@ Released 2018-09-13
 [`missing_spin_loop`]: https://rust-lang.github.io/rust-clippy/master/index.html#missing_spin_loop
 [`mistyped_literal_suffixes`]: https://rust-lang.github.io/rust-clippy/master/index.html#mistyped_literal_suffixes
 [`mixed_case_hex_literals`]: https://rust-lang.github.io/rust-clippy/master/index.html#mixed_case_hex_literals
+[`mixed_read_write_in_expression`]: https://rust-lang.github.io/rust-clippy/master/index.html#mixed_read_write_in_expression
 [`mod_module_files`]: https://rust-lang.github.io/rust-clippy/master/index.html#mod_module_files
 [`module_inception`]: https://rust-lang.github.io/rust-clippy/master/index.html#module_inception
 [`module_name_repetitions`]: https://rust-lang.github.io/rust-clippy/master/index.html#module_name_repetitions
@@ -3592,6 +3611,7 @@ Released 2018-09-13
 [`never_loop`]: https://rust-lang.github.io/rust-clippy/master/index.html#never_loop
 [`new_ret_no_self`]: https://rust-lang.github.io/rust-clippy/master/index.html#new_ret_no_self
 [`new_without_default`]: https://rust-lang.github.io/rust-clippy/master/index.html#new_without_default
+[`new_without_default_derive`]: https://rust-lang.github.io/rust-clippy/master/index.html#new_without_default_derive
 [`no_effect`]: https://rust-lang.github.io/rust-clippy/master/index.html#no_effect
 [`no_effect_underscore_binding`]: https://rust-lang.github.io/rust-clippy/master/index.html#no_effect_underscore_binding
 [`non_ascii_literal`]: https://rust-lang.github.io/rust-clippy/master/index.html#non_ascii_literal
@@ -3605,19 +3625,25 @@ Released 2018-09-13
 [`ok_expect`]: https://rust-lang.github.io/rust-clippy/master/index.html#ok_expect
 [`only_used_in_recursion`]: https://rust-lang.github.io/rust-clippy/master/index.html#only_used_in_recursion
 [`op_ref`]: https://rust-lang.github.io/rust-clippy/master/index.html#op_ref
+[`option_and_then_some`]: https://rust-lang.github.io/rust-clippy/master/index.html#option_and_then_some
 [`option_as_ref_deref`]: https://rust-lang.github.io/rust-clippy/master/index.html#option_as_ref_deref
 [`option_env_unwrap`]: https://rust-lang.github.io/rust-clippy/master/index.html#option_env_unwrap
+[`option_expect_used`]: https://rust-lang.github.io/rust-clippy/master/index.html#option_expect_used
 [`option_filter_map`]: https://rust-lang.github.io/rust-clippy/master/index.html#option_filter_map
 [`option_if_let_else`]: https://rust-lang.github.io/rust-clippy/master/index.html#option_if_let_else
 [`option_map_or_none`]: https://rust-lang.github.io/rust-clippy/master/index.html#option_map_or_none
 [`option_map_unit_fn`]: https://rust-lang.github.io/rust-clippy/master/index.html#option_map_unit_fn
+[`option_map_unwrap_or`]: https://rust-lang.github.io/rust-clippy/master/index.html#option_map_unwrap_or
+[`option_map_unwrap_or_else`]: https://rust-lang.github.io/rust-clippy/master/index.html#option_map_unwrap_or_else
 [`option_option`]: https://rust-lang.github.io/rust-clippy/master/index.html#option_option
+[`option_unwrap_used`]: https://rust-lang.github.io/rust-clippy/master/index.html#option_unwrap_used
 [`or_fun_call`]: https://rust-lang.github.io/rust-clippy/master/index.html#or_fun_call
 [`or_then_unwrap`]: https://rust-lang.github.io/rust-clippy/master/index.html#or_then_unwrap
 [`out_of_bounds_indexing`]: https://rust-lang.github.io/rust-clippy/master/index.html#out_of_bounds_indexing
 [`overflow_check_conditional`]: https://rust-lang.github.io/rust-clippy/master/index.html#overflow_check_conditional
 [`panic`]: https://rust-lang.github.io/rust-clippy/master/index.html#panic
 [`panic_in_result_fn`]: https://rust-lang.github.io/rust-clippy/master/index.html#panic_in_result_fn
+[`panic_params`]: https://rust-lang.github.io/rust-clippy/master/index.html#panic_params
 [`panicking_unwrap`]: https://rust-lang.github.io/rust-clippy/master/index.html#panicking_unwrap
 [`partialeq_ne_impl`]: https://rust-lang.github.io/rust-clippy/master/index.html#partialeq_ne_impl
 [`path_buf_push_overwrite`]: https://rust-lang.github.io/rust-clippy/master/index.html#path_buf_push_overwrite
@@ -3642,6 +3668,7 @@ Released 2018-09-13
 [`range_step_by_zero`]: https://rust-lang.github.io/rust-clippy/master/index.html#range_step_by_zero
 [`range_zip_with_len`]: https://rust-lang.github.io/rust-clippy/master/index.html#range_zip_with_len
 [`rc_buffer`]: https://rust-lang.github.io/rust-clippy/master/index.html#rc_buffer
+[`rc_clone_in_vec_init`]: https://rust-lang.github.io/rust-clippy/master/index.html#rc_clone_in_vec_init
 [`rc_mutex`]: https://rust-lang.github.io/rust-clippy/master/index.html#rc_mutex
 [`recursive_format_impl`]: https://rust-lang.github.io/rust-clippy/master/index.html#recursive_format_impl
 [`redundant_allocation`]: https://rust-lang.github.io/rust-clippy/master/index.html#redundant_allocation
@@ -3658,14 +3685,18 @@ 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
 [`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
 [`regex_macro`]: https://rust-lang.github.io/rust-clippy/master/index.html#regex_macro
 [`repeat_once`]: https://rust-lang.github.io/rust-clippy/master/index.html#repeat_once
 [`replace_consts`]: https://rust-lang.github.io/rust-clippy/master/index.html#replace_consts
 [`rest_pat_in_fully_bound_structs`]: https://rust-lang.github.io/rust-clippy/master/index.html#rest_pat_in_fully_bound_structs
+[`result_expect_used`]: https://rust-lang.github.io/rust-clippy/master/index.html#result_expect_used
 [`result_map_or_into_option`]: https://rust-lang.github.io/rust-clippy/master/index.html#result_map_or_into_option
 [`result_map_unit_fn`]: https://rust-lang.github.io/rust-clippy/master/index.html#result_map_unit_fn
+[`result_map_unwrap_or_else`]: https://rust-lang.github.io/rust-clippy/master/index.html#result_map_unwrap_or_else
 [`result_unit_err`]: https://rust-lang.github.io/rust-clippy/master/index.html#result_unit_err
+[`result_unwrap_used`]: https://rust-lang.github.io/rust-clippy/master/index.html#result_unwrap_used
 [`return_self_not_must_use`]: https://rust-lang.github.io/rust-clippy/master/index.html#return_self_not_must_use
 [`reversed_empty_ranges`]: https://rust-lang.github.io/rust-clippy/master/index.html#reversed_empty_ranges
 [`same_functions_in_if_condition`]: https://rust-lang.github.io/rust-clippy/master/index.html#same_functions_in_if_condition
@@ -3684,10 +3715,12 @@ Released 2018-09-13
 [`short_circuit_statement`]: https://rust-lang.github.io/rust-clippy/master/index.html#short_circuit_statement
 [`should_assert_eq`]: https://rust-lang.github.io/rust-clippy/master/index.html#should_assert_eq
 [`should_implement_trait`]: https://rust-lang.github.io/rust-clippy/master/index.html#should_implement_trait
+[`significant_drop_in_scrutinee`]: https://rust-lang.github.io/rust-clippy/master/index.html#significant_drop_in_scrutinee
 [`similar_names`]: https://rust-lang.github.io/rust-clippy/master/index.html#similar_names
 [`single_char_add_str`]: https://rust-lang.github.io/rust-clippy/master/index.html#single_char_add_str
 [`single_char_lifetime_names`]: https://rust-lang.github.io/rust-clippy/master/index.html#single_char_lifetime_names
 [`single_char_pattern`]: https://rust-lang.github.io/rust-clippy/master/index.html#single_char_pattern
+[`single_char_push_str`]: https://rust-lang.github.io/rust-clippy/master/index.html#single_char_push_str
 [`single_component_path_imports`]: https://rust-lang.github.io/rust-clippy/master/index.html#single_component_path_imports
 [`single_element_loop`]: https://rust-lang.github.io/rust-clippy/master/index.html#single_element_loop
 [`single_match`]: https://rust-lang.github.io/rust-clippy/master/index.html#single_match
@@ -3707,6 +3740,7 @@ Released 2018-09-13
 [`string_to_string`]: https://rust-lang.github.io/rust-clippy/master/index.html#string_to_string
 [`strlen_on_c_strings`]: https://rust-lang.github.io/rust-clippy/master/index.html#strlen_on_c_strings
 [`struct_excessive_bools`]: https://rust-lang.github.io/rust-clippy/master/index.html#struct_excessive_bools
+[`stutter`]: https://rust-lang.github.io/rust-clippy/master/index.html#stutter
 [`suboptimal_flops`]: https://rust-lang.github.io/rust-clippy/master/index.html#suboptimal_flops
 [`suspicious_arithmetic_impl`]: https://rust-lang.github.io/rust-clippy/master/index.html#suspicious_arithmetic_impl
 [`suspicious_assignment_formatting`]: https://rust-lang.github.io/rust-clippy/master/index.html#suspicious_assignment_formatting
@@ -3718,7 +3752,9 @@ Released 2018-09-13
 [`suspicious_unary_op_formatting`]: https://rust-lang.github.io/rust-clippy/master/index.html#suspicious_unary_op_formatting
 [`tabs_in_doc_comments`]: https://rust-lang.github.io/rust-clippy/master/index.html#tabs_in_doc_comments
 [`temporary_assignment`]: https://rust-lang.github.io/rust-clippy/master/index.html#temporary_assignment
+[`temporary_cstring_as_ptr`]: https://rust-lang.github.io/rust-clippy/master/index.html#temporary_cstring_as_ptr
 [`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
 [`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
@@ -3753,6 +3789,7 @@ Released 2018-09-13
 [`unit_cmp`]: https://rust-lang.github.io/rust-clippy/master/index.html#unit_cmp
 [`unit_hash`]: https://rust-lang.github.io/rust-clippy/master/index.html#unit_hash
 [`unit_return_expecting_ord`]: https://rust-lang.github.io/rust-clippy/master/index.html#unit_return_expecting_ord
+[`unknown_clippy_lints`]: https://rust-lang.github.io/rust-clippy/master/index.html#unknown_clippy_lints
 [`unnecessary_cast`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_cast
 [`unnecessary_filter_map`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_filter_map
 [`unnecessary_find_map`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_find_map
@@ -3782,6 +3819,7 @@ Released 2018-09-13
 [`unused_async`]: https://rust-lang.github.io/rust-clippy/master/index.html#unused_async
 [`unused_collect`]: https://rust-lang.github.io/rust-clippy/master/index.html#unused_collect
 [`unused_io_amount`]: https://rust-lang.github.io/rust-clippy/master/index.html#unused_io_amount
+[`unused_label`]: https://rust-lang.github.io/rust-clippy/master/index.html#unused_label
 [`unused_self`]: https://rust-lang.github.io/rust-clippy/master/index.html#unused_self
 [`unused_unit`]: https://rust-lang.github.io/rust-clippy/master/index.html#unused_unit
 [`unusual_byte_groupings`]: https://rust-lang.github.io/rust-clippy/master/index.html#unusual_byte_groupings
@@ -3822,5 +3860,6 @@ Released 2018-09-13
 [`zero_prefixed_literal`]: https://rust-lang.github.io/rust-clippy/master/index.html#zero_prefixed_literal
 [`zero_ptr`]: https://rust-lang.github.io/rust-clippy/master/index.html#zero_ptr
 [`zero_sized_map_values`]: https://rust-lang.github.io/rust-clippy/master/index.html#zero_sized_map_values
+[`zero_width_space`]: https://rust-lang.github.io/rust-clippy/master/index.html#zero_width_space
 [`zst_offset`]: https://rust-lang.github.io/rust-clippy/master/index.html#zst_offset
 <!-- end autogenerated links to lint list -->
diff --git a/src/tools/clippy/CONTRIBUTING.md b/src/tools/clippy/CONTRIBUTING.md
index fc663de8f79..6ab2bd59137 100644
--- a/src/tools/clippy/CONTRIBUTING.md
+++ b/src/tools/clippy/CONTRIBUTING.md
@@ -67,9 +67,9 @@ and resolved paths.
 
 [`T-AST`] issues will generally need you to match against a predefined syntax structure.
 To figure out how this syntax structure is encoded in the AST, it is recommended to run
-`rustc -Z ast-json` on an example of the structure and compare with the [nodes in the AST docs].
+`rustc -Z unpretty=ast-tree` on an example of the structure and compare with the [nodes in the AST docs].
 Usually the lint will end up to be a nested series of matches and ifs, [like so][deep-nesting].
-But we can make it nest-less by using [if_chain] macro, [like this][nest-less].
+But we can make it nest-less by using [let chains], [like this][nest-less].
 
 [`E-medium`] issues are generally pretty easy too, though it's recommended you work on an [`good-first-issue`]
 first. Sometimes they are only somewhat involved code wise, but not difficult per-se.
@@ -87,9 +87,9 @@ an AST expression). `match_def_path()` in Clippy's `utils` module can also be us
 [`E-medium`]: https://github.com/rust-lang/rust-clippy/labels/E-medium
 [`ty`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty
 [nodes in the AST docs]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_ast/ast/
-[deep-nesting]: https://github.com/rust-lang/rust-clippy/blob/557f6848bd5b7183f55c1e1522a326e9e1df6030/clippy_lints/src/mem_forget.rs#L29-L43
-[if_chain]: https://docs.rs/if_chain/*/if_chain
-[nest-less]: https://github.com/rust-lang/rust-clippy/blob/557f6848bd5b7183f55c1e1522a326e9e1df6030/clippy_lints/src/bit_mask.rs#L124-L150
+[deep-nesting]: https://github.com/rust-lang/rust-clippy/blob/5e4f0922911536f80d9591180fa604229ac13939/clippy_lints/src/mem_forget.rs#L31-L45
+[let chains]: https://github.com/rust-lang/rust/pull/94927
+[nest-less]: https://github.com/rust-lang/rust-clippy/blob/5e4f0922911536f80d9591180fa604229ac13939/clippy_lints/src/bit_mask.rs#L133-L159
 
 ## Writing code
 
diff --git a/src/tools/clippy/Cargo.toml b/src/tools/clippy/Cargo.toml
index dd6518d5241..373e720b0d5 100644
--- a/src/tools/clippy/Cargo.toml
+++ b/src/tools/clippy/Cargo.toml
@@ -1,6 +1,6 @@
 [package]
 name = "clippy"
-version = "0.1.62"
+version = "0.1.63"
 description = "A bunch of helpful lints to avoid common pitfalls in Rust"
 repository = "https://github.com/rust-lang/rust-clippy"
 readme = "README.md"
@@ -25,6 +25,7 @@ clippy_lints = { path = "clippy_lints" }
 semver = "1.0"
 rustc_tools_util = { path = "rustc_tools_util" }
 tempfile = { version = "3.2", optional = true }
+termize = "0.1"
 
 [dev-dependencies]
 compiletest_rs = { version = "0.7.1", features = ["tmp"] }
diff --git a/src/tools/clippy/clippy_dev/src/lint.rs b/src/tools/clippy/clippy_dev/src/lint.rs
index 1bc1a39542d..9e463aa741c 100644
--- a/src/tools/clippy/clippy_dev/src/lint.rs
+++ b/src/tools/clippy/clippy_dev/src/lint.rs
@@ -13,7 +13,7 @@ fn exit_if_err(status: io::Result<ExitStatus>) {
     }
 }
 
-pub fn run(path: &str) {
+pub fn run<'a>(path: &str, args: impl Iterator<Item = &'a str>) {
     let is_file = match fs::metadata(path) {
         Ok(metadata) => metadata.is_file(),
         Err(e) => {
@@ -30,6 +30,7 @@ pub fn run(path: &str) {
                 .args(["-Z", "no-codegen"])
                 .args(["--edition", "2021"])
                 .arg(path)
+                .args(args)
                 .status(),
         );
     } else {
@@ -42,6 +43,8 @@ pub fn run(path: &str) {
             .expect("failed to create tempdir");
 
         let status = Command::new(cargo_clippy_path())
+            .arg("clippy")
+            .args(args)
             .current_dir(path)
             .env("CARGO_TARGET_DIR", target.as_ref())
             .status();
diff --git a/src/tools/clippy/clippy_dev/src/main.rs b/src/tools/clippy/clippy_dev/src/main.rs
index ebf8f38d490..d5cd7ca96c0 100644
--- a/src/tools/clippy/clippy_dev/src/main.rs
+++ b/src/tools/clippy/clippy_dev/src/main.rs
@@ -76,7 +76,8 @@ fn main() {
         },
         ("lint", Some(matches)) => {
             let path = matches.value_of("path").unwrap();
-            lint::run(path);
+            let args = matches.values_of("args").into_iter().flatten();
+            lint::run(path, args);
         },
         ("rename_lint", Some(matches)) => {
             let old_name = matches.value_of("old_name").unwrap();
@@ -123,7 +124,7 @@ fn get_clap_config<'a>() -> ArgMatches<'a> {
                  * the lint count in README.md is correct\n \
                  * the changelog contains markdown link references at the bottom\n \
                  * all lint groups include the correct lints\n \
-                 * lint modules in `clippy_lints/*` are visible in `src/lifb.rs` via `pub mod`\n \
+                 * lint modules in `clippy_lints/*` are visible in `src/lib.rs` via `pub mod`\n \
                  * all lints are registered in the lint store",
                 )
                 .arg(Arg::with_name("print-only").long("print-only").help(
@@ -278,11 +279,23 @@ fn get_clap_config<'a>() -> ArgMatches<'a> {
                         Lint a package directory:
                             cargo dev lint tests/ui-cargo/wildcard_dependencies/fail
                             cargo dev lint ~/my-project
+
+                        Run rustfix:
+                            cargo dev lint ~/my-project -- --fix
+
+                        Set lint levels:
+                            cargo dev lint file.rs -- -W clippy::pedantic
+                            cargo dev lint ~/my-project -- -- -W clippy::pedantic
                 "})
                 .arg(
                     Arg::with_name("path")
                         .required(true)
                         .help("The path to a file or package directory to lint"),
+                )
+                .arg(
+                    Arg::with_name("args")
+                        .multiple(true)
+                        .help("Pass extra arguments to cargo/clippy-driver"),
                 ),
         )
         .subcommand(
diff --git a/src/tools/clippy/clippy_dev/src/new_lint.rs b/src/tools/clippy/clippy_dev/src/new_lint.rs
index 10f67d301f8..07d19638788 100644
--- a/src/tools/clippy/clippy_dev/src/new_lint.rs
+++ b/src/tools/clippy/clippy_dev/src/new_lint.rs
@@ -133,7 +133,7 @@ fn to_camel_case(name: &str) -> String {
         .collect()
 }
 
-fn get_stabilisation_version() -> String {
+fn get_stabilization_version() -> String {
     fn parse_manifest(contents: &str) -> Option<String> {
         let version = contents
             .lines()
@@ -199,7 +199,7 @@ fn get_lint_file_contents(lint: &LintData<'_>, enable_msrv: bool) -> String {
         },
     };
 
-    let version = get_stabilisation_version();
+    let version = get_stabilization_version();
     let lint_name = lint.name;
     let category = lint.category;
     let name_camel = to_camel_case(lint.name);
diff --git a/src/tools/clippy/clippy_dev/src/update_lints.rs b/src/tools/clippy/clippy_dev/src/update_lints.rs
index 1a6a4336da2..5024e63bfa7 100644
--- a/src/tools/clippy/clippy_dev/src/update_lints.rs
+++ b/src/tools/clippy/clippy_dev/src/update_lints.rs
@@ -17,7 +17,7 @@ const GENERATED_FILE_COMMENT: &str = "// This file was generated by `cargo dev u
 
 const DOCS_LINK: &str = "https://rust-lang.github.io/rust-clippy/master/index.html";
 
-#[derive(Clone, Copy, PartialEq)]
+#[derive(Clone, Copy, PartialEq, Eq)]
 pub enum UpdateMode {
     Check,
     Change,
@@ -66,8 +66,13 @@ fn generate_lint_files(
         |res| {
             for lint in usable_lints
                 .iter()
-                .map(|l| &l.name)
-                .chain(deprecated_lints.iter().map(|l| &l.name))
+                .map(|l| &*l.name)
+                .chain(deprecated_lints.iter().map(|l| &*l.name))
+                .chain(
+                    renamed_lints
+                        .iter()
+                        .map(|l| l.old_name.strip_prefix("clippy::").unwrap_or(&l.old_name)),
+                )
                 .sorted()
             {
                 writeln!(res, "[`{}`]: {}#{}", lint, DOCS_LINK, lint).unwrap();
@@ -372,7 +377,7 @@ fn exit_with_failure() {
 }
 
 /// Lint data parsed from the Clippy source code.
-#[derive(Clone, PartialEq, Debug)]
+#[derive(Clone, PartialEq, Eq, Debug)]
 struct Lint {
     name: String,
     group: String,
@@ -414,7 +419,7 @@ impl Lint {
     }
 }
 
-#[derive(Clone, PartialEq, Debug)]
+#[derive(Clone, PartialEq, Eq, Debug)]
 struct DeprecatedLint {
     name: String,
     reason: String,
diff --git a/src/tools/clippy/clippy_lints/Cargo.toml b/src/tools/clippy/clippy_lints/Cargo.toml
index aebf9a87cab..0a3f04da357 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.62"
+version = "0.1.63"
 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/approx_const.rs b/src/tools/clippy/clippy_lints/src/approx_const.rs
index e109ee0009e..da1b646f477 100644
--- a/src/tools/clippy/clippy_lints/src/approx_const.rs
+++ b/src/tools/clippy/clippy_lints/src/approx_const.rs
@@ -87,9 +87,7 @@ impl ApproxConstant {
         let s = s.as_str();
         if s.parse::<f64>().is_ok() {
             for &(constant, name, min_digits, msrv) in &KNOWN_CONSTS {
-                if is_approx_const(constant, s, min_digits)
-                    && msrv.as_ref().map_or(true, |msrv| meets_msrv(self.msrv.as_ref(), msrv))
-                {
+                if is_approx_const(constant, s, min_digits) && msrv.map_or(true, |msrv| meets_msrv(self.msrv, msrv)) {
                     span_lint_and_help(
                         cx,
                         APPROX_CONSTANT,
diff --git a/src/tools/clippy/clippy_lints/src/assign_ops.rs b/src/tools/clippy/clippy_lints/src/assign_ops.rs
index 12c1bddf79d..4c2d3366483 100644
--- a/src/tools/clippy/clippy_lints/src/assign_ops.rs
+++ b/src/tools/clippy/clippy_lints/src/assign_ops.rs
@@ -50,7 +50,7 @@ declare_clippy_lint! {
     /// ### Known problems
     /// Clippy cannot know for sure if `a op= a op b` should have
     /// been `a = a op a op b` or `a = a op b`/`a op= b`. Therefore, it suggests both.
-    /// If `a op= a op b` is really the correct behaviour it should be
+    /// If `a op= a op b` is really the correct behavior it should be
     /// written as `a = a op a op b` as it's less confusing.
     ///
     /// ### Example
diff --git a/src/tools/clippy/clippy_lints/src/attrs.rs b/src/tools/clippy/clippy_lints/src/attrs.rs
index 8b0e11cb802..3de91f3d24a 100644
--- a/src/tools/clippy/clippy_lints/src/attrs.rs
+++ b/src/tools/clippy/clippy_lints/src/attrs.rs
@@ -6,7 +6,7 @@ use clippy_utils::msrvs;
 use clippy_utils::source::{first_line_of_span, is_present_in_source, snippet_opt, without_block_comments};
 use clippy_utils::{extract_msrv_attr, meets_msrv};
 use if_chain::if_chain;
-use rustc_ast::{AttrKind, AttrStyle, Attribute, Lit, LitKind, MacArgs, MacArgsEq, MetaItemKind, NestedMetaItem};
+use rustc_ast::{AttrKind, AttrStyle, Attribute, Lit, LitKind, MetaItemKind, NestedMetaItem};
 use rustc_errors::Applicability;
 use rustc_hir::{
     Block, Expr, ExprKind, ImplItem, ImplItemKind, Item, ItemKind, StmtKind, TraitFn, TraitItem, TraitItemKind,
@@ -586,21 +586,10 @@ impl EarlyLintPass for EarlyAttributes {
 
 fn check_empty_line_after_outer_attr(cx: &EarlyContext<'_>, item: &rustc_ast::Item) {
     for attr in &item.attrs {
-        let attr_item = if let AttrKind::Normal(ref attr, _) = attr.kind {
-            attr
-        } else {
-            return;
-        };
-
-        if attr.style == AttrStyle::Outer {
-            if let MacArgs::Eq(_, MacArgsEq::Ast(expr)) = &attr_item.args
-                && !matches!(expr.kind, rustc_ast::ExprKind::Lit(..)) {
-                return;
-            }
-            if attr_item.args.inner_tokens().is_empty() || !is_present_in_source(cx, attr.span) {
-                return;
-            }
-
+        if matches!(attr.kind, AttrKind::Normal(..))
+            && attr.style == AttrStyle::Outer
+            && is_present_in_source(cx, attr.span)
+        {
             let begin_of_attr_to_item = Span::new(attr.span.lo(), item.span.lo(), item.span.ctxt(), item.span.parent());
             let end_of_attr_to_item = Span::new(attr.span.hi(), item.span.lo(), item.span.ctxt(), item.span.parent());
 
@@ -624,7 +613,7 @@ fn check_empty_line_after_outer_attr(cx: &EarlyContext<'_>, item: &rustc_ast::It
 
 fn check_deprecated_cfg_attr(cx: &EarlyContext<'_>, attr: &Attribute, msrv: Option<RustcVersion>) {
     if_chain! {
-        if meets_msrv(msrv.as_ref(), &msrvs::TOOL_ATTRIBUTES);
+        if meets_msrv(msrv, msrvs::TOOL_ATTRIBUTES);
         // check cfg_attr
         if attr.has_name(sym::cfg_attr);
         if let Some(items) = attr.meta_item_list();
diff --git a/src/tools/clippy/clippy_lints/src/bit_mask.rs b/src/tools/clippy/clippy_lints/src/bit_mask.rs
index ca4af66cad1..dc7e400fdc2 100644
--- a/src/tools/clippy/clippy_lints/src/bit_mask.rs
+++ b/src/tools/clippy/clippy_lints/src/bit_mask.rs
@@ -1,7 +1,6 @@
 use clippy_utils::consts::{constant, Constant};
 use clippy_utils::diagnostics::{span_lint, span_lint_and_then};
 use clippy_utils::sugg::Sugg;
-use if_chain::if_chain;
 use rustc_ast::ast::LitKind;
 use rustc_errors::Applicability;
 use rustc_hir::{BinOpKind, Expr, ExprKind};
@@ -130,23 +129,24 @@ impl<'tcx> LateLintPass<'tcx> for BitMask {
                 }
             }
         }
-        if_chain! {
-            if let ExprKind::Binary(op, left, right) = &e.kind;
-            if BinOpKind::Eq == op.node;
-            if let ExprKind::Binary(op1, left1, right1) = &left.kind;
-            if BinOpKind::BitAnd == op1.node;
-            if let ExprKind::Lit(lit) = &right1.kind;
-            if let LitKind::Int(n, _) = lit.node;
-            if let ExprKind::Lit(lit1) = &right.kind;
-            if let LitKind::Int(0, _) = lit1.node;
-            if n.leading_zeros() == n.count_zeros();
-            if n > u128::from(self.verbose_bit_mask_threshold);
-            then {
-                span_lint_and_then(cx,
-                                   VERBOSE_BIT_MASK,
-                                   e.span,
-                                   "bit mask could be simplified with a call to `trailing_zeros`",
-                                   |diag| {
+
+        if let ExprKind::Binary(op, left, right) = &e.kind
+            && BinOpKind::Eq == op.node
+            && let ExprKind::Binary(op1, left1, right1) = &left.kind
+            && BinOpKind::BitAnd == op1.node
+            && let ExprKind::Lit(lit) = &right1.kind
+            && let LitKind::Int(n, _) = lit.node
+            && let ExprKind::Lit(lit1) = &right.kind
+            && let LitKind::Int(0, _) = lit1.node
+            && n.leading_zeros() == n.count_zeros()
+            && n > u128::from(self.verbose_bit_mask_threshold)
+        {
+            span_lint_and_then(
+                cx,
+                VERBOSE_BIT_MASK,
+                e.span,
+                "bit mask could be simplified with a call to `trailing_zeros`",
+                |diag| {
                     let sugg = Sugg::hir(cx, left1, "...").maybe_par();
                     diag.span_suggestion(
                         e.span,
@@ -154,8 +154,8 @@ impl<'tcx> LateLintPass<'tcx> for BitMask {
                         format!("{}.trailing_zeros() >= {}", sugg, n.count_ones()),
                         Applicability::MaybeIncorrect,
                     );
-                });
-            }
+                },
+            );
         }
     }
 }
diff --git a/src/tools/clippy/clippy_lints/src/booleans.rs b/src/tools/clippy/clippy_lints/src/booleans.rs
index f7449c8dc72..0adb6327164 100644
--- a/src/tools/clippy/clippy_lints/src/booleans.rs
+++ b/src/tools/clippy/clippy_lints/src/booleans.rs
@@ -137,7 +137,7 @@ impl<'a, 'tcx, 'v> Hir2Qmm<'a, 'tcx, 'v> {
         }
         for (n, expr) in self.terminals.iter().enumerate() {
             if eq_expr_value(self.cx, e, expr) {
-                #[allow(clippy::cast_possible_truncation)]
+                #[expect(clippy::cast_possible_truncation)]
                 return Ok(Bool::Term(n as u8));
             }
 
@@ -149,7 +149,7 @@ impl<'a, 'tcx, 'v> Hir2Qmm<'a, 'tcx, 'v> {
                 if eq_expr_value(self.cx, e_lhs, expr_lhs);
                 if eq_expr_value(self.cx, e_rhs, expr_rhs);
                 then {
-                    #[allow(clippy::cast_possible_truncation)]
+                    #[expect(clippy::cast_possible_truncation)]
                     return Ok(Bool::Not(Box::new(Bool::Term(n as u8))));
                 }
             }
@@ -157,7 +157,7 @@ impl<'a, 'tcx, 'v> Hir2Qmm<'a, 'tcx, 'v> {
         let n = self.terminals.len();
         self.terminals.push(e);
         if n < 32 {
-            #[allow(clippy::cast_possible_truncation)]
+            #[expect(clippy::cast_possible_truncation)]
             Ok(Bool::Term(n as u8))
         } else {
             Err("too many literals".to_owned())
diff --git a/src/tools/clippy/clippy_lints/src/borrow_as_ptr.rs b/src/tools/clippy/clippy_lints/src/borrow_as_ptr.rs
index 9f8eb488c29..0993adbae2e 100644
--- a/src/tools/clippy/clippy_lints/src/borrow_as_ptr.rs
+++ b/src/tools/clippy/clippy_lints/src/borrow_as_ptr.rs
@@ -57,7 +57,7 @@ impl BorrowAsPtr {
 
 impl<'tcx> LateLintPass<'tcx> for BorrowAsPtr {
     fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
-        if !meets_msrv(self.msrv.as_ref(), &msrvs::BORROW_AS_PTR) {
+        if !meets_msrv(self.msrv, msrvs::BORROW_AS_PTR) {
             return;
         }
 
diff --git a/src/tools/clippy/clippy_lints/src/casts/cast_abs_to_unsigned.rs b/src/tools/clippy/clippy_lints/src/casts/cast_abs_to_unsigned.rs
index e9b0f1f672d..6bac6bf83f8 100644
--- a/src/tools/clippy/clippy_lints/src/casts/cast_abs_to_unsigned.rs
+++ b/src/tools/clippy/clippy_lints/src/casts/cast_abs_to_unsigned.rs
@@ -16,10 +16,10 @@ pub(super) fn check(
     cast_expr: &Expr<'_>,
     cast_from: Ty<'_>,
     cast_to: Ty<'_>,
-    msrv: &Option<RustcVersion>,
+    msrv: Option<RustcVersion>,
 ) {
     if_chain! {
-        if meets_msrv(msrv.as_ref(), &msrvs::UNSIGNED_ABS);
+        if meets_msrv(msrv, msrvs::UNSIGNED_ABS);
         if cast_from.is_integral();
         if cast_to.is_integral();
         if cast_from.is_signed();
diff --git a/src/tools/clippy/clippy_lints/src/casts/cast_lossless.rs b/src/tools/clippy/clippy_lints/src/casts/cast_lossless.rs
index 4a95bed1148..938458e30ca 100644
--- a/src/tools/clippy/clippy_lints/src/casts/cast_lossless.rs
+++ b/src/tools/clippy/clippy_lints/src/casts/cast_lossless.rs
@@ -16,7 +16,7 @@ pub(super) fn check(
     cast_op: &Expr<'_>,
     cast_from: Ty<'_>,
     cast_to: Ty<'_>,
-    msrv: &Option<RustcVersion>,
+    msrv: Option<RustcVersion>,
 ) {
     if !should_lint(cx, expr, cast_from, cast_to, msrv) {
         return;
@@ -68,7 +68,7 @@ fn should_lint(
     expr: &Expr<'_>,
     cast_from: Ty<'_>,
     cast_to: Ty<'_>,
-    msrv: &Option<RustcVersion>,
+    msrv: Option<RustcVersion>,
 ) -> bool {
     // Do not suggest using From in consts/statics until it is valid to do so (see #2267).
     if in_constant(cx, expr.hir_id) {
@@ -93,9 +93,9 @@ fn should_lint(
             } else {
                 64
             };
-            from_nbits < to_nbits
+            !is_isize_or_usize(cast_from) && from_nbits < to_nbits
         },
-        (false, true) if matches!(cast_from.kind(), ty::Bool) && meets_msrv(msrv.as_ref(), &msrvs::FROM_BOOL) => true,
+        (false, true) if matches!(cast_from.kind(), ty::Bool) && meets_msrv(msrv, msrvs::FROM_BOOL) => true,
         (_, _) => {
             matches!(cast_from.kind(), ty::Float(FloatTy::F32)) && matches!(cast_to.kind(), ty::Float(FloatTy::F64))
         },
diff --git a/src/tools/clippy/clippy_lints/src/casts/cast_slice_different_sizes.rs b/src/tools/clippy/clippy_lints/src/casts/cast_slice_different_sizes.rs
index 2238668abca..027c660ce3b 100644
--- a/src/tools/clippy/clippy_lints/src/casts/cast_slice_different_sizes.rs
+++ b/src/tools/clippy/clippy_lints/src/casts/cast_slice_different_sizes.rs
@@ -8,9 +8,9 @@ use rustc_semver::RustcVersion;
 
 use super::CAST_SLICE_DIFFERENT_SIZES;
 
-pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'tcx>, msrv: &Option<RustcVersion>) {
+pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'tcx>, msrv: Option<RustcVersion>) {
     // suggestion is invalid if `ptr::slice_from_raw_parts` does not exist
-    if !meets_msrv(msrv.as_ref(), &msrvs::PTR_SLICE_RAW_PARTS) {
+    if !meets_msrv(msrv, msrvs::PTR_SLICE_RAW_PARTS) {
         return;
     }
 
@@ -121,7 +121,7 @@ fn expr_cast_chain_tys<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'tcx>) -> Optio
         let to_slice_ty = get_raw_slice_ty_mut(cast_to)?;
 
         // If the expression that makes up the source of this cast is itself a cast, recursively
-        // call `expr_cast_chain_tys` and update the end type with the final tartet type.
+        // call `expr_cast_chain_tys` and update the end type with the final target type.
         // Otherwise, this cast is not immediately nested, just construct the info for this cast
         if let Some(prev_info) = expr_cast_chain_tys(cx, cast_expr) {
             Some(CastChainInfo {
diff --git a/src/tools/clippy/clippy_lints/src/casts/mod.rs b/src/tools/clippy/clippy_lints/src/casts/mod.rs
index b58252dcb94..daf3b7b4ce4 100644
--- a/src/tools/clippy/clippy_lints/src/casts/mod.rs
+++ b/src/tools/clippy/clippy_lints/src/casts/mod.rs
@@ -306,7 +306,7 @@ declare_clippy_lint! {
     /// Checks for casts of `&T` to `&mut T` anywhere in the code.
     ///
     /// ### Why is this bad?
-    /// It’s basically guaranteed to be undefined behaviour.
+    /// It’s basically guaranteed to be undefined behavior.
     /// `UnsafeCell` is the only way to obtain aliasable data that is considered
     /// mutable.
     ///
@@ -413,6 +413,7 @@ declare_clippy_lint! {
 }
 
 declare_clippy_lint! {
+    /// ### What it does
     /// Checks for `as` casts between raw pointers to slices with differently sized elements.
     ///
     /// ### Why is this bad?
@@ -531,7 +532,7 @@ impl_lint_pass!(Casts => [
 impl<'tcx> LateLintPass<'tcx> for Casts {
     fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
         if !in_external_macro(cx.sess(), expr.span) {
-            ptr_as_ptr::check(cx, expr, &self.msrv);
+            ptr_as_ptr::check(cx, expr, self.msrv);
         }
 
         if expr.span.from_expansion() {
@@ -561,9 +562,9 @@ impl<'tcx> LateLintPass<'tcx> for Casts {
                     cast_possible_wrap::check(cx, expr, cast_from, cast_to);
                     cast_precision_loss::check(cx, expr, cast_from, cast_to);
                     cast_sign_loss::check(cx, expr, cast_expr, cast_from, cast_to);
-                    cast_abs_to_unsigned::check(cx, expr, cast_expr, cast_from, cast_to, &self.msrv);
+                    cast_abs_to_unsigned::check(cx, expr, cast_expr, cast_from, cast_to, self.msrv);
                 }
-                cast_lossless::check(cx, expr, cast_expr, cast_from, cast_to, &self.msrv);
+                cast_lossless::check(cx, expr, cast_expr, cast_from, cast_to, self.msrv);
                 cast_enum_constructor::check(cx, expr, cast_expr, cast_from);
             }
         }
@@ -571,8 +572,8 @@ impl<'tcx> LateLintPass<'tcx> for Casts {
         cast_ref_to_mut::check(cx, expr);
         cast_ptr_alignment::check(cx, expr);
         char_lit_as_u8::check(cx, expr);
-        ptr_as_ptr::check(cx, expr, &self.msrv);
-        cast_slice_different_sizes::check(cx, expr, &self.msrv);
+        ptr_as_ptr::check(cx, expr, self.msrv);
+        cast_slice_different_sizes::check(cx, expr, self.msrv);
     }
 
     extract_msrv_attr!(LateContext);
diff --git a/src/tools/clippy/clippy_lints/src/casts/ptr_as_ptr.rs b/src/tools/clippy/clippy_lints/src/casts/ptr_as_ptr.rs
index fb04f93fbcf..46d45d09661 100644
--- a/src/tools/clippy/clippy_lints/src/casts/ptr_as_ptr.rs
+++ b/src/tools/clippy/clippy_lints/src/casts/ptr_as_ptr.rs
@@ -12,8 +12,8 @@ use rustc_semver::RustcVersion;
 
 use super::PTR_AS_PTR;
 
-pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, msrv: &Option<RustcVersion>) {
-    if !meets_msrv(msrv.as_ref(), &msrvs::POINTER_CAST) {
+pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, msrv: Option<RustcVersion>) {
+    if !meets_msrv(msrv, msrvs::POINTER_CAST) {
         return;
     }
 
diff --git a/src/tools/clippy/clippy_lints/src/checked_conversions.rs b/src/tools/clippy/clippy_lints/src/checked_conversions.rs
index 31cc3698592..7eeaaa01921 100644
--- a/src/tools/clippy/clippy_lints/src/checked_conversions.rs
+++ b/src/tools/clippy/clippy_lints/src/checked_conversions.rs
@@ -30,7 +30,6 @@ declare_clippy_lint! {
     /// Could be written:
     ///
     /// ```rust
-    /// # use std::convert::TryFrom;
     /// # let foo = 1;
     /// # let _ =
     /// i32::try_from(foo).is_ok()
@@ -57,7 +56,7 @@ impl_lint_pass!(CheckedConversions => [CHECKED_CONVERSIONS]);
 
 impl<'tcx> LateLintPass<'tcx> for CheckedConversions {
     fn check_expr(&mut self, cx: &LateContext<'_>, item: &Expr<'_>) {
-        if !meets_msrv(self.msrv.as_ref(), &msrvs::TRY_FROM) {
+        if !meets_msrv(self.msrv, msrvs::TRY_FROM) {
             return;
         }
 
@@ -123,7 +122,7 @@ struct Conversion<'a> {
 }
 
 /// The kind of conversion that is checked
-#[derive(Copy, Clone, Debug, PartialEq)]
+#[derive(Copy, Clone, Debug, PartialEq, Eq)]
 enum ConversionType {
     SignedToUnsigned,
     SignedToSigned,
diff --git a/src/tools/clippy/clippy_lints/src/cognitive_complexity.rs b/src/tools/clippy/clippy_lints/src/cognitive_complexity.rs
index 2bf7f868905..317c4bfb322 100644
--- a/src/tools/clippy/clippy_lints/src/cognitive_complexity.rs
+++ b/src/tools/clippy/clippy_lints/src/cognitive_complexity.rs
@@ -48,7 +48,7 @@ impl CognitiveComplexity {
 impl_lint_pass!(CognitiveComplexity => [COGNITIVE_COMPLEXITY]);
 
 impl CognitiveComplexity {
-    #[allow(clippy::cast_possible_truncation)]
+    #[expect(clippy::cast_possible_truncation)]
     fn check<'tcx>(
         &mut self,
         cx: &LateContext<'tcx>,
@@ -70,7 +70,7 @@ impl CognitiveComplexity {
         let ret_adjust = if is_type_diagnostic_item(cx, ret_ty, sym::Result) {
             returns
         } else {
-            #[allow(clippy::integer_division)]
+            #[expect(clippy::integer_division)]
             (returns / 2)
         };
 
diff --git a/src/tools/clippy/clippy_lints/src/collapsible_match.rs b/src/tools/clippy/clippy_lints/src/collapsible_match.rs
index 826eb0ae6b1..ec55009f347 100644
--- a/src/tools/clippy/clippy_lints/src/collapsible_match.rs
+++ b/src/tools/clippy/clippy_lints/src/collapsible_match.rs
@@ -109,7 +109,10 @@ fn check_arm<'tcx>(
             (Some(a), Some(b)) => SpanlessEq::new(cx).eq_expr(a, b),
         };
         // the binding must not be used in the if guard
-        if outer_guard.map_or(true, |(Guard::If(e) | Guard::IfLet(Let { init: e, .. }))| !is_local_used(cx, *e, binding_id));
+        if outer_guard.map_or(
+            true,
+            |(Guard::If(e) | Guard::IfLet(Let { init: e, .. }))| !is_local_used(cx, *e, binding_id)
+        );
         // ...or anywhere in the inner expression
         if match inner {
             IfLetOrMatch::IfLet(_, _, body, els) => {
diff --git a/src/tools/clippy/clippy_lints/src/dbg_macro.rs b/src/tools/clippy/clippy_lints/src/dbg_macro.rs
index a0e5d302633..f99d793c201 100644
--- a/src/tools/clippy/clippy_lints/src/dbg_macro.rs
+++ b/src/tools/clippy/clippy_lints/src/dbg_macro.rs
@@ -1,7 +1,7 @@
 use clippy_utils::diagnostics::span_lint_and_sugg;
-use clippy_utils::is_in_test_function;
 use clippy_utils::macros::root_macro_call_first_node;
 use clippy_utils::source::snippet_with_applicability;
+use clippy_utils::{is_in_cfg_test, is_in_test_function};
 use rustc_errors::Applicability;
 use rustc_hir::{Expr, ExprKind};
 use rustc_lint::{LateContext, LateLintPass};
@@ -37,7 +37,7 @@ impl LateLintPass<'_> for DbgMacro {
         let Some(macro_call) = root_macro_call_first_node(cx, expr) else { return };
         if cx.tcx.is_diagnostic_item(sym::dbg_macro, macro_call.def_id) {
             // we make an exception for test code
-            if is_in_test_function(cx.tcx, expr.hir_id) {
+            if is_in_test_function(cx.tcx, expr.hir_id) || is_in_cfg_test(cx.tcx, expr.hir_id) {
                 return;
             }
             let mut applicability = Applicability::MachineApplicable;
diff --git a/src/tools/clippy/clippy_lints/src/default.rs b/src/tools/clippy/clippy_lints/src/default.rs
index f7e4bc24321..243dfd3a461 100644
--- a/src/tools/clippy/clippy_lints/src/default.rs
+++ b/src/tools/clippy/clippy_lints/src/default.rs
@@ -110,7 +110,7 @@ impl<'tcx> LateLintPass<'tcx> for Default {
         }
     }
 
-    #[allow(clippy::too_many_lines)]
+    #[expect(clippy::too_many_lines)]
     fn check_block(&mut self, cx: &LateContext<'tcx>, block: &Block<'tcx>) {
         // start from the `let mut _ = _::default();` and look at all the following
         // statements, see if they re-assign the fields of the binding
diff --git a/src/tools/clippy/clippy_lints/src/default_numeric_fallback.rs b/src/tools/clippy/clippy_lints/src/default_numeric_fallback.rs
index f3996e5b44d..3d9f9ed41ce 100644
--- a/src/tools/clippy/clippy_lints/src/default_numeric_fallback.rs
+++ b/src/tools/clippy/clippy_lints/src/default_numeric_fallback.rs
@@ -116,7 +116,6 @@ impl<'a, 'tcx> NumericFallbackVisitor<'a, 'tcx> {
 }
 
 impl<'a, 'tcx> Visitor<'tcx> for NumericFallbackVisitor<'a, 'tcx> {
-    #[allow(clippy::too_many_lines)]
     fn visit_expr(&mut self, expr: &'tcx Expr<'_>) {
         match &expr.kind {
             ExprKind::Call(func, args) => {
diff --git a/src/tools/clippy/clippy_lints/src/default_union_representation.rs b/src/tools/clippy/clippy_lints/src/default_union_representation.rs
index 9b5da0bd8a6..d559ad423df 100644
--- a/src/tools/clippy/clippy_lints/src/default_union_representation.rs
+++ b/src/tools/clippy/clippy_lints/src/default_union_representation.rs
@@ -25,7 +25,7 @@ declare_clippy_lint! {
     ///
     /// fn main() {
     ///     let _x: u32 = unsafe {
-    ///         Foo { a: 0_i32 }.b // Undefined behaviour: `b` is allowed to be padding
+    ///         Foo { a: 0_i32 }.b // Undefined behavior: `b` is allowed to be padding
     ///     };
     /// }
     /// ```
@@ -39,7 +39,7 @@ declare_clippy_lint! {
     ///
     /// fn main() {
     ///     let _x: u32 = unsafe {
-    ///         Foo { a: 0_i32 }.b // Now defined behaviour, this is just an i32 -> u32 transmute
+    ///         Foo { a: 0_i32 }.b // Now defined behavior, this is just an i32 -> u32 transmute
     ///     };
     /// }
     /// ```
diff --git a/src/tools/clippy/clippy_lints/src/deprecated_lints.rs b/src/tools/clippy/clippy_lints/src/deprecated_lints.rs
index bba27576c89..5d5ea0f49c8 100644
--- a/src/tools/clippy/clippy_lints/src/deprecated_lints.rs
+++ b/src/tools/clippy/clippy_lints/src/deprecated_lints.rs
@@ -194,7 +194,6 @@ declare_deprecated_lint! {
     /// ### Deprecation reason
     /// The `avoid_breaking_exported_api` config option was added, which
     /// enables the `enum_variant_names` lint for public items.
-    /// ```
     #[clippy::version = "1.54.0"]
     pub PUB_ENUM_VARIANT_NAMES,
     "set the `avoid-breaking-exported-api` config option to `false` to enable the `enum_variant_names` lint for public items"
diff --git a/src/tools/clippy/clippy_lints/src/dereference.rs b/src/tools/clippy/clippy_lints/src/dereference.rs
index fe391198342..ea4c0207bb0 100644
--- a/src/tools/clippy/clippy_lints/src/dereference.rs
+++ b/src/tools/clippy/clippy_lints/src/dereference.rs
@@ -168,7 +168,7 @@ struct RefPat {
 }
 
 impl<'tcx> LateLintPass<'tcx> for Dereferencing {
-    #[allow(clippy::too_many_lines)]
+    #[expect(clippy::too_many_lines)]
     fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
         // Skip path expressions from deref calls. e.g. `Deref::deref(e)`
         if Some(expr.hir_id) == self.skip_expr.take() {
@@ -580,7 +580,7 @@ fn find_adjustments<'tcx>(
     }
 }
 
-#[allow(clippy::needless_pass_by_value)]
+#[expect(clippy::needless_pass_by_value)]
 fn report(cx: &LateContext<'_>, expr: &Expr<'_>, state: State, data: StateData) {
     match state {
         State::DerefMethod {
diff --git a/src/tools/clippy/clippy_lints/src/derive.rs b/src/tools/clippy/clippy_lints/src/derive.rs
index 545bc7d2103..fe99f4a8d55 100644
--- a/src/tools/clippy/clippy_lints/src/derive.rs
+++ b/src/tools/clippy/clippy_lints/src/derive.rs
@@ -1,8 +1,9 @@
-use clippy_utils::diagnostics::{span_lint_and_help, span_lint_and_note, span_lint_and_then};
+use clippy_utils::diagnostics::{span_lint_and_help, span_lint_and_note, span_lint_and_sugg, span_lint_and_then};
 use clippy_utils::paths;
 use clippy_utils::ty::{implements_trait, is_copy};
 use clippy_utils::{is_lint_allowed, match_def_path};
 use if_chain::if_chain;
+use rustc_errors::Applicability;
 use rustc_hir::intravisit::{walk_expr, walk_fn, walk_item, FnKind, Visitor};
 use rustc_hir::{
     BlockCheckMode, BodyId, Expr, ExprKind, FnDecl, HirId, Impl, Item, ItemKind, TraitRef, UnsafeSource, Unsafety,
@@ -101,8 +102,8 @@ declare_clippy_lint! {
     /// types.
     ///
     /// ### Why is this bad?
-    /// To avoid surprising behaviour, these traits should
-    /// agree and the behaviour of `Copy` cannot be overridden. In almost all
+    /// To avoid surprising behavior, these traits should
+    /// agree and the behavior of `Copy` cannot be overridden. In almost all
     /// situations a `Copy` type should have a `Clone` implementation that does
     /// nothing more than copy the object, which is what `#[derive(Copy, Clone)]`
     /// gets you.
@@ -156,11 +157,44 @@ declare_clippy_lint! {
     "deriving `serde::Deserialize` on a type that has methods using `unsafe`"
 }
 
+declare_clippy_lint! {
+    /// ### What it does
+    /// Checks for types that derive `PartialEq` and could implement `Eq`.
+    ///
+    /// ### Why is this bad?
+    /// If a type `T` derives `PartialEq` and all of its members implement `Eq`,
+    /// then `T` can always implement `Eq`. Implementing `Eq` allows `T` to be used
+    /// in APIs that require `Eq` types. It also allows structs containing `T` to derive
+    /// `Eq` themselves.
+    ///
+    /// ### Example
+    /// ```rust
+    /// #[derive(PartialEq)]
+    /// struct Foo {
+    ///     i_am_eq: i32,
+    ///     i_am_eq_too: Vec<String>,
+    /// }
+    /// ```
+    /// Use instead:
+    /// ```rust
+    /// #[derive(PartialEq, Eq)]
+    /// struct Foo {
+    ///     i_am_eq: i32,
+    ///     i_am_eq_too: Vec<String>,
+    /// }
+    /// ```
+    #[clippy::version = "1.62.0"]
+    pub DERIVE_PARTIAL_EQ_WITHOUT_EQ,
+    style,
+    "deriving `PartialEq` on a type that can implement `Eq`, without implementing `Eq`"
+}
+
 declare_lint_pass!(Derive => [
     EXPL_IMPL_CLONE_ON_COPY,
     DERIVE_HASH_XOR_EQ,
     DERIVE_ORD_XOR_PARTIAL_ORD,
-    UNSAFE_DERIVE_DESERIALIZE
+    UNSAFE_DERIVE_DESERIALIZE,
+    DERIVE_PARTIAL_EQ_WITHOUT_EQ
 ]);
 
 impl<'tcx> LateLintPass<'tcx> for Derive {
@@ -171,14 +205,14 @@ impl<'tcx> LateLintPass<'tcx> for Derive {
         }) = item.kind
         {
             let ty = cx.tcx.type_of(item.def_id);
-            let is_automatically_derived =
-                cx.tcx.has_attr(item.def_id.to_def_id(), sym::automatically_derived);
+            let is_automatically_derived = cx.tcx.has_attr(item.def_id.to_def_id(), sym::automatically_derived);
 
             check_hash_peq(cx, item.span, trait_ref, ty, is_automatically_derived);
             check_ord_partial_ord(cx, item.span, trait_ref, ty, is_automatically_derived);
 
             if is_automatically_derived {
                 check_unsafe_derive_deserialize(cx, item, trait_ref, ty);
+                check_partial_eq_without_eq(cx, item.span, trait_ref, ty);
             } else {
                 check_copy_clone(cx, item, trait_ref, ty);
             }
@@ -419,3 +453,36 @@ impl<'tcx> Visitor<'tcx> for UnsafeVisitor<'_, 'tcx> {
         self.cx.tcx.hir()
     }
 }
+
+/// Implementation of the `DERIVE_PARTIAL_EQ_WITHOUT_EQ` lint.
+fn check_partial_eq_without_eq<'tcx>(cx: &LateContext<'tcx>, span: Span, trait_ref: &TraitRef<'_>, ty: Ty<'tcx>) {
+    if_chain! {
+        if let ty::Adt(adt, substs) = ty.kind();
+        if let Some(eq_trait_def_id) = cx.tcx.get_diagnostic_item(sym::Eq);
+        if let Some(def_id) = trait_ref.trait_def_id();
+        if cx.tcx.is_diagnostic_item(sym::PartialEq, def_id);
+        if !implements_trait(cx, ty, eq_trait_def_id, substs);
+        then {
+            // If all of our fields implement `Eq`, we can implement `Eq` too
+            for variant in adt.variants() {
+                for field in &variant.fields {
+                    let ty = field.ty(cx.tcx, substs);
+
+                    if !implements_trait(cx, ty, eq_trait_def_id, substs) {
+                        return;
+                    }
+                }
+            }
+
+            span_lint_and_sugg(
+                cx,
+                DERIVE_PARTIAL_EQ_WITHOUT_EQ,
+                span.ctxt().outer_expn_data().call_site,
+                "you are deriving `PartialEq` and can implement `Eq`",
+                "consider deriving `Eq` as well",
+                "PartialEq, Eq".to_string(),
+                Applicability::MachineApplicable,
+            )
+        }
+    }
+}
diff --git a/src/tools/clippy/clippy_lints/src/disallowed_methods.rs b/src/tools/clippy/clippy_lints/src/disallowed_methods.rs
index 4c12202c84a..53973ab792a 100644
--- a/src/tools/clippy/clippy_lints/src/disallowed_methods.rs
+++ b/src/tools/clippy/clippy_lints/src/disallowed_methods.rs
@@ -1,7 +1,7 @@
 use clippy_utils::diagnostics::span_lint_and_then;
-use clippy_utils::fn_def_id;
+use clippy_utils::{fn_def_id, get_parent_expr, path_def_id};
 
-use rustc_hir::{def::Res, def_id::DefIdMap, Expr};
+use rustc_hir::{def::Res, def_id::DefIdMap, Expr, ExprKind};
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_session::{declare_tool_lint, impl_lint_pass};
 
@@ -84,7 +84,15 @@ impl<'tcx> LateLintPass<'tcx> for DisallowedMethods {
     }
 
     fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
-        let def_id = match fn_def_id(cx, expr) {
+        let uncalled_path = if let Some(parent) = get_parent_expr(cx, expr)
+            && let ExprKind::Call(receiver, _) = parent.kind
+            && receiver.hir_id == expr.hir_id
+        {
+            None
+        } else {
+            path_def_id(cx, expr)
+        };
+        let def_id = match uncalled_path.or_else(|| fn_def_id(cx, expr)) {
             Some(def_id) => def_id,
             None => return,
         };
diff --git a/src/tools/clippy/clippy_lints/src/doc.rs b/src/tools/clippy/clippy_lints/src/doc.rs
index b3fd8af4730..aaec88f50c7 100644
--- a/src/tools/clippy/clippy_lints/src/doc.rs
+++ b/src/tools/clippy/clippy_lints/src/doc.rs
@@ -198,7 +198,7 @@ declare_clippy_lint! {
     "presence of `fn main() {` in code examples"
 }
 
-#[allow(clippy::module_name_repetitions)]
+#[expect(clippy::module_name_repetitions)]
 #[derive(Clone)]
 pub struct DocMarkdown {
     valid_idents: FxHashSet<String>,
@@ -373,7 +373,7 @@ fn lint_for_missing_headers<'tcx>(
 /// `rustc_ast::parse::lexer::comments::strip_doc_comment_decoration` because we
 /// need to keep track of
 /// the spans but this function is inspired from the later.
-#[allow(clippy::cast_possible_truncation)]
+#[expect(clippy::cast_possible_truncation)]
 #[must_use]
 pub fn strip_doc_comment_decoration(doc: &str, comment_kind: CommentKind, span: Span) -> (String, Vec<(usize, Span)>) {
     // one-line comments lose their prefix
@@ -428,7 +428,7 @@ fn check_attrs<'a>(cx: &LateContext<'_>, valid_idents: &FxHashSet<String>, attrs
     /// We don't want the parser to choke on intra doc links. Since we don't
     /// actually care about rendering them, just pretend that all broken links are
     /// point to a fake address.
-    #[allow(clippy::unnecessary_wraps)] // we're following a type signature
+    #[expect(clippy::unnecessary_wraps)] // we're following a type signature
     fn fake_broken_link_callback<'a>(_: BrokenLink<'_>) -> Option<(CowStr<'a>, CowStr<'a>)> {
         Some(("fake".into(), "fake".into()))
     }
diff --git a/src/tools/clippy/clippy_lints/src/double_comparison.rs b/src/tools/clippy/clippy_lints/src/double_comparison.rs
index 176092e5b28..be95375789d 100644
--- a/src/tools/clippy/clippy_lints/src/double_comparison.rs
+++ b/src/tools/clippy/clippy_lints/src/double_comparison.rs
@@ -40,7 +40,7 @@ declare_clippy_lint! {
 declare_lint_pass!(DoubleComparisons => [DOUBLE_COMPARISONS]);
 
 impl<'tcx> DoubleComparisons {
-    #[allow(clippy::similar_names)]
+    #[expect(clippy::similar_names)]
     fn check_binop(cx: &LateContext<'tcx>, op: BinOpKind, lhs: &'tcx Expr<'_>, rhs: &'tcx Expr<'_>, span: Span) {
         let (lkind, llhs, lrhs, rkind, rlhs, rrhs) = match (&lhs.kind, &rhs.kind) {
             (ExprKind::Binary(lb, llhs, lrhs), ExprKind::Binary(rb, rlhs, rrhs)) => {
diff --git a/src/tools/clippy/clippy_lints/src/duplicate_mod.rs b/src/tools/clippy/clippy_lints/src/duplicate_mod.rs
new file mode 100644
index 00000000000..c6c7b959d4f
--- /dev/null
+++ b/src/tools/clippy/clippy_lints/src/duplicate_mod.rs
@@ -0,0 +1,102 @@
+use clippy_utils::diagnostics::span_lint_and_help;
+use rustc_ast::ast::{Crate, Inline, Item, ItemKind, ModKind};
+use rustc_errors::MultiSpan;
+use rustc_lint::{EarlyContext, EarlyLintPass, LintContext};
+use rustc_session::{declare_tool_lint, impl_lint_pass};
+use rustc_span::{FileName, Span};
+use std::collections::BTreeMap;
+use std::path::PathBuf;
+
+declare_clippy_lint! {
+    /// ### What it does
+    /// Checks for files that are included as modules multiple times.
+    ///
+    /// ### Why is this bad?
+    /// Loading a file as a module more than once causes it to be compiled
+    /// multiple times, taking longer and putting duplicate content into the
+    /// module tree.
+    ///
+    /// ### Example
+    /// ```rust,ignore
+    /// // lib.rs
+    /// mod a;
+    /// mod b;
+    /// ```
+    /// ```rust,ignore
+    /// // a.rs
+    /// #[path = "./b.rs"]
+    /// mod b;
+    /// ```
+    ///
+    /// Use instead:
+    ///
+    /// ```rust,ignore
+    /// // lib.rs
+    /// mod a;
+    /// mod b;
+    /// ```
+    /// ```rust,ignore
+    /// // a.rs
+    /// use crate::b;
+    /// ```
+    #[clippy::version = "1.62.0"]
+    pub DUPLICATE_MOD,
+    suspicious,
+    "file loaded as module multiple times"
+}
+
+#[derive(PartialOrd, Ord, PartialEq, Eq)]
+struct Modules {
+    local_path: PathBuf,
+    spans: Vec<Span>,
+}
+
+#[derive(Default)]
+pub struct DuplicateMod {
+    /// map from the canonicalized path to `Modules`, `BTreeMap` to make the
+    /// order deterministic for tests
+    modules: BTreeMap<PathBuf, Modules>,
+}
+
+impl_lint_pass!(DuplicateMod => [DUPLICATE_MOD]);
+
+impl EarlyLintPass for DuplicateMod {
+    fn check_item(&mut self, cx: &EarlyContext<'_>, item: &Item) {
+        if let ItemKind::Mod(_, ModKind::Loaded(_, Inline::No, mod_spans)) = &item.kind
+            && let FileName::Real(real) = cx.sess().source_map().span_to_filename(mod_spans.inner_span)
+            && let Some(local_path) = real.into_local_path()
+            && let Ok(absolute_path) = local_path.canonicalize()
+        {
+            let modules = self.modules.entry(absolute_path).or_insert(Modules {
+                local_path,
+                spans: Vec::new(),
+            });
+            modules.spans.push(item.span_with_attributes());
+        }
+    }
+
+    fn check_crate_post(&mut self, cx: &EarlyContext<'_>, _: &Crate) {
+        for Modules { local_path, spans } in self.modules.values() {
+            if spans.len() < 2 {
+                continue;
+            }
+
+            let mut multi_span = MultiSpan::from_spans(spans.clone());
+            let (&first, duplicates) = spans.split_first().unwrap();
+
+            multi_span.push_span_label(first, "first loaded here");
+            for &duplicate in duplicates {
+                multi_span.push_span_label(duplicate, "loaded again here");
+            }
+
+            span_lint_and_help(
+                cx,
+                DUPLICATE_MOD,
+                multi_span,
+                &format!("file is loaded as a module multiple times: `{}`", local_path.display()),
+                None,
+                "replace all but one `mod` item with `use` items",
+            );
+        }
+    }
+}
diff --git a/src/tools/clippy/clippy_lints/src/entry.rs b/src/tools/clippy/clippy_lints/src/entry.rs
index d3d3ed2c235..c5a987842c3 100644
--- a/src/tools/clippy/clippy_lints/src/entry.rs
+++ b/src/tools/clippy/clippy_lints/src/entry.rs
@@ -63,7 +63,7 @@ declare_clippy_lint! {
 declare_lint_pass!(HashMapPass => [MAP_ENTRY]);
 
 impl<'tcx> LateLintPass<'tcx> for HashMapPass {
-    #[allow(clippy::too_many_lines)]
+    #[expect(clippy::too_many_lines)]
     fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
         let (cond_expr, then_expr, else_expr) = match higher::If::hir(expr) {
             Some(higher::If { cond, then, r#else }) => (cond, then, r#else),
@@ -319,7 +319,7 @@ struct Insertion<'tcx> {
 ///   `or_insert_with`.
 /// * Determine if there's any sub-expression that can't be placed in a closure.
 /// * Determine if there's only a single insert statement. `or_insert` can be used in this case.
-#[allow(clippy::struct_excessive_bools)]
+#[expect(clippy::struct_excessive_bools)]
 struct InsertSearcher<'cx, 'tcx> {
     cx: &'cx LateContext<'tcx>,
     /// The map expression used in the contains call.
diff --git a/src/tools/clippy/clippy_lints/src/enum_clike.rs b/src/tools/clippy/clippy_lints/src/enum_clike.rs
index e2a5430da08..10be245b362 100644
--- a/src/tools/clippy/clippy_lints/src/enum_clike.rs
+++ b/src/tools/clippy/clippy_lints/src/enum_clike.rs
@@ -8,7 +8,6 @@ use rustc_lint::{LateContext, LateLintPass};
 use rustc_middle::ty::util::IntTypeExt;
 use rustc_middle::ty::{self, IntTy, UintTy};
 use rustc_session::{declare_lint_pass, declare_tool_lint};
-use std::convert::TryFrom;
 
 declare_clippy_lint! {
     /// ### What it does
@@ -37,7 +36,7 @@ declare_clippy_lint! {
 declare_lint_pass!(UnportableVariant => [ENUM_CLIKE_UNPORTABLE_VARIANT]);
 
 impl<'tcx> LateLintPass<'tcx> for UnportableVariant {
-    #[allow(clippy::cast_possible_truncation, clippy::cast_possible_wrap, clippy::cast_sign_loss)]
+    #[expect(clippy::cast_possible_wrap)]
     fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'_>) {
         if cx.tcx.data_layout.pointer_size.bits() != 64 {
             return;
diff --git a/src/tools/clippy/clippy_lints/src/enum_variants.rs b/src/tools/clippy/clippy_lints/src/enum_variants.rs
index 346d03ca556..e029b8e8537 100644
--- a/src/tools/clippy/clippy_lints/src/enum_variants.rs
+++ b/src/tools/clippy/clippy_lints/src/enum_variants.rs
@@ -240,7 +240,7 @@ impl LateLintPass<'_> for EnumVariantNames {
         assert!(last.is_some());
     }
 
-    #[allow(clippy::similar_names)]
+    #[expect(clippy::similar_names)]
     fn check_item(&mut self, cx: &LateContext<'_>, item: &Item<'_>) {
         let item_name = item.ident.name.as_str();
         let item_camel = to_camel_case(item_name);
diff --git a/src/tools/clippy/clippy_lints/src/eq_op.rs b/src/tools/clippy/clippy_lints/src/eq_op.rs
index 51c811b304c..afb5d32f953 100644
--- a/src/tools/clippy/clippy_lints/src/eq_op.rs
+++ b/src/tools/clippy/clippy_lints/src/eq_op.rs
@@ -72,7 +72,7 @@ declare_clippy_lint! {
 declare_lint_pass!(EqOp => [EQ_OP, OP_REF]);
 
 impl<'tcx> LateLintPass<'tcx> for EqOp {
-    #[allow(clippy::similar_names, clippy::too_many_lines)]
+    #[expect(clippy::similar_names, clippy::too_many_lines)]
     fn check_expr(&mut self, cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) {
         if_chain! {
             if let Some((macro_call, macro_name)) = first_node_macro_backtrace(cx, e).find_map(|macro_call| {
@@ -138,7 +138,6 @@ impl<'tcx> LateLintPass<'tcx> for EqOp {
                 },
             };
             if let Some(trait_id) = trait_id {
-                #[allow(clippy::match_same_arms)]
                 match (&left.kind, &right.kind) {
                     // do not suggest to dereference literals
                     (&ExprKind::Lit(..), _) | (_, &ExprKind::Lit(..)) => {},
diff --git a/src/tools/clippy/clippy_lints/src/excessive_bools.rs b/src/tools/clippy/clippy_lints/src/excessive_bools.rs
index 245a4fc12fd..7a81fb37e84 100644
--- a/src/tools/clippy/clippy_lints/src/excessive_bools.rs
+++ b/src/tools/clippy/clippy_lints/src/excessive_bools.rs
@@ -4,8 +4,6 @@ use rustc_lint::{EarlyContext, EarlyLintPass};
 use rustc_session::{declare_tool_lint, impl_lint_pass};
 use rustc_span::{sym, Span};
 
-use std::convert::TryInto;
-
 declare_clippy_lint! {
     /// ### What it does
     /// Checks for excessive
diff --git a/src/tools/clippy/clippy_lints/src/fallible_impl_from.rs b/src/tools/clippy/clippy_lints/src/fallible_impl_from.rs
index 088d9996516..9f868df3ad0 100644
--- a/src/tools/clippy/clippy_lints/src/fallible_impl_from.rs
+++ b/src/tools/clippy/clippy_lints/src/fallible_impl_from.rs
@@ -32,7 +32,6 @@ declare_clippy_lint! {
     /// // Good
     /// struct Foo(i32);
     ///
-    /// use std::convert::TryFrom;
     /// impl TryFrom<String> for Foo {
     ///     type Error = ();
     ///     fn try_from(s: String) -> Result<Self, Self::Error> {
diff --git a/src/tools/clippy/clippy_lints/src/floating_point_arithmetic.rs b/src/tools/clippy/clippy_lints/src/floating_point_arithmetic.rs
index 79ce53f7a5f..42503c26de1 100644
--- a/src/tools/clippy/clippy_lints/src/floating_point_arithmetic.rs
+++ b/src/tools/clippy/clippy_lints/src/floating_point_arithmetic.rs
@@ -215,7 +215,7 @@ fn check_ln1p(cx: &LateContext<'_>, expr: &Expr<'_>, args: &[Expr<'_>]) {
 // converted to an integer without loss of precision. For now we only check
 // ranges [-16777215, 16777216) for type f32 as whole number floats outside
 // this range are lossy and ambiguous.
-#[allow(clippy::cast_possible_truncation)]
+#[expect(clippy::cast_possible_truncation)]
 fn get_integer_from_float_constant(value: &Constant) -> Option<i32> {
     match value {
         F32(num) if num.fract() == 0.0 => {
diff --git a/src/tools/clippy/clippy_lints/src/from_over_into.rs b/src/tools/clippy/clippy_lints/src/from_over_into.rs
index c2f52605151..5d25c1d0634 100644
--- a/src/tools/clippy/clippy_lints/src/from_over_into.rs
+++ b/src/tools/clippy/clippy_lints/src/from_over_into.rs
@@ -55,7 +55,7 @@ impl_lint_pass!(FromOverInto => [FROM_OVER_INTO]);
 
 impl<'tcx> LateLintPass<'tcx> for FromOverInto {
     fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx hir::Item<'_>) {
-        if !meets_msrv(self.msrv.as_ref(), &msrvs::RE_REBALANCING_COHERENCE) {
+        if !meets_msrv(self.msrv, msrvs::RE_REBALANCING_COHERENCE) {
             return;
         }
 
diff --git a/src/tools/clippy/clippy_lints/src/if_then_some_else_none.rs b/src/tools/clippy/clippy_lints/src/if_then_some_else_none.rs
index 9525c163ece..b8d227855d9 100644
--- a/src/tools/clippy/clippy_lints/src/if_then_some_else_none.rs
+++ b/src/tools/clippy/clippy_lints/src/if_then_some_else_none.rs
@@ -57,7 +57,7 @@ impl_lint_pass!(IfThenSomeElseNone => [IF_THEN_SOME_ELSE_NONE]);
 
 impl<'tcx> LateLintPass<'tcx> for IfThenSomeElseNone {
     fn check_expr(&mut self, cx: &LateContext<'_>, expr: &'tcx Expr<'_>) {
-        if !meets_msrv(self.msrv.as_ref(), &msrvs::BOOL_THEN) {
+        if !meets_msrv(self.msrv, msrvs::BOOL_THEN) {
             return;
         }
 
diff --git a/src/tools/clippy/clippy_lints/src/implicit_hasher.rs b/src/tools/clippy/clippy_lints/src/implicit_hasher.rs
index feb1b1014b1..4f9680f60fe 100644
--- a/src/tools/clippy/clippy_lints/src/implicit_hasher.rs
+++ b/src/tools/clippy/clippy_lints/src/implicit_hasher.rs
@@ -62,7 +62,7 @@ declare_clippy_lint! {
 declare_lint_pass!(ImplicitHasher => [IMPLICIT_HASHER]);
 
 impl<'tcx> LateLintPass<'tcx> for ImplicitHasher {
-    #[allow(clippy::cast_possible_truncation, clippy::too_many_lines)]
+    #[expect(clippy::cast_possible_truncation, clippy::too_many_lines)]
     fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'_>) {
         use rustc_span::BytePos;
 
diff --git a/src/tools/clippy/clippy_lints/src/implicit_return.rs b/src/tools/clippy/clippy_lints/src/implicit_return.rs
index d650d6e9a85..647947d5d30 100644
--- a/src/tools/clippy/clippy_lints/src/implicit_return.rs
+++ b/src/tools/clippy/clippy_lints/src/implicit_return.rs
@@ -164,7 +164,7 @@ fn lint_implicit_returns(
             })
             .visit_block(block);
             if add_return {
-                #[allow(clippy::option_if_let_else)]
+                #[expect(clippy::option_if_let_else)]
                 if let Some(span) = call_site_span {
                     lint_return(cx, span);
                     LintLocation::Parent
@@ -196,7 +196,7 @@ fn lint_implicit_returns(
 
         _ =>
         {
-            #[allow(clippy::option_if_let_else)]
+            #[expect(clippy::option_if_let_else)]
             if let Some(span) = call_site_span {
                 lint_return(cx, span);
                 LintLocation::Parent
diff --git a/src/tools/clippy/clippy_lints/src/index_refutable_slice.rs b/src/tools/clippy/clippy_lints/src/index_refutable_slice.rs
index 8a84513b779..9ce5b8e17a9 100644
--- a/src/tools/clippy/clippy_lints/src/index_refutable_slice.rs
+++ b/src/tools/clippy/clippy_lints/src/index_refutable_slice.rs
@@ -14,7 +14,6 @@ use rustc_middle::ty;
 use rustc_semver::RustcVersion;
 use rustc_session::{declare_tool_lint, impl_lint_pass};
 use rustc_span::{symbol::Ident, Span};
-use std::convert::TryInto;
 
 declare_clippy_lint! {
     /// ### What it does
@@ -75,7 +74,7 @@ impl<'tcx> LateLintPass<'tcx> for IndexRefutableSlice {
             if !expr.span.from_expansion() || is_expn_of(expr.span, "if_chain").is_some();
             if let Some(IfLet {let_pat, if_then, ..}) = IfLet::hir(cx, expr);
             if !is_lint_allowed(cx, INDEX_REFUTABLE_SLICE, expr.hir_id);
-            if meets_msrv(self.msrv.as_ref(), &msrvs::SLICE_PATTERNS);
+            if meets_msrv(self.msrv, msrvs::SLICE_PATTERNS);
 
             let found_slices = find_slice_values(cx, let_pat);
             if !found_slices.is_empty();
diff --git a/src/tools/clippy/clippy_lints/src/int_plus_one.rs b/src/tools/clippy/clippy_lints/src/int_plus_one.rs
index 3716d36ad88..8db7b307ddb 100644
--- a/src/tools/clippy/clippy_lints/src/int_plus_one.rs
+++ b/src/tools/clippy/clippy_lints/src/int_plus_one.rs
@@ -52,7 +52,7 @@ enum Side {
 }
 
 impl IntPlusOne {
-    #[allow(clippy::cast_sign_loss)]
+    #[expect(clippy::cast_sign_loss)]
     fn check_lit(lit: &Lit, target_value: i128) -> bool {
         if let LitKind::Int(value, ..) = lit.kind {
             return value == (target_value as u128);
diff --git a/src/tools/clippy/clippy_lints/src/lib.register_all.rs b/src/tools/clippy/clippy_lints/src/lib.register_all.rs
index e68718f9fdf..be5c478900f 100644
--- a/src/tools/clippy/clippy_lints/src/lib.register_all.rs
+++ b/src/tools/clippy/clippy_lints/src/lib.register_all.rs
@@ -46,6 +46,7 @@ store.register_group(true, "clippy::all", Some("clippy_all"), vec![
     LintId::of(derivable_impls::DERIVABLE_IMPLS),
     LintId::of(derive::DERIVE_HASH_XOR_EQ),
     LintId::of(derive::DERIVE_ORD_XOR_PARTIAL_ORD),
+    LintId::of(derive::DERIVE_PARTIAL_EQ_WITHOUT_EQ),
     LintId::of(disallowed_methods::DISALLOWED_METHODS),
     LintId::of(disallowed_types::DISALLOWED_TYPES),
     LintId::of(doc::MISSING_SAFETY_DOC),
@@ -59,6 +60,7 @@ store.register_group(true, "clippy::all", Some("clippy_all"), vec![
     LintId::of(drop_forget_ref::FORGET_NON_DROP),
     LintId::of(drop_forget_ref::FORGET_REF),
     LintId::of(drop_forget_ref::UNDROPPED_MANUALLY_DROPS),
+    LintId::of(duplicate_mod::DUPLICATE_MOD),
     LintId::of(duration_subsec::DURATION_SUBSEC),
     LintId::of(entry::MAP_ENTRY),
     LintId::of(enum_clike::ENUM_CLIKE_UNPORTABLE_VARIANT),
@@ -69,8 +71,6 @@ store.register_group(true, "clippy::all", Some("clippy_all"), vec![
     LintId::of(erasing_op::ERASING_OP),
     LintId::of(escape::BOXED_LOCAL),
     LintId::of(eta_reduction::REDUNDANT_CLOSURE),
-    LintId::of(eval_order_dependence::DIVERGING_SUB_EXPRESSION),
-    LintId::of(eval_order_dependence::EVAL_ORDER_DEPENDENCE),
     LintId::of(explicit_write::EXPLICIT_WRITE),
     LintId::of(float_equality_without_abs::FLOAT_EQUALITY_WITHOUT_ABS),
     LintId::of(float_literal::EXCESSIVE_PRECISION),
@@ -228,6 +228,7 @@ store.register_group(true, "clippy::all", Some("clippy_all"), vec![
     LintId::of(misc_early::REDUNDANT_PATTERN),
     LintId::of(misc_early::UNNEEDED_WILDCARD_PATTERN),
     LintId::of(misc_early::ZERO_PREFIXED_LITERAL),
+    LintId::of(mixed_read_write_in_expression::DIVERGING_SUB_EXPRESSION),
     LintId::of(mut_key::MUTABLE_KEY_TYPE),
     LintId::of(mut_mutex_lock::MUT_MUTEX_LOCK),
     LintId::of(mut_reference::UNNECESSARY_MUT_PASSED),
@@ -263,6 +264,7 @@ store.register_group(true, "clippy::all", Some("clippy_all"), vec![
     LintId::of(ranges::MANUAL_RANGE_CONTAINS),
     LintId::of(ranges::RANGE_ZIP_WITH_LEN),
     LintId::of(ranges::REVERSED_EMPTY_RANGES),
+    LintId::of(rc_clone_in_vec_init::RC_CLONE_IN_VEC_INIT),
     LintId::of(redundant_clone::REDUNDANT_CLONE),
     LintId::of(redundant_closure_call::REDUNDANT_CLOSURE_CALL),
     LintId::of(redundant_field_names::REDUNDANT_FIELD_NAMES),
@@ -276,6 +278,7 @@ store.register_group(true, "clippy::all", Some("clippy_all"), vec![
     LintId::of(self_assignment::SELF_ASSIGNMENT),
     LintId::of(self_named_constructors::SELF_NAMED_CONSTRUCTORS),
     LintId::of(serde_api::SERDE_API_MISUSE),
+    LintId::of(significant_drop_in_scrutinee::SIGNIFICANT_DROP_IN_SCRUTINEE),
     LintId::of(single_component_path_imports::SINGLE_COMPONENT_PATH_IMPORTS),
     LintId::of(size_of_in_element_count::SIZE_OF_IN_ELEMENT_COUNT),
     LintId::of(slow_vector_initialization::SLOW_VECTOR_INITIALIZATION),
diff --git a/src/tools/clippy/clippy_lints/src/lib.register_complexity.rs b/src/tools/clippy/clippy_lints/src/lib.register_complexity.rs
index 6f3c433af31..b15c979d0c7 100644
--- a/src/tools/clippy/clippy_lints/src/lib.register_complexity.rs
+++ b/src/tools/clippy/clippy_lints/src/lib.register_complexity.rs
@@ -12,7 +12,6 @@ store.register_group(true, "clippy::complexity", Some("clippy_complexity"), vec!
     LintId::of(double_comparison::DOUBLE_COMPARISONS),
     LintId::of(double_parens::DOUBLE_PARENS),
     LintId::of(duration_subsec::DURATION_SUBSEC),
-    LintId::of(eval_order_dependence::DIVERGING_SUB_EXPRESSION),
     LintId::of(explicit_write::EXPLICIT_WRITE),
     LintId::of(format::USELESS_FORMAT),
     LintId::of(functions::TOO_MANY_ARGUMENTS),
@@ -59,6 +58,7 @@ store.register_group(true, "clippy::complexity", Some("clippy_complexity"), vec!
     LintId::of(misc::SHORT_CIRCUIT_STATEMENT),
     LintId::of(misc_early::UNNEEDED_WILDCARD_PATTERN),
     LintId::of(misc_early::ZERO_PREFIXED_LITERAL),
+    LintId::of(mixed_read_write_in_expression::DIVERGING_SUB_EXPRESSION),
     LintId::of(needless_arbitrary_self_type::NEEDLESS_ARBITRARY_SELF_TYPE),
     LintId::of(needless_bool::BOOL_COMPARISON),
     LintId::of(needless_bool::NEEDLESS_BOOL),
diff --git a/src/tools/clippy/clippy_lints/src/lib.register_lints.rs b/src/tools/clippy/clippy_lints/src/lib.register_lints.rs
index c888a5feda2..3350697ed7a 100644
--- a/src/tools/clippy/clippy_lints/src/lib.register_lints.rs
+++ b/src/tools/clippy/clippy_lints/src/lib.register_lints.rs
@@ -113,6 +113,7 @@ store.register_lints(&[
     derivable_impls::DERIVABLE_IMPLS,
     derive::DERIVE_HASH_XOR_EQ,
     derive::DERIVE_ORD_XOR_PARTIAL_ORD,
+    derive::DERIVE_PARTIAL_EQ_WITHOUT_EQ,
     derive::EXPL_IMPL_CLONE_ON_COPY,
     derive::UNSAFE_DERIVE_DESERIALIZE,
     disallowed_methods::DISALLOWED_METHODS,
@@ -132,6 +133,7 @@ store.register_lints(&[
     drop_forget_ref::FORGET_NON_DROP,
     drop_forget_ref::FORGET_REF,
     drop_forget_ref::UNDROPPED_MANUALLY_DROPS,
+    duplicate_mod::DUPLICATE_MOD,
     duration_subsec::DURATION_SUBSEC,
     else_if_without_else::ELSE_IF_WITHOUT_ELSE,
     empty_drop::EMPTY_DROP,
@@ -149,8 +151,6 @@ store.register_lints(&[
     escape::BOXED_LOCAL,
     eta_reduction::REDUNDANT_CLOSURE,
     eta_reduction::REDUNDANT_CLOSURE_FOR_METHOD_CALLS,
-    eval_order_dependence::DIVERGING_SUB_EXPRESSION,
-    eval_order_dependence::EVAL_ORDER_DEPENDENCE,
     excessive_bools::FN_PARAMS_EXCESSIVE_BOOLS,
     excessive_bools::STRUCT_EXCESSIVE_BOOLS,
     exhaustive_items::EXHAUSTIVE_ENUMS,
@@ -381,6 +381,8 @@ store.register_lints(&[
     missing_doc::MISSING_DOCS_IN_PRIVATE_ITEMS,
     missing_enforced_import_rename::MISSING_ENFORCED_IMPORT_RENAMES,
     missing_inline::MISSING_INLINE_IN_PUBLIC_ITEMS,
+    mixed_read_write_in_expression::DIVERGING_SUB_EXPRESSION,
+    mixed_read_write_in_expression::MIXED_READ_WRITE_IN_EXPRESSION,
     module_style::MOD_MODULE_FILES,
     module_style::SELF_NAMED_MODULE_FILES,
     modulo_arithmetic::MODULO_ARITHMETIC,
@@ -446,6 +448,7 @@ store.register_lints(&[
     ranges::RANGE_PLUS_ONE,
     ranges::RANGE_ZIP_WITH_LEN,
     ranges::REVERSED_EMPTY_RANGES,
+    rc_clone_in_vec_init::RC_CLONE_IN_VEC_INIT,
     redundant_clone::REDUNDANT_CLONE,
     redundant_closure_call::REDUNDANT_CLOSURE_CALL,
     redundant_else::REDUNDANT_ELSE,
@@ -470,6 +473,7 @@ store.register_lints(&[
     shadow::SHADOW_REUSE,
     shadow::SHADOW_SAME,
     shadow::SHADOW_UNRELATED,
+    significant_drop_in_scrutinee::SIGNIFICANT_DROP_IN_SCRUTINEE,
     single_char_lifetime_names::SINGLE_CHAR_LIFETIME_NAMES,
     single_component_path_imports::SINGLE_COMPONENT_PATH_IMPORTS,
     size_of_in_element_count::SIZE_OF_IN_ELEMENT_COUNT,
diff --git a/src/tools/clippy/clippy_lints/src/lib.register_restriction.rs b/src/tools/clippy/clippy_lints/src/lib.register_restriction.rs
index 77ec6c83ba4..a6d3a06dc16 100644
--- a/src/tools/clippy/clippy_lints/src/lib.register_restriction.rs
+++ b/src/tools/clippy/clippy_lints/src/lib.register_restriction.rs
@@ -46,6 +46,7 @@ store.register_group(true, "clippy::restriction", Some("clippy_restriction"), ve
     LintId::of(missing_doc::MISSING_DOCS_IN_PRIVATE_ITEMS),
     LintId::of(missing_enforced_import_rename::MISSING_ENFORCED_IMPORT_RENAMES),
     LintId::of(missing_inline::MISSING_INLINE_IN_PUBLIC_ITEMS),
+    LintId::of(mixed_read_write_in_expression::MIXED_READ_WRITE_IN_EXPRESSION),
     LintId::of(module_style::MOD_MODULE_FILES),
     LintId::of(module_style::SELF_NAMED_MODULE_FILES),
     LintId::of(modulo_arithmetic::MODULO_ARITHMETIC),
diff --git a/src/tools/clippy/clippy_lints/src/lib.register_style.rs b/src/tools/clippy/clippy_lints/src/lib.register_style.rs
index d183c0449cd..62f26d821a0 100644
--- a/src/tools/clippy/clippy_lints/src/lib.register_style.rs
+++ b/src/tools/clippy/clippy_lints/src/lib.register_style.rs
@@ -16,6 +16,7 @@ store.register_group(true, "clippy::style", Some("clippy_style"), vec![
     LintId::of(comparison_chain::COMPARISON_CHAIN),
     LintId::of(default::FIELD_REASSIGN_WITH_DEFAULT),
     LintId::of(dereference::NEEDLESS_BORROW),
+    LintId::of(derive::DERIVE_PARTIAL_EQ_WITHOUT_EQ),
     LintId::of(disallowed_methods::DISALLOWED_METHODS),
     LintId::of(disallowed_types::DISALLOWED_TYPES),
     LintId::of(doc::MISSING_SAFETY_DOC),
diff --git a/src/tools/clippy/clippy_lints/src/lib.register_suspicious.rs b/src/tools/clippy/clippy_lints/src/lib.register_suspicious.rs
index 7a881bfe399..2de49f1624a 100644
--- a/src/tools/clippy/clippy_lints/src/lib.register_suspicious.rs
+++ b/src/tools/clippy/clippy_lints/src/lib.register_suspicious.rs
@@ -14,7 +14,7 @@ store.register_group(true, "clippy::suspicious", Some("clippy_suspicious"), vec!
     LintId::of(crate_in_macro_def::CRATE_IN_MACRO_DEF),
     LintId::of(drop_forget_ref::DROP_NON_DROP),
     LintId::of(drop_forget_ref::FORGET_NON_DROP),
-    LintId::of(eval_order_dependence::EVAL_ORDER_DEPENDENCE),
+    LintId::of(duplicate_mod::DUPLICATE_MOD),
     LintId::of(float_equality_without_abs::FLOAT_EQUALITY_WITHOUT_ABS),
     LintId::of(format_impl::PRINT_IN_FORMAT_IMPL),
     LintId::of(formatting::SUSPICIOUS_ASSIGNMENT_FORMATTING),
@@ -26,6 +26,8 @@ store.register_group(true, "clippy::suspicious", Some("clippy_suspicious"), vec!
     LintId::of(methods::SUSPICIOUS_MAP),
     LintId::of(mut_key::MUTABLE_KEY_TYPE),
     LintId::of(octal_escapes::OCTAL_ESCAPES),
+    LintId::of(rc_clone_in_vec_init::RC_CLONE_IN_VEC_INIT),
+    LintId::of(significant_drop_in_scrutinee::SIGNIFICANT_DROP_IN_SCRUTINEE),
     LintId::of(suspicious_trait_impl::SUSPICIOUS_ARITHMETIC_IMPL),
     LintId::of(suspicious_trait_impl::SUSPICIOUS_OP_ASSIGN_IMPL),
 ])
diff --git a/src/tools/clippy/clippy_lints/src/lib.rs b/src/tools/clippy/clippy_lints/src/lib.rs
index 09071a255c5..4ac834f7240 100644
--- a/src/tools/clippy/clippy_lints/src/lib.rs
+++ b/src/tools/clippy/clippy_lints/src/lib.rs
@@ -8,6 +8,7 @@
 #![feature(iter_intersperse)]
 #![feature(let_chains)]
 #![feature(let_else)]
+#![feature(lint_reasons)]
 #![feature(once_cell)]
 #![feature(rustc_private)]
 #![feature(stmt_expr_attributes)]
@@ -210,6 +211,7 @@ mod doc;
 mod double_comparison;
 mod double_parens;
 mod drop_forget_ref;
+mod duplicate_mod;
 mod duration_subsec;
 mod else_if_without_else;
 mod empty_drop;
@@ -223,7 +225,6 @@ mod equatable_if_let;
 mod erasing_op;
 mod escape;
 mod eta_reduction;
-mod eval_order_dependence;
 mod excessive_bools;
 mod exhaustive_items;
 mod exit;
@@ -299,6 +300,7 @@ mod missing_const_for_fn;
 mod missing_doc;
 mod missing_enforced_import_rename;
 mod missing_inline;
+mod mixed_read_write_in_expression;
 mod module_style;
 mod modulo_arithmetic;
 mod mut_key;
@@ -345,6 +347,7 @@ mod ptr_offset_with_cast;
 mod pub_use;
 mod question_mark;
 mod ranges;
+mod rc_clone_in_vec_init;
 mod redundant_clone;
 mod redundant_closure_call;
 mod redundant_else;
@@ -417,7 +420,7 @@ mod zero_sized_map_values;
 // end lints modules, do not remove this comment, it’s used in `update_lints`
 
 pub use crate::utils::conf::Conf;
-use crate::utils::conf::TryConf;
+use crate::utils::conf::{format_error, TryConf};
 
 /// Register all pre expansion lints
 ///
@@ -462,7 +465,7 @@ pub fn read_conf(sess: &Session) -> Conf {
         sess.struct_err(&format!(
             "error reading Clippy's configuration file `{}`: {}",
             file_name.display(),
-            error
+            format_error(error)
         ))
         .emit();
     }
@@ -473,7 +476,7 @@ pub fn read_conf(sess: &Session) -> Conf {
 /// Register all lints and lint groups with the rustc plugin registry
 ///
 /// Used in `./src/driver.rs`.
-#[allow(clippy::too_many_lines)]
+#[expect(clippy::too_many_lines)]
 pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: &Conf) {
     register_removed_non_tool_lints(store);
 
@@ -583,8 +586,17 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
     });
 
     let avoid_breaking_exported_api = conf.avoid_breaking_exported_api;
+    let allow_expect_in_tests = conf.allow_expect_in_tests;
+    let allow_unwrap_in_tests = conf.allow_unwrap_in_tests;
     store.register_late_pass(move || Box::new(approx_const::ApproxConstant::new(msrv)));
-    store.register_late_pass(move || Box::new(methods::Methods::new(avoid_breaking_exported_api, msrv)));
+    store.register_late_pass(move || {
+        Box::new(methods::Methods::new(
+            avoid_breaking_exported_api,
+            msrv,
+            allow_expect_in_tests,
+            allow_unwrap_in_tests,
+        ))
+    });
     store.register_late_pass(move || Box::new(matches::Matches::new(msrv)));
     store.register_early_pass(move || Box::new(manual_non_exhaustive::ManualNonExhaustiveStruct::new(msrv)));
     store.register_late_pass(move || Box::new(manual_non_exhaustive::ManualNonExhaustiveEnum::new(msrv)));
@@ -669,7 +681,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
     store.register_late_pass(|| Box::new(arithmetic::Arithmetic::default()));
     store.register_late_pass(|| Box::new(assign_ops::AssignOps));
     store.register_late_pass(|| Box::new(let_if_seq::LetIfSeq));
-    store.register_late_pass(|| Box::new(eval_order_dependence::EvalOrderDependence));
+    store.register_late_pass(|| Box::new(mixed_read_write_in_expression::EvalOrderDependence));
     store.register_late_pass(|| Box::new(missing_doc::MissingDoc::new()));
     store.register_late_pass(|| Box::new(missing_inline::MissingInline));
     store.register_late_pass(move || Box::new(exhaustive_items::ExhaustiveItems));
@@ -892,6 +904,8 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
     let max_include_file_size = conf.max_include_file_size;
     store.register_late_pass(move || Box::new(large_include_file::LargeIncludeFile::new(max_include_file_size)));
     store.register_late_pass(|| Box::new(strings::TrimSplitWhitespace));
+    store.register_late_pass(|| Box::new(rc_clone_in_vec_init::RcCloneInVecInit));
+    store.register_early_pass(|| Box::new(duplicate_mod::DuplicateMod::default()));
     // add lints here, do not remove this comment, it's used in `new_lint`
 }
 
diff --git a/src/tools/clippy/clippy_lints/src/literal_representation.rs b/src/tools/clippy/clippy_lints/src/literal_representation.rs
index 269d3c62eaf..9998712b852 100644
--- a/src/tools/clippy/clippy_lints/src/literal_representation.rs
+++ b/src/tools/clippy/clippy_lints/src/literal_representation.rs
@@ -204,7 +204,6 @@ impl WarningType {
     }
 }
 
-#[allow(clippy::module_name_repetitions)]
 #[derive(Copy, Clone)]
 pub struct LiteralDigitGrouping {
     lint_fraction_readability: bool,
@@ -432,7 +431,7 @@ impl LiteralDigitGrouping {
     }
 }
 
-#[allow(clippy::module_name_repetitions)]
+#[expect(clippy::module_name_repetitions)]
 #[derive(Copy, Clone)]
 pub struct DecimalLiteralRepresentation {
     threshold: u64,
diff --git a/src/tools/clippy/clippy_lints/src/loops/mod.rs b/src/tools/clippy/clippy_lints/src/loops/mod.rs
index f029067d367..75d771f992a 100644
--- a/src/tools/clippy/clippy_lints/src/loops/mod.rs
+++ b/src/tools/clippy/clippy_lints/src/loops/mod.rs
@@ -620,7 +620,6 @@ declare_lint_pass!(Loops => [
 ]);
 
 impl<'tcx> LateLintPass<'tcx> for Loops {
-    #[allow(clippy::too_many_lines)]
     fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
         let for_loop = higher::ForLoop::hir(expr);
         if let Some(higher::ForLoop {
diff --git a/src/tools/clippy/clippy_lints/src/loops/needless_range_loop.rs b/src/tools/clippy/clippy_lints/src/loops/needless_range_loop.rs
index 6ed141fa4a5..09f9c05b4fc 100644
--- a/src/tools/clippy/clippy_lints/src/loops/needless_range_loop.rs
+++ b/src/tools/clippy/clippy_lints/src/loops/needless_range_loop.rs
@@ -19,7 +19,7 @@ use std::mem;
 
 /// Checks for looping over a range and then indexing a sequence with it.
 /// The iteratee must be a range literal.
-#[allow(clippy::too_many_lines)]
+#[expect(clippy::too_many_lines)]
 pub(super) fn check<'tcx>(
     cx: &LateContext<'tcx>,
     pat: &'tcx Pat<'_>,
diff --git a/src/tools/clippy/clippy_lints/src/loops/utils.rs b/src/tools/clippy/clippy_lints/src/loops/utils.rs
index 772d251b620..4801a84eb92 100644
--- a/src/tools/clippy/clippy_lints/src/loops/utils.rs
+++ b/src/tools/clippy/clippy_lints/src/loops/utils.rs
@@ -13,7 +13,7 @@ use rustc_span::symbol::{sym, Symbol};
 use rustc_typeck::hir_ty_to_ty;
 use std::iter::Iterator;
 
-#[derive(Debug, PartialEq)]
+#[derive(Debug, PartialEq, Eq)]
 enum IncrementVisitorVarState {
     Initial,  // Not examined yet
     IncrOnce, // Incremented exactly once, may be a loop counter
diff --git a/src/tools/clippy/clippy_lints/src/loops/while_let_on_iterator.rs b/src/tools/clippy/clippy_lints/src/loops/while_let_on_iterator.rs
index 20a8294a0d1..82760607ba2 100644
--- a/src/tools/clippy/clippy_lints/src/loops/while_let_on_iterator.rs
+++ b/src/tools/clippy/clippy_lints/src/loops/while_let_on_iterator.rs
@@ -239,7 +239,7 @@ fn uses_iter<'tcx>(cx: &LateContext<'tcx>, iter_expr: &IterExpr, container: &'tc
     v.uses_iter
 }
 
-#[allow(clippy::too_many_lines)]
+#[expect(clippy::too_many_lines)]
 fn needs_mutable_borrow(cx: &LateContext<'_>, iter_expr: &IterExpr, loop_expr: &Expr<'_>) -> bool {
     struct AfterLoopVisitor<'a, 'b, 'tcx> {
         cx: &'a LateContext<'tcx>,
diff --git a/src/tools/clippy/clippy_lints/src/macro_use.rs b/src/tools/clippy/clippy_lints/src/macro_use.rs
index ca1ccb93bf3..753469c603d 100644
--- a/src/tools/clippy/clippy_lints/src/macro_use.rs
+++ b/src/tools/clippy/clippy_lints/src/macro_use.rs
@@ -48,7 +48,7 @@ impl MacroRefData {
 }
 
 #[derive(Default)]
-#[allow(clippy::module_name_repetitions)]
+#[expect(clippy::module_name_repetitions)]
 pub struct MacroUseImports {
     /// the actual import path used and the span of the attribute above it.
     imports: Vec<(String, Span)>,
@@ -134,7 +134,6 @@ impl<'tcx> LateLintPass<'tcx> for MacroUseImports {
             self.push_unique_macro_pat_ty(cx, ty.span);
         }
     }
-    #[allow(clippy::too_many_lines)]
     fn check_crate_post(&mut self, cx: &LateContext<'_>) {
         let mut used = FxHashMap::default();
         let mut check_dup = vec![];
diff --git a/src/tools/clippy/clippy_lints/src/main_recursion.rs b/src/tools/clippy/clippy_lints/src/main_recursion.rs
index fad8fa467d4..20333c150e3 100644
--- a/src/tools/clippy/clippy_lints/src/main_recursion.rs
+++ b/src/tools/clippy/clippy_lints/src/main_recursion.rs
@@ -12,7 +12,7 @@ declare_clippy_lint! {
     ///
     /// ### Why is this bad?
     /// Apart from special setups (which we could detect following attributes like #![no_std]),
-    /// recursing into main() seems like an unintuitive antipattern we should be able to detect.
+    /// recursing into main() seems like an unintuitive anti-pattern we should be able to detect.
     ///
     /// ### Example
     /// ```no_run
diff --git a/src/tools/clippy/clippy_lints/src/manual_bits.rs b/src/tools/clippy/clippy_lints/src/manual_bits.rs
index ac3d9447b6b..60bbcde4f1d 100644
--- a/src/tools/clippy/clippy_lints/src/manual_bits.rs
+++ b/src/tools/clippy/clippy_lints/src/manual_bits.rs
@@ -48,7 +48,7 @@ impl_lint_pass!(ManualBits => [MANUAL_BITS]);
 
 impl<'tcx> LateLintPass<'tcx> for ManualBits {
     fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
-        if !meets_msrv(self.msrv.as_ref(), &msrvs::MANUAL_BITS) {
+        if !meets_msrv(self.msrv, msrvs::MANUAL_BITS) {
             return;
         }
 
diff --git a/src/tools/clippy/clippy_lints/src/manual_map.rs b/src/tools/clippy/clippy_lints/src/manual_map.rs
index 8475e367b09..230ae029ed9 100644
--- a/src/tools/clippy/clippy_lints/src/manual_map.rs
+++ b/src/tools/clippy/clippy_lints/src/manual_map.rs
@@ -46,7 +46,7 @@ declare_clippy_lint! {
 declare_lint_pass!(ManualMap => [MANUAL_MAP]);
 
 impl<'tcx> LateLintPass<'tcx> for ManualMap {
-    #[allow(clippy::too_many_lines)]
+    #[expect(clippy::too_many_lines)]
     fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
         let (scrutinee, then_pat, then_body, else_pat, else_body) = match IfLetOrMatch::parse(cx, expr) {
             Some(IfLetOrMatch::IfLet(scrutinee, pat, body, Some(r#else))) => (scrutinee, pat, body, None, r#else),
diff --git a/src/tools/clippy/clippy_lints/src/manual_non_exhaustive.rs b/src/tools/clippy/clippy_lints/src/manual_non_exhaustive.rs
index 09164690700..80845ace3f9 100644
--- a/src/tools/clippy/clippy_lints/src/manual_non_exhaustive.rs
+++ b/src/tools/clippy/clippy_lints/src/manual_non_exhaustive.rs
@@ -1,6 +1,6 @@
 use clippy_utils::diagnostics::span_lint_and_then;
 use clippy_utils::source::snippet_opt;
-use clippy_utils::{is_lint_allowed, meets_msrv, msrvs};
+use clippy_utils::{is_doc_hidden, is_lint_allowed, meets_msrv, msrvs};
 use rustc_ast::ast::{self, VisibilityKind};
 use rustc_data_structures::fx::FxHashSet;
 use rustc_errors::Applicability;
@@ -61,7 +61,7 @@ declare_clippy_lint! {
     "manual implementations of the non-exhaustive pattern can be simplified using #[non_exhaustive]"
 }
 
-#[allow(clippy::module_name_repetitions)]
+#[expect(clippy::module_name_repetitions)]
 pub struct ManualNonExhaustiveStruct {
     msrv: Option<RustcVersion>,
 }
@@ -75,7 +75,7 @@ impl ManualNonExhaustiveStruct {
 
 impl_lint_pass!(ManualNonExhaustiveStruct => [MANUAL_NON_EXHAUSTIVE]);
 
-#[allow(clippy::module_name_repetitions)]
+#[expect(clippy::module_name_repetitions)]
 pub struct ManualNonExhaustiveEnum {
     msrv: Option<RustcVersion>,
     constructed_enum_variants: FxHashSet<(DefId, DefId)>,
@@ -97,7 +97,7 @@ impl_lint_pass!(ManualNonExhaustiveEnum => [MANUAL_NON_EXHAUSTIVE]);
 
 impl EarlyLintPass for ManualNonExhaustiveStruct {
     fn check_item(&mut self, cx: &EarlyContext<'_>, item: &ast::Item) {
-        if !meets_msrv(self.msrv.as_ref(), &msrvs::NON_EXHAUSTIVE) {
+        if !meets_msrv(self.msrv, msrvs::NON_EXHAUSTIVE) {
             return;
         }
 
@@ -149,7 +149,7 @@ impl EarlyLintPass for ManualNonExhaustiveStruct {
 
 impl<'tcx> LateLintPass<'tcx> for ManualNonExhaustiveEnum {
     fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx hir::Item<'_>) {
-        if !meets_msrv(self.msrv.as_ref(), &msrvs::NON_EXHAUSTIVE) {
+        if !meets_msrv(self.msrv, msrvs::NON_EXHAUSTIVE) {
             return;
         }
 
@@ -160,7 +160,7 @@ impl<'tcx> LateLintPass<'tcx> for ManualNonExhaustiveEnum {
                 let id = cx.tcx.hir().local_def_id(v.id);
                 (matches!(v.data, hir::VariantData::Unit(_))
                     && v.ident.as_str().starts_with('_')
-                    && cx.tcx.is_doc_hidden(id.to_def_id()))
+                    && is_doc_hidden(cx.tcx.hir().attrs(v.id)))
                 .then(|| (id, v.span))
             });
             if let Some((id, span)) = iter.next()
diff --git a/src/tools/clippy/clippy_lints/src/manual_strip.rs b/src/tools/clippy/clippy_lints/src/manual_strip.rs
index aacabf303a7..dfb3efc4e28 100644
--- a/src/tools/clippy/clippy_lints/src/manual_strip.rs
+++ b/src/tools/clippy/clippy_lints/src/manual_strip.rs
@@ -68,7 +68,7 @@ enum StripKind {
 
 impl<'tcx> LateLintPass<'tcx> for ManualStrip {
     fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
-        if !meets_msrv(self.msrv.as_ref(), &msrvs::STR_STRIP_PREFIX) {
+        if !meets_msrv(self.msrv, msrvs::STR_STRIP_PREFIX) {
             return;
         }
 
diff --git a/src/tools/clippy/clippy_lints/src/map_clone.rs b/src/tools/clippy/clippy_lints/src/map_clone.rs
index ceb66947d02..a13d191375b 100644
--- a/src/tools/clippy/clippy_lints/src/map_clone.rs
+++ b/src/tools/clippy/clippy_lints/src/map_clone.rs
@@ -144,7 +144,7 @@ impl MapClone {
     fn lint_explicit_closure(&self, cx: &LateContext<'_>, replace: Span, root: Span, is_copy: bool) {
         let mut applicability = Applicability::MachineApplicable;
 
-        let (message, sugg_method) = if is_copy && meets_msrv(self.msrv.as_ref(), &msrvs::ITERATOR_COPIED) {
+        let (message, sugg_method) = if is_copy && meets_msrv(self.msrv, msrvs::ITERATOR_COPIED) {
             ("you are using an explicit closure for copying elements", "copied")
         } else {
             ("you are using an explicit closure for cloning elements", "cloned")
diff --git a/src/tools/clippy/clippy_lints/src/matches/match_same_arms.rs b/src/tools/clippy/clippy_lints/src/matches/match_same_arms.rs
index 9b7344fb8b0..a96a7fe55f3 100644
--- a/src/tools/clippy/clippy_lints/src/matches/match_same_arms.rs
+++ b/src/tools/clippy/clippy_lints/src/matches/match_same_arms.rs
@@ -16,7 +16,7 @@ use std::collections::hash_map::Entry;
 
 use super::MATCH_SAME_ARMS;
 
-#[allow(clippy::too_many_lines)]
+#[expect(clippy::too_many_lines)]
 pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, arms: &'tcx [Arm<'_>]) {
     let hash = |&(_, arm): &(usize, &Arm<'_>)| -> u64 {
         let mut h = SpanlessHash::new(cx);
@@ -225,9 +225,9 @@ fn iter_matching_struct_fields<'a>(
     Iter(left.iter(), right.iter())
 }
 
-#[allow(clippy::similar_names)]
+#[expect(clippy::similar_names)]
 impl<'a> NormalizedPat<'a> {
-    #[allow(clippy::too_many_lines)]
+    #[expect(clippy::too_many_lines)]
     fn from_pat(cx: &LateContext<'_>, arena: &'a DroplessArena, pat: &'a Pat<'_>) -> Self {
         match pat.kind {
             PatKind::Wild | PatKind::Binding(.., None) => Self::Wild,
diff --git a/src/tools/clippy/clippy_lints/src/matches/match_single_binding.rs b/src/tools/clippy/clippy_lints/src/matches/match_single_binding.rs
index 39fe54648fb..a59711d4cac 100644
--- a/src/tools/clippy/clippy_lints/src/matches/match_single_binding.rs
+++ b/src/tools/clippy/clippy_lints/src/matches/match_single_binding.rs
@@ -1,15 +1,22 @@
 use clippy_utils::diagnostics::span_lint_and_sugg;
-use clippy_utils::source::{indent_of, snippet_block, snippet_with_applicability};
+use clippy_utils::macros::HirNode;
+use clippy_utils::source::{indent_of, snippet, snippet_block, snippet_with_applicability};
 use clippy_utils::sugg::Sugg;
 use clippy_utils::{get_parent_expr, is_refutable, peel_blocks};
 use rustc_errors::Applicability;
-use rustc_hir::{Arm, Expr, ExprKind, Local, Node, PatKind};
+use rustc_hir::{Arm, Expr, ExprKind, Node, PatKind};
 use rustc_lint::LateContext;
+use rustc_span::Span;
 
 use super::MATCH_SINGLE_BINDING;
 
-#[allow(clippy::too_many_lines)]
-pub(crate) fn check<'a>(cx: &LateContext<'a>, ex: &Expr<'a>, arms: &[Arm<'_>], expr: &Expr<'_>) {
+enum AssignmentExpr {
+    Assign { span: Span, match_span: Span },
+    Local { span: Span, pat_span: Span },
+}
+
+#[expect(clippy::too_many_lines)]
+pub(crate) fn check<'a>(cx: &LateContext<'a>, ex: &Expr<'a>, arms: &[Arm<'_>], expr: &Expr<'a>) {
     if expr.span.from_expansion() || arms.len() != 1 || is_refutable(cx, arms[0].pat) {
         return;
     }
@@ -42,61 +49,59 @@ pub(crate) fn check<'a>(cx: &LateContext<'a>, ex: &Expr<'a>, arms: &[Arm<'_>], e
     let mut applicability = Applicability::MaybeIncorrect;
     match arms[0].pat.kind {
         PatKind::Binding(..) | PatKind::Tuple(_, _) | PatKind::Struct(..) => {
-            // If this match is in a local (`let`) stmt
-            let (target_span, sugg) = if let Some(parent_let_node) = opt_parent_let(cx, ex) {
-                (
-                    parent_let_node.span,
+            let (target_span, sugg) = match opt_parent_assign_span(cx, ex) {
+                Some(AssignmentExpr::Assign { span, match_span }) => {
+                    let sugg = sugg_with_curlies(
+                        cx,
+                        (ex, expr),
+                        (bind_names, matched_vars),
+                        &*snippet_body,
+                        &mut applicability,
+                        Some(span),
+                    );
+
+                    span_lint_and_sugg(
+                        cx,
+                        MATCH_SINGLE_BINDING,
+                        span.to(match_span),
+                        "this assignment could be simplified",
+                        "consider removing the `match` expression",
+                        sugg,
+                        applicability,
+                    );
+
+                    return;
+                },
+                Some(AssignmentExpr::Local { span, pat_span }) => (
+                    span,
                     format!(
                         "let {} = {};\n{}let {} = {};",
                         snippet_with_applicability(cx, bind_names, "..", &mut applicability),
                         snippet_with_applicability(cx, matched_vars, "..", &mut applicability),
                         " ".repeat(indent_of(cx, expr.span).unwrap_or(0)),
-                        snippet_with_applicability(cx, parent_let_node.pat.span, "..", &mut applicability),
+                        snippet_with_applicability(cx, pat_span, "..", &mut applicability),
                         snippet_body
                     ),
-                )
-            } else {
-                // If we are in closure, we need curly braces around suggestion
-                let mut indent = " ".repeat(indent_of(cx, ex.span).unwrap_or(0));
-                let (mut cbrace_start, mut cbrace_end) = ("".to_string(), "".to_string());
-                if let Some(parent_expr) = get_parent_expr(cx, expr) {
-                    if let ExprKind::Closure(..) = parent_expr.kind {
-                        cbrace_end = format!("\n{}}}", indent);
-                        // Fix body indent due to the closure
-                        indent = " ".repeat(indent_of(cx, bind_names).unwrap_or(0));
-                        cbrace_start = format!("{{\n{}", indent);
-                    }
-                }
-                // If the parent is already an arm, and the body is another match statement,
-                // we need curly braces around suggestion
-                let parent_node_id = cx.tcx.hir().get_parent_node(expr.hir_id);
-                if let Node::Arm(arm) = &cx.tcx.hir().get(parent_node_id) {
-                    if let ExprKind::Match(..) = arm.body.kind {
-                        cbrace_end = format!("\n{}}}", indent);
-                        // Fix body indent due to the match
-                        indent = " ".repeat(indent_of(cx, bind_names).unwrap_or(0));
-                        cbrace_start = format!("{{\n{}", indent);
-                    }
-                }
-                (
-                    expr.span,
-                    format!(
-                        "{}let {} = {};\n{}{}{}",
-                        cbrace_start,
-                        snippet_with_applicability(cx, bind_names, "..", &mut applicability),
-                        snippet_with_applicability(cx, matched_vars, "..", &mut applicability),
-                        indent,
-                        snippet_body,
-                        cbrace_end
-                    ),
-                )
+                ),
+                None => {
+                    let sugg = sugg_with_curlies(
+                        cx,
+                        (ex, expr),
+                        (bind_names, matched_vars),
+                        &*snippet_body,
+                        &mut applicability,
+                        None,
+                    );
+                    (expr.span, sugg)
+                },
             };
+
             span_lint_and_sugg(
                 cx,
                 MATCH_SINGLE_BINDING,
                 target_span,
                 "this match could be written as a `let` statement",
-                "consider using `let` statement",
+                "consider using a `let` statement",
                 sugg,
                 applicability,
             );
@@ -110,6 +115,7 @@ pub(crate) fn check<'a>(cx: &LateContext<'a>, ex: &Expr<'a>, arms: &[Arm<'_>], e
                     indent,
                     snippet_body
                 );
+
                 span_lint_and_sugg(
                     cx,
                     MATCH_SINGLE_BINDING,
@@ -135,15 +141,76 @@ pub(crate) fn check<'a>(cx: &LateContext<'a>, ex: &Expr<'a>, arms: &[Arm<'_>], e
     }
 }
 
-/// Returns true if the `ex` match expression is in a local (`let`) statement
-fn opt_parent_let<'a>(cx: &LateContext<'a>, ex: &Expr<'a>) -> Option<&'a Local<'a>> {
+/// Returns true if the `ex` match expression is in a local (`let`) or assign expression
+fn opt_parent_assign_span<'a>(cx: &LateContext<'a>, ex: &Expr<'a>) -> Option<AssignmentExpr> {
     let map = &cx.tcx.hir();
-    if_chain! {
-        if let Some(Node::Expr(parent_arm_expr)) = map.find(map.get_parent_node(ex.hir_id));
-        if let Some(Node::Local(parent_let_expr)) = map.find(map.get_parent_node(parent_arm_expr.hir_id));
-        then {
-            return Some(parent_let_expr);
-        }
+
+    if let Some(Node::Expr(parent_arm_expr)) = map.find(map.get_parent_node(ex.hir_id)) {
+        return match map.find(map.get_parent_node(parent_arm_expr.hir_id)) {
+            Some(Node::Local(parent_let_expr)) => Some(AssignmentExpr::Local {
+                span: parent_let_expr.span,
+                pat_span: parent_let_expr.pat.span(),
+            }),
+            Some(Node::Expr(Expr {
+                kind: ExprKind::Assign(parent_assign_expr, match_expr, _),
+                ..
+            })) => Some(AssignmentExpr::Assign {
+                span: parent_assign_expr.span,
+                match_span: match_expr.span,
+            }),
+            _ => None,
+        };
     }
+
     None
 }
+
+fn sugg_with_curlies<'a>(
+    cx: &LateContext<'a>,
+    (ex, match_expr): (&Expr<'a>, &Expr<'a>),
+    (bind_names, matched_vars): (Span, Span),
+    snippet_body: &str,
+    applicability: &mut Applicability,
+    assignment: Option<Span>,
+) -> String {
+    let mut indent = " ".repeat(indent_of(cx, ex.span).unwrap_or(0));
+
+    let (mut cbrace_start, mut cbrace_end) = (String::new(), String::new());
+    if let Some(parent_expr) = get_parent_expr(cx, match_expr) {
+        if let ExprKind::Closure(..) = parent_expr.kind {
+            cbrace_end = format!("\n{}}}", indent);
+            // Fix body indent due to the closure
+            indent = " ".repeat(indent_of(cx, bind_names).unwrap_or(0));
+            cbrace_start = format!("{{\n{}", indent);
+        }
+    }
+
+    // If the parent is already an arm, and the body is another match statement,
+    // we need curly braces around suggestion
+    let parent_node_id = cx.tcx.hir().get_parent_node(match_expr.hir_id);
+    if let Node::Arm(arm) = &cx.tcx.hir().get(parent_node_id) {
+        if let ExprKind::Match(..) = arm.body.kind {
+            cbrace_end = format!("\n{}}}", indent);
+            // Fix body indent due to the match
+            indent = " ".repeat(indent_of(cx, bind_names).unwrap_or(0));
+            cbrace_start = format!("{{\n{}", indent);
+        }
+    }
+
+    let assignment_str = assignment.map_or_else(String::new, |span| {
+        let mut s = snippet(cx, span, "..").to_string();
+        s.push_str(" = ");
+        s
+    });
+
+    format!(
+        "{}let {} = {};\n{}{}{}{}",
+        cbrace_start,
+        snippet_with_applicability(cx, bind_names, "..", applicability),
+        snippet_with_applicability(cx, matched_vars, "..", applicability),
+        indent,
+        assignment_str,
+        snippet_body,
+        cbrace_end
+    )
+}
diff --git a/src/tools/clippy/clippy_lints/src/matches/match_wild_enum.rs b/src/tools/clippy/clippy_lints/src/matches/match_wild_enum.rs
index fc45ccee185..6f8d766aef7 100644
--- a/src/tools/clippy/clippy_lints/src/matches/match_wild_enum.rs
+++ b/src/tools/clippy/clippy_lints/src/matches/match_wild_enum.rs
@@ -10,7 +10,7 @@ use rustc_span::sym;
 
 use super::{MATCH_WILDCARD_FOR_SINGLE_VARIANTS, WILDCARD_ENUM_MATCH_ARM};
 
-#[allow(clippy::too_many_lines)]
+#[expect(clippy::too_many_lines)]
 pub(crate) fn check(cx: &LateContext<'_>, ex: &Expr<'_>, arms: &[Arm<'_>]) {
     let ty = cx.typeck_results().expr_ty(ex).peel_refs();
     let adt_def = match ty.kind() {
@@ -56,7 +56,6 @@ pub(crate) fn check(cx: &LateContext<'_>, ex: &Expr<'_>, arms: &[Arm<'_>]) {
         recurse_or_patterns(arm.pat, |pat| {
             let path = match &peel_hir_pat_refs(pat).0.kind {
                 PatKind::Path(path) => {
-                    #[allow(clippy::match_same_arms)]
                     let id = match cx.qpath_res(path, pat.hir_id) {
                         Res::Def(
                             DefKind::Const | DefKind::ConstParam | DefKind::AnonConst | DefKind::InlineConst,
diff --git a/src/tools/clippy/clippy_lints/src/matches/mod.rs b/src/tools/clippy/clippy_lints/src/matches/mod.rs
index 401ecef460c..3d8391bce2b 100644
--- a/src/tools/clippy/clippy_lints/src/matches/mod.rs
+++ b/src/tools/clippy/clippy_lints/src/matches/mod.rs
@@ -658,7 +658,7 @@ impl<'tcx> LateLintPass<'tcx> for Matches {
             }
             if !contains_cfg_arm(cx, expr, ex, arms) {
                 if source == MatchSource::Normal {
-                    if !(meets_msrv(self.msrv.as_ref(), &msrvs::MATCHES_MACRO)
+                    if !(meets_msrv(self.msrv, msrvs::MATCHES_MACRO)
                         && match_like_matches::check_match(cx, expr, ex, arms))
                     {
                         match_same_arms::check(cx, arms);
@@ -685,7 +685,7 @@ impl<'tcx> LateLintPass<'tcx> for Matches {
             match_wild_err_arm::check(cx, ex, arms);
             wild_in_or_pats::check(cx, arms);
         } else {
-            if meets_msrv(self.msrv.as_ref(), &msrvs::MATCHES_MACRO) {
+            if meets_msrv(self.msrv, msrvs::MATCHES_MACRO) {
                 match_like_matches::check(cx, expr);
             }
             redundant_pattern_match::check(cx, expr);
diff --git a/src/tools/clippy/clippy_lints/src/matches/redundant_pattern_match.rs b/src/tools/clippy/clippy_lints/src/matches/redundant_pattern_match.rs
index 37b67647efe..1a8b9d15f37 100644
--- a/src/tools/clippy/clippy_lints/src/matches/redundant_pattern_match.rs
+++ b/src/tools/clippy/clippy_lints/src/matches/redundant_pattern_match.rs
@@ -340,7 +340,7 @@ pub(super) fn check_match<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, op
     }
 }
 
-#[allow(clippy::too_many_arguments)]
+#[expect(clippy::too_many_arguments)]
 fn find_good_method_for_match<'a>(
     cx: &LateContext<'_>,
     arms: &[Arm<'_>],
diff --git a/src/tools/clippy/clippy_lints/src/mem_replace.rs b/src/tools/clippy/clippy_lints/src/mem_replace.rs
index 054937e3e36..41073d40f3d 100644
--- a/src/tools/clippy/clippy_lints/src/mem_replace.rs
+++ b/src/tools/clippy/clippy_lints/src/mem_replace.rs
@@ -254,7 +254,7 @@ impl<'tcx> LateLintPass<'tcx> for MemReplace {
             then {
                 check_replace_option_with_none(cx, src, dest, expr.span);
                 check_replace_with_uninit(cx, src, dest, expr.span);
-                if meets_msrv(self.msrv.as_ref(), &msrvs::MEM_TAKE) {
+                if meets_msrv(self.msrv, msrvs::MEM_TAKE) {
                     check_replace_with_default(cx, src, dest, expr.span);
                 }
             }
diff --git a/src/tools/clippy/clippy_lints/src/methods/cloned_instead_of_copied.rs b/src/tools/clippy/clippy_lints/src/methods/cloned_instead_of_copied.rs
index 6d30bb5a278..e9aeab2d5b6 100644
--- a/src/tools/clippy/clippy_lints/src/methods/cloned_instead_of_copied.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/cloned_instead_of_copied.rs
@@ -10,16 +10,16 @@ use rustc_span::{sym, Span};
 
 use super::CLONED_INSTEAD_OF_COPIED;
 
-pub fn check(cx: &LateContext<'_>, expr: &Expr<'_>, recv: &Expr<'_>, span: Span, msrv: Option<&RustcVersion>) {
+pub fn check(cx: &LateContext<'_>, expr: &Expr<'_>, recv: &Expr<'_>, span: Span, msrv: Option<RustcVersion>) {
     let recv_ty = cx.typeck_results().expr_ty_adjusted(recv);
     let inner_ty = match recv_ty.kind() {
         // `Option<T>` -> `T`
         ty::Adt(adt, subst)
-            if cx.tcx.is_diagnostic_item(sym::Option, adt.did()) && meets_msrv(msrv, &msrvs::OPTION_COPIED) =>
+            if cx.tcx.is_diagnostic_item(sym::Option, adt.did()) && meets_msrv(msrv, msrvs::OPTION_COPIED) =>
         {
             subst.type_at(0)
         },
-        _ if is_trait_method(cx, expr, sym::Iterator) && meets_msrv(msrv, &msrvs::ITERATOR_COPIED) => {
+        _ if is_trait_method(cx, expr, sym::Iterator) && meets_msrv(msrv, msrvs::ITERATOR_COPIED) => {
             match get_iterator_item_ty(cx, recv_ty) {
                 // <T as Iterator>::Item
                 Some(ty) => ty,
diff --git a/src/tools/clippy/clippy_lints/src/methods/err_expect.rs b/src/tools/clippy/clippy_lints/src/methods/err_expect.rs
index be9d4ad94fb..570a1b87358 100644
--- a/src/tools/clippy/clippy_lints/src/methods/err_expect.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/err_expect.rs
@@ -13,7 +13,7 @@ pub(super) fn check(
     cx: &LateContext<'_>,
     _expr: &rustc_hir::Expr<'_>,
     recv: &rustc_hir::Expr<'_>,
-    msrv: Option<&RustcVersion>,
+    msrv: Option<RustcVersion>,
     expect_span: Span,
     err_span: Span,
 ) {
@@ -21,7 +21,7 @@ pub(super) fn check(
         if is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(recv), sym::Result);
         // Test the version to make sure the lint can be showed (expect_err has been
         // introduced in rust 1.17.0 : https://github.com/rust-lang/rust/pull/38982)
-        if meets_msrv(msrv, &msrvs::EXPECT_ERR);
+        if meets_msrv(msrv, msrvs::EXPECT_ERR);
 
         // Grabs the `Result<T, E>` type
         let result_type = cx.typeck_results().expr_ty(recv);
diff --git a/src/tools/clippy/clippy_lints/src/methods/expect_used.rs b/src/tools/clippy/clippy_lints/src/methods/expect_used.rs
index 55be513c5bb..fbc3348f185 100644
--- a/src/tools/clippy/clippy_lints/src/methods/expect_used.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/expect_used.rs
@@ -1,4 +1,5 @@
 use clippy_utils::diagnostics::span_lint_and_help;
+use clippy_utils::is_in_test_function;
 use clippy_utils::ty::is_type_diagnostic_item;
 use rustc_hir as hir;
 use rustc_lint::LateContext;
@@ -7,7 +8,7 @@ use rustc_span::sym;
 use super::EXPECT_USED;
 
 /// lint use of `expect()` for `Option`s and `Result`s
-pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, recv: &hir::Expr<'_>) {
+pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, recv: &hir::Expr<'_>, allow_expect_in_tests: bool) {
     let obj_ty = cx.typeck_results().expr_ty(recv).peel_refs();
 
     let mess = if is_type_diagnostic_item(cx, obj_ty, sym::Option) {
@@ -18,6 +19,10 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, recv: &hir::Expr
         None
     };
 
+    if allow_expect_in_tests && is_in_test_function(cx.tcx, expr.hir_id) {
+        return;
+    }
+
     if let Some((lint, kind, none_value)) = mess {
         span_lint_and_help(
             cx,
diff --git a/src/tools/clippy/clippy_lints/src/methods/filter_map_next.rs b/src/tools/clippy/clippy_lints/src/methods/filter_map_next.rs
index f0d69a1f42e..38ec4d8e3ab 100644
--- a/src/tools/clippy/clippy_lints/src/methods/filter_map_next.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/filter_map_next.rs
@@ -14,10 +14,10 @@ pub(super) fn check<'tcx>(
     expr: &'tcx hir::Expr<'_>,
     recv: &'tcx hir::Expr<'_>,
     arg: &'tcx hir::Expr<'_>,
-    msrv: Option<&RustcVersion>,
+    msrv: Option<RustcVersion>,
 ) {
     if is_trait_method(cx, expr, sym::Iterator) {
-        if !meets_msrv(msrv, &msrvs::ITERATOR_FIND_MAP) {
+        if !meets_msrv(msrv, msrvs::ITERATOR_FIND_MAP) {
             return;
         }
 
diff --git a/src/tools/clippy/clippy_lints/src/methods/is_digit_ascii_radix.rs b/src/tools/clippy/clippy_lints/src/methods/is_digit_ascii_radix.rs
index ad333df2f2d..aa176dcc8b4 100644
--- a/src/tools/clippy/clippy_lints/src/methods/is_digit_ascii_radix.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/is_digit_ascii_radix.rs
@@ -15,9 +15,9 @@ pub(super) fn check<'tcx>(
     expr: &'tcx Expr<'_>,
     self_arg: &'tcx Expr<'_>,
     radix: &'tcx Expr<'_>,
-    msrv: Option<&RustcVersion>,
+    msrv: Option<RustcVersion>,
 ) {
-    if !meets_msrv(msrv, &msrvs::IS_ASCII_DIGIT) {
+    if !meets_msrv(msrv, msrvs::IS_ASCII_DIGIT) {
         return;
     }
 
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 9ec84e76519..4a8e7ce4ddb 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
@@ -19,13 +19,13 @@ pub(super) fn check<'tcx>(
     recv: &'tcx hir::Expr<'_>,
     map_arg: &'tcx hir::Expr<'_>,
     unwrap_arg: &'tcx hir::Expr<'_>,
-    msrv: Option<&RustcVersion>,
+    msrv: Option<RustcVersion>,
 ) -> bool {
     // lint if the caller of `map()` is an `Option`
     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);
 
-    if is_result && !meets_msrv(msrv, &msrvs::RESULT_MAP_OR_ELSE) {
+    if is_result && !meets_msrv(msrv, msrvs::RESULT_MAP_OR_ELSE) {
         return false;
     }
 
diff --git a/src/tools/clippy/clippy_lints/src/methods/mod.rs b/src/tools/clippy/clippy_lints/src/methods/mod.rs
index f3be71f6b8b..35fc452ed7c 100644
--- a/src/tools/clippy/clippy_lints/src/methods/mod.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/mod.rs
@@ -1563,7 +1563,7 @@ declare_clippy_lint! {
     #[clippy::version = "1.39.0"]
     pub MANUAL_SATURATING_ARITHMETIC,
     style,
-    "`.chcked_add/sub(x).unwrap_or(MAX/MIN)`"
+    "`.checked_add/sub(x).unwrap_or(MAX/MIN)`"
 }
 
 declare_clippy_lint! {
@@ -1776,8 +1776,6 @@ declare_clippy_lint! {
     ///
     /// ### Example
     /// ```rust
-    /// use std::iter::FromIterator;
-    ///
     /// let five_fives = std::iter::repeat(5).take(5);
     ///
     /// let v = Vec::from_iter(five_fives);
@@ -2200,14 +2198,23 @@ declare_clippy_lint! {
 pub struct Methods {
     avoid_breaking_exported_api: bool,
     msrv: Option<RustcVersion>,
+    allow_expect_in_tests: bool,
+    allow_unwrap_in_tests: bool,
 }
 
 impl Methods {
     #[must_use]
-    pub fn new(avoid_breaking_exported_api: bool, msrv: Option<RustcVersion>) -> Self {
+    pub fn new(
+        avoid_breaking_exported_api: bool,
+        msrv: Option<RustcVersion>,
+        allow_expect_in_tests: bool,
+        allow_unwrap_in_tests: bool,
+    ) -> Self {
         Self {
             avoid_breaking_exported_api,
             msrv,
+            allow_expect_in_tests,
+            allow_unwrap_in_tests,
         }
     }
 }
@@ -2306,7 +2313,7 @@ impl<'tcx> LateLintPass<'tcx> for Methods {
             return;
         }
 
-        check_methods(cx, expr, self.msrv.as_ref());
+        self.check_methods(cx, expr);
 
         match expr.kind {
             hir::ExprKind::Call(func, args) => {
@@ -2322,7 +2329,7 @@ impl<'tcx> LateLintPass<'tcx> for Methods {
                 single_char_add_str::check(cx, expr, args);
                 into_iter_on_ref::check(cx, expr, method_span, method_call.ident.name, args);
                 single_char_pattern::check(cx, expr, method_call.ident.name, args);
-                unnecessary_to_owned::check(cx, expr, method_call.ident.name, args, self.msrv.as_ref());
+                unnecessary_to_owned::check(cx, expr, method_call.ident.name, args, self.msrv);
             },
             hir::ExprKind::Binary(op, lhs, rhs) if op.node == hir::BinOpKind::Eq || op.node == hir::BinOpKind::Ne => {
                 let mut info = BinaryExprInfo {
@@ -2505,196 +2512,201 @@ impl<'tcx> LateLintPass<'tcx> for Methods {
     extract_msrv_attr!(LateContext);
 }
 
-#[allow(clippy::too_many_lines)]
-fn check_methods<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, msrv: Option<&RustcVersion>) {
-    if let Some((name, [recv, args @ ..], span)) = method_call(expr) {
-        match (name, args) {
-            ("add" | "offset" | "sub" | "wrapping_offset" | "wrapping_add" | "wrapping_sub", [_arg]) => {
-                zst_offset::check(cx, expr, recv);
-            },
-            ("and_then", [arg]) => {
-                let biom_option_linted = bind_instead_of_map::OptionAndThenSome::check(cx, expr, recv, arg);
-                let biom_result_linted = bind_instead_of_map::ResultAndThenOk::check(cx, expr, recv, arg);
-                if !biom_option_linted && !biom_result_linted {
-                    unnecessary_lazy_eval::check(cx, expr, recv, arg, "and");
-                }
-            },
-            ("as_deref" | "as_deref_mut", []) => {
-                needless_option_as_deref::check(cx, expr, recv, name);
-            },
-            ("as_mut", []) => useless_asref::check(cx, expr, "as_mut", recv),
-            ("as_ref", []) => useless_asref::check(cx, expr, "as_ref", recv),
-            ("assume_init", []) => uninit_assumed_init::check(cx, expr, recv),
-            ("cloned", []) => cloned_instead_of_copied::check(cx, expr, recv, span, msrv),
-            ("collect", []) => match method_call(recv) {
-                Some((name @ ("cloned" | "copied"), [recv2], _)) => {
-                    iter_cloned_collect::check(cx, name, expr, recv2);
+impl Methods {
+    #[allow(clippy::too_many_lines)]
+    fn check_methods<'tcx>(&self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
+        if let Some((name, [recv, args @ ..], span)) = method_call(expr) {
+            match (name, args) {
+                ("add" | "offset" | "sub" | "wrapping_offset" | "wrapping_add" | "wrapping_sub", [_arg]) => {
+                    zst_offset::check(cx, expr, recv);
                 },
-                Some(("map", [m_recv, m_arg], _)) => {
-                    map_collect_result_unit::check(cx, expr, m_recv, m_arg, recv);
-                },
-                Some(("take", [take_self_arg, take_arg], _)) => {
-                    if meets_msrv(msrv, &msrvs::STR_REPEAT) {
-                        manual_str_repeat::check(cx, expr, recv, take_self_arg, take_arg);
+                ("and_then", [arg]) => {
+                    let biom_option_linted = bind_instead_of_map::OptionAndThenSome::check(cx, expr, recv, arg);
+                    let biom_result_linted = bind_instead_of_map::ResultAndThenOk::check(cx, expr, recv, arg);
+                    if !biom_option_linted && !biom_result_linted {
+                        unnecessary_lazy_eval::check(cx, expr, recv, arg, "and");
                     }
                 },
-                _ => {},
-            },
-            (name @ "count", args @ []) => match method_call(recv) {
-                Some(("cloned", [recv2], _)) => iter_overeager_cloned::check(cx, expr, recv2, name, args),
-                Some((name2 @ ("into_iter" | "iter" | "iter_mut"), [recv2], _)) => {
-                    iter_count::check(cx, expr, recv2, name2);
+                ("as_deref" | "as_deref_mut", []) => {
+                    needless_option_as_deref::check(cx, expr, recv, name);
                 },
-                Some(("map", [_, arg], _)) => suspicious_map::check(cx, expr, recv, arg),
-                _ => {},
-            },
-            ("drain", [arg]) => {
-                iter_with_drain::check(cx, expr, recv, span, arg);
-            },
-            ("expect", [_]) => match method_call(recv) {
-                Some(("ok", [recv], _)) => ok_expect::check(cx, expr, recv),
-                Some(("err", [recv], err_span)) => err_expect::check(cx, expr, recv, msrv, span, err_span),
-                _ => expect_used::check(cx, expr, recv),
-            },
-            ("extend", [arg]) => {
-                string_extend_chars::check(cx, expr, recv, arg);
-                extend_with_drain::check(cx, expr, recv, arg);
-            },
-            ("filter_map", [arg]) => {
-                unnecessary_filter_map::check(cx, expr, arg, name);
-                filter_map_identity::check(cx, expr, arg, span);
-            },
-            ("find_map", [arg]) => {
-                unnecessary_filter_map::check(cx, expr, arg, name);
-            },
-            ("flat_map", [arg]) => {
-                flat_map_identity::check(cx, expr, arg, span);
-                flat_map_option::check(cx, expr, arg, span);
-            },
-            (name @ "flatten", args @ []) => match method_call(recv) {
-                Some(("map", [recv, map_arg], map_span)) => map_flatten::check(cx, expr, recv, map_arg, map_span),
-                Some(("cloned", [recv2], _)) => iter_overeager_cloned::check(cx, expr, recv2, name, args),
-                _ => {},
-            },
-            ("fold", [init, acc]) => unnecessary_fold::check(cx, expr, init, acc, span),
-            ("for_each", [_]) => {
-                if let Some(("inspect", [_, _], span2)) = method_call(recv) {
-                    inspect_for_each::check(cx, expr, span2);
-                }
-            },
-            ("get_or_insert_with", [arg]) => unnecessary_lazy_eval::check(cx, expr, recv, arg, "get_or_insert"),
-            ("is_file", []) => filetype_is_file::check(cx, expr, recv),
-            ("is_digit", [radix]) => is_digit_ascii_radix::check(cx, expr, recv, radix, msrv),
-            ("is_none", []) => check_is_some_is_none(cx, expr, recv, false),
-            ("is_some", []) => check_is_some_is_none(cx, expr, recv, true),
-            ("join", [join_arg]) => {
-                if let Some(("collect", _, span)) = method_call(recv) {
-                    unnecessary_join::check(cx, expr, recv, join_arg, span);
-                }
-            },
-            ("last", args @ []) | ("skip", args @ [_]) => {
-                if let Some((name2, [recv2, args2 @ ..], _span2)) = method_call(recv) {
-                    if let ("cloned", []) = (name2, args2) {
-                        iter_overeager_cloned::check(cx, expr, recv2, name, args);
-                    }
-                }
-            },
-            (name @ ("map" | "map_err"), [m_arg]) => {
-                if let Some((name, [recv2, args @ ..], span2)) = method_call(recv) {
-                    match (name, args) {
-                        ("as_mut", []) => option_as_ref_deref::check(cx, expr, recv2, m_arg, true, msrv),
-                        ("as_ref", []) => option_as_ref_deref::check(cx, expr, recv2, m_arg, false, msrv),
-                        ("filter", [f_arg]) => {
-                            filter_map::check(cx, expr, recv2, f_arg, span2, recv, m_arg, span, false);
-                        },
-                        ("find", [f_arg]) => filter_map::check(cx, expr, recv2, f_arg, span2, recv, m_arg, span, true),
-                        _ => {},
-                    }
-                }
-                map_identity::check(cx, expr, recv, m_arg, name, span);
-            },
-            ("map_or", [def, map]) => option_map_or_none::check(cx, expr, recv, def, map),
-            (name @ "next", args @ []) => {
-                if let Some((name2, [recv2, args2 @ ..], _)) = method_call(recv) {
-                    match (name2, args2) {
-                        ("cloned", []) => iter_overeager_cloned::check(cx, expr, recv2, name, args),
-                        ("filter", [arg]) => filter_next::check(cx, expr, recv2, arg),
-                        ("filter_map", [arg]) => filter_map_next::check(cx, expr, recv2, arg, msrv),
-                        ("iter", []) => iter_next_slice::check(cx, expr, recv2),
-                        ("skip", [arg]) => iter_skip_next::check(cx, expr, recv2, arg),
-                        ("skip_while", [_]) => skip_while_next::check(cx, expr),
-                        _ => {},
-                    }
-                }
-            },
-            ("nth", args @ [n_arg]) => match method_call(recv) {
-                Some(("bytes", [recv2], _)) => bytes_nth::check(cx, expr, recv2, n_arg),
-                Some(("cloned", [recv2], _)) => iter_overeager_cloned::check(cx, expr, recv2, name, args),
-                Some(("iter", [recv2], _)) => iter_nth::check(cx, expr, recv2, recv, n_arg, false),
-                Some(("iter_mut", [recv2], _)) => iter_nth::check(cx, expr, recv2, recv, n_arg, true),
-                _ => iter_nth_zero::check(cx, expr, recv, n_arg),
-            },
-            ("ok_or_else", [arg]) => unnecessary_lazy_eval::check(cx, expr, recv, arg, "ok_or"),
-            ("or_else", [arg]) => {
-                if !bind_instead_of_map::ResultOrElseErrInfo::check(cx, expr, recv, arg) {
-                    unnecessary_lazy_eval::check(cx, expr, recv, arg, "or");
-                }
-            },
-            ("splitn" | "rsplitn", [count_arg, pat_arg]) => {
-                if let Some((Constant::Int(count), _)) = constant(cx, cx.typeck_results(), count_arg) {
-                    suspicious_splitn::check(cx, name, expr, recv, count);
-                    str_splitn::check(cx, name, expr, recv, pat_arg, count, msrv);
-                }
-            },
-            ("splitn_mut" | "rsplitn_mut", [count_arg, _]) => {
-                if let Some((Constant::Int(count), _)) = constant(cx, cx.typeck_results(), count_arg) {
-                    suspicious_splitn::check(cx, name, expr, recv, count);
-                }
-            },
-            ("step_by", [arg]) => iterator_step_by_zero::check(cx, expr, arg),
-            ("take", args @ [_arg]) => {
-                if let Some((name2, [recv2, args2 @ ..], _span2)) = method_call(recv) {
-                    if let ("cloned", []) = (name2, args2) {
-                        iter_overeager_cloned::check(cx, expr, recv2, name, args);
-                    }
-                }
-            },
-            ("take", []) => needless_option_take::check(cx, expr, recv),
-            ("to_os_string" | "to_owned" | "to_path_buf" | "to_vec", []) => {
-                implicit_clone::check(cx, name, expr, recv);
-            },
-            ("unwrap", []) => {
-                match method_call(recv) {
-                    Some(("get", [recv, get_arg], _)) => {
-                        get_unwrap::check(cx, expr, recv, get_arg, false);
+                ("as_mut", []) => useless_asref::check(cx, expr, "as_mut", recv),
+                ("as_ref", []) => useless_asref::check(cx, expr, "as_ref", recv),
+                ("assume_init", []) => uninit_assumed_init::check(cx, expr, recv),
+                ("cloned", []) => cloned_instead_of_copied::check(cx, expr, recv, span, self.msrv),
+                ("collect", []) => match method_call(recv) {
+                    Some((name @ ("cloned" | "copied"), [recv2], _)) => {
+                        iter_cloned_collect::check(cx, name, expr, recv2);
                     },
-                    Some(("get_mut", [recv, get_arg], _)) => {
-                        get_unwrap::check(cx, expr, recv, get_arg, true);
+                    Some(("map", [m_recv, m_arg], _)) => {
+                        map_collect_result_unit::check(cx, expr, m_recv, m_arg, recv);
                     },
-                    Some(("or", [recv, or_arg], or_span)) => {
-                        or_then_unwrap::check(cx, expr, recv, or_arg, or_span);
+                    Some(("take", [take_self_arg, take_arg], _)) => {
+                        if meets_msrv(self.msrv, msrvs::STR_REPEAT) {
+                            manual_str_repeat::check(cx, expr, recv, take_self_arg, take_arg);
+                        }
                     },
                     _ => {},
-                }
-                unwrap_used::check(cx, expr, recv);
-            },
-            ("unwrap_or", [u_arg]) => match method_call(recv) {
-                Some((arith @ ("checked_add" | "checked_sub" | "checked_mul"), [lhs, rhs], _)) => {
-                    manual_saturating_arithmetic::check(cx, expr, lhs, rhs, u_arg, &arith["checked_".len()..]);
                 },
-                Some(("map", [m_recv, m_arg], span)) => {
-                    option_map_unwrap_or::check(cx, expr, m_recv, m_arg, recv, u_arg, span);
+                (name @ "count", args @ []) => match method_call(recv) {
+                    Some(("cloned", [recv2], _)) => iter_overeager_cloned::check(cx, expr, recv2, name, args),
+                    Some((name2 @ ("into_iter" | "iter" | "iter_mut"), [recv2], _)) => {
+                        iter_count::check(cx, expr, recv2, name2);
+                    },
+                    Some(("map", [_, arg], _)) => suspicious_map::check(cx, expr, recv, arg),
+                    _ => {},
+                },
+                ("drain", [arg]) => {
+                    iter_with_drain::check(cx, expr, recv, span, arg);
+                },
+                ("expect", [_]) => match method_call(recv) {
+                    Some(("ok", [recv], _)) => ok_expect::check(cx, expr, recv),
+                    Some(("err", [recv], err_span)) => err_expect::check(cx, expr, recv, self.msrv, span, err_span),
+                    _ => expect_used::check(cx, expr, recv, self.allow_expect_in_tests),
+                },
+                ("extend", [arg]) => {
+                    string_extend_chars::check(cx, expr, recv, arg);
+                    extend_with_drain::check(cx, expr, recv, arg);
+                },
+                ("filter_map", [arg]) => {
+                    unnecessary_filter_map::check(cx, expr, arg, name);
+                    filter_map_identity::check(cx, expr, arg, span);
+                },
+                ("find_map", [arg]) => {
+                    unnecessary_filter_map::check(cx, expr, arg, name);
+                },
+                ("flat_map", [arg]) => {
+                    flat_map_identity::check(cx, expr, arg, span);
+                    flat_map_option::check(cx, expr, arg, span);
+                },
+                (name @ "flatten", args @ []) => match method_call(recv) {
+                    Some(("map", [recv, map_arg], map_span)) => map_flatten::check(cx, expr, recv, map_arg, map_span),
+                    Some(("cloned", [recv2], _)) => iter_overeager_cloned::check(cx, expr, recv2, name, args),
+                    _ => {},
+                },
+                ("fold", [init, acc]) => unnecessary_fold::check(cx, expr, init, acc, span),
+                ("for_each", [_]) => {
+                    if let Some(("inspect", [_, _], span2)) = method_call(recv) {
+                        inspect_for_each::check(cx, expr, span2);
+                    }
+                },
+                ("get_or_insert_with", [arg]) => unnecessary_lazy_eval::check(cx, expr, recv, arg, "get_or_insert"),
+                ("is_file", []) => filetype_is_file::check(cx, expr, recv),
+                ("is_digit", [radix]) => is_digit_ascii_radix::check(cx, expr, recv, radix, self.msrv),
+                ("is_none", []) => check_is_some_is_none(cx, expr, recv, false),
+                ("is_some", []) => check_is_some_is_none(cx, expr, recv, true),
+                ("join", [join_arg]) => {
+                    if let Some(("collect", _, span)) = method_call(recv) {
+                        unnecessary_join::check(cx, expr, recv, join_arg, span);
+                    }
+                },
+                ("last", args @ []) | ("skip", args @ [_]) => {
+                    if let Some((name2, [recv2, args2 @ ..], _span2)) = method_call(recv) {
+                        if let ("cloned", []) = (name2, args2) {
+                            iter_overeager_cloned::check(cx, expr, recv2, name, args);
+                        }
+                    }
+                },
+                (name @ ("map" | "map_err"), [m_arg]) => {
+                    if let Some((name, [recv2, args @ ..], span2)) = method_call(recv) {
+                        match (name, args) {
+                            ("as_mut", []) => option_as_ref_deref::check(cx, expr, recv2, m_arg, true, self.msrv),
+                            ("as_ref", []) => option_as_ref_deref::check(cx, expr, recv2, m_arg, false, self.msrv),
+                            ("filter", [f_arg]) => {
+                                filter_map::check(cx, expr, recv2, f_arg, span2, recv, m_arg, span, false);
+                            },
+                            ("find", [f_arg]) => {
+                                filter_map::check(cx, expr, recv2, f_arg, span2, recv, m_arg, span, true);
+                            },
+                            _ => {},
+                        }
+                    }
+                    map_identity::check(cx, expr, recv, m_arg, name, span);
+                },
+                ("map_or", [def, map]) => option_map_or_none::check(cx, expr, recv, def, map),
+                (name @ "next", args @ []) => {
+                    if let Some((name2, [recv2, args2 @ ..], _)) = method_call(recv) {
+                        match (name2, args2) {
+                            ("cloned", []) => iter_overeager_cloned::check(cx, expr, recv2, name, args),
+                            ("filter", [arg]) => filter_next::check(cx, expr, recv2, arg),
+                            ("filter_map", [arg]) => filter_map_next::check(cx, expr, recv2, arg, self.msrv),
+                            ("iter", []) => iter_next_slice::check(cx, expr, recv2),
+                            ("skip", [arg]) => iter_skip_next::check(cx, expr, recv2, arg),
+                            ("skip_while", [_]) => skip_while_next::check(cx, expr),
+                            _ => {},
+                        }
+                    }
+                },
+                ("nth", args @ [n_arg]) => match method_call(recv) {
+                    Some(("bytes", [recv2], _)) => bytes_nth::check(cx, expr, recv2, n_arg),
+                    Some(("cloned", [recv2], _)) => iter_overeager_cloned::check(cx, expr, recv2, name, args),
+                    Some(("iter", [recv2], _)) => iter_nth::check(cx, expr, recv2, recv, n_arg, false),
+                    Some(("iter_mut", [recv2], _)) => iter_nth::check(cx, expr, recv2, recv, n_arg, true),
+                    _ => iter_nth_zero::check(cx, expr, recv, n_arg),
+                },
+                ("ok_or_else", [arg]) => unnecessary_lazy_eval::check(cx, expr, recv, arg, "ok_or"),
+                ("or_else", [arg]) => {
+                    if !bind_instead_of_map::ResultOrElseErrInfo::check(cx, expr, recv, arg) {
+                        unnecessary_lazy_eval::check(cx, expr, recv, arg, "or");
+                    }
+                },
+                ("splitn" | "rsplitn", [count_arg, pat_arg]) => {
+                    if let Some((Constant::Int(count), _)) = constant(cx, cx.typeck_results(), count_arg) {
+                        suspicious_splitn::check(cx, name, expr, recv, count);
+                        str_splitn::check(cx, name, expr, recv, pat_arg, count, self.msrv);
+                    }
+                },
+                ("splitn_mut" | "rsplitn_mut", [count_arg, _]) => {
+                    if let Some((Constant::Int(count), _)) = constant(cx, cx.typeck_results(), count_arg) {
+                        suspicious_splitn::check(cx, name, expr, recv, count);
+                    }
+                },
+                ("step_by", [arg]) => iterator_step_by_zero::check(cx, expr, arg),
+                ("take", args @ [_arg]) => {
+                    if let Some((name2, [recv2, args2 @ ..], _span2)) = method_call(recv) {
+                        if let ("cloned", []) = (name2, args2) {
+                            iter_overeager_cloned::check(cx, expr, recv2, name, args);
+                        }
+                    }
+                },
+                ("take", []) => needless_option_take::check(cx, expr, recv),
+                ("to_os_string" | "to_owned" | "to_path_buf" | "to_vec", []) => {
+                    implicit_clone::check(cx, name, expr, recv);
+                },
+                ("unwrap", []) => {
+                    match method_call(recv) {
+                        Some(("get", [recv, get_arg], _)) => {
+                            get_unwrap::check(cx, expr, recv, get_arg, false);
+                        },
+                        Some(("get_mut", [recv, get_arg], _)) => {
+                            get_unwrap::check(cx, expr, recv, get_arg, true);
+                        },
+                        Some(("or", [recv, or_arg], or_span)) => {
+                            or_then_unwrap::check(cx, expr, recv, or_arg, or_span);
+                        },
+                        _ => {},
+                    }
+                    unwrap_used::check(cx, expr, recv, self.allow_unwrap_in_tests);
+                },
+                ("unwrap_or", [u_arg]) => match method_call(recv) {
+                    Some((arith @ ("checked_add" | "checked_sub" | "checked_mul"), [lhs, rhs], _)) => {
+                        manual_saturating_arithmetic::check(cx, expr, lhs, rhs, u_arg, &arith["checked_".len()..]);
+                    },
+                    Some(("map", [m_recv, m_arg], span)) => {
+                        option_map_unwrap_or::check(cx, expr, m_recv, m_arg, recv, u_arg, span);
+                    },
+                    _ => {},
+                },
+                ("unwrap_or_else", [u_arg]) => match method_call(recv) {
+                    Some(("map", [recv, map_arg], _))
+                        if map_unwrap_or::check(cx, expr, recv, map_arg, u_arg, self.msrv) => {},
+                    _ => {
+                        unwrap_or_else_default::check(cx, expr, recv, u_arg);
+                        unnecessary_lazy_eval::check(cx, expr, recv, u_arg, "unwrap_or");
+                    },
                 },
                 _ => {},
-            },
-            ("unwrap_or_else", [u_arg]) => match method_call(recv) {
-                Some(("map", [recv, map_arg], _)) if map_unwrap_or::check(cx, expr, recv, map_arg, u_arg, msrv) => {},
-                _ => {
-                    unwrap_or_else_default::check(cx, expr, recv, u_arg);
-                    unnecessary_lazy_eval::check(cx, expr, recv, u_arg, "unwrap_or");
-                },
-            },
-            _ => {},
+            }
         }
     }
 }
@@ -2821,7 +2833,7 @@ const TRAIT_METHODS: [ShouldImplTraitCase; 30] = [
     ShouldImplTraitCase::new("std::ops::Sub", "sub",  2,  FN_HEADER,  SelfKind::Value,  OutType::Any, true),
 ];
 
-#[derive(Clone, Copy, PartialEq, Debug)]
+#[derive(Clone, Copy, PartialEq, Eq, Debug)]
 enum SelfKind {
     Value,
     Ref,
diff --git a/src/tools/clippy/clippy_lints/src/methods/option_as_ref_deref.rs b/src/tools/clippy/clippy_lints/src/methods/option_as_ref_deref.rs
index ba2d2914315..b50a173d835 100644
--- a/src/tools/clippy/clippy_lints/src/methods/option_as_ref_deref.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/option_as_ref_deref.rs
@@ -19,9 +19,9 @@ pub(super) fn check<'tcx>(
     as_ref_recv: &hir::Expr<'_>,
     map_arg: &hir::Expr<'_>,
     is_mut: bool,
-    msrv: Option<&RustcVersion>,
+    msrv: Option<RustcVersion>,
 ) {
-    if !meets_msrv(msrv, &msrvs::OPTION_AS_DEREF) {
+    if !meets_msrv(msrv, msrvs::OPTION_AS_DEREF) {
         return;
     }
 
diff --git a/src/tools/clippy/clippy_lints/src/methods/str_splitn.rs b/src/tools/clippy/clippy_lints/src/methods/str_splitn.rs
index 52891eeed06..90651a6ba04 100644
--- a/src/tools/clippy/clippy_lints/src/methods/str_splitn.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/str_splitn.rs
@@ -24,7 +24,7 @@ pub(super) fn check(
     self_arg: &Expr<'_>,
     pat_arg: &Expr<'_>,
     count: u128,
-    msrv: Option<&RustcVersion>,
+    msrv: Option<RustcVersion>,
 ) {
     if count < 2 || !cx.typeck_results().expr_ty_adjusted(self_arg).peel_refs().is_str() {
         return;
@@ -34,7 +34,7 @@ pub(super) fn check(
         IterUsageKind::Nth(n) => count > n + 1,
         IterUsageKind::NextTuple => count > 2,
     };
-    let manual = count == 2 && meets_msrv(msrv, &msrvs::STR_SPLIT_ONCE);
+    let manual = count == 2 && meets_msrv(msrv, msrvs::STR_SPLIT_ONCE);
 
     match parse_iter_usage(cx, expr.span.ctxt(), cx.tcx.hir().parent_iter(expr.hir_id)) {
         Some(usage) if needless(usage.kind) => lint_needless(cx, method_name, expr, self_arg, pat_arg),
@@ -271,7 +271,7 @@ enum IterUsageKind {
     NextTuple,
 }
 
-#[derive(Debug, PartialEq)]
+#[derive(Debug, PartialEq, Eq)]
 enum UnwrapKind {
     Unwrap,
     QuestionMark,
diff --git a/src/tools/clippy/clippy_lints/src/methods/unnecessary_to_owned.rs b/src/tools/clippy/clippy_lints/src/methods/unnecessary_to_owned.rs
index 02b882e8b55..97c4feb3122 100644
--- a/src/tools/clippy/clippy_lints/src/methods/unnecessary_to_owned.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/unnecessary_to_owned.rs
@@ -26,7 +26,7 @@ pub fn check<'tcx>(
     expr: &'tcx Expr<'tcx>,
     method_name: Symbol,
     args: &'tcx [Expr<'tcx>],
-    msrv: Option<&RustcVersion>,
+    msrv: Option<RustcVersion>,
 ) {
     if_chain! {
         if let Some(method_def_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id);
@@ -65,13 +65,12 @@ fn check_addr_of_expr(
         if let Some(parent) = get_parent_expr(cx, expr);
         if let ExprKind::AddrOf(BorrowKind::Ref, Mutability::Not, _) = parent.kind;
         let adjustments = cx.typeck_results().expr_adjustments(parent).iter().collect::<Vec<_>>();
-        if let Some(target_ty) = match adjustments[..]
-        {
+        if let
             // For matching uses of `Cow::from`
             [
                 Adjustment {
                     kind: Adjust::Deref(None),
-                    ..
+                    target: referent_ty,
                 },
                 Adjustment {
                     kind: Adjust::Borrow(_),
@@ -82,7 +81,7 @@ fn check_addr_of_expr(
             | [
                 Adjustment {
                     kind: Adjust::Deref(None),
-                    ..
+                    target: referent_ty,
                 },
                 Adjustment {
                     kind: Adjust::Borrow(_),
@@ -97,7 +96,7 @@ fn check_addr_of_expr(
             | [
                 Adjustment {
                     kind: Adjust::Deref(None),
-                    ..
+                    target: referent_ty,
                 },
                 Adjustment {
                     kind: Adjust::Deref(Some(OverloadedDeref { .. })),
@@ -107,17 +106,24 @@ fn check_addr_of_expr(
                     kind: Adjust::Borrow(_),
                     target: target_ty,
                 },
-            ] => Some(target_ty),
-            _ => None,
-        };
+            ] = adjustments[..];
         let receiver_ty = cx.typeck_results().expr_ty(receiver);
-        // Only flag cases where the receiver is copyable or the method is `Cow::into_owned`. This
-        // restriction is to ensure there is not overlap between `redundant_clone` and this lint.
-        if is_copy(cx, receiver_ty) || is_cow_into_owned(cx, method_name, method_def_id);
+        let (target_ty, n_target_refs) = peel_mid_ty_refs(*target_ty);
+        let (receiver_ty, n_receiver_refs) = peel_mid_ty_refs(receiver_ty);
+        // Only flag cases satisfying at least one of the following three conditions:
+        // * the referent and receiver types are distinct
+        // * the referent/receiver type is a copyable array
+        // * the method is `Cow::into_owned`
+        // This restriction is to ensure there is no overlap between `redundant_clone` and this
+        // lint. It also avoids the following false positive:
+        //  https://github.com/rust-lang/rust-clippy/issues/8759
+        //   Arrays are a bit of a corner case. Non-copyable arrays are handled by
+        // `redundant_clone`, but copyable arrays are not.
+        if *referent_ty != receiver_ty
+            || (matches!(referent_ty.kind(), ty::Array(..)) && is_copy(cx, *referent_ty))
+            || is_cow_into_owned(cx, method_name, method_def_id);
         if let Some(receiver_snippet) = snippet_opt(cx, receiver.span);
         then {
-            let (target_ty, n_target_refs) = peel_mid_ty_refs(*target_ty);
-            let (receiver_ty, n_receiver_refs) = peel_mid_ty_refs(receiver_ty);
             if receiver_ty == target_ty && n_target_refs >= n_receiver_refs {
                 span_lint_and_sugg(
                     cx,
@@ -192,7 +198,7 @@ fn check_into_iter_call_arg(
     expr: &Expr<'_>,
     method_name: Symbol,
     receiver: &Expr<'_>,
-    msrv: Option<&RustcVersion>,
+    msrv: Option<RustcVersion>,
 ) -> bool {
     if_chain! {
         if let Some(parent) = get_parent_expr(cx, expr);
@@ -207,7 +213,11 @@ fn check_into_iter_call_arg(
             if unnecessary_iter_cloned::check_for_loop_iter(cx, parent, method_name, receiver, true) {
                 return true;
             }
-            let cloned_or_copied = if is_copy(cx, item_ty) && meets_msrv(msrv, &msrvs::ITERATOR_COPIED) { "copied" } else { "cloned" };
+            let cloned_or_copied = if is_copy(cx, item_ty) && meets_msrv(msrv, msrvs::ITERATOR_COPIED) {
+                "copied"
+            } else {
+                "cloned"
+            };
             // The next suggestion may be incorrect because the removal of the `to_owned`-like
             // function could cause the iterator to hold a reference to a resource that is used
             // mutably. See https://github.com/rust-lang/rust-clippy/issues/8148.
diff --git a/src/tools/clippy/clippy_lints/src/methods/unwrap_used.rs b/src/tools/clippy/clippy_lints/src/methods/unwrap_used.rs
index 44676d78c60..5c761014927 100644
--- a/src/tools/clippy/clippy_lints/src/methods/unwrap_used.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/unwrap_used.rs
@@ -1,4 +1,5 @@
 use clippy_utils::diagnostics::span_lint_and_help;
+use clippy_utils::is_in_test_function;
 use clippy_utils::ty::is_type_diagnostic_item;
 use rustc_hir as hir;
 use rustc_lint::LateContext;
@@ -7,7 +8,7 @@ use rustc_span::sym;
 use super::UNWRAP_USED;
 
 /// lint use of `unwrap()` for `Option`s and `Result`s
-pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, recv: &hir::Expr<'_>) {
+pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, recv: &hir::Expr<'_>, allow_unwrap_in_tests: bool) {
     let obj_ty = cx.typeck_results().expr_ty(recv).peel_refs();
 
     let mess = if is_type_diagnostic_item(cx, obj_ty, sym::Option) {
@@ -18,6 +19,10 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, recv: &hir::Expr
         None
     };
 
+    if allow_unwrap_in_tests && is_in_test_function(cx.tcx, expr.hir_id) {
+        return;
+    }
+
     if let Some((lint, kind, none_value)) = mess {
         span_lint_and_help(
             cx,
diff --git a/src/tools/clippy/clippy_lints/src/misc.rs b/src/tools/clippy/clippy_lints/src/misc.rs
index ac82dd306a5..7fdc28c5a06 100644
--- a/src/tools/clippy/clippy_lints/src/misc.rs
+++ b/src/tools/clippy/clippy_lints/src/misc.rs
@@ -1,6 +1,6 @@
 use clippy_utils::diagnostics::{span_lint, span_lint_and_sugg, span_lint_and_then, span_lint_hir_and_then};
 use clippy_utils::source::{snippet, snippet_opt};
-use clippy_utils::ty::implements_trait;
+use clippy_utils::ty::{implements_trait, is_copy};
 use if_chain::if_chain;
 use rustc_ast::ast::LitKind;
 use rustc_errors::Applicability;
@@ -20,8 +20,8 @@ use rustc_span::symbol::sym;
 use clippy_utils::consts::{constant, Constant};
 use clippy_utils::sugg::Sugg;
 use clippy_utils::{
-    get_item_name, get_parent_expr, in_constant, is_diag_trait_item, is_integer_const, iter_input_pats,
-    last_path_segment, match_any_def_paths, path_def_id, paths, unsext, SpanlessEq,
+    get_item_name, get_parent_expr, in_constant, is_integer_const, iter_input_pats, last_path_segment,
+    match_any_def_paths, path_def_id, paths, unsext, SpanlessEq,
 };
 
 declare_clippy_lint! {
@@ -548,7 +548,7 @@ fn is_array(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
     matches!(&cx.typeck_results().expr_ty(expr).peel_refs().kind(), ty::Array(_, _))
 }
 
-#[allow(clippy::too_many_lines)]
+#[expect(clippy::too_many_lines)]
 fn check_to_owned(cx: &LateContext<'_>, expr: &Expr<'_>, other: &Expr<'_>, left: bool) {
     #[derive(Default)]
     struct EqImpl {
@@ -569,33 +569,34 @@ fn check_to_owned(cx: &LateContext<'_>, expr: &Expr<'_>, other: &Expr<'_>, left:
         })
     }
 
-    let (arg_ty, snip) = match expr.kind {
-        ExprKind::MethodCall(.., args, _) if args.len() == 1 => {
-            if_chain!(
-                if let Some(expr_def_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id);
-                if is_diag_trait_item(cx, expr_def_id, sym::ToString)
-                    || is_diag_trait_item(cx, expr_def_id, sym::ToOwned);
-                then {
-                    (cx.typeck_results().expr_ty(&args[0]), snippet(cx, args[0].span, ".."))
-                } else {
-                    return;
-                }
-            )
+    let typeck = cx.typeck_results();
+    let (arg, arg_span) = match expr.kind {
+        ExprKind::MethodCall(.., [arg], _)
+            if typeck
+                .type_dependent_def_id(expr.hir_id)
+                .and_then(|id| cx.tcx.trait_of_item(id))
+                .map_or(false, |id| {
+                    matches!(cx.tcx.get_diagnostic_name(id), Some(sym::ToString | sym::ToOwned))
+                }) =>
+        {
+            (arg, arg.span)
         },
-        ExprKind::Call(path, [arg]) => {
+        ExprKind::Call(path, [arg])
             if path_def_id(cx, path)
                 .and_then(|id| match_any_def_paths(cx, id, &[&paths::FROM_STR_METHOD, &paths::FROM_FROM]))
-                .is_some()
-            {
-                (cx.typeck_results().expr_ty(arg), snippet(cx, arg.span, ".."))
-            } else {
-                return;
-            }
+                .map_or(false, |idx| match idx {
+                    0 => true,
+                    1 => !is_copy(cx, typeck.expr_ty(expr)),
+                    _ => false,
+                }) =>
+        {
+            (arg, arg.span)
         },
         _ => return,
     };
 
-    let other_ty = cx.typeck_results().expr_ty(other);
+    let arg_ty = typeck.expr_ty(arg);
+    let other_ty = typeck.expr_ty(other);
 
     let without_deref = symmetric_partial_eq(cx, arg_ty, other_ty).unwrap_or_default();
     let with_deref = arg_ty
@@ -627,13 +628,14 @@ fn check_to_owned(cx: &LateContext<'_>, expr: &Expr<'_>, other: &Expr<'_>, left:
                 return;
             }
 
+            let arg_snip = snippet(cx, arg_span, "..");
             let expr_snip;
             let eq_impl;
             if with_deref.is_implemented() {
-                expr_snip = format!("*{}", snip);
+                expr_snip = format!("*{}", arg_snip);
                 eq_impl = with_deref;
             } else {
-                expr_snip = snip.to_string();
+                expr_snip = arg_snip.to_string();
                 eq_impl = without_deref;
             };
 
diff --git a/src/tools/clippy/clippy_lints/src/missing_const_for_fn.rs b/src/tools/clippy/clippy_lints/src/missing_const_for_fn.rs
index 06209bfe7b0..16d65966c10 100644
--- a/src/tools/clippy/clippy_lints/src/missing_const_for_fn.rs
+++ b/src/tools/clippy/clippy_lints/src/missing_const_for_fn.rs
@@ -93,7 +93,7 @@ impl<'tcx> LateLintPass<'tcx> for MissingConstForFn {
         span: Span,
         hir_id: HirId,
     ) {
-        if !meets_msrv(self.msrv.as_ref(), &msrvs::CONST_IF_MATCH) {
+        if !meets_msrv(self.msrv, msrvs::CONST_IF_MATCH) {
             return;
         }
 
@@ -146,7 +146,7 @@ impl<'tcx> LateLintPass<'tcx> for MissingConstForFn {
 
         let mir = cx.tcx.optimized_mir(def_id);
 
-        if let Err((span, err)) = is_min_const_fn(cx.tcx, mir, self.msrv.as_ref()) {
+        if let Err((span, err)) = is_min_const_fn(cx.tcx, mir, self.msrv) {
             if cx.tcx.is_const_fn_raw(def_id.to_def_id()) {
                 cx.tcx.sess.span_err(span, err.as_ref());
             }
diff --git a/src/tools/clippy/clippy_lints/src/eval_order_dependence.rs b/src/tools/clippy/clippy_lints/src/mixed_read_write_in_expression.rs
similarity index 98%
rename from src/tools/clippy/clippy_lints/src/eval_order_dependence.rs
rename to src/tools/clippy/clippy_lints/src/mixed_read_write_in_expression.rs
index 65599a0587d..405fc23e8de 100644
--- a/src/tools/clippy/clippy_lints/src/eval_order_dependence.rs
+++ b/src/tools/clippy/clippy_lints/src/mixed_read_write_in_expression.rs
@@ -40,8 +40,8 @@ declare_clippy_lint! {
     /// let a = tmp + x;
     /// ```
     #[clippy::version = "pre 1.29.0"]
-    pub EVAL_ORDER_DEPENDENCE,
-    suspicious,
+    pub MIXED_READ_WRITE_IN_EXPRESSION,
+    restriction,
     "whether a variable read occurs before a write depends on sub-expression evaluation order"
 }
 
@@ -73,7 +73,7 @@ declare_clippy_lint! {
     "whether an expression contains a diverging sub expression"
 }
 
-declare_lint_pass!(EvalOrderDependence => [EVAL_ORDER_DEPENDENCE, DIVERGING_SUB_EXPRESSION]);
+declare_lint_pass!(EvalOrderDependence => [MIXED_READ_WRITE_IN_EXPRESSION, DIVERGING_SUB_EXPRESSION]);
 
 impl<'tcx> LateLintPass<'tcx> for EvalOrderDependence {
     fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
@@ -303,7 +303,7 @@ impl<'a, 'tcx> Visitor<'tcx> for ReadVisitor<'a, 'tcx> {
             if !is_in_assignment_position(self.cx, expr) {
                 span_lint_and_note(
                     self.cx,
-                    EVAL_ORDER_DEPENDENCE,
+                    MIXED_READ_WRITE_IN_EXPRESSION,
                     expr.span,
                     &format!("unsequenced read of `{}`", self.cx.tcx.hir().name(self.var)),
                     Some(self.write_expr.span),
diff --git a/src/tools/clippy/clippy_lints/src/mutable_debug_assertion.rs b/src/tools/clippy/clippy_lints/src/mutable_debug_assertion.rs
index cd1bc202370..bb6d820b08c 100644
--- a/src/tools/clippy/clippy_lints/src/mutable_debug_assertion.rs
+++ b/src/tools/clippy/clippy_lints/src/mutable_debug_assertion.rs
@@ -16,7 +16,7 @@ declare_clippy_lint! {
     /// ### Why is this bad?
     /// In release builds `debug_assert!` macros are optimized out by the
     /// compiler.
-    /// Therefore mutating something in a `debug_assert!` macro results in different behaviour
+    /// Therefore mutating something in a `debug_assert!` macro results in different behavior
     /// between a release and debug build.
     ///
     /// ### Example
diff --git a/src/tools/clippy/clippy_lints/src/needless_bitwise_bool.rs b/src/tools/clippy/clippy_lints/src/needless_bitwise_bool.rs
index 95395e2e136..623d22bc9bd 100644
--- a/src/tools/clippy/clippy_lints/src/needless_bitwise_bool.rs
+++ b/src/tools/clippy/clippy_lints/src/needless_bitwise_bool.rs
@@ -53,7 +53,7 @@ fn is_bitwise_operation(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
     false
 }
 
-fn suggesstion_snippet(cx: &LateContext<'_>, expr: &Expr<'_>) -> Option<String> {
+fn suggestion_snippet(cx: &LateContext<'_>, expr: &Expr<'_>) -> Option<String> {
     if let ExprKind::Binary(ref op, left, right) = expr.kind {
         if let (Some(l_snippet), Some(r_snippet)) = (snippet_opt(cx, left.span), snippet_opt(cx, right.span)) {
             let op_snippet = match op.node {
@@ -75,7 +75,7 @@ impl LateLintPass<'_> for NeedlessBitwiseBool {
                 expr.span,
                 "use of bitwise operator instead of lazy operator between booleans",
                 |diag| {
-                    if let Some(sugg) = suggesstion_snippet(cx, expr) {
+                    if let Some(sugg) = suggestion_snippet(cx, expr) {
                         diag.span_suggestion(expr.span, "try", sugg, Applicability::MachineApplicable);
                     }
                 },
diff --git a/src/tools/clippy/clippy_lints/src/needless_pass_by_value.rs b/src/tools/clippy/clippy_lints/src/needless_pass_by_value.rs
index 303ce7a5075..f423be4b67a 100644
--- a/src/tools/clippy/clippy_lints/src/needless_pass_by_value.rs
+++ b/src/tools/clippy/clippy_lints/src/needless_pass_by_value.rs
@@ -70,7 +70,7 @@ macro_rules! need {
 }
 
 impl<'tcx> LateLintPass<'tcx> for NeedlessPassByValue {
-    #[allow(clippy::too_many_lines)]
+    #[expect(clippy::too_many_lines)]
     fn check_fn(
         &mut self,
         cx: &LateContext<'tcx>,
diff --git a/src/tools/clippy/clippy_lints/src/neg_multiply.rs b/src/tools/clippy/clippy_lints/src/neg_multiply.rs
index 6ba9ba0753d..707f3b2181a 100644
--- a/src/tools/clippy/clippy_lints/src/neg_multiply.rs
+++ b/src/tools/clippy/clippy_lints/src/neg_multiply.rs
@@ -34,7 +34,6 @@ declare_clippy_lint! {
 
 declare_lint_pass!(NegMultiply => [NEG_MULTIPLY]);
 
-#[allow(clippy::match_same_arms)]
 impl<'tcx> LateLintPass<'tcx> for NegMultiply {
     fn check_expr(&mut self, cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) {
         if let ExprKind::Binary(ref op, left, right) = e.kind {
diff --git a/src/tools/clippy/clippy_lints/src/new_without_default.rs b/src/tools/clippy/clippy_lints/src/new_without_default.rs
index 2bdccb42507..093ec389335 100644
--- a/src/tools/clippy/clippy_lints/src/new_without_default.rs
+++ b/src/tools/clippy/clippy_lints/src/new_without_default.rs
@@ -58,7 +58,6 @@ pub struct NewWithoutDefault {
 impl_lint_pass!(NewWithoutDefault => [NEW_WITHOUT_DEFAULT]);
 
 impl<'tcx> LateLintPass<'tcx> for NewWithoutDefault {
-    #[allow(clippy::too_many_lines)]
     fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx hir::Item<'_>) {
         if let hir::ItemKind::Impl(hir::Impl {
             of_trait: None,
diff --git a/src/tools/clippy/clippy_lints/src/non_expressive_names.rs b/src/tools/clippy/clippy_lints/src/non_expressive_names.rs
index e3bc40c4b49..7f6b535c7b1 100644
--- a/src/tools/clippy/clippy_lints/src/non_expressive_names.rs
+++ b/src/tools/clippy/clippy_lints/src/non_expressive_names.rs
@@ -191,7 +191,7 @@ impl<'a, 'tcx, 'b> SimilarNamesNameVisitor<'a, 'tcx, 'b> {
         }
     }
 
-    #[allow(clippy::too_many_lines)]
+    #[expect(clippy::too_many_lines)]
     fn check_ident(&mut self, ident: Ident) {
         let interned_name = ident.name.as_str();
         if interned_name.chars().any(char::is_uppercase) {
diff --git a/src/tools/clippy/clippy_lints/src/pass_by_ref_or_value.rs b/src/tools/clippy/clippy_lints/src/pass_by_ref_or_value.rs
index 9af3059a37f..e3ded716341 100644
--- a/src/tools/clippy/clippy_lints/src/pass_by_ref_or_value.rs
+++ b/src/tools/clippy/clippy_lints/src/pass_by_ref_or_value.rs
@@ -52,7 +52,7 @@ declare_clippy_lint! {
     /// to a function that needs the memory address. For further details, refer to
     /// [this issue](https://github.com/rust-lang/rust-clippy/issues/5953)
     /// that explains a real case in which this false positive
-    /// led to an **undefined behaviour** introduced with unsafe code.
+    /// led to an **undefined behavior** introduced with unsafe code.
     ///
     /// ### Example
     ///
@@ -124,7 +124,7 @@ impl<'tcx> PassByRefOrValue {
             // Cap the calculated bit width at 32-bits to reduce
             // portability problems between 32 and 64-bit targets
             let bit_width = cmp::min(bit_width, 32);
-            #[allow(clippy::integer_division)]
+            #[expect(clippy::integer_division)]
             let byte_width = bit_width / 8;
             // Use a limit of 2 times the register byte width
             byte_width * 2
diff --git a/src/tools/clippy/clippy_lints/src/pattern_type_mismatch.rs b/src/tools/clippy/clippy_lints/src/pattern_type_mismatch.rs
index be319ee110d..a4d265111f9 100644
--- a/src/tools/clippy/clippy_lints/src/pattern_type_mismatch.rs
+++ b/src/tools/clippy/clippy_lints/src/pattern_type_mismatch.rs
@@ -163,7 +163,6 @@ enum Level {
     Lower,
 }
 
-#[allow(rustc::usage_of_ty_tykind)]
 fn find_first_mismatch<'tcx>(cx: &LateContext<'tcx>, pat: &Pat<'_>) -> Option<(Span, Mutability, Level)> {
     let mut result = None;
     pat.walk(|p| {
diff --git a/src/tools/clippy/clippy_lints/src/ptr.rs b/src/tools/clippy/clippy_lints/src/ptr.rs
index c35eeeac67a..86460c1b27e 100644
--- a/src/tools/clippy/clippy_lints/src/ptr.rs
+++ b/src/tools/clippy/clippy_lints/src/ptr.rs
@@ -514,7 +514,7 @@ fn check_mut_from_ref<'tcx>(cx: &LateContext<'tcx>, sig: &FnSig<'_>, body: Optio
     }
 }
 
-#[allow(clippy::too_many_lines)]
+#[expect(clippy::too_many_lines)]
 fn check_ptr_arg_usage<'tcx>(cx: &LateContext<'tcx>, body: &'tcx Body<'_>, args: &[PtrArg<'tcx>]) -> Vec<PtrArgResult> {
     struct V<'cx, 'tcx> {
         cx: &'cx LateContext<'tcx>,
diff --git a/src/tools/clippy/clippy_lints/src/ranges.rs b/src/tools/clippy/clippy_lints/src/ranges.rs
index be7610f365c..26dc88a406e 100644
--- a/src/tools/clippy/clippy_lints/src/ranges.rs
+++ b/src/tools/clippy/clippy_lints/src/ranges.rs
@@ -193,7 +193,7 @@ impl<'tcx> LateLintPass<'tcx> for Ranges {
                 check_range_zip_with_len(cx, path, args, expr.span);
             },
             ExprKind::Binary(ref op, l, r) => {
-                if meets_msrv(self.msrv.as_ref(), &msrvs::RANGE_CONTAINS) {
+                if meets_msrv(self.msrv, msrvs::RANGE_CONTAINS) {
                     check_possible_range_contains(cx, op.node, l, r, expr);
                 }
             },
@@ -207,7 +207,13 @@ impl<'tcx> LateLintPass<'tcx> for Ranges {
     extract_msrv_attr!(LateContext);
 }
 
-fn check_possible_range_contains(cx: &LateContext<'_>, op: BinOpKind, l: &Expr<'_>, r: &Expr<'_>, expr: &Expr<'_>) {
+fn check_possible_range_contains(
+    cx: &LateContext<'_>,
+    op: BinOpKind,
+    left: &Expr<'_>,
+    right: &Expr<'_>,
+    expr: &Expr<'_>,
+) {
     if in_constant(cx, expr.hir_id) {
         return;
     }
@@ -219,21 +225,19 @@ fn check_possible_range_contains(cx: &LateContext<'_>, op: BinOpKind, l: &Expr<'
         _ => return,
     };
     // value, name, order (higher/lower), inclusiveness
-    if let (Some((lval, lid, name_span, lval_span, lord, linc)), Some((rval, rid, _, rval_span, rord, rinc))) =
-        (check_range_bounds(cx, l), check_range_bounds(cx, r))
-    {
+    if let (Some(l), Some(r)) = (check_range_bounds(cx, left), check_range_bounds(cx, right)) {
         // we only lint comparisons on the same name and with different
         // direction
-        if lid != rid || lord == rord {
+        if l.id != r.id || l.ord == r.ord {
             return;
         }
-        let ord = Constant::partial_cmp(cx.tcx, cx.typeck_results().expr_ty(l), &lval, &rval);
-        if combine_and && ord == Some(rord) {
+        let ord = Constant::partial_cmp(cx.tcx, cx.typeck_results().expr_ty(l.expr), &l.val, &r.val);
+        if combine_and && ord == Some(r.ord) {
             // order lower bound and upper bound
-            let (l_span, u_span, l_inc, u_inc) = if rord == Ordering::Less {
-                (lval_span, rval_span, linc, rinc)
+            let (l_span, u_span, l_inc, u_inc) = if r.ord == Ordering::Less {
+                (l.val_span, r.val_span, l.inc, r.inc)
             } else {
-                (rval_span, lval_span, rinc, linc)
+                (r.val_span, l.val_span, r.inc, l.inc)
             };
             // we only lint inclusive lower bounds
             if !l_inc {
@@ -245,7 +249,7 @@ fn check_possible_range_contains(cx: &LateContext<'_>, op: BinOpKind, l: &Expr<'
                 ("Range", "..")
             };
             let mut applicability = Applicability::MachineApplicable;
-            let name = snippet_with_applicability(cx, name_span, "_", &mut applicability);
+            let name = snippet_with_applicability(cx, l.name_span, "_", &mut applicability);
             let lo = snippet_with_applicability(cx, l_span, "_", &mut applicability);
             let hi = snippet_with_applicability(cx, u_span, "_", &mut applicability);
             let space = if lo.ends_with('.') { " " } else { "" };
@@ -258,13 +262,13 @@ fn check_possible_range_contains(cx: &LateContext<'_>, op: BinOpKind, l: &Expr<'
                 format!("({}{}{}{}).contains(&{})", lo, space, range_op, hi, name),
                 applicability,
             );
-        } else if !combine_and && ord == Some(lord) {
+        } else if !combine_and && ord == Some(l.ord) {
             // `!_.contains(_)`
             // order lower bound and upper bound
-            let (l_span, u_span, l_inc, u_inc) = if lord == Ordering::Less {
-                (lval_span, rval_span, linc, rinc)
+            let (l_span, u_span, l_inc, u_inc) = if l.ord == Ordering::Less {
+                (l.val_span, r.val_span, l.inc, r.inc)
             } else {
-                (rval_span, lval_span, rinc, linc)
+                (r.val_span, l.val_span, r.inc, l.inc)
             };
             if l_inc {
                 return;
@@ -275,7 +279,7 @@ fn check_possible_range_contains(cx: &LateContext<'_>, op: BinOpKind, l: &Expr<'
                 ("RangeInclusive", "..=")
             };
             let mut applicability = Applicability::MachineApplicable;
-            let name = snippet_with_applicability(cx, name_span, "_", &mut applicability);
+            let name = snippet_with_applicability(cx, l.name_span, "_", &mut applicability);
             let lo = snippet_with_applicability(cx, l_span, "_", &mut applicability);
             let hi = snippet_with_applicability(cx, u_span, "_", &mut applicability);
             let space = if lo.ends_with('.') { " " } else { "" };
@@ -292,7 +296,20 @@ fn check_possible_range_contains(cx: &LateContext<'_>, op: BinOpKind, l: &Expr<'
     }
 }
 
-fn check_range_bounds(cx: &LateContext<'_>, ex: &Expr<'_>) -> Option<(Constant, HirId, Span, Span, Ordering, bool)> {
+struct RangeBounds<'a> {
+    val: Constant,
+    expr: &'a Expr<'a>,
+    id: HirId,
+    name_span: Span,
+    val_span: Span,
+    ord: Ordering,
+    inc: bool,
+}
+
+// Takes a binary expression such as x <= 2 as input
+// Breaks apart into various pieces, such as the value of the number,
+// hir id of the variable, and direction/inclusiveness of the operator
+fn check_range_bounds<'a>(cx: &'a LateContext<'_>, ex: &'a Expr<'_>) -> Option<RangeBounds<'a>> {
     if let ExprKind::Binary(ref op, l, r) = ex.kind {
         let (inclusive, ordering) = match op.node {
             BinOpKind::Gt => (false, Ordering::Greater),
@@ -303,11 +320,27 @@ fn check_range_bounds(cx: &LateContext<'_>, ex: &Expr<'_>) -> Option<(Constant,
         };
         if let Some(id) = path_to_local(l) {
             if let Some((c, _)) = constant(cx, cx.typeck_results(), r) {
-                return Some((c, id, l.span, r.span, ordering, inclusive));
+                return Some(RangeBounds {
+                    val: c,
+                    expr: r,
+                    id,
+                    name_span: l.span,
+                    val_span: r.span,
+                    ord: ordering,
+                    inc: inclusive,
+                });
             }
         } else if let Some(id) = path_to_local(r) {
             if let Some((c, _)) = constant(cx, cx.typeck_results(), l) {
-                return Some((c, id, r.span, l.span, ordering.reverse(), inclusive));
+                return Some(RangeBounds {
+                    val: c,
+                    expr: l,
+                    id,
+                    name_span: r.span,
+                    val_span: l.span,
+                    ord: ordering.reverse(),
+                    inc: inclusive,
+                });
             }
         }
     }
diff --git a/src/tools/clippy/clippy_lints/src/rc_clone_in_vec_init.rs b/src/tools/clippy/clippy_lints/src/rc_clone_in_vec_init.rs
new file mode 100644
index 00000000000..110f58f3734
--- /dev/null
+++ b/src/tools/clippy/clippy_lints/src/rc_clone_in_vec_init.rs
@@ -0,0 +1,141 @@
+use clippy_utils::diagnostics::span_lint_and_then;
+use clippy_utils::higher::VecArgs;
+use clippy_utils::last_path_segment;
+use clippy_utils::macros::root_macro_call_first_node;
+use clippy_utils::source::{indent_of, snippet};
+use rustc_errors::Applicability;
+use rustc_hir::{Expr, ExprKind, QPath, TyKind};
+use rustc_lint::{LateContext, LateLintPass};
+use rustc_session::{declare_lint_pass, declare_tool_lint};
+use rustc_span::{sym, Span, Symbol};
+
+declare_clippy_lint! {
+    /// ### What it does
+    /// Checks for `Arc::new` or `Rc::new` in `vec![elem; len]`
+    ///
+    /// ### Why is this bad?
+    /// This will create `elem` once and clone it `len` times - doing so with `Arc` or `Rc`
+    /// is a bit misleading, as it will create references to the same pointer, rather
+    /// than different instances.
+    ///
+    /// ### Example
+    /// ```rust
+    /// let v = vec![std::sync::Arc::new("some data".to_string()); 100];
+    /// // or
+    /// let v = vec![std::rc::Rc::new("some data".to_string()); 100];
+    /// ```
+    /// Use instead:
+    /// ```rust
+    ///
+    /// // Initialize each value separately:
+    /// let mut data = Vec::with_capacity(100);
+    /// for _ in 0..100 {
+    ///     data.push(std::rc::Rc::new("some data".to_string()));
+    /// }
+    ///
+    /// // Or if you want clones of the same reference,
+    /// // Create the reference beforehand to clarify that
+    /// // it should be cloned for each value
+    /// let data = std::rc::Rc::new("some data".to_string());
+    /// let v = vec![data; 100];
+    /// ```
+    #[clippy::version = "1.62.0"]
+    pub RC_CLONE_IN_VEC_INIT,
+    suspicious,
+    "initializing `Arc` or `Rc` in `vec![elem; len]`"
+}
+declare_lint_pass!(RcCloneInVecInit => [RC_CLONE_IN_VEC_INIT]);
+
+impl LateLintPass<'_> for RcCloneInVecInit {
+    fn check_expr(&mut self, cx: &LateContext<'_>, expr: &Expr<'_>) {
+        let Some(macro_call) = root_macro_call_first_node(cx, expr) else { return; };
+        let Some(VecArgs::Repeat(elem, len)) = VecArgs::hir(cx, expr) else { return; };
+        let Some(symbol) = new_reference_call(cx, elem) else { return; };
+
+        emit_lint(cx, symbol, macro_call.span, elem, len);
+    }
+}
+
+fn elem_snippet(cx: &LateContext<'_>, elem: &Expr<'_>, symbol_name: &str) -> String {
+    let elem_snippet = snippet(cx, elem.span, "..").to_string();
+    if elem_snippet.contains('\n') {
+        // This string must be found in `elem_snippet`, otherwise we won't be constructing
+        // the snippet in the first place.
+        let reference_creation = format!("{symbol_name}::new");
+        let (code_until_reference_creation, _right) = elem_snippet.split_once(&reference_creation).unwrap();
+
+        return format!("{code_until_reference_creation}{reference_creation}(..)");
+    }
+
+    elem_snippet
+}
+
+fn loop_init_suggestion(elem: &str, len: &str, indent: &str) -> String {
+    format!(
+        r#"{{
+{indent}    let mut v = Vec::with_capacity({len});
+{indent}    (0..{len}).for_each(|_| v.push({elem}));
+{indent}    v
+{indent}}}"#
+    )
+}
+
+fn extract_suggestion(elem: &str, len: &str, indent: &str) -> String {
+    format!(
+        "{{
+{indent}    let data = {elem};
+{indent}    vec![data; {len}]
+{indent}}}"
+    )
+}
+
+fn emit_lint(cx: &LateContext<'_>, symbol: Symbol, lint_span: Span, elem: &Expr<'_>, len: &Expr<'_>) {
+    let symbol_name = symbol.as_str();
+
+    span_lint_and_then(
+        cx,
+        RC_CLONE_IN_VEC_INIT,
+        lint_span,
+        &format!("calling `{symbol_name}::new` in `vec![elem; len]`"),
+        |diag| {
+            let len_snippet = snippet(cx, len.span, "..");
+            let elem_snippet = elem_snippet(cx, elem, symbol_name);
+            let indentation = " ".repeat(indent_of(cx, lint_span).unwrap_or(0));
+            let loop_init_suggestion = loop_init_suggestion(&elem_snippet, len_snippet.as_ref(), &indentation);
+            let extract_suggestion = extract_suggestion(&elem_snippet, len_snippet.as_ref(), &indentation);
+
+            diag.note(format!("each element will point to the same `{symbol_name}` instance"));
+            diag.span_suggestion(
+                lint_span,
+                format!("consider initializing each `{symbol_name}` element individually"),
+                loop_init_suggestion,
+                Applicability::Unspecified,
+            );
+            diag.span_suggestion(
+                lint_span,
+                format!(
+                    "or if this is intentional, consider extracting the `{symbol_name}` initialization to a variable"
+                ),
+                extract_suggestion,
+                Applicability::Unspecified,
+            );
+        },
+    );
+}
+
+/// Checks whether the given `expr` is a call to `Arc::new` or `Rc::new`
+fn new_reference_call(cx: &LateContext<'_>, expr: &Expr<'_>) -> Option<Symbol> {
+    if_chain! {
+        if let ExprKind::Call(func, _args) = expr.kind;
+        if let ExprKind::Path(ref func_path @ QPath::TypeRelative(ty, _)) = func.kind;
+        if let TyKind::Path(ref ty_path) = ty.kind;
+        if let Some(def_id) = cx.qpath_res(ty_path, ty.hir_id).opt_def_id();
+        if last_path_segment(func_path).ident.name == sym::new;
+
+        then {
+            return cx.tcx.get_diagnostic_name(def_id).filter(|symbol| symbol == &sym::Arc || symbol == &sym::Rc);
+        }
+    }
+
+    None
+}
diff --git a/src/tools/clippy/clippy_lints/src/redundant_clone.rs b/src/tools/clippy/clippy_lints/src/redundant_clone.rs
index 37aac8b2a49..0004b8afdd3 100644
--- a/src/tools/clippy/clippy_lints/src/redundant_clone.rs
+++ b/src/tools/clippy/clippy_lints/src/redundant_clone.rs
@@ -19,7 +19,6 @@ use rustc_mir_dataflow::{Analysis, AnalysisDomain, CallReturnPlaces, GenKill, Ge
 use rustc_session::{declare_lint_pass, declare_tool_lint};
 use rustc_span::source_map::{BytePos, Span};
 use rustc_span::sym;
-use std::convert::TryFrom;
 use std::ops::ControlFlow;
 
 macro_rules! unwrap_or_continue {
@@ -71,7 +70,7 @@ declare_clippy_lint! {
 declare_lint_pass!(RedundantClone => [REDUNDANT_CLONE]);
 
 impl<'tcx> LateLintPass<'tcx> for RedundantClone {
-    #[allow(clippy::too_many_lines)]
+    #[expect(clippy::too_many_lines)]
     fn check_fn(
         &mut self,
         cx: &LateContext<'tcx>,
@@ -633,7 +632,7 @@ impl<'a, 'tcx> mir::visit::Visitor<'tcx> for PossibleBorrowerVisitor<'a, 'tcx> {
 }
 
 /// Collect possible borrowed for every `&mut` local.
-/// For exampel, `_1 = &mut _2` generate _1: {_2,...}
+/// For example, `_1 = &mut _2` generate _1: {_2,...}
 /// Known Problems: not sure all borrowed are tracked
 struct PossibleOriginVisitor<'a, 'tcx> {
     possible_origin: TransitiveRelation,
diff --git a/src/tools/clippy/clippy_lints/src/redundant_field_names.rs b/src/tools/clippy/clippy_lints/src/redundant_field_names.rs
index 40a62fd6d20..40b03068f6c 100644
--- a/src/tools/clippy/clippy_lints/src/redundant_field_names.rs
+++ b/src/tools/clippy/clippy_lints/src/redundant_field_names.rs
@@ -51,7 +51,7 @@ impl_lint_pass!(RedundantFieldNames => [REDUNDANT_FIELD_NAMES]);
 
 impl EarlyLintPass for RedundantFieldNames {
     fn check_expr(&mut self, cx: &EarlyContext<'_>, expr: &Expr) {
-        if !meets_msrv(self.msrv.as_ref(), &msrvs::FIELD_INIT_SHORTHAND) {
+        if !meets_msrv(self.msrv, msrvs::FIELD_INIT_SHORTHAND) {
             return;
         }
 
diff --git a/src/tools/clippy/clippy_lints/src/redundant_static_lifetimes.rs b/src/tools/clippy/clippy_lints/src/redundant_static_lifetimes.rs
index ea5064217ab..2d26c49252f 100644
--- a/src/tools/clippy/clippy_lints/src/redundant_static_lifetimes.rs
+++ b/src/tools/clippy/clippy_lints/src/redundant_static_lifetimes.rs
@@ -99,7 +99,7 @@ impl RedundantStaticLifetimes {
 
 impl EarlyLintPass for RedundantStaticLifetimes {
     fn check_item(&mut self, cx: &EarlyContext<'_>, item: &Item) {
-        if !meets_msrv(self.msrv.as_ref(), &msrvs::STATIC_IN_CONST) {
+        if !meets_msrv(self.msrv, msrvs::STATIC_IN_CONST) {
             return;
         }
 
diff --git a/src/tools/clippy/clippy_lints/src/reference.rs b/src/tools/clippy/clippy_lints/src/reference.rs
index 811a7bb9c15..f789cec6d6a 100644
--- a/src/tools/clippy/clippy_lints/src/reference.rs
+++ b/src/tools/clippy/clippy_lints/src/reference.rs
@@ -54,13 +54,12 @@ impl EarlyLintPass for DerefAddrOf {
             then {
                 let mut applicability = Applicability::MachineApplicable;
                 let sugg = if e.span.from_expansion() {
-                    #[allow(clippy::option_if_let_else)]
                     if let Some(macro_source) = snippet_opt(cx, e.span) {
                         // Remove leading whitespace from the given span
                         // e.g: ` $visitor` turns into `$visitor`
                         let trim_leading_whitespaces = |span| {
                             snippet_opt(cx, span).and_then(|snip| {
-                                #[allow(clippy::cast_possible_truncation)]
+                                #[expect(clippy::cast_possible_truncation)]
                                 snip.find(|c: char| !c.is_whitespace()).map(|pos| {
                                     span.lo() + BytePos(pos as u32)
                                 })
@@ -68,7 +67,7 @@ impl EarlyLintPass for DerefAddrOf {
                         };
 
                         let mut generate_snippet = |pattern: &str| {
-                            #[allow(clippy::cast_possible_truncation)]
+                            #[expect(clippy::cast_possible_truncation)]
                             macro_source.rfind(pattern).map(|pattern_pos| {
                                 let rpos = pattern_pos + pattern.len();
                                 let span_after_ref = e.span.with_lo(BytePos(e.span.lo().0 + rpos as u32));
diff --git a/src/tools/clippy/clippy_lints/src/regex.rs b/src/tools/clippy/clippy_lints/src/regex.rs
index a92097e1d24..67129299e2f 100644
--- a/src/tools/clippy/clippy_lints/src/regex.rs
+++ b/src/tools/clippy/clippy_lints/src/regex.rs
@@ -7,7 +7,6 @@ use rustc_hir::{BorrowKind, Expr, ExprKind};
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_session::{declare_lint_pass, declare_tool_lint};
 use rustc_span::source_map::{BytePos, Span};
-use std::convert::TryFrom;
 
 declare_clippy_lint! {
     /// ### What it does
@@ -79,7 +78,6 @@ impl<'tcx> LateLintPass<'tcx> for Regex {
     }
 }
 
-#[allow(clippy::cast_possible_truncation)] // truncation very unlikely here
 #[must_use]
 fn str_span(base: Span, c: regex_syntax::ast::Span, offset: u8) -> Span {
     let offset = u32::from(offset);
diff --git a/src/tools/clippy/clippy_lints/src/renamed_lints.rs b/src/tools/clippy/clippy_lints/src/renamed_lints.rs
index bfc03116fe2..ba03ef93721 100644
--- a/src/tools/clippy/clippy_lints/src/renamed_lints.rs
+++ b/src/tools/clippy/clippy_lints/src/renamed_lints.rs
@@ -9,6 +9,7 @@ pub static RENAMED_LINTS: &[(&str, &str)] = &[
     ("clippy::cyclomatic_complexity", "clippy::cognitive_complexity"),
     ("clippy::disallowed_method", "clippy::disallowed_methods"),
     ("clippy::disallowed_type", "clippy::disallowed_types"),
+    ("clippy::eval_order_dependence", "clippy::mixed_read_write_in_expression"),
     ("clippy::for_loop_over_option", "clippy::for_loops_over_fallibles"),
     ("clippy::for_loop_over_result", "clippy::for_loops_over_fallibles"),
     ("clippy::identity_conversion", "clippy::useless_conversion"),
diff --git a/src/tools/clippy/clippy_lints/src/significant_drop_in_scrutinee.rs b/src/tools/clippy/clippy_lints/src/significant_drop_in_scrutinee.rs
index f300acf0fb2..424b361a905 100644
--- a/src/tools/clippy/clippy_lints/src/significant_drop_in_scrutinee.rs
+++ b/src/tools/clippy/clippy_lints/src/significant_drop_in_scrutinee.rs
@@ -29,7 +29,7 @@ declare_clippy_lint! {
     /// the match block and thus will not unlock.
     ///
     /// ### Example
-    /// ```rust
+    /// ```rust.ignore
     /// # use std::sync::Mutex;
     ///
     /// # struct State {}
@@ -83,7 +83,7 @@ declare_clippy_lint! {
     /// ```
     #[clippy::version = "1.60.0"]
     pub SIGNIFICANT_DROP_IN_SCRUTINEE,
-    nursery,
+    suspicious,
     "warns when a temporary of a type with a drop with a significant side-effect might have a surprising lifetime"
 }
 
@@ -99,7 +99,7 @@ impl<'tcx> LateLintPass<'tcx> for SignificantDropInScrutinee {
                     found.found_span,
                     "temporary with significant drop in match scrutinee",
                     |diag| set_diagnostic(diag, cx, expr, found),
-                )
+                );
             }
         }
     }
@@ -148,8 +148,8 @@ fn set_diagnostic<'tcx>(diag: &mut Diagnostic, cx: &LateContext<'tcx>, expr: &'t
     );
 }
 
-/// If the expression is an ExprKind::Match, check if the scrutinee has a significant drop that may
-/// have a surprising lifetime.
+/// If the expression is an `ExprKind::Match`, check if the scrutinee has a significant drop that
+/// may have a surprising lifetime.
 fn has_significant_drop_in_scrutinee<'tcx, 'a>(
     cx: &'a LateContext<'tcx>,
     expr: &'tcx Expr<'tcx>,
@@ -171,6 +171,7 @@ struct SigDropHelper<'a, 'tcx> {
     special_handling_for_binary_op: bool,
 }
 
+#[expect(clippy::enum_variant_names)]
 #[derive(Debug, PartialEq, Eq, Clone, Copy)]
 enum LintSuggestion {
     MoveOnly,
@@ -213,7 +214,7 @@ impl<'a, 'tcx> SigDropHelper<'a, 'tcx> {
     }
 
     /// This will try to set the current suggestion (so it can be moved into the suggestions vec
-    /// later). If allow_move_and_clone is false, the suggestion *won't* be set -- this gives us
+    /// later). If `allow_move_and_clone` is false, the suggestion *won't* be set -- this gives us
     /// an opportunity to look for another type in the chain that will be trivially copyable.
     /// However, if we are at the the end of the chain, we want to accept whatever is there. (The
     /// suggestion won't actually be output, but the diagnostic message will be output, so the user
@@ -313,10 +314,10 @@ impl<'a, 'tcx> SigDropHelper<'a, 'tcx> {
                 }
                 false
             },
-            rustc_middle::ty::Array(ty, _) => self.has_sig_drop_attr(cx, *ty),
-            rustc_middle::ty::RawPtr(TypeAndMut { ty, .. }) => self.has_sig_drop_attr(cx, *ty),
-            rustc_middle::ty::Ref(_, ty, _) => self.has_sig_drop_attr(cx, *ty),
-            rustc_middle::ty::Slice(ty) => self.has_sig_drop_attr(cx, *ty),
+            rustc_middle::ty::Array(ty, _)
+            | rustc_middle::ty::RawPtr(TypeAndMut { ty, .. })
+            | rustc_middle::ty::Ref(_, ty, _)
+            | rustc_middle::ty::Slice(ty) => self.has_sig_drop_attr(cx, *ty),
             _ => false,
         }
     }
@@ -332,15 +333,12 @@ impl<'a, 'tcx> Visitor<'tcx> for SigDropHelper<'a, 'tcx> {
 
         match ex.kind {
             ExprKind::MethodCall(_, [ref expr, ..], _) => {
-                self.visit_expr(expr)
+                self.visit_expr(expr);
             }
             ExprKind::Binary(_, left, right) => {
                 self.visit_exprs_for_binary_ops(left, right, false, ex.span);
             }
-            ExprKind::Assign(left, right, _) => {
-                self.visit_exprs_for_binary_ops(left, right, true, ex.span);
-            }
-            ExprKind::AssignOp(_, left, right) => {
+            ExprKind::Assign(left, right, _) | ExprKind::AssignOp(_, left, right) => {
                 self.visit_exprs_for_binary_ops(left, right, true, ex.span);
             }
             ExprKind::Tup(exprs) => {
diff --git a/src/tools/clippy/clippy_lints/src/tabs_in_doc_comments.rs b/src/tools/clippy/clippy_lints/src/tabs_in_doc_comments.rs
index 15543b6a262..e223aea297f 100644
--- a/src/tools/clippy/clippy_lints/src/tabs_in_doc_comments.rs
+++ b/src/tools/clippy/clippy_lints/src/tabs_in_doc_comments.rs
@@ -4,7 +4,6 @@ use rustc_errors::Applicability;
 use rustc_lint::{EarlyContext, EarlyLintPass};
 use rustc_session::{declare_lint_pass, declare_tool_lint};
 use rustc_span::source_map::{BytePos, Span};
-use std::convert::TryFrom;
 
 declare_clippy_lint! {
     /// ### What it does
diff --git a/src/tools/clippy/clippy_lints/src/transmute/mod.rs b/src/tools/clippy/clippy_lints/src/transmute/mod.rs
index 342f23f030c..d2a040beb0c 100644
--- a/src/tools/clippy/clippy_lints/src/transmute/mod.rs
+++ b/src/tools/clippy/clippy_lints/src/transmute/mod.rs
@@ -27,7 +27,7 @@ declare_clippy_lint! {
     /// architecture.
     ///
     /// ### Why is this bad?
-    /// It's basically guaranteed to be undefined behaviour.
+    /// It's basically guaranteed to be undefined behavior.
     ///
     /// ### Known problems
     /// When accessing C, users might want to store pointer
@@ -40,7 +40,7 @@ declare_clippy_lint! {
     #[clippy::version = "pre 1.29.0"]
     pub WRONG_TRANSMUTE,
     correctness,
-    "transmutes that are confusing at best, undefined behaviour at worst and always useless"
+    "transmutes that are confusing at best, undefined behavior at worst and always useless"
 }
 
 // FIXME: Move this to `complexity` again, after #5343 is fixed
diff --git a/src/tools/clippy/clippy_lints/src/types/redundant_allocation.rs b/src/tools/clippy/clippy_lints/src/types/redundant_allocation.rs
index 10d2ae2eb1d..a1312fcda0b 100644
--- a/src/tools/clippy/clippy_lints/src/types/redundant_allocation.rs
+++ b/src/tools/clippy/clippy_lints/src/types/redundant_allocation.rs
@@ -5,6 +5,7 @@ use rustc_errors::Applicability;
 use rustc_hir::{self as hir, def_id::DefId, QPath, TyKind};
 use rustc_lint::LateContext;
 use rustc_span::symbol::sym;
+use rustc_typeck::hir_ty_to_ty;
 
 use super::{utils, REDUNDANT_ALLOCATION};
 
@@ -54,8 +55,10 @@ pub(super) fn check(cx: &LateContext<'_>, hir_ty: &hir::Ty<'_>, qpath: &QPath<'_
     };
     let inner_span = match qpath_generic_tys(inner_qpath).next() {
         Some(ty) => {
-            // Box<Box<dyn T>> is smaller than Box<dyn T> because of wide pointers
-            if matches!(ty.kind, TyKind::TraitObject(..)) {
+            // Reallocation of a fat pointer causes it to become thin. `hir_ty_to_ty` is safe to use
+            // here because `mod.rs` guarantees this lint is only run on types outside of bodies and
+            // is not run on locals.
+            if !hir_ty_to_ty(cx.tcx, ty).is_sized(cx.tcx.at(ty.span), cx.param_env) {
                 return false;
             }
             ty.span
diff --git a/src/tools/clippy/clippy_lints/src/undocumented_unsafe_blocks.rs b/src/tools/clippy/clippy_lints/src/undocumented_unsafe_blocks.rs
index 465d8a914fb..5a8677f90be 100644
--- a/src/tools/clippy/clippy_lints/src/undocumented_unsafe_blocks.rs
+++ b/src/tools/clippy/clippy_lints/src/undocumented_unsafe_blocks.rs
@@ -1,17 +1,18 @@
 use clippy_utils::diagnostics::span_lint_and_help;
-use clippy_utils::is_lint_allowed;
 use clippy_utils::source::walk_span_to_context;
+use clippy_utils::{get_parent_node, is_lint_allowed};
 use rustc_data_structures::sync::Lrc;
-use rustc_hir::{Block, BlockCheckMode, UnsafeSource};
+use rustc_hir as hir;
+use rustc_hir::{Block, BlockCheckMode, ItemKind, Node, UnsafeSource};
 use rustc_lexer::{tokenize, TokenKind};
 use rustc_lint::{LateContext, LateLintPass, LintContext};
 use rustc_middle::lint::in_external_macro;
 use rustc_session::{declare_lint_pass, declare_tool_lint};
-use rustc_span::{BytePos, Pos, SyntaxContext};
+use rustc_span::{BytePos, Pos, Span, SyntaxContext};
 
 declare_clippy_lint! {
     /// ### What it does
-    /// Checks for `unsafe` blocks without a `// SAFETY: ` comment
+    /// Checks for `unsafe` blocks and impls without a `// SAFETY: ` comment
     /// explaining why the unsafe operations performed inside
     /// the block are safe.
     ///
@@ -34,7 +35,7 @@ declare_clippy_lint! {
     /// ```
     ///
     /// ### Why is this bad?
-    /// Undocumented unsafe blocks can make it difficult to
+    /// Undocumented unsafe blocks and impls can make it difficult to
     /// read and maintain code, as well as uncover unsoundness
     /// and bugs.
     ///
@@ -66,7 +67,7 @@ impl LateLintPass<'_> for UndocumentedUnsafeBlocks {
         if block.rules == BlockCheckMode::UnsafeBlock(UnsafeSource::UserProvided)
             && !in_external_macro(cx.tcx.sess, block.span)
             && !is_lint_allowed(cx, UNDOCUMENTED_UNSAFE_BLOCKS, block.hir_id)
-            && !is_unsafe_from_proc_macro(cx, block)
+            && !is_unsafe_from_proc_macro(cx, block.span)
             && !block_has_safety_comment(cx, block)
         {
             let source_map = cx.tcx.sess.source_map();
@@ -86,11 +87,37 @@ impl LateLintPass<'_> for UndocumentedUnsafeBlocks {
             );
         }
     }
+
+    fn check_item(&mut self, cx: &LateContext<'_>, item: &hir::Item<'_>) {
+        if let hir::ItemKind::Impl(imple) = item.kind
+            && imple.unsafety == hir::Unsafety::Unsafe
+            && !in_external_macro(cx.tcx.sess, item.span)
+            && !is_lint_allowed(cx, UNDOCUMENTED_UNSAFE_BLOCKS, item.hir_id())
+            && !is_unsafe_from_proc_macro(cx, item.span)
+            && !item_has_safety_comment(cx, item)
+        {
+            let source_map = cx.tcx.sess.source_map();
+            let span = if source_map.is_multiline(item.span) {
+                source_map.span_until_char(item.span, '\n')
+            } else {
+                item.span
+            };
+
+            span_lint_and_help(
+                cx,
+                UNDOCUMENTED_UNSAFE_BLOCKS,
+                span,
+                "unsafe impl missing a safety comment",
+                None,
+                "consider adding a safety comment on the preceding line",
+            );
+        }
+    }
 }
 
-fn is_unsafe_from_proc_macro(cx: &LateContext<'_>, block: &Block<'_>) -> bool {
+fn is_unsafe_from_proc_macro(cx: &LateContext<'_>, span: Span) -> bool {
     let source_map = cx.sess().source_map();
-    let file_pos = source_map.lookup_byte_offset(block.span.lo());
+    let file_pos = source_map.lookup_byte_offset(span.lo());
     file_pos
         .sf
         .src
@@ -100,7 +127,7 @@ fn is_unsafe_from_proc_macro(cx: &LateContext<'_>, block: &Block<'_>) -> bool {
 }
 
 /// Checks if the lines immediately preceding the block contain a safety comment.
-fn block_has_safety_comment(cx: &LateContext<'_>, block: &Block<'_>) -> bool {
+fn block_has_safety_comment(cx: &LateContext<'_>, block: &hir::Block<'_>) -> bool {
     // This intentionally ignores text before the start of a function so something like:
     // ```
     //     // SAFETY: reason
@@ -109,13 +136,115 @@ fn block_has_safety_comment(cx: &LateContext<'_>, block: &Block<'_>) -> bool {
     // won't work. This is to avoid dealing with where such a comment should be place relative to
     // attributes and doc comments.
 
+    span_from_macro_expansion_has_safety_comment(cx, block.span) || span_in_body_has_safety_comment(cx, block.span)
+}
+
+/// Checks if the lines immediately preceding the item contain a safety comment.
+#[allow(clippy::collapsible_match)]
+fn item_has_safety_comment(cx: &LateContext<'_>, item: &hir::Item<'_>) -> bool {
+    if span_from_macro_expansion_has_safety_comment(cx, item.span) {
+        return true;
+    }
+
+    if item.span.ctxt() == SyntaxContext::root() {
+        if let Some(parent_node) = get_parent_node(cx.tcx, item.hir_id()) {
+            let comment_start = match parent_node {
+                Node::Crate(parent_mod) => {
+                    comment_start_before_impl_in_mod(cx, parent_mod, parent_mod.spans.inner_span, item)
+                },
+                Node::Item(parent_item) => {
+                    if let ItemKind::Mod(parent_mod) = &parent_item.kind {
+                        comment_start_before_impl_in_mod(cx, parent_mod, parent_item.span, item)
+                    } else {
+                        // Doesn't support impls in this position. Pretend a comment was found.
+                        return true;
+                    }
+                },
+                Node::Stmt(stmt) => {
+                    if let Some(stmt_parent) = get_parent_node(cx.tcx, stmt.hir_id) {
+                        match stmt_parent {
+                            Node::Block(block) => walk_span_to_context(block.span, SyntaxContext::root()).map(Span::lo),
+                            _ => {
+                                // Doesn't support impls in this position. Pretend a comment was found.
+                                return true;
+                            },
+                        }
+                    } else {
+                        // Problem getting the parent node. Pretend a comment was found.
+                        return true;
+                    }
+                },
+                _ => {
+                    // Doesn't support impls in this position. Pretend a comment was found.
+                    return true;
+                },
+            };
+
+            let source_map = cx.sess().source_map();
+            if let Some(comment_start) = comment_start
+                && let Ok(unsafe_line) = source_map.lookup_line(item.span.lo())
+                && let Ok(comment_start_line) = source_map.lookup_line(comment_start)
+                && Lrc::ptr_eq(&unsafe_line.sf, &comment_start_line.sf)
+                && let Some(src) = unsafe_line.sf.src.as_deref()
+            {
+                comment_start_line.line < unsafe_line.line && text_has_safety_comment(
+                    src,
+                    &unsafe_line.sf.lines[comment_start_line.line + 1..=unsafe_line.line],
+                    unsafe_line.sf.start_pos.to_usize(),
+                )
+            } else {
+                // Problem getting source text. Pretend a comment was found.
+                true
+            }
+        } else {
+            // No parent node. Pretend a comment was found.
+            true
+        }
+    } else {
+        false
+    }
+}
+
+fn comment_start_before_impl_in_mod(
+    cx: &LateContext<'_>,
+    parent_mod: &hir::Mod<'_>,
+    parent_mod_span: Span,
+    imple: &hir::Item<'_>,
+) -> Option<BytePos> {
+    parent_mod.item_ids.iter().enumerate().find_map(|(idx, item_id)| {
+        if *item_id == imple.item_id() {
+            if idx == 0 {
+                // mod A { /* comment */ unsafe impl T {} ... }
+                // ^------------------------------------------^ returns the start of this span
+                // ^---------------------^ finally checks comments in this range
+                if let Some(sp) = walk_span_to_context(parent_mod_span, SyntaxContext::root()) {
+                    return Some(sp.lo());
+                }
+            } else {
+                // some_item /* comment */ unsafe impl T {}
+                // ^-------^ returns the end of this span
+                //         ^---------------^ finally checks comments in this range
+                let prev_item = cx.tcx.hir().item(parent_mod.item_ids[idx - 1]);
+                if let Some(sp) = walk_span_to_context(prev_item.span, SyntaxContext::root()) {
+                    return Some(sp.hi());
+                }
+            }
+        }
+        None
+    })
+}
+
+fn span_from_macro_expansion_has_safety_comment(cx: &LateContext<'_>, span: Span) -> bool {
     let source_map = cx.sess().source_map();
-    let ctxt = block.span.ctxt();
-    if ctxt != SyntaxContext::root() {
-        // From a macro expansion. Get the text from the start of the macro declaration to start of the unsafe block.
+    let ctxt = span.ctxt();
+    if ctxt == SyntaxContext::root() {
+        false
+    } else {
+        // From a macro expansion. Get the text from the start of the macro declaration to start of the
+        // unsafe block.
         //     macro_rules! foo { () => { stuff }; (x) => { unsafe { stuff } }; }
         //     ^--------------------------------------------^
-        if let Ok(unsafe_line) = source_map.lookup_line(block.span.lo())
+        if let Ok(unsafe_line) = source_map.lookup_line(span.lo())
             && let Ok(macro_line) = source_map.lookup_line(ctxt.outer_expn_data().def_site.lo())
             && Lrc::ptr_eq(&unsafe_line.sf, &macro_line.sf)
             && let Some(src) = unsafe_line.sf.src.as_deref()
@@ -129,24 +258,35 @@ fn block_has_safety_comment(cx: &LateContext<'_>, block: &Block<'_>) -> bool {
             // Problem getting source text. Pretend a comment was found.
             true
         }
-    } else if let Ok(unsafe_line) = source_map.lookup_line(block.span.lo())
+    }
+}
+
+fn span_in_body_has_safety_comment(cx: &LateContext<'_>, span: Span) -> bool {
+    let source_map = cx.sess().source_map();
+    let ctxt = span.ctxt();
+    if ctxt == SyntaxContext::root()
         && let Some(body) = cx.enclosing_body
-        && let Some(body_span) = walk_span_to_context(cx.tcx.hir().body(body).value.span, SyntaxContext::root())
-        && let Ok(body_line) = source_map.lookup_line(body_span.lo())
-        && Lrc::ptr_eq(&unsafe_line.sf, &body_line.sf)
-        && let Some(src) = unsafe_line.sf.src.as_deref()
     {
-        // Get the text from the start of function body to the unsafe block.
-        //     fn foo() { some_stuff; unsafe { stuff }; other_stuff; }
-        //              ^-------------^
-        body_line.line < unsafe_line.line && text_has_safety_comment(
-            src,
-            &unsafe_line.sf.lines[body_line.line + 1..=unsafe_line.line],
-            unsafe_line.sf.start_pos.to_usize(),
-        )
+        if let Ok(unsafe_line) = source_map.lookup_line(span.lo())
+            && let Some(body_span) = walk_span_to_context(cx.tcx.hir().body(body).value.span, SyntaxContext::root())
+            && let Ok(body_line) = source_map.lookup_line(body_span.lo())
+            && Lrc::ptr_eq(&unsafe_line.sf, &body_line.sf)
+            && let Some(src) = unsafe_line.sf.src.as_deref()
+        {
+            // Get the text from the start of function body to the unsafe block.
+            //     fn foo() { some_stuff; unsafe { stuff }; other_stuff; }
+            //              ^-------------^
+            body_line.line < unsafe_line.line && text_has_safety_comment(
+                src,
+                &unsafe_line.sf.lines[body_line.line + 1..=unsafe_line.line],
+                unsafe_line.sf.start_pos.to_usize(),
+            )
+        } else {
+            // Problem getting source text. Pretend a comment was found.
+            true
+        }
     } else {
-        // Problem getting source text. Pretend a comment was found.
-        true
+        false
     }
 }
 
diff --git a/src/tools/clippy/clippy_lints/src/uninit_vec.rs b/src/tools/clippy/clippy_lints/src/uninit_vec.rs
index 6d909c34690..9f4c5555f11 100644
--- a/src/tools/clippy/clippy_lints/src/uninit_vec.rs
+++ b/src/tools/clippy/clippy_lints/src/uninit_vec.rs
@@ -98,7 +98,7 @@ fn handle_uninit_vec_pair<'tcx>(
                 // Check T of Vec<T>
                 if !is_uninit_value_valid_for_ty(cx, substs.type_at(0)) {
                     // FIXME: #7698, false positive of the internal lints
-                    #[allow(clippy::collapsible_span_lint_calls)]
+                    #[expect(clippy::collapsible_span_lint_calls)]
                     span_lint_and_then(
                         cx,
                         UNINIT_VEC,
diff --git a/src/tools/clippy/clippy_lints/src/unit_types/let_unit_value.rs b/src/tools/clippy/clippy_lints/src/unit_types/let_unit_value.rs
index f3f1f53aac5..d86002c926e 100644
--- a/src/tools/clippy/clippy_lints/src/unit_types/let_unit_value.rs
+++ b/src/tools/clippy/clippy_lints/src/unit_types/let_unit_value.rs
@@ -3,6 +3,7 @@ use clippy_utils::source::snippet_with_macro_callsite;
 use clippy_utils::visitors::for_each_value_source;
 use core::ops::ControlFlow;
 use rustc_errors::Applicability;
+use rustc_hir::def::{DefKind, Res};
 use rustc_hir::{Expr, ExprKind, PatKind, Stmt, StmtKind};
 use rustc_lint::{LateContext, LintContext};
 use rustc_middle::lint::in_external_macro;
@@ -71,14 +72,18 @@ fn needs_inferred_result_ty(cx: &LateContext<'_>, e: &Expr<'_>) -> bool {
                 ..
             },
             _,
-        ) => cx.qpath_res(path, *hir_id).opt_def_id(),
-        ExprKind::MethodCall(..) => cx.typeck_results().type_dependent_def_id(e.hir_id),
+        ) => match cx.qpath_res(path, *hir_id) {
+            Res::Def(DefKind::AssocFn | DefKind::Fn, id) => id,
+            _ => return false,
+        },
+        ExprKind::MethodCall(..) => match cx.typeck_results().type_dependent_def_id(e.hir_id) {
+            Some(id) => id,
+            None => return false,
+        },
         _ => return false,
     };
-    if let Some(id) = id
-        && let sig = cx.tcx.fn_sig(id).skip_binder()
-        && let ty::Param(output_ty) = *sig.output().kind()
-    {
+    let sig = cx.tcx.fn_sig(id).skip_binder();
+    if let ty::Param(output_ty) = *sig.output().kind() {
         sig.inputs().iter().all(|&ty| !ty_contains_param(ty, output_ty.index))
     } else {
         false
diff --git a/src/tools/clippy/clippy_lints/src/unnested_or_patterns.rs b/src/tools/clippy/clippy_lints/src/unnested_or_patterns.rs
index ae431aac83b..04e2f301bfd 100644
--- a/src/tools/clippy/clippy_lints/src/unnested_or_patterns.rs
+++ b/src/tools/clippy/clippy_lints/src/unnested_or_patterns.rs
@@ -61,13 +61,13 @@ impl_lint_pass!(UnnestedOrPatterns => [UNNESTED_OR_PATTERNS]);
 
 impl EarlyLintPass for UnnestedOrPatterns {
     fn check_arm(&mut self, cx: &EarlyContext<'_>, a: &ast::Arm) {
-        if meets_msrv(self.msrv.as_ref(), &msrvs::OR_PATTERNS) {
+        if meets_msrv(self.msrv, msrvs::OR_PATTERNS) {
             lint_unnested_or_patterns(cx, &a.pat);
         }
     }
 
     fn check_expr(&mut self, cx: &EarlyContext<'_>, e: &ast::Expr) {
-        if meets_msrv(self.msrv.as_ref(), &msrvs::OR_PATTERNS) {
+        if meets_msrv(self.msrv, msrvs::OR_PATTERNS) {
             if let ast::ExprKind::Let(pat, _, _) = &e.kind {
                 lint_unnested_or_patterns(cx, pat);
             }
@@ -75,13 +75,13 @@ impl EarlyLintPass for UnnestedOrPatterns {
     }
 
     fn check_param(&mut self, cx: &EarlyContext<'_>, p: &ast::Param) {
-        if meets_msrv(self.msrv.as_ref(), &msrvs::OR_PATTERNS) {
+        if meets_msrv(self.msrv, msrvs::OR_PATTERNS) {
             lint_unnested_or_patterns(cx, &p.pat);
         }
     }
 
     fn check_local(&mut self, cx: &EarlyContext<'_>, l: &ast::Local) {
-        if meets_msrv(self.msrv.as_ref(), &msrvs::OR_PATTERNS) {
+        if meets_msrv(self.msrv, msrvs::OR_PATTERNS) {
             lint_unnested_or_patterns(cx, &l.pat);
         }
     }
diff --git a/src/tools/clippy/clippy_lints/src/unused_unit.rs b/src/tools/clippy/clippy_lints/src/unused_unit.rs
index bfd17a68749..52585e59566 100644
--- a/src/tools/clippy/clippy_lints/src/unused_unit.rs
+++ b/src/tools/clippy/clippy_lints/src/unused_unit.rs
@@ -130,7 +130,7 @@ fn lint_unneeded_unit_return(cx: &EarlyContext<'_>, ty: &ast::Ty, span: Span) {
         snippet_opt(cx, span.with_hi(ty.span.hi())).map_or((ty.span, Applicability::MaybeIncorrect), |fn_source| {
             position_before_rarrow(&fn_source).map_or((ty.span, Applicability::MaybeIncorrect), |rpos| {
                 (
-                    #[allow(clippy::cast_possible_truncation)]
+                    #[expect(clippy::cast_possible_truncation)]
                     ty.span.with_lo(BytePos(span.lo().0 + rpos as u32)),
                     Applicability::MachineApplicable,
                 )
diff --git a/src/tools/clippy/clippy_lints/src/use_self.rs b/src/tools/clippy/clippy_lints/src/use_self.rs
index 138f8bccb3f..66f7748e9e0 100644
--- a/src/tools/clippy/clippy_lints/src/use_self.rs
+++ b/src/tools/clippy/clippy_lints/src/use_self.rs
@@ -198,7 +198,7 @@ impl<'tcx> LateLintPass<'tcx> for UseSelf {
     fn check_ty(&mut self, cx: &LateContext<'_>, hir_ty: &hir::Ty<'_>) {
         if_chain! {
             if !hir_ty.span.from_expansion();
-            if meets_msrv(self.msrv.as_ref(), &msrvs::TYPE_ALIAS_ENUM_VARIANTS);
+            if meets_msrv(self.msrv, msrvs::TYPE_ALIAS_ENUM_VARIANTS);
             if let Some(&StackItem::Check {
                 impl_id,
                 in_body,
@@ -225,7 +225,7 @@ impl<'tcx> LateLintPass<'tcx> for UseSelf {
     fn check_expr(&mut self, cx: &LateContext<'_>, expr: &Expr<'_>) {
         if_chain! {
             if !expr.span.from_expansion();
-            if meets_msrv(self.msrv.as_ref(), &msrvs::TYPE_ALIAS_ENUM_VARIANTS);
+            if meets_msrv(self.msrv, msrvs::TYPE_ALIAS_ENUM_VARIANTS);
             if let Some(&StackItem::Check { impl_id, .. }) = self.stack.last();
             if cx.typeck_results().expr_ty(expr) == cx.tcx.type_of(impl_id);
             then {} else { return; }
@@ -256,7 +256,7 @@ impl<'tcx> LateLintPass<'tcx> for UseSelf {
     fn check_pat(&mut self, cx: &LateContext<'_>, pat: &Pat<'_>) {
         if_chain! {
             if !pat.span.from_expansion();
-            if meets_msrv(self.msrv.as_ref(), &msrvs::TYPE_ALIAS_ENUM_VARIANTS);
+            if meets_msrv(self.msrv, msrvs::TYPE_ALIAS_ENUM_VARIANTS);
             if let Some(&StackItem::Check { impl_id, .. }) = self.stack.last();
             if let PatKind::Path(QPath::Resolved(_, path)) = pat.kind;
             if !matches!(path.res, Res::SelfTy { .. } | Res::Def(DefKind::TyParam, _));
diff --git a/src/tools/clippy/clippy_lints/src/useless_conversion.rs b/src/tools/clippy/clippy_lints/src/useless_conversion.rs
index abd8a362370..4a3b5383c89 100644
--- a/src/tools/clippy/clippy_lints/src/useless_conversion.rs
+++ b/src/tools/clippy/clippy_lints/src/useless_conversion.rs
@@ -41,7 +41,7 @@ pub struct UselessConversion {
 
 impl_lint_pass!(UselessConversion => [USELESS_CONVERSION]);
 
-#[allow(clippy::too_many_lines)]
+#[expect(clippy::too_many_lines)]
 impl<'tcx> LateLintPass<'tcx> for UselessConversion {
     fn check_expr(&mut self, cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) {
         if e.span.from_expansion() {
diff --git a/src/tools/clippy/clippy_lints/src/utils/conf.rs b/src/tools/clippy/clippy_lints/src/utils/conf.rs
index 74b0168a179..cd4d16fe95f 100644
--- a/src/tools/clippy/clippy_lints/src/utils/conf.rs
+++ b/src/tools/clippy/clippy_lints/src/utils/conf.rs
@@ -6,7 +6,8 @@ use serde::de::{Deserializer, IgnoredAny, IntoDeserializer, MapAccess, Visitor};
 use serde::Deserialize;
 use std::error::Error;
 use std::path::{Path, PathBuf};
-use std::{env, fmt, fs, io};
+use std::str::FromStr;
+use std::{cmp, env, fmt, fs, io, iter};
 
 /// Holds information used by `MISSING_ENFORCED_IMPORT_RENAMES` lint.
 #[derive(Clone, Debug, Deserialize)]
@@ -43,18 +44,33 @@ pub enum DisallowedType {
 #[derive(Default)]
 pub struct TryConf {
     pub conf: Conf,
-    pub errors: Vec<String>,
+    pub errors: Vec<Box<dyn Error>>,
 }
 
 impl TryConf {
-    fn from_error(error: impl Error) -> Self {
+    fn from_error(error: impl Error + 'static) -> Self {
         Self {
             conf: Conf::default(),
-            errors: vec![error.to_string()],
+            errors: vec![Box::new(error)],
         }
     }
 }
 
+#[derive(Debug)]
+struct ConfError(String);
+
+impl fmt::Display for ConfError {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        <String as fmt::Display>::fmt(&self.0, f)
+    }
+}
+
+impl Error for ConfError {}
+
+fn conf_error(s: String) -> Box<dyn Error> {
+    Box::new(ConfError(s))
+}
+
 macro_rules! define_Conf {
     ($(
         $(#[doc = $doc:literal])+
@@ -103,11 +119,11 @@ macro_rules! define_Conf {
                 while let Some(name) = map.next_key::<&str>()? {
                     match Field::deserialize(name.into_deserializer())? {
                         $(Field::$name => {
-                            $(errors.push(format!("deprecated field `{}`. {}", name, $dep));)?
+                            $(errors.push(conf_error(format!("deprecated field `{}`. {}", name, $dep)));)?
                             match map.next_value() {
-                                Err(e) => errors.push(e.to_string()),
+                                Err(e) => errors.push(conf_error(e.to_string())),
                                 Ok(value) => match $name {
-                                    Some(_) => errors.push(format!("duplicate field `{}`", name)),
+                                    Some(_) => errors.push(conf_error(format!("duplicate field `{}`", name))),
                                     None => $name = Some(value),
                                 }
                             }
@@ -316,6 +332,14 @@ define_Conf! {
     ///
     /// The maximum size of a file included via `include_bytes!()` or `include_str!()`, in bytes
     (max_include_file_size: u64 = 1_000_000),
+    /// Lint: EXPECT_USED.
+    ///
+    /// Whether `expect` should be allowed in test functions
+    (allow_expect_in_tests: bool = false),
+    /// Lint: UNWRAP_USED.
+    ///
+    /// Whether `unwrap` should be allowed in test functions
+    (allow_unwrap_in_tests: bool = false),
 }
 
 /// Search for the configuration file.
@@ -375,3 +399,102 @@ pub fn read(path: &Path) -> TryConf {
     };
     toml::from_str(&content).unwrap_or_else(TryConf::from_error)
 }
+
+const SEPARATOR_WIDTH: usize = 4;
+
+// Check whether the error is "unknown field" and, if so, list the available fields sorted and at
+// least one per line, more if `CLIPPY_TERMINAL_WIDTH` is set and allows it.
+pub fn format_error(error: Box<dyn Error>) -> String {
+    let s = error.to_string();
+
+    if_chain! {
+        if error.downcast::<toml::de::Error>().is_ok();
+        if let Some((prefix, mut fields, suffix)) = parse_unknown_field_message(&s);
+        then {
+            use fmt::Write;
+
+            fields.sort_unstable();
+
+            let (rows, column_widths) = calculate_dimensions(&fields);
+
+            let mut msg = String::from(prefix);
+            for row in 0..rows {
+                write!(msg, "\n").unwrap();
+                for (column, column_width) in column_widths.iter().copied().enumerate() {
+                    let index = column * rows + row;
+                    let field = fields.get(index).copied().unwrap_or_default();
+                    write!(
+                        msg,
+                        "{:separator_width$}{:field_width$}",
+                        " ",
+                        field,
+                        separator_width = SEPARATOR_WIDTH,
+                        field_width = column_width
+                    )
+                    .unwrap();
+                }
+            }
+            write!(msg, "\n{}", suffix).unwrap();
+            msg
+        } else {
+            s
+        }
+    }
+}
+
+// `parse_unknown_field_message` will become unnecessary if
+// https://github.com/alexcrichton/toml-rs/pull/364 is merged.
+fn parse_unknown_field_message(s: &str) -> Option<(&str, Vec<&str>, &str)> {
+    // An "unknown field" message has the following form:
+    //   unknown field `UNKNOWN`, expected one of `FIELD0`, `FIELD1`, ..., `FIELDN` at line X column Y
+    //                                           ^^      ^^^^                     ^^
+    if_chain! {
+        if s.starts_with("unknown field");
+        let slices = s.split("`, `").collect::<Vec<_>>();
+        let n = slices.len();
+        if n >= 2;
+        if let Some((prefix, first_field)) = slices[0].rsplit_once(" `");
+        if let Some((last_field, suffix)) = slices[n - 1].split_once("` ");
+        then {
+            let fields = iter::once(first_field)
+                .chain(slices[1..n - 1].iter().copied())
+                .chain(iter::once(last_field))
+                .collect::<Vec<_>>();
+            Some((prefix, fields, suffix))
+        } else {
+            None
+        }
+    }
+}
+
+fn calculate_dimensions(fields: &[&str]) -> (usize, Vec<usize>) {
+    let columns = env::var("CLIPPY_TERMINAL_WIDTH")
+        .ok()
+        .and_then(|s| <usize as FromStr>::from_str(&s).ok())
+        .map_or(1, |terminal_width| {
+            let max_field_width = fields.iter().map(|field| field.len()).max().unwrap();
+            cmp::max(1, terminal_width / (SEPARATOR_WIDTH + max_field_width))
+        });
+
+    let rows = (fields.len() + (columns - 1)) / columns;
+
+    let column_widths = (0..columns)
+        .map(|column| {
+            if column < columns - 1 {
+                (0..rows)
+                    .map(|row| {
+                        let index = column * rows + row;
+                        let field = fields.get(index).copied().unwrap_or_default();
+                        field.len()
+                    })
+                    .max()
+                    .unwrap()
+            } else {
+                // Avoid adding extra space to the last column.
+                0
+            }
+        })
+        .collect::<Vec<_>>();
+
+    (rows, column_widths)
+}
diff --git a/src/tools/clippy/clippy_lints/src/vec.rs b/src/tools/clippy/clippy_lints/src/vec.rs
index 79e7410c3a8..ba1ff65479d 100644
--- a/src/tools/clippy/clippy_lints/src/vec.rs
+++ b/src/tools/clippy/clippy_lints/src/vec.rs
@@ -12,7 +12,7 @@ use rustc_middle::ty::{self, Ty};
 use rustc_session::{declare_tool_lint, impl_lint_pass};
 use rustc_span::source_map::Span;
 
-#[allow(clippy::module_name_repetitions)]
+#[expect(clippy::module_name_repetitions)]
 #[derive(Copy, Clone)]
 pub struct UselessVec {
     pub too_large_for_stack: u64,
@@ -83,7 +83,7 @@ impl UselessVec {
         let snippet = match *vec_args {
             higher::VecArgs::Repeat(elem, len) => {
                 if let Some((Constant::Int(len_constant), _)) = constant(cx, cx.typeck_results(), len) {
-                    #[allow(clippy::cast_possible_truncation)]
+                    #[expect(clippy::cast_possible_truncation)]
                     if len_constant as u64 * size_of(cx, elem) > self.too_large_for_stack {
                         return;
                     }
@@ -110,7 +110,6 @@ impl UselessVec {
             },
             higher::VecArgs::Vec(args) => {
                 if let Some(last) = args.iter().last() {
-                    #[allow(clippy::cast_possible_truncation)]
                     if args.len() as u64 * size_of(cx, last) > self.too_large_for_stack {
                         return;
                     }
diff --git a/src/tools/clippy/clippy_lints/src/vec_init_then_push.rs b/src/tools/clippy/clippy_lints/src/vec_init_then_push.rs
index fbf2b3e081b..35db45e2b0c 100644
--- a/src/tools/clippy/clippy_lints/src/vec_init_then_push.rs
+++ b/src/tools/clippy/clippy_lints/src/vec_init_then_push.rs
@@ -1,19 +1,30 @@
 use clippy_utils::diagnostics::span_lint_and_sugg;
 use clippy_utils::higher::{get_vec_init_kind, VecInitKind};
 use clippy_utils::source::snippet;
-use clippy_utils::{path_to_local, path_to_local_id};
-use if_chain::if_chain;
+use clippy_utils::visitors::for_each_local_use_after_expr;
+use clippy_utils::{get_parent_expr, path_to_local_id};
+use core::ops::ControlFlow;
 use rustc_errors::Applicability;
-use rustc_hir::{BindingAnnotation, Block, Expr, ExprKind, HirId, Local, PatKind, Stmt, StmtKind};
+use rustc_hir::def::Res;
+use rustc_hir::{
+    BindingAnnotation, Block, Expr, ExprKind, HirId, Local, Mutability, PatKind, QPath, Stmt, StmtKind, UnOp,
+};
 use rustc_lint::{LateContext, LateLintPass, LintContext};
 use rustc_middle::lint::in_external_macro;
 use rustc_session::{declare_tool_lint, impl_lint_pass};
-use rustc_span::Span;
+use rustc_span::{Span, Symbol};
 
 declare_clippy_lint! {
     /// ### What it does
     /// Checks for calls to `push` immediately after creating a new `Vec`.
     ///
+    /// If the `Vec` is created using `with_capacity` this will only lint if the capacity is a
+    /// constant and the number of pushes is greater than or equal to the initial capacity.
+    ///
+    /// If the `Vec` is extended after the initial sequence of pushes and it was default initialized
+    /// then this will only lint after there were at least four pushes. This number may change in
+    /// the future.
+    ///
     /// ### Why is this bad?
     /// The `vec![]` macro is both more performant and easier to read than
     /// multiple `push` calls.
@@ -43,26 +54,88 @@ pub struct VecInitThenPush {
 struct VecPushSearcher {
     local_id: HirId,
     init: VecInitKind,
-    lhs_is_local: bool,
-    lhs_span: Span,
+    lhs_is_let: bool,
+    let_ty_span: Option<Span>,
+    name: Symbol,
     err_span: Span,
-    found: u64,
+    found: u128,
+    last_push_expr: HirId,
 }
 impl VecPushSearcher {
     fn display_err(&self, cx: &LateContext<'_>) {
-        match self.init {
+        let required_pushes_before_extension = match self.init {
             _ if self.found == 0 => return,
-            VecInitKind::WithLiteralCapacity(x) if x > self.found => return,
+            VecInitKind::WithConstCapacity(x) if x > self.found => return,
+            VecInitKind::WithConstCapacity(x) => x,
             VecInitKind::WithExprCapacity(_) => return,
-            _ => (),
+            _ => 3,
         };
 
-        let mut s = if self.lhs_is_local {
+        let mut needs_mut = false;
+        let res = for_each_local_use_after_expr(cx, self.local_id, self.last_push_expr, |e| {
+            let Some(parent) = get_parent_expr(cx, e) else {
+                return ControlFlow::Continue(())
+            };
+            let adjusted_ty = cx.typeck_results().expr_ty_adjusted(e);
+            let adjusted_mut = adjusted_ty.ref_mutability().unwrap_or(Mutability::Not);
+            needs_mut |= adjusted_mut == Mutability::Mut;
+            match parent.kind {
+                ExprKind::AddrOf(_, Mutability::Mut, _) => {
+                    needs_mut = true;
+                    return ControlFlow::Break(true);
+                },
+                ExprKind::Unary(UnOp::Deref, _) | ExprKind::Index(..) if !needs_mut => {
+                    let mut last_place = parent;
+                    while let Some(parent) = get_parent_expr(cx, parent) {
+                        if matches!(parent.kind, ExprKind::Unary(UnOp::Deref, _) | ExprKind::Field(..))
+                            || matches!(parent.kind, ExprKind::Index(e, _) if e.hir_id == last_place.hir_id)
+                        {
+                            last_place = parent;
+                        } else {
+                            break;
+                        }
+                    }
+                    needs_mut |= cx.typeck_results().expr_ty_adjusted(last_place).ref_mutability()
+                        == Some(Mutability::Mut)
+                        || get_parent_expr(cx, last_place)
+                            .map_or(false, |e| matches!(e.kind, ExprKind::AddrOf(_, Mutability::Mut, _)));
+                },
+                ExprKind::MethodCall(_, [recv, ..], _)
+                    if recv.hir_id == e.hir_id
+                        && adjusted_mut == Mutability::Mut
+                        && !adjusted_ty.peel_refs().is_slice() =>
+                {
+                    // No need to set `needs_mut` to true. The receiver will be either explicitly borrowed, or it will
+                    // be implicitly borrowed via an adjustment. Both of these cases are already handled by this point.
+                    return ControlFlow::Break(true);
+                },
+                ExprKind::Assign(lhs, ..) if e.hir_id == lhs.hir_id => {
+                    needs_mut = true;
+                    return ControlFlow::Break(false);
+                },
+                _ => (),
+            }
+            ControlFlow::Continue(())
+        });
+
+        // Avoid allocating small `Vec`s when they'll be extended right after.
+        if res == ControlFlow::Break(true) && self.found <= required_pushes_before_extension {
+            return;
+        }
+
+        let mut s = if self.lhs_is_let {
             String::from("let ")
         } else {
             String::new()
         };
-        s.push_str(&snippet(cx, self.lhs_span, ".."));
+        if needs_mut {
+            s.push_str("mut ");
+        }
+        s.push_str(self.name.as_str());
+        if let Some(span) = self.let_ty_span {
+            s.push_str(": ");
+            s.push_str(&snippet(cx, span, "_"));
+        }
         s.push_str(" = vec![..];");
 
         span_lint_and_sugg(
@@ -83,60 +156,63 @@ impl<'tcx> LateLintPass<'tcx> for VecInitThenPush {
     }
 
     fn check_local(&mut self, cx: &LateContext<'tcx>, local: &'tcx Local<'tcx>) {
-        if_chain! {
-            if !in_external_macro(cx.sess(), local.span);
-            if let Some(init) = local.init;
-            if let PatKind::Binding(BindingAnnotation::Mutable, id, _, None) = local.pat.kind;
-            if let Some(init_kind) = get_vec_init_kind(cx, init);
-            then {
-                self.searcher = Some(VecPushSearcher {
-                        local_id: id,
-                        init: init_kind,
-                        lhs_is_local: true,
-                        lhs_span: local.ty.map_or(local.pat.span, |t| local.pat.span.to(t.span)),
-                        err_span: local.span,
-                        found: 0,
-                    });
-            }
+        if let Some(init_expr) = local.init
+            && let PatKind::Binding(BindingAnnotation::Mutable, id, name, None) = local.pat.kind
+            && !in_external_macro(cx.sess(), local.span)
+            && let Some(init) = get_vec_init_kind(cx, init_expr)
+            && !matches!(init, VecInitKind::WithExprCapacity(_))
+        {
+            self.searcher = Some(VecPushSearcher {
+                local_id: id,
+                init,
+                lhs_is_let: true,
+                name: name.name,
+                let_ty_span: local.ty.map(|ty| ty.span),
+                err_span: local.span,
+                found: 0,
+                last_push_expr: init_expr.hir_id,
+            });
         }
     }
 
     fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
-        if_chain! {
-            if self.searcher.is_none();
-            if !in_external_macro(cx.sess(), expr.span);
-            if let ExprKind::Assign(left, right, _) = expr.kind;
-            if let Some(id) = path_to_local(left);
-            if let Some(init_kind) = get_vec_init_kind(cx, right);
-            then {
-                self.searcher = Some(VecPushSearcher {
-                    local_id: id,
-                    init: init_kind,
-                    lhs_is_local: false,
-                    lhs_span: left.span,
-                    err_span: expr.span,
-                    found: 0,
-                });
-            }
+        if self.searcher.is_none()
+            && let ExprKind::Assign(left, right, _) = expr.kind
+            && let ExprKind::Path(QPath::Resolved(None, path)) = left.kind
+            && let [name] = &path.segments
+            && let Res::Local(id) = path.res
+            && !in_external_macro(cx.sess(), expr.span)
+            && let Some(init) = get_vec_init_kind(cx, right)
+            && !matches!(init, VecInitKind::WithExprCapacity(_))
+        {
+            self.searcher = Some(VecPushSearcher {
+                local_id: id,
+                init,
+                lhs_is_let: false,
+                let_ty_span: None,
+                name: name.ident.name,
+                err_span: expr.span,
+                found: 0,
+                last_push_expr: expr.hir_id,
+            });
         }
     }
 
     fn check_stmt(&mut self, cx: &LateContext<'tcx>, stmt: &'tcx Stmt<'_>) {
         if let Some(searcher) = self.searcher.take() {
-            if_chain! {
-                if let StmtKind::Expr(expr) | StmtKind::Semi(expr) = stmt.kind;
-                if let ExprKind::MethodCall(path, [self_arg, _], _) = expr.kind;
-                if path_to_local_id(self_arg, searcher.local_id);
-                if path.ident.name.as_str() == "push";
-                then {
-                    self.searcher = Some(VecPushSearcher {
-                        found: searcher.found + 1,
-                        err_span: searcher.err_span.to(stmt.span),
-                        .. searcher
-                    });
-                } else {
-                    searcher.display_err(cx);
-                }
+            if let StmtKind::Expr(expr) | StmtKind::Semi(expr) = stmt.kind
+                && let ExprKind::MethodCall(name, [self_arg, _], _) = expr.kind
+                && path_to_local_id(self_arg, searcher.local_id)
+                && name.ident.as_str() == "push"
+            {
+                self.searcher = Some(VecPushSearcher {
+                    found: searcher.found + 1,
+                    err_span: searcher.err_span.to(stmt.span),
+                    last_push_expr: expr.hir_id,
+                    .. searcher
+                });
+            } else {
+                searcher.display_err(cx);
             }
         }
     }
diff --git a/src/tools/clippy/clippy_lints/src/write.rs b/src/tools/clippy/clippy_lints/src/write.rs
index 54b93a20a05..d2493c055a5 100644
--- a/src/tools/clippy/clippy_lints/src/write.rs
+++ b/src/tools/clippy/clippy_lints/src/write.rs
@@ -342,8 +342,6 @@ impl EarlyLintPass for Write {
             if let (Some(fmt_str), expr) = self.check_tts(cx, mac.args.inner_tokens(), true) {
                 if fmt_str.symbol == kw::Empty {
                     let mut applicability = Applicability::MachineApplicable;
-                    // FIXME: remove this `#[allow(...)]` once the issue #5822 gets fixed
-                    #[allow(clippy::option_if_let_else)]
                     let suggestion = if let Some(e) = expr {
                         snippet_with_applicability(cx, e.span, "v", &mut applicability)
                     } else {
@@ -528,7 +526,6 @@ impl Write {
     /// ```rust,ignore
     /// (Some("string to write: {}"), Some(buf))
     /// ```
-    #[allow(clippy::too_many_lines)]
     fn check_tts<'a>(&self, cx: &EarlyContext<'a>, tts: TokenStream, is_write: bool) -> (Option<StrLit>, Option<Expr>) {
         let mut parser = parser::Parser::new(&cx.sess().parse_sess, tts, false, None);
         let expr = if is_write {
diff --git a/src/tools/clippy/clippy_utils/Cargo.toml b/src/tools/clippy/clippy_utils/Cargo.toml
index 0b1fd95c345..c4e0b8448ab 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.62"
+version = "0.1.63"
 edition = "2021"
 publish = false
 
diff --git a/src/tools/clippy/clippy_utils/src/ast_utils.rs b/src/tools/clippy/clippy_utils/src/ast_utils.rs
index 7919800483f..b379f8c06c6 100644
--- a/src/tools/clippy/clippy_utils/src/ast_utils.rs
+++ b/src/tools/clippy/clippy_utils/src/ast_utils.rs
@@ -242,7 +242,7 @@ pub fn eq_item<K>(l: &Item<K>, r: &Item<K>, mut eq_kind: impl FnMut(&K, &K) -> b
     eq_id(l.ident, r.ident) && over(&l.attrs, &r.attrs, eq_attr) && eq_vis(&l.vis, &r.vis) && eq_kind(&l.kind, &r.kind)
 }
 
-#[allow(clippy::too_many_lines)] // Just a big match statement
+#[expect(clippy::too_many_lines)] // Just a big match statement
 pub fn eq_item_kind(l: &ItemKind, r: &ItemKind) -> bool {
     use ItemKind::*;
     match (l, r) {
diff --git a/src/tools/clippy/clippy_utils/src/attrs.rs b/src/tools/clippy/clippy_utils/src/attrs.rs
index 904b1a05ccc..49318849d58 100644
--- a/src/tools/clippy/clippy_utils/src/attrs.rs
+++ b/src/tools/clippy/clippy_utils/src/attrs.rs
@@ -1,12 +1,11 @@
 use rustc_ast::ast;
+use rustc_ast::attr;
 use rustc_errors::Applicability;
 use rustc_session::Session;
-use rustc_ast::attr;
 use rustc_span::sym;
 use std::str::FromStr;
 
 /// Deprecation status of attributes known by Clippy.
-#[allow(dead_code)]
 pub enum DeprecationStatus {
     /// Attribute is deprecated
     Deprecated,
@@ -158,4 +157,3 @@ pub fn is_doc_hidden(attrs: &[ast::Attribute]) -> bool {
         .filter_map(ast::Attribute::meta_item_list)
         .any(|l| attr::list_contains_name(&l, sym::hidden))
 }
-
diff --git a/src/tools/clippy/clippy_utils/src/consts.rs b/src/tools/clippy/clippy_utils/src/consts.rs
index a80c7ee4929..9f162a117b2 100644
--- a/src/tools/clippy/clippy_utils/src/consts.rs
+++ b/src/tools/clippy/clippy_utils/src/consts.rs
@@ -13,7 +13,6 @@ use rustc_middle::ty::{self, EarlyBinder, FloatTy, ScalarInt, Ty, TyCtxt};
 use rustc_middle::{bug, span_bug};
 use rustc_span::symbol::Symbol;
 use std::cmp::Ordering::{self, Equal};
-use std::convert::TryInto;
 use std::hash::{Hash, Hasher};
 use std::iter;
 
@@ -130,12 +129,10 @@ impl Constant {
         match (left, right) {
             (&Self::Str(ref ls), &Self::Str(ref rs)) => Some(ls.cmp(rs)),
             (&Self::Char(ref l), &Self::Char(ref r)) => Some(l.cmp(r)),
-            (&Self::Int(l), &Self::Int(r)) => {
-                if let ty::Int(int_ty) = *cmp_type.kind() {
-                    Some(sext(tcx, l, int_ty).cmp(&sext(tcx, r, int_ty)))
-                } else {
-                    Some(l.cmp(&r))
-                }
+            (&Self::Int(l), &Self::Int(r)) => match *cmp_type.kind() {
+                ty::Int(int_ty) => Some(sext(tcx, l, int_ty).cmp(&sext(tcx, r, int_ty))),
+                ty::Uint(_) => Some(l.cmp(&r)),
+                _ => bug!("Not an int type"),
             },
             (&Self::F64(l), &Self::F64(r)) => l.partial_cmp(&r),
             (&Self::F32(l), &Self::F32(r)) => l.partial_cmp(&r),
@@ -352,7 +349,7 @@ impl<'a, 'tcx> ConstEvalLateContext<'a, 'tcx> {
         }
     }
 
-    #[allow(clippy::cast_possible_wrap)]
+    #[expect(clippy::cast_possible_wrap)]
     fn constant_not(&self, o: &Constant, ty: Ty<'_>) -> Option<Constant> {
         use self::Constant::{Bool, Int};
         match *o {
diff --git a/src/tools/clippy/clippy_utils/src/diagnostics.rs b/src/tools/clippy/clippy_utils/src/diagnostics.rs
index b142397f71b..4e037d88494 100644
--- a/src/tools/clippy/clippy_utils/src/diagnostics.rs
+++ b/src/tools/clippy/clippy_utils/src/diagnostics.rs
@@ -77,7 +77,7 @@ pub fn span_lint<T: LintContext>(cx: &T, lint: &'static Lint, sp: impl Into<Mult
 pub fn span_lint_and_help<'a, T: LintContext>(
     cx: &'a T,
     lint: &'static Lint,
-    span: Span,
+    span: impl Into<MultiSpan>,
     msg: &str,
     help_span: Option<Span>,
     help: &str,
diff --git a/src/tools/clippy/clippy_utils/src/eager_or_lazy.rs b/src/tools/clippy/clippy_utils/src/eager_or_lazy.rs
index a6ef6d79fc0..1a784b6cdda 100644
--- a/src/tools/clippy/clippy_utils/src/eager_or_lazy.rs
+++ b/src/tools/clippy/clippy_utils/src/eager_or_lazy.rs
@@ -96,7 +96,7 @@ fn fn_eagerness<'tcx>(
     }
 }
 
-#[allow(clippy::too_many_lines)]
+#[expect(clippy::too_many_lines)]
 fn expr_eagerness<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) -> EagernessSuggestion {
     struct V<'cx, 'tcx> {
         cx: &'cx LateContext<'tcx>,
diff --git a/src/tools/clippy/clippy_utils/src/higher.rs b/src/tools/clippy/clippy_utils/src/higher.rs
index 2095fc966c5..1e0fc789af2 100644
--- a/src/tools/clippy/clippy_utils/src/higher.rs
+++ b/src/tools/clippy/clippy_utils/src/higher.rs
@@ -2,10 +2,11 @@
 
 #![deny(clippy::missing_docs_in_private_items)]
 
+use crate::consts::{constant_simple, Constant};
 use crate::ty::is_type_diagnostic_item;
 use crate::{is_expn_of, match_def_path, paths};
 use if_chain::if_chain;
-use rustc_ast::ast::{self, LitKind};
+use rustc_ast::ast;
 use rustc_hir as hir;
 use rustc_hir::{Arm, Block, Expr, ExprKind, HirId, LoopSource, MatchSource, Node, Pat, QPath};
 use rustc_lint::LateContext;
@@ -431,7 +432,7 @@ pub enum VecInitKind {
     /// `Vec::default()` or `Default::default()`
     Default,
     /// `Vec::with_capacity(123)`
-    WithLiteralCapacity(u64),
+    WithConstCapacity(u128),
     /// `Vec::with_capacity(slice.len())`
     WithExprCapacity(HirId),
 }
@@ -449,15 +450,11 @@ pub fn get_vec_init_kind<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) -
                     return Some(VecInitKind::Default);
                 } else if name.ident.name.as_str() == "with_capacity" {
                     let arg = args.get(0)?;
-                    if_chain! {
-                        if let ExprKind::Lit(lit) = &arg.kind;
-                        if let LitKind::Int(num, _) = lit.node;
-                        then {
-                            return Some(VecInitKind::WithLiteralCapacity(num.try_into().ok()?));
-                        }
-                    }
-                    return Some(VecInitKind::WithExprCapacity(arg.hir_id));
-                }
+                    return match constant_simple(cx, cx.typeck_results(), arg) {
+                        Some(Constant::Int(num)) => Some(VecInitKind::WithConstCapacity(num)),
+                        _ => Some(VecInitKind::WithExprCapacity(arg.hir_id)),
+                    };
+                };
             },
             ExprKind::Path(QPath::Resolved(_, path))
                 if match_def_path(cx, path.res.opt_def_id()?, &paths::DEFAULT_TRAIT_METHOD)
diff --git a/src/tools/clippy/clippy_utils/src/hir_utils.rs b/src/tools/clippy/clippy_utils/src/hir_utils.rs
index aa21f15ee5d..c440793b90e 100644
--- a/src/tools/clippy/clippy_utils/src/hir_utils.rs
+++ b/src/tools/clippy/clippy_utils/src/hir_utils.rs
@@ -64,7 +64,6 @@ impl<'a, 'tcx> SpanlessEq<'a, 'tcx> {
         }
     }
 
-    #[allow(dead_code)]
     pub fn eq_block(&mut self, left: &Block<'_>, right: &Block<'_>) -> bool {
         self.inter_expr().eq_block(left, right)
     }
@@ -194,7 +193,7 @@ impl HirEqInterExpr<'_, '_, '_> {
         res
     }
 
-    #[allow(clippy::similar_names)]
+    #[expect(clippy::similar_names)]
     pub fn eq_expr(&mut self, left: &Expr<'_>, right: &Expr<'_>) -> bool {
         if !self.inner.allow_side_effects && left.span.ctxt() != right.span.ctxt() {
             return false;
@@ -361,7 +360,7 @@ impl HirEqInterExpr<'_, '_, '_> {
         }
     }
 
-    #[allow(clippy::similar_names)]
+    #[expect(clippy::similar_names)]
     fn eq_qpath(&mut self, left: &QPath<'_>, right: &QPath<'_>) -> bool {
         match (left, right) {
             (&QPath::Resolved(ref lty, lpath), &QPath::Resolved(ref rty, rpath)) => {
@@ -407,7 +406,6 @@ impl HirEqInterExpr<'_, '_, '_> {
         left.ident.name == right.ident.name && both(&left.args, &right.args, |l, r| self.eq_path_parameters(l, r))
     }
 
-    #[allow(clippy::similar_names)]
     pub fn eq_ty(&mut self, left: &Ty<'_>, right: &Ty<'_>) -> bool {
         match (&left.kind, &right.kind) {
             (&TyKind::Slice(l_vec), &TyKind::Slice(r_vec)) => self.eq_ty(l_vec, r_vec),
@@ -562,7 +560,7 @@ impl<'a, 'tcx> SpanlessHash<'a, 'tcx> {
         std::mem::discriminant(&b.rules).hash(&mut self.s);
     }
 
-    #[allow(clippy::too_many_lines)]
+    #[expect(clippy::too_many_lines)]
     pub fn hash_expr(&mut self, e: &Expr<'_>) {
         let simple_const = self
             .maybe_typeck_results
diff --git a/src/tools/clippy/clippy_utils/src/lib.rs b/src/tools/clippy/clippy_utils/src/lib.rs
index 6db7f247a99..adb37cc9d75 100644
--- a/src/tools/clippy/clippy_utils/src/lib.rs
+++ b/src/tools/clippy/clippy_utils/src/lib.rs
@@ -2,6 +2,7 @@
 #![feature(control_flow_enum)]
 #![feature(let_else)]
 #![feature(let_chains)]
+#![feature(lint_reasons)]
 #![feature(once_cell)]
 #![feature(rustc_private)]
 #![recursion_limit = "512"]
@@ -35,7 +36,6 @@ extern crate rustc_typeck;
 #[macro_use]
 pub mod sym_helper;
 
-#[allow(clippy::module_name_repetitions)]
 pub mod ast_utils;
 pub mod attrs;
 pub mod comparisons;
@@ -67,6 +67,7 @@ use std::sync::{Mutex, MutexGuard};
 
 use if_chain::if_chain;
 use rustc_ast::ast::{self, LitKind};
+use rustc_ast::Attribute;
 use rustc_data_structures::fx::FxHashMap;
 use rustc_data_structures::unhash::UnhashMap;
 use rustc_hir as hir;
@@ -77,9 +78,9 @@ use rustc_hir::intravisit::{walk_expr, FnKind, Visitor};
 use rustc_hir::LangItem::{OptionNone, ResultErr, ResultOk};
 use rustc_hir::{
     def, Arm, ArrayLen, BindingAnnotation, Block, BlockCheckMode, Body, Constness, Destination, Expr, ExprKind, FnDecl,
-    HirId, Impl, ImplItem, ImplItemKind, IsAsync, Item, ItemKind, LangItem, Local, MatchSource,
-    Mutability, Node, Param, Pat, PatKind, Path, PathSegment, PrimTy, QPath, Stmt, StmtKind, TraitItem, TraitItemKind,
-    TraitRef, TyKind, UnOp,
+    HirId, Impl, ImplItem, ImplItemKind, IsAsync, Item, ItemKind, LangItem, Local, MatchSource, Mutability, Node,
+    Param, Pat, PatKind, Path, PathSegment, PrimTy, QPath, Stmt, StmtKind, TraitItem, TraitItemKind, TraitRef, TyKind,
+    UnOp,
 };
 use rustc_lint::{LateContext, Level, Lint, LintContext};
 use rustc_middle::hir::place::PlaceBase;
@@ -116,8 +117,8 @@ pub fn parse_msrv(msrv: &str, sess: Option<&Session>, span: Option<Span>) -> Opt
     None
 }
 
-pub fn meets_msrv(msrv: Option<&RustcVersion>, lint_msrv: &RustcVersion) -> bool {
-    msrv.map_or(true, |msrv| msrv.meets(*lint_msrv))
+pub fn meets_msrv(msrv: Option<RustcVersion>, lint_msrv: RustcVersion) -> bool {
+    msrv.map_or(true, |msrv| msrv.meets(lint_msrv))
 }
 
 #[macro_export]
@@ -1554,14 +1555,14 @@ pub fn int_bits(tcx: TyCtxt<'_>, ity: rustc_ty::IntTy) -> u64 {
     Integer::from_int_ty(&tcx, ity).size().bits()
 }
 
-#[allow(clippy::cast_possible_wrap)]
+#[expect(clippy::cast_possible_wrap)]
 /// Turn a constant int byte representation into an i128
 pub fn sext(tcx: TyCtxt<'_>, u: u128, ity: rustc_ty::IntTy) -> i128 {
     let amt = 128 - int_bits(tcx, ity);
     ((u as i128) << amt) >> amt
 }
 
-#[allow(clippy::cast_sign_loss)]
+#[expect(clippy::cast_sign_loss)]
 /// clip unused bytes
 pub fn unsext(tcx: TyCtxt<'_>, u: i128, ity: rustc_ty::IntTy) -> u128 {
     let amt = 128 - int_bits(tcx, ity);
@@ -2123,6 +2124,27 @@ pub fn is_in_test_function(tcx: TyCtxt<'_>, id: hir::HirId) -> bool {
     })
 }
 
+/// Checks if the item containing the given `HirId` has `#[cfg(test)]` attribute applied
+///
+/// Note: Add `// compile-flags: --test` to UI tests with a `#[cfg(test)]` function
+pub fn is_in_cfg_test(tcx: TyCtxt<'_>, id: hir::HirId) -> bool {
+    fn is_cfg_test(attr: &Attribute) -> bool {
+        if attr.has_name(sym::cfg)
+            && let Some(items) = attr.meta_item_list()
+            && let [item] = &*items
+            && item.has_name(sym::test)
+        {
+            true
+        } else {
+            false
+        }
+    }
+    tcx.hir()
+        .parent_iter(id)
+        .flat_map(|(parent_id, _)| tcx.hir().attrs(parent_id))
+        .any(is_cfg_test)
+}
+
 /// Checks whether item either has `test` attribute applied, or
 /// is a module with `test` in its name.
 ///
diff --git a/src/tools/clippy/clippy_utils/src/numeric_literal.rs b/src/tools/clippy/clippy_utils/src/numeric_literal.rs
index b92d42e8323..3fb5415ce02 100644
--- a/src/tools/clippy/clippy_utils/src/numeric_literal.rs
+++ b/src/tools/clippy/clippy_utils/src/numeric_literal.rs
@@ -1,7 +1,7 @@
 use rustc_ast::ast::{Lit, LitFloatType, LitIntType, LitKind};
 use std::iter;
 
-#[derive(Debug, PartialEq, Copy, Clone)]
+#[derive(Debug, PartialEq, Eq, Copy, Clone)]
 pub enum Radix {
     Binary,
     Octal,
diff --git a/src/tools/clippy/clippy_utils/src/paths.rs b/src/tools/clippy/clippy_utils/src/paths.rs
index 60971fb716d..9b9cbff2d14 100644
--- a/src/tools/clippy/clippy_utils/src/paths.rs
+++ b/src/tools/clippy/clippy_utils/src/paths.rs
@@ -43,9 +43,9 @@ pub const FROM_FROM: [&str; 4] = ["core", "convert", "From", "from"];
 pub const FROM_ITERATOR_METHOD: [&str; 6] = ["core", "iter", "traits", "collect", "FromIterator", "from_iter"];
 pub const FROM_STR_METHOD: [&str; 5] = ["core", "str", "traits", "FromStr", "from_str"];
 pub const FUTURE_FROM_GENERATOR: [&str; 3] = ["core", "future", "from_generator"];
-#[allow(clippy::invalid_paths)] // internal lints do not know about all external crates
+#[expect(clippy::invalid_paths)] // internal lints do not know about all external crates
 pub const FUTURES_IO_ASYNCREADEXT: [&str; 3] = ["futures_util", "io", "AsyncReadExt"];
-#[allow(clippy::invalid_paths)] // internal lints do not know about all external crates
+#[expect(clippy::invalid_paths)] // internal lints do not know about all external crates
 pub const FUTURES_IO_ASYNCWRITEEXT: [&str; 3] = ["futures_util", "io", "AsyncWriteExt"];
 pub const HASHMAP_CONTAINS_KEY: [&str; 6] = ["std", "collections", "hash", "map", "HashMap", "contains_key"];
 pub const HASHMAP_ENTRY: [&str; 5] = ["std", "collections", "hash", "map", "Entry"];
@@ -63,7 +63,7 @@ pub const IPADDR_V4: [&str; 5] = ["std", "net", "ip", "IpAddr", "V4"];
 pub const IPADDR_V6: [&str; 5] = ["std", "net", "ip", "IpAddr", "V6"];
 pub const ITER_COUNT: [&str; 6] = ["core", "iter", "traits", "iterator", "Iterator", "count"];
 pub const ITER_REPEAT: [&str; 5] = ["core", "iter", "sources", "repeat", "repeat"];
-#[allow(clippy::invalid_paths)] // internal lints do not know about all external crates
+#[expect(clippy::invalid_paths)] // internal lints do not know about all external crates
 pub const ITERTOOLS_NEXT_TUPLE: [&str; 3] = ["itertools", "Itertools", "next_tuple"];
 #[cfg(feature = "internal")]
 pub const KW_MODULE: [&str; 3] = ["rustc_span", "symbol", "kw"];
@@ -117,17 +117,17 @@ pub const RANGE_ARGUMENT_TRAIT: [&str; 3] = ["core", "ops", "RangeBounds"];
 pub const RC_PTR_EQ: [&str; 4] = ["alloc", "rc", "Rc", "ptr_eq"];
 pub const REFCELL_REF: [&str; 3] = ["core", "cell", "Ref"];
 pub const REFCELL_REFMUT: [&str; 3] = ["core", "cell", "RefMut"];
-#[allow(clippy::invalid_paths)] // internal lints do not know about all external crates
+#[expect(clippy::invalid_paths)] // internal lints do not know about all external crates
 pub const REGEX_BUILDER_NEW: [&str; 5] = ["regex", "re_builder", "unicode", "RegexBuilder", "new"];
-#[allow(clippy::invalid_paths)] // internal lints do not know about all external crates
+#[expect(clippy::invalid_paths)] // internal lints do not know about all external crates
 pub const REGEX_BYTES_BUILDER_NEW: [&str; 5] = ["regex", "re_builder", "bytes", "RegexBuilder", "new"];
-#[allow(clippy::invalid_paths)] // internal lints do not know about all external crates
+#[expect(clippy::invalid_paths)] // internal lints do not know about all external crates
 pub const REGEX_BYTES_NEW: [&str; 4] = ["regex", "re_bytes", "Regex", "new"];
-#[allow(clippy::invalid_paths)] // internal lints do not know about all external crates
+#[expect(clippy::invalid_paths)] // internal lints do not know about all external crates
 pub const REGEX_BYTES_SET_NEW: [&str; 5] = ["regex", "re_set", "bytes", "RegexSet", "new"];
-#[allow(clippy::invalid_paths)] // internal lints do not know about all external crates
+#[expect(clippy::invalid_paths)] // internal lints do not know about all external crates
 pub const REGEX_NEW: [&str; 4] = ["regex", "re_unicode", "Regex", "new"];
-#[allow(clippy::invalid_paths)] // internal lints do not know about all external crates
+#[expect(clippy::invalid_paths)] // internal lints do not know about all external crates
 pub const REGEX_SET_NEW: [&str; 5] = ["regex", "re_set", "unicode", "RegexSet", "new"];
 /// Preferably use the diagnostic item `sym::Result` where possible
 pub const RESULT: [&str; 3] = ["core", "result", "Result"];
@@ -169,9 +169,9 @@ pub const SYM_MODULE: [&str; 3] = ["rustc_span", "symbol", "sym"];
 pub const SYNTAX_CONTEXT: [&str; 3] = ["rustc_span", "hygiene", "SyntaxContext"];
 pub const TO_OWNED_METHOD: [&str; 4] = ["alloc", "borrow", "ToOwned", "to_owned"];
 pub const TO_STRING_METHOD: [&str; 4] = ["alloc", "string", "ToString", "to_string"];
-#[allow(clippy::invalid_paths)] // internal lints do not know about all external crates
+#[expect(clippy::invalid_paths)] // internal lints do not know about all external crates
 pub const TOKIO_IO_ASYNCREADEXT: [&str; 5] = ["tokio", "io", "util", "async_read_ext", "AsyncReadExt"];
-#[allow(clippy::invalid_paths)] // internal lints do not know about all external crates
+#[expect(clippy::invalid_paths)] // internal lints do not know about all external crates
 pub const TOKIO_IO_ASYNCWRITEEXT: [&str; 5] = ["tokio", "io", "util", "async_write_ext", "AsyncWriteExt"];
 pub const TRY_FROM: [&str; 4] = ["core", "convert", "TryFrom", "try_from"];
 pub const VEC_AS_MUT_SLICE: [&str; 4] = ["alloc", "vec", "Vec", "as_mut_slice"];
diff --git a/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs b/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs
index 66d373a1bf8..a6d7042fabc 100644
--- a/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs
+++ b/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs
@@ -18,7 +18,7 @@ use std::borrow::Cow;
 
 type McfResult = Result<(), (Span, Cow<'static, str>)>;
 
-pub fn is_min_const_fn<'a, 'tcx>(tcx: TyCtxt<'tcx>, body: &'a Body<'tcx>, msrv: Option<&RustcVersion>) -> McfResult {
+pub fn is_min_const_fn<'a, 'tcx>(tcx: TyCtxt<'tcx>, body: &'a Body<'tcx>, msrv: Option<RustcVersion>) -> McfResult {
     let def_id = body.source.def_id();
     let mut current = def_id;
     loop {
@@ -268,7 +268,7 @@ fn check_terminator<'a, 'tcx>(
     tcx: TyCtxt<'tcx>,
     body: &'a Body<'tcx>,
     terminator: &Terminator<'tcx>,
-    msrv: Option<&RustcVersion>,
+    msrv: Option<RustcVersion>,
 ) -> McfResult {
     let span = terminator.source_info.span;
     match &terminator.kind {
@@ -352,7 +352,7 @@ fn check_terminator<'a, 'tcx>(
     }
 }
 
-fn is_const_fn(tcx: TyCtxt<'_>, def_id: DefId, msrv: Option<&RustcVersion>) -> bool {
+fn is_const_fn(tcx: TyCtxt<'_>, def_id: DefId, msrv: Option<RustcVersion>) -> bool {
     tcx.is_const_fn(def_id)
         && tcx.lookup_const_stability(def_id).map_or(true, |const_stab| {
             if let rustc_attr::StabilityLevel::Stable { since } = const_stab.level {
@@ -361,7 +361,7 @@ fn is_const_fn(tcx: TyCtxt<'_>, def_id: DefId, msrv: Option<&RustcVersion>) -> b
                 // as a part of an unimplemented MSRV check https://github.com/rust-lang/rust/issues/65262.
                 crate::meets_msrv(
                     msrv,
-                    &RustcVersion::parse(since.as_str())
+                    RustcVersion::parse(since.as_str())
                         .expect("`rustc_attr::StabilityLevel::Stable::since` is ill-formatted"),
                 )
             } else {
diff --git a/src/tools/clippy/clippy_utils/src/source.rs b/src/tools/clippy/clippy_utils/src/source.rs
index c69a3d8d2a1..04ef2f57447 100644
--- a/src/tools/clippy/clippy_utils/src/source.rs
+++ b/src/tools/clippy/clippy_utils/src/source.rs
@@ -137,7 +137,7 @@ pub fn position_before_rarrow(s: &str) -> Option<usize> {
 }
 
 /// Reindent a multiline string with possibility of ignoring the first line.
-#[allow(clippy::needless_pass_by_value)]
+#[expect(clippy::needless_pass_by_value)]
 pub fn reindent_multiline(s: Cow<'_, str>, ignore_first: bool, indent: Option<usize>) -> Cow<'_, str> {
     let s_space = reindent_multiline_inner(&s, ignore_first, indent, ' ');
     let s_tab = reindent_multiline_inner(&s_space, ignore_first, indent, '\t');
diff --git a/src/tools/clippy/clippy_utils/src/sugg.rs b/src/tools/clippy/clippy_utils/src/sugg.rs
index db5299c2c05..4f3757f1ec6 100644
--- a/src/tools/clippy/clippy_utils/src/sugg.rs
+++ b/src/tools/clippy/clippy_utils/src/sugg.rs
@@ -17,7 +17,6 @@ use rustc_middle::ty;
 use rustc_span::source_map::{BytePos, CharPos, Pos, Span, SyntaxContext};
 use rustc_typeck::expr_use_visitor::{Delegate, ExprUseVisitor, PlaceBase, PlaceWithHirId};
 use std::borrow::Cow;
-use std::convert::TryInto;
 use std::fmt::{Display, Write as _};
 use std::iter;
 use std::ops::{Add, Neg, Not, Sub};
@@ -50,7 +49,7 @@ impl Display for Sugg<'_> {
     }
 }
 
-#[allow(clippy::wrong_self_convention)] // ok, because of the function `as_ty` method
+#[expect(clippy::wrong_self_convention)] // ok, because of the function `as_ty` method
 impl<'a> Sugg<'a> {
     /// Prepare a suggestion from an expression.
     pub fn hir_opt(cx: &LateContext<'_>, expr: &hir::Expr<'_>) -> Option<Self> {
@@ -318,7 +317,6 @@ impl<'a> Sugg<'a> {
 
     /// Convenience method to create the `<lhs>..<rhs>` or `<lhs>...<rhs>`
     /// suggestion.
-    #[allow(dead_code)]
     pub fn range(self, end: &Self, limit: ast::RangeLimits) -> Sugg<'static> {
         match limit {
             ast::RangeLimits::HalfOpen => make_assoc(AssocOp::DotDot, &self, end),
@@ -886,7 +884,6 @@ impl<'tcx> DerefDelegate<'_, 'tcx> {
 impl<'tcx> Delegate<'tcx> for DerefDelegate<'_, 'tcx> {
     fn consume(&mut self, _: &PlaceWithHirId<'tcx>, _: HirId) {}
 
-    #[allow(clippy::too_many_lines)]
     fn borrow(&mut self, cmt: &PlaceWithHirId<'tcx>, _: HirId, _: ty::BorrowKind) {
         if let PlaceBase::Local(id) = cmt.place.base {
             let map = self.cx.tcx.hir();
diff --git a/src/tools/clippy/clippy_utils/src/ty.rs b/src/tools/clippy/clippy_utils/src/ty.rs
index b09eb8c6cd1..07d3d280763 100644
--- a/src/tools/clippy/clippy_utils/src/ty.rs
+++ b/src/tools/clippy/clippy_utils/src/ty.rs
@@ -603,7 +603,7 @@ impl core::ops::Add<u32> for EnumValue {
 }
 
 /// Attempts to read the given constant as though it were an an enum value.
-#[allow(clippy::cast_possible_truncation, clippy::cast_possible_wrap)]
+#[expect(clippy::cast_possible_truncation, clippy::cast_possible_wrap)]
 pub fn read_explicit_enum_value(tcx: TyCtxt<'_>, id: DefId) -> Option<EnumValue> {
     if let Ok(ConstValue::Scalar(Scalar::Int(value))) = tcx.const_eval_poly(id) {
         match tcx.type_of(id).kind() {
diff --git a/src/tools/clippy/clippy_utils/src/usage.rs b/src/tools/clippy/clippy_utils/src/usage.rs
index b7b9d54d0b2..9819778540c 100644
--- a/src/tools/clippy/clippy_utils/src/usage.rs
+++ b/src/tools/clippy/clippy_utils/src/usage.rs
@@ -44,7 +44,6 @@ struct MutVarsDelegate {
 }
 
 impl<'tcx> MutVarsDelegate {
-    #[allow(clippy::similar_names)]
     fn update(&mut self, cat: &PlaceWithHirId<'tcx>) {
         match cat.place.base {
             PlaceBase::Local(id) => {
diff --git a/src/tools/clippy/clippy_utils/src/visitors.rs b/src/tools/clippy/clippy_utils/src/visitors.rs
index c00bc2bd213..b6c8f1d516e 100644
--- a/src/tools/clippy/clippy_utils/src/visitors.rs
+++ b/src/tools/clippy/clippy_utils/src/visitors.rs
@@ -1,4 +1,4 @@
-use crate::path_to_local_id;
+use crate::{get_enclosing_block, path_to_local_id};
 use core::ops::ControlFlow;
 use rustc_hir as hir;
 use rustc_hir::def::{DefKind, Res};
@@ -436,3 +436,61 @@ pub fn for_each_value_source<'tcx, B>(
         _ => f(e),
     }
 }
+
+/// Runs the given function for each path expression referencing the given local which occur after
+/// the given expression.
+pub fn for_each_local_use_after_expr<'tcx, B>(
+    cx: &LateContext<'tcx>,
+    local_id: HirId,
+    expr_id: HirId,
+    f: impl FnMut(&'tcx Expr<'tcx>) -> ControlFlow<B>,
+) -> ControlFlow<B> {
+    struct V<'cx, 'tcx, F, B> {
+        cx: &'cx LateContext<'tcx>,
+        local_id: HirId,
+        expr_id: HirId,
+        found: bool,
+        res: ControlFlow<B>,
+        f: F,
+    }
+    impl<'cx, 'tcx, F: FnMut(&'tcx Expr<'tcx>) -> ControlFlow<B>, B> Visitor<'tcx> for V<'cx, 'tcx, F, B> {
+        type NestedFilter = nested_filter::OnlyBodies;
+        fn nested_visit_map(&mut self) -> Self::Map {
+            self.cx.tcx.hir()
+        }
+
+        fn visit_expr(&mut self, e: &'tcx Expr<'tcx>) {
+            if !self.found {
+                if e.hir_id == self.expr_id {
+                    self.found = true;
+                } else {
+                    walk_expr(self, e);
+                }
+                return;
+            }
+            if self.res.is_break() {
+                return;
+            }
+            if path_to_local_id(e, self.local_id) {
+                self.res = (self.f)(e);
+            } else {
+                walk_expr(self, e);
+            }
+        }
+    }
+
+    if let Some(b) = get_enclosing_block(cx, local_id) {
+        let mut v = V {
+            cx,
+            local_id,
+            expr_id,
+            found: false,
+            res: ControlFlow::Continue(()),
+            f,
+        };
+        v.visit_block(b);
+        v.res
+    } else {
+        ControlFlow::Continue(())
+    }
+}
diff --git a/src/tools/clippy/doc/adding_lints.md b/src/tools/clippy/doc/adding_lints.md
index 307cf2f3a90..e8f0c338fd5 100644
--- a/src/tools/clippy/doc/adding_lints.md
+++ b/src/tools/clippy/doc/adding_lints.md
@@ -28,7 +28,7 @@ because that's clearly a non-descriptive name.
   - [Debugging](#debugging)
   - [PR Checklist](#pr-checklist)
   - [Adding configuration to a lint](#adding-configuration-to-a-lint)
-  - [Cheatsheet](#cheatsheet)
+  - [Cheat Sheet](#cheat-sheet)
 
 ## Setup
 
@@ -432,7 +432,7 @@ The project's MSRV can then be matched against the feature MSRV in the LintPass
 using the `meets_msrv` utility function.
 
 ``` rust
-if !meets_msrv(self.msrv.as_ref(), &msrvs::STR_STRIP_PREFIX) {
+if !meets_msrv(self.msrv, msrvs::STR_STRIP_PREFIX) {
     return;
 }
 ```
@@ -649,14 +649,14 @@ in the following steps:
         with the configuration value and a rust file that should be linted by Clippy. The test can
         otherwise be written as usual.
 
-## Cheatsheet
+## Cheat Sheet
 
 Here are some pointers to things you are likely going to need for every lint:
 
 * [Clippy utils][utils] - Various helper functions. Maybe the function you need
   is already in here ([`is_type_diagnostic_item`], [`implements_trait`], [`snippet`], etc)
 * [Clippy diagnostics][diagnostics]
-* [The `if_chain` macro][if_chain]
+* [Let chains][let-chains]
 * [`from_expansion`][from_expansion] and [`in_external_macro`][in_external_macro]
 * [`Span`][span]
 * [`Applicability`][applicability]
@@ -684,7 +684,7 @@ don't hesitate to ask on [Zulip] or in the issue/PR.
 [`is_type_diagnostic_item`]: https://doc.rust-lang.org/nightly/nightly-rustc/clippy_utils/ty/fn.is_type_diagnostic_item.html
 [`implements_trait`]: https://doc.rust-lang.org/nightly/nightly-rustc/clippy_utils/ty/fn.implements_trait.html
 [`snippet`]: https://doc.rust-lang.org/nightly/nightly-rustc/clippy_utils/source/fn.snippet.html
-[if_chain]: https://docs.rs/if_chain/*/if_chain/
+[let-chains]: https://github.com/rust-lang/rust/pull/94927
 [from_expansion]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_span/struct.Span.html#method.from_expansion
 [in_external_macro]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/lint/fn.in_external_macro.html
 [span]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_span/struct.Span.html
diff --git a/src/tools/clippy/doc/common_tools_writing_lints.md b/src/tools/clippy/doc/common_tools_writing_lints.md
index 828bf4cbef9..131ac3c3611 100644
--- a/src/tools/clippy/doc/common_tools_writing_lints.md
+++ b/src/tools/clippy/doc/common_tools_writing_lints.md
@@ -62,16 +62,14 @@ Starting with an `expr`, you can check whether it is calling a specific method `
 ```rust
 impl<'tcx> LateLintPass<'tcx> for MyStructLint {
     fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>) {
-        if_chain! {
-            // Check our expr is calling a method
-            if let hir::ExprKind::MethodCall(path, _, [_self_arg, ..]) = &expr.kind;
+        // Check our expr is calling a method
+        if let hir::ExprKind::MethodCall(path, _, [_self_arg, ..]) = &expr.kind
             // Check the name of this method is `some_method`
-            if path.ident.name == sym!(some_method);
+            && path.ident.name == sym!(some_method)
             // Optionally, check the type of the self argument.
             // - See "Checking for a specific type"
-            then {
+        {
                 // ...
-            }
         }
     }
 }
@@ -165,18 +163,16 @@ use clippy_utils::{is_type_diagnostic_item, return_ty};
 
 impl<'tcx> LateLintPass<'tcx> for MyTypeImpl {
     fn check_impl_item(&mut self, cx: &LateContext<'tcx>, impl_item: &'tcx ImplItem<'_>) {
-        if_chain! {
-            // Check if item is a method/function
-            if let ImplItemKind::Fn(ref signature, _) = impl_item.kind;
+        // Check if item is a method/function
+        if let ImplItemKind::Fn(ref signature, _) = impl_item.kind
             // Check the method is named `some_method`
-            if impl_item.ident.name == sym!(some_method);
+            && impl_item.ident.name == sym!(some_method)
             // We can also check it has a parameter `self`
-            if signature.decl.implicit_self.has_implicit_self();
+            && signature.decl.implicit_self.has_implicit_self()
             // We can go further and even check if its return type is `String`
-            if is_type_diagnostic_item(cx, return_ty(cx, impl_item.hir_id), sym!(string_type));
-            then {
-                // ...
-            }
+            && is_type_diagnostic_item(cx, return_ty(cx, impl_item.hir_id), sym!(string_type))
+        {
+            // ...
         }
     }
 }
diff --git a/src/tools/clippy/lintcheck/Cargo.toml b/src/tools/clippy/lintcheck/Cargo.toml
index c694037021a..e63f65ce2f7 100644
--- a/src/tools/clippy/lintcheck/Cargo.toml
+++ b/src/tools/clippy/lintcheck/Cargo.toml
@@ -6,16 +6,15 @@ readme = "README.md"
 license = "MIT OR Apache-2.0"
 repository = "https://github.com/rust-lang/rust-clippy"
 categories = ["development-tools"]
-edition = "2018"
+edition = "2021"
 publish = false
 
 [dependencies]
+cargo_metadata = "0.14"
 clap = "2.33"
 flate2 = "1.0"
-fs_extra = "1.2"
 rayon = "1.5.1"
 serde = { version = "1.0", features = ["derive"] }
-serde_json = "1.0"
 tar = "0.4"
 toml = "0.5"
 ureq = "2.2"
diff --git a/src/tools/clippy/lintcheck/lintcheck_crates.toml b/src/tools/clippy/lintcheck/lintcheck_crates.toml
index dfee28f1a87..4fbae8614ca 100644
--- a/src/tools/clippy/lintcheck/lintcheck_crates.toml
+++ b/src/tools/clippy/lintcheck/lintcheck_crates.toml
@@ -24,7 +24,7 @@ unicode-xid = {name = "unicode-xid", versions = ['0.2.1']}
 anyhow = {name = "anyhow", versions = ['1.0.38']}
 async-trait = {name = "async-trait", versions = ['0.1.42']}
 cxx = {name = "cxx", versions = ['1.0.32']}
-ryu = {name = "ryu", version = ['1.0.5']}
+ryu = {name = "ryu", versions = ['1.0.5']}
 serde_yaml = {name = "serde_yaml", versions = ['0.8.17']}
 thiserror = {name = "thiserror", versions = ['1.0.24']}
 # some embark crates, there are other interesting crates but
diff --git a/src/tools/clippy/lintcheck/src/config.rs b/src/tools/clippy/lintcheck/src/config.rs
new file mode 100644
index 00000000000..de32b484360
--- /dev/null
+++ b/src/tools/clippy/lintcheck/src/config.rs
@@ -0,0 +1,140 @@
+use clap::{App, Arg, ArgMatches};
+use std::env;
+use std::path::PathBuf;
+
+fn get_clap_config<'a>() -> ArgMatches<'a> {
+    App::new("lintcheck")
+        .about("run clippy on a set of crates and check output")
+        .arg(
+            Arg::with_name("only")
+                .takes_value(true)
+                .value_name("CRATE")
+                .long("only")
+                .help("Only process a single crate of the list"),
+        )
+        .arg(
+            Arg::with_name("crates-toml")
+                .takes_value(true)
+                .value_name("CRATES-SOURCES-TOML-PATH")
+                .long("crates-toml")
+                .help("Set the path for a crates.toml where lintcheck should read the sources from"),
+        )
+        .arg(
+            Arg::with_name("threads")
+                .takes_value(true)
+                .value_name("N")
+                .short("j")
+                .long("jobs")
+                .help("Number of threads to use, 0 automatic choice"),
+        )
+        .arg(
+            Arg::with_name("fix")
+                .long("--fix")
+                .help("Runs cargo clippy --fix and checks if all suggestions apply"),
+        )
+        .arg(
+            Arg::with_name("filter")
+                .long("--filter")
+                .takes_value(true)
+                .multiple(true)
+                .value_name("clippy_lint_name")
+                .help("Apply a filter to only collect specified lints, this also overrides `allow` attributes"),
+        )
+        .arg(
+            Arg::with_name("markdown")
+                .long("--markdown")
+                .help("Change the reports table to use markdown links"),
+        )
+        .get_matches()
+}
+
+#[derive(Debug)]
+pub(crate) struct LintcheckConfig {
+    /// max number of jobs to spawn (default 1)
+    pub max_jobs: usize,
+    /// we read the sources to check from here
+    pub sources_toml_path: PathBuf,
+    /// we save the clippy lint results here
+    pub lintcheck_results_path: PathBuf,
+    /// Check only a specified package
+    pub only: Option<String>,
+    /// whether to just run --fix and not collect all the warnings
+    pub fix: bool,
+    /// A list of lints that this lintcheck run should focus on
+    pub lint_filter: Vec<String>,
+    /// Indicate if the output should support markdown syntax
+    pub markdown: bool,
+}
+
+impl LintcheckConfig {
+    pub fn new() -> Self {
+        let clap_config = get_clap_config();
+
+        // first, check if we got anything passed via the LINTCHECK_TOML env var,
+        // if not, ask clap if we got any value for --crates-toml  <foo>
+        // if not, use the default "lintcheck/lintcheck_crates.toml"
+        let sources_toml = env::var("LINTCHECK_TOML").unwrap_or_else(|_| {
+            clap_config
+                .value_of("crates-toml")
+                .clone()
+                .unwrap_or("lintcheck/lintcheck_crates.toml")
+                .to_string()
+        });
+
+        let markdown = clap_config.is_present("markdown");
+        let sources_toml_path = PathBuf::from(sources_toml);
+
+        // for the path where we save the lint results, get the filename without extension (so for
+        // wasd.toml, use "wasd"...)
+        let filename: PathBuf = sources_toml_path.file_stem().unwrap().into();
+        let lintcheck_results_path = PathBuf::from(format!(
+            "lintcheck-logs/{}_logs.{}",
+            filename.display(),
+            if markdown { "md" } else { "txt" }
+        ));
+
+        // look at the --threads arg, if 0 is passed, ask rayon rayon how many threads it would spawn and
+        // use half of that for the physical core count
+        // by default use a single thread
+        let max_jobs = match clap_config.value_of("threads") {
+            Some(threads) => {
+                let threads: usize = threads
+                    .parse()
+                    .unwrap_or_else(|_| panic!("Failed to parse '{}' to a digit", threads));
+                if threads == 0 {
+                    // automatic choice
+                    // Rayon seems to return thread count so half that for core count
+                    (rayon::current_num_threads() / 2) as usize
+                } else {
+                    threads
+                }
+            },
+            // no -j passed, use a single thread
+            None => 1,
+        };
+
+        let lint_filter: Vec<String> = clap_config
+            .values_of("filter")
+            .map(|iter| {
+                iter.map(|lint_name| {
+                    let mut filter = lint_name.replace('_', "-");
+                    if !filter.starts_with("clippy::") {
+                        filter.insert_str(0, "clippy::");
+                    }
+                    filter
+                })
+                .collect()
+            })
+            .unwrap_or_default();
+
+        LintcheckConfig {
+            max_jobs,
+            sources_toml_path,
+            lintcheck_results_path,
+            only: clap_config.value_of("only").map(String::from),
+            fix: clap_config.is_present("fix"),
+            lint_filter,
+            markdown,
+        }
+    }
+}
diff --git a/src/tools/clippy/lintcheck/src/main.rs b/src/tools/clippy/lintcheck/src/main.rs
index 816efbdaedf..dff9d27db0a 100644
--- a/src/tools/clippy/lintcheck/src/main.rs
+++ b/src/tools/clippy/lintcheck/src/main.rs
@@ -7,23 +7,25 @@
 
 #![allow(clippy::collapsible_else_if)]
 
-use std::ffi::OsStr;
+mod config;
+
+use config::LintcheckConfig;
+
+use std::collections::HashMap;
+use std::env;
 use std::fmt::Write as _;
+use std::fs::write;
+use std::io::ErrorKind;
+use std::path::{Path, PathBuf};
 use std::process::Command;
 use std::sync::atomic::{AtomicUsize, Ordering};
-use std::{collections::HashMap, io::ErrorKind};
-use std::{
-    env,
-    fs::write,
-    path::{Path, PathBuf},
-    thread,
-    time::Duration,
-};
+use std::thread;
+use std::time::Duration;
 
-use clap::{App, Arg, ArgMatches};
+use cargo_metadata::diagnostic::DiagnosticLevel;
+use cargo_metadata::Message;
 use rayon::prelude::*;
 use serde::{Deserialize, Serialize};
-use serde_json::Value;
 use walkdir::{DirEntry, WalkDir};
 
 #[cfg(not(windows))]
@@ -93,37 +95,67 @@ struct Crate {
 #[derive(Debug)]
 struct ClippyWarning {
     crate_name: String,
-    crate_version: String,
     file: String,
-    line: String,
-    column: String,
-    linttype: String,
+    line: usize,
+    column: usize,
+    lint_type: String,
     message: String,
     is_ice: bool,
 }
 
 #[allow(unused)]
 impl ClippyWarning {
+    fn new(cargo_message: Message, krate: &Crate) -> Option<Self> {
+        let diag = match cargo_message {
+            Message::CompilerMessage(message) => message.message,
+            _ => return None,
+        };
+
+        let lint_type = diag.code?.code;
+        if !(lint_type.contains("clippy") || diag.message.contains("clippy"))
+            || diag.message.contains("could not read cargo metadata")
+        {
+            return None;
+        }
+
+        let span = diag.spans.into_iter().find(|span| span.is_primary)?;
+
+        let file = match Path::new(&span.file_name).strip_prefix(env!("CARGO_HOME")) {
+            Ok(stripped) => format!("$CARGO_HOME/{}", stripped.display()),
+            Err(_) => format!(
+                "target/lintcheck/sources/{}-{}/{}",
+                krate.name, krate.version, span.file_name
+            ),
+        };
+
+        Some(Self {
+            crate_name: krate.name.clone(),
+            file,
+            line: span.line_start,
+            column: span.column_start,
+            lint_type,
+            message: diag.message,
+            is_ice: diag.level == DiagnosticLevel::Ice,
+        })
+    }
+
     fn to_output(&self, markdown: bool) -> String {
-        let file = format!("{}-{}/{}", &self.crate_name, &self.crate_version, &self.file);
-        let file_with_pos = format!("{}:{}:{}", &file, &self.line, &self.column);
+        let file_with_pos = format!("{}:{}:{}", &self.file, &self.line, &self.column);
         if markdown {
-            let lint = format!("`{}`", self.linttype);
+            let lint = format!("`{}`", self.lint_type);
+
+            let mut file = self.file.clone();
+            if !file.starts_with('$') {
+                file.insert_str(0, "../");
+            }
 
             let mut output = String::from("| ");
-            let _ = write!(
-                output,
-                "[`{}`](../target/lintcheck/sources/{}#L{})",
-                file_with_pos, file, self.line
-            );
+            let _ = write!(output, "[`{}`]({}#L{})", file_with_pos, file, self.line);
             let _ = write!(output, r#" | {:<50} | "{}" |"#, lint, self.message);
             output.push('\n');
             output
         } else {
-            format!(
-                "target/lintcheck/sources/{} {} \"{}\"\n",
-                file_with_pos, self.linttype, self.message
-            )
+            format!("{} {} \"{}\"\n", file_with_pos, self.lint_type, self.message)
         }
     }
 }
@@ -278,18 +310,17 @@ impl Crate {
         &self,
         cargo_clippy_path: &Path,
         target_dir_index: &AtomicUsize,
-        thread_limit: usize,
         total_crates_to_lint: usize,
-        fix: bool,
+        config: &LintcheckConfig,
         lint_filter: &Vec<String>,
     ) -> Vec<ClippyWarning> {
         // advance the atomic index by one
         let index = target_dir_index.fetch_add(1, Ordering::SeqCst);
         // "loop" the index within 0..thread_limit
-        let thread_index = index % thread_limit;
+        let thread_index = index % config.max_jobs;
         let perc = (index * 100) / total_crates_to_lint;
 
-        if thread_limit == 1 {
+        if config.max_jobs == 1 {
             println!(
                 "{}/{} {}% Linting {} {}",
                 index, total_crates_to_lint, perc, &self.name, &self.version
@@ -305,7 +336,7 @@ impl Crate {
 
         let shared_target_dir = clippy_project_root().join("target/lintcheck/shared_target_dir");
 
-        let mut args = if fix {
+        let mut args = if config.fix {
             vec!["--fix", "--"]
         } else {
             vec!["--", "--message-format=json", "--"]
@@ -356,7 +387,7 @@ impl Crate {
             );
         }
 
-        if fix {
+        if config.fix {
             if let Some(stderr) = stderr
                 .lines()
                 .find(|line| line.contains("failed to automatically apply fixes suggested by rustc to crate"))
@@ -371,127 +402,15 @@ impl Crate {
             return Vec::new();
         }
 
-        let output_lines = stdout.lines();
-        let warnings: Vec<ClippyWarning> = output_lines
-            .into_iter()
-            // get all clippy warnings and ICEs
-            .filter(|line| filter_clippy_warnings(&line))
-            .map(|json_msg| parse_json_message(json_msg, &self))
+        // get all clippy warnings and ICEs
+        let warnings: Vec<ClippyWarning> = Message::parse_stream(stdout.as_bytes())
+            .filter_map(|msg| ClippyWarning::new(msg.unwrap(), &self))
             .collect();
 
         warnings
     }
 }
 
-#[derive(Debug)]
-struct LintcheckConfig {
-    /// max number of jobs to spawn (default 1)
-    max_jobs: usize,
-    /// we read the sources to check from here
-    sources_toml_path: PathBuf,
-    /// we save the clippy lint results here
-    lintcheck_results_path: PathBuf,
-    /// whether to just run --fix and not collect all the warnings
-    fix: bool,
-    /// A list of lints that this lintcheck run should focus on
-    lint_filter: Vec<String>,
-    /// Indicate if the output should support markdown syntax
-    markdown: bool,
-}
-
-impl LintcheckConfig {
-    fn from_clap(clap_config: &ArgMatches) -> Self {
-        // first, check if we got anything passed via the LINTCHECK_TOML env var,
-        // if not, ask clap if we got any value for --crates-toml  <foo>
-        // if not, use the default "lintcheck/lintcheck_crates.toml"
-        let sources_toml = env::var("LINTCHECK_TOML").unwrap_or_else(|_| {
-            clap_config
-                .value_of("crates-toml")
-                .clone()
-                .unwrap_or("lintcheck/lintcheck_crates.toml")
-                .to_string()
-        });
-
-        let markdown = clap_config.is_present("markdown");
-        let sources_toml_path = PathBuf::from(sources_toml);
-
-        // for the path where we save the lint results, get the filename without extension (so for
-        // wasd.toml, use "wasd"...)
-        let filename: PathBuf = sources_toml_path.file_stem().unwrap().into();
-        let lintcheck_results_path = PathBuf::from(format!(
-            "lintcheck-logs/{}_logs.{}",
-            filename.display(),
-            if markdown { "md" } else { "txt" }
-        ));
-
-        // look at the --threads arg, if 0 is passed, ask rayon rayon how many threads it would spawn and
-        // use half of that for the physical core count
-        // by default use a single thread
-        let max_jobs = match clap_config.value_of("threads") {
-            Some(threads) => {
-                let threads: usize = threads
-                    .parse()
-                    .unwrap_or_else(|_| panic!("Failed to parse '{}' to a digit", threads));
-                if threads == 0 {
-                    // automatic choice
-                    // Rayon seems to return thread count so half that for core count
-                    (rayon::current_num_threads() / 2) as usize
-                } else {
-                    threads
-                }
-            },
-            // no -j passed, use a single thread
-            None => 1,
-        };
-        let fix: bool = clap_config.is_present("fix");
-        let lint_filter: Vec<String> = clap_config
-            .values_of("filter")
-            .map(|iter| {
-                iter.map(|lint_name| {
-                    let mut filter = lint_name.replace('_', "-");
-                    if !filter.starts_with("clippy::") {
-                        filter.insert_str(0, "clippy::");
-                    }
-                    filter
-                })
-                .collect()
-            })
-            .unwrap_or_default();
-
-        LintcheckConfig {
-            max_jobs,
-            sources_toml_path,
-            lintcheck_results_path,
-            fix,
-            lint_filter,
-            markdown,
-        }
-    }
-}
-
-/// takes a single json-formatted clippy warnings and returns true (we are interested in that line)
-/// or false (we aren't)
-fn filter_clippy_warnings(line: &str) -> bool {
-    // we want to collect ICEs because clippy might have crashed.
-    // these are summarized later
-    if line.contains("internal compiler error: ") {
-        return true;
-    }
-    // in general, we want all clippy warnings
-    // however due to some kind of bug, sometimes there are absolute paths
-    // to libcore files inside the message
-    // or we end up with cargo-metadata output (https://github.com/rust-lang/rust-clippy/issues/6508)
-
-    // filter out these message to avoid unnecessary noise in the logs
-    if line.contains("clippy::")
-        && !(line.contains("could not read cargo metadata")
-            || (line.contains(".rustup") && line.contains("toolchains")))
-    {
-        return true;
-    }
-    false
-}
-
 /// Builds clippy inside the repo to make sure we have a clippy executable we can use.
 fn build_clippy() {
     let status = Command::new("cargo")
@@ -527,10 +446,8 @@ fn read_crates(toml_path: &Path) -> Vec<CrateSource> {
                 path: PathBuf::from(path),
                 options: tk.options.clone(),
             });
-        }
-
-        // if we have multiple versions, save each one
-        if let Some(ref versions) = tk.versions {
+        } else if let Some(ref versions) = tk.versions {
+            // if we have multiple versions, save each one
             versions.iter().for_each(|ver| {
                 crate_sources.push(CrateSource::CratesIo {
                     name: tk.name.clone(),
@@ -538,16 +455,18 @@ fn read_crates(toml_path: &Path) -> Vec<CrateSource> {
                     options: tk.options.clone(),
                 });
             })
-        }
-        // otherwise, we should have a git source
-        if tk.git_url.is_some() && tk.git_hash.is_some() {
+        } else if tk.git_url.is_some() && tk.git_hash.is_some() {
+            // otherwise, we should have a git source
             crate_sources.push(CrateSource::Git {
                 name: tk.name.clone(),
                 url: tk.git_url.clone().unwrap(),
                 commit: tk.git_hash.clone().unwrap(),
                 options: tk.options.clone(),
             });
+        } else {
+            panic!("Invalid crate source: {tk:?}");
         }
+
         // if we have a version as well as a git data OR only one git data, something is funky
         if tk.versions.is_some() && (tk.git_url.is_some() || tk.git_hash.is_some())
             || tk.git_hash.is_some() != tk.git_url.is_some()
@@ -568,57 +487,13 @@ fn read_crates(toml_path: &Path) -> Vec<CrateSource> {
     crate_sources
 }
 
-/// Parse the json output of clippy and return a `ClippyWarning`
-fn parse_json_message(json_message: &str, krate: &Crate) -> ClippyWarning {
-    let jmsg: Value = serde_json::from_str(&json_message).unwrap_or_else(|e| panic!("Failed to parse json:\n{:?}", e));
-
-    let file: String = jmsg["message"]["spans"][0]["file_name"]
-        .to_string()
-        .trim_matches('"')
-        .into();
-
-    let file = if file.contains(".cargo") {
-        // if we deal with macros, a filename may show the origin of a macro which can be inside a dep from
-        // the registry.
-        // don't show the full path in that case.
-
-        // /home/matthias/.cargo/registry/src/github.com-1ecc6299db9ec823/syn-1.0.63/src/custom_keyword.rs
-        let path = PathBuf::from(file);
-        let mut piter = path.iter();
-        // consume all elements until we find ".cargo", so that "/home/matthias" is skipped
-        let _: Option<&OsStr> = piter.find(|x| x == &std::ffi::OsString::from(".cargo"));
-        // collect the remaining segments
-        let file = piter.collect::<PathBuf>();
-        format!("{}", file.display())
-    } else {
-        file
-    };
-
-    ClippyWarning {
-        crate_name: krate.name.to_string(),
-        crate_version: krate.version.to_string(),
-        file,
-        line: jmsg["message"]["spans"][0]["line_start"]
-            .to_string()
-            .trim_matches('"')
-            .into(),
-        column: jmsg["message"]["spans"][0]["text"][0]["highlight_start"]
-            .to_string()
-            .trim_matches('"')
-            .into(),
-        linttype: jmsg["message"]["code"]["code"].to_string().trim_matches('"').into(),
-        message: jmsg["message"]["message"].to_string().trim_matches('"').into(),
-        is_ice: json_message.contains("internal compiler error: "),
-    }
-}
-
 /// Generate a short list of occurring lints-types and their count
 fn gather_stats(clippy_warnings: &[ClippyWarning]) -> (String, HashMap<&String, usize>) {
     // count lint type occurrences
     let mut counter: HashMap<&String, usize> = HashMap::new();
     clippy_warnings
         .iter()
-        .for_each(|wrn| *counter.entry(&wrn.linttype).or_insert(0) += 1);
+        .for_each(|wrn| *counter.entry(&wrn.lint_type).or_insert(0) += 1);
 
     // collect into a tupled list for sorting
     let mut stats: Vec<(&&String, &usize)> = counter.iter().map(|(lint, count)| (lint, count)).collect();
@@ -667,22 +542,14 @@ fn lintcheck_needs_rerun(lintcheck_logs_path: &Path) -> bool {
     logs_modified < clippy_modified
 }
 
-/// lintchecks `main()` function
-///
-/// # Panics
-///
-/// This function panics if the clippy binaries don't exist
-/// or if lintcheck is executed from the wrong directory (aka none-repo-root)
-pub fn main() {
+fn main() {
     // assert that we launch lintcheck from the repo root (via cargo lintcheck)
     if std::fs::metadata("lintcheck/Cargo.toml").is_err() {
         eprintln!("lintcheck needs to be run from clippys repo root!\nUse `cargo lintcheck` alternatively.");
         std::process::exit(3);
     }
 
-    let clap_config = &get_clap_config();
-
-    let config = LintcheckConfig::from_clap(clap_config);
+    let config = LintcheckConfig::new();
 
     println!("Compiling clippy...");
     build_clippy();
@@ -736,76 +603,46 @@ pub fn main() {
         })
         .collect();
 
-    let clippy_warnings: Vec<ClippyWarning> = if let Some(only_one_crate) = clap_config.value_of("only") {
-        // if we don't have the specified crate in the .toml, throw an error
-        if !crates.iter().any(|krate| {
-            let name = match krate {
-                CrateSource::CratesIo { name, .. } | CrateSource::Git { name, .. } | CrateSource::Path { name, .. } => {
-                    name
-                },
-            };
-            name == only_one_crate
-        }) {
-            eprintln!(
-                "ERROR: could not find crate '{}' in lintcheck/lintcheck_crates.toml",
-                only_one_crate
-            );
-            std::process::exit(1);
-        }
+    let crates: Vec<Crate> = crates
+        .into_iter()
+        .filter(|krate| {
+            if let Some(only_one_crate) = &config.only {
+                let name = match krate {
+                    CrateSource::CratesIo { name, .. }
+                    | CrateSource::Git { name, .. }
+                    | CrateSource::Path { name, .. } => name,
+                };
 
-        // only check a single crate that was passed via cmdline
-        crates
-            .into_iter()
-            .map(|krate| krate.download_and_extract())
-            .filter(|krate| krate.name == only_one_crate)
-            .flat_map(|krate| {
-                krate.run_clippy_lints(&cargo_clippy_path, &AtomicUsize::new(0), 1, 1, config.fix, &lint_filter)
-            })
-            .collect()
-    } else {
-        if config.max_jobs > 1 {
-            // run parallel with rayon
+                name == only_one_crate
+            } else {
+                true
+            }
+        })
+        .map(|krate| krate.download_and_extract())
+        .collect();
 
-            // Ask rayon for thread count. Assume that half of that is the number of physical cores
-            // Use one target dir for each core so that we can run N clippys in parallel.
-            // We need to use different target dirs because cargo would lock them for a single build otherwise,
-            // killing the parallelism. However this also means that deps will only be reused half/a
-            // quarter of the time which might result in a longer wall clock runtime
+    if crates.is_empty() {
+        eprintln!(
+            "ERROR: could not find crate '{}' in lintcheck/lintcheck_crates.toml",
+            config.only.unwrap(),
+        );
+        std::process::exit(1);
+    }
 
-            // This helps when we check many small crates with dep-trees that don't have a lot of branches in
-            // order to achieve some kind of parallelism
+    // run parallel with rayon
 
-            // by default, use a single thread
-            let num_cpus = config.max_jobs;
-            let num_crates = crates.len();
+    // This helps when we check many small crates with dep-trees that don't have a lot of branches in
+    // order to achieve some kind of parallelism
 
-            // check all crates (default)
-            crates
-                .into_par_iter()
-                .map(|krate| krate.download_and_extract())
-                .flat_map(|krate| {
-                    krate.run_clippy_lints(
-                        &cargo_clippy_path,
-                        &counter,
-                        num_cpus,
-                        num_crates,
-                        config.fix,
-                        &lint_filter,
-                    )
-                })
-                .collect()
-        } else {
-            // run sequential
-            let num_crates = crates.len();
-            crates
-                .into_iter()
-                .map(|krate| krate.download_and_extract())
-                .flat_map(|krate| {
-                    krate.run_clippy_lints(&cargo_clippy_path, &counter, 1, num_crates, config.fix, &lint_filter)
-                })
-                .collect()
-        }
-    };
+    rayon::ThreadPoolBuilder::new()
+        .num_threads(config.max_jobs)
+        .build_global()
+        .unwrap();
+
+    let clippy_warnings: Vec<ClippyWarning> = crates
+        .par_iter()
+        .flat_map(|krate| krate.run_clippy_lints(&cargo_clippy_path, &counter, crates.len(), &config, &lint_filter))
+        .collect();
 
     // if we are in --fix mode, don't change the log files, terminate here
     if config.fix {
@@ -837,7 +674,7 @@ pub fn main() {
         text.push_str("| file | lint | message |\n");
         text.push_str("| --- | --- | --- |\n");
     }
-    write!(text, "{}", all_msgs.join(""));
+    write!(text, "{}", all_msgs.join("")).unwrap();
     text.push_str("\n\n### ICEs:\n");
     for (cratename, msg) in ices.iter() {
         let _ = write!(text, "{}: '{}'", cratename, msg);
@@ -949,75 +786,10 @@ fn create_dirs(krate_download_dir: &Path, extract_dir: &Path) {
     });
 }
 
-fn get_clap_config<'a>() -> ArgMatches<'a> {
-    App::new("lintcheck")
-        .about("run clippy on a set of crates and check output")
-        .arg(
-            Arg::with_name("only")
-                .takes_value(true)
-                .value_name("CRATE")
-                .long("only")
-                .help("only process a single crate of the list"),
-        )
-        .arg(
-            Arg::with_name("crates-toml")
-                .takes_value(true)
-                .value_name("CRATES-SOURCES-TOML-PATH")
-                .long("crates-toml")
-                .help("set the path for a crates.toml where lintcheck should read the sources from"),
-        )
-        .arg(
-            Arg::with_name("threads")
-                .takes_value(true)
-                .value_name("N")
-                .short("j")
-                .long("jobs")
-                .help("number of threads to use, 0 automatic choice"),
-        )
-        .arg(
-            Arg::with_name("fix")
-                .long("--fix")
-                .help("runs cargo clippy --fix and checks if all suggestions apply"),
-        )
-        .arg(
-            Arg::with_name("filter")
-                .long("--filter")
-                .takes_value(true)
-                .multiple(true)
-                .value_name("clippy_lint_name")
-                .help("apply a filter to only collect specified lints, this also overrides `allow` attributes"),
-        )
-        .arg(
-            Arg::with_name("markdown")
-                .long("--markdown")
-                .help("change the reports table to use markdown links"),
-        )
-        .get_matches()
-}
-
 /// Returns the path to the Clippy project directory
-///
-/// # Panics
-///
-/// Panics if the current directory could not be retrieved, there was an error reading any of the
-/// Cargo.toml files or ancestor directory is the clippy root directory
 #[must_use]
-pub fn clippy_project_root() -> PathBuf {
-    let current_dir = std::env::current_dir().unwrap();
-    for path in current_dir.ancestors() {
-        let result = std::fs::read_to_string(path.join("Cargo.toml"));
-        if let Err(err) = &result {
-            if err.kind() == std::io::ErrorKind::NotFound {
-                continue;
-            }
-        }
-
-        let content = result.unwrap();
-        if content.contains("[package]\nname = \"clippy\"") {
-            return path.to_path_buf();
-        }
-    }
-    panic!("error: Can't determine root of project. Please run inside a Clippy working dir.");
+fn clippy_project_root() -> &'static Path {
+    Path::new(env!("CARGO_MANIFEST_DIR")).parent().unwrap()
 }
 
 #[test]
diff --git a/src/tools/clippy/rust-toolchain b/src/tools/clippy/rust-toolchain
index 03acb51306d..997e7ba9382 100644
--- a/src/tools/clippy/rust-toolchain
+++ b/src/tools/clippy/rust-toolchain
@@ -1,3 +1,3 @@
 [toolchain]
-channel = "nightly-2022-05-05"
+channel = "nightly-2022-05-19"
 components = ["cargo", "llvm-tools-preview", "rust-src", "rust-std", "rustc", "rustc-dev", "rustfmt"]
diff --git a/src/tools/clippy/src/main.rs b/src/tools/clippy/src/main.rs
index 240e233420f..9ee4a40cbf2 100644
--- a/src/tools/clippy/src/main.rs
+++ b/src/tools/clippy/src/main.rs
@@ -123,8 +123,12 @@ impl ClippyCmd {
             .map(|arg| format!("{}__CLIPPY_HACKERY__", arg))
             .collect();
 
+        // Currently, `CLIPPY_TERMINAL_WIDTH` is used only to format "unknown field" error messages.
+        let terminal_width = termize::dimensions().map_or(0, |(w, _)| w);
+
         cmd.env("RUSTC_WORKSPACE_WRAPPER", Self::path())
             .env("CLIPPY_ARGS", clippy_args)
+            .env("CLIPPY_TERMINAL_WIDTH", terminal_width.to_string())
             .arg(self.cargo_subcommand)
             .args(&self.args);
 
diff --git a/src/tools/clippy/tests/dogfood.rs b/src/tools/clippy/tests/dogfood.rs
index eb97d1933d5..9da80518ce9 100644
--- a/src/tools/clippy/tests/dogfood.rs
+++ b/src/tools/clippy/tests/dogfood.rs
@@ -21,7 +21,7 @@ fn dogfood_clippy() {
 
     // "" is the root package
     for package in &["", "clippy_dev", "clippy_lints", "clippy_utils", "rustc_tools_util"] {
-        run_clippy_for_package(package);
+        run_clippy_for_package(package, &[]);
     }
 }
 
@@ -38,7 +38,7 @@ fn run_metadata_collection_lint() {
 
     // Run collection as is
     std::env::set_var("ENABLE_METADATA_COLLECTION", "1");
-    run_clippy_for_package("clippy_lints");
+    run_clippy_for_package("clippy_lints", &["-A", "unfulfilled_lint_expectations"]);
 
     // Check if cargo caching got in the way
     if let Ok(file) = File::open(metadata_output_path) {
@@ -61,10 +61,10 @@ fn run_metadata_collection_lint() {
     .unwrap();
 
     // Running the collection again
-    run_clippy_for_package("clippy_lints");
+    run_clippy_for_package("clippy_lints", &["-A", "unfulfilled_lint_expectations"]);
 }
 
-fn run_clippy_for_package(project: &str) {
+fn run_clippy_for_package(project: &str, args: &[&str]) {
     let root_dir = PathBuf::from(env!("CARGO_MANIFEST_DIR"));
 
     let mut command = Command::new(&*test_utils::CARGO_CLIPPY_PATH);
@@ -76,6 +76,7 @@ fn run_clippy_for_package(project: &str) {
         .arg("--all-targets")
         .arg("--all-features")
         .arg("--")
+        .args(args)
         .args(&["-D", "clippy::all"])
         .args(&["-D", "clippy::pedantic"])
         .arg("-Cdebuginfo=0"); // disable debuginfo to generate less data in the target dir
diff --git a/src/tools/clippy/tests/ui-cargo/duplicate_mod/fail/Cargo.toml b/src/tools/clippy/tests/ui-cargo/duplicate_mod/fail/Cargo.toml
new file mode 100644
index 00000000000..bf3c817de1c
--- /dev/null
+++ b/src/tools/clippy/tests/ui-cargo/duplicate_mod/fail/Cargo.toml
@@ -0,0 +1,5 @@
+[package]
+name = "duplicate_mod"
+edition = "2021"
+publish = false
+version = "0.1.0"
diff --git a/src/tools/clippy/tests/ui-cargo/duplicate_mod/fail/src/a.rs b/src/tools/clippy/tests/ui-cargo/duplicate_mod/fail/src/a.rs
new file mode 100644
index 00000000000..8b137891791
--- /dev/null
+++ b/src/tools/clippy/tests/ui-cargo/duplicate_mod/fail/src/a.rs
@@ -0,0 +1 @@
+
diff --git a/src/tools/clippy/tests/ui-cargo/duplicate_mod/fail/src/b.rs b/src/tools/clippy/tests/ui-cargo/duplicate_mod/fail/src/b.rs
new file mode 100644
index 00000000000..8b137891791
--- /dev/null
+++ b/src/tools/clippy/tests/ui-cargo/duplicate_mod/fail/src/b.rs
@@ -0,0 +1 @@
+
diff --git a/src/tools/clippy/tests/ui-cargo/duplicate_mod/fail/src/c.rs b/src/tools/clippy/tests/ui-cargo/duplicate_mod/fail/src/c.rs
new file mode 100644
index 00000000000..8b137891791
--- /dev/null
+++ b/src/tools/clippy/tests/ui-cargo/duplicate_mod/fail/src/c.rs
@@ -0,0 +1 @@
+
diff --git a/src/tools/clippy/tests/ui-cargo/duplicate_mod/fail/src/from_other_module.rs b/src/tools/clippy/tests/ui-cargo/duplicate_mod/fail/src/from_other_module.rs
new file mode 100644
index 00000000000..8b137891791
--- /dev/null
+++ b/src/tools/clippy/tests/ui-cargo/duplicate_mod/fail/src/from_other_module.rs
@@ -0,0 +1 @@
+
diff --git a/src/tools/clippy/tests/ui-cargo/duplicate_mod/fail/src/main.rs b/src/tools/clippy/tests/ui-cargo/duplicate_mod/fail/src/main.rs
new file mode 100644
index 00000000000..79b343da247
--- /dev/null
+++ b/src/tools/clippy/tests/ui-cargo/duplicate_mod/fail/src/main.rs
@@ -0,0 +1,16 @@
+mod a;
+
+mod b;
+#[path = "b.rs"]
+mod b2;
+
+mod c;
+#[path = "c.rs"]
+mod c2;
+#[path = "c.rs"]
+mod c3;
+
+mod from_other_module;
+mod other_module;
+
+fn main() {}
diff --git a/src/tools/clippy/tests/ui-cargo/duplicate_mod/fail/src/main.stderr b/src/tools/clippy/tests/ui-cargo/duplicate_mod/fail/src/main.stderr
new file mode 100644
index 00000000000..00d7739c8a2
--- /dev/null
+++ b/src/tools/clippy/tests/ui-cargo/duplicate_mod/fail/src/main.stderr
@@ -0,0 +1,42 @@
+error: file is loaded as a module multiple times: `$DIR/b.rs`
+  --> $DIR/main.rs:3:1
+   |
+LL |   mod b;
+   |   ^^^^^^ first loaded here
+LL | / #[path = "b.rs"]
+LL | | mod b2;
+   | |_______^ loaded again here
+   |
+   = note: `-D clippy::duplicate-mod` implied by `-D warnings`
+   = help: replace all but one `mod` item with `use` items
+
+error: file is loaded as a module multiple times: `$DIR/c.rs`
+  --> $DIR/main.rs:7:1
+   |
+LL |   mod c;
+   |   ^^^^^^ first loaded here
+LL | / #[path = "c.rs"]
+LL | | mod c2;
+   | |_______^ loaded again here
+LL | / #[path = "c.rs"]
+LL | | mod c3;
+   | |_______^ loaded again here
+   |
+   = help: replace all but one `mod` item with `use` items
+
+error: file is loaded as a module multiple times: `$DIR/from_other_module.rs`
+  --> $DIR/main.rs:13:1
+   |
+LL |   mod from_other_module;
+   |   ^^^^^^^^^^^^^^^^^^^^^^ first loaded here
+   |
+  ::: $DIR/other_module/mod.rs:1:1
+   |
+LL | / #[path = "../from_other_module.rs"]
+LL | | mod m;
+   | |______^ loaded again here
+   |
+   = help: replace all but one `mod` item with `use` items
+
+error: aborting due to 3 previous errors
+
diff --git a/src/tools/clippy/tests/ui-cargo/duplicate_mod/fail/src/other_module/mod.rs b/src/tools/clippy/tests/ui-cargo/duplicate_mod/fail/src/other_module/mod.rs
new file mode 100644
index 00000000000..36ce7286ade
--- /dev/null
+++ b/src/tools/clippy/tests/ui-cargo/duplicate_mod/fail/src/other_module/mod.rs
@@ -0,0 +1,2 @@
+#[path = "../from_other_module.rs"]
+mod m;
diff --git a/src/tools/clippy/tests/ui-toml/expect_used/clippy.toml b/src/tools/clippy/tests/ui-toml/expect_used/clippy.toml
new file mode 100644
index 00000000000..6933b816419
--- /dev/null
+++ b/src/tools/clippy/tests/ui-toml/expect_used/clippy.toml
@@ -0,0 +1 @@
+allow-expect-in-tests = true
diff --git a/src/tools/clippy/tests/ui-toml/expect_used/expect_used.rs b/src/tools/clippy/tests/ui-toml/expect_used/expect_used.rs
new file mode 100644
index 00000000000..22dcd3ae9d6
--- /dev/null
+++ b/src/tools/clippy/tests/ui-toml/expect_used/expect_used.rs
@@ -0,0 +1,29 @@
+// compile-flags: --test
+#![warn(clippy::expect_used)]
+
+fn expect_option() {
+    let opt = Some(0);
+    let _ = opt.expect("");
+}
+
+fn expect_result() {
+    let res: Result<u8, ()> = Ok(0);
+    let _ = res.expect("");
+}
+
+fn main() {
+    expect_option();
+    expect_result();
+}
+
+#[test]
+fn test_expect_option() {
+    let opt = Some(0);
+    let _ = opt.expect("");
+}
+
+#[test]
+fn test_expect_result() {
+    let res: Result<u8, ()> = Ok(0);
+    let _ = res.expect("");
+}
diff --git a/src/tools/clippy/tests/ui-toml/expect_used/expect_used.stderr b/src/tools/clippy/tests/ui-toml/expect_used/expect_used.stderr
new file mode 100644
index 00000000000..9cb2199ed21
--- /dev/null
+++ b/src/tools/clippy/tests/ui-toml/expect_used/expect_used.stderr
@@ -0,0 +1,19 @@
+error: used `expect()` on `an Option` value
+  --> $DIR/expect_used.rs:6:13
+   |
+LL |     let _ = opt.expect("");
+   |             ^^^^^^^^^^^^^^
+   |
+   = note: `-D clippy::expect-used` implied by `-D warnings`
+   = help: if this value is an `None`, it will panic
+
+error: used `expect()` on `a Result` value
+  --> $DIR/expect_used.rs:11:13
+   |
+LL |     let _ = res.expect("");
+   |             ^^^^^^^^^^^^^^
+   |
+   = help: if this value is an `Err`, it will panic
+
+error: aborting due to 2 previous errors
+
diff --git a/src/tools/clippy/tests/ui-toml/toml_disallowed_methods/conf_disallowed_methods.rs b/src/tools/clippy/tests/ui-toml/toml_disallowed_methods/conf_disallowed_methods.rs
index 338b3b5b28f..3397fa1ec69 100644
--- a/src/tools/clippy/tests/ui-toml/toml_disallowed_methods/conf_disallowed_methods.rs
+++ b/src/tools/clippy/tests/ui-toml/toml_disallowed_methods/conf_disallowed_methods.rs
@@ -14,4 +14,10 @@ fn main() {
 
     let _ = 2.0f32.clamp(3.0f32, 4.0f32);
     let _ = 2.0f64.clamp(3.0f64, 4.0f64);
+
+    let indirect: fn(&str) -> Result<Regex, regex::Error> = Regex::new;
+    let re = indirect(".").unwrap();
+
+    let in_call = Box::new(f32::clamp);
+    let in_method_call = ["^", "$"].into_iter().map(Regex::new);
 }
diff --git a/src/tools/clippy/tests/ui-toml/toml_disallowed_methods/conf_disallowed_methods.stderr b/src/tools/clippy/tests/ui-toml/toml_disallowed_methods/conf_disallowed_methods.stderr
index 5533676aea2..5cbb567546c 100644
--- a/src/tools/clippy/tests/ui-toml/toml_disallowed_methods/conf_disallowed_methods.stderr
+++ b/src/tools/clippy/tests/ui-toml/toml_disallowed_methods/conf_disallowed_methods.stderr
@@ -32,5 +32,23 @@ error: use of a disallowed method `f32::clamp`
 LL |     let _ = 2.0f32.clamp(3.0f32, 4.0f32);
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
-error: aborting due to 5 previous errors
+error: use of a disallowed method `regex::Regex::new`
+  --> $DIR/conf_disallowed_methods.rs:18:61
+   |
+LL |     let indirect: fn(&str) -> Result<Regex, regex::Error> = Regex::new;
+   |                                                             ^^^^^^^^^^
+
+error: use of a disallowed method `f32::clamp`
+  --> $DIR/conf_disallowed_methods.rs:21:28
+   |
+LL |     let in_call = Box::new(f32::clamp);
+   |                            ^^^^^^^^^^
+
+error: use of a disallowed method `regex::Regex::new`
+  --> $DIR/conf_disallowed_methods.rs:22:53
+   |
+LL |     let in_method_call = ["^", "$"].into_iter().map(Regex::new);
+   |                                                     ^^^^^^^^^^
+
+error: aborting due to 8 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 8701809b4da..92838aa57df 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
@@ -1,4 +1,43 @@
-error: error reading Clippy's configuration file `$DIR/clippy.toml`: unknown field `foobar`, expected one of `avoid-breaking-exported-api`, `msrv`, `blacklisted-names`, `cognitive-complexity-threshold`, `cyclomatic-complexity-threshold`, `doc-valid-idents`, `too-many-arguments-threshold`, `type-complexity-threshold`, `single-char-binding-names-threshold`, `too-large-for-stack`, `enum-variant-name-threshold`, `enum-variant-size-threshold`, `verbose-bit-mask-threshold`, `literal-representation-threshold`, `trivial-copy-size-limit`, `pass-by-value-size-limit`, `too-many-lines-threshold`, `array-size-threshold`, `vec-box-size-threshold`, `max-trait-bounds`, `max-struct-bools`, `max-fn-params-bools`, `warn-on-all-wildcard-imports`, `disallowed-methods`, `disallowed-types`, `unreadable-literal-lint-fractions`, `upper-case-acronyms-aggressive`, `cargo-ignore-publish`, `standard-macro-braces`, `enforced-import-renames`, `allowed-scripts`, `enable-raw-pointer-heuristic-for-send`, `max-suggested-slice-pattern-length`, `await-holding-invalid-types`, `max-include-file-size`, `third-party` at line 5 column 1
+error: error reading Clippy's configuration file `$DIR/clippy.toml`: unknown field `foobar`, expected one of
+           allow-expect-in-tests
+           allow-unwrap-in-tests
+           allowed-scripts
+           array-size-threshold
+           avoid-breaking-exported-api
+           await-holding-invalid-types
+           blacklisted-names
+           cargo-ignore-publish
+           cognitive-complexity-threshold
+           cyclomatic-complexity-threshold
+           disallowed-methods
+           disallowed-types
+           doc-valid-idents
+           enable-raw-pointer-heuristic-for-send
+           enforced-import-renames
+           enum-variant-name-threshold
+           enum-variant-size-threshold
+           literal-representation-threshold
+           max-fn-params-bools
+           max-include-file-size
+           max-struct-bools
+           max-suggested-slice-pattern-length
+           max-trait-bounds
+           msrv
+           pass-by-value-size-limit
+           single-char-binding-names-threshold
+           standard-macro-braces
+           third-party
+           too-large-for-stack
+           too-many-arguments-threshold
+           too-many-lines-threshold
+           trivial-copy-size-limit
+           type-complexity-threshold
+           unreadable-literal-lint-fractions
+           upper-case-acronyms-aggressive
+           vec-box-size-threshold
+           verbose-bit-mask-threshold
+           warn-on-all-wildcard-imports
+       at line 5 column 1
 
 error: aborting due to previous error
 
diff --git a/src/tools/clippy/tests/ui-toml/unwrap_used/clippy.toml b/src/tools/clippy/tests/ui-toml/unwrap_used/clippy.toml
new file mode 100644
index 00000000000..154626ef4e8
--- /dev/null
+++ b/src/tools/clippy/tests/ui-toml/unwrap_used/clippy.toml
@@ -0,0 +1 @@
+allow-unwrap-in-tests = true
diff --git a/src/tools/clippy/tests/ui-toml/unwrap_used/unwrap_used.rs b/src/tools/clippy/tests/ui-toml/unwrap_used/unwrap_used.rs
new file mode 100644
index 00000000000..74d0d7c2650
--- /dev/null
+++ b/src/tools/clippy/tests/ui-toml/unwrap_used/unwrap_used.rs
@@ -0,0 +1,73 @@
+// compile-flags: --test
+
+#![allow(unused_mut, clippy::from_iter_instead_of_collect)]
+#![warn(clippy::unwrap_used)]
+#![deny(clippy::get_unwrap)]
+
+use std::collections::BTreeMap;
+use std::collections::HashMap;
+use std::collections::VecDeque;
+
+struct GetFalsePositive {
+    arr: [u32; 3],
+}
+
+impl GetFalsePositive {
+    fn get(&self, pos: usize) -> Option<&u32> {
+        self.arr.get(pos)
+    }
+    fn get_mut(&mut self, pos: usize) -> Option<&mut u32> {
+        self.arr.get_mut(pos)
+    }
+}
+
+fn main() {
+    let mut boxed_slice: Box<[u8]> = Box::new([0, 1, 2, 3]);
+    let mut some_slice = &mut [0, 1, 2, 3];
+    let mut some_vec = vec![0, 1, 2, 3];
+    let mut some_vecdeque: VecDeque<_> = some_vec.iter().cloned().collect();
+    let mut some_hashmap: HashMap<u8, char> = HashMap::from_iter(vec![(1, 'a'), (2, 'b')]);
+    let mut some_btreemap: BTreeMap<u8, char> = BTreeMap::from_iter(vec![(1, 'a'), (2, 'b')]);
+    let mut false_positive = GetFalsePositive { arr: [0, 1, 2] };
+
+    {
+        // Test `get().unwrap()`
+        let _ = boxed_slice.get(1).unwrap();
+        let _ = some_slice.get(0).unwrap();
+        let _ = some_vec.get(0).unwrap();
+        let _ = some_vecdeque.get(0).unwrap();
+        let _ = some_hashmap.get(&1).unwrap();
+        let _ = some_btreemap.get(&1).unwrap();
+        #[allow(clippy::unwrap_used)]
+        let _ = false_positive.get(0).unwrap();
+        // Test with deref
+        let _: u8 = *boxed_slice.get(1).unwrap();
+    }
+
+    {
+        // Test `get_mut().unwrap()`
+        *boxed_slice.get_mut(0).unwrap() = 1;
+        *some_slice.get_mut(0).unwrap() = 1;
+        *some_vec.get_mut(0).unwrap() = 1;
+        *some_vecdeque.get_mut(0).unwrap() = 1;
+        // Check false positives
+        #[allow(clippy::unwrap_used)]
+        {
+            *some_hashmap.get_mut(&1).unwrap() = 'b';
+            *some_btreemap.get_mut(&1).unwrap() = 'b';
+            *false_positive.get_mut(0).unwrap() = 1;
+        }
+    }
+
+    {
+        // Test `get().unwrap().foo()` and `get_mut().unwrap().bar()`
+        let _ = some_vec.get(0..1).unwrap().to_vec();
+        let _ = some_vec.get_mut(0..1).unwrap().to_vec();
+    }
+}
+
+#[test]
+fn test() {
+    let boxed_slice: Box<[u8]> = Box::new([0, 1, 2, 3]);
+    let _ = boxed_slice.get(1).unwrap();
+}
diff --git a/src/tools/clippy/tests/ui-toml/unwrap_used/unwrap_used.stderr b/src/tools/clippy/tests/ui-toml/unwrap_used/unwrap_used.stderr
new file mode 100644
index 00000000000..6bcfa0a8b56
--- /dev/null
+++ b/src/tools/clippy/tests/ui-toml/unwrap_used/unwrap_used.stderr
@@ -0,0 +1,197 @@
+error: called `.get().unwrap()` on a slice. Using `[]` is more clear and more concise
+  --> $DIR/unwrap_used.rs:35:17
+   |
+LL |         let _ = boxed_slice.get(1).unwrap();
+   |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `&boxed_slice[1]`
+   |
+note: the lint level is defined here
+  --> $DIR/unwrap_used.rs:5:9
+   |
+LL | #![deny(clippy::get_unwrap)]
+   |         ^^^^^^^^^^^^^^^^^^
+
+error: used `unwrap()` on `an Option` value
+  --> $DIR/unwrap_used.rs:35:17
+   |
+LL |         let _ = boxed_slice.get(1).unwrap();
+   |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: `-D clippy::unwrap-used` implied by `-D warnings`
+   = help: if you don't want to handle the `None` case gracefully, consider using `expect()` to provide a better panic message
+
+error: called `.get().unwrap()` on a slice. Using `[]` is more clear and more concise
+  --> $DIR/unwrap_used.rs:36:17
+   |
+LL |         let _ = some_slice.get(0).unwrap();
+   |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `&some_slice[0]`
+
+error: used `unwrap()` on `an Option` value
+  --> $DIR/unwrap_used.rs:36:17
+   |
+LL |         let _ = some_slice.get(0).unwrap();
+   |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = help: if you don't want to handle the `None` case gracefully, consider using `expect()` to provide a better panic message
+
+error: called `.get().unwrap()` on a Vec. Using `[]` is more clear and more concise
+  --> $DIR/unwrap_used.rs:37:17
+   |
+LL |         let _ = some_vec.get(0).unwrap();
+   |                 ^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `&some_vec[0]`
+
+error: used `unwrap()` on `an Option` value
+  --> $DIR/unwrap_used.rs:37:17
+   |
+LL |         let _ = some_vec.get(0).unwrap();
+   |                 ^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = help: if you don't want to handle the `None` case gracefully, consider using `expect()` to provide a better panic message
+
+error: called `.get().unwrap()` on a VecDeque. Using `[]` is more clear and more concise
+  --> $DIR/unwrap_used.rs:38:17
+   |
+LL |         let _ = some_vecdeque.get(0).unwrap();
+   |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `&some_vecdeque[0]`
+
+error: used `unwrap()` on `an Option` value
+  --> $DIR/unwrap_used.rs:38:17
+   |
+LL |         let _ = some_vecdeque.get(0).unwrap();
+   |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = help: if you don't want to handle the `None` case gracefully, consider using `expect()` to provide a better panic message
+
+error: called `.get().unwrap()` on a HashMap. Using `[]` is more clear and more concise
+  --> $DIR/unwrap_used.rs:39:17
+   |
+LL |         let _ = some_hashmap.get(&1).unwrap();
+   |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `&some_hashmap[&1]`
+
+error: used `unwrap()` on `an Option` value
+  --> $DIR/unwrap_used.rs:39:17
+   |
+LL |         let _ = some_hashmap.get(&1).unwrap();
+   |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = help: if you don't want to handle the `None` case gracefully, consider using `expect()` to provide a better panic message
+
+error: called `.get().unwrap()` on a BTreeMap. Using `[]` is more clear and more concise
+  --> $DIR/unwrap_used.rs:40:17
+   |
+LL |         let _ = some_btreemap.get(&1).unwrap();
+   |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `&some_btreemap[&1]`
+
+error: used `unwrap()` on `an Option` value
+  --> $DIR/unwrap_used.rs:40:17
+   |
+LL |         let _ = some_btreemap.get(&1).unwrap();
+   |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = help: if you don't want to handle the `None` case gracefully, consider using `expect()` to provide a better panic message
+
+error: called `.get().unwrap()` on a slice. Using `[]` is more clear and more concise
+  --> $DIR/unwrap_used.rs:44:21
+   |
+LL |         let _: u8 = *boxed_slice.get(1).unwrap();
+   |                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `boxed_slice[1]`
+
+error: used `unwrap()` on `an Option` value
+  --> $DIR/unwrap_used.rs:44:22
+   |
+LL |         let _: u8 = *boxed_slice.get(1).unwrap();
+   |                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = help: if you don't want to handle the `None` case gracefully, consider using `expect()` to provide a better panic message
+
+error: called `.get_mut().unwrap()` on a slice. Using `[]` is more clear and more concise
+  --> $DIR/unwrap_used.rs:49:9
+   |
+LL |         *boxed_slice.get_mut(0).unwrap() = 1;
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `boxed_slice[0]`
+
+error: used `unwrap()` on `an Option` value
+  --> $DIR/unwrap_used.rs:49:10
+   |
+LL |         *boxed_slice.get_mut(0).unwrap() = 1;
+   |          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = help: if you don't want to handle the `None` case gracefully, consider using `expect()` to provide a better panic message
+
+error: called `.get_mut().unwrap()` on a slice. Using `[]` is more clear and more concise
+  --> $DIR/unwrap_used.rs:50:9
+   |
+LL |         *some_slice.get_mut(0).unwrap() = 1;
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `some_slice[0]`
+
+error: used `unwrap()` on `an Option` value
+  --> $DIR/unwrap_used.rs:50:10
+   |
+LL |         *some_slice.get_mut(0).unwrap() = 1;
+   |          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = help: if you don't want to handle the `None` case gracefully, consider using `expect()` to provide a better panic message
+
+error: called `.get_mut().unwrap()` on a Vec. Using `[]` is more clear and more concise
+  --> $DIR/unwrap_used.rs:51:9
+   |
+LL |         *some_vec.get_mut(0).unwrap() = 1;
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `some_vec[0]`
+
+error: used `unwrap()` on `an Option` value
+  --> $DIR/unwrap_used.rs:51:10
+   |
+LL |         *some_vec.get_mut(0).unwrap() = 1;
+   |          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = help: if you don't want to handle the `None` case gracefully, consider using `expect()` to provide a better panic message
+
+error: called `.get_mut().unwrap()` on a VecDeque. Using `[]` is more clear and more concise
+  --> $DIR/unwrap_used.rs:52:9
+   |
+LL |         *some_vecdeque.get_mut(0).unwrap() = 1;
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `some_vecdeque[0]`
+
+error: used `unwrap()` on `an Option` value
+  --> $DIR/unwrap_used.rs:52:10
+   |
+LL |         *some_vecdeque.get_mut(0).unwrap() = 1;
+   |          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = help: if you don't want to handle the `None` case gracefully, consider using `expect()` to provide a better panic message
+
+error: called `.get().unwrap()` on a Vec. Using `[]` is more clear and more concise
+  --> $DIR/unwrap_used.rs:64:17
+   |
+LL |         let _ = some_vec.get(0..1).unwrap().to_vec();
+   |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `some_vec[0..1]`
+
+error: used `unwrap()` on `an Option` value
+  --> $DIR/unwrap_used.rs:64:17
+   |
+LL |         let _ = some_vec.get(0..1).unwrap().to_vec();
+   |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = help: if you don't want to handle the `None` case gracefully, consider using `expect()` to provide a better panic message
+
+error: called `.get_mut().unwrap()` on a Vec. Using `[]` is more clear and more concise
+  --> $DIR/unwrap_used.rs:65:17
+   |
+LL |         let _ = some_vec.get_mut(0..1).unwrap().to_vec();
+   |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `some_vec[0..1]`
+
+error: used `unwrap()` on `an Option` value
+  --> $DIR/unwrap_used.rs:65:17
+   |
+LL |         let _ = some_vec.get_mut(0..1).unwrap().to_vec();
+   |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = help: if you don't want to handle the `None` case gracefully, consider using `expect()` to provide a better panic message
+
+error: called `.get().unwrap()` on a slice. Using `[]` is more clear and more concise
+  --> $DIR/unwrap_used.rs:72:13
+   |
+LL |     let _ = boxed_slice.get(1).unwrap();
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `&boxed_slice[1]`
+
+error: aborting due to 27 previous errors
+
diff --git a/src/tools/clippy/tests/ui/absurd-extreme-comparisons.rs b/src/tools/clippy/tests/ui/absurd-extreme-comparisons.rs
index d205b383d1f..f682b280c1b 100644
--- a/src/tools/clippy/tests/ui/absurd-extreme-comparisons.rs
+++ b/src/tools/clippy/tests/ui/absurd-extreme-comparisons.rs
@@ -37,7 +37,7 @@ fn main() {
 
 use std::cmp::{Ordering, PartialEq, PartialOrd};
 
-#[derive(PartialEq, PartialOrd)]
+#[derive(PartialEq, Eq, PartialOrd)]
 pub struct U(u64);
 
 impl PartialEq<u32> for U {
diff --git a/src/tools/clippy/tests/ui/assign_ops2.rs b/src/tools/clippy/tests/ui/assign_ops2.rs
index 4703a8c7777..f6d3a8fa3f0 100644
--- a/src/tools/clippy/tests/ui/assign_ops2.rs
+++ b/src/tools/clippy/tests/ui/assign_ops2.rs
@@ -24,7 +24,7 @@ fn main() {
 
 use std::ops::{Mul, MulAssign};
 
-#[derive(Copy, Clone, Debug, PartialEq)]
+#[derive(Copy, Clone, Debug, PartialEq, Eq)]
 pub struct Wrap(i64);
 
 impl Mul<i64> for Wrap {
diff --git a/src/tools/clippy/tests/ui/auxiliary/proc_macro_suspicious_else_formatting.rs b/src/tools/clippy/tests/ui/auxiliary/proc_macro_suspicious_else_formatting.rs
index 26c88489b03..a2ef0fe827c 100644
--- a/src/tools/clippy/tests/ui/auxiliary/proc_macro_suspicious_else_formatting.rs
+++ b/src/tools/clippy/tests/ui/auxiliary/proc_macro_suspicious_else_formatting.rs
@@ -5,7 +5,6 @@
 
 extern crate proc_macro;
 use proc_macro::{token_stream, Delimiter, Group, Ident, Span, TokenStream, TokenTree};
-use std::iter::FromIterator;
 
 fn read_ident(iter: &mut token_stream::IntoIter) -> Ident {
     match iter.next() {
diff --git a/src/tools/clippy/tests/ui/blacklisted_name.rs b/src/tools/clippy/tests/ui/blacklisted_name.rs
index 57d7139fef5..27df732a088 100644
--- a/src/tools/clippy/tests/ui/blacklisted_name.rs
+++ b/src/tools/clippy/tests/ui/blacklisted_name.rs
@@ -46,10 +46,10 @@ fn issue_1647_ref_mut() {
 
 mod tests {
     fn issue_7305() {
-        // `blackisted_name` lint should not be triggered inside of the test code.
+        // `blacklisted_name` lint should not be triggered inside of the test code.
         let foo = 0;
 
-        // Check that even in nested functions warning is still not triggere.
+        // Check that even in nested functions warning is still not triggered.
         fn nested() {
             let foo = 0;
         }
diff --git a/src/tools/clippy/tests/ui/branches_sharing_code/shared_at_top.rs b/src/tools/clippy/tests/ui/branches_sharing_code/shared_at_top.rs
index 51a46481399..bdeb0a39558 100644
--- a/src/tools/clippy/tests/ui/branches_sharing_code/shared_at_top.rs
+++ b/src/tools/clippy/tests/ui/branches_sharing_code/shared_at_top.rs
@@ -1,4 +1,4 @@
-#![allow(dead_code, clippy::eval_order_dependence)]
+#![allow(dead_code, clippy::mixed_read_write_in_expression)]
 #![deny(clippy::if_same_then_else, clippy::branches_sharing_code)]
 
 // This tests the branches_sharing_code lint at the start of blocks
diff --git a/src/tools/clippy/tests/ui/branches_sharing_code/valid_if_blocks.rs b/src/tools/clippy/tests/ui/branches_sharing_code/valid_if_blocks.rs
index 0c70e3748ec..a26141be237 100644
--- a/src/tools/clippy/tests/ui/branches_sharing_code/valid_if_blocks.rs
+++ b/src/tools/clippy/tests/ui/branches_sharing_code/valid_if_blocks.rs
@@ -1,4 +1,4 @@
-#![allow(dead_code, clippy::eval_order_dependence)]
+#![allow(dead_code, clippy::mixed_read_write_in_expression)]
 #![deny(clippy::if_same_then_else, clippy::branches_sharing_code)]
 
 // This tests valid if blocks that shouldn't trigger the lint
diff --git a/src/tools/clippy/tests/ui/cast_size_32bit.stderr b/src/tools/clippy/tests/ui/cast_size_32bit.stderr
index 140676a5ffc..7125f741c15 100644
--- a/src/tools/clippy/tests/ui/cast_size_32bit.stderr
+++ b/src/tools/clippy/tests/ui/cast_size_32bit.stderr
@@ -14,26 +14,12 @@ LL |     x0 as f64;
    |
    = note: `-D clippy::cast-precision-loss` implied by `-D warnings`
 
-error: casting `isize` to `f64` may become silently lossy if you later change the type
-  --> $DIR/cast_size_32bit.rs:15:5
-   |
-LL |     x0 as f64;
-   |     ^^^^^^^^^ help: try: `f64::from(x0)`
-   |
-   = note: `-D clippy::cast-lossless` implied by `-D warnings`
-
 error: casting `usize` to `f64` causes a loss of precision on targets with 64-bit wide pointers (`usize` is 64 bits wide, but `f64`'s mantissa is only 52 bits wide)
   --> $DIR/cast_size_32bit.rs:16:5
    |
 LL |     x1 as f64;
    |     ^^^^^^^^^
 
-error: casting `usize` to `f64` may become silently lossy if you later change the type
-  --> $DIR/cast_size_32bit.rs:16:5
-   |
-LL |     x1 as f64;
-   |     ^^^^^^^^^ help: try: `f64::from(x1)`
-
 error: casting `isize` to `f32` causes a loss of precision (`isize` is 32 or 64 bits wide, but `f32`'s mantissa is only 23 bits wide)
   --> $DIR/cast_size_32bit.rs:17:5
    |
diff --git a/src/tools/clippy/tests/ui/checked_conversions.fixed b/src/tools/clippy/tests/ui/checked_conversions.fixed
index 12290db3dcf..0983d393b56 100644
--- a/src/tools/clippy/tests/ui/checked_conversions.fixed
+++ b/src/tools/clippy/tests/ui/checked_conversions.fixed
@@ -7,8 +7,6 @@
 )]
 #![warn(clippy::checked_conversions)]
 
-use std::convert::TryFrom;
-
 // Positive tests
 
 // Signed to unsigned
diff --git a/src/tools/clippy/tests/ui/checked_conversions.rs b/src/tools/clippy/tests/ui/checked_conversions.rs
index 895a301e821..7d26ace47fd 100644
--- a/src/tools/clippy/tests/ui/checked_conversions.rs
+++ b/src/tools/clippy/tests/ui/checked_conversions.rs
@@ -7,8 +7,6 @@
 )]
 #![warn(clippy::checked_conversions)]
 
-use std::convert::TryFrom;
-
 // Positive tests
 
 // Signed to unsigned
diff --git a/src/tools/clippy/tests/ui/checked_conversions.stderr b/src/tools/clippy/tests/ui/checked_conversions.stderr
index 18518def0ac..2e518040561 100644
--- a/src/tools/clippy/tests/ui/checked_conversions.stderr
+++ b/src/tools/clippy/tests/ui/checked_conversions.stderr
@@ -1,5 +1,5 @@
 error: checked cast can be simplified
-  --> $DIR/checked_conversions.rs:17:13
+  --> $DIR/checked_conversions.rs:15:13
    |
 LL |     let _ = value <= (u32::max_value() as i64) && value >= 0;
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `u32::try_from(value).is_ok()`
@@ -7,91 +7,91 @@ LL |     let _ = value <= (u32::max_value() as i64) && value >= 0;
    = note: `-D clippy::checked-conversions` implied by `-D warnings`
 
 error: checked cast can be simplified
-  --> $DIR/checked_conversions.rs:18:13
+  --> $DIR/checked_conversions.rs:16:13
    |
 LL |     let _ = value <= (u32::MAX as i64) && value >= 0;
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `u32::try_from(value).is_ok()`
 
 error: checked cast can be simplified
-  --> $DIR/checked_conversions.rs:22:13
+  --> $DIR/checked_conversions.rs:20:13
    |
 LL |     let _ = value <= i64::from(u16::max_value()) && value >= 0;
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `u16::try_from(value).is_ok()`
 
 error: checked cast can be simplified
-  --> $DIR/checked_conversions.rs:23:13
+  --> $DIR/checked_conversions.rs:21:13
    |
 LL |     let _ = value <= i64::from(u16::MAX) && value >= 0;
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `u16::try_from(value).is_ok()`
 
 error: checked cast can be simplified
-  --> $DIR/checked_conversions.rs:27:13
+  --> $DIR/checked_conversions.rs:25:13
    |
 LL |     let _ = value <= (u8::max_value() as isize) && value >= 0;
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `u8::try_from(value).is_ok()`
 
 error: checked cast can be simplified
-  --> $DIR/checked_conversions.rs:28:13
+  --> $DIR/checked_conversions.rs:26:13
    |
 LL |     let _ = value <= (u8::MAX as isize) && value >= 0;
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `u8::try_from(value).is_ok()`
 
 error: checked cast can be simplified
-  --> $DIR/checked_conversions.rs:34:13
+  --> $DIR/checked_conversions.rs:32:13
    |
 LL |     let _ = value <= (i32::max_value() as i64) && value >= (i32::min_value() as i64);
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `i32::try_from(value).is_ok()`
 
 error: checked cast can be simplified
-  --> $DIR/checked_conversions.rs:35:13
+  --> $DIR/checked_conversions.rs:33:13
    |
 LL |     let _ = value <= (i32::MAX as i64) && value >= (i32::MIN as i64);
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `i32::try_from(value).is_ok()`
 
 error: checked cast can be simplified
-  --> $DIR/checked_conversions.rs:39:13
+  --> $DIR/checked_conversions.rs:37:13
    |
 LL |     let _ = value <= i64::from(i16::max_value()) && value >= i64::from(i16::min_value());
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `i16::try_from(value).is_ok()`
 
 error: checked cast can be simplified
-  --> $DIR/checked_conversions.rs:40:13
+  --> $DIR/checked_conversions.rs:38:13
    |
 LL |     let _ = value <= i64::from(i16::MAX) && value >= i64::from(i16::MIN);
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `i16::try_from(value).is_ok()`
 
 error: checked cast can be simplified
-  --> $DIR/checked_conversions.rs:46:13
+  --> $DIR/checked_conversions.rs:44:13
    |
 LL |     let _ = value <= i32::max_value() as u32;
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `i32::try_from(value).is_ok()`
 
 error: checked cast can be simplified
-  --> $DIR/checked_conversions.rs:47:13
+  --> $DIR/checked_conversions.rs:45:13
    |
 LL |     let _ = value <= i32::MAX as u32;
    |             ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `i32::try_from(value).is_ok()`
 
 error: checked cast can be simplified
-  --> $DIR/checked_conversions.rs:51:13
+  --> $DIR/checked_conversions.rs:49:13
    |
 LL |     let _ = value <= isize::max_value() as usize && value as i32 == 5;
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `isize::try_from(value).is_ok()`
 
 error: checked cast can be simplified
-  --> $DIR/checked_conversions.rs:52:13
+  --> $DIR/checked_conversions.rs:50:13
    |
 LL |     let _ = value <= isize::MAX as usize && value as i32 == 5;
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `isize::try_from(value).is_ok()`
 
 error: checked cast can be simplified
-  --> $DIR/checked_conversions.rs:56:13
+  --> $DIR/checked_conversions.rs:54:13
    |
 LL |     let _ = value <= u16::max_value() as u32 && value as i32 == 5;
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `u16::try_from(value).is_ok()`
 
 error: checked cast can be simplified
-  --> $DIR/checked_conversions.rs:57:13
+  --> $DIR/checked_conversions.rs:55:13
    |
 LL |     let _ = value <= u16::MAX as u32 && value as i32 == 5;
    |             ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `u16::try_from(value).is_ok()`
diff --git a/src/tools/clippy/tests/ui/cmp_owned/asymmetric_partial_eq.fixed b/src/tools/clippy/tests/ui/cmp_owned/asymmetric_partial_eq.fixed
index 3305ac9bf8b..abd059c2308 100644
--- a/src/tools/clippy/tests/ui/cmp_owned/asymmetric_partial_eq.fixed
+++ b/src/tools/clippy/tests/ui/cmp_owned/asymmetric_partial_eq.fixed
@@ -1,5 +1,5 @@
 // run-rustfix
-#![allow(unused, clippy::redundant_clone)] // See #5700
+#![allow(unused, clippy::redundant_clone, clippy::derive_partial_eq_without_eq)] // See #5700
 
 // Define the types in each module to avoid trait impls leaking between modules.
 macro_rules! impl_types {
diff --git a/src/tools/clippy/tests/ui/cmp_owned/asymmetric_partial_eq.rs b/src/tools/clippy/tests/ui/cmp_owned/asymmetric_partial_eq.rs
index 88bc2f51dd6..020ef5f840b 100644
--- a/src/tools/clippy/tests/ui/cmp_owned/asymmetric_partial_eq.rs
+++ b/src/tools/clippy/tests/ui/cmp_owned/asymmetric_partial_eq.rs
@@ -1,5 +1,5 @@
 // run-rustfix
-#![allow(unused, clippy::redundant_clone)] // See #5700
+#![allow(unused, clippy::redundant_clone, clippy::derive_partial_eq_without_eq)] // See #5700
 
 // Define the types in each module to avoid trait impls leaking between modules.
 macro_rules! impl_types {
diff --git a/src/tools/clippy/tests/ui/cmp_owned/with_suggestion.fixed b/src/tools/clippy/tests/ui/cmp_owned/with_suggestion.fixed
index 05fb96339e3..b28c4378e33 100644
--- a/src/tools/clippy/tests/ui/cmp_owned/with_suggestion.fixed
+++ b/src/tools/clippy/tests/ui/cmp_owned/with_suggestion.fixed
@@ -45,7 +45,7 @@ impl ToOwned for Foo {
     }
 }
 
-#[derive(PartialEq)]
+#[derive(PartialEq, Eq)]
 struct Bar;
 
 impl PartialEq<Foo> for Bar {
@@ -61,7 +61,7 @@ impl std::borrow::Borrow<Foo> for Bar {
     }
 }
 
-#[derive(PartialEq)]
+#[derive(PartialEq, Eq)]
 struct Baz;
 
 impl ToOwned for Baz {
diff --git a/src/tools/clippy/tests/ui/cmp_owned/with_suggestion.rs b/src/tools/clippy/tests/ui/cmp_owned/with_suggestion.rs
index 0a02825ed82..c1089010fe1 100644
--- a/src/tools/clippy/tests/ui/cmp_owned/with_suggestion.rs
+++ b/src/tools/clippy/tests/ui/cmp_owned/with_suggestion.rs
@@ -45,7 +45,7 @@ impl ToOwned for Foo {
     }
 }
 
-#[derive(PartialEq)]
+#[derive(PartialEq, Eq)]
 struct Bar;
 
 impl PartialEq<Foo> for Bar {
@@ -61,7 +61,7 @@ impl std::borrow::Borrow<Foo> for Bar {
     }
 }
 
-#[derive(PartialEq)]
+#[derive(PartialEq, Eq)]
 struct Baz;
 
 impl ToOwned for Baz {
diff --git a/src/tools/clippy/tests/ui/cmp_owned/without_suggestion.rs b/src/tools/clippy/tests/ui/cmp_owned/without_suggestion.rs
index f44a3901fb4..d8a202cb6a1 100644
--- a/src/tools/clippy/tests/ui/cmp_owned/without_suggestion.rs
+++ b/src/tools/clippy/tests/ui/cmp_owned/without_suggestion.rs
@@ -9,6 +9,10 @@ fn main() {
     let x = &&Baz;
     let y = &Baz;
     y.to_owned() == **x;
+
+    let x = 0u32;
+    let y = U32Wrapper(x);
+    let _ = U32Wrapper::from(x) == y;
 }
 
 struct Foo;
@@ -26,7 +30,7 @@ impl ToOwned for Foo {
     }
 }
 
-#[derive(PartialEq)]
+#[derive(PartialEq, Eq)]
 struct Baz;
 
 impl ToOwned for Baz {
@@ -36,7 +40,7 @@ impl ToOwned for Baz {
     }
 }
 
-#[derive(PartialEq)]
+#[derive(PartialEq, Eq)]
 struct Bar;
 
 impl PartialEq<Foo> for Bar {
@@ -51,3 +55,21 @@ impl std::borrow::Borrow<Foo> for Bar {
         &FOO
     }
 }
+
+#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
+struct U32Wrapper(u32);
+impl From<u32> for U32Wrapper {
+    fn from(x: u32) -> Self {
+        Self(x)
+    }
+}
+impl PartialEq<u32> for U32Wrapper {
+    fn eq(&self, other: &u32) -> bool {
+        self.0 == *other
+    }
+}
+impl PartialEq<U32Wrapper> for u32 {
+    fn eq(&self, other: &U32Wrapper) -> bool {
+        *self == other.0
+    }
+}
diff --git a/src/tools/clippy/tests/ui/cmp_owned/without_suggestion.stderr b/src/tools/clippy/tests/ui/cmp_owned/without_suggestion.stderr
index 2ea3d8fac0d..d2dd14d8edb 100644
--- a/src/tools/clippy/tests/ui/cmp_owned/without_suggestion.stderr
+++ b/src/tools/clippy/tests/ui/cmp_owned/without_suggestion.stderr
@@ -13,7 +13,7 @@ LL |     y.to_owned() == **x;
    |     ^^^^^^^^^^^^^^^^^^^ try implementing the comparison without allocating
 
 error: this creates an owned instance just for comparison
-  --> $DIR/without_suggestion.rs:18:9
+  --> $DIR/without_suggestion.rs:22:9
    |
 LL |         self.to_owned() == *other
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^ try implementing the comparison without allocating
diff --git a/src/tools/clippy/tests/ui/crashes/auxiliary/proc_macro_crash.rs b/src/tools/clippy/tests/ui/crashes/auxiliary/proc_macro_crash.rs
index ed8e7a708a5..5ff2af7cd82 100644
--- a/src/tools/clippy/tests/ui/crashes/auxiliary/proc_macro_crash.rs
+++ b/src/tools/clippy/tests/ui/crashes/auxiliary/proc_macro_crash.rs
@@ -12,7 +12,6 @@
 extern crate proc_macro;
 
 use proc_macro::{Delimiter, Group, Ident, Span, TokenStream, TokenTree};
-use std::iter::FromIterator;
 
 #[proc_macro]
 pub fn macro_test(input_stream: TokenStream) -> TokenStream {
diff --git a/src/tools/clippy/tests/ui/crashes/ice-6254.rs b/src/tools/clippy/tests/ui/crashes/ice-6254.rs
index c19eca43884..a2a60a16915 100644
--- a/src/tools/clippy/tests/ui/crashes/ice-6254.rs
+++ b/src/tools/clippy/tests/ui/crashes/ice-6254.rs
@@ -2,6 +2,7 @@
 // panicked at 'assertion failed: rows.iter().all(|r| r.len() == v.len())',
 // compiler/rustc_mir_build/src/thir/pattern/_match.rs:2030:5
 
+#[allow(clippy::derive_partial_eq_without_eq)]
 #[derive(PartialEq)]
 struct Foo(i32);
 const FOO_REF_REF: &&Foo = &&Foo(42);
diff --git a/src/tools/clippy/tests/ui/crashes/ice-6254.stderr b/src/tools/clippy/tests/ui/crashes/ice-6254.stderr
index 95ebf23d818..f37ab2e9b0c 100644
--- a/src/tools/clippy/tests/ui/crashes/ice-6254.stderr
+++ b/src/tools/clippy/tests/ui/crashes/ice-6254.stderr
@@ -1,5 +1,5 @@
 error: to use a constant of type `Foo` in a pattern, `Foo` must be annotated with `#[derive(PartialEq, Eq)]`
-  --> $DIR/ice-6254.rs:12:9
+  --> $DIR/ice-6254.rs:13:9
    |
 LL |         FOO_REF_REF => {},
    |         ^^^^^^^^^^^
diff --git a/src/tools/clippy/tests/ui/crashes/ice-8821.rs b/src/tools/clippy/tests/ui/crashes/ice-8821.rs
new file mode 100644
index 00000000000..fb87b79aeed
--- /dev/null
+++ b/src/tools/clippy/tests/ui/crashes/ice-8821.rs
@@ -0,0 +1,8 @@
+#![warn(clippy::let_unit_value)]
+
+fn f() {}
+static FN: fn() = f;
+
+fn main() {
+    let _: () = FN();
+}
diff --git a/src/tools/clippy/tests/ui/crashes/ice-8821.stderr b/src/tools/clippy/tests/ui/crashes/ice-8821.stderr
new file mode 100644
index 00000000000..486096e0a06
--- /dev/null
+++ b/src/tools/clippy/tests/ui/crashes/ice-8821.stderr
@@ -0,0 +1,10 @@
+error: this let-binding has unit value
+  --> $DIR/ice-8821.rs:7:5
+   |
+LL |     let _: () = FN();
+   |     ^^^^^^^^^^^^^^^^^ help: omit the `let` binding: `FN();`
+   |
+   = note: `-D clippy::let-unit-value` implied by `-D warnings`
+
+error: aborting due to previous error
+
diff --git a/src/tools/clippy/tests/ui/dbg_macro.rs b/src/tools/clippy/tests/ui/dbg_macro.rs
index baf01174b67..25294e8c766 100644
--- a/src/tools/clippy/tests/ui/dbg_macro.rs
+++ b/src/tools/clippy/tests/ui/dbg_macro.rs
@@ -46,3 +46,15 @@ mod issue7274 {
 pub fn issue8481() {
     dbg!(1);
 }
+
+#[cfg(test)]
+fn foo2() {
+    dbg!(1);
+}
+
+#[cfg(test)]
+mod mod1 {
+    fn func() {
+        dbg!(1);
+    }
+}
diff --git a/src/tools/clippy/tests/ui/derive_hash_xor_eq.rs b/src/tools/clippy/tests/ui/derive_hash_xor_eq.rs
index 10abe22d53e..813ddc56646 100644
--- a/src/tools/clippy/tests/ui/derive_hash_xor_eq.rs
+++ b/src/tools/clippy/tests/ui/derive_hash_xor_eq.rs
@@ -1,3 +1,5 @@
+#![allow(clippy::derive_partial_eq_without_eq)]
+
 #[derive(PartialEq, Hash)]
 struct Foo;
 
diff --git a/src/tools/clippy/tests/ui/derive_hash_xor_eq.stderr b/src/tools/clippy/tests/ui/derive_hash_xor_eq.stderr
index b383072ca4d..e5184bd1407 100644
--- a/src/tools/clippy/tests/ui/derive_hash_xor_eq.stderr
+++ b/src/tools/clippy/tests/ui/derive_hash_xor_eq.stderr
@@ -1,12 +1,12 @@
 error: you are deriving `Hash` but have implemented `PartialEq` explicitly
-  --> $DIR/derive_hash_xor_eq.rs:10:10
+  --> $DIR/derive_hash_xor_eq.rs:12:10
    |
 LL | #[derive(Hash)]
    |          ^^^^
    |
    = note: `#[deny(clippy::derive_hash_xor_eq)]` on by default
 note: `PartialEq` implemented here
-  --> $DIR/derive_hash_xor_eq.rs:13:1
+  --> $DIR/derive_hash_xor_eq.rs:15:1
    |
 LL | / impl PartialEq for Bar {
 LL | |     fn eq(&self, _: &Bar) -> bool {
@@ -17,13 +17,13 @@ LL | | }
    = note: this error originates in the derive macro `Hash` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error: you are deriving `Hash` but have implemented `PartialEq` explicitly
-  --> $DIR/derive_hash_xor_eq.rs:19:10
+  --> $DIR/derive_hash_xor_eq.rs:21:10
    |
 LL | #[derive(Hash)]
    |          ^^^^
    |
 note: `PartialEq` implemented here
-  --> $DIR/derive_hash_xor_eq.rs:22:1
+  --> $DIR/derive_hash_xor_eq.rs:24:1
    |
 LL | / impl PartialEq<Baz> for Baz {
 LL | |     fn eq(&self, _: &Baz) -> bool {
@@ -34,7 +34,7 @@ LL | | }
    = note: this error originates in the derive macro `Hash` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error: you are implementing `Hash` explicitly but have derived `PartialEq`
-  --> $DIR/derive_hash_xor_eq.rs:31:1
+  --> $DIR/derive_hash_xor_eq.rs:33:1
    |
 LL | / impl std::hash::Hash for Bah {
 LL | |     fn hash<H: std::hash::Hasher>(&self, _: &mut H) {}
@@ -42,14 +42,14 @@ LL | | }
    | |_^
    |
 note: `PartialEq` implemented here
-  --> $DIR/derive_hash_xor_eq.rs:28:10
+  --> $DIR/derive_hash_xor_eq.rs:30:10
    |
 LL | #[derive(PartialEq)]
    |          ^^^^^^^^^
    = note: this error originates in the derive macro `PartialEq` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error: you are implementing `Hash` explicitly but have derived `PartialEq`
-  --> $DIR/derive_hash_xor_eq.rs:49:5
+  --> $DIR/derive_hash_xor_eq.rs:51:5
    |
 LL | /     impl Hash for Foo3 {
 LL | |         fn hash<H: std::hash::Hasher>(&self, _: &mut H) {}
@@ -57,7 +57,7 @@ LL | |     }
    | |_____^
    |
 note: `PartialEq` implemented here
-  --> $DIR/derive_hash_xor_eq.rs:46:14
+  --> $DIR/derive_hash_xor_eq.rs:48:14
    |
 LL |     #[derive(PartialEq)]
    |              ^^^^^^^^^
diff --git a/src/tools/clippy/tests/ui/derive_partial_eq_without_eq.fixed b/src/tools/clippy/tests/ui/derive_partial_eq_without_eq.fixed
new file mode 100644
index 00000000000..7d4d1b3b649
--- /dev/null
+++ b/src/tools/clippy/tests/ui/derive_partial_eq_without_eq.fixed
@@ -0,0 +1,98 @@
+// run-rustfix
+
+#![allow(unused)]
+#![warn(clippy::derive_partial_eq_without_eq)]
+
+// Don't warn on structs that aren't PartialEq
+struct NotPartialEq {
+    foo: u32,
+    bar: String,
+}
+
+// Eq can be derived but is missing
+#[derive(Debug, PartialEq, Eq)]
+struct MissingEq {
+    foo: u32,
+    bar: String,
+}
+
+// Eq is derived
+#[derive(PartialEq, Eq)]
+struct NotMissingEq {
+    foo: u32,
+    bar: String,
+}
+
+// Eq is manually implemented
+#[derive(PartialEq)]
+struct ManualEqImpl {
+    foo: u32,
+    bar: String,
+}
+
+impl Eq for ManualEqImpl {}
+
+// Cannot be Eq because f32 isn't Eq
+#[derive(PartialEq)]
+struct CannotBeEq {
+    foo: u32,
+    bar: f32,
+}
+
+// Don't warn if PartialEq is manually implemented
+struct ManualPartialEqImpl {
+    foo: u32,
+    bar: String,
+}
+
+impl PartialEq for ManualPartialEqImpl {
+    fn eq(&self, other: &Self) -> bool {
+        self.foo == other.foo && self.bar == other.bar
+    }
+}
+
+// Generic fields should be properly checked for Eq-ness
+#[derive(PartialEq)]
+struct GenericNotEq<T: Eq, U: PartialEq> {
+    foo: T,
+    bar: U,
+}
+
+#[derive(PartialEq, Eq)]
+struct GenericEq<T: Eq, U: Eq> {
+    foo: T,
+    bar: U,
+}
+
+#[derive(PartialEq, Eq)]
+struct TupleStruct(u32);
+
+#[derive(PartialEq, Eq)]
+struct GenericTupleStruct<T: Eq>(T);
+
+#[derive(PartialEq)]
+struct TupleStructNotEq(f32);
+
+#[derive(PartialEq, Eq)]
+enum Enum {
+    Foo(u32),
+    Bar { a: String, b: () },
+}
+
+#[derive(PartialEq, Eq)]
+enum GenericEnum<T: Eq, U: Eq, V: Eq> {
+    Foo(T),
+    Bar { a: U, b: V },
+}
+
+#[derive(PartialEq)]
+enum EnumNotEq {
+    Foo(u32),
+    Bar { a: String, b: f32 },
+}
+
+// Ensure that rustfix works properly when `PartialEq` has other derives on either side
+#[derive(Debug, PartialEq, Eq, Clone)]
+struct RustFixWithOtherDerives;
+
+fn main() {}
diff --git a/src/tools/clippy/tests/ui/derive_partial_eq_without_eq.rs b/src/tools/clippy/tests/ui/derive_partial_eq_without_eq.rs
new file mode 100644
index 00000000000..ab4e1df1ca4
--- /dev/null
+++ b/src/tools/clippy/tests/ui/derive_partial_eq_without_eq.rs
@@ -0,0 +1,98 @@
+// run-rustfix
+
+#![allow(unused)]
+#![warn(clippy::derive_partial_eq_without_eq)]
+
+// Don't warn on structs that aren't PartialEq
+struct NotPartialEq {
+    foo: u32,
+    bar: String,
+}
+
+// Eq can be derived but is missing
+#[derive(Debug, PartialEq)]
+struct MissingEq {
+    foo: u32,
+    bar: String,
+}
+
+// Eq is derived
+#[derive(PartialEq, Eq)]
+struct NotMissingEq {
+    foo: u32,
+    bar: String,
+}
+
+// Eq is manually implemented
+#[derive(PartialEq)]
+struct ManualEqImpl {
+    foo: u32,
+    bar: String,
+}
+
+impl Eq for ManualEqImpl {}
+
+// Cannot be Eq because f32 isn't Eq
+#[derive(PartialEq)]
+struct CannotBeEq {
+    foo: u32,
+    bar: f32,
+}
+
+// Don't warn if PartialEq is manually implemented
+struct ManualPartialEqImpl {
+    foo: u32,
+    bar: String,
+}
+
+impl PartialEq for ManualPartialEqImpl {
+    fn eq(&self, other: &Self) -> bool {
+        self.foo == other.foo && self.bar == other.bar
+    }
+}
+
+// Generic fields should be properly checked for Eq-ness
+#[derive(PartialEq)]
+struct GenericNotEq<T: Eq, U: PartialEq> {
+    foo: T,
+    bar: U,
+}
+
+#[derive(PartialEq)]
+struct GenericEq<T: Eq, U: Eq> {
+    foo: T,
+    bar: U,
+}
+
+#[derive(PartialEq)]
+struct TupleStruct(u32);
+
+#[derive(PartialEq)]
+struct GenericTupleStruct<T: Eq>(T);
+
+#[derive(PartialEq)]
+struct TupleStructNotEq(f32);
+
+#[derive(PartialEq)]
+enum Enum {
+    Foo(u32),
+    Bar { a: String, b: () },
+}
+
+#[derive(PartialEq)]
+enum GenericEnum<T: Eq, U: Eq, V: Eq> {
+    Foo(T),
+    Bar { a: U, b: V },
+}
+
+#[derive(PartialEq)]
+enum EnumNotEq {
+    Foo(u32),
+    Bar { a: String, b: f32 },
+}
+
+// Ensure that rustfix works properly when `PartialEq` has other derives on either side
+#[derive(Debug, PartialEq, Clone)]
+struct RustFixWithOtherDerives;
+
+fn main() {}
diff --git a/src/tools/clippy/tests/ui/derive_partial_eq_without_eq.stderr b/src/tools/clippy/tests/ui/derive_partial_eq_without_eq.stderr
new file mode 100644
index 00000000000..bf55165890a
--- /dev/null
+++ b/src/tools/clippy/tests/ui/derive_partial_eq_without_eq.stderr
@@ -0,0 +1,46 @@
+error: you are deriving `PartialEq` and can implement `Eq`
+  --> $DIR/derive_partial_eq_without_eq.rs:13:17
+   |
+LL | #[derive(Debug, PartialEq)]
+   |                 ^^^^^^^^^ help: consider deriving `Eq` as well: `PartialEq, Eq`
+   |
+   = note: `-D clippy::derive-partial-eq-without-eq` implied by `-D warnings`
+
+error: you are deriving `PartialEq` and can implement `Eq`
+  --> $DIR/derive_partial_eq_without_eq.rs:61:10
+   |
+LL | #[derive(PartialEq)]
+   |          ^^^^^^^^^ help: consider deriving `Eq` as well: `PartialEq, Eq`
+
+error: you are deriving `PartialEq` and can implement `Eq`
+  --> $DIR/derive_partial_eq_without_eq.rs:67:10
+   |
+LL | #[derive(PartialEq)]
+   |          ^^^^^^^^^ help: consider deriving `Eq` as well: `PartialEq, Eq`
+
+error: you are deriving `PartialEq` and can implement `Eq`
+  --> $DIR/derive_partial_eq_without_eq.rs:70:10
+   |
+LL | #[derive(PartialEq)]
+   |          ^^^^^^^^^ help: consider deriving `Eq` as well: `PartialEq, Eq`
+
+error: you are deriving `PartialEq` and can implement `Eq`
+  --> $DIR/derive_partial_eq_without_eq.rs:76:10
+   |
+LL | #[derive(PartialEq)]
+   |          ^^^^^^^^^ help: consider deriving `Eq` as well: `PartialEq, Eq`
+
+error: you are deriving `PartialEq` and can implement `Eq`
+  --> $DIR/derive_partial_eq_without_eq.rs:82:10
+   |
+LL | #[derive(PartialEq)]
+   |          ^^^^^^^^^ help: consider deriving `Eq` as well: `PartialEq, Eq`
+
+error: you are deriving `PartialEq` and can implement `Eq`
+  --> $DIR/derive_partial_eq_without_eq.rs:95:17
+   |
+LL | #[derive(Debug, PartialEq, Clone)]
+   |                 ^^^^^^^^^ help: consider deriving `Eq` as well: `PartialEq, Eq`
+
+error: aborting due to 7 previous errors
+
diff --git a/src/tools/clippy/tests/ui/equatable_if_let.fixed b/src/tools/clippy/tests/ui/equatable_if_let.fixed
index 88918d9671e..47bf25e409b 100644
--- a/src/tools/clippy/tests/ui/equatable_if_let.fixed
+++ b/src/tools/clippy/tests/ui/equatable_if_let.fixed
@@ -1,6 +1,6 @@
 // run-rustfix
 
-#![allow(unused_variables, dead_code)]
+#![allow(unused_variables, dead_code, clippy::derive_partial_eq_without_eq)]
 #![warn(clippy::equatable_if_let)]
 
 use std::cmp::Ordering;
diff --git a/src/tools/clippy/tests/ui/equatable_if_let.rs b/src/tools/clippy/tests/ui/equatable_if_let.rs
index 9a7ab75ef45..d498bca2455 100644
--- a/src/tools/clippy/tests/ui/equatable_if_let.rs
+++ b/src/tools/clippy/tests/ui/equatable_if_let.rs
@@ -1,6 +1,6 @@
 // run-rustfix
 
-#![allow(unused_variables, dead_code)]
+#![allow(unused_variables, dead_code, clippy::derive_partial_eq_without_eq)]
 #![warn(clippy::equatable_if_let)]
 
 use std::cmp::Ordering;
diff --git a/src/tools/clippy/tests/ui/from_iter_instead_of_collect.fixed b/src/tools/clippy/tests/ui/from_iter_instead_of_collect.fixed
index 12db43b5343..403c3b3e443 100644
--- a/src/tools/clippy/tests/ui/from_iter_instead_of_collect.fixed
+++ b/src/tools/clippy/tests/ui/from_iter_instead_of_collect.fixed
@@ -4,7 +4,6 @@
 #![allow(unused_imports)]
 
 use std::collections::{BTreeMap, BTreeSet, HashMap, VecDeque};
-use std::iter::FromIterator;
 
 struct Foo(Vec<bool>);
 
diff --git a/src/tools/clippy/tests/ui/from_iter_instead_of_collect.rs b/src/tools/clippy/tests/ui/from_iter_instead_of_collect.rs
index f5ec190e0cd..fefc7b01a65 100644
--- a/src/tools/clippy/tests/ui/from_iter_instead_of_collect.rs
+++ b/src/tools/clippy/tests/ui/from_iter_instead_of_collect.rs
@@ -4,7 +4,6 @@
 #![allow(unused_imports)]
 
 use std::collections::{BTreeMap, BTreeSet, HashMap, VecDeque};
-use std::iter::FromIterator;
 
 struct Foo(Vec<bool>);
 
diff --git a/src/tools/clippy/tests/ui/from_iter_instead_of_collect.stderr b/src/tools/clippy/tests/ui/from_iter_instead_of_collect.stderr
index 8f08ac8c3ff..8aa3c3c01f8 100644
--- a/src/tools/clippy/tests/ui/from_iter_instead_of_collect.stderr
+++ b/src/tools/clippy/tests/ui/from_iter_instead_of_collect.stderr
@@ -1,5 +1,5 @@
 error: usage of `FromIterator::from_iter`
-  --> $DIR/from_iter_instead_of_collect.rs:19:9
+  --> $DIR/from_iter_instead_of_collect.rs:18:9
    |
 LL |         <Self as FromIterator<bool>>::from_iter(iter.into_iter().copied())
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `.collect()` instead of `::from_iter()`: `iter.into_iter().copied().collect::<Self>()`
@@ -7,85 +7,85 @@ LL |         <Self as FromIterator<bool>>::from_iter(iter.into_iter().copied())
    = note: `-D clippy::from-iter-instead-of-collect` implied by `-D warnings`
 
 error: usage of `FromIterator::from_iter`
-  --> $DIR/from_iter_instead_of_collect.rs:25:13
+  --> $DIR/from_iter_instead_of_collect.rs:24:13
    |
 LL |     let _ = Vec::from_iter(iter_expr);
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `.collect()` instead of `::from_iter()`: `iter_expr.collect::<Vec<_>>()`
 
 error: usage of `FromIterator::from_iter`
-  --> $DIR/from_iter_instead_of_collect.rs:27:13
+  --> $DIR/from_iter_instead_of_collect.rs:26:13
    |
 LL |     let _ = HashMap::<usize, &i8>::from_iter(vec![5, 5, 5, 5].iter().enumerate());
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `.collect()` instead of `::from_iter()`: `vec![5, 5, 5, 5].iter().enumerate().collect::<HashMap<usize, &i8>>()`
 
 error: usage of `FromIterator::from_iter`
-  --> $DIR/from_iter_instead_of_collect.rs:32:19
+  --> $DIR/from_iter_instead_of_collect.rs:31:19
    |
 LL |     assert_eq!(a, Vec::from_iter(0..3));
    |                   ^^^^^^^^^^^^^^^^^^^^ help: use `.collect()` instead of `::from_iter()`: `(0..3).collect::<Vec<_>>()`
 
 error: usage of `FromIterator::from_iter`
-  --> $DIR/from_iter_instead_of_collect.rs:33:19
+  --> $DIR/from_iter_instead_of_collect.rs:32:19
    |
 LL |     assert_eq!(a, Vec::<i32>::from_iter(0..3));
    |                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `.collect()` instead of `::from_iter()`: `(0..3).collect::<Vec<i32>>()`
 
 error: usage of `FromIterator::from_iter`
-  --> $DIR/from_iter_instead_of_collect.rs:35:17
+  --> $DIR/from_iter_instead_of_collect.rs:34:17
    |
 LL |     let mut b = VecDeque::from_iter(0..3);
    |                 ^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `.collect()` instead of `::from_iter()`: `(0..3).collect::<VecDeque<_>>()`
 
 error: usage of `FromIterator::from_iter`
-  --> $DIR/from_iter_instead_of_collect.rs:38:17
+  --> $DIR/from_iter_instead_of_collect.rs:37:17
    |
 LL |     let mut b = VecDeque::<i32>::from_iter(0..3);
    |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `.collect()` instead of `::from_iter()`: `(0..3).collect::<VecDeque<i32>>()`
 
 error: usage of `FromIterator::from_iter`
-  --> $DIR/from_iter_instead_of_collect.rs:43:21
+  --> $DIR/from_iter_instead_of_collect.rs:42:21
    |
 LL |         let mut b = collections::VecDeque::<i32>::from_iter(0..3);
    |                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `.collect()` instead of `::from_iter()`: `(0..3).collect::<collections::VecDeque<i32>>()`
 
 error: usage of `FromIterator::from_iter`
-  --> $DIR/from_iter_instead_of_collect.rs:48:14
+  --> $DIR/from_iter_instead_of_collect.rs:47:14
    |
 LL |     let bm = BTreeMap::from_iter(values.iter().cloned());
    |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `.collect()` instead of `::from_iter()`: `values.iter().cloned().collect::<BTreeMap<_, _>>()`
 
 error: usage of `FromIterator::from_iter`
-  --> $DIR/from_iter_instead_of_collect.rs:49:19
+  --> $DIR/from_iter_instead_of_collect.rs:48:19
    |
 LL |     let mut bar = BTreeMap::from_iter(bm.range(0..2));
    |                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `.collect()` instead of `::from_iter()`: `bm.range(0..2).collect::<BTreeMap<_, _>>()`
 
 error: usage of `FromIterator::from_iter`
-  --> $DIR/from_iter_instead_of_collect.rs:52:19
+  --> $DIR/from_iter_instead_of_collect.rs:51:19
    |
 LL |     let mut bts = BTreeSet::from_iter(0..3);
    |                   ^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `.collect()` instead of `::from_iter()`: `(0..3).collect::<BTreeSet<_>>()`
 
 error: usage of `FromIterator::from_iter`
-  --> $DIR/from_iter_instead_of_collect.rs:56:17
+  --> $DIR/from_iter_instead_of_collect.rs:55:17
    |
 LL |         let _ = collections::BTreeSet::from_iter(0..3);
    |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `.collect()` instead of `::from_iter()`: `(0..3).collect::<collections::BTreeSet<_>>()`
 
 error: usage of `FromIterator::from_iter`
-  --> $DIR/from_iter_instead_of_collect.rs:57:17
+  --> $DIR/from_iter_instead_of_collect.rs:56:17
    |
 LL |         let _ = collections::BTreeSet::<u32>::from_iter(0..3);
    |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `.collect()` instead of `::from_iter()`: `(0..3).collect::<collections::BTreeSet<u32>>()`
 
 error: usage of `FromIterator::from_iter`
-  --> $DIR/from_iter_instead_of_collect.rs:60:15
+  --> $DIR/from_iter_instead_of_collect.rs:59:15
    |
 LL |     for _i in Vec::from_iter([1, 2, 3].iter()) {}
    |               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `.collect()` instead of `::from_iter()`: `[1, 2, 3].iter().collect::<Vec<_>>()`
 
 error: usage of `FromIterator::from_iter`
-  --> $DIR/from_iter_instead_of_collect.rs:61:15
+  --> $DIR/from_iter_instead_of_collect.rs:60:15
    |
 LL |     for _i in Vec::<&i32>::from_iter([1, 2, 3].iter()) {}
    |               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `.collect()` instead of `::from_iter()`: `[1, 2, 3].iter().collect::<Vec<&i32>>()`
diff --git a/src/tools/clippy/tests/ui/get_unwrap.fixed b/src/tools/clippy/tests/ui/get_unwrap.fixed
index c3a36dcabd1..8f165d67589 100644
--- a/src/tools/clippy/tests/ui/get_unwrap.fixed
+++ b/src/tools/clippy/tests/ui/get_unwrap.fixed
@@ -7,7 +7,6 @@
 use std::collections::BTreeMap;
 use std::collections::HashMap;
 use std::collections::VecDeque;
-use std::iter::FromIterator;
 
 struct GetFalsePositive {
     arr: [u32; 3],
diff --git a/src/tools/clippy/tests/ui/get_unwrap.rs b/src/tools/clippy/tests/ui/get_unwrap.rs
index d77a202aa39..786749daa74 100644
--- a/src/tools/clippy/tests/ui/get_unwrap.rs
+++ b/src/tools/clippy/tests/ui/get_unwrap.rs
@@ -7,7 +7,6 @@
 use std::collections::BTreeMap;
 use std::collections::HashMap;
 use std::collections::VecDeque;
-use std::iter::FromIterator;
 
 struct GetFalsePositive {
     arr: [u32; 3],
diff --git a/src/tools/clippy/tests/ui/get_unwrap.stderr b/src/tools/clippy/tests/ui/get_unwrap.stderr
index cb5f44fbd59..ea8fec52735 100644
--- a/src/tools/clippy/tests/ui/get_unwrap.stderr
+++ b/src/tools/clippy/tests/ui/get_unwrap.stderr
@@ -1,5 +1,5 @@
 error: called `.get().unwrap()` on a slice. Using `[]` is more clear and more concise
-  --> $DIR/get_unwrap.rs:36:17
+  --> $DIR/get_unwrap.rs:35:17
    |
 LL |         let _ = boxed_slice.get(1).unwrap();
    |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `&boxed_slice[1]`
@@ -11,7 +11,7 @@ LL | #![deny(clippy::get_unwrap)]
    |         ^^^^^^^^^^^^^^^^^^
 
 error: used `unwrap()` on `an Option` value
-  --> $DIR/get_unwrap.rs:36:17
+  --> $DIR/get_unwrap.rs:35:17
    |
 LL |         let _ = boxed_slice.get(1).unwrap();
    |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -20,13 +20,13 @@ LL |         let _ = boxed_slice.get(1).unwrap();
    = help: if you don't want to handle the `None` case gracefully, consider using `expect()` to provide a better panic message
 
 error: called `.get().unwrap()` on a slice. Using `[]` is more clear and more concise
-  --> $DIR/get_unwrap.rs:37:17
+  --> $DIR/get_unwrap.rs:36:17
    |
 LL |         let _ = some_slice.get(0).unwrap();
    |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `&some_slice[0]`
 
 error: used `unwrap()` on `an Option` value
-  --> $DIR/get_unwrap.rs:37:17
+  --> $DIR/get_unwrap.rs:36:17
    |
 LL |         let _ = some_slice.get(0).unwrap();
    |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -34,13 +34,13 @@ LL |         let _ = some_slice.get(0).unwrap();
    = help: if you don't want to handle the `None` case gracefully, consider using `expect()` to provide a better panic message
 
 error: called `.get().unwrap()` on a Vec. Using `[]` is more clear and more concise
-  --> $DIR/get_unwrap.rs:38:17
+  --> $DIR/get_unwrap.rs:37:17
    |
 LL |         let _ = some_vec.get(0).unwrap();
    |                 ^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `&some_vec[0]`
 
 error: used `unwrap()` on `an Option` value
-  --> $DIR/get_unwrap.rs:38:17
+  --> $DIR/get_unwrap.rs:37:17
    |
 LL |         let _ = some_vec.get(0).unwrap();
    |                 ^^^^^^^^^^^^^^^^^^^^^^^^
@@ -48,13 +48,13 @@ LL |         let _ = some_vec.get(0).unwrap();
    = help: if you don't want to handle the `None` case gracefully, consider using `expect()` to provide a better panic message
 
 error: called `.get().unwrap()` on a VecDeque. Using `[]` is more clear and more concise
-  --> $DIR/get_unwrap.rs:39:17
+  --> $DIR/get_unwrap.rs:38:17
    |
 LL |         let _ = some_vecdeque.get(0).unwrap();
    |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `&some_vecdeque[0]`
 
 error: used `unwrap()` on `an Option` value
-  --> $DIR/get_unwrap.rs:39:17
+  --> $DIR/get_unwrap.rs:38:17
    |
 LL |         let _ = some_vecdeque.get(0).unwrap();
    |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -62,13 +62,13 @@ LL |         let _ = some_vecdeque.get(0).unwrap();
    = help: if you don't want to handle the `None` case gracefully, consider using `expect()` to provide a better panic message
 
 error: called `.get().unwrap()` on a HashMap. Using `[]` is more clear and more concise
-  --> $DIR/get_unwrap.rs:40:17
+  --> $DIR/get_unwrap.rs:39:17
    |
 LL |         let _ = some_hashmap.get(&1).unwrap();
    |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `&some_hashmap[&1]`
 
 error: used `unwrap()` on `an Option` value
-  --> $DIR/get_unwrap.rs:40:17
+  --> $DIR/get_unwrap.rs:39:17
    |
 LL |         let _ = some_hashmap.get(&1).unwrap();
    |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -76,13 +76,13 @@ LL |         let _ = some_hashmap.get(&1).unwrap();
    = help: if you don't want to handle the `None` case gracefully, consider using `expect()` to provide a better panic message
 
 error: called `.get().unwrap()` on a BTreeMap. Using `[]` is more clear and more concise
-  --> $DIR/get_unwrap.rs:41:17
+  --> $DIR/get_unwrap.rs:40:17
    |
 LL |         let _ = some_btreemap.get(&1).unwrap();
    |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `&some_btreemap[&1]`
 
 error: used `unwrap()` on `an Option` value
-  --> $DIR/get_unwrap.rs:41:17
+  --> $DIR/get_unwrap.rs:40:17
    |
 LL |         let _ = some_btreemap.get(&1).unwrap();
    |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -90,13 +90,13 @@ LL |         let _ = some_btreemap.get(&1).unwrap();
    = help: if you don't want to handle the `None` case gracefully, consider using `expect()` to provide a better panic message
 
 error: called `.get().unwrap()` on a slice. Using `[]` is more clear and more concise
-  --> $DIR/get_unwrap.rs:45:21
+  --> $DIR/get_unwrap.rs:44:21
    |
 LL |         let _: u8 = *boxed_slice.get(1).unwrap();
    |                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `boxed_slice[1]`
 
 error: used `unwrap()` on `an Option` value
-  --> $DIR/get_unwrap.rs:45:22
+  --> $DIR/get_unwrap.rs:44:22
    |
 LL |         let _: u8 = *boxed_slice.get(1).unwrap();
    |                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -104,13 +104,13 @@ LL |         let _: u8 = *boxed_slice.get(1).unwrap();
    = help: if you don't want to handle the `None` case gracefully, consider using `expect()` to provide a better panic message
 
 error: called `.get_mut().unwrap()` on a slice. Using `[]` is more clear and more concise
-  --> $DIR/get_unwrap.rs:50:9
+  --> $DIR/get_unwrap.rs:49:9
    |
 LL |         *boxed_slice.get_mut(0).unwrap() = 1;
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `boxed_slice[0]`
 
 error: used `unwrap()` on `an Option` value
-  --> $DIR/get_unwrap.rs:50:10
+  --> $DIR/get_unwrap.rs:49:10
    |
 LL |         *boxed_slice.get_mut(0).unwrap() = 1;
    |          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -118,13 +118,13 @@ LL |         *boxed_slice.get_mut(0).unwrap() = 1;
    = help: if you don't want to handle the `None` case gracefully, consider using `expect()` to provide a better panic message
 
 error: called `.get_mut().unwrap()` on a slice. Using `[]` is more clear and more concise
-  --> $DIR/get_unwrap.rs:51:9
+  --> $DIR/get_unwrap.rs:50:9
    |
 LL |         *some_slice.get_mut(0).unwrap() = 1;
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `some_slice[0]`
 
 error: used `unwrap()` on `an Option` value
-  --> $DIR/get_unwrap.rs:51:10
+  --> $DIR/get_unwrap.rs:50:10
    |
 LL |         *some_slice.get_mut(0).unwrap() = 1;
    |          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -132,13 +132,13 @@ LL |         *some_slice.get_mut(0).unwrap() = 1;
    = help: if you don't want to handle the `None` case gracefully, consider using `expect()` to provide a better panic message
 
 error: called `.get_mut().unwrap()` on a Vec. Using `[]` is more clear and more concise
-  --> $DIR/get_unwrap.rs:52:9
+  --> $DIR/get_unwrap.rs:51:9
    |
 LL |         *some_vec.get_mut(0).unwrap() = 1;
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `some_vec[0]`
 
 error: used `unwrap()` on `an Option` value
-  --> $DIR/get_unwrap.rs:52:10
+  --> $DIR/get_unwrap.rs:51:10
    |
 LL |         *some_vec.get_mut(0).unwrap() = 1;
    |          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -146,13 +146,13 @@ LL |         *some_vec.get_mut(0).unwrap() = 1;
    = help: if you don't want to handle the `None` case gracefully, consider using `expect()` to provide a better panic message
 
 error: called `.get_mut().unwrap()` on a VecDeque. Using `[]` is more clear and more concise
-  --> $DIR/get_unwrap.rs:53:9
+  --> $DIR/get_unwrap.rs:52:9
    |
 LL |         *some_vecdeque.get_mut(0).unwrap() = 1;
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `some_vecdeque[0]`
 
 error: used `unwrap()` on `an Option` value
-  --> $DIR/get_unwrap.rs:53:10
+  --> $DIR/get_unwrap.rs:52:10
    |
 LL |         *some_vecdeque.get_mut(0).unwrap() = 1;
    |          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -160,13 +160,13 @@ LL |         *some_vecdeque.get_mut(0).unwrap() = 1;
    = help: if you don't want to handle the `None` case gracefully, consider using `expect()` to provide a better panic message
 
 error: called `.get().unwrap()` on a Vec. Using `[]` is more clear and more concise
-  --> $DIR/get_unwrap.rs:65:17
+  --> $DIR/get_unwrap.rs:64:17
    |
 LL |         let _ = some_vec.get(0..1).unwrap().to_vec();
    |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `some_vec[0..1]`
 
 error: used `unwrap()` on `an Option` value
-  --> $DIR/get_unwrap.rs:65:17
+  --> $DIR/get_unwrap.rs:64:17
    |
 LL |         let _ = some_vec.get(0..1).unwrap().to_vec();
    |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -174,13 +174,13 @@ LL |         let _ = some_vec.get(0..1).unwrap().to_vec();
    = help: if you don't want to handle the `None` case gracefully, consider using `expect()` to provide a better panic message
 
 error: called `.get_mut().unwrap()` on a Vec. Using `[]` is more clear and more concise
-  --> $DIR/get_unwrap.rs:66:17
+  --> $DIR/get_unwrap.rs:65:17
    |
 LL |         let _ = some_vec.get_mut(0..1).unwrap().to_vec();
    |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `some_vec[0..1]`
 
 error: used `unwrap()` on `an Option` value
-  --> $DIR/get_unwrap.rs:66:17
+  --> $DIR/get_unwrap.rs:65:17
    |
 LL |         let _ = some_vec.get_mut(0..1).unwrap().to_vec();
    |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
diff --git a/src/tools/clippy/tests/ui/infinite_iter.rs b/src/tools/clippy/tests/ui/infinite_iter.rs
index 1fe68897765..a1e5fad0c62 100644
--- a/src/tools/clippy/tests/ui/infinite_iter.rs
+++ b/src/tools/clippy/tests/ui/infinite_iter.rs
@@ -51,7 +51,6 @@ fn main() {
 
 mod finite_collect {
     use std::collections::HashSet;
-    use std::iter::FromIterator;
 
     struct C;
     impl FromIterator<i32> for C {
diff --git a/src/tools/clippy/tests/ui/infinite_iter.stderr b/src/tools/clippy/tests/ui/infinite_iter.stderr
index 5f5e7ac9f25..ba277e36339 100644
--- a/src/tools/clippy/tests/ui/infinite_iter.stderr
+++ b/src/tools/clippy/tests/ui/infinite_iter.stderr
@@ -98,7 +98,7 @@ LL |     (0..).all(|x| x == 24); // maybe infinite iter
    |     ^^^^^^^^^^^^^^^^^^^^^^
 
 error: infinite iteration detected
-  --> $DIR/infinite_iter.rs:64:31
+  --> $DIR/infinite_iter.rs:63:31
    |
 LL |         let _: HashSet<i32> = (0..).collect(); // Infinite iter
    |                               ^^^^^^^^^^^^^^^
diff --git a/src/tools/clippy/tests/ui/manual_str_repeat.fixed b/src/tools/clippy/tests/ui/manual_str_repeat.fixed
index dc140257f32..0704ba2f933 100644
--- a/src/tools/clippy/tests/ui/manual_str_repeat.fixed
+++ b/src/tools/clippy/tests/ui/manual_str_repeat.fixed
@@ -4,7 +4,7 @@
 #![warn(clippy::manual_str_repeat)]
 
 use std::borrow::Cow;
-use std::iter::{repeat, FromIterator};
+use std::iter::repeat;
 
 fn main() {
     let _: String = "test".repeat(10);
diff --git a/src/tools/clippy/tests/ui/manual_str_repeat.rs b/src/tools/clippy/tests/ui/manual_str_repeat.rs
index 0d69c989b2e..f522be439aa 100644
--- a/src/tools/clippy/tests/ui/manual_str_repeat.rs
+++ b/src/tools/clippy/tests/ui/manual_str_repeat.rs
@@ -4,7 +4,7 @@
 #![warn(clippy::manual_str_repeat)]
 
 use std::borrow::Cow;
-use std::iter::{repeat, FromIterator};
+use std::iter::repeat;
 
 fn main() {
     let _: String = std::iter::repeat("test").take(10).collect();
diff --git a/src/tools/clippy/tests/ui/map_err.rs b/src/tools/clippy/tests/ui/map_err.rs
index 00e037843f8..bb35ab1a14e 100644
--- a/src/tools/clippy/tests/ui/map_err.rs
+++ b/src/tools/clippy/tests/ui/map_err.rs
@@ -1,6 +1,5 @@
 #![warn(clippy::map_err_ignore)]
 #![allow(clippy::unnecessary_wraps)]
-use std::convert::TryFrom;
 use std::error::Error;
 use std::fmt;
 
diff --git a/src/tools/clippy/tests/ui/map_err.stderr b/src/tools/clippy/tests/ui/map_err.stderr
index 37e87e64de2..c035840521e 100644
--- a/src/tools/clippy/tests/ui/map_err.stderr
+++ b/src/tools/clippy/tests/ui/map_err.stderr
@@ -1,5 +1,5 @@
 error: `map_err(|_|...` wildcard pattern discards the original error
-  --> $DIR/map_err.rs:23:32
+  --> $DIR/map_err.rs:22:32
    |
 LL |     println!("{:?}", x.map_err(|_| Errors::Ignored));
    |                                ^^^
diff --git a/src/tools/clippy/tests/ui/match_single_binding.fixed b/src/tools/clippy/tests/ui/match_single_binding.fixed
index b8dc8179f7d..de46e6cff55 100644
--- a/src/tools/clippy/tests/ui/match_single_binding.fixed
+++ b/src/tools/clippy/tests/ui/match_single_binding.fixed
@@ -111,3 +111,16 @@ fn main() {
     let x = 1;
     println!("Not an array index start");
 }
+
+#[allow(dead_code)]
+fn issue_8723() {
+    let (mut val, idx) = ("a b", 1);
+
+    let (pre, suf) = val.split_at(idx);
+    val = {
+        println!("{}", pre);
+        suf
+    };
+
+    let _ = val;
+}
diff --git a/src/tools/clippy/tests/ui/match_single_binding.rs b/src/tools/clippy/tests/ui/match_single_binding.rs
index fe63dcd63f2..eea64fcb292 100644
--- a/src/tools/clippy/tests/ui/match_single_binding.rs
+++ b/src/tools/clippy/tests/ui/match_single_binding.rs
@@ -126,3 +126,17 @@ fn main() {
         _ => println!("Not an array index start"),
     }
 }
+
+#[allow(dead_code)]
+fn issue_8723() {
+    let (mut val, idx) = ("a b", 1);
+
+    val = match val.split_at(idx) {
+        (pre, suf) => {
+            println!("{}", pre);
+            suf
+        },
+    };
+
+    let _ = val;
+}
diff --git a/src/tools/clippy/tests/ui/match_single_binding.stderr b/src/tools/clippy/tests/ui/match_single_binding.stderr
index d939291f53c..5d4e7314b21 100644
--- a/src/tools/clippy/tests/ui/match_single_binding.stderr
+++ b/src/tools/clippy/tests/ui/match_single_binding.stderr
@@ -9,7 +9,7 @@ LL | |     }
    | |_____^
    |
    = note: `-D clippy::match-single-binding` implied by `-D warnings`
-help: consider using `let` statement
+help: consider using a `let` statement
    |
 LL ~     let (x, y, z) = (a, b, c);
 LL +     {
@@ -25,7 +25,7 @@ LL | |         (x, y, z) => println!("{} {} {}", x, y, z),
 LL | |     }
    | |_____^
    |
-help: consider using `let` statement
+help: consider using a `let` statement
    |
 LL ~     let (x, y, z) = (a, b, c);
 LL +     println!("{} {} {}", x, y, z);
@@ -88,7 +88,7 @@ LL | |         Point { x, y } => println!("Coords: ({}, {})", x, y),
 LL | |     }
    | |_____^
    |
-help: consider using `let` statement
+help: consider using a `let` statement
    |
 LL ~     let Point { x, y } = p;
 LL +     println!("Coords: ({}, {})", x, y);
@@ -102,7 +102,7 @@ LL | |         Point { x: x1, y: y1 } => println!("Coords: ({}, {})", x1, y1),
 LL | |     }
    | |_____^
    |
-help: consider using `let` statement
+help: consider using a `let` statement
    |
 LL ~     let Point { x: x1, y: y1 } = p;
 LL +     println!("Coords: ({}, {})", x1, y1);
@@ -116,7 +116,7 @@ LL | |         ref r => println!("Got a reference to {}", r),
 LL | |     }
    | |_____^
    |
-help: consider using `let` statement
+help: consider using a `let` statement
    |
 LL ~     let ref r = x;
 LL +     println!("Got a reference to {}", r);
@@ -130,7 +130,7 @@ LL | |         ref mut mr => println!("Got a mutable reference to {}", mr),
 LL | |     }
    | |_____^
    |
-help: consider using `let` statement
+help: consider using a `let` statement
    |
 LL ~     let ref mut mr = x;
 LL +     println!("Got a mutable reference to {}", mr);
@@ -144,7 +144,7 @@ LL | |         Point { x, y } => x * y,
 LL | |     };
    | |______^
    |
-help: consider using `let` statement
+help: consider using a `let` statement
    |
 LL ~     let Point { x, y } = coords();
 LL +     let product = x * y;
@@ -159,7 +159,7 @@ LL | |             unwrapped => unwrapped,
 LL | |         })
    | |_________^
    |
-help: consider using `let` statement
+help: consider using a `let` statement
    |
 LL ~         .map(|i| {
 LL +             let unwrapped = i.unwrap();
@@ -176,5 +176,25 @@ LL | |         _ => println!("Not an array index start"),
 LL | |     }
    | |_____^ help: consider using the match body instead: `println!("Not an array index start");`
 
-error: aborting due to 12 previous errors
+error: this assignment could be simplified
+  --> $DIR/match_single_binding.rs:134:5
+   |
+LL | /     val = match val.split_at(idx) {
+LL | |         (pre, suf) => {
+LL | |             println!("{}", pre);
+LL | |             suf
+LL | |         },
+LL | |     };
+   | |_____^
+   |
+help: consider removing the `match` expression
+   |
+LL ~     let (pre, suf) = val.split_at(idx);
+LL +     val = {
+LL +         println!("{}", pre);
+LL +         suf
+LL ~     };
+   |
+
+error: aborting due to 13 previous errors
 
diff --git a/src/tools/clippy/tests/ui/match_single_binding2.stderr b/src/tools/clippy/tests/ui/match_single_binding2.stderr
index d3493319466..22bf7d8be4a 100644
--- a/src/tools/clippy/tests/ui/match_single_binding2.stderr
+++ b/src/tools/clippy/tests/ui/match_single_binding2.stderr
@@ -8,7 +8,7 @@ LL | |             },
    | |_____________^
    |
    = note: `-D clippy::match-single-binding` implied by `-D warnings`
-help: consider using `let` statement
+help: consider using a `let` statement
    |
 LL ~             Some((iter, _item)) => {
 LL +                 let (min, max) = iter.size_hint();
@@ -24,7 +24,7 @@ LL | |                 (a, b) => println!("a {:?} and b {:?}", a, b),
 LL | |             }
    | |_____________^
    |
-help: consider using `let` statement
+help: consider using a `let` statement
    |
 LL ~             let (a, b) = get_tup();
 LL +             println!("a {:?} and b {:?}", a, b);
diff --git a/src/tools/clippy/tests/ui/methods.rs b/src/tools/clippy/tests/ui/methods.rs
index 977ce54327b..9805097084d 100644
--- a/src/tools/clippy/tests/ui/methods.rs
+++ b/src/tools/clippy/tests/ui/methods.rs
@@ -26,7 +26,6 @@ use std::collections::BTreeMap;
 use std::collections::HashMap;
 use std::collections::HashSet;
 use std::collections::VecDeque;
-use std::iter::FromIterator;
 use std::ops::Mul;
 use std::rc::{self, Rc};
 use std::sync::{self, Arc};
diff --git a/src/tools/clippy/tests/ui/methods.stderr b/src/tools/clippy/tests/ui/methods.stderr
index b63672dd6fd..6be38b24fbd 100644
--- a/src/tools/clippy/tests/ui/methods.stderr
+++ b/src/tools/clippy/tests/ui/methods.stderr
@@ -1,5 +1,5 @@
 error: methods called `new` usually return `Self`
-  --> $DIR/methods.rs:104:5
+  --> $DIR/methods.rs:103:5
    |
 LL | /     fn new() -> i32 {
 LL | |         0
@@ -9,7 +9,7 @@ LL | |     }
    = note: `-D clippy::new-ret-no-self` implied by `-D warnings`
 
 error: called `filter(..).next()` on an `Iterator`. This is more succinctly expressed by calling `.find(..)` instead
-  --> $DIR/methods.rs:125:13
+  --> $DIR/methods.rs:124:13
    |
 LL |       let _ = v.iter().filter(|&x| {
    |  _____________^
diff --git a/src/tools/clippy/tests/ui/eval_order_dependence.rs b/src/tools/clippy/tests/ui/mixed_read_write_in_expression.rs
similarity index 97%
rename from src/tools/clippy/tests/ui/eval_order_dependence.rs
rename to src/tools/clippy/tests/ui/mixed_read_write_in_expression.rs
index aad78319d48..7640057ab6e 100644
--- a/src/tools/clippy/tests/ui/eval_order_dependence.rs
+++ b/src/tools/clippy/tests/ui/mixed_read_write_in_expression.rs
@@ -1,4 +1,4 @@
-#[warn(clippy::eval_order_dependence)]
+#[warn(clippy::mixed_read_write_in_expression)]
 #[allow(
     unused_assignments,
     unused_variables,
diff --git a/src/tools/clippy/tests/ui/eval_order_dependence.stderr b/src/tools/clippy/tests/ui/mixed_read_write_in_expression.stderr
similarity index 63%
rename from src/tools/clippy/tests/ui/eval_order_dependence.stderr
rename to src/tools/clippy/tests/ui/mixed_read_write_in_expression.stderr
index 7c6265a0879..2e951cdbcbf 100644
--- a/src/tools/clippy/tests/ui/eval_order_dependence.stderr
+++ b/src/tools/clippy/tests/ui/mixed_read_write_in_expression.stderr
@@ -1,48 +1,48 @@
 error: unsequenced read of `x`
-  --> $DIR/eval_order_dependence.rs:14:9
+  --> $DIR/mixed_read_write_in_expression.rs:14:9
    |
 LL |     } + x;
    |         ^
    |
-   = note: `-D clippy::eval-order-dependence` implied by `-D warnings`
+   = note: `-D clippy::mixed-read-write-in-expression` implied by `-D warnings`
 note: whether read occurs before this write depends on evaluation order
-  --> $DIR/eval_order_dependence.rs:12:9
+  --> $DIR/mixed_read_write_in_expression.rs:12:9
    |
 LL |         x = 1;
    |         ^^^^^
 
 error: unsequenced read of `x`
-  --> $DIR/eval_order_dependence.rs:17:5
+  --> $DIR/mixed_read_write_in_expression.rs:17:5
    |
 LL |     x += {
    |     ^
    |
 note: whether read occurs before this write depends on evaluation order
-  --> $DIR/eval_order_dependence.rs:18:9
+  --> $DIR/mixed_read_write_in_expression.rs:18:9
    |
 LL |         x = 20;
    |         ^^^^^^
 
 error: unsequenced read of `x`
-  --> $DIR/eval_order_dependence.rs:30:12
+  --> $DIR/mixed_read_write_in_expression.rs:30:12
    |
 LL |         a: x,
    |            ^
    |
 note: whether read occurs before this write depends on evaluation order
-  --> $DIR/eval_order_dependence.rs:32:13
+  --> $DIR/mixed_read_write_in_expression.rs:32:13
    |
 LL |             x = 6;
    |             ^^^^^
 
 error: unsequenced read of `x`
-  --> $DIR/eval_order_dependence.rs:39:9
+  --> $DIR/mixed_read_write_in_expression.rs:39:9
    |
 LL |         x += {
    |         ^
    |
 note: whether read occurs before this write depends on evaluation order
-  --> $DIR/eval_order_dependence.rs:40:13
+  --> $DIR/mixed_read_write_in_expression.rs:40:13
    |
 LL |             x = 20;
    |             ^^^^^^
diff --git a/src/tools/clippy/tests/ui/range_contains.fixed b/src/tools/clippy/tests/ui/range_contains.fixed
index 47c974e614b..f4977199711 100644
--- a/src/tools/clippy/tests/ui/range_contains.fixed
+++ b/src/tools/clippy/tests/ui/range_contains.fixed
@@ -6,7 +6,7 @@
 #[allow(clippy::short_circuit_statement)]
 #[allow(clippy::unnecessary_operation)]
 fn main() {
-    let x = 9_u32;
+    let x = 9_i32;
 
     // order shouldn't matter
     (8..12).contains(&x);
@@ -43,6 +43,12 @@ fn main() {
     let y = 3.;
     (0. ..1.).contains(&y);
     !(0. ..=1.).contains(&y);
+
+    // handle negatives #8721
+    (-10..=10).contains(&x);
+    x >= 10 && x <= -10;
+    (-3. ..=3.).contains(&y);
+    y >= 3. && y <= -3.;
 }
 
 // Fix #6373
diff --git a/src/tools/clippy/tests/ui/range_contains.rs b/src/tools/clippy/tests/ui/range_contains.rs
index 835deced5e4..9e2180b0c99 100644
--- a/src/tools/clippy/tests/ui/range_contains.rs
+++ b/src/tools/clippy/tests/ui/range_contains.rs
@@ -6,7 +6,7 @@
 #[allow(clippy::short_circuit_statement)]
 #[allow(clippy::unnecessary_operation)]
 fn main() {
-    let x = 9_u32;
+    let x = 9_i32;
 
     // order shouldn't matter
     x >= 8 && x < 12;
@@ -43,6 +43,12 @@ fn main() {
     let y = 3.;
     y >= 0. && y < 1.;
     y < 0. || y > 1.;
+
+    // handle negatives #8721
+    x >= -10 && x <= 10;
+    x >= 10 && x <= -10;
+    y >= -3. && y <= 3.;
+    y >= 3. && y <= -3.;
 }
 
 // Fix #6373
diff --git a/src/tools/clippy/tests/ui/range_contains.stderr b/src/tools/clippy/tests/ui/range_contains.stderr
index bc79f1bca84..1817ee1715d 100644
--- a/src/tools/clippy/tests/ui/range_contains.stderr
+++ b/src/tools/clippy/tests/ui/range_contains.stderr
@@ -84,5 +84,17 @@ error: manual `!RangeInclusive::contains` implementation
 LL |     y < 0. || y > 1.;
    |     ^^^^^^^^^^^^^^^^ help: use: `!(0. ..=1.).contains(&y)`
 
-error: aborting due to 14 previous errors
+error: manual `RangeInclusive::contains` implementation
+  --> $DIR/range_contains.rs:48:5
+   |
+LL |     x >= -10 && x <= 10;
+   |     ^^^^^^^^^^^^^^^^^^^ help: use: `(-10..=10).contains(&x)`
+
+error: manual `RangeInclusive::contains` implementation
+  --> $DIR/range_contains.rs:50:5
+   |
+LL |     y >= -3. && y <= 3.;
+   |     ^^^^^^^^^^^^^^^^^^^ help: use: `(-3. ..=3.).contains(&y)`
+
+error: aborting due to 16 previous errors
 
diff --git a/src/tools/clippy/tests/ui/rc_clone_in_vec_init/arc.rs b/src/tools/clippy/tests/ui/rc_clone_in_vec_init/arc.rs
new file mode 100644
index 00000000000..384060e6eae
--- /dev/null
+++ b/src/tools/clippy/tests/ui/rc_clone_in_vec_init/arc.rs
@@ -0,0 +1,68 @@
+#![warn(clippy::rc_clone_in_vec_init)]
+use std::sync::{Arc, Mutex};
+
+fn main() {}
+
+fn should_warn_simple_case() {
+    let v = vec![Arc::new("x".to_string()); 2];
+}
+
+fn should_warn_simple_case_with_big_indentation() {
+    if true {
+        let k = 1;
+        dbg!(k);
+        if true {
+            let v = vec![Arc::new("x".to_string()); 2];
+        }
+    }
+}
+
+fn should_warn_complex_case() {
+    let v = vec![
+        std::sync::Arc::new(Mutex::new({
+            let x = 1;
+            dbg!(x);
+            x
+        }));
+        2
+    ];
+
+    let v1 = vec![
+        Arc::new(Mutex::new({
+            let x = 1;
+            dbg!(x);
+            x
+        }));
+        2
+    ];
+}
+
+fn should_not_warn_custom_arc() {
+    #[derive(Clone)]
+    struct Arc;
+
+    impl Arc {
+        fn new() -> Self {
+            Arc
+        }
+    }
+
+    let v = vec![Arc::new(); 2];
+}
+
+fn should_not_warn_vec_from_elem_but_not_arc() {
+    let v = vec![String::new(); 2];
+    let v1 = vec![1; 2];
+    let v2 = vec![
+        Box::new(std::sync::Arc::new({
+            let y = 3;
+            dbg!(y);
+            y
+        }));
+        2
+    ];
+}
+
+fn should_not_warn_vec_macro_but_not_from_elem() {
+    let v = vec![Arc::new("x".to_string())];
+}
diff --git a/src/tools/clippy/tests/ui/rc_clone_in_vec_init/arc.stderr b/src/tools/clippy/tests/ui/rc_clone_in_vec_init/arc.stderr
new file mode 100644
index 00000000000..ce84186c8e3
--- /dev/null
+++ b/src/tools/clippy/tests/ui/rc_clone_in_vec_init/arc.stderr
@@ -0,0 +1,109 @@
+error: calling `Arc::new` in `vec![elem; len]`
+  --> $DIR/arc.rs:7:13
+   |
+LL |     let v = vec![Arc::new("x".to_string()); 2];
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: `-D clippy::rc-clone-in-vec-init` implied by `-D warnings`
+   = note: each element will point to the same `Arc` instance
+help: consider initializing each `Arc` element individually
+   |
+LL ~     let v = {
+LL +         let mut v = Vec::with_capacity(2);
+LL +         (0..2).for_each(|_| v.push(Arc::new("x".to_string())));
+LL +         v
+LL ~     };
+   |
+help: or if this is intentional, consider extracting the `Arc` initialization to a variable
+   |
+LL ~     let v = {
+LL +         let data = Arc::new("x".to_string());
+LL +         vec![data; 2]
+LL ~     };
+   |
+
+error: calling `Arc::new` in `vec![elem; len]`
+  --> $DIR/arc.rs:15:21
+   |
+LL |             let v = vec![Arc::new("x".to_string()); 2];
+   |                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: each element will point to the same `Arc` instance
+help: consider initializing each `Arc` element individually
+   |
+LL ~             let v = {
+LL +                 let mut v = Vec::with_capacity(2);
+LL +                 (0..2).for_each(|_| v.push(Arc::new("x".to_string())));
+LL +                 v
+LL ~             };
+   |
+help: or if this is intentional, consider extracting the `Arc` initialization to a variable
+   |
+LL ~             let v = {
+LL +                 let data = Arc::new("x".to_string());
+LL +                 vec![data; 2]
+LL ~             };
+   |
+
+error: calling `Arc::new` in `vec![elem; len]`
+  --> $DIR/arc.rs:21:13
+   |
+LL |       let v = vec![
+   |  _____________^
+LL | |         std::sync::Arc::new(Mutex::new({
+LL | |             let x = 1;
+LL | |             dbg!(x);
+...  |
+LL | |         2
+LL | |     ];
+   | |_____^
+   |
+   = note: each element will point to the same `Arc` instance
+help: consider initializing each `Arc` element individually
+   |
+LL ~     let v = {
+LL +         let mut v = Vec::with_capacity(2);
+LL +         (0..2).for_each(|_| v.push(std::sync::Arc::new(..)));
+LL +         v
+LL ~     };
+   |
+help: or if this is intentional, consider extracting the `Arc` initialization to a variable
+   |
+LL ~     let v = {
+LL +         let data = std::sync::Arc::new(..);
+LL +         vec![data; 2]
+LL ~     };
+   |
+
+error: calling `Arc::new` in `vec![elem; len]`
+  --> $DIR/arc.rs:30:14
+   |
+LL |       let v1 = vec![
+   |  ______________^
+LL | |         Arc::new(Mutex::new({
+LL | |             let x = 1;
+LL | |             dbg!(x);
+...  |
+LL | |         2
+LL | |     ];
+   | |_____^
+   |
+   = note: each element will point to the same `Arc` instance
+help: consider initializing each `Arc` element individually
+   |
+LL ~     let v1 = {
+LL +         let mut v = Vec::with_capacity(2);
+LL +         (0..2).for_each(|_| v.push(Arc::new(..)));
+LL +         v
+LL ~     };
+   |
+help: or if this is intentional, consider extracting the `Arc` initialization to a variable
+   |
+LL ~     let v1 = {
+LL +         let data = Arc::new(..);
+LL +         vec![data; 2]
+LL ~     };
+   |
+
+error: aborting due to 4 previous errors
+
diff --git a/src/tools/clippy/tests/ui/rc_clone_in_vec_init/rc.rs b/src/tools/clippy/tests/ui/rc_clone_in_vec_init/rc.rs
new file mode 100644
index 00000000000..0394457fe17
--- /dev/null
+++ b/src/tools/clippy/tests/ui/rc_clone_in_vec_init/rc.rs
@@ -0,0 +1,69 @@
+#![warn(clippy::rc_clone_in_vec_init)]
+use std::rc::Rc;
+use std::sync::Mutex;
+
+fn main() {}
+
+fn should_warn_simple_case() {
+    let v = vec![Rc::new("x".to_string()); 2];
+}
+
+fn should_warn_simple_case_with_big_indentation() {
+    if true {
+        let k = 1;
+        dbg!(k);
+        if true {
+            let v = vec![Rc::new("x".to_string()); 2];
+        }
+    }
+}
+
+fn should_warn_complex_case() {
+    let v = vec![
+        std::rc::Rc::new(Mutex::new({
+            let x = 1;
+            dbg!(x);
+            x
+        }));
+        2
+    ];
+
+    let v1 = vec![
+        Rc::new(Mutex::new({
+            let x = 1;
+            dbg!(x);
+            x
+        }));
+        2
+    ];
+}
+
+fn should_not_warn_custom_arc() {
+    #[derive(Clone)]
+    struct Rc;
+
+    impl Rc {
+        fn new() -> Self {
+            Rc
+        }
+    }
+
+    let v = vec![Rc::new(); 2];
+}
+
+fn should_not_warn_vec_from_elem_but_not_rc() {
+    let v = vec![String::new(); 2];
+    let v1 = vec![1; 2];
+    let v2 = vec![
+        Box::new(std::rc::Rc::new({
+            let y = 3;
+            dbg!(y);
+            y
+        }));
+        2
+    ];
+}
+
+fn should_not_warn_vec_macro_but_not_from_elem() {
+    let v = vec![Rc::new("x".to_string())];
+}
diff --git a/src/tools/clippy/tests/ui/rc_clone_in_vec_init/rc.stderr b/src/tools/clippy/tests/ui/rc_clone_in_vec_init/rc.stderr
new file mode 100644
index 00000000000..0f5cc0cf98f
--- /dev/null
+++ b/src/tools/clippy/tests/ui/rc_clone_in_vec_init/rc.stderr
@@ -0,0 +1,109 @@
+error: calling `Rc::new` in `vec![elem; len]`
+  --> $DIR/rc.rs:8:13
+   |
+LL |     let v = vec![Rc::new("x".to_string()); 2];
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: `-D clippy::rc-clone-in-vec-init` implied by `-D warnings`
+   = note: each element will point to the same `Rc` instance
+help: consider initializing each `Rc` element individually
+   |
+LL ~     let v = {
+LL +         let mut v = Vec::with_capacity(2);
+LL +         (0..2).for_each(|_| v.push(Rc::new("x".to_string())));
+LL +         v
+LL ~     };
+   |
+help: or if this is intentional, consider extracting the `Rc` initialization to a variable
+   |
+LL ~     let v = {
+LL +         let data = Rc::new("x".to_string());
+LL +         vec![data; 2]
+LL ~     };
+   |
+
+error: calling `Rc::new` in `vec![elem; len]`
+  --> $DIR/rc.rs:16:21
+   |
+LL |             let v = vec![Rc::new("x".to_string()); 2];
+   |                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: each element will point to the same `Rc` instance
+help: consider initializing each `Rc` element individually
+   |
+LL ~             let v = {
+LL +                 let mut v = Vec::with_capacity(2);
+LL +                 (0..2).for_each(|_| v.push(Rc::new("x".to_string())));
+LL +                 v
+LL ~             };
+   |
+help: or if this is intentional, consider extracting the `Rc` initialization to a variable
+   |
+LL ~             let v = {
+LL +                 let data = Rc::new("x".to_string());
+LL +                 vec![data; 2]
+LL ~             };
+   |
+
+error: calling `Rc::new` in `vec![elem; len]`
+  --> $DIR/rc.rs:22:13
+   |
+LL |       let v = vec![
+   |  _____________^
+LL | |         std::rc::Rc::new(Mutex::new({
+LL | |             let x = 1;
+LL | |             dbg!(x);
+...  |
+LL | |         2
+LL | |     ];
+   | |_____^
+   |
+   = note: each element will point to the same `Rc` instance
+help: consider initializing each `Rc` element individually
+   |
+LL ~     let v = {
+LL +         let mut v = Vec::with_capacity(2);
+LL +         (0..2).for_each(|_| v.push(std::rc::Rc::new(..)));
+LL +         v
+LL ~     };
+   |
+help: or if this is intentional, consider extracting the `Rc` initialization to a variable
+   |
+LL ~     let v = {
+LL +         let data = std::rc::Rc::new(..);
+LL +         vec![data; 2]
+LL ~     };
+   |
+
+error: calling `Rc::new` in `vec![elem; len]`
+  --> $DIR/rc.rs:31:14
+   |
+LL |       let v1 = vec![
+   |  ______________^
+LL | |         Rc::new(Mutex::new({
+LL | |             let x = 1;
+LL | |             dbg!(x);
+...  |
+LL | |         2
+LL | |     ];
+   | |_____^
+   |
+   = note: each element will point to the same `Rc` instance
+help: consider initializing each `Rc` element individually
+   |
+LL ~     let v1 = {
+LL +         let mut v = Vec::with_capacity(2);
+LL +         (0..2).for_each(|_| v.push(Rc::new(..)));
+LL +         v
+LL ~     };
+   |
+help: or if this is intentional, consider extracting the `Rc` initialization to a variable
+   |
+LL ~     let v1 = {
+LL +         let data = Rc::new(..);
+LL +         vec![data; 2]
+LL ~     };
+   |
+
+error: aborting due to 4 previous errors
+
diff --git a/src/tools/clippy/tests/ui/recursive_format_impl.stderr b/src/tools/clippy/tests/ui/recursive_format_impl.stderr
index 6171696ed69..1a717ac92d8 100644
--- a/src/tools/clippy/tests/ui/recursive_format_impl.stderr
+++ b/src/tools/clippy/tests/ui/recursive_format_impl.stderr
@@ -6,15 +6,6 @@ LL |         write!(f, "{}", self.to_string())
    |
    = note: `-D clippy::recursive-format-impl` implied by `-D warnings`
 
-error: unnecessary use of `to_string`
-  --> $DIR/recursive_format_impl.rs:61:50
-   |
-LL |             Self::E(string) => write!(f, "E {}", string.to_string()),
-   |                                                  ^^^^^^^^^^^^^^^^^^
-   |
-   = note: `-D clippy::unnecessary-to-owned` implied by `-D warnings`
-   = note: this error originates in the macro `$crate::format_args` (in Nightly builds, run with -Z macro-backtrace for more info)
-
 error: using `self` as `Display` in `impl Display` will cause infinite recursion
   --> $DIR/recursive_format_impl.rs:73:9
    |
@@ -87,5 +78,5 @@ LL |         write!(f, "{}", &&**&&*self)
    |
    = note: this error originates in the macro `write` (in Nightly builds, run with -Z macro-backtrace for more info)
 
-error: aborting due to 11 previous errors
+error: aborting due to 10 previous errors
 
diff --git a/src/tools/clippy/tests/ui/redundant_allocation.rs b/src/tools/clippy/tests/ui/redundant_allocation.rs
index 80f94e5f3cb..cf7d8c6e349 100644
--- a/src/tools/clippy/tests/ui/redundant_allocation.rs
+++ b/src/tools/clippy/tests/ui/redundant_allocation.rs
@@ -97,4 +97,39 @@ mod box_dyn {
     pub fn test_rc_box(_: Rc<Box<Box<dyn T>>>) {}
 }
 
+// https://github.com/rust-lang/rust-clippy/issues/8604
+mod box_fat_ptr {
+    use std::boxed::Box;
+    use std::path::Path;
+    use std::rc::Rc;
+    use std::sync::Arc;
+
+    pub struct DynSized {
+        foo: [usize],
+    }
+
+    struct S {
+        a: Box<Box<str>>,
+        b: Rc<Box<str>>,
+        c: Arc<Box<str>>,
+
+        e: Box<Box<[usize]>>,
+        f: Box<Box<Path>>,
+        g: Box<Box<DynSized>>,
+    }
+
+    pub fn test_box_str(_: Box<Box<str>>) {}
+    pub fn test_rc_str(_: Rc<Box<str>>) {}
+    pub fn test_arc_str(_: Arc<Box<str>>) {}
+
+    pub fn test_box_slice(_: Box<Box<[usize]>>) {}
+    pub fn test_box_path(_: Box<Box<Path>>) {}
+    pub fn test_box_custom(_: Box<Box<DynSized>>) {}
+
+    pub fn test_rc_box_str(_: Rc<Box<Box<str>>>) {}
+    pub fn test_rc_box_slice(_: Rc<Box<Box<[usize]>>>) {}
+    pub fn test_rc_box_path(_: Rc<Box<Box<Path>>>) {}
+    pub fn test_rc_box_custom(_: Rc<Box<Box<DynSized>>>) {}
+}
+
 fn main() {}
diff --git a/src/tools/clippy/tests/ui/redundant_allocation.stderr b/src/tools/clippy/tests/ui/redundant_allocation.stderr
index c3b10e5f5e6..fab1b069fcb 100644
--- a/src/tools/clippy/tests/ui/redundant_allocation.stderr
+++ b/src/tools/clippy/tests/ui/redundant_allocation.stderr
@@ -143,5 +143,41 @@ LL |     pub fn test_rc_box(_: Rc<Box<Box<dyn T>>>) {}
    = note: `Box<Box<dyn T>>` is already on the heap, `Rc<Box<Box<dyn T>>>` makes an extra allocation
    = help: consider using just `Rc<Box<dyn T>>` or `Box<Box<dyn T>>`
 
-error: aborting due to 16 previous errors
+error: usage of `Rc<Box<Box<str>>>`
+  --> $DIR/redundant_allocation.rs:129:31
+   |
+LL |     pub fn test_rc_box_str(_: Rc<Box<Box<str>>>) {}
+   |                               ^^^^^^^^^^^^^^^^^
+   |
+   = note: `Box<Box<str>>` is already on the heap, `Rc<Box<Box<str>>>` makes an extra allocation
+   = help: consider using just `Rc<Box<str>>` or `Box<Box<str>>`
+
+error: usage of `Rc<Box<Box<[usize]>>>`
+  --> $DIR/redundant_allocation.rs:130:33
+   |
+LL |     pub fn test_rc_box_slice(_: Rc<Box<Box<[usize]>>>) {}
+   |                                 ^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: `Box<Box<[usize]>>` is already on the heap, `Rc<Box<Box<[usize]>>>` makes an extra allocation
+   = help: consider using just `Rc<Box<[usize]>>` or `Box<Box<[usize]>>`
+
+error: usage of `Rc<Box<Box<Path>>>`
+  --> $DIR/redundant_allocation.rs:131:32
+   |
+LL |     pub fn test_rc_box_path(_: Rc<Box<Box<Path>>>) {}
+   |                                ^^^^^^^^^^^^^^^^^^
+   |
+   = note: `Box<Box<Path>>` is already on the heap, `Rc<Box<Box<Path>>>` makes an extra allocation
+   = help: consider using just `Rc<Box<Path>>` or `Box<Box<Path>>`
+
+error: usage of `Rc<Box<Box<DynSized>>>`
+  --> $DIR/redundant_allocation.rs:132:34
+   |
+LL |     pub fn test_rc_box_custom(_: Rc<Box<Box<DynSized>>>) {}
+   |                                  ^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: `Box<Box<DynSized>>` is already on the heap, `Rc<Box<Box<DynSized>>>` makes an extra allocation
+   = help: consider using just `Rc<Box<DynSized>>` or `Box<Box<DynSized>>`
+
+error: aborting due to 20 previous errors
 
diff --git a/src/tools/clippy/tests/ui/rename.fixed b/src/tools/clippy/tests/ui/rename.fixed
index 9c4079ad6d3..53288be9404 100644
--- a/src/tools/clippy/tests/ui/rename.fixed
+++ b/src/tools/clippy/tests/ui/rename.fixed
@@ -10,6 +10,7 @@
 #![allow(clippy::cognitive_complexity)]
 #![allow(clippy::disallowed_methods)]
 #![allow(clippy::disallowed_types)]
+#![allow(clippy::mixed_read_write_in_expression)]
 #![allow(clippy::for_loops_over_fallibles)]
 #![allow(clippy::useless_conversion)]
 #![allow(clippy::match_result_ok)]
@@ -39,6 +40,7 @@
 #![warn(clippy::cognitive_complexity)]
 #![warn(clippy::disallowed_methods)]
 #![warn(clippy::disallowed_types)]
+#![warn(clippy::mixed_read_write_in_expression)]
 #![warn(clippy::for_loops_over_fallibles)]
 #![warn(clippy::for_loops_over_fallibles)]
 #![warn(clippy::useless_conversion)]
diff --git a/src/tools/clippy/tests/ui/rename.rs b/src/tools/clippy/tests/ui/rename.rs
index e83e66b7fbd..539f34f847a 100644
--- a/src/tools/clippy/tests/ui/rename.rs
+++ b/src/tools/clippy/tests/ui/rename.rs
@@ -10,6 +10,7 @@
 #![allow(clippy::cognitive_complexity)]
 #![allow(clippy::disallowed_methods)]
 #![allow(clippy::disallowed_types)]
+#![allow(clippy::mixed_read_write_in_expression)]
 #![allow(clippy::for_loops_over_fallibles)]
 #![allow(clippy::useless_conversion)]
 #![allow(clippy::match_result_ok)]
@@ -39,6 +40,7 @@
 #![warn(clippy::cyclomatic_complexity)]
 #![warn(clippy::disallowed_method)]
 #![warn(clippy::disallowed_type)]
+#![warn(clippy::eval_order_dependence)]
 #![warn(clippy::for_loop_over_option)]
 #![warn(clippy::for_loop_over_result)]
 #![warn(clippy::identity_conversion)]
diff --git a/src/tools/clippy/tests/ui/rename.stderr b/src/tools/clippy/tests/ui/rename.stderr
index f811b10d017..8ea46b580a8 100644
--- a/src/tools/clippy/tests/ui/rename.stderr
+++ b/src/tools/clippy/tests/ui/rename.stderr
@@ -1,5 +1,5 @@
 error: lint `clippy::block_in_if_condition_expr` has been renamed to `clippy::blocks_in_if_conditions`
-  --> $DIR/rename.rs:35:9
+  --> $DIR/rename.rs:36:9
    |
 LL | #![warn(clippy::block_in_if_condition_expr)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::blocks_in_if_conditions`
@@ -7,202 +7,208 @@ LL | #![warn(clippy::block_in_if_condition_expr)]
    = note: `-D renamed-and-removed-lints` implied by `-D warnings`
 
 error: lint `clippy::block_in_if_condition_stmt` has been renamed to `clippy::blocks_in_if_conditions`
-  --> $DIR/rename.rs:36:9
+  --> $DIR/rename.rs:37:9
    |
 LL | #![warn(clippy::block_in_if_condition_stmt)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::blocks_in_if_conditions`
 
 error: lint `clippy::box_vec` has been renamed to `clippy::box_collection`
-  --> $DIR/rename.rs:37:9
+  --> $DIR/rename.rs:38:9
    |
 LL | #![warn(clippy::box_vec)]
    |         ^^^^^^^^^^^^^^^ help: use the new name: `clippy::box_collection`
 
 error: lint `clippy::const_static_lifetime` has been renamed to `clippy::redundant_static_lifetimes`
-  --> $DIR/rename.rs:38:9
+  --> $DIR/rename.rs:39:9
    |
 LL | #![warn(clippy::const_static_lifetime)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::redundant_static_lifetimes`
 
 error: lint `clippy::cyclomatic_complexity` has been renamed to `clippy::cognitive_complexity`
-  --> $DIR/rename.rs:39:9
+  --> $DIR/rename.rs:40:9
    |
 LL | #![warn(clippy::cyclomatic_complexity)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::cognitive_complexity`
 
 error: lint `clippy::disallowed_method` has been renamed to `clippy::disallowed_methods`
-  --> $DIR/rename.rs:40:9
+  --> $DIR/rename.rs:41:9
    |
 LL | #![warn(clippy::disallowed_method)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::disallowed_methods`
 
 error: lint `clippy::disallowed_type` has been renamed to `clippy::disallowed_types`
-  --> $DIR/rename.rs:41:9
+  --> $DIR/rename.rs:42:9
    |
 LL | #![warn(clippy::disallowed_type)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::disallowed_types`
 
+error: lint `clippy::eval_order_dependence` has been renamed to `clippy::mixed_read_write_in_expression`
+  --> $DIR/rename.rs:43:9
+   |
+LL | #![warn(clippy::eval_order_dependence)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::mixed_read_write_in_expression`
+
 error: lint `clippy::for_loop_over_option` has been renamed to `clippy::for_loops_over_fallibles`
-  --> $DIR/rename.rs:42:9
+  --> $DIR/rename.rs:44:9
    |
 LL | #![warn(clippy::for_loop_over_option)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::for_loops_over_fallibles`
 
 error: lint `clippy::for_loop_over_result` has been renamed to `clippy::for_loops_over_fallibles`
-  --> $DIR/rename.rs:43:9
+  --> $DIR/rename.rs:45:9
    |
 LL | #![warn(clippy::for_loop_over_result)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::for_loops_over_fallibles`
 
 error: lint `clippy::identity_conversion` has been renamed to `clippy::useless_conversion`
-  --> $DIR/rename.rs:44:9
+  --> $DIR/rename.rs:46:9
    |
 LL | #![warn(clippy::identity_conversion)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::useless_conversion`
 
 error: lint `clippy::if_let_some_result` has been renamed to `clippy::match_result_ok`
-  --> $DIR/rename.rs:45:9
+  --> $DIR/rename.rs:47:9
    |
 LL | #![warn(clippy::if_let_some_result)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::match_result_ok`
 
 error: lint `clippy::new_without_default_derive` has been renamed to `clippy::new_without_default`
-  --> $DIR/rename.rs:46:9
+  --> $DIR/rename.rs:48:9
    |
 LL | #![warn(clippy::new_without_default_derive)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::new_without_default`
 
 error: lint `clippy::option_and_then_some` has been renamed to `clippy::bind_instead_of_map`
-  --> $DIR/rename.rs:47:9
+  --> $DIR/rename.rs:49:9
    |
 LL | #![warn(clippy::option_and_then_some)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::bind_instead_of_map`
 
 error: lint `clippy::option_expect_used` has been renamed to `clippy::expect_used`
-  --> $DIR/rename.rs:48:9
+  --> $DIR/rename.rs:50:9
    |
 LL | #![warn(clippy::option_expect_used)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::expect_used`
 
 error: lint `clippy::option_map_unwrap_or` has been renamed to `clippy::map_unwrap_or`
-  --> $DIR/rename.rs:49:9
+  --> $DIR/rename.rs:51:9
    |
 LL | #![warn(clippy::option_map_unwrap_or)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::map_unwrap_or`
 
 error: lint `clippy::option_map_unwrap_or_else` has been renamed to `clippy::map_unwrap_or`
-  --> $DIR/rename.rs:50:9
+  --> $DIR/rename.rs:52:9
    |
 LL | #![warn(clippy::option_map_unwrap_or_else)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::map_unwrap_or`
 
 error: lint `clippy::option_unwrap_used` has been renamed to `clippy::unwrap_used`
-  --> $DIR/rename.rs:51:9
+  --> $DIR/rename.rs:53:9
    |
 LL | #![warn(clippy::option_unwrap_used)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::unwrap_used`
 
 error: lint `clippy::ref_in_deref` has been renamed to `clippy::needless_borrow`
-  --> $DIR/rename.rs:52:9
+  --> $DIR/rename.rs:54:9
    |
 LL | #![warn(clippy::ref_in_deref)]
    |         ^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::needless_borrow`
 
 error: lint `clippy::result_expect_used` has been renamed to `clippy::expect_used`
-  --> $DIR/rename.rs:53:9
+  --> $DIR/rename.rs:55:9
    |
 LL | #![warn(clippy::result_expect_used)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::expect_used`
 
 error: lint `clippy::result_map_unwrap_or_else` has been renamed to `clippy::map_unwrap_or`
-  --> $DIR/rename.rs:54:9
+  --> $DIR/rename.rs:56:9
    |
 LL | #![warn(clippy::result_map_unwrap_or_else)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::map_unwrap_or`
 
 error: lint `clippy::result_unwrap_used` has been renamed to `clippy::unwrap_used`
-  --> $DIR/rename.rs:55:9
+  --> $DIR/rename.rs:57:9
    |
 LL | #![warn(clippy::result_unwrap_used)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::unwrap_used`
 
 error: lint `clippy::single_char_push_str` has been renamed to `clippy::single_char_add_str`
-  --> $DIR/rename.rs:56:9
+  --> $DIR/rename.rs:58:9
    |
 LL | #![warn(clippy::single_char_push_str)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::single_char_add_str`
 
 error: lint `clippy::stutter` has been renamed to `clippy::module_name_repetitions`
-  --> $DIR/rename.rs:57:9
+  --> $DIR/rename.rs:59:9
    |
 LL | #![warn(clippy::stutter)]
    |         ^^^^^^^^^^^^^^^ help: use the new name: `clippy::module_name_repetitions`
 
 error: lint `clippy::to_string_in_display` has been renamed to `clippy::recursive_format_impl`
-  --> $DIR/rename.rs:58:9
+  --> $DIR/rename.rs:60:9
    |
 LL | #![warn(clippy::to_string_in_display)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::recursive_format_impl`
 
 error: lint `clippy::zero_width_space` has been renamed to `clippy::invisible_characters`
-  --> $DIR/rename.rs:59:9
+  --> $DIR/rename.rs:61:9
    |
 LL | #![warn(clippy::zero_width_space)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::invisible_characters`
 
 error: lint `clippy::drop_bounds` has been renamed to `drop_bounds`
-  --> $DIR/rename.rs:60:9
+  --> $DIR/rename.rs:62:9
    |
 LL | #![warn(clippy::drop_bounds)]
    |         ^^^^^^^^^^^^^^^^^^^ help: use the new name: `drop_bounds`
 
 error: lint `clippy::into_iter_on_array` has been renamed to `array_into_iter`
-  --> $DIR/rename.rs:61:9
+  --> $DIR/rename.rs:63:9
    |
 LL | #![warn(clippy::into_iter_on_array)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `array_into_iter`
 
 error: lint `clippy::invalid_atomic_ordering` has been renamed to `invalid_atomic_ordering`
-  --> $DIR/rename.rs:62:9
+  --> $DIR/rename.rs:64:9
    |
 LL | #![warn(clippy::invalid_atomic_ordering)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `invalid_atomic_ordering`
 
 error: lint `clippy::invalid_ref` has been renamed to `invalid_value`
-  --> $DIR/rename.rs:63:9
+  --> $DIR/rename.rs:65:9
    |
 LL | #![warn(clippy::invalid_ref)]
    |         ^^^^^^^^^^^^^^^^^^^ help: use the new name: `invalid_value`
 
 error: lint `clippy::mem_discriminant_non_enum` has been renamed to `enum_intrinsics_non_enums`
-  --> $DIR/rename.rs:64:9
+  --> $DIR/rename.rs:66:9
    |
 LL | #![warn(clippy::mem_discriminant_non_enum)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `enum_intrinsics_non_enums`
 
 error: lint `clippy::panic_params` has been renamed to `non_fmt_panics`
-  --> $DIR/rename.rs:65:9
+  --> $DIR/rename.rs:67:9
    |
 LL | #![warn(clippy::panic_params)]
    |         ^^^^^^^^^^^^^^^^^^^^ help: use the new name: `non_fmt_panics`
 
 error: lint `clippy::temporary_cstring_as_ptr` has been renamed to `temporary_cstring_as_ptr`
-  --> $DIR/rename.rs:66:9
+  --> $DIR/rename.rs:68:9
    |
 LL | #![warn(clippy::temporary_cstring_as_ptr)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `temporary_cstring_as_ptr`
 
 error: lint `clippy::unknown_clippy_lints` has been renamed to `unknown_lints`
-  --> $DIR/rename.rs:67:9
+  --> $DIR/rename.rs:69:9
    |
 LL | #![warn(clippy::unknown_clippy_lints)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `unknown_lints`
 
 error: lint `clippy::unused_label` has been renamed to `unused_labels`
-  --> $DIR/rename.rs:68:9
+  --> $DIR/rename.rs:70:9
    |
 LL | #![warn(clippy::unused_label)]
    |         ^^^^^^^^^^^^^^^^^^^^ help: use the new name: `unused_labels`
 
-error: aborting due to 34 previous errors
+error: aborting due to 35 previous errors
 
diff --git a/src/tools/clippy/tests/ui/self_assignment.rs b/src/tools/clippy/tests/ui/self_assignment.rs
index a7cbb9cd78b..ef647622910 100644
--- a/src/tools/clippy/tests/ui/self_assignment.rs
+++ b/src/tools/clippy/tests/ui/self_assignment.rs
@@ -39,7 +39,7 @@ pub fn negatives_not_equal(mut a: usize, b: &mut usize, mut s: S) {
     t.0 = t.1;
 }
 
-#[allow(clippy::eval_order_dependence)]
+#[allow(clippy::mixed_read_write_in_expression)]
 pub fn negatives_side_effects() {
     let mut v = vec![1, 2, 3, 4, 5];
     let mut i = 0;
diff --git a/src/tools/clippy/tests/ui/significant_drop_in_scrutinee.rs b/src/tools/clippy/tests/ui/significant_drop_in_scrutinee.rs
index c4a3301e722..f83a6dd0eb2 100644
--- a/src/tools/clippy/tests/ui/significant_drop_in_scrutinee.rs
+++ b/src/tools/clippy/tests/ui/significant_drop_in_scrutinee.rs
@@ -29,8 +29,8 @@ fn should_not_trigger_lint_with_mutex_guard_outside_match() {
     match is_foo {
         true => {
             mutex.lock().unwrap().bar();
-        }
-        false => {}
+        },
+        false => {},
     };
 }
 
@@ -43,8 +43,8 @@ fn should_not_trigger_lint_with_mutex_guard_when_taking_ownership_in_match() {
         Ok(guard) => {
             guard.foo();
             mutex.lock().unwrap().bar();
-        }
-        _ => {}
+        },
+        _ => {},
     };
 }
 
@@ -57,8 +57,8 @@ fn should_trigger_lint_with_mutex_guard_in_match_scrutinee() {
     match mutex.lock().unwrap().foo() {
         true => {
             mutex.lock().unwrap().bar();
-        }
-        false => {}
+        },
+        false => {},
     };
 }
 
@@ -68,10 +68,10 @@ fn should_not_trigger_lint_for_insignificant_drop() {
     match 1u64.to_string().is_empty() {
         true => {
             println!("It was empty")
-        }
+        },
         false => {
             println!("It was not empty")
-        }
+        },
     }
 }
 
@@ -131,12 +131,12 @@ fn should_trigger_lint_with_wrapped_mutex() {
         1 => {
             println!("Got 1. Is it still 1?");
             println!("{}", s.lock_m().get_the_value());
-        }
+        },
         2 => {
             println!("Got 2. Is it still 2?");
             println!("{}", s.lock_m().get_the_value());
-        }
-        _ => {}
+        },
+        _ => {},
     }
     println!("All done!");
 }
@@ -152,12 +152,12 @@ fn should_trigger_lint_with_double_wrapped_mutex() {
         1 => {
             println!("Got 1. Is it still 1?");
             println!("{}", s.lock_m().get_the_value());
-        }
+        },
         2 => {
             println!("Got 2. Is it still 2?");
             println!("{}", s.lock_m().get_the_value());
-        }
-        _ => {}
+        },
+        _ => {},
     }
     println!("All done!");
 }
@@ -201,10 +201,10 @@ fn should_trigger_lint_for_vec() {
             let current_count = counter.i.load(Ordering::Relaxed);
             println!("Current count {}", current_count);
             assert_eq!(current_count, 0);
-        }
-        1 => {}
-        3 => {}
-        _ => {}
+        },
+        1 => {},
+        3 => {},
+        _ => {},
     };
 }
 
@@ -224,8 +224,8 @@ fn should_trigger_lint_for_tuple_in_scrutinee() {
                 println!("started");
                 mutex1.lock().unwrap().s.len();
                 println!("done");
-            }
-            (_, _) => {}
+            },
+            (_, _) => {},
         };
 
         match (true, mutex1.lock().unwrap().s.len(), true) {
@@ -233,8 +233,8 @@ fn should_trigger_lint_for_tuple_in_scrutinee() {
                 println!("started");
                 mutex1.lock().unwrap().s.len();
                 println!("done");
-            }
-            (_, _, _) => {}
+            },
+            (_, _, _) => {},
         };
 
         let mutex2 = Mutex::new(StateWithField { s: "two".to_owned() });
@@ -244,8 +244,8 @@ fn should_trigger_lint_for_tuple_in_scrutinee() {
                 mutex1.lock().unwrap().s.len();
                 mutex2.lock().unwrap().s.len();
                 println!("done");
-            }
-            (_, _, _) => {}
+            },
+            (_, _, _) => {},
         };
 
         let mutex3 = Mutex::new(StateWithField { s: "three".to_owned() });
@@ -255,19 +255,18 @@ fn should_trigger_lint_for_tuple_in_scrutinee() {
                 mutex1.lock().unwrap().s.len();
                 mutex2.lock().unwrap().s.len();
                 println!("done");
-            }
-            _ => {}
+            },
+            _ => {},
         };
 
-
         match (true, mutex3.lock().unwrap().s.as_str()) {
             (_, "three") => {
                 println!("started");
                 mutex1.lock().unwrap().s.len();
                 mutex2.lock().unwrap().s.len();
                 println!("done");
-            }
-            (_, _) => {}
+            },
+            (_, _) => {},
         };
     }
 }
@@ -282,15 +281,15 @@ fn should_trigger_lint_for_accessing_field_in_mutex_in_one_side_of_binary_op() {
     match mutex.lock().unwrap().s.len() > 1 {
         true => {
             mutex.lock().unwrap().s.len();
-        }
-        false => {}
+        },
+        false => {},
     };
 
     match 1 < mutex.lock().unwrap().s.len() {
         true => {
             mutex.lock().unwrap().s.len();
-        }
-        false => {}
+        },
+        false => {},
     };
 }
 
@@ -300,20 +299,30 @@ fn should_trigger_lint_for_accessing_field_in_mutex_in_one_side_of_binary_op() {
 // drop problem, the lint recommends moving the entire binary operation.
 fn should_trigger_lint_for_accessing_fields_in_mutex_in_both_sides_of_binary_op() {
     let mutex1 = Mutex::new(StateWithField { s: "state".to_owned() });
-    let mutex2 = Mutex::new(StateWithField { s: "statewithfield".to_owned() });
+    let mutex2 = Mutex::new(StateWithField {
+        s: "statewithfield".to_owned(),
+    });
 
     match mutex1.lock().unwrap().s.len() < mutex2.lock().unwrap().s.len() {
         true => {
-            println!("{} < {}", mutex1.lock().unwrap().s.len(), mutex2.lock().unwrap().s.len());
-        }
-        false => {}
+            println!(
+                "{} < {}",
+                mutex1.lock().unwrap().s.len(),
+                mutex2.lock().unwrap().s.len()
+            );
+        },
+        false => {},
     };
 
     match mutex1.lock().unwrap().s.len() >= mutex2.lock().unwrap().s.len() {
         true => {
-            println!("{} >= {}", mutex1.lock().unwrap().s.len(), mutex2.lock().unwrap().s.len());
-        }
-        false => {}
+            println!(
+                "{} >= {}",
+                mutex1.lock().unwrap().s.len(),
+                mutex2.lock().unwrap().s.len()
+            );
+        },
+        false => {},
     };
 }
 
@@ -328,8 +337,8 @@ fn should_not_trigger_lint_for_closure_in_scrutinee() {
     match get_mutex_guard() > 1 {
         true => {
             mutex1.lock().unwrap().s.len();
-        }
-        false => {}
+        },
+        false => {},
     };
 }
 
@@ -343,8 +352,8 @@ fn should_trigger_lint_for_return_from_closure_in_scrutinee() {
     match get_mutex_guard().s.len() > 1 {
         true => {
             mutex1.lock().unwrap().s.len();
-        }
-        false => {}
+        },
+        false => {},
     };
 }
 
@@ -357,13 +366,20 @@ fn should_trigger_lint_for_return_from_match_in_scrutinee() {
     // Should trigger lint because the nested match within the scrutinee returns a temporary with a
     // significant drop is but not used directly in any match arms, so it has a potentially
     // surprising lifetime.
-    match match i { 100 => mutex1.lock().unwrap(), _ => mutex2.lock().unwrap() }.s.len() > 1 {
+    match match i {
+        100 => mutex1.lock().unwrap(),
+        _ => mutex2.lock().unwrap(),
+    }
+    .s
+    .len()
+        > 1
+    {
         true => {
             mutex1.lock().unwrap().s.len();
-        }
+        },
         false => {
             println!("nothing to do here");
-        }
+        },
     };
 }
 
@@ -376,11 +392,19 @@ fn should_trigger_lint_for_return_from_if_in_scrutinee() {
     // Should trigger lint because the nested if-expression within the scrutinee returns a temporary
     // with a significant drop is but not used directly in any match arms, so it has a potentially
     // surprising lifetime.
-    match if i > 1 { mutex1.lock().unwrap() } else { mutex2.lock().unwrap() }.s.len() > 1 {
+    match if i > 1 {
+        mutex1.lock().unwrap()
+    } else {
+        mutex2.lock().unwrap()
+    }
+    .s
+    .len()
+        > 1
+    {
         true => {
             mutex1.lock().unwrap().s.len();
-        }
-        false => {}
+        },
+        false => {},
     };
 }
 
@@ -392,11 +416,15 @@ fn should_not_trigger_lint_for_if_in_scrutinee() {
     // Should not trigger the lint because the temporary with a significant drop *is* dropped within
     // the body of the if-expression nested within the match scrutinee, and therefore does not have
     // a potentially surprising lifetime.
-    match if i > 1 { mutex.lock().unwrap().s.len() > 1 } else { false } {
+    match if i > 1 {
+        mutex.lock().unwrap().s.len() > 1
+    } else {
+        false
+    } {
         true => {
             mutex.lock().unwrap().s.len();
-        }
-        false => {}
+        },
+        false => {},
     };
 }
 
@@ -430,7 +458,9 @@ struct StateStringWithBoxedMutexGuard {
 
 impl StateStringWithBoxedMutexGuard {
     fn new() -> StateStringWithBoxedMutexGuard {
-        StateStringWithBoxedMutexGuard { s: Mutex::new("A String".to_owned()) }
+        StateStringWithBoxedMutexGuard {
+            s: Mutex::new("A String".to_owned()),
+        }
     }
     fn lock(&self) -> Box<MutexGuard<String>> {
         Box::new(self.s.lock().unwrap())
@@ -450,7 +480,6 @@ fn should_trigger_lint_for_boxed_mutex_guard_holding_string() {
     };
 }
 
-
 struct StateWithIntField {
     i: u64,
 }
@@ -467,36 +496,36 @@ fn should_trigger_lint_in_assign_expr() {
     match mutex.lock().unwrap().i = i {
         _ => {
             println!("{}", mutex.lock().unwrap().i);
-        }
+        },
     };
 
     match i = mutex.lock().unwrap().i {
         _ => {
             println!("{}", mutex.lock().unwrap().i);
-        }
+        },
     };
 
     match mutex.lock().unwrap().i += 1 {
         _ => {
             println!("{}", mutex.lock().unwrap().i);
-        }
+        },
     };
 
     match i += mutex.lock().unwrap().i {
         _ => {
             println!("{}", mutex.lock().unwrap().i);
-        }
+        },
     };
 }
 
 #[derive(Debug)]
 enum RecursiveEnum {
-    Foo(Option<Box<RecursiveEnum>>)
+    Foo(Option<Box<RecursiveEnum>>),
 }
 
 #[derive(Debug)]
 enum GenericRecursiveEnum<T> {
-    Foo(T, Option<Box<GenericRecursiveEnum<T>>>)
+    Foo(T, Option<Box<GenericRecursiveEnum<T>>>),
 }
 
 fn should_not_cause_stack_overflow() {
@@ -506,20 +535,20 @@ fn should_not_cause_stack_overflow() {
     match f {
         RecursiveEnum::Foo(Some(f)) => {
             println!("{:?}", f)
-        }
+        },
         RecursiveEnum::Foo(f) => {
             println!("{:?}", f)
-        }
+        },
     }
 
     let f = GenericRecursiveEnum::Foo(1u64, Some(Box::new(GenericRecursiveEnum::Foo(2u64, None))));
     match f {
         GenericRecursiveEnum::Foo(i, Some(f)) => {
             println!("{} {:?}", i, f)
-        }
+        },
         GenericRecursiveEnum::Foo(i, f) => {
             println!("{} {:?}", i, f)
-        }
+        },
     }
 }
 
diff --git a/src/tools/clippy/tests/ui/significant_drop_in_scrutinee.stderr b/src/tools/clippy/tests/ui/significant_drop_in_scrutinee.stderr
index c442e93f539..af160564985 100644
--- a/src/tools/clippy/tests/ui/significant_drop_in_scrutinee.stderr
+++ b/src/tools/clippy/tests/ui/significant_drop_in_scrutinee.stderr
@@ -102,13 +102,13 @@ LL |         match mutex3.lock().unwrap().s.as_str() {
    |               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: temporary with significant drop in match scrutinee
-  --> $DIR/significant_drop_in_scrutinee.rs:263:22
+  --> $DIR/significant_drop_in_scrutinee.rs:262:22
    |
 LL |         match (true, mutex3.lock().unwrap().s.as_str()) {
    |                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: temporary with significant drop in match scrutinee
-  --> $DIR/significant_drop_in_scrutinee.rs:282:11
+  --> $DIR/significant_drop_in_scrutinee.rs:281:11
    |
 LL |     match mutex.lock().unwrap().s.len() > 1 {
    |           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -120,7 +120,7 @@ LL ~     match value {
    |
 
 error: temporary with significant drop in match scrutinee
-  --> $DIR/significant_drop_in_scrutinee.rs:289:11
+  --> $DIR/significant_drop_in_scrutinee.rs:288:11
    |
 LL |     match 1 < mutex.lock().unwrap().s.len() {
    |           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -132,7 +132,7 @@ LL ~     match value {
    |
 
 error: temporary with significant drop in match scrutinee
-  --> $DIR/significant_drop_in_scrutinee.rs:305:11
+  --> $DIR/significant_drop_in_scrutinee.rs:306:11
    |
 LL |     match mutex1.lock().unwrap().s.len() < mutex2.lock().unwrap().s.len() {
    |           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -144,7 +144,7 @@ LL ~     match value {
    |
 
 error: temporary with significant drop in match scrutinee
-  --> $DIR/significant_drop_in_scrutinee.rs:312:11
+  --> $DIR/significant_drop_in_scrutinee.rs:317:11
    |
 LL |     match mutex1.lock().unwrap().s.len() >= mutex2.lock().unwrap().s.len() {
    |           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -156,7 +156,7 @@ LL ~     match value {
    |
 
 error: temporary with significant drop in match scrutinee
-  --> $DIR/significant_drop_in_scrutinee.rs:343:11
+  --> $DIR/significant_drop_in_scrutinee.rs:352:11
    |
 LL |     match get_mutex_guard().s.len() > 1 {
    |           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -168,31 +168,53 @@ LL ~     match value {
    |
 
 error: temporary with significant drop in match scrutinee
-  --> $DIR/significant_drop_in_scrutinee.rs:360:11
+  --> $DIR/significant_drop_in_scrutinee.rs:369:11
    |
-LL |     match match i { 100 => mutex1.lock().unwrap(), _ => mutex2.lock().unwrap() }.s.len() > 1 {
-   |           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL |       match match i {
+   |  ___________^
+LL | |         100 => mutex1.lock().unwrap(),
+LL | |         _ => mutex2.lock().unwrap(),
+LL | |     }
+LL | |     .s
+LL | |     .len()
+LL | |         > 1
+   | |___________^
    |
 help: try moving the temporary above the match
    |
-LL ~     let value = match i { 100 => mutex1.lock().unwrap(), _ => mutex2.lock().unwrap() }.s.len() > 1;
-LL ~     match value {
-   |
+LL ~     let value = match i {
+LL +         100 => mutex1.lock().unwrap(),
+LL +         _ => mutex2.lock().unwrap(),
+LL +     }
+LL +     .s
+LL +     .len()
+ ...
 
 error: temporary with significant drop in match scrutinee
-  --> $DIR/significant_drop_in_scrutinee.rs:379:11
+  --> $DIR/significant_drop_in_scrutinee.rs:395:11
    |
-LL |     match if i > 1 { mutex1.lock().unwrap() } else { mutex2.lock().unwrap() }.s.len() > 1 {
-   |           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL |       match if i > 1 {
+   |  ___________^
+LL | |         mutex1.lock().unwrap()
+LL | |     } else {
+LL | |         mutex2.lock().unwrap()
+...  |
+LL | |     .len()
+LL | |         > 1
+   | |___________^
    |
 help: try moving the temporary above the match
    |
-LL ~     let value = if i > 1 { mutex1.lock().unwrap() } else { mutex2.lock().unwrap() }.s.len() > 1;
-LL ~     match value {
-   |
+LL ~     let value = if i > 1 {
+LL +         mutex1.lock().unwrap()
+LL +     } else {
+LL +         mutex2.lock().unwrap()
+LL +     }
+LL +     .s
+ ...
 
 error: temporary with significant drop in match scrutinee
-  --> $DIR/significant_drop_in_scrutinee.rs:421:11
+  --> $DIR/significant_drop_in_scrutinee.rs:449:11
    |
 LL |     match s.lock().deref().deref() {
    |           ^^^^^^^^^^^^^^^^^^^^^^^^
@@ -204,13 +226,13 @@ LL ~     match value {
    |
 
 error: temporary with significant drop in match scrutinee
-  --> $DIR/significant_drop_in_scrutinee.rs:447:11
+  --> $DIR/significant_drop_in_scrutinee.rs:477:11
    |
 LL |     match s.lock().deref().deref() {
    |           ^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: temporary with significant drop in match scrutinee
-  --> $DIR/significant_drop_in_scrutinee.rs:467:11
+  --> $DIR/significant_drop_in_scrutinee.rs:496:11
    |
 LL |     match mutex.lock().unwrap().i = i {
    |           ^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -222,7 +244,7 @@ LL ~     match () {
    |
 
 error: temporary with significant drop in match scrutinee
-  --> $DIR/significant_drop_in_scrutinee.rs:473:11
+  --> $DIR/significant_drop_in_scrutinee.rs:502:11
    |
 LL |     match i = mutex.lock().unwrap().i {
    |           ^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -234,7 +256,7 @@ LL ~     match () {
    |
 
 error: temporary with significant drop in match scrutinee
-  --> $DIR/significant_drop_in_scrutinee.rs:479:11
+  --> $DIR/significant_drop_in_scrutinee.rs:508:11
    |
 LL |     match mutex.lock().unwrap().i += 1 {
    |           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -246,7 +268,7 @@ LL ~     match () {
    |
 
 error: temporary with significant drop in match scrutinee
-  --> $DIR/significant_drop_in_scrutinee.rs:485:11
+  --> $DIR/significant_drop_in_scrutinee.rs:514:11
    |
 LL |     match i += mutex.lock().unwrap().i {
    |           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
diff --git a/src/tools/clippy/tests/ui/undocumented_unsafe_blocks.rs b/src/tools/clippy/tests/ui/undocumented_unsafe_blocks.rs
index 7be15b0b2dd..33b6a82f9d2 100644
--- a/src/tools/clippy/tests/ui/undocumented_unsafe_blocks.rs
+++ b/src/tools/clippy/tests/ui/undocumented_unsafe_blocks.rs
@@ -1,7 +1,7 @@
 // aux-build:proc_macro_unsafe.rs
 
 #![warn(clippy::undocumented_unsafe_blocks)]
-#![allow(clippy::let_unit_value)]
+#![allow(clippy::let_unit_value, clippy::missing_safety_doc)]
 
 extern crate proc_macro_unsafe;
 
@@ -334,4 +334,155 @@ pub fn print_binary_tree() {
     println!("{}", unsafe { String::from_utf8_unchecked(vec![]) });
 }
 
+mod unsafe_impl_smoke_test {
+    unsafe trait A {}
+
+    // error: no safety comment
+    unsafe impl A for () {}
+
+    // Safety: ok
+    unsafe impl A for (i32) {}
+
+    mod sub_mod {
+        // error:
+        unsafe impl B for (u32) {}
+        unsafe trait B {}
+    }
+
+    #[rustfmt::skip]
+    mod sub_mod2 {
+        // 
+        // SAFETY: ok
+        // 
+
+        unsafe impl B for (u32) {}
+        unsafe trait B {}
+    }
+}
+
+mod unsafe_impl_from_macro {
+    unsafe trait T {}
+
+    // error
+    macro_rules! no_safety_comment {
+        ($t:ty) => {
+            unsafe impl T for $t {}
+        };
+    }
+
+    // ok
+    no_safety_comment!(());
+
+    // ok
+    macro_rules! with_safety_comment {
+        ($t:ty) => {
+            // SAFETY:
+            unsafe impl T for $t {}
+        };
+    }
+
+    // ok
+    with_safety_comment!((i32));
+}
+
+mod unsafe_impl_macro_and_not_macro {
+    unsafe trait T {}
+
+    // error
+    macro_rules! no_safety_comment {
+        ($t:ty) => {
+            unsafe impl T for $t {}
+        };
+    }
+
+    // ok
+    no_safety_comment!(());
+
+    // error
+    unsafe impl T for (i32) {}
+
+    // ok
+    no_safety_comment!(u32);
+
+    // error
+    unsafe impl T for (bool) {}
+}
+
+#[rustfmt::skip]
+mod unsafe_impl_valid_comment {
+    unsafe trait SaFety {}
+    // SaFety:
+    unsafe impl SaFety for () {}
+
+    unsafe trait MultiLineComment {}
+    // The following impl is safe
+    // ...
+    // Safety: reason
+    unsafe impl MultiLineComment for () {}
+
+    unsafe trait NoAscii {}
+    // 安全 SAFETY: 以下のコードは安全です
+    unsafe impl NoAscii for () {}
+
+    unsafe trait InlineAndPrecedingComment {}
+    // SAFETY:
+    /* comment */ unsafe impl InlineAndPrecedingComment for () {}
+
+    unsafe trait BuriedSafety {}
+    // Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor
+    // incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation
+    // ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in
+    // reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint
+    // occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est
+    // laborum. Safety:
+    // Tellus elementum sagittis vitae et leo duis ut diam quam. Sit amet nulla facilisi
+    // morbi tempus iaculis urna. Amet luctus venenatis lectus magna. At quis risus sed vulputate odio
+    // ut. Luctus venenatis lectus magna fringilla urna. Tortor id aliquet lectus proin nibh nisl
+    // condimentum id venenatis. Vulputate dignissim suspendisse in est ante in nibh mauris cursus.
+    unsafe impl BuriedSafety for () {}
+
+    unsafe trait MultiLineBlockComment {}
+    /* This is a description
+     * Safety: */
+    unsafe impl MultiLineBlockComment for () {}
+}
+
+#[rustfmt::skip]
+mod unsafe_impl_invalid_comment {
+    unsafe trait NoComment {}
+
+    unsafe impl NoComment for () {}
+
+    unsafe trait InlineComment {}
+
+    /* SAFETY: */ unsafe impl InlineComment for () {}
+
+    unsafe trait TrailingComment {}
+
+    unsafe impl TrailingComment for () {} // SAFETY:
+
+    unsafe trait Interference {}
+    // SAFETY:
+    const BIG_NUMBER: i32 = 1000000;
+    unsafe impl Interference for () {}
+}
+
+unsafe trait ImplInFn {}
+
+fn impl_in_fn() {
+    // error
+    unsafe impl ImplInFn for () {}
+
+    // SAFETY: ok
+    unsafe impl ImplInFn for (i32) {}
+}
+
+unsafe trait CrateRoot {}
+
+// error
+unsafe impl CrateRoot for () {}
+
+// SAFETY: ok
+unsafe impl CrateRoot for (i32) {}
+
 fn main() {}
diff --git a/src/tools/clippy/tests/ui/undocumented_unsafe_blocks.stderr b/src/tools/clippy/tests/ui/undocumented_unsafe_blocks.stderr
index 87d445bd7b8..b79949e9d06 100644
--- a/src/tools/clippy/tests/ui/undocumented_unsafe_blocks.stderr
+++ b/src/tools/clippy/tests/ui/undocumented_unsafe_blocks.stderr
@@ -147,5 +147,121 @@ LL |     println!("{}", unsafe { String::from_utf8_unchecked(vec![]) });
    |
    = help: consider adding a safety comment on the preceding line
 
-error: aborting due to 18 previous errors
+error: unsafe impl missing a safety comment
+  --> $DIR/undocumented_unsafe_blocks.rs:341:5
+   |
+LL |     unsafe impl A for () {}
+   |     ^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = help: consider adding a safety comment on the preceding line
+
+error: unsafe impl missing a safety comment
+  --> $DIR/undocumented_unsafe_blocks.rs:348:9
+   |
+LL |         unsafe impl B for (u32) {}
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = help: consider adding a safety comment on the preceding line
+
+error: unsafe impl missing a safety comment
+  --> $DIR/undocumented_unsafe_blocks.rs:369:13
+   |
+LL |             unsafe impl T for $t {}
+   |             ^^^^^^^^^^^^^^^^^^^^^^^
+...
+LL |     no_safety_comment!(());
+   |     ---------------------- in this macro invocation
+   |
+   = help: consider adding a safety comment on the preceding line
+   = note: this error originates in the macro `no_safety_comment` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: unsafe impl missing a safety comment
+  --> $DIR/undocumented_unsafe_blocks.rs:394:13
+   |
+LL |             unsafe impl T for $t {}
+   |             ^^^^^^^^^^^^^^^^^^^^^^^
+...
+LL |     no_safety_comment!(());
+   |     ---------------------- in this macro invocation
+   |
+   = help: consider adding a safety comment on the preceding line
+   = note: this error originates in the macro `no_safety_comment` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: unsafe impl missing a safety comment
+  --> $DIR/undocumented_unsafe_blocks.rs:402:5
+   |
+LL |     unsafe impl T for (i32) {}
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = help: consider adding a safety comment on the preceding line
+
+error: unsafe impl missing a safety comment
+  --> $DIR/undocumented_unsafe_blocks.rs:394:13
+   |
+LL |             unsafe impl T for $t {}
+   |             ^^^^^^^^^^^^^^^^^^^^^^^
+...
+LL |     no_safety_comment!(u32);
+   |     ----------------------- in this macro invocation
+   |
+   = help: consider adding a safety comment on the preceding line
+   = note: this error originates in the macro `no_safety_comment` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: unsafe impl missing a safety comment
+  --> $DIR/undocumented_unsafe_blocks.rs:408:5
+   |
+LL |     unsafe impl T for (bool) {}
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = help: consider adding a safety comment on the preceding line
+
+error: unsafe impl missing a safety comment
+  --> $DIR/undocumented_unsafe_blocks.rs:454:5
+   |
+LL |     unsafe impl NoComment for () {}
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = help: consider adding a safety comment on the preceding line
+
+error: unsafe impl missing a safety comment
+  --> $DIR/undocumented_unsafe_blocks.rs:458:19
+   |
+LL |     /* SAFETY: */ unsafe impl InlineComment for () {}
+   |                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = help: consider adding a safety comment on the preceding line
+
+error: unsafe impl missing a safety comment
+  --> $DIR/undocumented_unsafe_blocks.rs:462:5
+   |
+LL |     unsafe impl TrailingComment for () {} // SAFETY:
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = help: consider adding a safety comment on the preceding line
+
+error: unsafe impl missing a safety comment
+  --> $DIR/undocumented_unsafe_blocks.rs:467:5
+   |
+LL |     unsafe impl Interference for () {}
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = help: consider adding a safety comment on the preceding line
+
+error: unsafe impl missing a safety comment
+  --> $DIR/undocumented_unsafe_blocks.rs:474:5
+   |
+LL |     unsafe impl ImplInFn for () {}
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = help: consider adding a safety comment on the preceding line
+
+error: unsafe impl missing a safety comment
+  --> $DIR/undocumented_unsafe_blocks.rs:483:1
+   |
+LL | unsafe impl CrateRoot for () {}
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = help: consider adding a safety comment on the preceding line
+
+error: aborting due to 31 previous errors
 
diff --git a/src/tools/clippy/tests/ui/unit_cmp.rs b/src/tools/clippy/tests/ui/unit_cmp.rs
index 8d3a4eed82e..3d271104361 100644
--- a/src/tools/clippy/tests/ui/unit_cmp.rs
+++ b/src/tools/clippy/tests/ui/unit_cmp.rs
@@ -1,5 +1,9 @@
 #![warn(clippy::unit_cmp)]
-#![allow(clippy::no_effect, clippy::unnecessary_operation)]
+#![allow(
+    clippy::no_effect,
+    clippy::unnecessary_operation,
+    clippy::derive_partial_eq_without_eq
+)]
 
 #[derive(PartialEq)]
 pub struct ContainsUnit(()); // should be fine
diff --git a/src/tools/clippy/tests/ui/unit_cmp.stderr b/src/tools/clippy/tests/ui/unit_cmp.stderr
index 824506a4257..41cf19ae685 100644
--- a/src/tools/clippy/tests/ui/unit_cmp.stderr
+++ b/src/tools/clippy/tests/ui/unit_cmp.stderr
@@ -1,5 +1,5 @@
 error: ==-comparison of unit values detected. This will always be true
-  --> $DIR/unit_cmp.rs:12:8
+  --> $DIR/unit_cmp.rs:16:8
    |
 LL |       if {
    |  ________^
@@ -12,7 +12,7 @@ LL | |     } {}
    = note: `-D clippy::unit-cmp` implied by `-D warnings`
 
 error: >-comparison of unit values detected. This will always be false
-  --> $DIR/unit_cmp.rs:18:8
+  --> $DIR/unit_cmp.rs:22:8
    |
 LL |       if {
    |  ________^
@@ -23,7 +23,7 @@ LL | |     } {}
    | |_____^
 
 error: `assert_eq` of unit values detected. This will always succeed
-  --> $DIR/unit_cmp.rs:24:5
+  --> $DIR/unit_cmp.rs:28:5
    |
 LL | /     assert_eq!(
 LL | |         {
@@ -35,7 +35,7 @@ LL | |     );
    | |_____^
 
 error: `debug_assert_eq` of unit values detected. This will always succeed
-  --> $DIR/unit_cmp.rs:32:5
+  --> $DIR/unit_cmp.rs:36:5
    |
 LL | /     debug_assert_eq!(
 LL | |         {
@@ -47,7 +47,7 @@ LL | |     );
    | |_____^
 
 error: `assert_ne` of unit values detected. This will always fail
-  --> $DIR/unit_cmp.rs:41:5
+  --> $DIR/unit_cmp.rs:45:5
    |
 LL | /     assert_ne!(
 LL | |         {
@@ -59,7 +59,7 @@ LL | |     );
    | |_____^
 
 error: `debug_assert_ne` of unit values detected. This will always fail
-  --> $DIR/unit_cmp.rs:49:5
+  --> $DIR/unit_cmp.rs:53:5
    |
 LL | /     debug_assert_ne!(
 LL | |         {
diff --git a/src/tools/clippy/tests/ui/unnecessary_to_owned.fixed b/src/tools/clippy/tests/ui/unnecessary_to_owned.fixed
index 7455e22d49b..f4f76cd3dd4 100644
--- a/src/tools/clippy/tests/ui/unnecessary_to_owned.fixed
+++ b/src/tools/clippy/tests/ui/unnecessary_to_owned.fixed
@@ -78,10 +78,10 @@ fn main() {
     require_slice(array.as_ref());
     require_slice(array_ref.as_ref());
     require_slice(slice);
-    require_slice(x_ref);
+    require_slice(&x_ref.to_owned()); // No longer flagged because of #8759.
 
     require_x(&Cow::<X>::Owned(x.clone()));
-    require_x(x_ref);
+    require_x(&x_ref.to_owned()); // No longer flagged because of #8759.
 
     require_deref_c_str(c_str);
     require_deref_os_str(os_str);
@@ -152,6 +152,7 @@ fn main() {
     require_os_str(&OsString::from("x"));
     require_path(&std::path::PathBuf::from("x"));
     require_str(&String::from("x"));
+    require_slice(&[String::from("x")]);
 }
 
 fn require_c_str(_: &CStr) {}
@@ -272,3 +273,59 @@ mod issue_8507 {
         Box::new(build(y))
     }
 }
+
+// https://github.com/rust-lang/rust-clippy/issues/8759
+mod issue_8759 {
+    #![allow(dead_code)]
+
+    #[derive(Default)]
+    struct View {}
+
+    impl std::borrow::ToOwned for View {
+        type Owned = View;
+        fn to_owned(&self) -> Self::Owned {
+            View {}
+        }
+    }
+
+    #[derive(Default)]
+    struct RenderWindow {
+        default_view: View,
+    }
+
+    impl RenderWindow {
+        fn default_view(&self) -> &View {
+            &self.default_view
+        }
+        fn set_view(&mut self, _view: &View) {}
+    }
+
+    fn main() {
+        let mut rw = RenderWindow::default();
+        rw.set_view(&rw.default_view().to_owned());
+    }
+}
+
+mod issue_8759_variant {
+    #![allow(dead_code)]
+
+    #[derive(Clone, Default)]
+    struct View {}
+
+    #[derive(Default)]
+    struct RenderWindow {
+        default_view: View,
+    }
+
+    impl RenderWindow {
+        fn default_view(&self) -> &View {
+            &self.default_view
+        }
+        fn set_view(&mut self, _view: &View) {}
+    }
+
+    fn main() {
+        let mut rw = RenderWindow::default();
+        rw.set_view(&rw.default_view().to_owned());
+    }
+}
diff --git a/src/tools/clippy/tests/ui/unnecessary_to_owned.rs b/src/tools/clippy/tests/ui/unnecessary_to_owned.rs
index bbcd00ad220..fe09a489ab0 100644
--- a/src/tools/clippy/tests/ui/unnecessary_to_owned.rs
+++ b/src/tools/clippy/tests/ui/unnecessary_to_owned.rs
@@ -78,10 +78,10 @@ fn main() {
     require_slice(&array.to_owned());
     require_slice(&array_ref.to_owned());
     require_slice(&slice.to_owned());
-    require_slice(&x_ref.to_owned());
+    require_slice(&x_ref.to_owned()); // No longer flagged because of #8759.
 
     require_x(&Cow::<X>::Owned(x.clone()).into_owned());
-    require_x(&x_ref.to_owned());
+    require_x(&x_ref.to_owned()); // No longer flagged because of #8759.
 
     require_deref_c_str(c_str.to_owned());
     require_deref_os_str(os_str.to_owned());
@@ -152,6 +152,7 @@ fn main() {
     require_os_str(&OsString::from("x").to_os_string());
     require_path(&std::path::PathBuf::from("x").to_path_buf());
     require_str(&String::from("x").to_string());
+    require_slice(&[String::from("x")].to_owned());
 }
 
 fn require_c_str(_: &CStr) {}
@@ -272,3 +273,59 @@ mod issue_8507 {
         Box::new(build(y.to_string()))
     }
 }
+
+// https://github.com/rust-lang/rust-clippy/issues/8759
+mod issue_8759 {
+    #![allow(dead_code)]
+
+    #[derive(Default)]
+    struct View {}
+
+    impl std::borrow::ToOwned for View {
+        type Owned = View;
+        fn to_owned(&self) -> Self::Owned {
+            View {}
+        }
+    }
+
+    #[derive(Default)]
+    struct RenderWindow {
+        default_view: View,
+    }
+
+    impl RenderWindow {
+        fn default_view(&self) -> &View {
+            &self.default_view
+        }
+        fn set_view(&mut self, _view: &View) {}
+    }
+
+    fn main() {
+        let mut rw = RenderWindow::default();
+        rw.set_view(&rw.default_view().to_owned());
+    }
+}
+
+mod issue_8759_variant {
+    #![allow(dead_code)]
+
+    #[derive(Clone, Default)]
+    struct View {}
+
+    #[derive(Default)]
+    struct RenderWindow {
+        default_view: View,
+    }
+
+    impl RenderWindow {
+        fn default_view(&self) -> &View {
+            &self.default_view
+        }
+        fn set_view(&mut self, _view: &View) {}
+    }
+
+    fn main() {
+        let mut rw = RenderWindow::default();
+        rw.set_view(&rw.default_view().to_owned());
+    }
+}
diff --git a/src/tools/clippy/tests/ui/unnecessary_to_owned.stderr b/src/tools/clippy/tests/ui/unnecessary_to_owned.stderr
index f9713559e4f..af7e7b41fb0 100644
--- a/src/tools/clippy/tests/ui/unnecessary_to_owned.stderr
+++ b/src/tools/clippy/tests/ui/unnecessary_to_owned.stderr
@@ -47,6 +47,18 @@ note: this value is dropped without further use
 LL |     require_str(&String::from("x").to_string());
    |                  ^^^^^^^^^^^^^^^^^
 
+error: redundant clone
+  --> $DIR/unnecessary_to_owned.rs:155: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:155:20
+   |
+LL |     require_slice(&[String::from("x")].to_owned());
+   |                    ^^^^^^^^^^^^^^^^^^^
+
 error: unnecessary use of `into_owned`
   --> $DIR/unnecessary_to_owned.rs:60:36
    |
@@ -151,24 +163,12 @@ error: unnecessary use of `to_owned`
 LL |     require_slice(&slice.to_owned());
    |                   ^^^^^^^^^^^^^^^^^ help: use: `slice`
 
-error: unnecessary use of `to_owned`
-  --> $DIR/unnecessary_to_owned.rs:81:19
-   |
-LL |     require_slice(&x_ref.to_owned());
-   |                   ^^^^^^^^^^^^^^^^^ help: use: `x_ref`
-
 error: unnecessary use of `into_owned`
   --> $DIR/unnecessary_to_owned.rs:83: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:84:15
-   |
-LL |     require_x(&x_ref.to_owned());
-   |               ^^^^^^^^^^^^^^^^^ help: use: `x_ref`
-
 error: unnecessary use of `to_owned`
   --> $DIR/unnecessary_to_owned.rs:86:25
    |
@@ -476,7 +476,7 @@ LL |     let _ = IntoIterator::into_iter([std::path::PathBuf::new()][..].to_owne
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use: `[std::path::PathBuf::new()][..].iter().cloned()`
 
 error: unnecessary use of `to_vec`
-  --> $DIR/unnecessary_to_owned.rs:197:14
+  --> $DIR/unnecessary_to_owned.rs:198:14
    |
 LL |     for t in file_types.to_vec() {
    |              ^^^^^^^^^^^^^^^^^^^
@@ -492,22 +492,22 @@ LL +         let path = match get_file_path(t) {
    | 
 
 error: unnecessary use of `to_vec`
-  --> $DIR/unnecessary_to_owned.rs:220:14
+  --> $DIR/unnecessary_to_owned.rs:221:14
    |
 LL |     let _ = &["x"][..].to_vec().into_iter();
    |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use: `["x"][..].iter().cloned()`
 
 error: unnecessary use of `to_vec`
-  --> $DIR/unnecessary_to_owned.rs:225:14
+  --> $DIR/unnecessary_to_owned.rs:226:14
    |
 LL |     let _ = &["x"][..].to_vec().into_iter();
    |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use: `["x"][..].iter().copied()`
 
 error: unnecessary use of `to_string`
-  --> $DIR/unnecessary_to_owned.rs:272:24
+  --> $DIR/unnecessary_to_owned.rs:273:24
    |
 LL |         Box::new(build(y.to_string()))
    |                        ^^^^^^^^^^^^^ help: use: `y`
 
-error: aborting due to 79 previous errors
+error: aborting due to 78 previous errors
 
diff --git a/src/tools/clippy/tests/ui/useless_conversion_try.rs b/src/tools/clippy/tests/ui/useless_conversion_try.rs
index 3787ea99144..39f54c27bee 100644
--- a/src/tools/clippy/tests/ui/useless_conversion_try.rs
+++ b/src/tools/clippy/tests/ui/useless_conversion_try.rs
@@ -1,7 +1,5 @@
 #![deny(clippy::useless_conversion)]
 
-use std::convert::{TryFrom, TryInto};
-
 fn test_generic<T: Copy>(val: T) -> T {
     let _ = T::try_from(val).unwrap();
     val.try_into().unwrap()
diff --git a/src/tools/clippy/tests/ui/useless_conversion_try.stderr b/src/tools/clippy/tests/ui/useless_conversion_try.stderr
index 2e0d9129bfb..b691c13f7db 100644
--- a/src/tools/clippy/tests/ui/useless_conversion_try.stderr
+++ b/src/tools/clippy/tests/ui/useless_conversion_try.stderr
@@ -1,5 +1,5 @@
 error: useless conversion to the same type: `T`
-  --> $DIR/useless_conversion_try.rs:6:13
+  --> $DIR/useless_conversion_try.rs:4:13
    |
 LL |     let _ = T::try_from(val).unwrap();
    |             ^^^^^^^^^^^^^^^^
@@ -12,7 +12,7 @@ LL | #![deny(clippy::useless_conversion)]
    = help: consider removing `T::try_from()`
 
 error: useless conversion to the same type: `T`
-  --> $DIR/useless_conversion_try.rs:7:5
+  --> $DIR/useless_conversion_try.rs:5:5
    |
 LL |     val.try_into().unwrap()
    |     ^^^^^^^^^^^^^^
@@ -20,7 +20,7 @@ LL |     val.try_into().unwrap()
    = help: consider removing `.try_into()`
 
 error: useless conversion to the same type: `std::string::String`
-  --> $DIR/useless_conversion_try.rs:29:21
+  --> $DIR/useless_conversion_try.rs:27:21
    |
 LL |     let _: String = "foo".to_string().try_into().unwrap();
    |                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -28,7 +28,7 @@ LL |     let _: String = "foo".to_string().try_into().unwrap();
    = help: consider removing `.try_into()`
 
 error: useless conversion to the same type: `std::string::String`
-  --> $DIR/useless_conversion_try.rs:30:21
+  --> $DIR/useless_conversion_try.rs:28:21
    |
 LL |     let _: String = TryFrom::try_from("foo".to_string()).unwrap();
    |                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -36,7 +36,7 @@ LL |     let _: String = TryFrom::try_from("foo".to_string()).unwrap();
    = help: consider removing `TryFrom::try_from()`
 
 error: useless conversion to the same type: `std::string::String`
-  --> $DIR/useless_conversion_try.rs:31:13
+  --> $DIR/useless_conversion_try.rs:29:13
    |
 LL |     let _ = String::try_from("foo".to_string()).unwrap();
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -44,7 +44,7 @@ LL |     let _ = String::try_from("foo".to_string()).unwrap();
    = help: consider removing `String::try_from()`
 
 error: useless conversion to the same type: `std::string::String`
-  --> $DIR/useless_conversion_try.rs:32:13
+  --> $DIR/useless_conversion_try.rs:30:13
    |
 LL |     let _ = String::try_from(format!("A: {:04}", 123)).unwrap();
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -52,7 +52,7 @@ LL |     let _ = String::try_from(format!("A: {:04}", 123)).unwrap();
    = help: consider removing `String::try_from()`
 
 error: useless conversion to the same type: `std::string::String`
-  --> $DIR/useless_conversion_try.rs:33:21
+  --> $DIR/useless_conversion_try.rs:31:21
    |
 LL |     let _: String = format!("Hello {}", "world").try_into().unwrap();
    |                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -60,7 +60,7 @@ LL |     let _: String = format!("Hello {}", "world").try_into().unwrap();
    = help: consider removing `.try_into()`
 
 error: useless conversion to the same type: `std::string::String`
-  --> $DIR/useless_conversion_try.rs:34:21
+  --> $DIR/useless_conversion_try.rs:32:21
    |
 LL |     let _: String = "".to_owned().try_into().unwrap();
    |                     ^^^^^^^^^^^^^^^^^^^^^^^^
@@ -68,7 +68,7 @@ LL |     let _: String = "".to_owned().try_into().unwrap();
    = help: consider removing `.try_into()`
 
 error: useless conversion to the same type: `std::string::String`
-  --> $DIR/useless_conversion_try.rs:35:27
+  --> $DIR/useless_conversion_try.rs:33:27
    |
 LL |     let _: String = match String::from("_").try_into() {
    |                           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
diff --git a/src/tools/clippy/tests/ui/vec_init_then_push.rs b/src/tools/clippy/tests/ui/vec_init_then_push.rs
index 5099aad83bc..531745424a7 100644
--- a/src/tools/clippy/tests/ui/vec_init_then_push.rs
+++ b/src/tools/clippy/tests/ui/vec_init_then_push.rs
@@ -29,6 +29,12 @@ fn main() {
         // no lint
         vec.push(1);
     }
+
+    let mut vec = Vec::with_capacity(5);
+    vec.push(1);
+    vec.push(2);
+    vec.push(3);
+    vec.push(4);
 }
 
 pub fn no_lint() -> Vec<i32> {
@@ -44,3 +50,57 @@ pub fn no_lint() -> Vec<i32> {
         }
     }
 }
+
+fn _from_iter(items: impl Iterator<Item = u32>) -> Vec<u32> {
+    let mut v = Vec::new();
+    v.push(0);
+    v.push(1);
+    v.extend(items);
+    v
+}
+
+fn _cond_push(x: bool) -> Vec<u32> {
+    let mut v = Vec::new();
+    v.push(0);
+    if x {
+        v.push(1);
+    }
+    v.push(2);
+    v
+}
+
+fn _push_then_edit(x: u32) -> Vec<u32> {
+    let mut v = Vec::new();
+    v.push(x);
+    v.push(1);
+    v[0] = v[1] + 5;
+    v
+}
+
+fn _cond_push_with_large_start(x: bool) -> Vec<u32> {
+    let mut v = Vec::new();
+    v.push(0);
+    v.push(1);
+    v.push(0);
+    v.push(1);
+    v.push(0);
+    v.push(0);
+    v.push(1);
+    v.push(0);
+    if x {
+        v.push(1);
+    }
+
+    let mut v2 = Vec::new();
+    v2.push(0);
+    v2.push(1);
+    v2.push(0);
+    v2.push(1);
+    v2.push(0);
+    v2.push(0);
+    v2.push(1);
+    v2.push(0);
+    v2.extend(&v);
+
+    v2
+}
diff --git a/src/tools/clippy/tests/ui/vec_init_then_push.stderr b/src/tools/clippy/tests/ui/vec_init_then_push.stderr
index 9ec3e10e624..50b029fc337 100644
--- a/src/tools/clippy/tests/ui/vec_init_then_push.stderr
+++ b/src/tools/clippy/tests/ui/vec_init_then_push.stderr
@@ -3,7 +3,7 @@ error: calls to `push` immediately after creation
    |
 LL | /     let mut def_err: Vec<u32> = Default::default();
 LL | |     def_err.push(0);
-   | |____________________^ help: consider using the `vec![]` macro: `let mut def_err: Vec<u32> = vec![..];`
+   | |____________________^ help: consider using the `vec![]` macro: `let def_err: Vec<u32> = vec![..];`
    |
    = note: `-D clippy::vec-init-then-push` implied by `-D warnings`
 
@@ -30,5 +30,37 @@ LL | /     new_err = Vec::new();
 LL | |     new_err.push(0);
    | |____________________^ help: consider using the `vec![]` macro: `new_err = vec![..];`
 
-error: aborting due to 4 previous errors
+error: calls to `push` immediately after creation
+  --> $DIR/vec_init_then_push.rs:73:5
+   |
+LL | /     let mut v = Vec::new();
+LL | |     v.push(x);
+LL | |     v.push(1);
+   | |______________^ help: consider using the `vec![]` macro: `let mut v = vec![..];`
+
+error: calls to `push` immediately after creation
+  --> $DIR/vec_init_then_push.rs:81:5
+   |
+LL | /     let mut v = Vec::new();
+LL | |     v.push(0);
+LL | |     v.push(1);
+LL | |     v.push(0);
+...  |
+LL | |     v.push(1);
+LL | |     v.push(0);
+   | |______________^ help: consider using the `vec![]` macro: `let mut v = vec![..];`
+
+error: calls to `push` immediately after creation
+  --> $DIR/vec_init_then_push.rs:94:5
+   |
+LL | /     let mut v2 = Vec::new();
+LL | |     v2.push(0);
+LL | |     v2.push(1);
+LL | |     v2.push(0);
+...  |
+LL | |     v2.push(1);
+LL | |     v2.push(0);
+   | |_______________^ help: consider using the `vec![]` macro: `let mut v2 = vec![..];`
+
+error: aborting due to 7 previous errors
 
diff --git a/src/tools/clippy/util/gh-pages/index.html b/src/tools/clippy/util/gh-pages/index.html
index 97c974003c6..2076d129978 100644
--- a/src/tools/clippy/util/gh-pages/index.html
+++ b/src/tools/clippy/util/gh-pages/index.html
@@ -94,6 +94,29 @@ Otherwise, have a great day =^.^=
         @media (min-width: 992px) {
             .search-control {
                 margin-top: 0;
+                float: right;
+            }
+        }
+
+        @media (min-width: 405px) {
+            #upper-filters {
+                display: flex;
+            }
+        }
+
+        @media (max-width: 430px) {
+            /* Turn the version filter list to the left */
+            #version-filter-selector {
+                right: 0;
+                left: auto;
+            }
+        }
+
+        @media (max-width: 412px) {
+            #upper-filters,
+            .panel-body .search-control  {
+                padding-right: 8px;
+                padding-left: 8px;
             }
         }
 
@@ -244,7 +267,7 @@ Otherwise, have a great day =^.^=
             cursor: pointer;
         }
 
-        .theme-choice>li:hover {
+        .theme-choice > li:hover {
             background: var(--theme-hover);
         }
 
@@ -273,23 +296,44 @@ Otherwise, have a great day =^.^=
             border: 1px solid var(--theme-popup-border);
         }
 
-        #filter-label, #filter-clear {
+        #version-filter-selector .checkbox {
+            display: flex;
+        }
+
+        #version-filter {
+            min-width: available;
+        }
+
+        #version-filter li label {
+            padding-right: 0;
+            width: 35%;
+        }
+
+        .version-filter-input {
+            height: 60%;
+            width: 30%;
+            text-align: center;
+            border: none;
+            border-bottom: 1px solid #000000;
+        }
+
+        #filter-label, .filter-clear {
             background: var(--searchbar-bg);
             color: var(--searchbar-fg);
             border-color: var(--theme-popup-border);
             filter: brightness(95%);
         }
-        #filter-label:hover, #filter-clear:hover {
+        #filter-label:hover, .filter-clear:hover {
             filter: brightness(90%);
         }
-        #filter-input {
+        .filter-input {
             background: var(--searchbar-bg);
             color: var(--searchbar-fg);
             border-color: var(--theme-popup-border);
         }
 
-        #filter-input::-webkit-input-placeholder,
-        #filter-input::-moz-placeholder {
+        .filter-input::-webkit-input-placeholder,
+        .filter-input::-moz-placeholder {
             color: var(--searchbar-fg);
             opacity: 30%;
         }
@@ -338,7 +382,7 @@ Otherwise, have a great day =^.^=
 
             <div class="panel panel-default" ng-show="data">
                 <div class="panel-body row">
-                    <div class="col-12 col-md-4">
+                    <div id="upper-filters" class="col-12 col-md-4">
                         <div class="btn-group" filter-dropdown>
                             <button type="button" class="btn btn-default dropdown-toggle">
                                 Lint levels <span class="badge">{{selectedValuesCount(levels)}}</span> <span class="caret"></span>
@@ -391,13 +435,47 @@ Otherwise, have a great day =^.^=
                                 </li>
                             </ul>
                         </div>
+                        <div id="version-filter">
+                            <div class="btn-group" filter-dropdown>
+                                <button type="button" class="btn btn-default dropdown-toggle">
+                                    Version
+                                    <span id="version-filter-count" class="badge">
+                                        {{versionFilterCount(versionFilters)}}
+                                    </span>
+                                    <span class="caret"></span>
+                                </button>
+                                <ul id="version-filter-selector" class="dropdown-menu">
+                                    <li class="checkbox">
+                                        <label ng-click="clearVersionFilters()">
+                                            <input type="checkbox" class="invisible" />
+                                            Clear filters
+                                        </label>
+                                    </li>
+                                    <li role="separator" class="divider"></li>
+                                    <li class="checkbox" ng-repeat="(filter, vars) in versionFilters">
+                                        <label ng-attr-for="filter-{filter}">{{filter}}</label>
+                                        <span>1.</span>
+                                        <input type="number"
+                                                min="29"
+                                                ng-attr-id="filter-{filter}"
+                                                class="version-filter-input form-control filter-input"
+                                                maxlength="2"
+                                                ng-model="versionFilters[filter].minorVersion"
+                                                ng-model-options="{debounce: 50}"
+                                                ng-change="updateVersionFilters()" />
+                                        <span>.0</span>
+                                    </li>
+                                </ul>
+                            </div>
+                        </div>
+
                     </div>
-                    <div class="col-12 col-md-8 search-control">
+                    <div class="col-12 col-md-7 search-control">
                         <div class="input-group">
-                            <label class="input-group-addon" id="filter-label" for="filter-input">Filter:</label>
-                            <input type="text" class="form-control" placeholder="Keywords or search string" id="filter-input" ng-model="search" ng-model-options="{debounce: 50}"/>
+                            <label class="input-group-addon" id="filter-label" for="search-input">Filter:</label>
+                            <input type="text" class="form-control filter-input" placeholder="Keywords or search string" id="search-input" ng-model="search" ng-model-options="{debounce: 50}"/>
                             <span class="input-group-btn">
-                                <button id="filter-clear" class="btn" type="button" ng-click="search = ''">
+                                <button class="filter-clear btn" type="button" ng-click="search = ''">
                                     Clear
                                 </button>
                             </span>
@@ -406,12 +484,15 @@ Otherwise, have a great day =^.^=
                 </div>
             </div>
             <!-- The order of the filters should be from most likely to remove a lint to least likely to improve performance. -->
-            <article class="panel panel-default" id="{{lint.id}}" ng-repeat="lint in data | filter:bySearch | filter:byGroups | filter:byLevels">
+            <article class="panel panel-default" id="{{lint.id}}" ng-repeat="lint in data | filter:bySearch | filter:byGroups | filter:byLevels | filter:byVersion">
                 <header class="panel-heading" ng-click="open[lint.id] = !open[lint.id]">
                     <h2 class="panel-title">
                         <div class="panel-title-name">
                             <span>{{lint.id}}</span>
                             <a href="#{{lint.id}}" class="anchor label label-default" ng-click="open[lint.id] = true; $event.stopPropagation()">&para;</a>
+                            <a href="" id="clipboard-{{lint.id}}" class="anchor label label-default" ng-click="copyToClipboard(lint); $event.stopPropagation()">
+                                &#128203;
+                            </a>
                         </div>
 
                         <div class="panel-title-addons">
@@ -462,295 +543,6 @@ Otherwise, have a great day =^.^=
     <script src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/9.5.0/highlight.min.js"></script>
     <script src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/9.5.0/languages/rust.min.js"></script>
     <script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.4.12/angular.min.js"></script>
-    <script>
-    (function () {
-        var md = window.markdownit({
-            html: true,
-            linkify: true,
-            typographer: true,
-            highlight: function (str, lang) {
-                if (lang && hljs.getLanguage(lang)) {
-                    try {
-                        return '<pre class="hljs"><code>' +
-                            hljs.highlight(lang, str, true).value +
-                            '</code></pre>';
-                    } catch (__) {}
-                }
-
-                return '<pre class="hljs"><code>' + md.utils.escapeHtml(str) + '</code></pre>';
-            }
-        });
-
-        function scrollToLint(lintId) {
-            var target = document.getElementById(lintId);
-            if (!target) {
-                return;
-            }
-            target.scrollIntoView();
-        }
-
-        function scrollToLintByURL($scope) {
-            var removeListener = $scope.$on('ngRepeatFinished', function(ngRepeatFinishedEvent) {
-                scrollToLint(window.location.hash.slice(1));
-                removeListener();
-            });
-        }
-
-        function selectGroup($scope, selectedGroup) {
-            var groups = $scope.groups;
-            for (var group in groups) {
-                if (groups.hasOwnProperty(group)) {
-                    if (group === selectedGroup) {
-                        groups[group] = true;
-                    } else {
-                        groups[group] = false;
-                    }
-                }
-            }
-        }
-
-        angular.module("clippy", [])
-        .filter('markdown', function ($sce) {
-            return function (text) {
-                return $sce.trustAsHtml(
-                    md.render(text || '')
-                    // Oh deer, what a hack :O
-                    .replace('<table', '<table class="table"')
-                );
-            };
-        })
-        .directive('themeDropdown', function ($document) {
-            return {
-                restrict: 'A',
-                link: function ($scope, $element, $attr) {
-                    $element.bind('click', function () {
-                        $element.toggleClass('open');
-                        $element.addClass('open-recent');
-                    });
-
-                    $document.bind('click', function () {
-                        if (!$element.hasClass('open-recent')) {
-                            $element.removeClass('open');
-                        }
-                        $element.removeClass('open-recent');
-                    })
-                }
-            }
-        })
-        .directive('filterDropdown', function ($document) {
-            return {
-                restrict: 'A',
-                link: function ($scope, $element, $attr) {
-                    $element.bind('click', function (event) {
-                        if (event.target.closest('button')) {
-                            $element.toggleClass('open');
-                        } else {
-                            $element.addClass('open');
-                        }
-                        $element.addClass('open-recent');
-                    });
-
-                    $document.bind('click', function () {
-                        if (!$element.hasClass('open-recent')) {
-                            $element.removeClass('open');
-                        }
-                        $element.removeClass('open-recent');
-                    })
-                }
-            }
-        })
-        .directive('onFinishRender', function ($timeout) {
-            return {
-                restrict: 'A',
-                link: function (scope, element, attr) {
-                    if (scope.$last === true) {
-                        $timeout(function () {
-                            scope.$emit(attr.onFinishRender);
-                        });
-                    }
-                }
-            };
-        })
-        .controller("lintList", function ($scope, $http, $timeout) {
-            // Level filter
-            var LEVEL_FILTERS_DEFAULT = {allow: true, warn: true, deny: true, none: true};
-            $scope.levels = LEVEL_FILTERS_DEFAULT;
-            $scope.byLevels = function (lint) {
-                return $scope.levels[lint.level];
-            };
-
-            var GROUPS_FILTER_DEFAULT = {
-                cargo: true,
-                complexity: true,
-                correctness: true,
-                deprecated: false,
-                nursery: true,
-                pedantic: true,
-                perf: true,
-                restriction: true,
-                style: true,
-                suspicious: true,
-            };
-            $scope.groups = GROUPS_FILTER_DEFAULT;
-            const THEMES_DEFAULT = {
-                light: "Light",
-                rust: "Rust",
-                coal: "Coal",
-                navy: "Navy",
-                ayu: "Ayu"
-            };
-            $scope.themes = THEMES_DEFAULT;
-
-            $scope.selectTheme = function (theme) {
-                setTheme(theme, true);
-            }
-
-            $scope.toggleLevels = function (value) {
-                const levels = $scope.levels;
-                for (const key in levels) {
-                    if (levels.hasOwnProperty(key)) {
-                        levels[key] = value;
-                    }
-                }
-            };
-            $scope.toggleGroups = function (value) {
-                const groups = $scope.groups;
-                for (const key in groups) {
-                    if (groups.hasOwnProperty(key)) {
-                        groups[key] = value;
-                    }
-                }
-            };
-            $scope.selectedValuesCount = function (obj) {
-                return Object.values(obj).filter(x => x).length;
-            }
-            $scope.byGroups = function (lint) {
-                return $scope.groups[lint.group];
-            };
-
-            $scope.bySearch = function (lint, index, array) {
-                let searchStr = $scope.search;
-                // It can be `null` I haven't missed this value
-                if (searchStr == null || searchStr.length < 3) {
-                    return true;
-                }
-                searchStr = searchStr.toLowerCase();
-
-                // Search by id
-                if (lint.id.indexOf(searchStr.replace("-", "_")) !== -1) {
-                    return true;
-                }
-
-                // Search the description
-                // The use of `for`-loops instead of `foreach` enables us to return early
-                let terms = searchStr.split(" ");
-                let docsLowerCase = lint.docs.toLowerCase();
-                for (index = 0; index < terms.length; index++) {
-                    // This is more likely and will therefor be checked first
-                    if (docsLowerCase.indexOf(terms[index]) !== -1) {
-                        continue;
-                    }
-
-                    if (lint.id.indexOf(terms[index]) !== -1) {
-                        continue;
-                    }
-
-                    return false;
-                }
-
-                return true;
-            }
-
-            // Get data
-            $scope.open = {};
-            $scope.loading = true;
-            // This will be used to jump into the source code of the version that this documentation is for.
-            $scope.docVersion = window.location.pathname.split('/')[2] || "master";
-
-            if (window.location.hash.length > 1) {
-                $scope.search = window.location.hash.slice(1);
-                $scope.open[window.location.hash.slice(1)] = true;
-                scrollToLintByURL($scope);
-            }
-
-            $http.get('./lints.json')
-            .success(function (data) {
-                $scope.data = data;
-                $scope.loading = false;
-
-                var selectedGroup = getQueryVariable("sel");
-                if (selectedGroup) {
-                    selectGroup($scope, selectedGroup.toLowerCase());
-                }
-
-                scrollToLintByURL($scope);
-
-                setTimeout(function () {
-                    var el = document.getElementById('filter-input');
-                    if (el) { el.focus() }
-                }, 0);
-            })
-            .error(function (data) {
-                $scope.error = data;
-                $scope.loading = false;
-            });
-
-            window.addEventListener('hashchange', function () {
-                // trigger re-render
-                $timeout(function () {
-                    $scope.levels = LEVEL_FILTERS_DEFAULT;
-                    $scope.search = window.location.hash.slice(1);
-                    $scope.open[window.location.hash.slice(1)] = true;
-
-                    scrollToLintByURL($scope);
-                });
-                return true;
-            }, false);
-        });
-    })();
-
-    function getQueryVariable(variable) {
-        var query = window.location.search.substring(1);
-        var vars = query.split('&');
-        for (var i = 0; i < vars.length; i++) {
-            var pair = vars[i].split('=');
-            if (decodeURIComponent(pair[0]) == variable) {
-                return decodeURIComponent(pair[1]);
-            }
-        }
-    }
-
-    function setTheme(theme, store) {
-        let enableHighlight = false;
-        let enableNight = false;
-        let enableAyu = false;
-
-        if (theme == "ayu") {
-            enableAyu = true;
-        } else if (theme == "coal" || theme == "navy") {
-            enableNight = true;
-        } else if (theme == "rust") {
-            enableHighlight = true;
-        } else {
-            enableHighlight = true;
-            // this makes sure that an unknown theme request gets set to a known one
-            theme = "light";
-        }
-        document.getElementsByTagName("body")[0].className = theme;
-
-        document.getElementById("styleHighlight").disabled = !enableHighlight;
-        document.getElementById("styleNight").disabled = !enableNight;
-        document.getElementById("styleAyu").disabled = !enableAyu;
-
-        if (store) {
-            try {
-                localStorage.setItem('clippy-lint-list-theme', theme);
-            } catch (e) { }
-        }
-    }
-
-    // loading the theme after the initial load
-    setTheme(localStorage.getItem('clippy-lint-list-theme'), false);
-    </script>
+    <script src="script.js"></script>
 </body>
 </html>
diff --git a/src/tools/clippy/util/gh-pages/script.js b/src/tools/clippy/util/gh-pages/script.js
new file mode 100644
index 00000000000..bf4ce79b2cb
--- /dev/null
+++ b/src/tools/clippy/util/gh-pages/script.js
@@ -0,0 +1,371 @@
+(function () {
+    var md = window.markdownit({
+        html: true,
+        linkify: true,
+        typographer: true,
+        highlight: function (str, lang) {
+            if (lang && hljs.getLanguage(lang)) {
+                try {
+                    return '<pre class="hljs"><code>' +
+                        hljs.highlight(lang, str, true).value +
+                        '</code></pre>';
+                } catch (__) {}
+            }
+
+            return '<pre class="hljs"><code>' + md.utils.escapeHtml(str) + '</code></pre>';
+        }
+    });
+
+    function scrollToLint(lintId) {
+        var target = document.getElementById(lintId);
+        if (!target) {
+            return;
+        }
+        target.scrollIntoView();
+    }
+
+    function scrollToLintByURL($scope) {
+        var removeListener = $scope.$on('ngRepeatFinished', function(ngRepeatFinishedEvent) {
+            scrollToLint(window.location.hash.slice(1));
+            removeListener();
+        });
+    }
+
+    function selectGroup($scope, selectedGroup) {
+        var groups = $scope.groups;
+        for (var group in groups) {
+            if (groups.hasOwnProperty(group)) {
+                if (group === selectedGroup) {
+                    groups[group] = true;
+                } else {
+                    groups[group] = false;
+                }
+            }
+        }
+    }
+
+    angular.module("clippy", [])
+        .filter('markdown', function ($sce) {
+            return function (text) {
+                return $sce.trustAsHtml(
+                    md.render(text || '')
+                        // Oh deer, what a hack :O
+                        .replace('<table', '<table class="table"')
+                );
+            };
+        })
+        .directive('themeDropdown', function ($document) {
+            return {
+                restrict: 'A',
+                link: function ($scope, $element, $attr) {
+                    $element.bind('click', function () {
+                        $element.toggleClass('open');
+                        $element.addClass('open-recent');
+                    });
+
+                    $document.bind('click', function () {
+                        if (!$element.hasClass('open-recent')) {
+                            $element.removeClass('open');
+                        }
+                        $element.removeClass('open-recent');
+                    })
+                }
+            }
+        })
+        .directive('filterDropdown', function ($document) {
+            return {
+                restrict: 'A',
+                link: function ($scope, $element, $attr) {
+                    $element.bind('click', function (event) {
+                        if (event.target.closest('button')) {
+                            $element.toggleClass('open');
+                        } else {
+                            $element.addClass('open');
+                        }
+                        $element.addClass('open-recent');
+                    });
+
+                    $document.bind('click', function () {
+                        if (!$element.hasClass('open-recent')) {
+                            $element.removeClass('open');
+                        }
+                        $element.removeClass('open-recent');
+                    })
+                }
+            }
+        })
+        .directive('onFinishRender', function ($timeout) {
+            return {
+                restrict: 'A',
+                link: function (scope, element, attr) {
+                    if (scope.$last === true) {
+                        $timeout(function () {
+                            scope.$emit(attr.onFinishRender);
+                        });
+                    }
+                }
+            };
+        })
+        .controller("lintList", function ($scope, $http, $timeout) {
+            // Level filter
+            var LEVEL_FILTERS_DEFAULT = {allow: true, warn: true, deny: true, none: true};
+            $scope.levels = LEVEL_FILTERS_DEFAULT;
+            $scope.byLevels = function (lint) {
+                return $scope.levels[lint.level];
+            };
+
+            var GROUPS_FILTER_DEFAULT = {
+                cargo: true,
+                complexity: true,
+                correctness: true,
+                deprecated: false,
+                nursery: true,
+                pedantic: true,
+                perf: true,
+                restriction: true,
+                style: true,
+                suspicious: true,
+            };
+            $scope.groups = GROUPS_FILTER_DEFAULT;
+            const THEMES_DEFAULT = {
+                light: "Light",
+                rust: "Rust",
+                coal: "Coal",
+                navy: "Navy",
+                ayu: "Ayu"
+            };
+            $scope.themes = THEMES_DEFAULT;
+
+            $scope.versionFilters = {
+                "≥": {enabled: false, minorVersion: null },
+                "≤": {enabled: false, minorVersion: null },
+                "=": {enabled: false, minorVersion: null },
+            };
+
+            $scope.selectTheme = function (theme) {
+                setTheme(theme, true);
+            }
+
+            $scope.toggleLevels = function (value) {
+                const levels = $scope.levels;
+                for (const key in levels) {
+                    if (levels.hasOwnProperty(key)) {
+                        levels[key] = value;
+                    }
+                }
+            };
+
+            $scope.toggleGroups = function (value) {
+                const groups = $scope.groups;
+                for (const key in groups) {
+                    if (groups.hasOwnProperty(key)) {
+                        groups[key] = value;
+                    }
+                }
+            };
+
+            $scope.selectedValuesCount = function (obj) {
+                return Object.values(obj).filter(x => x).length;
+            }
+
+            $scope.clearVersionFilters = function () {
+                for (let filter in $scope.versionFilters) {
+                    $scope.versionFilters[filter] = { enabled: false, minorVersion: null };
+                }
+            }
+
+            $scope.versionFilterCount = function(obj) {
+                return Object.values(obj).filter(x => x.enabled).length;
+            }
+
+            $scope.updateVersionFilters = function() {
+                for (const filter in $scope.versionFilters) {
+                    let minorVersion = $scope.versionFilters[filter].minorVersion;
+
+                    // 1.29.0 and greater
+                    if (minorVersion && minorVersion > 28) {
+                        $scope.versionFilters[filter].enabled = true;
+                        continue;
+                    }
+
+                    $scope.versionFilters[filter].enabled = false;
+                }
+            }
+
+            $scope.byVersion = function(lint) {
+                let filters = $scope.versionFilters;
+                for (const filter in filters) {
+                    if (filters[filter].enabled) {
+                        let minorVersion = filters[filter].minorVersion;
+
+                        // Strip the "pre " prefix for pre 1.29.0 lints
+                        let lintVersion = lint.version.startsWith("pre ") ? lint.version.substring(4, lint.version.length) : lint.version;
+                        let lintMinorVersion = lintVersion.substring(2, 4);
+
+                        switch (filter) {
+                            // "=" gets the highest priority, since all filters are inclusive
+                            case "=":
+                                return (lintMinorVersion == minorVersion);
+                            case "≥":
+                                if (lintMinorVersion < minorVersion) { return false; }
+                                break;
+                            case "≤":
+                                if (lintMinorVersion > minorVersion) { return false; }
+                                break;
+                            default:
+                                return true
+                        }
+                    }
+                }
+
+                return true;
+            }
+
+            $scope.byGroups = function (lint) {
+                return $scope.groups[lint.group];
+            };
+
+            $scope.bySearch = function (lint, index, array) {
+                let searchStr = $scope.search;
+                // It can be `null` I haven't missed this value
+                if (searchStr == null || searchStr.length < 3) {
+                    return true;
+                }
+                searchStr = searchStr.toLowerCase();
+
+                // Search by id
+                if (lint.id.indexOf(searchStr.replace("-", "_")) !== -1) {
+                    return true;
+                }
+
+                // Search the description
+                // The use of `for`-loops instead of `foreach` enables us to return early
+                let terms = searchStr.split(" ");
+                let docsLowerCase = lint.docs.toLowerCase();
+                for (index = 0; index < terms.length; index++) {
+                    // This is more likely and will therefor be checked first
+                    if (docsLowerCase.indexOf(terms[index]) !== -1) {
+                        continue;
+                    }
+
+                    if (lint.id.indexOf(terms[index]) !== -1) {
+                        continue;
+                    }
+
+                    return false;
+                }
+
+                return true;
+            }
+
+            $scope.copyToClipboard = function (lint) {
+                const clipboard = document.getElementById("clipboard-" + lint.id);
+                if (clipboard) {
+                    let resetClipboardTimeout = null;
+                    let resetClipboardIcon = clipboard.innerHTML;
+
+                    function resetClipboard() {
+                        resetClipboardTimeout = null;
+                        clipboard.innerHTML = resetClipboardIcon;
+                    }
+
+                    navigator.clipboard.writeText("clippy::" + lint.id);
+
+                    clipboard.innerHTML = "&#10003;";
+                    if (resetClipboardTimeout !== null) {
+                        clearTimeout(resetClipboardTimeout);
+                    }
+                    resetClipboardTimeout = setTimeout(resetClipboard, 1000);
+                }
+            }
+
+            // Get data
+            $scope.open = {};
+            $scope.loading = true;
+            // This will be used to jump into the source code of the version that this documentation is for.
+            $scope.docVersion = window.location.pathname.split('/')[2] || "master";
+
+            if (window.location.hash.length > 1) {
+                $scope.search = window.location.hash.slice(1);
+                $scope.open[window.location.hash.slice(1)] = true;
+                scrollToLintByURL($scope);
+            }
+
+            $http.get('./lints.json')
+                .success(function (data) {
+                    $scope.data = data;
+                    $scope.loading = false;
+
+                    var selectedGroup = getQueryVariable("sel");
+                    if (selectedGroup) {
+                        selectGroup($scope, selectedGroup.toLowerCase());
+                    }
+
+                    scrollToLintByURL($scope);
+
+                    setTimeout(function () {
+                        var el = document.getElementById('filter-input');
+                        if (el) { el.focus() }
+                    }, 0);
+                })
+                .error(function (data) {
+                    $scope.error = data;
+                    $scope.loading = false;
+                });
+
+            window.addEventListener('hashchange', function () {
+                // trigger re-render
+                $timeout(function () {
+                    $scope.levels = LEVEL_FILTERS_DEFAULT;
+                    $scope.search = window.location.hash.slice(1);
+                    $scope.open[window.location.hash.slice(1)] = true;
+
+                    scrollToLintByURL($scope);
+                });
+                return true;
+            }, false);
+        });
+})();
+
+function getQueryVariable(variable) {
+    var query = window.location.search.substring(1);
+    var vars = query.split('&');
+    for (var i = 0; i < vars.length; i++) {
+        var pair = vars[i].split('=');
+        if (decodeURIComponent(pair[0]) == variable) {
+            return decodeURIComponent(pair[1]);
+        }
+    }
+}
+
+function setTheme(theme, store) {
+    let enableHighlight = false;
+    let enableNight = false;
+    let enableAyu = false;
+
+    if (theme == "ayu") {
+        enableAyu = true;
+    } else if (theme == "coal" || theme == "navy") {
+        enableNight = true;
+    } else if (theme == "rust") {
+        enableHighlight = true;
+    } else {
+        enableHighlight = true;
+        // this makes sure that an unknown theme request gets set to a known one
+        theme = "light";
+    }
+    document.getElementsByTagName("body")[0].className = theme;
+
+    document.getElementById("styleHighlight").disabled = !enableHighlight;
+    document.getElementById("styleNight").disabled = !enableNight;
+    document.getElementById("styleAyu").disabled = !enableAyu;
+
+    if (store) {
+        try {
+            localStorage.setItem('clippy-lint-list-theme', theme);
+        } catch (e) { }
+    }
+}
+
+// loading the theme after the initial load
+setTheme(localStorage.getItem('clippy-lint-list-theme'), false);