about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--.github/workflows/clippy_bors.yml29
-rw-r--r--CHANGELOG.md13
-rw-r--r--book/src/lint_configuration.md21
-rw-r--r--clippy_dev/src/lib.rs2
-rw-r--r--clippy_dev/src/main.rs2
-rw-r--r--clippy_dev/src/setup/vscode.rs2
-rw-r--r--clippy_lints/src/absolute_paths.rs100
-rw-r--r--clippy_lints/src/arc_with_non_send_sync.rs12
-rw-r--r--clippy_lints/src/assertions_on_result_states.rs6
-rw-r--r--clippy_lints/src/bool_assert_comparison.rs2
-rw-r--r--clippy_lints/src/casts/as_ptr_cast_mut.rs2
-rw-r--r--clippy_lints/src/casts/cast_ptr_alignment.rs2
-rw-r--r--clippy_lints/src/casts/mod.rs8
-rw-r--r--clippy_lints/src/casts/ptr_as_ptr.rs64
-rw-r--r--clippy_lints/src/casts/unnecessary_cast.rs22
-rw-r--r--clippy_lints/src/copy_iterator.rs2
-rw-r--r--clippy_lints/src/declared_lints.rs12
-rw-r--r--clippy_lints/src/default.rs8
-rw-r--r--clippy_lints/src/default_numeric_fallback.rs8
-rw-r--r--clippy_lints/src/dereference.rs1047
-rw-r--r--clippy_lints/src/derivable_impls.rs21
-rw-r--r--clippy_lints/src/derive.rs20
-rw-r--r--clippy_lints/src/doc.rs2
-rw-r--r--clippy_lints/src/empty_enum.rs2
-rw-r--r--clippy_lints/src/enum_clike.rs2
-rw-r--r--clippy_lints/src/error_impl_error.rs87
-rw-r--r--clippy_lints/src/eta_reduction.rs338
-rw-r--r--clippy_lints/src/from_over_into.rs5
-rw-r--r--clippy_lints/src/functions/must_use.rs6
-rw-r--r--clippy_lints/src/functions/result.rs6
-rw-r--r--clippy_lints/src/future_not_send.rs4
-rw-r--r--clippy_lints/src/ignored_unit_patterns.rs52
-rw-r--r--clippy_lints/src/implicit_saturating_sub.rs4
-rw-r--r--clippy_lints/src/incorrect_impls.rs81
-rw-r--r--clippy_lints/src/inherent_impl.rs2
-rw-r--r--clippy_lints/src/inherent_to_string.rs35
-rw-r--r--clippy_lints/src/iter_not_returning_iterator.rs2
-rw-r--r--clippy_lints/src/large_enum_variant.rs6
-rw-r--r--clippy_lints/src/len_zero.rs37
-rw-r--r--clippy_lints/src/let_underscore.rs3
-rw-r--r--clippy_lints/src/lib.rs17
-rw-r--r--clippy_lints/src/lifetimes.rs3
-rw-r--r--clippy_lints/src/loops/explicit_iter_loop.rs4
-rw-r--r--clippy_lints/src/loops/missing_spin_loop.rs2
-rw-r--r--clippy_lints/src/loops/needless_range_loop.rs2
-rw-r--r--clippy_lints/src/loops/single_element_loop.rs3
-rw-r--r--clippy_lints/src/loops/utils.rs4
-rw-r--r--clippy_lints/src/manual_bits.rs2
-rw-r--r--clippy_lints/src/manual_slice_size_calculation.rs2
-rw-r--r--clippy_lints/src/map_unit_fn.rs2
-rw-r--r--clippy_lints/src/matches/match_as_ref.rs8
-rw-r--r--clippy_lints/src/matches/mod.rs33
-rw-r--r--clippy_lints/src/matches/redundant_guards.rs190
-rw-r--r--clippy_lints/src/matches/redundant_pattern_match.rs3
-rw-r--r--clippy_lints/src/matches/rest_pat_in_fully_bound_struct.rs2
-rw-r--r--clippy_lints/src/matches/significant_drop_in_scrutinee.rs3
-rw-r--r--clippy_lints/src/methods/bytecount.rs2
-rw-r--r--clippy_lints/src/methods/bytes_count_to_len.rs2
-rw-r--r--clippy_lints/src/methods/case_sensitive_file_extension_comparisons.rs2
-rw-r--r--clippy_lints/src/methods/err_expect.rs2
-rw-r--r--clippy_lints/src/methods/expect_fun_call.rs4
-rw-r--r--clippy_lints/src/methods/expect_used.rs44
-rw-r--r--clippy_lints/src/methods/filter_map_bool_then.rs45
-rw-r--r--clippy_lints/src/methods/flat_map_option.rs2
-rw-r--r--clippy_lints/src/methods/get_first.rs2
-rw-r--r--clippy_lints/src/methods/implicit_clone.rs2
-rw-r--r--clippy_lints/src/methods/inefficient_to_string.rs8
-rw-r--r--clippy_lints/src/methods/manual_ok_or.rs2
-rw-r--r--clippy_lints/src/methods/map_clone.rs2
-rw-r--r--clippy_lints/src/methods/map_collect_result_unit.rs4
-rw-r--r--clippy_lints/src/methods/map_err_ignore.rs2
-rw-r--r--clippy_lints/src/methods/map_flatten.rs2
-rw-r--r--clippy_lints/src/methods/mod.rs186
-rw-r--r--clippy_lints/src/methods/mut_mutex_lock.rs2
-rw-r--r--clippy_lints/src/methods/needless_collect.rs14
-rw-r--r--clippy_lints/src/methods/ok_expect.rs2
-rw-r--r--clippy_lints/src/methods/open_options.rs2
-rw-r--r--clippy_lints/src/methods/or_fun_call.rs122
-rw-r--r--clippy_lints/src/methods/path_buf_push_overwrite.rs2
-rw-r--r--clippy_lints/src/methods/read_line_without_trim.rs4
-rw-r--r--clippy_lints/src/methods/readonly_write_lock.rs52
-rw-r--r--clippy_lints/src/methods/stable_sort_primitive.rs2
-rw-r--r--clippy_lints/src/methods/suspicious_splitn.rs2
-rw-r--r--clippy_lints/src/methods/type_id_on_box.rs4
-rw-r--r--clippy_lints/src/methods/unnecessary_filter_map.rs10
-rw-r--r--clippy_lints/src/methods/unnecessary_literal_unwrap.rs31
-rw-r--r--clippy_lints/src/methods/unnecessary_sort_by.rs6
-rw-r--r--clippy_lints/src/methods/unnecessary_to_owned.rs48
-rw-r--r--clippy_lints/src/methods/unwrap_expect_used.rs83
-rw-r--r--clippy_lints/src/methods/unwrap_or_else_default.rs70
-rw-r--r--clippy_lints/src/methods/unwrap_used.rs53
-rw-r--r--clippy_lints/src/methods/utils.rs2
-rw-r--r--clippy_lints/src/methods/vec_resize_to_zero.rs2
-rw-r--r--clippy_lints/src/min_ident_chars.rs8
-rw-r--r--clippy_lints/src/mut_key.rs6
-rw-r--r--clippy_lints/src/mut_reference.rs9
-rw-r--r--clippy_lints/src/needless_pass_by_ref_mut.rs207
-rw-r--r--clippy_lints/src/needless_pass_by_value.rs14
-rw-r--r--clippy_lints/src/new_without_default.rs6
-rw-r--r--clippy_lints/src/non_copy_const.rs25
-rw-r--r--clippy_lints/src/non_send_fields_in_send_ty.rs15
-rw-r--r--clippy_lints/src/only_used_in_recursion.rs19
-rw-r--r--clippy_lints/src/operators/arithmetic_side_effects.rs8
-rw-r--r--clippy_lints/src/operators/const_comparisons.rs207
-rw-r--r--clippy_lints/src/operators/mod.rs43
-rw-r--r--clippy_lints/src/option_env_unwrap.rs39
-rw-r--r--clippy_lints/src/option_if_let_else.rs2
-rw-r--r--clippy_lints/src/pass_by_ref_or_value.rs2
-rw-r--r--clippy_lints/src/ptr.rs31
-rw-r--r--clippy_lints/src/question_mark.rs12
-rw-r--r--clippy_lints/src/redundant_locals.rs103
-rw-r--r--clippy_lints/src/redundant_slicing.rs5
-rw-r--r--clippy_lints/src/redundant_static_lifetimes.rs3
-rw-r--r--clippy_lints/src/renamed_lints.rs1
-rw-r--r--clippy_lints/src/returns.rs81
-rw-r--r--clippy_lints/src/self_named_constructors.rs2
-rw-r--r--clippy_lints/src/significant_drop_tightening.rs44
-rw-r--r--clippy_lints/src/size_of_in_element_count.rs4
-rw-r--r--clippy_lints/src/slow_vector_initialization.rs113
-rw-r--r--clippy_lints/src/strings.rs2
-rw-r--r--clippy_lints/src/suspicious_xor_used_as_pow.rs48
-rw-r--r--clippy_lints/src/transmute/transmute_undefined_repr.rs8
-rw-r--r--clippy_lints/src/transmute/unsound_collection_transmute.rs6
-rw-r--r--clippy_lints/src/uninit_vec.rs4
-rw-r--r--clippy_lints/src/unit_return_expecting_ord.rs8
-rw-r--r--clippy_lints/src/unit_types/let_unit_value.rs2
-rw-r--r--clippy_lints/src/unnamed_address.rs2
-rw-r--r--clippy_lints/src/unused_async.rs108
-rw-r--r--clippy_lints/src/use_self.rs10
-rw-r--r--clippy_lints/src/useless_conversion.rs8
-rw-r--r--clippy_lints/src/utils/conf.rs10
-rw-r--r--clippy_lints/src/utils/internal_lints/interning_defined_symbol.rs2
-rw-r--r--clippy_lints/src/utils/internal_lints/invalid_paths.rs8
-rw-r--r--clippy_lints/src/utils/internal_lints/msrv_attr_impl.rs5
-rw-r--r--clippy_lints/src/utils/internal_lints/unnecessary_def_path.rs4
-rw-r--r--clippy_lints/src/utils/mod.rs2
-rw-r--r--clippy_lints/src/vec.rs4
-rw-r--r--clippy_lints/src/zero_sized_map_values.rs4
-rw-r--r--clippy_utils/src/consts.rs18
-rw-r--r--clippy_utils/src/eager_or_lazy.rs29
-rw-r--r--clippy_utils/src/hir_utils.rs25
-rw-r--r--clippy_utils/src/lib.rs339
-rw-r--r--clippy_utils/src/mir/possible_origin.rs2
-rw-r--r--clippy_utils/src/paths.rs4
-rw-r--r--clippy_utils/src/qualify_min_const_fn.rs9
-rw-r--r--clippy_utils/src/sugg.rs2
-rw-r--r--clippy_utils/src/ty.rs258
-rw-r--r--clippy_utils/src/ty/type_certainty/mod.rs9
-rw-r--r--clippy_utils/src/usage.rs49
-rw-r--r--clippy_utils/src/visitors.rs10
-rw-r--r--rust-toolchain2
-rw-r--r--tests/compile-test.rs40
-rw-r--r--tests/integration.rs24
-rw-r--r--tests/ui-toml/absolute_paths/absolute_paths.allow_crates.stderr28
-rw-r--r--tests/ui-toml/absolute_paths/absolute_paths.disallow_crates.stderr70
-rw-r--r--tests/ui-toml/absolute_paths/absolute_paths.rs97
-rw-r--r--tests/ui-toml/absolute_paths/allow_crates/clippy.toml2
-rw-r--r--tests/ui-toml/absolute_paths/auxiliary/helper.rs11
-rw-r--r--tests/ui-toml/absolute_paths/disallow_crates/clippy.toml1
-rw-r--r--tests/ui-toml/expect_used/expect_used.stderr4
-rw-r--r--tests/ui-toml/toml_unknown_key/conf_unknown_key.stderr4
-rw-r--r--tests/ui-toml/unwrap_used/unwrap_used.stderr39
-rw-r--r--tests/ui/arc_with_non_send_sync.rs30
-rw-r--r--tests/ui/arc_with_non_send_sync.stderr6
-rw-r--r--tests/ui/arithmetic_side_effects.rs7
-rw-r--r--tests/ui/comparison_to_empty.fixed12
-rw-r--r--tests/ui/comparison_to_empty.rs12
-rw-r--r--tests/ui/comparison_to_empty.stderr40
-rw-r--r--tests/ui/const_comparisons.rs93
-rw-r--r--tests/ui/const_comparisons.stderr228
-rw-r--r--tests/ui/crashes/ice-6256.rs2
-rw-r--r--tests/ui/error_impl_error.rs90
-rw-r--r--tests/ui/error_impl_error.stderr45
-rw-r--r--tests/ui/eta.fixed57
-rw-r--r--tests/ui/eta.rs57
-rw-r--r--tests/ui/eta.stderr8
-rw-r--r--tests/ui/expect.stderr6
-rw-r--r--tests/ui/filter_map_bool_then.fixed44
-rw-r--r--tests/ui/filter_map_bool_then.rs44
-rw-r--r--tests/ui/filter_map_bool_then.stderr34
-rw-r--r--tests/ui/get_unwrap.stderr39
-rw-r--r--tests/ui/if_same_then_else.rs41
-rw-r--r--tests/ui/if_same_then_else.stderr20
-rw-r--r--tests/ui/ifs_same_cond.rs4
-rw-r--r--tests/ui/ifs_same_cond.stderr4
-rw-r--r--tests/ui/ignored_unit_patterns.fixed17
-rw-r--r--tests/ui/ignored_unit_patterns.rs17
-rw-r--r--tests/ui/ignored_unit_patterns.stderr28
-rw-r--r--tests/ui/incorrect_partial_ord_impl_on_ord_type.fixed33
-rw-r--r--tests/ui/incorrect_partial_ord_impl_on_ord_type.rs33
-rw-r--r--tests/ui/incorrect_partial_ord_impl_on_ord_type.stderr4
-rw-r--r--tests/ui/incorrect_partial_ord_impl_on_ord_type_fully_qual.rs51
-rw-r--r--tests/ui/incorrect_partial_ord_impl_on_ord_type_fully_qual.stderr31
-rw-r--r--tests/ui/infinite_loop.stderr16
-rw-r--r--tests/ui/inherent_to_string.rs26
-rw-r--r--tests/ui/inherent_to_string.stderr10
-rw-r--r--tests/ui/let_underscore_future.stderr16
-rw-r--r--tests/ui/match_expr_like_matches_macro.fixed3
-rw-r--r--tests/ui/match_expr_like_matches_macro.rs3
-rw-r--r--tests/ui/match_expr_like_matches_macro.stderr28
-rw-r--r--tests/ui/min_ident_chars.rs4
-rw-r--r--tests/ui/mut_key.stderr16
-rw-r--r--tests/ui/mut_reference.rs15
-rw-r--r--tests/ui/mut_reference.stderr30
-rw-r--r--tests/ui/needless_pass_by_ref_mut.rs120
-rw-r--r--tests/ui/needless_pass_by_ref_mut.stderr72
-rw-r--r--tests/ui/needless_return_with_question_mark.fixed40
-rw-r--r--tests/ui/needless_return_with_question_mark.rs40
-rw-r--r--tests/ui/needless_return_with_question_mark.stderr10
-rw-r--r--tests/ui/option_env_unwrap.rs1
-rw-r--r--tests/ui/option_env_unwrap.stderr18
-rw-r--r--tests/ui/option_if_let_else.fixed3
-rw-r--r--tests/ui/option_if_let_else.rs3
-rw-r--r--tests/ui/option_if_let_else.stderr46
-rw-r--r--tests/ui/or_fun_call.fixed63
-rw-r--r--tests/ui/or_fun_call.rs55
-rw-r--r--tests/ui/or_fun_call.stderr90
-rw-r--r--tests/ui/ptr_arg.rs13
-rw-r--r--tests/ui/ptr_as_ptr.fixed16
-rw-r--r--tests/ui/ptr_as_ptr.rs16
-rw-r--r--tests/ui/ptr_as_ptr.stderr28
-rw-r--r--tests/ui/question_mark.fixed17
-rw-r--r--tests/ui/question_mark.rs17
-rw-r--r--tests/ui/question_mark.stderr6
-rw-r--r--tests/ui/range_contains.fixed2
-rw-r--r--tests/ui/range_contains.rs2
-rw-r--r--tests/ui/range_contains.stderr42
-rw-r--r--tests/ui/read_zero_byte_vec.rs6
-rw-r--r--tests/ui/read_zero_byte_vec.stderr20
-rw-r--r--tests/ui/readonly_write_lock.rs42
-rw-r--r--tests/ui/readonly_write_lock.stderr16
-rw-r--r--tests/ui/redundant_guards.fixed133
-rw-r--r--tests/ui/redundant_guards.rs133
-rw-r--r--tests/ui/redundant_guards.stderr98
-rw-r--r--tests/ui/redundant_locals.rs111
-rw-r--r--tests/ui/redundant_locals.stderr136
-rw-r--r--tests/ui/rename.fixed2
-rw-r--r--tests/ui/rename.rs2
-rw-r--r--tests/ui/rename.stderr114
-rw-r--r--tests/ui/self_assignment.rs2
-rw-r--r--tests/ui/self_assignment.stderr6
-rw-r--r--tests/ui/shadow.rs7
-rw-r--r--tests/ui/shadow.stderr92
-rw-r--r--tests/ui/should_impl_trait/method_list_2.stderr18
-rw-r--r--tests/ui/significant_drop_tightening.fixed27
-rw-r--r--tests/ui/significant_drop_tightening.rs27
-rw-r--r--tests/ui/significant_drop_tightening.stderr6
-rw-r--r--tests/ui/single_match.fixed1
-rw-r--r--tests/ui/single_match.rs1
-rw-r--r--tests/ui/single_match.stderr36
-rw-r--r--tests/ui/slow_vector_initialization.rs16
-rw-r--r--tests/ui/slow_vector_initialization.stderr64
-rw-r--r--tests/ui/suspicious_xor_used_as_pow.stderr10
-rw-r--r--tests/ui/swap.fixed3
-rw-r--r--tests/ui/swap.rs3
-rw-r--r--tests/ui/swap.stderr34
-rw-r--r--tests/ui/try_err.fixed6
-rw-r--r--tests/ui/try_err.rs6
-rw-r--r--tests/ui/try_err.stderr22
-rw-r--r--tests/ui/unnecessary_cast.fixed17
-rw-r--r--tests/ui/unnecessary_cast.rs17
-rw-r--r--tests/ui/unnecessary_cast.stderr88
-rw-r--r--tests/ui/unnecessary_filter_map.rs6
-rw-r--r--tests/ui/unnecessary_filter_map.stderr8
-rw-r--r--tests/ui/unnecessary_find_map.rs6
-rw-r--r--tests/ui/unnecessary_find_map.stderr8
-rw-r--r--tests/ui/unnecessary_literal_unwrap.fixed11
-rw-r--r--tests/ui/unnecessary_literal_unwrap.rs11
-rw-r--r--tests/ui/unnecessary_literal_unwrap.stderr188
-rw-r--r--tests/ui/unnecessary_literal_unwrap_unfixable.rs2
-rw-r--r--tests/ui/unnecessary_literal_unwrap_unfixable.stderr182
-rw-r--r--tests/ui/unused_async.rs17
-rw-r--r--tests/ui/unused_async.stderr14
-rw-r--r--tests/ui/unwrap.stderr9
-rw-r--r--tests/ui/unwrap_expect_used.rs11
-rw-r--r--tests/ui/unwrap_expect_used.stderr24
-rw-r--r--tests/ui/unwrap_or_else_default.fixed25
-rw-r--r--tests/ui/unwrap_or_else_default.rs25
-rw-r--r--tests/ui/unwrap_or_else_default.stderr100
-rw-r--r--triagebot.toml5
280 files changed, 7079 insertions, 2434 deletions
diff --git a/.github/workflows/clippy_bors.yml b/.github/workflows/clippy_bors.yml
index 4eb11a3ac85..5c69714bc1e 100644
--- a/.github/workflows/clippy_bors.yml
+++ b/.github/workflows/clippy_bors.yml
@@ -187,16 +187,14 @@ jobs:
     - name: Extract Binaries
       run: |
         DIR=$CARGO_TARGET_DIR/debug
-        rm $DIR/deps/integration-*.d
-        mv $DIR/deps/integration-* $DIR/integration
+        find $DIR/deps/integration-* -executable ! -type d | xargs -I {} mv {} $DIR/integration
         find $DIR ! -executable -o -type d ! -path $DIR | xargs rm -rf
-        rm -rf $CARGO_TARGET_DIR/release
 
     - name: Upload Binaries
-      uses: actions/upload-artifact@v1
+      uses: actions/upload-artifact@v3
       with:
-        name: target
-        path: target
+        name: binaries
+        path: target/debug
 
   integration:
     needs: integration_build
@@ -206,22 +204,20 @@ jobs:
       matrix:
         integration:
         - 'rust-lang/cargo'
-        # FIXME: re-enable once fmt_macros is renamed in RLS
-        # - 'rust-lang/rls'
         - 'rust-lang/chalk'
         - 'rust-lang/rustfmt'
         - 'Marwes/combine'
         - 'Geal/nom'
         - 'rust-lang/stdarch'
         - 'serde-rs/serde'
-        # FIXME: chrono currently cannot be compiled with `--all-targets`
-        # - 'chronotope/chrono'
+        - 'chronotope/chrono'
         - 'hyperium/hyper'
         - 'rust-random/rand'
         - 'rust-lang/futures-rs'
         - 'rust-itertools/itertools'
         - 'rust-lang-nursery/failure'
         - 'rust-lang/log'
+        - 'matthiaskrgr/clippy_ci_panic_test'
 
     runs-on: ubuntu-latest
 
@@ -237,12 +233,17 @@ jobs:
     - name: Install toolchain
       run: rustup show active-toolchain
 
+    - name: Set LD_LIBRARY_PATH
+      run: |
+        SYSROOT=$(rustc --print sysroot)
+        echo "LD_LIBRARY_PATH=${SYSROOT}/lib${LD_LIBRARY_PATH+:${LD_LIBRARY_PATH}}" >> $GITHUB_ENV
+
     # Download
     - name: Download target dir
-      uses: actions/download-artifact@v1
+      uses: actions/download-artifact@v3
       with:
-        name: target
-        path: target
+        name: binaries
+        path: target/debug
 
     - name: Make Binaries Executable
       run: chmod +x $CARGO_TARGET_DIR/debug/*
@@ -251,7 +252,7 @@ jobs:
     - name: Test ${{ matrix.integration }}
       run: |
         RUSTUP_TOOLCHAIN="$(rustup show active-toolchain | grep -o -E "nightly-[0-9]{4}-[0-9]{2}-[0-9]{2}")" \
-          $CARGO_TARGET_DIR/debug/integration
+          $CARGO_TARGET_DIR/debug/integration --show-output
       env:
         INTEGRATION: ${{ matrix.integration }}
 
diff --git a/CHANGELOG.md b/CHANGELOG.md
index acc9d8ffbf7..71671273c57 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -4680,6 +4680,7 @@ Released 2018-09-13
 
 <!-- lint disable no-unused-definitions -->
 <!-- begin autogenerated links to lint list -->
+[`absolute_paths`]: https://rust-lang.github.io/rust-clippy/master/index.html#absolute_paths
 [`absurd_extreme_comparisons`]: https://rust-lang.github.io/rust-clippy/master/index.html#absurd_extreme_comparisons
 [`alloc_instead_of_core`]: https://rust-lang.github.io/rust-clippy/master/index.html#alloc_instead_of_core
 [`allow_attributes`]: https://rust-lang.github.io/rust-clippy/master/index.html#allow_attributes
@@ -4819,6 +4820,7 @@ Released 2018-09-13
 [`equatable_if_let`]: https://rust-lang.github.io/rust-clippy/master/index.html#equatable_if_let
 [`erasing_op`]: https://rust-lang.github.io/rust-clippy/master/index.html#erasing_op
 [`err_expect`]: https://rust-lang.github.io/rust-clippy/master/index.html#err_expect
+[`error_impl_error`]: https://rust-lang.github.io/rust-clippy/master/index.html#error_impl_error
 [`eval_order_dependence`]: https://rust-lang.github.io/rust-clippy/master/index.html#eval_order_dependence
 [`excessive_nesting`]: https://rust-lang.github.io/rust-clippy/master/index.html#excessive_nesting
 [`excessive_precision`]: https://rust-lang.github.io/rust-clippy/master/index.html#excessive_precision
@@ -4842,6 +4844,7 @@ Released 2018-09-13
 [`field_reassign_with_default`]: https://rust-lang.github.io/rust-clippy/master/index.html#field_reassign_with_default
 [`filetype_is_file`]: https://rust-lang.github.io/rust-clippy/master/index.html#filetype_is_file
 [`filter_map`]: https://rust-lang.github.io/rust-clippy/master/index.html#filter_map
+[`filter_map_bool_then`]: https://rust-lang.github.io/rust-clippy/master/index.html#filter_map_bool_then
 [`filter_map_identity`]: https://rust-lang.github.io/rust-clippy/master/index.html#filter_map_identity
 [`filter_map_next`]: https://rust-lang.github.io/rust-clippy/master/index.html#filter_map_next
 [`filter_next`]: https://rust-lang.github.io/rust-clippy/master/index.html#filter_next
@@ -4887,12 +4890,14 @@ Released 2018-09-13
 [`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
 [`ifs_same_cond`]: https://rust-lang.github.io/rust-clippy/master/index.html#ifs_same_cond
+[`ignored_unit_patterns`]: https://rust-lang.github.io/rust-clippy/master/index.html#ignored_unit_patterns
 [`impl_trait_in_params`]: https://rust-lang.github.io/rust-clippy/master/index.html#impl_trait_in_params
 [`implicit_clone`]: https://rust-lang.github.io/rust-clippy/master/index.html#implicit_clone
 [`implicit_hasher`]: https://rust-lang.github.io/rust-clippy/master/index.html#implicit_hasher
 [`implicit_return`]: https://rust-lang.github.io/rust-clippy/master/index.html#implicit_return
 [`implicit_saturating_add`]: https://rust-lang.github.io/rust-clippy/master/index.html#implicit_saturating_add
 [`implicit_saturating_sub`]: https://rust-lang.github.io/rust-clippy/master/index.html#implicit_saturating_sub
+[`impossible_comparisons`]: https://rust-lang.github.io/rust-clippy/master/index.html#impossible_comparisons
 [`imprecise_flops`]: https://rust-lang.github.io/rust-clippy/master/index.html#imprecise_flops
 [`inconsistent_digit_grouping`]: https://rust-lang.github.io/rust-clippy/master/index.html#inconsistent_digit_grouping
 [`inconsistent_struct_constructor`]: https://rust-lang.github.io/rust-clippy/master/index.html#inconsistent_struct_constructor
@@ -5095,6 +5100,7 @@ Released 2018-09-13
 [`needless_raw_string_hashes`]: https://rust-lang.github.io/rust-clippy/master/index.html#needless_raw_string_hashes
 [`needless_raw_strings`]: https://rust-lang.github.io/rust-clippy/master/index.html#needless_raw_strings
 [`needless_return`]: https://rust-lang.github.io/rust-clippy/master/index.html#needless_return
+[`needless_return_with_question_mark`]: https://rust-lang.github.io/rust-clippy/master/index.html#needless_return_with_question_mark
 [`needless_splitn`]: https://rust-lang.github.io/rust-clippy/master/index.html#needless_splitn
 [`needless_update`]: https://rust-lang.github.io/rust-clippy/master/index.html#needless_update
 [`neg_cmp_op_on_partial_ord`]: https://rust-lang.github.io/rust-clippy/master/index.html#neg_cmp_op_on_partial_ord
@@ -5177,6 +5183,7 @@ Released 2018-09-13
 [`rc_mutex`]: https://rust-lang.github.io/rust-clippy/master/index.html#rc_mutex
 [`read_line_without_trim`]: https://rust-lang.github.io/rust-clippy/master/index.html#read_line_without_trim
 [`read_zero_byte_vec`]: https://rust-lang.github.io/rust-clippy/master/index.html#read_zero_byte_vec
+[`readonly_write_lock`]: https://rust-lang.github.io/rust-clippy/master/index.html#readonly_write_lock
 [`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
 [`redundant_async_block`]: https://rust-lang.github.io/rust-clippy/master/index.html#redundant_async_block
@@ -5185,9 +5192,12 @@ Released 2018-09-13
 [`redundant_closure`]: https://rust-lang.github.io/rust-clippy/master/index.html#redundant_closure
 [`redundant_closure_call`]: https://rust-lang.github.io/rust-clippy/master/index.html#redundant_closure_call
 [`redundant_closure_for_method_calls`]: https://rust-lang.github.io/rust-clippy/master/index.html#redundant_closure_for_method_calls
+[`redundant_comparisons`]: https://rust-lang.github.io/rust-clippy/master/index.html#redundant_comparisons
 [`redundant_else`]: https://rust-lang.github.io/rust-clippy/master/index.html#redundant_else
 [`redundant_feature_names`]: https://rust-lang.github.io/rust-clippy/master/index.html#redundant_feature_names
 [`redundant_field_names`]: https://rust-lang.github.io/rust-clippy/master/index.html#redundant_field_names
+[`redundant_guards`]: https://rust-lang.github.io/rust-clippy/master/index.html#redundant_guards
+[`redundant_locals`]: https://rust-lang.github.io/rust-clippy/master/index.html#redundant_locals
 [`redundant_pattern`]: https://rust-lang.github.io/rust-clippy/master/index.html#redundant_pattern
 [`redundant_pattern_matching`]: https://rust-lang.github.io/rust-clippy/master/index.html#redundant_pattern_matching
 [`redundant_pub_crate`]: https://rust-lang.github.io/rust-clippy/master/index.html#redundant_pub_crate
@@ -5366,6 +5376,7 @@ Released 2018-09-13
 [`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
 [`unwrap_in_result`]: https://rust-lang.github.io/rust-clippy/master/index.html#unwrap_in_result
+[`unwrap_or_default`]: https://rust-lang.github.io/rust-clippy/master/index.html#unwrap_or_default
 [`unwrap_or_else_default`]: https://rust-lang.github.io/rust-clippy/master/index.html#unwrap_or_else_default
 [`unwrap_used`]: https://rust-lang.github.io/rust-clippy/master/index.html#unwrap_used
 [`upper_case_acronyms`]: https://rust-lang.github.io/rust-clippy/master/index.html#upper_case_acronyms
@@ -5466,4 +5477,6 @@ Released 2018-09-13
 [`accept-comment-above-statement`]: https://doc.rust-lang.org/clippy/lint_configuration.html#accept-comment-above-statement
 [`accept-comment-above-attributes`]: https://doc.rust-lang.org/clippy/lint_configuration.html#accept-comment-above-attributes
 [`allow-one-hash-in-raw-strings`]: https://doc.rust-lang.org/clippy/lint_configuration.html#allow-one-hash-in-raw-strings
+[`absolute-paths-max-segments`]: https://doc.rust-lang.org/clippy/lint_configuration.html#absolute-paths-max-segments
+[`absolute-paths-allowed-crates`]: https://doc.rust-lang.org/clippy/lint_configuration.html#absolute-paths-allowed-crates
 <!-- end autogenerated links to configuration documentation -->
diff --git a/book/src/lint_configuration.md b/book/src/lint_configuration.md
index f8073dac330..caaad6d1173 100644
--- a/book/src/lint_configuration.md
+++ b/book/src/lint_configuration.md
@@ -730,3 +730,24 @@ Whether to allow `r#""#` when `r""` can be used
 * [`unnecessary_raw_string_hashes`](https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_raw_string_hashes)
 
 
+## `absolute-paths-max-segments`
+The maximum number of segments a path can have before being linted, anything above this will
+be linted.
+
+**Default Value:** `2` (`u64`)
+
+---
+**Affected lints:**
+* [`absolute_paths`](https://rust-lang.github.io/rust-clippy/master/index.html#absolute_paths)
+
+
+## `absolute-paths-allowed-crates`
+Which crates to allow absolute paths from
+
+**Default Value:** `{}` (`rustc_data_structures::fx::FxHashSet<String>`)
+
+---
+**Affected lints:**
+* [`absolute_paths`](https://rust-lang.github.io/rust-clippy/master/index.html#absolute_paths)
+
+
diff --git a/clippy_dev/src/lib.rs b/clippy_dev/src/lib.rs
index 4624451cff4..c4ae4f0e2bd 100644
--- a/clippy_dev/src/lib.rs
+++ b/clippy_dev/src/lib.rs
@@ -51,7 +51,7 @@ pub fn clippy_project_root() -> PathBuf {
     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 {
+            if err.kind() == io::ErrorKind::NotFound {
                 continue;
             }
         }
diff --git a/clippy_dev/src/main.rs b/clippy_dev/src/main.rs
index 43eaccdf5a3..fca750fafc7 100644
--- a/clippy_dev/src/main.rs
+++ b/clippy_dev/src/main.rs
@@ -41,7 +41,7 @@ fn main() {
                 matches.get_one::<String>("type").map(String::as_str),
                 matches.get_flag("msrv"),
             ) {
-                Ok(_) => update_lints::update(update_lints::UpdateMode::Change),
+                Ok(()) => update_lints::update(update_lints::UpdateMode::Change),
                 Err(e) => eprintln!("Unable to create lint: {e}"),
             }
         },
diff --git a/clippy_dev/src/setup/vscode.rs b/clippy_dev/src/setup/vscode.rs
index dbcdc9b59e5..204f4af2cf1 100644
--- a/clippy_dev/src/setup/vscode.rs
+++ b/clippy_dev/src/setup/vscode.rs
@@ -47,7 +47,7 @@ fn check_install_precondition(force_override: bool) -> bool {
         }
     } else {
         match fs::create_dir(vs_dir_path) {
-            Ok(_) => {
+            Ok(()) => {
                 println!("info: created `{VSCODE_DIR}` directory for clippy");
             },
             Err(err) => {
diff --git a/clippy_lints/src/absolute_paths.rs b/clippy_lints/src/absolute_paths.rs
new file mode 100644
index 00000000000..04417c4c460
--- /dev/null
+++ b/clippy_lints/src/absolute_paths.rs
@@ -0,0 +1,100 @@
+use clippy_utils::diagnostics::span_lint;
+use clippy_utils::source::snippet_opt;
+use rustc_data_structures::fx::FxHashSet;
+use rustc_hir::def::{DefKind, Res};
+use rustc_hir::def_id::{DefId, CRATE_DEF_INDEX};
+use rustc_hir::{HirId, ItemKind, Node, Path};
+use rustc_lint::{LateContext, LateLintPass};
+use rustc_session::{declare_tool_lint, impl_lint_pass};
+use rustc_span::symbol::kw;
+
+declare_clippy_lint! {
+    /// ### What it does
+    /// Checks for usage of items through absolute paths, like `std::env::current_dir`.
+    ///
+    /// ### Why is this bad?
+    /// Many codebases have their own style when it comes to importing, but one that is seldom used
+    /// is using absolute paths *everywhere*. This is generally considered unidiomatic, and you
+    /// should add a `use` statement.
+    ///
+    /// The default maximum segments (2) is pretty strict, you may want to increase this in
+    /// `clippy.toml`.
+    ///
+    /// Note: One exception to this is code from macro expansion - this does not lint such cases, as
+    /// using absolute paths is the proper way of referencing items in one.
+    ///
+    /// ### Example
+    /// ```rust
+    /// let x = std::f64::consts::PI;
+    /// ```
+    /// Use any of the below instead, or anything else:
+    /// ```rust
+    /// use std::f64;
+    /// use std::f64::consts;
+    /// use std::f64::consts::PI;
+    /// let x = f64::consts::PI;
+    /// let x = consts::PI;
+    /// let x = PI;
+    /// use std::f64::consts as f64_consts;
+    /// let x = f64_consts::PI;
+    /// ```
+    #[clippy::version = "1.73.0"]
+    pub ABSOLUTE_PATHS,
+    restriction,
+    "checks for usage of an item without a `use` statement"
+}
+impl_lint_pass!(AbsolutePaths => [ABSOLUTE_PATHS]);
+
+pub struct AbsolutePaths {
+    pub absolute_paths_max_segments: u64,
+    pub absolute_paths_allowed_crates: FxHashSet<String>,
+}
+
+impl LateLintPass<'_> for AbsolutePaths {
+    // We should only lint `QPath::Resolved`s, but since `Path` is only used in `Resolved` and `UsePath`
+    // we don't need to use a visitor or anything as we can just check if the `Node` for `hir_id` isn't
+    // a `Use`
+    #[expect(clippy::cast_possible_truncation)]
+    fn check_path(&mut self, cx: &LateContext<'_>, path: &Path<'_>, hir_id: HirId) {
+        let Self {
+            absolute_paths_max_segments,
+            absolute_paths_allowed_crates,
+        } = self;
+
+        if !path.span.from_expansion()
+            && let Some(node) = cx.tcx.hir().find(hir_id)
+            && !matches!(node, Node::Item(item) if matches!(item.kind, ItemKind::Use(_, _)))
+            && let [first, rest @ ..] = path.segments
+            // Handle `::std`
+            && let (segment, len) = if first.ident.name == kw::PathRoot {
+                // Indexing is fine as `PathRoot` must be followed by another segment. `len() - 1`
+                // is fine here for the same reason
+                (&rest[0], path.segments.len() - 1)
+            } else {
+                (first, path.segments.len())
+            }
+            && len > *absolute_paths_max_segments as usize
+            && let Some(segment_snippet) = snippet_opt(cx, segment.ident.span)
+            && segment_snippet == segment.ident.as_str()
+        {
+            let is_abs_external =
+                matches!(segment.res, Res::Def(DefKind::Mod, DefId { index, .. }) if index == CRATE_DEF_INDEX);
+            let is_abs_crate = segment.ident.name == kw::Crate;
+
+            if is_abs_external && absolute_paths_allowed_crates.contains(segment.ident.name.as_str())
+                || is_abs_crate && absolute_paths_allowed_crates.contains("crate")
+            {
+                return;
+            }
+
+            if is_abs_external || is_abs_crate {
+                span_lint(
+                    cx,
+                    ABSOLUTE_PATHS,
+                    path.span,
+                    "consider bringing this path into scope with the `use` keyword",
+                );
+            }
+        }
+    }
+}
diff --git a/clippy_lints/src/arc_with_non_send_sync.rs b/clippy_lints/src/arc_with_non_send_sync.rs
index 7adcd9ad055..35a04b5e44a 100644
--- a/clippy_lints/src/arc_with_non_send_sync.rs
+++ b/clippy_lints/src/arc_with_non_send_sync.rs
@@ -1,6 +1,6 @@
 use clippy_utils::diagnostics::span_lint_and_then;
-use clippy_utils::last_path_segment;
 use clippy_utils::ty::{implements_trait, is_type_diagnostic_item};
+use clippy_utils::{is_from_proc_macro, last_path_segment};
 use rustc_hir::{Expr, ExprKind};
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_middle::ty;
@@ -38,10 +38,11 @@ declare_clippy_lint! {
 }
 declare_lint_pass!(ArcWithNonSendSync => [ARC_WITH_NON_SEND_SYNC]);
 
-impl LateLintPass<'_> for ArcWithNonSendSync {
-    fn check_expr(&mut self, cx: &LateContext<'_>, expr: &Expr<'_>) {
-        let ty = cx.typeck_results().expr_ty(expr);
-        if is_type_diagnostic_item(cx, ty, sym::Arc)
+impl<'tcx> LateLintPass<'tcx> for ArcWithNonSendSync {
+    fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) {
+        if !expr.span.from_expansion()
+            && let ty = cx.typeck_results().expr_ty(expr)
+            && is_type_diagnostic_item(cx, ty, sym::Arc)
             && let ExprKind::Call(func, [arg]) = expr.kind
             && let ExprKind::Path(func_path) = func.kind
             && last_path_segment(&func_path).ident.name == sym::new
@@ -54,6 +55,7 @@ impl LateLintPass<'_> for ArcWithNonSendSync {
             && let Some(sync) = cx.tcx.lang_items().sync_trait()
             && let [is_send, is_sync] = [send, sync].map(|id| implements_trait(cx, arg_ty, id, &[]))
             && !(is_send && is_sync)
+            && !is_from_proc_macro(cx, expr)
         {
             span_lint_and_then(
                 cx,
diff --git a/clippy_lints/src/assertions_on_result_states.rs b/clippy_lints/src/assertions_on_result_states.rs
index f6d6c23bb6e..2980c9d6db3 100644
--- a/clippy_lints/src/assertions_on_result_states.rs
+++ b/clippy_lints/src/assertions_on_result_states.rs
@@ -47,7 +47,7 @@ impl<'tcx> LateLintPass<'tcx> for AssertionsOnResultStates {
             && let result_type_with_refs = cx.typeck_results().expr_ty(recv)
             && let result_type = result_type_with_refs.peel_refs()
             && is_type_diagnostic_item(cx, result_type, sym::Result)
-            && let ty::Adt(_, substs) = result_type.kind()
+            && let ty::Adt(_, args) = result_type.kind()
         {
             if !is_copy(cx, result_type) {
                 if result_type_with_refs != result_type {
@@ -61,7 +61,7 @@ impl<'tcx> LateLintPass<'tcx> for AssertionsOnResultStates {
             let semicolon = if is_expr_final_block_expr(cx.tcx, e) {";"} else {""};
             let mut app = Applicability::MachineApplicable;
             match method_segment.ident.as_str() {
-                "is_ok" if type_suitable_to_unwrap(cx, substs.type_at(1)) => {
+                "is_ok" if type_suitable_to_unwrap(cx, args.type_at(1)) => {
                     span_lint_and_sugg(
                         cx,
                         ASSERTIONS_ON_RESULT_STATES,
@@ -75,7 +75,7 @@ impl<'tcx> LateLintPass<'tcx> for AssertionsOnResultStates {
                         app,
                     );
                 }
-                "is_err" if type_suitable_to_unwrap(cx, substs.type_at(0)) => {
+                "is_err" if type_suitable_to_unwrap(cx, args.type_at(0)) => {
                     span_lint_and_sugg(
                         cx,
                         ASSERTIONS_ON_RESULT_STATES,
diff --git a/clippy_lints/src/bool_assert_comparison.rs b/clippy_lints/src/bool_assert_comparison.rs
index adc7e60a3fc..4503597713a 100644
--- a/clippy_lints/src/bool_assert_comparison.rs
+++ b/clippy_lints/src/bool_assert_comparison.rs
@@ -61,7 +61,7 @@ fn is_impl_not_trait_with_bool_out<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -
             )
         })
         .map_or(false, |assoc_item| {
-            let proj = Ty::new_projection(cx.tcx, assoc_item.def_id, cx.tcx.mk_substs_trait(ty, []));
+            let proj = Ty::new_projection(cx.tcx, assoc_item.def_id, cx.tcx.mk_args_trait(ty, []));
             let nty = cx.tcx.normalize_erasing_regions(cx.param_env, proj);
 
             nty.is_bool()
diff --git a/clippy_lints/src/casts/as_ptr_cast_mut.rs b/clippy_lints/src/casts/as_ptr_cast_mut.rs
index e3d1f7df294..1e56ed5f450 100644
--- a/clippy_lints/src/casts/as_ptr_cast_mut.rs
+++ b/clippy_lints/src/casts/as_ptr_cast_mut.rs
@@ -15,7 +15,7 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, cast_expr: &Expr<'_>,
         && let ExprKind::MethodCall(method_name, receiver, [], _) = cast_expr.peel_blocks().kind
         && method_name.ident.name == rustc_span::sym::as_ptr
         && let Some(as_ptr_did) = cx.typeck_results().type_dependent_def_id(cast_expr.peel_blocks().hir_id)
-        && let as_ptr_sig = cx.tcx.fn_sig(as_ptr_did).subst_identity()
+        && let as_ptr_sig = cx.tcx.fn_sig(as_ptr_did).instantiate_identity()
         && let Some(first_param_ty) = as_ptr_sig.skip_binder().inputs().iter().next()
         && let ty::Ref(_, _, Mutability::Not) = first_param_ty.kind()
         && let Some(recv) = snippet_opt(cx, receiver.span)
diff --git a/clippy_lints/src/casts/cast_ptr_alignment.rs b/clippy_lints/src/casts/cast_ptr_alignment.rs
index 6c8ee296c75..5bf467efa0f 100644
--- a/clippy_lints/src/casts/cast_ptr_alignment.rs
+++ b/clippy_lints/src/casts/cast_ptr_alignment.rs
@@ -66,7 +66,7 @@ fn is_used_as_unaligned(cx: &LateContext<'_>, e: &Expr<'_>) -> bool {
             if matches!(name.ident.as_str(), "read_unaligned" | "write_unaligned")
                 && let Some(def_id) = cx.typeck_results().type_dependent_def_id(parent.hir_id)
                 && let Some(def_id) = cx.tcx.impl_of_method(def_id)
-                && cx.tcx.type_of(def_id).subst_identity().is_unsafe_ptr()
+                && cx.tcx.type_of(def_id).instantiate_identity().is_unsafe_ptr()
             {
                 true
             } else {
diff --git a/clippy_lints/src/casts/mod.rs b/clippy_lints/src/casts/mod.rs
index 0ac6ef6496a..d34de305f5d 100644
--- a/clippy_lints/src/casts/mod.rs
+++ b/clippy_lints/src/casts/mod.rs
@@ -181,6 +181,14 @@ declare_clippy_lint! {
     /// ### Why is this bad?
     /// It's just unnecessary.
     ///
+    /// ### Known problems
+    /// When the expression on the left is a function call, the lint considers the return type to be
+    /// a type alias if it's aliased through a `use` statement
+    /// (like `use std::io::Result as IoResult`). It will not lint such cases.
+    ///
+    /// This check is also rather primitive. It will only work on primitive types without any
+    /// intermediate references, raw pointers and trait objects may or may not work.
+    ///
     /// ### Example
     /// ```rust
     /// let _ = 2i32 as i32;
diff --git a/clippy_lints/src/casts/ptr_as_ptr.rs b/clippy_lints/src/casts/ptr_as_ptr.rs
index 15ffb00da88..181dbcf6e9a 100644
--- a/clippy_lints/src/casts/ptr_as_ptr.rs
+++ b/clippy_lints/src/casts/ptr_as_ptr.rs
@@ -1,9 +1,7 @@
-use std::borrow::Cow;
-
 use clippy_utils::diagnostics::span_lint_and_sugg;
 use clippy_utils::msrvs::{self, Msrv};
+use clippy_utils::source::snippet_with_applicability;
 use clippy_utils::sugg::Sugg;
-use if_chain::if_chain;
 use rustc_errors::Applicability;
 use rustc_hir::{Expr, ExprKind, Mutability, TyKind};
 use rustc_lint::LateContext;
@@ -16,33 +14,41 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, msrv: &Msrv) {
         return;
     }
 
-    if_chain! {
-        if let ExprKind::Cast(cast_expr, cast_to_hir_ty) = expr.kind;
-        let (cast_from, cast_to) = (cx.typeck_results().expr_ty(cast_expr), cx.typeck_results().expr_ty(expr));
-        if let ty::RawPtr(TypeAndMut { mutbl: from_mutbl, .. }) = cast_from.kind();
-        if let ty::RawPtr(TypeAndMut { ty: to_pointee_ty, mutbl: to_mutbl }) = cast_to.kind();
-        if matches!((from_mutbl, to_mutbl),
-            (Mutability::Not, Mutability::Not) | (Mutability::Mut, Mutability::Mut));
+    if let ExprKind::Cast(cast_expr, cast_to_hir_ty) = expr.kind
+        && let (cast_from, cast_to) = (cx.typeck_results().expr_ty(cast_expr), cx.typeck_results().expr_ty(expr))
+        && let ty::RawPtr(TypeAndMut { mutbl: from_mutbl, .. }) = cast_from.kind()
+        && let ty::RawPtr(TypeAndMut { ty: to_pointee_ty, mutbl: to_mutbl }) = cast_to.kind()
+        && matches!((from_mutbl, to_mutbl),
+            (Mutability::Not, Mutability::Not) | (Mutability::Mut, Mutability::Mut))
         // The `U` in `pointer::cast` have to be `Sized`
         // as explained here: https://github.com/rust-lang/rust/issues/60602.
-        if to_pointee_ty.is_sized(cx.tcx, cx.param_env);
-        then {
-            let mut applicability = Applicability::MachineApplicable;
-            let cast_expr_sugg = Sugg::hir_with_applicability(cx, cast_expr, "_", &mut applicability);
-            let turbofish = match &cast_to_hir_ty.kind {
-                    TyKind::Infer => Cow::Borrowed(""),
-                    TyKind::Ptr(mut_ty) if matches!(mut_ty.ty.kind, TyKind::Infer) => Cow::Borrowed(""),
-                    _ => Cow::Owned(format!("::<{to_pointee_ty}>")),
-                };
-            span_lint_and_sugg(
-                cx,
-                PTR_AS_PTR,
-                expr.span,
-                "`as` casting between raw pointers without changing its mutability",
-                "try `pointer::cast`, a safer alternative",
-                format!("{}.cast{turbofish}()", cast_expr_sugg.maybe_par()),
-                applicability,
-            );
-        }
+        && to_pointee_ty.is_sized(cx.tcx, cx.param_env)
+    {
+        let mut app = Applicability::MachineApplicable;
+        let cast_expr_sugg = Sugg::hir_with_applicability(cx, cast_expr, "_", &mut app);
+        let turbofish = match &cast_to_hir_ty.kind {
+            TyKind::Infer => String::new(),
+            TyKind::Ptr(mut_ty) => {
+                if matches!(mut_ty.ty.kind, TyKind::Infer) {
+                    String::new()
+                } else {
+                    format!(
+                        "::<{}>",
+                        snippet_with_applicability(cx, mut_ty.ty.span, "/* type */", &mut app)
+                    )
+                }
+            },
+            _ => return,
+        };
+
+        span_lint_and_sugg(
+            cx,
+            PTR_AS_PTR,
+            expr.span,
+            "`as` casting between raw pointers without changing its mutability",
+            "try `pointer::cast`, a safer alternative",
+            format!("{}.cast{turbofish}()", cast_expr_sugg.maybe_par()),
+            app,
+        );
     }
 }
diff --git a/clippy_lints/src/casts/unnecessary_cast.rs b/clippy_lints/src/casts/unnecessary_cast.rs
index 4b45b0c9eac..86057bb74ee 100644
--- a/clippy_lints/src/casts/unnecessary_cast.rs
+++ b/clippy_lints/src/casts/unnecessary_cast.rs
@@ -85,11 +85,6 @@ pub(super) fn check<'tcx>(
         }
     }
 
-    // skip cast of fn call that returns type alias
-    if let ExprKind::Cast(inner, ..) = expr.kind && is_cast_from_ty_alias(cx, inner, cast_from) {
-        return false;
-    }
-
     // skip cast to non-primitive type
     if_chain! {
         if let ExprKind::Cast(_, cast_to) = expr.kind;
@@ -101,6 +96,11 @@ pub(super) fn check<'tcx>(
         }
     }
 
+    // skip cast of fn call that returns type alias
+    if let ExprKind::Cast(inner, ..) = expr.kind && is_cast_from_ty_alias(cx, inner, cast_from) {
+        return false;
+    }
+
     if let Some(lit) = get_numeric_literal(cast_expr) {
         let literal_str = &cast_str;
 
@@ -254,14 +254,12 @@ fn is_cast_from_ty_alias<'tcx>(cx: &LateContext<'tcx>, expr: impl Visitable<'tcx
                 // function's declaration snippet is exactly equal to the `Ty`. That way, we can
                 // see whether it's a type alias.
                 //
-                // Will this work for more complex types? Probably not!
+                // FIXME: This won't work if the type is given an alias through `use`, should we
+                // consider this a type alias as well?
                 if !snippet
                     .split("->")
                     .skip(1)
-                    .map(|s| {
-                        s.trim() == cast_from.to_string()
-                            || s.split("where").any(|ty| ty.trim() == cast_from.to_string())
-                    })
+                    .map(|s| snippet_eq_ty(s, cast_from) || s.split("where").any(|ty| snippet_eq_ty(ty, cast_from)))
                     .any(|a| a)
                 {
                     return ControlFlow::Break(());
@@ -288,3 +286,7 @@ fn is_cast_from_ty_alias<'tcx>(cx: &LateContext<'tcx>, expr: impl Visitable<'tcx
     })
     .is_some()
 }
+
+fn snippet_eq_ty(snippet: &str, ty: Ty<'_>) -> bool {
+    snippet.trim() == ty.to_string() || snippet.trim().contains(&format!("::{ty}"))
+}
diff --git a/clippy_lints/src/copy_iterator.rs b/clippy_lints/src/copy_iterator.rs
index 0fc11523298..5d04ad0112d 100644
--- a/clippy_lints/src/copy_iterator.rs
+++ b/clippy_lints/src/copy_iterator.rs
@@ -43,7 +43,7 @@ impl<'tcx> LateLintPass<'tcx> for CopyIterator {
                 of_trait: Some(ref trait_ref),
                 ..
             }) = item.kind;
-            let ty = cx.tcx.type_of(item.owner_id).subst_identity();
+            let ty = cx.tcx.type_of(item.owner_id).instantiate_identity();
             if is_copy(cx, ty);
             if let Some(trait_id) = trait_ref.trait_def_id();
             if cx.tcx.is_diagnostic_item(sym::Iterator, trait_id);
diff --git a/clippy_lints/src/declared_lints.rs b/clippy_lints/src/declared_lints.rs
index 47995fea9f9..db114abfc86 100644
--- a/clippy_lints/src/declared_lints.rs
+++ b/clippy_lints/src/declared_lints.rs
@@ -37,6 +37,7 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[
     crate::utils::internal_lints::produce_ice::PRODUCE_ICE_INFO,
     #[cfg(feature = "internal")]
     crate::utils::internal_lints::unnecessary_def_path::UNNECESSARY_DEF_PATH_INFO,
+    crate::absolute_paths::ABSOLUTE_PATHS_INFO,
     crate::allow_attributes::ALLOW_ATTRIBUTES_INFO,
     crate::almost_complete_range::ALMOST_COMPLETE_RANGE_INFO,
     crate::approx_const::APPROX_CONSTANT_INFO,
@@ -155,6 +156,7 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[
     crate::enum_variants::MODULE_INCEPTION_INFO,
     crate::enum_variants::MODULE_NAME_REPETITIONS_INFO,
     crate::equatable_if_let::EQUATABLE_IF_LET_INFO,
+    crate::error_impl_error::ERROR_IMPL_ERROR_INFO,
     crate::escape::BOXED_LOCAL_INFO,
     crate::eta_reduction::REDUNDANT_CLOSURE_INFO,
     crate::eta_reduction::REDUNDANT_CLOSURE_FOR_METHOD_CALLS_INFO,
@@ -201,6 +203,7 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[
     crate::if_let_mutex::IF_LET_MUTEX_INFO,
     crate::if_not_else::IF_NOT_ELSE_INFO,
     crate::if_then_some_else_none::IF_THEN_SOME_ELSE_NONE_INFO,
+    crate::ignored_unit_patterns::IGNORED_UNIT_PATTERNS_INFO,
     crate::implicit_hasher::IMPLICIT_HASHER_INFO,
     crate::implicit_return::IMPLICIT_RETURN_INFO,
     crate::implicit_saturating_add::IMPLICIT_SATURATING_ADD_INFO,
@@ -306,6 +309,7 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[
     crate::matches::MATCH_WILDCARD_FOR_SINGLE_VARIANTS_INFO,
     crate::matches::MATCH_WILD_ERR_ARM_INFO,
     crate::matches::NEEDLESS_MATCH_INFO,
+    crate::matches::REDUNDANT_GUARDS_INFO,
     crate::matches::REDUNDANT_PATTERN_MATCHING_INFO,
     crate::matches::REST_PAT_IN_FULLY_BOUND_STRUCTS_INFO,
     crate::matches::SIGNIFICANT_DROP_IN_SCRUTINEE_INFO,
@@ -334,6 +338,7 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[
     crate::methods::EXPECT_USED_INFO,
     crate::methods::EXTEND_WITH_DRAIN_INFO,
     crate::methods::FILETYPE_IS_FILE_INFO,
+    crate::methods::FILTER_MAP_BOOL_THEN_INFO,
     crate::methods::FILTER_MAP_IDENTITY_INFO,
     crate::methods::FILTER_MAP_NEXT_INFO,
     crate::methods::FILTER_NEXT_INFO,
@@ -394,6 +399,7 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[
     crate::methods::OR_THEN_UNWRAP_INFO,
     crate::methods::PATH_BUF_PUSH_OVERWRITE_INFO,
     crate::methods::RANGE_ZIP_WITH_LEN_INFO,
+    crate::methods::READONLY_WRITE_LOCK_INFO,
     crate::methods::READ_LINE_WITHOUT_TRIM_INFO,
     crate::methods::REPEAT_ONCE_INFO,
     crate::methods::RESULT_MAP_OR_INTO_OPTION_INFO,
@@ -422,7 +428,7 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[
     crate::methods::UNNECESSARY_LITERAL_UNWRAP_INFO,
     crate::methods::UNNECESSARY_SORT_BY_INFO,
     crate::methods::UNNECESSARY_TO_OWNED_INFO,
-    crate::methods::UNWRAP_OR_ELSE_DEFAULT_INFO,
+    crate::methods::UNWRAP_OR_DEFAULT_INFO,
     crate::methods::UNWRAP_USED_INFO,
     crate::methods::USELESS_ASREF_INFO,
     crate::methods::VEC_RESIZE_TO_ZERO_INFO,
@@ -512,6 +518,7 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[
     crate::operators::FLOAT_CMP_CONST_INFO,
     crate::operators::FLOAT_EQUALITY_WITHOUT_ABS_INFO,
     crate::operators::IDENTITY_OP_INFO,
+    crate::operators::IMPOSSIBLE_COMPARISONS_INFO,
     crate::operators::INEFFECTIVE_BIT_MASK_INFO,
     crate::operators::INTEGER_DIVISION_INFO,
     crate::operators::MISREFACTORED_ASSIGN_OP_INFO,
@@ -520,6 +527,7 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[
     crate::operators::NEEDLESS_BITWISE_BOOL_INFO,
     crate::operators::OP_REF_INFO,
     crate::operators::PTR_EQ_INFO,
+    crate::operators::REDUNDANT_COMPARISONS_INFO,
     crate::operators::SELF_ASSIGNMENT_INFO,
     crate::operators::VERBOSE_BIT_MASK_INFO,
     crate::option_env_unwrap::OPTION_ENV_UNWRAP_INFO,
@@ -559,6 +567,7 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[
     crate::redundant_closure_call::REDUNDANT_CLOSURE_CALL_INFO,
     crate::redundant_else::REDUNDANT_ELSE_INFO,
     crate::redundant_field_names::REDUNDANT_FIELD_NAMES_INFO,
+    crate::redundant_locals::REDUNDANT_LOCALS_INFO,
     crate::redundant_pub_crate::REDUNDANT_PUB_CRATE_INFO,
     crate::redundant_slicing::DEREF_BY_SLICING_INFO,
     crate::redundant_slicing::REDUNDANT_SLICING_INFO,
@@ -572,6 +581,7 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[
     crate::return_self_not_must_use::RETURN_SELF_NOT_MUST_USE_INFO,
     crate::returns::LET_AND_RETURN_INFO,
     crate::returns::NEEDLESS_RETURN_INFO,
+    crate::returns::NEEDLESS_RETURN_WITH_QUESTION_MARK_INFO,
     crate::same_name_method::SAME_NAME_METHOD_INFO,
     crate::self_named_constructors::SELF_NAMED_CONSTRUCTORS_INFO,
     crate::semicolon_block::SEMICOLON_INSIDE_BLOCK_INFO,
diff --git a/clippy_lints/src/default.rs b/clippy_lints/src/default.rs
index 80c22742ba4..763ad0264ad 100644
--- a/clippy_lints/src/default.rs
+++ b/clippy_lints/src/default.rs
@@ -150,7 +150,7 @@ impl<'tcx> LateLintPass<'tcx> for Default {
                     .fields
                     .iter()
                     .all(|field| {
-                        is_copy(cx, cx.tcx.type_of(field.did).subst_identity())
+                        is_copy(cx, cx.tcx.type_of(field.did).instantiate_identity())
                     });
                 if !has_drop(cx, binding_type) || all_fields_are_copy;
                 then {
@@ -219,11 +219,11 @@ impl<'tcx> LateLintPass<'tcx> for Default {
 
                 // give correct suggestion if generics are involved (see #6944)
                 let binding_type = if_chain! {
-                    if let ty::Adt(adt_def, substs) = binding_type.kind();
-                    if !substs.is_empty();
+                    if let ty::Adt(adt_def, args) = binding_type.kind();
+                    if !args.is_empty();
                     then {
                         let adt_def_ty_name = cx.tcx.item_name(adt_def.did());
-                        let generic_args = substs.iter().collect::<Vec<_>>();
+                        let generic_args = args.iter().collect::<Vec<_>>();
                         let tys_str = generic_args
                             .iter()
                             .map(ToString::to_string)
diff --git a/clippy_lints/src/default_numeric_fallback.rs b/clippy_lints/src/default_numeric_fallback.rs
index 0708b1cabdb..d09428dbc1f 100644
--- a/clippy_lints/src/default_numeric_fallback.rs
+++ b/clippy_lints/src/default_numeric_fallback.rs
@@ -137,7 +137,7 @@ impl<'a, 'tcx> Visitor<'tcx> for NumericFallbackVisitor<'a, 'tcx> {
 
             ExprKind::MethodCall(_, receiver, args, _) => {
                 if let Some(def_id) = self.cx.typeck_results().type_dependent_def_id(expr.hir_id) {
-                    let fn_sig = self.cx.tcx.fn_sig(def_id).subst_identity().skip_binder();
+                    let fn_sig = self.cx.tcx.fn_sig(def_id).instantiate_identity().skip_binder();
                     for (expr, bound) in iter::zip(std::iter::once(*receiver).chain(args.iter()), fn_sig.inputs()) {
                         self.ty_bounds.push((*bound).into());
                         self.visit_expr(expr);
@@ -163,7 +163,7 @@ impl<'a, 'tcx> Visitor<'tcx> for NumericFallbackVisitor<'a, 'tcx> {
                                     .iter()
                                     .find_map(|f_def| {
                                         if f_def.ident(self.cx.tcx) == field.ident
-                                            { Some(self.cx.tcx.type_of(f_def.did).subst_identity()) }
+                                            { Some(self.cx.tcx.type_of(f_def.did).instantiate_identity()) }
                                         else { None }
                                     });
                             self.ty_bounds.push(bound.into());
@@ -209,9 +209,9 @@ impl<'a, 'tcx> Visitor<'tcx> for NumericFallbackVisitor<'a, 'tcx> {
 
 fn fn_sig_opt<'tcx>(cx: &LateContext<'tcx>, hir_id: HirId) -> Option<PolyFnSig<'tcx>> {
     let node_ty = cx.typeck_results().node_type_opt(hir_id)?;
-    // We can't use `Ty::fn_sig` because it automatically performs substs, this may result in FNs.
+    // We can't use `Ty::fn_sig` because it automatically performs args, this may result in FNs.
     match node_ty.kind() {
-        ty::FnDef(def_id, _) => Some(cx.tcx.fn_sig(*def_id).subst_identity()),
+        ty::FnDef(def_id, _) => Some(cx.tcx.fn_sig(*def_id).instantiate_identity()),
         ty::FnPtr(fn_sig) => Some(*fn_sig),
         _ => None,
     }
diff --git a/clippy_lints/src/dereference.rs b/clippy_lints/src/dereference.rs
index b2f78ddf989..a5ec979ccd9 100644
--- a/clippy_lints/src/dereference.rs
+++ b/clippy_lints/src/dereference.rs
@@ -3,21 +3,23 @@ use clippy_utils::mir::{enclosing_mir, expr_local, local_assignments, used_exact
 use clippy_utils::msrvs::{self, Msrv};
 use clippy_utils::source::{snippet_with_applicability, snippet_with_context};
 use clippy_utils::sugg::has_enclosing_paren;
-use clippy_utils::ty::{adt_and_variant_of_res, expr_sig, is_copy, peel_mid_ty_refs, ty_sig};
+use clippy_utils::ty::{is_copy, peel_mid_ty_refs};
 use clippy_utils::{
-    fn_def_id, get_parent_expr, get_parent_expr_for_hir, is_lint_allowed, path_to_local, walk_to_expr_usage,
+    expr_use_ctxt, get_parent_expr, get_parent_node, is_lint_allowed, path_to_local, DefinedTy, ExprUseNode,
 };
 
+use hir::def::DefKind;
+use hir::MatchSource;
 use rustc_ast::util::parser::{PREC_POSTFIX, PREC_PREFIX};
 use rustc_data_structures::fx::FxIndexMap;
 use rustc_data_structures::graph::iterate::{CycleDetector, TriColorDepthFirstSearch};
 use rustc_errors::Applicability;
+use rustc_hir::def::Res;
 use rustc_hir::def_id::{DefId, LocalDefId};
 use rustc_hir::intravisit::{walk_ty, Visitor};
 use rustc_hir::{
-    self as hir, BindingAnnotation, Body, BodyId, BorrowKind, Closure, Expr, ExprKind, FnRetTy, GenericArg, HirId,
-    ImplItem, ImplItemKind, Item, ItemKind, Local, MatchSource, Mutability, Node, Pat, PatKind, Path, QPath, TraitItem,
-    TraitItemKind, TyKind, UnOp,
+    self as hir, BindingAnnotation, Body, BodyId, BorrowKind, Expr, ExprKind, HirId, Mutability, Node, Pat, PatKind,
+    Path, QPath, TyKind, UnOp,
 };
 use rustc_index::bit_set::BitSet;
 use rustc_infer::infer::TyCtxtInferExt;
@@ -25,8 +27,8 @@ use rustc_lint::{LateContext, LateLintPass};
 use rustc_middle::mir::{Rvalue, StatementKind};
 use rustc_middle::ty::adjustment::{Adjust, Adjustment, AutoBorrow, AutoBorrowMutability};
 use rustc_middle::ty::{
-    self, Binder, BoundVariableKind, ClauseKind, EarlyBinder, FnSig, GenericArgKind, List, ParamEnv, ParamTy,
-    ProjectionPredicate, Ty, TyCtxt, TypeVisitableExt, TypeckResults,
+    self, ClauseKind, EarlyBinder, FnSig, GenericArg, GenericArgKind, List, ParamEnv, ParamTy, ProjectionPredicate, Ty,
+    TyCtxt, TypeVisitableExt, TypeckResults,
 };
 use rustc_session::{declare_tool_lint, impl_lint_pass};
 use rustc_span::symbol::sym;
@@ -163,7 +165,7 @@ impl_lint_pass!(Dereferencing<'_> => [
 
 #[derive(Default)]
 pub struct Dereferencing<'tcx> {
-    state: Option<(State, StateData)>,
+    state: Option<(State, StateData<'tcx>)>,
 
     // While parsing a `deref` method call in ufcs form, the path to the function is itself an
     // expression. This is to store the id of that expression so it can be skipped when
@@ -203,29 +205,28 @@ impl<'tcx> Dereferencing<'tcx> {
 }
 
 #[derive(Debug)]
-struct StateData {
+struct StateData<'tcx> {
     /// Span of the top level expression
     span: Span,
     hir_id: HirId,
-    position: Position,
+    adjusted_ty: Ty<'tcx>,
 }
 
-#[derive(Debug)]
 struct DerefedBorrow {
     count: usize,
     msg: &'static str,
-    snip_expr: Option<HirId>,
+    stability: TyCoercionStability,
+    for_field_access: Option<Symbol>,
 }
 
-#[derive(Debug)]
 enum State {
     // Any number of deref method calls.
     DerefMethod {
         // The number of calls in a sequence which changed the referenced type
         ty_changed_count: usize,
-        is_final_ufcs: bool,
+        is_ufcs: bool,
         /// The required mutability
-        target_mut: Mutability,
+        mutbl: Mutability,
     },
     DerefedBorrow(DerefedBorrow),
     ExplicitDeref {
@@ -244,7 +245,7 @@ enum State {
 
 // A reference operation considered by this lint pass
 enum RefOp {
-    Method(Mutability),
+    Method { mutbl: Mutability, is_ufcs: bool },
     Deref,
     AddrOf(Mutability),
 }
@@ -294,48 +295,115 @@ impl<'tcx> LateLintPass<'tcx> for Dereferencing<'tcx> {
         match (self.state.take(), kind) {
             (None, kind) => {
                 let expr_ty = typeck.expr_ty(expr);
-                let (position, adjustments) = walk_parents(cx, &mut self.possible_borrowers, expr, &self.msrv);
-                match kind {
-                    RefOp::Deref => {
+                let use_cx = expr_use_ctxt(cx, expr);
+                let adjusted_ty = match &use_cx {
+                    Some(use_cx) => match use_cx.adjustments {
+                        [.., a] => a.target,
+                        _ => expr_ty,
+                    },
+                    _ => typeck.expr_ty_adjusted(expr),
+                };
+
+                match (use_cx, kind) {
+                    (Some(use_cx), RefOp::Deref) => {
                         let sub_ty = typeck.expr_ty(sub_expr);
-                        if let Position::FieldAccess {
-                            name,
-                            of_union: false,
-                        } = position
-                            && !ty_contains_field(sub_ty, name)
+                        if let ExprUseNode::FieldAccess(name) = use_cx.node
+                            && adjusted_ty.ty_adt_def().map_or(true, |adt| !adt.is_union())
+                            && !ty_contains_field(sub_ty, name.name)
                         {
                             self.state = Some((
-                                State::ExplicitDerefField { name },
-                                StateData { span: expr.span, hir_id: expr.hir_id, position },
+                                State::ExplicitDerefField { name: name.name },
+                                StateData {
+                                    span: expr.span,
+                                    hir_id: expr.hir_id,
+                                    adjusted_ty,
+                                },
                             ));
-                        } else if position.is_deref_stable() && sub_ty.is_ref() {
+                        } else if sub_ty.is_ref()
+                            // Linting method receivers would require verifying that name lookup
+                            // would resolve the same way. This is complicated by trait methods.
+                            && !use_cx.node.is_recv()
+                            && let Some(ty) = use_cx.node.defined_ty(cx)
+                            && TyCoercionStability::for_defined_ty(cx, ty, use_cx.node.is_return()).is_deref_stable()
+                        {
                             self.state = Some((
                                 State::ExplicitDeref { mutability: None },
-                                StateData { span: expr.span, hir_id: expr.hir_id, position },
+                                StateData {
+                                    span: expr.span,
+                                    hir_id: expr.hir_id,
+                                    adjusted_ty,
+                                },
                             ));
                         }
                     },
-                    RefOp::Method(target_mut)
+                    (_, RefOp::Method { mutbl, is_ufcs })
                         if !is_lint_allowed(cx, EXPLICIT_DEREF_METHODS, expr.hir_id)
-                            && position.lint_explicit_deref() =>
+                            // Allow explicit deref in method chains. e.g. `foo.deref().bar()`
+                            && (is_ufcs || !in_postfix_position(cx, expr)) =>
                     {
                         let ty_changed_count = usize::from(!deref_method_same_type(expr_ty, typeck.expr_ty(sub_expr)));
                         self.state = Some((
                             State::DerefMethod {
                                 ty_changed_count,
-                                is_final_ufcs: matches!(expr.kind, ExprKind::Call(..)),
-                                target_mut,
+                                is_ufcs,
+                                mutbl,
                             },
                             StateData {
                                 span: expr.span,
                                 hir_id: expr.hir_id,
-                                position,
+                                adjusted_ty,
                             },
                         ));
                     },
-                    RefOp::AddrOf(mutability) => {
+                    (Some(use_cx), RefOp::AddrOf(mutability)) => {
+                        let defined_ty = use_cx.node.defined_ty(cx);
+
+                        // Check needless_borrow for generic arguments.
+                        if !use_cx.is_ty_unified
+                            && let Some(DefinedTy::Mir(ty)) = defined_ty
+                            && let ty::Param(ty) = *ty.value.skip_binder().kind()
+                            && let Some((hir_id, fn_id, i)) = match use_cx.node {
+                                ExprUseNode::MethodArg(_, _, 0) => None,
+                                ExprUseNode::MethodArg(hir_id, None, i) => {
+                                    typeck.type_dependent_def_id(hir_id).map(|id| (hir_id, id, i))
+                                },
+                                ExprUseNode::FnArg(&Expr { kind: ExprKind::Path(ref p), hir_id, .. }, i)
+                                if !path_has_args(p) => match typeck.qpath_res(p, hir_id) {
+                                    Res::Def(DefKind::Fn | DefKind::Ctor(..) | DefKind::AssocFn, id) => {
+                                        Some((hir_id, id, i))
+                                    },
+                                    _ => None,
+                                },
+                                _ => None,
+                            } && let count = needless_borrow_generic_arg_count(
+                                cx,
+                                &mut self.possible_borrowers,
+                                fn_id,
+                                typeck.node_args(hir_id),
+                                i,
+                                ty,
+                                expr,
+                                &self.msrv,
+                            ) && count != 0
+                        {
+                            self.state = Some((
+                                State::DerefedBorrow(DerefedBorrow {
+                                    count: count - 1,
+                                    msg: "the borrowed expression implements the required traits",
+                                    stability: TyCoercionStability::None,
+                                    for_field_access: None,
+                                }),
+                                StateData {
+                                    span: expr.span,
+                                    hir_id: expr.hir_id,
+                                    adjusted_ty: use_cx.adjustments.last().map_or(expr_ty, |a| a.target),
+                                },
+                            ));
+                            return;
+                        }
+
                         // Find the number of times the borrow is auto-derefed.
-                        let mut iter = adjustments.iter();
+                        let mut iter = use_cx.adjustments.iter();
                         let mut deref_count = 0usize;
                         let next_adjust = loop {
                             match iter.next() {
@@ -352,6 +420,58 @@ impl<'tcx> LateLintPass<'tcx> for Dereferencing<'tcx> {
                             };
                         };
 
+                        let stability = defined_ty.map_or(TyCoercionStability::None, |ty| {
+                            TyCoercionStability::for_defined_ty(cx, ty, use_cx.node.is_return())
+                        });
+                        let can_auto_borrow = match use_cx.node {
+                            ExprUseNode::Callee => true,
+                            ExprUseNode::FieldAccess(_) => adjusted_ty.ty_adt_def().map_or(true, |adt| !adt.is_union()),
+                            ExprUseNode::MethodArg(hir_id, _, 0) if !use_cx.moved_before_use => {
+                                // Check for calls to trait methods where the trait is implemented
+                                // on a reference.
+                                // Two cases need to be handled:
+                                // * `self` methods on `&T` will never have auto-borrow
+                                // * `&self` methods on `&T` can have auto-borrow, but `&self` methods on `T` will take
+                                //   priority.
+                                if let Some(fn_id) = typeck.type_dependent_def_id(hir_id)
+                                    && let Some(trait_id) = cx.tcx.trait_of_item(fn_id)
+                                    && let arg_ty
+                                        = cx.tcx.erase_regions(use_cx.adjustments.last().map_or(expr_ty, |a| a.target))
+                                    && let ty::Ref(_, sub_ty, _) = *arg_ty.kind()
+                                    && let args = cx
+                                        .typeck_results()
+                                        .node_args_opt(hir_id).map(|args| &args[1..]).unwrap_or_default()
+                                    && let impl_ty = if cx.tcx.fn_sig(fn_id)
+                                        .instantiate_identity()
+                                        .skip_binder()
+                                        .inputs()[0].is_ref()
+                                    {
+                                        // Trait methods taking `&self`
+                                        sub_ty
+                                    } else {
+                                        // Trait methods taking `self`
+                                        arg_ty
+                                    } && impl_ty.is_ref()
+                                    && cx.tcx.infer_ctxt().build()
+                                        .type_implements_trait(
+                                            trait_id,
+                                            [impl_ty.into()].into_iter().chain(args.iter().copied()),
+                                            cx.param_env,
+                                        )
+                                        .must_apply_modulo_regions()
+                                {
+                                    false
+                                } else {
+                                    true
+                                }
+                            },
+                            _ => false,
+                        };
+
+                        let deref_msg =
+                            "this expression creates a reference which is immediately dereferenced by the compiler";
+                        let borrow_msg = "this expression borrows a value the compiler would automatically borrow";
+
                         // Determine the required number of references before any can be removed. In all cases the
                         // reference made by the current expression will be removed. After that there are four cases to
                         // handle.
@@ -374,26 +494,18 @@ impl<'tcx> LateLintPass<'tcx> for Dereferencing<'tcx> {
                         //        };
                         //    }
                         //    ```
-                        let deref_msg =
-                            "this expression creates a reference which is immediately dereferenced by the compiler";
-                        let borrow_msg = "this expression borrows a value the compiler would automatically borrow";
-                        let impl_msg = "the borrowed expression implements the required traits";
-
-                        let (required_refs, msg, snip_expr) = if position.can_auto_borrow() {
-                            (1, if deref_count == 1 { borrow_msg } else { deref_msg }, None)
-                        } else if let Position::ImplArg(hir_id) = position {
-                            (0, impl_msg, Some(hir_id))
-                        } else if let Some(&Adjust::Borrow(AutoBorrow::Ref(_, mutability))) =
-                            next_adjust.map(|a| &a.kind)
+                        let (required_refs, msg) = if can_auto_borrow {
+                            (1, if deref_count == 1 { borrow_msg } else { deref_msg })
+                        } else if let Some(&Adjustment {
+                                kind: Adjust::Borrow(AutoBorrow::Ref(_, mutability)),
+                                ..
+                            }) = next_adjust
+                            && matches!(mutability, AutoBorrowMutability::Mut { .. })
+                            && !stability.is_reborrow_stable()
                         {
-                            if matches!(mutability, AutoBorrowMutability::Mut { .. }) && !position.is_reborrow_stable()
-                            {
-                                (3, deref_msg, None)
-                            } else {
-                                (2, deref_msg, None)
-                            }
+                            (3, deref_msg)
                         } else {
-                            (2, deref_msg, None)
+                            (2, deref_msg)
                         };
 
                         if deref_count >= required_refs {
@@ -403,15 +515,19 @@ impl<'tcx> LateLintPass<'tcx> for Dereferencing<'tcx> {
                                     // can't be removed without breaking the code. See earlier comment.
                                     count: deref_count - required_refs,
                                     msg,
-                                    snip_expr,
+                                    stability,
+                                    for_field_access: match use_cx.node {
+                                        ExprUseNode::FieldAccess(name) => Some(name.name),
+                                        _ => None,
+                                    },
                                 }),
                                 StateData {
                                     span: expr.span,
                                     hir_id: expr.hir_id,
-                                    position,
+                                    adjusted_ty: use_cx.adjustments.last().map_or(expr_ty, |a| a.target),
                                 },
                             ));
-                        } else if position.is_deref_stable()
+                        } else if stability.is_deref_stable()
                             // Auto-deref doesn't combine with other adjustments
                             && next_adjust.map_or(true, |a| matches!(a.kind, Adjust::Deref(_) | Adjust::Borrow(_)))
                             && iter.all(|a| matches!(a.kind, Adjust::Deref(_) | Adjust::Borrow(_)))
@@ -421,24 +537,24 @@ impl<'tcx> LateLintPass<'tcx> for Dereferencing<'tcx> {
                                 StateData {
                                     span: expr.span,
                                     hir_id: expr.hir_id,
-                                    position,
+                                    adjusted_ty: use_cx.adjustments.last().map_or(expr_ty, |a| a.target),
                                 },
                             ));
                         }
                     },
-                    RefOp::Method(..) => (),
+                    (None, _) | (_, RefOp::Method { .. }) => (),
                 }
             },
             (
                 Some((
                     State::DerefMethod {
-                        target_mut,
+                        mutbl,
                         ty_changed_count,
                         ..
                     },
                     data,
                 )),
-                RefOp::Method(_),
+                RefOp::Method { is_ufcs, .. },
             ) => {
                 self.state = Some((
                     State::DerefMethod {
@@ -447,8 +563,8 @@ impl<'tcx> LateLintPass<'tcx> for Dereferencing<'tcx> {
                         } else {
                             ty_changed_count + 1
                         },
-                        is_final_ufcs: matches!(expr.kind, ExprKind::Call(..)),
-                        target_mut,
+                        is_ufcs,
+                        mutbl,
                     },
                     data,
                 ));
@@ -463,33 +579,44 @@ impl<'tcx> LateLintPass<'tcx> for Dereferencing<'tcx> {
                 ));
             },
             (Some((State::DerefedBorrow(state), data)), RefOp::AddrOf(mutability)) => {
-                let position = data.position;
+                let adjusted_ty = data.adjusted_ty;
+                let stability = state.stability;
                 report(cx, expr, State::DerefedBorrow(state), data);
-                if position.is_deref_stable() {
+                if stability.is_deref_stable() {
                     self.state = Some((
                         State::Borrow { mutability },
                         StateData {
                             span: expr.span,
                             hir_id: expr.hir_id,
-                            position,
+                            adjusted_ty,
                         },
                     ));
                 }
             },
             (Some((State::DerefedBorrow(state), data)), RefOp::Deref) => {
-                let position = data.position;
+                let adjusted_ty = data.adjusted_ty;
+                let stability = state.stability;
+                let for_field_access = state.for_field_access;
                 report(cx, expr, State::DerefedBorrow(state), data);
-                if let Position::FieldAccess{name, ..} = position
+                if let Some(name) = for_field_access
                     && !ty_contains_field(typeck.expr_ty(sub_expr), name)
                 {
                     self.state = Some((
                         State::ExplicitDerefField { name },
-                        StateData { span: expr.span, hir_id: expr.hir_id, position },
+                        StateData {
+                            span: expr.span,
+                            hir_id: expr.hir_id,
+                            adjusted_ty,
+                        },
                     ));
-                } else if position.is_deref_stable() {
+                } else if stability.is_deref_stable() {
                     self.state = Some((
                         State::ExplicitDeref { mutability: None },
-                        StateData { span: expr.span, hir_id: expr.hir_id, position },
+                        StateData {
+                            span: expr.span,
+                            hir_id: expr.hir_id,
+                            adjusted_ty,
+                        },
                     ));
                 }
             },
@@ -611,8 +738,8 @@ fn try_parse_ref_op<'tcx>(
     typeck: &'tcx TypeckResults<'_>,
     expr: &'tcx Expr<'_>,
 ) -> Option<(RefOp, &'tcx Expr<'tcx>)> {
-    let (def_id, arg) = match expr.kind {
-        ExprKind::MethodCall(_, arg, [], _) => (typeck.type_dependent_def_id(expr.hir_id)?, arg),
+    let (is_ufcs, def_id, arg) = match expr.kind {
+        ExprKind::MethodCall(_, arg, [], _) => (false, typeck.type_dependent_def_id(expr.hir_id)?, arg),
         ExprKind::Call(
             Expr {
                 kind: ExprKind::Path(path),
@@ -620,7 +747,7 @@ fn try_parse_ref_op<'tcx>(
                 ..
             },
             [arg],
-        ) => (typeck.qpath_res(path, *hir_id).opt_def_id()?, arg),
+        ) => (true, typeck.qpath_res(path, *hir_id).opt_def_id()?, arg),
         ExprKind::Unary(UnOp::Deref, sub_expr) if !typeck.expr_ty(sub_expr).is_unsafe_ptr() => {
             return Some((RefOp::Deref, sub_expr));
         },
@@ -628,9 +755,21 @@ fn try_parse_ref_op<'tcx>(
         _ => return None,
     };
     if tcx.is_diagnostic_item(sym::deref_method, def_id) {
-        Some((RefOp::Method(Mutability::Not), arg))
+        Some((
+            RefOp::Method {
+                mutbl: Mutability::Not,
+                is_ufcs,
+            },
+            arg,
+        ))
     } else if tcx.trait_of_item(def_id)? == tcx.lang_items().deref_mut_trait()? {
-        Some((RefOp::Method(Mutability::Mut), arg))
+        Some((
+            RefOp::Method {
+                mutbl: Mutability::Mut,
+                is_ufcs,
+            },
+            arg,
+        ))
     } else {
         None
     }
@@ -649,420 +788,164 @@ fn deref_method_same_type<'tcx>(result_ty: Ty<'tcx>, arg_ty: Ty<'tcx>) -> bool {
     }
 }
 
-/// The position of an expression relative to it's parent.
-#[derive(Clone, Copy, Debug)]
-enum Position {
-    MethodReceiver,
-    /// The method is defined on a reference type. e.g. `impl Foo for &T`
-    MethodReceiverRefImpl,
-    Callee,
-    ImplArg(HirId),
-    FieldAccess {
-        name: Symbol,
-        of_union: bool,
-    }, // union fields cannot be auto borrowed
-    Postfix,
-    Deref,
-    /// Any other location which will trigger auto-deref to a specific time.
-    /// Contains the precedence of the parent expression and whether the target type is sized.
-    DerefStable(i8, bool),
-    /// Any other location which will trigger auto-reborrowing.
-    /// Contains the precedence of the parent expression.
-    ReborrowStable(i8),
-    /// Contains the precedence of the parent expression.
-    Other(i8),
-}
-impl Position {
-    fn is_deref_stable(self) -> bool {
-        matches!(self, Self::DerefStable(..))
+fn path_has_args(p: &QPath<'_>) -> bool {
+    match *p {
+        QPath::Resolved(_, Path { segments: [.., s], .. }) | QPath::TypeRelative(_, s) => s.args.is_some(),
+        _ => false,
     }
+}
 
-    fn is_reborrow_stable(self) -> bool {
-        matches!(self, Self::DerefStable(..) | Self::ReborrowStable(_))
+fn in_postfix_position<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'tcx>) -> bool {
+    if let Some(parent) = get_parent_expr(cx, e)
+        && parent.span.ctxt() == e.span.ctxt()
+    {
+        match parent.kind {
+            ExprKind::Call(child, _) | ExprKind::MethodCall(_, child, _, _) | ExprKind::Index(child, _)
+                if child.hir_id == e.hir_id => true,
+            ExprKind::Field(_, _) | ExprKind::Match(_, _, MatchSource::TryDesugar | MatchSource::AwaitDesugar) => true,
+            _ => false,
+        }
+    } else {
+        false
     }
+}
 
-    fn can_auto_borrow(self) -> bool {
-        matches!(
-            self,
-            Self::MethodReceiver | Self::FieldAccess { of_union: false, .. } | Self::Callee
-        )
+#[derive(Clone, Copy)]
+enum TyCoercionStability {
+    Deref,
+    Reborrow,
+    None,
+}
+impl TyCoercionStability {
+    fn is_deref_stable(self) -> bool {
+        matches!(self, Self::Deref)
     }
 
-    fn lint_explicit_deref(self) -> bool {
-        matches!(self, Self::Other(_) | Self::DerefStable(..) | Self::ReborrowStable(_))
+    fn is_reborrow_stable(self) -> bool {
+        matches!(self, Self::Deref | Self::Reborrow)
     }
 
-    fn precedence(self) -> i8 {
-        match self {
-            Self::MethodReceiver
-            | Self::MethodReceiverRefImpl
-            | Self::Callee
-            | Self::FieldAccess { .. }
-            | Self::Postfix => PREC_POSTFIX,
-            Self::ImplArg(_) | Self::Deref => PREC_PREFIX,
-            Self::DerefStable(p, _) | Self::ReborrowStable(p) | Self::Other(p) => p,
+    fn for_defined_ty<'tcx>(cx: &LateContext<'tcx>, ty: DefinedTy<'tcx>, for_return: bool) -> Self {
+        match ty {
+            DefinedTy::Hir(ty) => Self::for_hir_ty(ty),
+            DefinedTy::Mir(ty) => Self::for_mir_ty(
+                cx.tcx,
+                ty.param_env,
+                cx.tcx.erase_late_bound_regions(ty.value),
+                for_return,
+            ),
         }
     }
-}
-
-/// Walks up the parent expressions attempting to determine both how stable the auto-deref result
-/// is, and which adjustments will be applied to it. Note this will not consider auto-borrow
-/// locations as those follow different rules.
-#[expect(clippy::too_many_lines)]
-fn walk_parents<'tcx>(
-    cx: &LateContext<'tcx>,
-    possible_borrowers: &mut Vec<(LocalDefId, PossibleBorrowerMap<'tcx, 'tcx>)>,
-    e: &'tcx Expr<'_>,
-    msrv: &Msrv,
-) -> (Position, &'tcx [Adjustment<'tcx>]) {
-    let mut adjustments = [].as_slice();
-    let mut precedence = 0i8;
-    let ctxt = e.span.ctxt();
-    let position = walk_to_expr_usage(cx, e, &mut |parent, child_id| {
-        // LocalTableInContext returns the wrong lifetime, so go use `expr_adjustments` instead.
-        if adjustments.is_empty() && let Node::Expr(e) = cx.tcx.hir().get(child_id) {
-            adjustments = cx.typeck_results().expr_adjustments(e);
-        }
-        match parent {
-            Node::Local(Local { ty: Some(ty), span, .. }) if span.ctxt() == ctxt => {
-                Some(binding_ty_auto_deref_stability(cx, ty, precedence, List::empty()))
-            },
-            Node::Item(&Item {
-                kind: ItemKind::Static(..) | ItemKind::Const(..),
-                owner_id,
-                span,
-                ..
-            })
-            | Node::TraitItem(&TraitItem {
-                kind: TraitItemKind::Const(..),
-                owner_id,
-                span,
-                ..
-            })
-            | Node::ImplItem(&ImplItem {
-                kind: ImplItemKind::Const(..),
-                owner_id,
-                span,
-                ..
-            }) if span.ctxt() == ctxt => {
-                let ty = cx.tcx.type_of(owner_id.def_id).subst_identity();
-                Some(ty_auto_deref_stability(cx.tcx, cx.param_env, ty, precedence).position_for_result(cx))
-            },
 
-            Node::Item(&Item {
-                kind: ItemKind::Fn(..),
-                owner_id,
-                span,
-                ..
-            })
-            | Node::TraitItem(&TraitItem {
-                kind: TraitItemKind::Fn(..),
-                owner_id,
-                span,
-                ..
-            })
-            | Node::ImplItem(&ImplItem {
-                kind: ImplItemKind::Fn(..),
-                owner_id,
-                span,
-                ..
-            }) if span.ctxt() == ctxt => {
-                let output = cx
-                    .tcx
-                    .erase_late_bound_regions(cx.tcx.fn_sig(owner_id).subst_identity().output());
-                Some(ty_auto_deref_stability(cx.tcx, cx.param_env, output, precedence).position_for_result(cx))
-            },
-
-            Node::ExprField(field) if field.span.ctxt() == ctxt => match get_parent_expr_for_hir(cx, field.hir_id) {
-                Some(Expr {
-                    hir_id,
-                    kind: ExprKind::Struct(path, ..),
-                    ..
-                }) => adt_and_variant_of_res(cx, cx.qpath_res(path, *hir_id))
-                    .and_then(|(adt, variant)| {
-                        variant
-                            .fields
-                            .iter()
-                            .find(|f| f.name == field.ident.name)
-                            .map(|f| (adt, f))
-                    })
-                    .map(|(adt, field_def)| {
-                        ty_auto_deref_stability(
-                            cx.tcx,
-                            // Use the param_env of the target type.
-                            cx.tcx.param_env(adt.did()),
-                            cx.tcx.type_of(field_def.did).subst_identity(),
-                            precedence,
-                        )
-                        .position_for_arg()
-                    }),
-                _ => None,
-            },
+    // Checks the stability of type coercions when assigned to a binding with the given explicit type.
+    //
+    // e.g.
+    // let x = Box::new(Box::new(0u32));
+    // let y1: &Box<_> = x.deref();
+    // let y2: &Box<_> = &x;
+    //
+    // Here `y1` and `y2` would resolve to different types, so the type `&Box<_>` is not stable when
+    // switching to auto-dereferencing.
+    fn for_hir_ty<'tcx>(ty: &'tcx hir::Ty<'tcx>) -> Self {
+        let TyKind::Ref(_, ty) = &ty.kind else {
+            return Self::None;
+        };
+        let mut ty = ty;
 
-            Node::Expr(parent) if parent.span.ctxt() == ctxt => match parent.kind {
-                ExprKind::Ret(_) => {
-                    let owner_id = cx.tcx.hir().body_owner_def_id(cx.enclosing_body.unwrap());
-                    Some(
-                        if let Node::Expr(
-                            closure_expr @ Expr {
-                                kind: ExprKind::Closure(closure),
-                                ..
-                            },
-                        ) = cx.tcx.hir().get_by_def_id(owner_id)
-                        {
-                            closure_result_position(cx, closure, cx.typeck_results().expr_ty(closure_expr), precedence)
-                        } else {
-                            let output = cx
-                                .tcx
-                                .erase_late_bound_regions(cx.tcx.fn_sig(owner_id).subst_identity().output());
-                            ty_auto_deref_stability(cx.tcx, cx.param_env, output, precedence).position_for_result(cx)
-                        },
-                    )
-                },
-                ExprKind::Closure(closure) => Some(closure_result_position(
-                    cx,
-                    closure,
-                    cx.typeck_results().expr_ty(parent),
-                    precedence,
-                )),
-                ExprKind::Call(func, _) if func.hir_id == child_id => {
-                    (child_id == e.hir_id).then_some(Position::Callee)
+        loop {
+            break match ty.ty.kind {
+                TyKind::Ref(_, ref ref_ty) => {
+                    ty = ref_ty;
+                    continue;
                 },
-                ExprKind::Call(func, args) => args
-                    .iter()
-                    .position(|arg| arg.hir_id == child_id)
-                    .zip(expr_sig(cx, func))
-                    .and_then(|(i, sig)| {
-                        sig.input_with_hir(i).map(|(hir_ty, ty)| {
-                            match hir_ty {
-                                // Type inference for closures can depend on how they're called. Only go by the explicit
-                                // types here.
-                                Some(hir_ty) => {
-                                    binding_ty_auto_deref_stability(cx, hir_ty, precedence, ty.bound_vars())
-                                },
-                                None => {
-                                    // `e.hir_id == child_id` for https://github.com/rust-lang/rust-clippy/issues/9739
-                                    // `!call_is_qualified(func)` for https://github.com/rust-lang/rust-clippy/issues/9782
-                                    if e.hir_id == child_id
-                                        && !call_is_qualified(func)
-                                        && let ty::Param(param_ty) = ty.skip_binder().kind()
-                                    {
-                                        needless_borrow_impl_arg_position(
-                                            cx,
-                                            possible_borrowers,
-                                            parent,
-                                            i,
-                                            *param_ty,
-                                            e,
-                                            precedence,
-                                            msrv,
-                                        )
-                                    } else {
-                                        ty_auto_deref_stability(
-                                            cx.tcx,
-                                            // Use the param_env of the target function.
-                                            sig.predicates_id().map_or(ParamEnv::empty(), |id| cx.tcx.param_env(id)),
-                                            cx.tcx.erase_late_bound_regions(ty),
-                                            precedence
-                                        ).position_for_arg()
-                                    }
-                                },
-                            }
+                TyKind::Path(
+                    QPath::TypeRelative(_, path)
+                    | QPath::Resolved(
+                        _,
+                        Path {
+                            segments: [.., path], ..
+                        },
+                    ),
+                ) => {
+                    if let Some(args) = path.args
+                        && args.args.iter().any(|arg| match arg {
+                            hir::GenericArg::Infer(_) => true,
+                            hir::GenericArg::Type(ty) => ty_contains_infer(ty),
+                            _ => false,
                         })
-                    }),
-                ExprKind::MethodCall(method, receiver, args, _) => {
-                    let fn_id = cx.typeck_results().type_dependent_def_id(parent.hir_id).unwrap();
-                    if receiver.hir_id == child_id {
-                        // Check for calls to trait methods where the trait is implemented on a reference.
-                        // Two cases need to be handled:
-                        // * `self` methods on `&T` will never have auto-borrow
-                        // * `&self` methods on `&T` can have auto-borrow, but `&self` methods on `T` will take
-                        //   priority.
-                        if e.hir_id != child_id {
-                            return Some(Position::ReborrowStable(precedence))
-                        } else if let Some(trait_id) = cx.tcx.trait_of_item(fn_id)
-                            && let arg_ty = cx.tcx.erase_regions(cx.typeck_results().expr_ty_adjusted(e))
-                            && let ty::Ref(_, sub_ty, _) = *arg_ty.kind()
-                            && let subs = cx
-                                .typeck_results()
-                                .node_substs_opt(parent.hir_id).map(|subs| &subs[1..]).unwrap_or_default()
-                            && let impl_ty = if cx.tcx.fn_sig(fn_id)
-                                .subst_identity()
-                                .skip_binder()
-                                .inputs()[0].is_ref()
-                            {
-                                // Trait methods taking `&self`
-                                sub_ty
-                            } else {
-                                // Trait methods taking `self`
-                                arg_ty
-                            } && impl_ty.is_ref()
-                            && let infcx = cx.tcx.infer_ctxt().build()
-                            && infcx
-                                .type_implements_trait(
-                                    trait_id,
-                                    [impl_ty.into()].into_iter().chain(subs.iter().copied()),
-                                    cx.param_env,
-                                )
-                                .must_apply_modulo_regions()
-                        {
-                            return Some(Position::MethodReceiverRefImpl)
-                        }
-                        return Some(Position::MethodReceiver);
+                    {
+                        Self::Reborrow
+                    } else {
+                        Self::Deref
                     }
-                    args.iter().position(|arg| arg.hir_id == child_id).map(|i| {
-                        let ty = cx.tcx.fn_sig(fn_id).subst_identity().input(i + 1);
-                        // `e.hir_id == child_id` for https://github.com/rust-lang/rust-clippy/issues/9739
-                        // `method.args.is_none()` for https://github.com/rust-lang/rust-clippy/issues/9782
-                        if e.hir_id == child_id
-                            && method.args.is_none()
-                            && let ty::Param(param_ty) = ty.skip_binder().kind()
-                        {
-                            needless_borrow_impl_arg_position(
-                                cx,
-                                possible_borrowers,
-                                parent,
-                                i + 1,
-                                *param_ty,
-                                e,
-                                precedence,
-                                msrv,
-                            )
-                        } else {
-                            ty_auto_deref_stability(
-                                cx.tcx,
-                                // Use the param_env of the target function.
-                                cx.tcx.param_env(fn_id),
-                                cx.tcx.erase_late_bound_regions(ty),
-                                precedence,
-                            )
-                            .position_for_arg()
-                        }
-                    })
                 },
-                ExprKind::Field(child, name) if child.hir_id == e.hir_id => Some(Position::FieldAccess {
-                    name: name.name,
-                    of_union: is_union(cx.typeck_results(), child),
-                }),
-                ExprKind::Unary(UnOp::Deref, child) if child.hir_id == e.hir_id => Some(Position::Deref),
-                ExprKind::Match(child, _, MatchSource::TryDesugar | MatchSource::AwaitDesugar)
-                | ExprKind::Index(child, _)
-                    if child.hir_id == e.hir_id =>
-                {
-                    Some(Position::Postfix)
-                },
-                _ if child_id == e.hir_id => {
-                    precedence = parent.precedence().order();
-                    None
-                },
-                _ => None,
-            },
-            _ => None,
+                TyKind::Slice(_)
+                | TyKind::Array(..)
+                | TyKind::Ptr(_)
+                | TyKind::BareFn(_)
+                | TyKind::Never
+                | TyKind::Tup(_)
+                | TyKind::Path(_) => Self::Deref,
+                TyKind::OpaqueDef(..)
+                | TyKind::Infer
+                | TyKind::Typeof(..)
+                | TyKind::TraitObject(..)
+                | TyKind::Err(_) => Self::Reborrow,
+            };
         }
-    })
-    .unwrap_or(Position::Other(precedence));
-    (position, adjustments)
-}
-
-fn is_union<'tcx>(typeck: &'tcx TypeckResults<'_>, path_expr: &'tcx Expr<'_>) -> bool {
-    typeck
-        .expr_ty_adjusted(path_expr)
-        .ty_adt_def()
-        .map_or(false, rustc_middle::ty::AdtDef::is_union)
-}
-
-fn closure_result_position<'tcx>(
-    cx: &LateContext<'tcx>,
-    closure: &'tcx Closure<'_>,
-    ty: Ty<'tcx>,
-    precedence: i8,
-) -> Position {
-    match closure.fn_decl.output {
-        FnRetTy::Return(hir_ty) => {
-            if let Some(sig) = ty_sig(cx, ty)
-                && let Some(output) = sig.output()
-            {
-                binding_ty_auto_deref_stability(cx, hir_ty, precedence, output.bound_vars())
-            } else {
-                Position::Other(precedence)
-            }
-        },
-        FnRetTy::DefaultReturn(_) => Position::Other(precedence),
     }
-}
 
-// Checks the stability of auto-deref when assigned to a binding with the given explicit type.
-//
-// e.g.
-// let x = Box::new(Box::new(0u32));
-// let y1: &Box<_> = x.deref();
-// let y2: &Box<_> = &x;
-//
-// Here `y1` and `y2` would resolve to different types, so the type `&Box<_>` is not stable when
-// switching to auto-dereferencing.
-fn binding_ty_auto_deref_stability<'tcx>(
-    cx: &LateContext<'tcx>,
-    ty: &'tcx hir::Ty<'_>,
-    precedence: i8,
-    binder_args: &'tcx List<BoundVariableKind>,
-) -> Position {
-    let TyKind::Ref(_, ty) = &ty.kind else {
-        return Position::Other(precedence);
-    };
-    let mut ty = ty;
+    fn for_mir_ty<'tcx>(tcx: TyCtxt<'tcx>, param_env: ParamEnv<'tcx>, ty: Ty<'tcx>, for_return: bool) -> Self {
+        let ty::Ref(_, mut ty, _) = *ty.kind() else {
+            return Self::None;
+        };
 
-    loop {
-        break match ty.ty.kind {
-            TyKind::Ref(_, ref ref_ty) => {
-                ty = ref_ty;
-                continue;
-            },
-            TyKind::Path(
-                QPath::TypeRelative(_, path)
-                | QPath::Resolved(
-                    _,
-                    Path {
-                        segments: [.., path], ..
-                    },
-                ),
-            ) => {
-                if let Some(args) = path.args
-                    && args.args.iter().any(|arg| match arg {
-                        GenericArg::Infer(_) => true,
-                        GenericArg::Type(ty) => ty_contains_infer(ty),
-                        _ => false,
-                    })
+        ty = tcx.try_normalize_erasing_regions(param_env, ty).unwrap_or(ty);
+        loop {
+            break match *ty.kind() {
+                ty::Ref(_, ref_ty, _) => {
+                    ty = ref_ty;
+                    continue;
+                },
+                ty::Param(_) if for_return => Self::Deref,
+                ty::Alias(ty::Weak | ty::Inherent, _) => unreachable!("should have been normalized away above"),
+                ty::Alias(ty::Projection, _) if !for_return && ty.has_non_region_param() => Self::Reborrow,
+                ty::Infer(_)
+                | ty::Error(_)
+                | ty::Bound(..)
+                | ty::Alias(ty::Opaque, ..)
+                | ty::Placeholder(_)
+                | ty::Dynamic(..)
+                | ty::Param(_) => Self::Reborrow,
+                ty::Adt(_, args)
+                    if ty.has_placeholders()
+                        || ty.has_opaque_types()
+                        || (!for_return && args.has_non_region_param()) =>
                 {
-                    Position::ReborrowStable(precedence)
-                } else {
-                    Position::DerefStable(
-                        precedence,
-                        cx.tcx
-                            .erase_late_bound_regions(Binder::bind_with_vars(
-                                cx.typeck_results().node_type(ty.ty.hir_id),
-                                binder_args,
-                            ))
-                            .is_sized(cx.tcx, cx.param_env.without_caller_bounds()),
-                    )
-                }
-            },
-            TyKind::Slice(_) => Position::DerefStable(precedence, false),
-            TyKind::Array(..) | TyKind::Ptr(_) | TyKind::BareFn(_) => Position::DerefStable(precedence, true),
-            TyKind::Never
-            | TyKind::Tup(_)
-            | TyKind::Path(_) => Position::DerefStable(
-                precedence,
-                cx.tcx
-                    .erase_late_bound_regions(Binder::bind_with_vars(
-                        cx.typeck_results().node_type(ty.ty.hir_id),
-                        binder_args,
-                    ))
-                    .is_sized(cx.tcx, cx.param_env.without_caller_bounds()),
-            ),
-            TyKind::OpaqueDef(..) | TyKind::Infer | TyKind::Typeof(..) | TyKind::TraitObject(..) | TyKind::Err(_) => {
-                Position::ReborrowStable(precedence)
-            },
-        };
+                    Self::Reborrow
+                },
+                ty::Bool
+                | ty::Char
+                | ty::Int(_)
+                | ty::Uint(_)
+                | ty::Array(..)
+                | ty::Float(_)
+                | ty::RawPtr(..)
+                | ty::FnPtr(_)
+                | ty::Str
+                | ty::Slice(..)
+                | ty::Adt(..)
+                | ty::Foreign(_)
+                | ty::FnDef(..)
+                | ty::Generator(..)
+                | ty::GeneratorWitness(..)
+                | ty::GeneratorWitnessMIR(..)
+                | ty::Closure(..)
+                | ty::Never
+                | ty::Tuple(_)
+                | ty::Alias(ty::Projection, _) => Self::Deref,
+            };
+        }
     }
 }
 
@@ -1084,10 +967,10 @@ fn ty_contains_infer(ty: &hir::Ty<'_>) -> bool {
             }
         }
 
-        fn visit_generic_arg(&mut self, arg: &GenericArg<'_>) {
-            if self.0 || matches!(arg, GenericArg::Infer(_)) {
+        fn visit_generic_arg(&mut self, arg: &hir::GenericArg<'_>) {
+            if self.0 || matches!(arg, hir::GenericArg::Infer(_)) {
                 self.0 = true;
-            } else if let GenericArg::Type(ty) = arg {
+            } else if let hir::GenericArg::Type(ty) = arg {
                 self.visit_ty(ty);
             }
         }
@@ -1097,51 +980,29 @@ fn ty_contains_infer(ty: &hir::Ty<'_>) -> bool {
     v.0
 }
 
-fn call_is_qualified(expr: &Expr<'_>) -> bool {
-    if let ExprKind::Path(path) = &expr.kind {
-        match path {
-            QPath::Resolved(_, path) => path.segments.last().map_or(false, |segment| segment.args.is_some()),
-            QPath::TypeRelative(_, segment) => segment.args.is_some(),
-            QPath::LangItem(..) => false,
-        }
-    } else {
-        false
-    }
-}
-
-// Checks whether:
-// * child is an expression of the form `&e` in an argument position requiring an `impl Trait`
-// * `e`'s type implements `Trait` and is copyable
-// If the conditions are met, returns `Some(Position::ImplArg(..))`; otherwise, returns `None`.
-//   The "is copyable" condition is to avoid the case where removing the `&` means `e` would have to
-// be moved, but it cannot be.
-#[expect(clippy::too_many_arguments, clippy::too_many_lines)]
-fn needless_borrow_impl_arg_position<'tcx>(
+/// Checks for the number of borrow expressions which can be removed from the given expression
+/// where the expression is used as an argument to a function expecting a generic type.
+///
+/// The following constraints will be checked:
+/// * The borrowed expression meets all the generic type's constraints.
+/// * The generic type appears only once in the functions signature.
+/// * The borrowed value will not be moved if it is used later in the function.
+#[expect(clippy::too_many_arguments)]
+fn needless_borrow_generic_arg_count<'tcx>(
     cx: &LateContext<'tcx>,
     possible_borrowers: &mut Vec<(LocalDefId, PossibleBorrowerMap<'tcx, 'tcx>)>,
-    parent: &Expr<'tcx>,
+    fn_id: DefId,
+    callee_args: &'tcx List<GenericArg<'tcx>>,
     arg_index: usize,
     param_ty: ParamTy,
     mut expr: &Expr<'tcx>,
-    precedence: i8,
     msrv: &Msrv,
-) -> Position {
+) -> usize {
     let destruct_trait_def_id = cx.tcx.lang_items().destruct_trait();
     let sized_trait_def_id = cx.tcx.lang_items().sized_trait();
 
-    let Some(callee_def_id) = fn_def_id(cx, parent) else {
-        return Position::Other(precedence);
-    };
-    let fn_sig = cx.tcx.fn_sig(callee_def_id).subst_identity().skip_binder();
-    let substs_with_expr_ty = cx
-        .typeck_results()
-        .node_substs(if let ExprKind::Call(callee, _) = parent.kind {
-            callee.hir_id
-        } else {
-            parent.hir_id
-        });
-
-    let predicates = cx.tcx.param_env(callee_def_id).caller_bounds();
+    let fn_sig = cx.tcx.fn_sig(fn_id).instantiate_identity().skip_binder();
+    let predicates = cx.tcx.param_env(fn_id).caller_bounds();
     let projection_predicates = predicates
         .iter()
         .filter_map(|predicate| {
@@ -1176,7 +1037,7 @@ fn needless_borrow_impl_arg_position<'tcx>(
                 || cx.tcx.is_diagnostic_item(sym::Any, trait_def_id)
         })
     {
-        return Position::Other(precedence);
+        return 0;
     }
 
     // See:
@@ -1184,14 +1045,14 @@ fn needless_borrow_impl_arg_position<'tcx>(
     // - https://github.com/rust-lang/rust-clippy/pull/9674#issuecomment-1292225232
     if projection_predicates
         .iter()
-        .any(|projection_predicate| is_mixed_projection_predicate(cx, callee_def_id, projection_predicate))
+        .any(|projection_predicate| is_mixed_projection_predicate(cx, fn_id, projection_predicate))
     {
-        return Position::Other(precedence);
+        return 0;
     }
 
-    // `substs_with_referent_ty` can be constructed outside of `check_referent` because the same
+    // `args_with_referent_ty` can be constructed outside of `check_referent` because the same
     // elements are modified each time `check_referent` is called.
-    let mut substs_with_referent_ty = substs_with_expr_ty.to_vec();
+    let mut args_with_referent_ty = callee_args.to_vec();
 
     let mut check_reference_and_referent = |reference, referent| {
         let referent_ty = cx.typeck_results().expr_ty(referent);
@@ -1215,7 +1076,7 @@ fn needless_borrow_impl_arg_position<'tcx>(
             fn_sig,
             arg_index,
             &projection_predicates,
-            &mut substs_with_referent_ty,
+            &mut args_with_referent_ty,
         ) {
             return false;
         }
@@ -1224,34 +1085,29 @@ fn needless_borrow_impl_arg_position<'tcx>(
             if let ClauseKind::Trait(trait_predicate) = predicate.kind().skip_binder()
                 && cx.tcx.is_diagnostic_item(sym::IntoIterator, trait_predicate.trait_ref.def_id)
                 && let ty::Param(param_ty) = trait_predicate.self_ty().kind()
-                && let GenericArgKind::Type(ty) = substs_with_referent_ty[param_ty.index as usize].unpack()
+                && let GenericArgKind::Type(ty) = args_with_referent_ty[param_ty.index as usize].unpack()
                 && ty.is_array()
                 && !msrv.meets(msrvs::ARRAY_INTO_ITERATOR)
             {
                 return false;
             }
 
-            let predicate = EarlyBinder::bind(predicate).subst(cx.tcx, &substs_with_referent_ty);
+            let predicate = EarlyBinder::bind(predicate).instantiate(cx.tcx, &args_with_referent_ty);
             let obligation = Obligation::new(cx.tcx, ObligationCause::dummy(), cx.param_env, predicate);
             let infcx = cx.tcx.infer_ctxt().build();
             infcx.predicate_must_hold_modulo_regions(&obligation)
         })
     };
 
-    let mut needless_borrow = false;
+    let mut count = 0;
     while let ExprKind::AddrOf(_, _, referent) = expr.kind {
         if !check_reference_and_referent(expr, referent) {
             break;
         }
         expr = referent;
-        needless_borrow = true;
-    }
-
-    if needless_borrow {
-        Position::ImplArg(expr.hir_id)
-    } else {
-        Position::Other(precedence)
+        count += 1;
     }
+    count
 }
 
 fn has_ref_mut_self_method(cx: &LateContext<'_>, trait_def_id: DefId) -> bool {
@@ -1260,7 +1116,12 @@ fn has_ref_mut_self_method(cx: &LateContext<'_>, trait_def_id: DefId) -> bool {
         .in_definition_order()
         .any(|assoc_item| {
             if assoc_item.fn_has_self_parameter {
-                let self_ty = cx.tcx.fn_sig(assoc_item.def_id).subst_identity().skip_binder().inputs()[0];
+                let self_ty = cx
+                    .tcx
+                    .fn_sig(assoc_item.def_id)
+                    .instantiate_identity()
+                    .skip_binder()
+                    .inputs()[0];
                 matches!(self_ty.kind(), ty::Ref(_, _, Mutability::Mut))
             } else {
                 false
@@ -1331,7 +1192,7 @@ fn referent_used_exactly_once<'tcx>(
     }
 }
 
-// Iteratively replaces `param_ty` with `new_ty` in `substs`, and similarly for each resulting
+// Iteratively replaces `param_ty` with `new_ty` in `args`, and similarly for each resulting
 // projected type that is a type parameter. Returns `false` if replacing the types would have an
 // effect on the function signature beyond substituting `new_ty` for `param_ty`.
 // See: https://github.com/rust-lang/rust-clippy/pull/9136#discussion_r927212757
@@ -1342,11 +1203,11 @@ fn replace_types<'tcx>(
     fn_sig: FnSig<'tcx>,
     arg_index: usize,
     projection_predicates: &[ProjectionPredicate<'tcx>],
-    substs: &mut [ty::GenericArg<'tcx>],
+    args: &mut [ty::GenericArg<'tcx>],
 ) -> bool {
-    let mut replaced = BitSet::new_empty(substs.len());
+    let mut replaced = BitSet::new_empty(args.len());
 
-    let mut deque = VecDeque::with_capacity(substs.len());
+    let mut deque = VecDeque::with_capacity(args.len());
     deque.push_back((param_ty, new_ty));
 
     while let Some((param_ty, new_ty)) = deque.pop_front() {
@@ -1360,7 +1221,7 @@ fn replace_types<'tcx>(
             return false;
         }
 
-        substs[param_ty.index as usize] = ty::GenericArg::from(new_ty);
+        args[param_ty.index as usize] = ty::GenericArg::from(new_ty);
 
         // The `replaced.insert(...)` check provides some protection against infinite loops.
         if replaced.insert(param_ty.index) {
@@ -1375,7 +1236,7 @@ fn replace_types<'tcx>(
                     ));
 
                     if let Ok(projected_ty) = cx.tcx.try_normalize_erasing_regions(cx.param_env, projection)
-                        && substs[term_param_ty.index as usize] != ty::GenericArg::from(projected_ty)
+                        && args[term_param_ty.index as usize] != ty::GenericArg::from(projected_ty)
                     {
                         deque.push_back((*term_param_ty, projected_ty));
                     }
@@ -1387,95 +1248,6 @@ fn replace_types<'tcx>(
     true
 }
 
-struct TyPosition<'tcx> {
-    position: Position,
-    ty: Option<Ty<'tcx>>,
-}
-impl From<Position> for TyPosition<'_> {
-    fn from(position: Position) -> Self {
-        Self { position, ty: None }
-    }
-}
-impl<'tcx> TyPosition<'tcx> {
-    fn new_deref_stable_for_result(precedence: i8, ty: Ty<'tcx>) -> Self {
-        Self {
-            position: Position::ReborrowStable(precedence),
-            ty: Some(ty),
-        }
-    }
-    fn position_for_result(self, cx: &LateContext<'tcx>) -> Position {
-        match (self.position, self.ty) {
-            (Position::ReborrowStable(precedence), Some(ty)) => {
-                Position::DerefStable(precedence, ty.is_sized(cx.tcx, cx.param_env))
-            },
-            (position, _) => position,
-        }
-    }
-    fn position_for_arg(self) -> Position {
-        self.position
-    }
-}
-
-// Checks whether a type is stable when switching to auto dereferencing,
-fn ty_auto_deref_stability<'tcx>(
-    tcx: TyCtxt<'tcx>,
-    param_env: ParamEnv<'tcx>,
-    ty: Ty<'tcx>,
-    precedence: i8,
-) -> TyPosition<'tcx> {
-    let ty::Ref(_, mut ty, _) = *ty.kind() else {
-        return Position::Other(precedence).into();
-    };
-
-    ty = tcx.try_normalize_erasing_regions(param_env, ty).unwrap_or(ty);
-
-    loop {
-        break match *ty.kind() {
-            ty::Ref(_, ref_ty, _) => {
-                ty = ref_ty;
-                continue;
-            },
-            ty::Param(_) => TyPosition::new_deref_stable_for_result(precedence, ty),
-            ty::Alias(ty::Weak, _) => unreachable!("should have been normalized away above"),
-            ty::Alias(ty::Inherent, _) => unreachable!("inherent projection should have been normalized away above"),
-            ty::Alias(ty::Projection, _) if ty.has_non_region_param() => {
-                TyPosition::new_deref_stable_for_result(precedence, ty)
-            },
-            ty::Infer(_)
-            | ty::Error(_)
-            | ty::Bound(..)
-            | ty::Alias(ty::Opaque, ..)
-            | ty::Placeholder(_)
-            | ty::Dynamic(..) => Position::ReborrowStable(precedence).into(),
-            ty::Adt(..) if ty.has_placeholders() || ty.has_opaque_types() => {
-                Position::ReborrowStable(precedence).into()
-            },
-            ty::Adt(_, substs) if substs.has_non_region_param() => {
-                TyPosition::new_deref_stable_for_result(precedence, ty)
-            },
-            ty::Bool
-            | ty::Char
-            | ty::Int(_)
-            | ty::Uint(_)
-            | ty::Array(..)
-            | ty::Float(_)
-            | ty::RawPtr(..)
-            | ty::FnPtr(_) => Position::DerefStable(precedence, true).into(),
-            ty::Str | ty::Slice(..) => Position::DerefStable(precedence, false).into(),
-            ty::Adt(..)
-            | ty::Foreign(_)
-            | ty::FnDef(..)
-            | ty::Generator(..)
-            | ty::GeneratorWitness(..)
-            | ty::GeneratorWitnessMIR(..)
-            | ty::Closure(..)
-            | ty::Never
-            | ty::Tuple(_)
-            | ty::Alias(ty::Projection, _) => Position::DerefStable(precedence, ty.is_sized(tcx, param_env)).into(),
-        };
-    }
-}
-
 fn ty_contains_field(ty: Ty<'_>, name: Symbol) -> bool {
     if let ty::Adt(adt, _) = *ty.kind() {
         adt.is_struct() && adt.all_fields().any(|f| f.name == name)
@@ -1485,12 +1257,12 @@ fn ty_contains_field(ty: Ty<'_>, name: Symbol) -> bool {
 }
 
 #[expect(clippy::needless_pass_by_value, clippy::too_many_lines)]
-fn report<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, state: State, data: StateData) {
+fn report<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, state: State, data: StateData<'tcx>) {
     match state {
         State::DerefMethod {
             ty_changed_count,
-            is_final_ufcs,
-            target_mut,
+            is_ufcs,
+            mutbl,
         } => {
             let mut app = Applicability::MachineApplicable;
             let (expr_str, _expr_is_macro_call) = snippet_with_context(cx, expr.span, data.span.ctxt(), "..", &mut app);
@@ -1505,12 +1277,12 @@ fn report<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, state: State, data
             };
             let addr_of_str = if ty_changed_count < ref_count {
                 // Check if a reborrow from &mut T -> &T is required.
-                if target_mut == Mutability::Not && matches!(ty.kind(), ty::Ref(_, _, Mutability::Mut)) {
+                if mutbl == Mutability::Not && matches!(ty.kind(), ty::Ref(_, _, Mutability::Mut)) {
                     "&*"
                 } else {
                     ""
                 }
-            } else if target_mut == Mutability::Mut {
+            } else if mutbl == Mutability::Mut {
                 "&mut "
             } else {
                 "&"
@@ -1527,7 +1299,7 @@ fn report<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, state: State, data
             */
 
             // Fix #10850, do not lint if it's `Foo::deref` instead of `foo.deref()`.
-            if is_final_ufcs {
+            if is_ufcs {
                 return;
             }
 
@@ -1535,7 +1307,7 @@ fn report<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, state: State, data
                 cx,
                 EXPLICIT_DEREF_METHODS,
                 data.span,
-                match target_mut {
+                match mutbl {
                     Mutability::Not => "explicit `deref` method call",
                     Mutability::Mut => "explicit `deref_mut` method call",
                 },
@@ -1546,13 +1318,19 @@ fn report<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, state: State, data
         },
         State::DerefedBorrow(state) => {
             let mut app = Applicability::MachineApplicable;
-            let snip_expr = state.snip_expr.map_or(expr, |hir_id| cx.tcx.hir().expect_expr(hir_id));
-            let (snip, snip_is_macro) = snippet_with_context(cx, snip_expr.span, data.span.ctxt(), "..", &mut app);
+            let (snip, snip_is_macro) = snippet_with_context(cx, expr.span, data.span.ctxt(), "..", &mut app);
             span_lint_hir_and_then(cx, NEEDLESS_BORROW, data.hir_id, data.span, state.msg, |diag| {
-                let calls_field = matches!(expr.kind, ExprKind::Field(..)) && matches!(data.position, Position::Callee);
+                let (precedence, calls_field) = match get_parent_node(cx.tcx, data.hir_id) {
+                    Some(Node::Expr(e)) => match e.kind {
+                        ExprKind::Call(callee, _) if callee.hir_id != data.hir_id => (0, false),
+                        ExprKind::Call(..) => (PREC_POSTFIX, matches!(expr.kind, ExprKind::Field(..))),
+                        _ => (e.precedence().order(), false),
+                    },
+                    _ => (0, false),
+                };
                 let sugg = if !snip_is_macro
+                    && (calls_field || expr.precedence().order() < precedence)
                     && !has_enclosing_paren(&snip)
-                    && (expr.precedence().order() < data.position.precedence() || calls_field)
                 {
                     format!("({snip})")
                 } else {
@@ -1569,7 +1347,8 @@ fn report<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, state: State, data
                     | ExprKind::If(..)
                     | ExprKind::Loop(..)
                     | ExprKind::Match(..)
-            ) && matches!(data.position, Position::DerefStable(_, true))
+            ) && let ty::Ref(_, ty, _) = data.adjusted_ty.kind()
+                && ty.is_sized(cx.tcx, cx.param_env)
             {
                 // Rustc bug: auto deref doesn't work on block expression when targeting sized types.
                 return;
@@ -1582,9 +1361,9 @@ fn report<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, state: State, data
                     Mutability::Not => "&",
                     Mutability::Mut => "&mut ",
                 };
-                (prefix, 0)
+                (prefix, PREC_PREFIX)
             } else {
-                ("", data.position.precedence())
+                ("", 0)
             };
             span_lint_hir_and_then(
                 cx,
@@ -1613,7 +1392,7 @@ fn report<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, state: State, data
                     | ExprKind::If(..)
                     | ExprKind::Loop(..)
                     | ExprKind::Match(..)
-            ) && matches!(data.position, Position::DerefStable(_, true))
+            ) && data.adjusted_ty.is_sized(cx.tcx, cx.param_env)
             {
                 // Rustc bug: auto deref doesn't work on block expression when targeting sized types.
                 return;
diff --git a/clippy_lints/src/derivable_impls.rs b/clippy_lints/src/derivable_impls.rs
index 7b0489112e6..9a85cc4ce2d 100644
--- a/clippy_lints/src/derivable_impls.rs
+++ b/clippy_lints/src/derivable_impls.rs
@@ -9,7 +9,7 @@ use rustc_hir::{
 };
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_middle::ty::adjustment::{Adjust, PointerCoercion};
-use rustc_middle::ty::{self, Adt, AdtDef, SubstsRef, Ty, TypeckResults};
+use rustc_middle::ty::{self, Adt, AdtDef, GenericArgsRef, Ty, TypeckResults};
 use rustc_session::{declare_tool_lint, impl_lint_pass};
 use rustc_span::sym;
 
@@ -79,7 +79,7 @@ fn is_path_self(e: &Expr<'_>) -> bool {
 fn contains_trait_object(ty: Ty<'_>) -> bool {
     match ty.kind() {
         ty::Ref(_, ty, _) => contains_trait_object(*ty),
-        ty::Adt(def, substs) => def.is_box() && substs[0].as_type().map_or(false, contains_trait_object),
+        ty::Adt(def, args) => def.is_box() && args[0].as_type().map_or(false, contains_trait_object),
         ty::Dynamic(..) => true,
         _ => false,
     }
@@ -91,18 +91,19 @@ fn check_struct<'tcx>(
     self_ty: &hir::Ty<'_>,
     func_expr: &Expr<'_>,
     adt_def: AdtDef<'_>,
-    substs: SubstsRef<'_>,
+    ty_args: GenericArgsRef<'_>,
     typeck_results: &'tcx TypeckResults<'tcx>,
 ) {
     if let TyKind::Path(QPath::Resolved(_, p)) = self_ty.kind {
         if let Some(PathSegment { args, .. }) = p.segments.last() {
             let args = args.map(|a| a.args).unwrap_or(&[]);
 
-            // substs contains the generic parameters of the type declaration, while args contains the arguments
-            // used at instantiation time. If both len are not equal, it means that some parameters were not
-            // provided (which means that the default values were used); in this case we will not risk
-            // suggesting too broad a rewrite. We won't either if any argument is a type or a const.
-            if substs.len() != args.len() || args.iter().any(|arg| !matches!(arg, GenericArg::Lifetime(_))) {
+            // ty_args contains the generic parameters of the type declaration, while args contains the
+            // arguments used at instantiation time. If both len are not equal, it means that some
+            // parameters were not provided (which means that the default values were used); in this
+            // case we will not risk suggesting too broad a rewrite. We won't either if any argument
+            // is a type or a const.
+            if ty_args.len() != args.len() || args.iter().any(|arg| !matches!(arg, GenericArg::Lifetime(_))) {
                 return;
             }
         }
@@ -213,7 +214,7 @@ impl<'tcx> LateLintPass<'tcx> for DerivableImpls {
             if let Some(Node::ImplItem(impl_item)) = cx.tcx.hir().find(impl_item_hir);
             if let ImplItemKind::Fn(_, b) = &impl_item.kind;
             if let Body { value: func_expr, .. } = cx.tcx.hir().body(*b);
-            if let &Adt(adt_def, substs) = cx.tcx.type_of(item.owner_id).subst_identity().kind();
+            if let &Adt(adt_def, args) = cx.tcx.type_of(item.owner_id).instantiate_identity().kind();
             if let attrs = cx.tcx.hir().attrs(item.hir_id());
             if !attrs.iter().any(|attr| attr.doc_str().is_some());
             if let child_attrs = cx.tcx.hir().attrs(impl_item_hir);
@@ -221,7 +222,7 @@ impl<'tcx> LateLintPass<'tcx> for DerivableImpls {
 
             then {
                 if adt_def.is_struct() {
-                    check_struct(cx, item, self_ty, func_expr, adt_def, substs, cx.tcx.typeck_body(*b));
+                    check_struct(cx, item, self_ty, func_expr, adt_def, args, cx.tcx.typeck_body(*b));
                 } else if adt_def.is_enum() && self.msrv.meets(msrvs::DEFAULT_ENUM_ATTRIBUTE) {
                     check_enum(cx, item, func_expr, adt_def);
                 }
diff --git a/clippy_lints/src/derive.rs b/clippy_lints/src/derive.rs
index 496ab0dcb1d..ad7b3b27383 100644
--- a/clippy_lints/src/derive.rs
+++ b/clippy_lints/src/derive.rs
@@ -210,7 +210,7 @@ impl<'tcx> LateLintPass<'tcx> for Derive {
             ..
         }) = item.kind
         {
-            let ty = cx.tcx.type_of(item.owner_id).subst_identity();
+            let ty = cx.tcx.type_of(item.owner_id).instantiate_identity();
             let is_automatically_derived = cx.tcx.has_attr(item.owner_id, sym::automatically_derived);
 
             check_hash_peq(cx, item.span, trait_ref, ty, is_automatically_derived);
@@ -251,7 +251,7 @@ fn check_hash_peq<'tcx>(
 
                 // Only care about `impl PartialEq<Foo> for Foo`
                 // For `impl PartialEq<B> for A, input_types is [A, B]
-                if trait_ref.subst_identity().substs.type_at(1) == ty {
+                if trait_ref.instantiate_identity().args.type_at(1) == ty {
                     span_lint_and_then(
                         cx,
                         DERIVED_HASH_WITH_MANUAL_EQ,
@@ -299,7 +299,7 @@ fn check_ord_partial_ord<'tcx>(
 
                 // Only care about `impl PartialOrd<Foo> for Foo`
                 // For `impl PartialOrd<B> for A, input_types is [A, B]
-                if trait_ref.subst_identity().substs.type_at(1) == ty {
+                if trait_ref.instantiate_identity().args.type_at(1) == ty {
                     let mess = if partial_ord_is_automatically_derived {
                         "you are implementing `Ord` explicitly but have derived `PartialOrd`"
                     } else {
@@ -346,9 +346,9 @@ fn check_copy_clone<'tcx>(cx: &LateContext<'tcx>, item: &Item<'_>, trait_ref: &h
     if !is_copy(cx, ty) {
         if ty_subs.non_erasable_generics().next().is_some() {
             let has_copy_impl = cx.tcx.all_local_trait_impls(()).get(&copy_id).map_or(false, |impls| {
-                impls.iter().any(|&id| {
-                    matches!(cx.tcx.type_of(id).subst_identity().kind(), ty::Adt(adt, _) if ty_adt.did() == adt.did())
-                })
+                impls
+                    .iter()
+                    .any(|&id| matches!(cx.tcx.type_of(id).instantiate_identity().kind(), ty::Adt(adt, _) if ty_adt.did() == adt.did()))
             });
             if !has_copy_impl {
                 return;
@@ -465,18 +465,18 @@ impl<'tcx> Visitor<'tcx> for UnsafeVisitor<'_, 'tcx> {
 /// Implementation of the `DERIVE_PARTIAL_EQ_WITHOUT_EQ` lint.
 fn check_partial_eq_without_eq<'tcx>(cx: &LateContext<'tcx>, span: Span, trait_ref: &hir::TraitRef<'_>, ty: Ty<'tcx>) {
     if_chain! {
-        if let ty::Adt(adt, substs) = ty.kind();
+        if let ty::Adt(adt, args) = ty.kind();
         if cx.tcx.visibility(adt.did()).is_public();
         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);
         let param_env = param_env_for_derived_eq(cx.tcx, adt.did(), eq_trait_def_id);
-        if !implements_trait_with_env(cx.tcx, param_env, ty, eq_trait_def_id, []);
+        if !implements_trait_with_env(cx.tcx, param_env, ty, eq_trait_def_id, &[]);
         // If all of our fields implement `Eq`, we can implement `Eq` too
         if adt
             .all_fields()
-            .map(|f| f.ty(cx.tcx, substs))
-            .all(|ty| implements_trait_with_env(cx.tcx, param_env, ty, eq_trait_def_id, []));
+            .map(|f| f.ty(cx.tcx, args))
+            .all(|ty| implements_trait_with_env(cx.tcx, param_env, ty, eq_trait_def_id, &[]));
         then {
             span_lint_and_sugg(
                 cx,
diff --git a/clippy_lints/src/doc.rs b/clippy_lints/src/doc.rs
index e5f39d102cd..00f70e586f4 100644
--- a/clippy_lints/src/doc.rs
+++ b/clippy_lints/src/doc.rs
@@ -729,7 +729,7 @@ fn check_code(cx: &LateContext<'_>, text: &str, edition: Edition, span: Span) {
                     false,
                     TerminalUrl::No,
                 );
-                let handler = Handler::with_emitter(false, None, Box::new(emitter));
+                let handler = Handler::with_emitter(Box::new(emitter)).disable_warnings();
                 let sess = ParseSess::with_span_handler(handler, sm);
 
                 let mut parser = match maybe_new_parser_from_source_str(&sess, filename, code) {
diff --git a/clippy_lints/src/empty_enum.rs b/clippy_lints/src/empty_enum.rs
index d94664daa56..1701d061128 100644
--- a/clippy_lints/src/empty_enum.rs
+++ b/clippy_lints/src/empty_enum.rs
@@ -49,7 +49,7 @@ impl<'tcx> LateLintPass<'tcx> for EmptyEnum {
         }
 
         if let ItemKind::Enum(..) = item.kind {
-            let ty = cx.tcx.type_of(item.owner_id).subst_identity();
+            let ty = cx.tcx.type_of(item.owner_id).instantiate_identity();
             let adt = ty.ty_adt_def().expect("already checked whether this is an enum");
             if adt.variants().is_empty() {
                 span_lint_and_help(
diff --git a/clippy_lints/src/enum_clike.rs b/clippy_lints/src/enum_clike.rs
index d85650712db..96c5c7fc509 100644
--- a/clippy_lints/src/enum_clike.rs
+++ b/clippy_lints/src/enum_clike.rs
@@ -45,7 +45,7 @@ impl<'tcx> LateLintPass<'tcx> for UnportableVariant {
             for var in def.variants {
                 if let Some(anon_const) = &var.disr_expr {
                     let def_id = cx.tcx.hir().body_owner_def_id(anon_const.body);
-                    let mut ty = cx.tcx.type_of(def_id.to_def_id()).subst_identity();
+                    let mut ty = cx.tcx.type_of(def_id.to_def_id()).instantiate_identity();
                     let constant = cx
                         .tcx
                         .const_eval_poly(def_id.to_def_id())
diff --git a/clippy_lints/src/error_impl_error.rs b/clippy_lints/src/error_impl_error.rs
new file mode 100644
index 00000000000..379af9b2234
--- /dev/null
+++ b/clippy_lints/src/error_impl_error.rs
@@ -0,0 +1,87 @@
+use clippy_utils::diagnostics::{span_lint, span_lint_hir_and_then};
+use clippy_utils::path_res;
+use clippy_utils::ty::implements_trait;
+use rustc_hir::def_id::{DefId, LocalDefId};
+use rustc_hir::{Item, ItemKind};
+use rustc_hir_analysis::hir_ty_to_ty;
+use rustc_lint::{LateContext, LateLintPass};
+use rustc_middle::ty::Visibility;
+use rustc_session::{declare_lint_pass, declare_tool_lint};
+use rustc_span::sym;
+
+declare_clippy_lint! {
+    /// ### What it does
+    /// Checks for types named `Error` that implement `Error`.
+    ///
+    /// ### Why is this bad?
+    /// It can become confusing when a codebase has 20 types all named `Error`, requiring either
+    /// aliasing them in the `use` statement or qualifying them like `my_module::Error`. This
+    /// hinders comprehension, as it requires you to memorize every variation of importing `Error`
+    /// used across a codebase.
+    ///
+    /// ### Example
+    /// ```rust,ignore
+    /// #[derive(Debug)]
+    /// pub enum Error { ... }
+    ///
+    /// impl std::fmt::Display for Error { ... }
+    ///
+    /// impl std::error::Error for Error { ... }
+    /// ```
+    #[clippy::version = "1.72.0"]
+    pub ERROR_IMPL_ERROR,
+    restriction,
+    "exported types named `Error` that implement `Error`"
+}
+declare_lint_pass!(ErrorImplError => [ERROR_IMPL_ERROR]);
+
+impl<'tcx> LateLintPass<'tcx> for ErrorImplError {
+    fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'tcx>) {
+        let Some(error_def_id) = cx.tcx.get_diagnostic_item(sym::Error) else {
+            return;
+        };
+
+        match item.kind {
+            ItemKind::TyAlias(ty, _) if implements_trait(cx, hir_ty_to_ty(cx.tcx, ty), error_def_id, &[])
+                && item.ident.name == sym::Error
+                && is_visible_outside_module(cx, item.owner_id.def_id) =>
+            {
+                span_lint(
+                    cx,
+                    ERROR_IMPL_ERROR,
+                    item.ident.span,
+                    "exported type alias named `Error` that implements `Error`",
+                );
+            },
+            ItemKind::Impl(imp) if let Some(trait_def_id) = imp.of_trait.and_then(|t| t.trait_def_id())
+                && error_def_id == trait_def_id
+                && let Some(def_id) = path_res(cx, imp.self_ty).opt_def_id().and_then(DefId::as_local)
+                && let hir_id = cx.tcx.hir().local_def_id_to_hir_id(def_id)
+                && let Some(ident) = cx.tcx.opt_item_ident(def_id.to_def_id())
+                && ident.name == sym::Error
+                && is_visible_outside_module(cx, def_id) =>
+            {
+                span_lint_hir_and_then(
+                    cx,
+                    ERROR_IMPL_ERROR,
+                    hir_id,
+                    ident.span,
+                    "exported type named `Error` that implements `Error`",
+                    |diag| {
+                        diag.span_note(item.span, "`Error` was implemented here");
+                    }
+                );
+            }
+            _ => {},
+        }
+    }
+}
+
+/// Do not lint private `Error`s, i.e., ones without any `pub` (minus `pub(self)` of course) and
+/// which aren't reexported
+fn is_visible_outside_module(cx: &LateContext<'_>, def_id: LocalDefId) -> bool {
+    !matches!(
+        cx.tcx.visibility(def_id),
+        Visibility::Restricted(mod_def_id) if cx.tcx.parent_module_from_def_id(def_id).to_def_id() == mod_def_id
+    )
+}
diff --git a/clippy_lints/src/eta_reduction.rs b/clippy_lints/src/eta_reduction.rs
index 58e62d1f3d3..8d6fb8438b6 100644
--- a/clippy_lints/src/eta_reduction.rs
+++ b/clippy_lints/src/eta_reduction.rs
@@ -1,19 +1,22 @@
 use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_and_then};
 use clippy_utils::higher::VecArgs;
 use clippy_utils::source::snippet_opt;
-use clippy_utils::ty::{implements_trait, is_type_diagnostic_item};
-use clippy_utils::usage::local_used_after_expr;
+use clippy_utils::ty::type_diagnostic_name;
+use clippy_utils::usage::{local_used_after_expr, local_used_in};
 use clippy_utils::{higher, is_adjusted, path_to_local, path_to_local_id};
-use if_chain::if_chain;
 use rustc_errors::Applicability;
 use rustc_hir::def_id::DefId;
-use rustc_hir::{Closure, Expr, ExprKind, Param, PatKind, Unsafety};
+use rustc_hir::{BindingAnnotation, Expr, ExprKind, FnRetTy, Param, PatKind, QPath, TyKind, Unsafety};
+use rustc_infer::infer::TyCtxtInferExt;
 use rustc_lint::{LateContext, LateLintPass};
-use rustc_middle::ty::adjustment::{Adjust, Adjustment, AutoBorrow};
-use rustc_middle::ty::binding::BindingMode;
-use rustc_middle::ty::{self, EarlyBinder, SubstsRef, Ty, TypeVisitableExt};
+use rustc_middle::ty::{
+    self, Binder, BoundConstness, ClosureArgs, ClosureKind, EarlyBinder, FnSig, GenericArg, GenericArgKind,
+    GenericArgsRef, ImplPolarity, List, Region, RegionKind, Ty, TypeVisitableExt, TypeckResults,
+};
 use rustc_session::{declare_lint_pass, declare_tool_lint};
 use rustc_span::symbol::sym;
+use rustc_target::spec::abi::Abi;
+use rustc_trait_selection::traits::error_reporting::InferCtxtExt as _;
 
 declare_clippy_lint! {
     /// ### What it does
@@ -72,14 +75,18 @@ declare_clippy_lint! {
 declare_lint_pass!(EtaReduction => [REDUNDANT_CLOSURE, REDUNDANT_CLOSURE_FOR_METHOD_CALLS]);
 
 impl<'tcx> LateLintPass<'tcx> for EtaReduction {
+    #[allow(clippy::too_many_lines)]
     fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
-        if expr.span.from_expansion() {
+        let body = if let ExprKind::Closure(c) = expr.kind
+            && c.fn_decl.inputs.iter().all(|ty| matches!(ty.kind, TyKind::Infer))
+            && matches!(c.fn_decl.output, FnRetTy::DefaultReturn(_))
+            && !expr.span.from_expansion()
+        {
+            cx.tcx.hir().body(c.body)
+        } else {
             return;
-        }
-        let body = match expr.kind {
-            ExprKind::Closure(&Closure { body, .. }) => cx.tcx.hir().body(body),
-            _ => return,
         };
+
         if body.value.span.from_expansion() {
             if body.params.is_empty() {
                 if let Some(VecArgs::Vec(&[])) = higher::VecArgs::hir(cx, body.value) {
@@ -99,149 +106,218 @@ impl<'tcx> LateLintPass<'tcx> for EtaReduction {
             return;
         }
 
-        let closure_ty = cx.typeck_results().expr_ty(expr);
+        let typeck = cx.typeck_results();
+        let closure = if let ty::Closure(_, closure_subs) = typeck.expr_ty(expr).kind() {
+            closure_subs.as_closure()
+        } else {
+            return;
+        };
 
-        if_chain!(
-            if !is_adjusted(cx, body.value);
-            if let ExprKind::Call(callee, args) = body.value.kind;
-            if let ExprKind::Path(_) = callee.kind;
-            if check_inputs(cx, body.params, None, args);
-            let callee_ty = cx.typeck_results().expr_ty_adjusted(callee);
-            let call_ty = cx.typeck_results().type_dependent_def_id(body.value.hir_id)
-                .map_or(callee_ty, |id| cx.tcx.type_of(id).subst_identity());
-            if check_sig(cx, closure_ty, call_ty);
-            let substs = cx.typeck_results().node_substs(callee.hir_id);
-            // This fixes some false positives that I don't entirely understand
-            if substs.is_empty() || !cx.typeck_results().expr_ty(expr).has_late_bound_regions();
-            // A type param function ref like `T::f` is not 'static, however
-            // it is if cast like `T::f as fn()`. This seems like a rustc bug.
-            if !substs.types().any(|t| matches!(t.kind(), ty::Param(_)));
-            let callee_ty_unadjusted = cx.typeck_results().expr_ty(callee).peel_refs();
-            if !is_type_diagnostic_item(cx, callee_ty_unadjusted, sym::Arc);
-            if !is_type_diagnostic_item(cx, callee_ty_unadjusted, sym::Rc);
-            if let ty::Closure(_, substs) = *closure_ty.kind();
-            // Don't lint if this is an inclusive range expression.
-            // They desugar to a call to `RangeInclusiveNew` which would have odd suggestions. (#10684)
-            if !matches!(higher::Range::hir(body.value), Some(higher::Range {
-                start: Some(_),
-                end: Some(_),
-                limits: rustc_ast::RangeLimits::Closed
-            }));
-            then {
-                span_lint_and_then(cx, REDUNDANT_CLOSURE, expr.span, "redundant closure", |diag| {
-                    if let Some(mut snippet) = snippet_opt(cx, callee.span) {
-                        if let Some(fn_mut_id) = cx.tcx.lang_items().fn_mut_trait()
-                            && let args = cx.tcx.erase_late_bound_regions(substs.as_closure().sig()).inputs()
-                            && implements_trait(
-                                   cx,
-                                   callee_ty.peel_refs(),
-                                   fn_mut_id,
-                                   &args.iter().copied().map(Into::into).collect::<Vec<_>>(),
-                               )
-                            && path_to_local(callee).map_or(false, |l| local_used_after_expr(cx, l, expr))
-                        {
-                                // Mutable closure is used after current expr; we cannot consume it.
-                                snippet = format!("&mut {snippet}");
-                        }
+        if is_adjusted(cx, body.value) {
+            return;
+        }
 
-                        diag.span_suggestion(
-                            expr.span,
-                            "replace the closure with the function itself",
-                            snippet,
-                            Applicability::MachineApplicable,
-                        );
-                    }
-                });
-            }
-        );
+        match body.value.kind {
+            ExprKind::Call(callee, args)
+                if matches!(callee.kind, ExprKind::Path(QPath::Resolved(..) | QPath::TypeRelative(..))) =>
+            {
+                let callee_ty = typeck.expr_ty(callee).peel_refs();
+                if matches!(
+                    type_diagnostic_name(cx, callee_ty),
+                    Some(sym::Arc | sym::Rc)
+                ) || !check_inputs(typeck, body.params, None, args) {
+                    return;
+                }
+                let callee_ty_adjusted = typeck.expr_adjustments(callee).last().map_or(
+                    callee_ty,
+                    |a| a.target.peel_refs(),
+                );
 
-        if_chain!(
-            if !is_adjusted(cx, body.value);
-            if let ExprKind::MethodCall(path, receiver, args, _) = body.value.kind;
-            if check_inputs(cx, body.params, Some(receiver), args);
-            let method_def_id = cx.typeck_results().type_dependent_def_id(body.value.hir_id).unwrap();
-            let substs = cx.typeck_results().node_substs(body.value.hir_id);
-            let call_ty = cx.tcx.type_of(method_def_id).subst(cx.tcx, substs);
-            if check_sig(cx, closure_ty, call_ty);
-            then {
-                span_lint_and_then(cx, REDUNDANT_CLOSURE_FOR_METHOD_CALLS, expr.span, "redundant closure", |diag| {
-                    let name = get_ufcs_type_name(cx, method_def_id, substs);
-                    diag.span_suggestion(
+                let sig = match callee_ty_adjusted.kind() {
+                    ty::FnDef(def, _) => cx.tcx.fn_sig(def).skip_binder().skip_binder(),
+                    ty::FnPtr(sig) => sig.skip_binder(),
+                    ty::Closure(_, subs) => cx
+                        .tcx
+                        .signature_unclosure(subs.as_closure().sig(), Unsafety::Normal)
+                        .skip_binder(),
+                    _ => {
+                        if typeck.type_dependent_def_id(body.value.hir_id).is_some()
+                            && let subs = typeck.node_args(body.value.hir_id)
+                            && let output = typeck.expr_ty(body.value)
+                            && let ty::Tuple(tys) = *subs.type_at(1).kind()
+                        {
+                            cx.tcx.mk_fn_sig(tys, output, false, Unsafety::Normal, Abi::Rust)
+                        } else {
+                            return;
+                        }
+                    },
+                };
+                if check_sig(cx, closure, sig)
+                    && let generic_args = typeck.node_args(callee.hir_id)
+                    // Given some trait fn `fn f() -> ()` and some type `T: Trait`, `T::f` is not
+                    // `'static` unless `T: 'static`. The cast `T::f as fn()` will, however, result
+                    // in a type which is `'static`.
+                    // For now ignore all callee types which reference a type parameter.
+                    && !generic_args.types().any(|t| matches!(t.kind(), ty::Param(_)))
+                {
+                    span_lint_and_then(
+                        cx,
+                        REDUNDANT_CLOSURE,
                         expr.span,
-                        "replace the closure with the method itself",
-                        format!("{name}::{}", path.ident.name),
-                        Applicability::MachineApplicable,
+                        "redundant closure",
+                        |diag| {
+                            if let Some(mut snippet) = snippet_opt(cx, callee.span) {
+                                if let Ok((ClosureKind::FnMut, _))
+                                    = cx.tcx.infer_ctxt().build().type_implements_fn_trait(
+                                        cx.param_env,
+                                        Binder::bind_with_vars(callee_ty_adjusted, List::empty()),
+                                        BoundConstness::NotConst,
+                                        ImplPolarity::Positive,
+                                    ) && path_to_local(callee)
+                                        .map_or(
+                                            false,
+                                            |l| local_used_in(cx, l, args) || local_used_after_expr(cx, l, expr),
+                                        )
+                                {
+                                    // Mutable closure is used after current expr; we cannot consume it.
+                                    snippet = format!("&mut {snippet}");
+                                }
+                                diag.span_suggestion(
+                                    expr.span,
+                                    "replace the closure with the function itself",
+                                    snippet,
+                                    Applicability::MachineApplicable,
+                                );
+                            }
+                        }
                     );
-                })
-            }
-        );
+                }
+            },
+            ExprKind::MethodCall(path, self_, args, _) if check_inputs(typeck, body.params, Some(self_), args) => {
+                if let Some(method_def_id) = typeck.type_dependent_def_id(body.value.hir_id)
+                    && check_sig(cx, closure, cx.tcx.fn_sig(method_def_id).skip_binder().skip_binder())
+                {
+                    span_lint_and_then(
+                        cx,
+                        REDUNDANT_CLOSURE_FOR_METHOD_CALLS,
+                        expr.span,
+                        "redundant closure",
+                        |diag| {
+                            let args = typeck.node_args(body.value.hir_id);
+                            let name = get_ufcs_type_name(cx, method_def_id, args);
+                            diag.span_suggestion(
+                                expr.span,
+                                "replace the closure with the method itself",
+                                format!("{}::{}", name, path.ident.name),
+                                Applicability::MachineApplicable,
+                            );
+                        },
+                    );
+                }
+            },
+            _ => (),
+        }
     }
 }
 
 fn check_inputs(
-    cx: &LateContext<'_>,
+    typeck: &TypeckResults<'_>,
     params: &[Param<'_>],
-    receiver: Option<&Expr<'_>>,
-    call_args: &[Expr<'_>],
+    self_arg: Option<&Expr<'_>>,
+    args: &[Expr<'_>],
 ) -> bool {
-    if receiver.map_or(params.len() != call_args.len(), |_| params.len() != call_args.len() + 1) {
-        return false;
+    params.len() == self_arg.map_or(0, |_| 1) + args.len()
+        && params.iter().zip(self_arg.into_iter().chain(args)).all(|(p, arg)| {
+            matches!(
+                p.pat.kind,PatKind::Binding(BindingAnnotation::NONE, id, _, None)
+                if path_to_local_id(arg, id)
+            )
+            // Only allow adjustments which change regions (i.e. re-borrowing).
+            && typeck
+                .expr_adjustments(arg)
+                .last()
+                .map_or(true, |a| a.target == typeck.expr_ty(arg))
+        })
+}
+
+fn check_sig<'tcx>(cx: &LateContext<'tcx>, closure: ClosureArgs<'tcx>, call_sig: FnSig<'_>) -> bool {
+    call_sig.unsafety == Unsafety::Normal
+        && !has_late_bound_to_non_late_bound_regions(
+            cx.tcx
+                .signature_unclosure(closure.sig(), Unsafety::Normal)
+                .skip_binder(),
+            call_sig,
+        )
+}
+
+/// This walks through both signatures and checks for any time a late-bound region is expected by an
+/// `impl Fn` type, but the target signature does not have a late-bound region in the same position.
+///
+/// This is needed because rustc is unable to late bind early-bound regions in a function signature.
+fn has_late_bound_to_non_late_bound_regions(from_sig: FnSig<'_>, to_sig: FnSig<'_>) -> bool {
+    fn check_region(from_region: Region<'_>, to_region: Region<'_>) -> bool {
+        matches!(from_region.kind(), RegionKind::ReLateBound(..))
+            && !matches!(to_region.kind(), RegionKind::ReLateBound(..))
     }
-    let binding_modes = cx.typeck_results().pat_binding_modes();
-    let check_inputs = |param: &Param<'_>, arg| {
-        match param.pat.kind {
-            PatKind::Binding(_, id, ..) if path_to_local_id(arg, id) => {},
-            _ => return false,
-        }
-        // checks that parameters are not bound as `ref` or `ref mut`
-        if let Some(BindingMode::BindByReference(_)) = binding_modes.get(param.pat.hir_id) {
-            return false;
-        }
 
-        match *cx.typeck_results().expr_adjustments(arg) {
-            [] => true,
-            [
-                Adjustment {
-                    kind: Adjust::Deref(None),
-                    ..
+    fn check_subs(from_subs: &[GenericArg<'_>], to_subs: &[GenericArg<'_>]) -> bool {
+        if from_subs.len() != to_subs.len() {
+            return true;
+        }
+        for (from_arg, to_arg) in to_subs.iter().zip(from_subs) {
+            match (from_arg.unpack(), to_arg.unpack()) {
+                (GenericArgKind::Lifetime(from_region), GenericArgKind::Lifetime(to_region)) => {
+                    if check_region(from_region, to_region) {
+                        return true;
+                    }
                 },
-                Adjustment {
-                    kind: Adjust::Borrow(AutoBorrow::Ref(_, mu2)),
-                    ..
+                (GenericArgKind::Type(from_ty), GenericArgKind::Type(to_ty)) => {
+                    if check_ty(from_ty, to_ty) {
+                        return true;
+                    }
                 },
-            ] => {
-                // re-borrow with the same mutability is allowed
-                let ty = cx.typeck_results().expr_ty(arg);
-                matches!(*ty.kind(), ty::Ref(.., mu1) if mu1 == mu2.into())
-            },
-            _ => false,
+                (GenericArgKind::Const(_), GenericArgKind::Const(_)) => (),
+                _ => return true,
+            }
         }
-    };
-    std::iter::zip(params, receiver.into_iter().chain(call_args.iter())).all(|(param, arg)| check_inputs(param, arg))
-}
-
-fn check_sig<'tcx>(cx: &LateContext<'tcx>, closure_ty: Ty<'tcx>, call_ty: Ty<'tcx>) -> bool {
-    let call_sig = call_ty.fn_sig(cx.tcx);
-    if call_sig.unsafety() == Unsafety::Unsafe {
-        return false;
+        false
     }
-    if !closure_ty.has_late_bound_regions() {
-        return true;
+
+    fn check_ty(from_ty: Ty<'_>, to_ty: Ty<'_>) -> bool {
+        match (from_ty.kind(), to_ty.kind()) {
+            (&ty::Adt(_, from_subs), &ty::Adt(_, to_subs)) => check_subs(from_subs, to_subs),
+            (&ty::Array(from_ty, _), &ty::Array(to_ty, _)) | (&ty::Slice(from_ty), &ty::Slice(to_ty)) => {
+                check_ty(from_ty, to_ty)
+            },
+            (&ty::Ref(from_region, from_ty, _), &ty::Ref(to_region, to_ty, _)) => {
+                check_region(from_region, to_region) || check_ty(from_ty, to_ty)
+            },
+            (&ty::Tuple(from_tys), &ty::Tuple(to_tys)) => {
+                from_tys.len() != to_tys.len()
+                    || from_tys
+                        .iter()
+                        .zip(to_tys)
+                        .any(|(from_ty, to_ty)| check_ty(from_ty, to_ty))
+            },
+            _ => from_ty.has_late_bound_regions(),
+        }
     }
-    let ty::Closure(_, substs) = closure_ty.kind() else {
-        return false;
-    };
-    let closure_sig = cx.tcx.signature_unclosure(substs.as_closure().sig(), Unsafety::Normal);
-    cx.tcx.erase_late_bound_regions(closure_sig) == cx.tcx.erase_late_bound_regions(call_sig)
+
+    assert!(from_sig.inputs_and_output.len() == to_sig.inputs_and_output.len());
+    from_sig
+        .inputs_and_output
+        .iter()
+        .zip(to_sig.inputs_and_output)
+        .any(|(from_ty, to_ty)| check_ty(from_ty, to_ty))
 }
 
-fn get_ufcs_type_name<'tcx>(cx: &LateContext<'tcx>, method_def_id: DefId, substs: SubstsRef<'tcx>) -> String {
+fn get_ufcs_type_name<'tcx>(cx: &LateContext<'tcx>, method_def_id: DefId, args: GenericArgsRef<'tcx>) -> String {
     let assoc_item = cx.tcx.associated_item(method_def_id);
     let def_id = assoc_item.container_id(cx.tcx);
     match assoc_item.container {
         ty::TraitContainer => cx.tcx.def_path_str(def_id),
         ty::ImplContainer => {
-            let ty = cx.tcx.type_of(def_id).skip_binder();
+            let ty = cx.tcx.type_of(def_id).instantiate_identity();
             match ty.kind() {
                 ty::Adt(adt, _) => cx.tcx.def_path_str(adt.did()),
                 ty::Array(..)
@@ -251,7 +327,7 @@ fn get_ufcs_type_name<'tcx>(cx: &LateContext<'tcx>, method_def_id: DefId, substs
                 | ty::Ref(..)
                 | ty::Slice(_)
                 | ty::Tuple(_) => {
-                    format!("<{}>", EarlyBinder::bind(ty).subst(cx.tcx, substs))
+                    format!("<{}>", EarlyBinder::bind(ty).instantiate(cx.tcx, args))
                 },
                 _ => ty.to_string(),
             }
diff --git a/clippy_lints/src/from_over_into.rs b/clippy_lints/src/from_over_into.rs
index 35e67f953ae..2b899e21ef5 100644
--- a/clippy_lints/src/from_over_into.rs
+++ b/clippy_lints/src/from_over_into.rs
@@ -77,9 +77,10 @@ impl<'tcx> LateLintPass<'tcx> for FromOverInto {
             && let Some(into_trait_seg) = hir_trait_ref.path.segments.last()
             // `impl Into<target_ty> for self_ty`
             && let Some(GenericArgs { args: [GenericArg::Type(target_ty)], .. }) = into_trait_seg.args
-            && let Some(middle_trait_ref) = cx.tcx.impl_trait_ref(item.owner_id).map(ty::EarlyBinder::subst_identity)
+            && let Some(middle_trait_ref) = cx.tcx.impl_trait_ref(item.owner_id)
+                                                  .map(ty::EarlyBinder::instantiate_identity)
             && cx.tcx.is_diagnostic_item(sym::Into, middle_trait_ref.def_id)
-            && !matches!(middle_trait_ref.substs.type_at(1).kind(), ty::Alias(ty::Opaque, _))
+            && !matches!(middle_trait_ref.args.type_at(1).kind(), ty::Alias(ty::Opaque, _))
         {
             span_lint_and_then(
                 cx,
diff --git a/clippy_lints/src/functions/must_use.rs b/clippy_lints/src/functions/must_use.rs
index c211ca67937..83445c7a0ca 100644
--- a/clippy_lints/src/functions/must_use.rs
+++ b/clippy_lints/src/functions/must_use.rs
@@ -197,14 +197,14 @@ fn is_mutable_ty<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>, tys: &mut DefIdSet)
     match *ty.kind() {
         // primitive types are never mutable
         ty::Bool | ty::Char | ty::Int(_) | ty::Uint(_) | ty::Float(_) | ty::Str => false,
-        ty::Adt(adt, substs) => {
+        ty::Adt(adt, args) => {
             tys.insert(adt.did()) && !ty.is_freeze(cx.tcx, cx.param_env)
                 || KNOWN_WRAPPER_TYS
                     .iter()
                     .any(|&sym| cx.tcx.is_diagnostic_item(sym, adt.did()))
-                    && substs.types().any(|ty| is_mutable_ty(cx, ty, tys))
+                    && args.types().any(|ty| is_mutable_ty(cx, ty, tys))
         },
-        ty::Tuple(substs) => substs.iter().any(|ty| is_mutable_ty(cx, ty, tys)),
+        ty::Tuple(args) => args.iter().any(|ty| is_mutable_ty(cx, ty, tys)),
         ty::Array(ty, _) | ty::Slice(ty) => is_mutable_ty(cx, ty, tys),
         ty::RawPtr(ty::TypeAndMut { ty, mutbl }) | ty::Ref(_, ty, mutbl) => {
             mutbl == hir::Mutability::Mut || is_mutable_ty(cx, ty, tys)
diff --git a/clippy_lints/src/functions/result.rs b/clippy_lints/src/functions/result.rs
index fa2a9b30c05..90fc0d4f662 100644
--- a/clippy_lints/src/functions/result.rs
+++ b/clippy_lints/src/functions/result.rs
@@ -21,11 +21,11 @@ fn result_err_ty<'tcx>(
 ) -> Option<(&'tcx hir::Ty<'tcx>, Ty<'tcx>)> {
     if !in_external_macro(cx.sess(), item_span)
         && let hir::FnRetTy::Return(hir_ty) = decl.output
-        && let ty = cx.tcx.erase_late_bound_regions(cx.tcx.fn_sig(id).subst_identity().output())
+        && let ty = cx.tcx.erase_late_bound_regions(cx.tcx.fn_sig(id).instantiate_identity().output())
         && is_type_diagnostic_item(cx, ty, sym::Result)
-        && let ty::Adt(_, substs) = ty.kind()
+        && let ty::Adt(_, args) = ty.kind()
     {
-        let err_ty = substs.type_at(1);
+        let err_ty = args.type_at(1);
         Some((hir_ty, err_ty))
     } else {
         None
diff --git a/clippy_lints/src/future_not_send.rs b/clippy_lints/src/future_not_send.rs
index 818ebd1134d..621415c881c 100644
--- a/clippy_lints/src/future_not_send.rs
+++ b/clippy_lints/src/future_not_send.rs
@@ -63,10 +63,10 @@ impl<'tcx> LateLintPass<'tcx> for FutureNotSend {
             return;
         }
         let ret_ty = return_ty(cx, cx.tcx.hir().local_def_id_to_hir_id(fn_def_id).expect_owner());
-        if let ty::Alias(ty::Opaque, AliasTy { def_id, substs, .. }) = *ret_ty.kind() {
+        if let ty::Alias(ty::Opaque, AliasTy { def_id, args, .. }) = *ret_ty.kind() {
             let preds = cx.tcx.explicit_item_bounds(def_id);
             let mut is_future = false;
-            for (p, _span) in preds.subst_iter_copied(cx.tcx, substs) {
+            for (p, _span) in preds.iter_instantiated_copied(cx.tcx, args) {
                 if let Some(trait_pred) = p.as_trait_clause() {
                     if Some(trait_pred.skip_binder().trait_ref.def_id) == cx.tcx.lang_items().future_trait() {
                         is_future = true;
diff --git a/clippy_lints/src/ignored_unit_patterns.rs b/clippy_lints/src/ignored_unit_patterns.rs
new file mode 100644
index 00000000000..c635120b882
--- /dev/null
+++ b/clippy_lints/src/ignored_unit_patterns.rs
@@ -0,0 +1,52 @@
+use clippy_utils::diagnostics::span_lint_and_sugg;
+use hir::PatKind;
+use rustc_errors::Applicability;
+use rustc_hir as hir;
+use rustc_lint::{LateContext, LateLintPass};
+use rustc_session::{declare_lint_pass, declare_tool_lint};
+
+declare_clippy_lint! {
+    /// ### What it does
+    /// Checks for usage of `_` in patterns of type `()`.
+    ///
+    /// ### Why is this bad?
+    /// Matching with `()` explicitly instead of `_` outlines
+    /// the fact that the pattern contains no data. Also it
+    /// would detect a type change that `_` would ignore.
+    ///
+    /// ### Example
+    /// ```rust
+    /// match std::fs::create_dir("tmp-work-dir") {
+    ///    Ok(_) => println!("Working directory created"),
+    ///    Err(s) => eprintln!("Could not create directory: {s}"),
+    /// }
+    /// ```
+    /// Use instead:
+    /// ```rust
+    /// match std::fs::create_dir("tmp-work-dir") {
+    ///    Ok(()) => println!("Working directory created"),
+    ///    Err(s) => eprintln!("Could not create directory: {s}"),
+    /// }
+    /// ```
+    #[clippy::version = "1.73.0"]
+    pub IGNORED_UNIT_PATTERNS,
+    pedantic,
+    "suggest replacing `_` by `()` in patterns where appropriate"
+}
+declare_lint_pass!(IgnoredUnitPatterns => [IGNORED_UNIT_PATTERNS]);
+
+impl<'tcx> LateLintPass<'tcx> for IgnoredUnitPatterns {
+    fn check_pat(&mut self, cx: &LateContext<'tcx>, pat: &'tcx hir::Pat<'tcx>) {
+        if matches!(pat.kind, PatKind::Wild) && cx.typeck_results().pat_ty(pat).is_unit() {
+            span_lint_and_sugg(
+                cx,
+                IGNORED_UNIT_PATTERNS,
+                pat.span,
+                "matching over `()` is more explicit",
+                "use `()` instead of `_`",
+                String::from("()"),
+                Applicability::MachineApplicable,
+            );
+        }
+    }
+}
diff --git a/clippy_lints/src/implicit_saturating_sub.rs b/clippy_lints/src/implicit_saturating_sub.rs
index 1e99b6faa6c..b99d4544681 100644
--- a/clippy_lints/src/implicit_saturating_sub.rs
+++ b/clippy_lints/src/implicit_saturating_sub.rs
@@ -102,7 +102,7 @@ impl<'tcx> LateLintPass<'tcx> for ImplicitSaturatingSub {
                             if let Some(const_id) = cx.typeck_results().type_dependent_def_id(cond_num_val.hir_id);
                             if let Some(impl_id) = cx.tcx.impl_of_method(const_id);
                             if let None = cx.tcx.impl_trait_ref(impl_id); // An inherent impl
-                            if cx.tcx.type_of(impl_id).subst_identity().is_integral();
+                            if cx.tcx.type_of(impl_id).instantiate_identity().is_integral();
                             then {
                                 print_lint_and_sugg(cx, var_name, expr)
                             }
@@ -115,7 +115,7 @@ impl<'tcx> LateLintPass<'tcx> for ImplicitSaturatingSub {
                             if let Some(func_id) = cx.typeck_results().type_dependent_def_id(func.hir_id);
                             if let Some(impl_id) = cx.tcx.impl_of_method(func_id);
                             if let None = cx.tcx.impl_trait_ref(impl_id); // An inherent impl
-                            if cx.tcx.type_of(impl_id).subst_identity().is_integral();
+                            if cx.tcx.type_of(impl_id).instantiate_identity().is_integral();
                             then {
                                 print_lint_and_sugg(cx, var_name, expr)
                             }
diff --git a/clippy_lints/src/incorrect_impls.rs b/clippy_lints/src/incorrect_impls.rs
index 166908ef4e4..c19a46f4e97 100644
--- a/clippy_lints/src/incorrect_impls.rs
+++ b/clippy_lints/src/incorrect_impls.rs
@@ -1,8 +1,9 @@
 use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_and_then};
+use clippy_utils::paths::ORD_CMP;
 use clippy_utils::ty::implements_trait;
-use clippy_utils::{get_parent_node, is_res_lang_ctor, last_path_segment, path_res};
+use clippy_utils::{get_parent_node, is_res_lang_ctor, last_path_segment, match_def_path, path_res, std_or_core};
 use rustc_errors::Applicability;
-use rustc_hir::def::Res;
+use rustc_hir::def_id::LocalDefId;
 use rustc_hir::{Expr, ExprKind, ImplItem, ImplItemKind, ItemKind, LangItem, Node, UnOp};
 use rustc_hir_analysis::hir_ty_to_ty;
 use rustc_lint::{LateContext, LateLintPass};
@@ -60,6 +61,10 @@ declare_clippy_lint! {
     /// wrapping the result of `cmp` in `Some` for `partial_cmp`. Not doing this may silently
     /// introduce an error upon refactoring.
     ///
+    /// ### Known issues
+    /// Code that calls the `.into()` method instead will be flagged as incorrect, despite `.into()`
+    /// wrapping it in `Some`.
+    ///
     /// ### Limitations
     /// Will not lint if `Self` and `Rhs` do not have the same type.
     ///
@@ -184,13 +189,13 @@ impl LateLintPass<'_> for IncorrectImpls {
                 .diagnostic_items(trait_impl.def_id.krate)
                 .name_to_id
                 .get(&sym::Ord)
-            && implements_trait(
-                    cx,
-                    hir_ty_to_ty(cx.tcx, imp.self_ty),
-                    *ord_def_id,
-                    trait_impl.substs,
-                )
+            && implements_trait(cx, hir_ty_to_ty(cx.tcx, imp.self_ty), *ord_def_id, &[])
         {
+            // If the `cmp` call likely needs to be fully qualified in the suggestion
+            // (like `std::cmp::Ord::cmp`). It's unfortunate we must put this here but we can't
+            // access `cmp_expr` in the suggestion without major changes, as we lint in `else`.
+            let mut needs_fully_qualified = false;
+
             if block.stmts.is_empty()
                 && let Some(expr) = block.expr
                 && let ExprKind::Call(
@@ -202,13 +207,12 @@ impl LateLintPass<'_> for IncorrectImpls {
                         [cmp_expr],
                     ) = expr.kind
                 && is_res_lang_ctor(cx, cx.qpath_res(some_path, *some_hir_id), LangItem::OptionSome)
-                && let ExprKind::MethodCall(cmp_path, _, [other_expr], ..) = cmp_expr.kind
-                && cmp_path.ident.name == sym::cmp
-                && let Res::Local(..) = path_res(cx, other_expr)
+                // Fix #11178, allow `Self::cmp(self, ..)` too
+                && self_cmp_call(cx, cmp_expr, impl_item.owner_id.def_id, &mut needs_fully_qualified)
             {} else {
                 // If `Self` and `Rhs` are not the same type, bail. This makes creating a valid
                 // suggestion tons more complex.
-                if let [lhs, rhs, ..] = trait_impl.substs.as_slice() && lhs != rhs {
+                if let [lhs, rhs, ..] = trait_impl.args.as_slice() && lhs != rhs {
                     return;
                 }
 
@@ -221,14 +225,29 @@ impl LateLintPass<'_> for IncorrectImpls {
                         let [_, other] = body.params else {
                             return;
                         };
+                        let Some(std_or_core) = std_or_core(cx) else {
+                            return;
+                        };
 
-                        let suggs = if let Some(other_ident) = other.pat.simple_ident() {
-                            vec![(block.span, format!("{{ Some(self.cmp({})) }}", other_ident.name))]
-                        } else {
-                            vec![
+                        let suggs = match (other.pat.simple_ident(), needs_fully_qualified) {
+                            (Some(other_ident), true) => vec![(
+                                block.span,
+                                format!("{{ Some({std_or_core}::cmp::Ord::cmp(self, {})) }}", other_ident.name),
+                            )],
+                            (Some(other_ident), false) => {
+                                vec![(block.span, format!("{{ Some(self.cmp({})) }}", other_ident.name))]
+                            },
+                            (None, true) => vec![
+                                (
+                                    block.span,
+                                    format!("{{ Some({std_or_core}::cmp::Ord::cmp(self, other)) }}"),
+                                ),
+                                (other.pat.span, "other".to_owned()),
+                            ],
+                            (None, false) => vec![
                                 (block.span, "{ Some(self.cmp(other)) }".to_owned()),
                                 (other.pat.span, "other".to_owned()),
-                            ]
+                            ],
                         };
 
                         diag.multipart_suggestion(
@@ -242,3 +261,31 @@ impl LateLintPass<'_> for IncorrectImpls {
         }
     }
 }
+
+/// Returns whether this is any of `self.cmp(..)`, `Self::cmp(self, ..)` or `Ord::cmp(self, ..)`.
+fn self_cmp_call<'tcx>(
+    cx: &LateContext<'tcx>,
+    cmp_expr: &'tcx Expr<'tcx>,
+    def_id: LocalDefId,
+    needs_fully_qualified: &mut bool,
+) -> bool {
+    match cmp_expr.kind {
+        ExprKind::Call(path, [_self, _other]) => path_res(cx, path)
+            .opt_def_id()
+            .is_some_and(|def_id| match_def_path(cx, def_id, &ORD_CMP)),
+        ExprKind::MethodCall(_, _, [_other], ..) => {
+            // We can set this to true here no matter what as if it's a `MethodCall` and goes to the
+            // `else` branch, it must be a method named `cmp` that isn't `Ord::cmp`
+            *needs_fully_qualified = true;
+
+            // It's a bit annoying but `typeck_results` only gives us the CURRENT body, which we
+            // have none, not of any `LocalDefId` we want, so we must call the query itself to avoid
+            // an immediate ICE
+            cx.tcx
+                .typeck(def_id)
+                .type_dependent_def_id(cmp_expr.hir_id)
+                .is_some_and(|def_id| match_def_path(cx, def_id, &ORD_CMP))
+        },
+        _ => false,
+    }
+}
diff --git a/clippy_lints/src/inherent_impl.rs b/clippy_lints/src/inherent_impl.rs
index 77e541d5b16..3d1113ff9cc 100644
--- a/clippy_lints/src/inherent_impl.rs
+++ b/clippy_lints/src/inherent_impl.rs
@@ -67,7 +67,7 @@ impl<'tcx> LateLintPass<'tcx> for MultipleInherentImpl {
             )
         }) {
             for impl_id in impl_ids.iter().map(|id| id.expect_local()) {
-                let impl_ty = cx.tcx.type_of(impl_id).subst_identity();
+                let impl_ty = cx.tcx.type_of(impl_id).instantiate_identity();
                 match type_map.entry(impl_ty) {
                     Entry::Vacant(e) => {
                         // Store the id for the first impl block of this type. The span is retrieved lazily.
diff --git a/clippy_lints/src/inherent_to_string.rs b/clippy_lints/src/inherent_to_string.rs
index d43e5cc9b2c..bc4ec33b733 100644
--- a/clippy_lints/src/inherent_to_string.rs
+++ b/clippy_lints/src/inherent_to_string.rs
@@ -1,11 +1,11 @@
 use clippy_utils::diagnostics::span_lint_and_help;
 use clippy_utils::ty::{implements_trait, is_type_lang_item};
 use clippy_utils::{return_ty, trait_ref_of_method};
-use if_chain::if_chain;
-use rustc_hir::{GenericParamKind, ImplItem, ImplItemKind, LangItem};
+use rustc_hir::{GenericParamKind, ImplItem, ImplItemKind, LangItem, Unsafety};
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_session::{declare_lint_pass, declare_tool_lint};
 use rustc_span::sym;
+use rustc_target::spec::abi::Abi;
 
 declare_clippy_lint! {
     /// ### What it does
@@ -95,24 +95,23 @@ impl<'tcx> LateLintPass<'tcx> for InherentToString {
             return;
         }
 
-        if_chain! {
-            // Check if item is a method, called to_string and has a parameter 'self'
-            if let ImplItemKind::Fn(ref signature, _) = impl_item.kind;
-            if impl_item.ident.name == sym::to_string;
-            let decl = &signature.decl;
-            if decl.implicit_self.has_implicit_self();
-            if decl.inputs.len() == 1;
-            if impl_item.generics.params.iter().all(|p| matches!(p.kind, GenericParamKind::Lifetime { .. }));
-
+        // Check if item is a method called `to_string` and has a parameter 'self'
+        if let ImplItemKind::Fn(ref signature, _) = impl_item.kind
+            // #11201
+            && let header = signature.header
+            && header.unsafety == Unsafety::Normal
+            && header.abi == Abi::Rust
+            && impl_item.ident.name == sym::to_string
+            && let decl = signature.decl
+            && decl.implicit_self.has_implicit_self()
+            && decl.inputs.len() == 1
+            && impl_item.generics.params.iter().all(|p| matches!(p.kind, GenericParamKind::Lifetime { .. }))
             // Check if return type is String
-            if is_type_lang_item(cx, return_ty(cx, impl_item.owner_id), LangItem::String);
-
+            && is_type_lang_item(cx, return_ty(cx, impl_item.owner_id), LangItem::String)
             // Filters instances of to_string which are required by a trait
-            if trait_ref_of_method(cx, impl_item.owner_id.def_id).is_none();
-
-            then {
-                show_lint(cx, impl_item);
-            }
+            && trait_ref_of_method(cx, impl_item.owner_id.def_id).is_none()
+        {
+            show_lint(cx, impl_item);
         }
     }
 }
diff --git a/clippy_lints/src/iter_not_returning_iterator.rs b/clippy_lints/src/iter_not_returning_iterator.rs
index c16717deee0..066d2c4b787 100644
--- a/clippy_lints/src/iter_not_returning_iterator.rs
+++ b/clippy_lints/src/iter_not_returning_iterator.rs
@@ -71,7 +71,7 @@ fn check_sig(cx: &LateContext<'_>, name: &str, sig: &FnSig<'_>, fn_id: LocalDefI
     if sig.decl.implicit_self.has_implicit_self() {
         let ret_ty = cx
             .tcx
-            .erase_late_bound_regions(cx.tcx.fn_sig(fn_id).subst_identity().output());
+            .erase_late_bound_regions(cx.tcx.fn_sig(fn_id).instantiate_identity().output());
         let ret_ty = cx
             .tcx
             .try_normalize_erasing_regions(cx.param_env, ret_ty)
diff --git a/clippy_lints/src/large_enum_variant.rs b/clippy_lints/src/large_enum_variant.rs
index 9caaec4e5cc..b22b57a3006 100644
--- a/clippy_lints/src/large_enum_variant.rs
+++ b/clippy_lints/src/large_enum_variant.rs
@@ -81,7 +81,7 @@ impl<'tcx> LateLintPass<'tcx> for LargeEnumVariant {
             return;
         }
         if let ItemKind::Enum(ref def, _) = item.kind {
-            let ty = cx.tcx.type_of(item.owner_id).subst_identity();
+            let ty = cx.tcx.type_of(item.owner_id).instantiate_identity();
             let Adt(adt, subst) = ty.kind() else {
                 panic!("already checked whether this is an enum")
             };
@@ -167,8 +167,8 @@ impl<'tcx> LateLintPass<'tcx> for LargeEnumVariant {
 }
 
 fn maybe_copy<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool {
-    if let Adt(_def, substs) = ty.kind()
-        && substs.types().next().is_some()
+    if let Adt(_def, args) = ty.kind()
+        && args.types().next().is_some()
         && let Some(copy_trait) = cx.tcx.lang_items().copy_trait()
     {
         return cx.tcx.non_blanket_impls_for_ty(copy_trait, ty).next().is_some();
diff --git a/clippy_lints/src/len_zero.rs b/clippy_lints/src/len_zero.rs
index e64d46bd6e3..deba232bdd2 100644
--- a/clippy_lints/src/len_zero.rs
+++ b/clippy_lints/src/len_zero.rs
@@ -7,11 +7,10 @@ use rustc_ast::ast::LitKind;
 use rustc_errors::Applicability;
 use rustc_hir::def::Res;
 use rustc_hir::def_id::{DefId, DefIdSet};
-use rustc_hir::lang_items::LangItem;
 use rustc_hir::{
     AssocItemKind, BinOpKind, Expr, ExprKind, FnRetTy, GenericArg, GenericBound, ImplItem, ImplItemKind,
-    ImplicitSelfKind, Item, ItemKind, Mutability, Node, PathSegment, PrimTy, QPath, TraitItemRef, TyKind,
-    TypeBindingKind,
+    ImplicitSelfKind, Item, ItemKind, LangItem, Mutability, Node, PatKind, PathSegment, PrimTy, QPath, TraitItemRef,
+    TyKind, TypeBindingKind,
 };
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_middle::ty::{self, AssocKind, FnSig, Ty};
@@ -146,7 +145,10 @@ impl<'tcx> LateLintPass<'tcx> for LenZero {
             if let Some(local_id) = ty_id.as_local();
             let ty_hir_id = cx.tcx.hir().local_def_id_to_hir_id(local_id);
             if !is_lint_allowed(cx, LEN_WITHOUT_IS_EMPTY, ty_hir_id);
-            if let Some(output) = parse_len_output(cx, cx.tcx.fn_sig(item.owner_id).subst_identity().skip_binder());
+            if let Some(output) = parse_len_output(
+                cx,
+                cx.tcx.fn_sig(item.owner_id).instantiate_identity().skip_binder()
+            );
             then {
                 let (name, kind) = match cx.tcx.hir().find(ty_hir_id) {
                     Some(Node::ForeignItem(x)) => (x.ident.name, "extern type"),
@@ -168,6 +170,31 @@ impl<'tcx> LateLintPass<'tcx> for LenZero {
             return;
         }
 
+        if let ExprKind::Let(lt) = expr.kind
+            && has_is_empty(cx, lt.init)
+            && match lt.pat.kind {
+                PatKind::Slice([], None, []) => true,
+                PatKind::Lit(lit) if is_empty_string(lit) => true,
+                _ => false,
+            }
+        {
+            let mut applicability = Applicability::MachineApplicable;
+
+            let lit1 = peel_ref_operators(cx, lt.init);
+            let lit_str =
+                Sugg::hir_with_context(cx, lit1, lt.span.ctxt(), "_", &mut applicability).maybe_par();
+
+            span_lint_and_sugg(
+                cx,
+                COMPARISON_TO_EMPTY,
+                lt.span,
+                "comparison to empty slice using `if let`",
+                "using `is_empty` is clearer and more explicit",
+                format!("{lit_str}.is_empty()"),
+                applicability,
+            );
+        }
+
         if let ExprKind::Binary(Spanned { node: cmp, .. }, left, right) = expr.kind {
             // expr.span might contains parenthesis, see issue #10529
             let actual_span = left.span.with_hi(right.span.hi());
@@ -426,7 +453,7 @@ fn check_for_is_empty(
             if !(is_empty.fn_has_self_parameter
                 && check_is_empty_sig(
                     cx,
-                    cx.tcx.fn_sig(is_empty.def_id).subst_identity().skip_binder(),
+                    cx.tcx.fn_sig(is_empty.def_id).instantiate_identity().skip_binder(),
                     self_kind,
                     output,
                 )) =>
diff --git a/clippy_lints/src/let_underscore.rs b/clippy_lints/src/let_underscore.rs
index b505a4e0af9..e7c875ab3a9 100644
--- a/clippy_lints/src/let_underscore.rs
+++ b/clippy_lints/src/let_underscore.rs
@@ -4,8 +4,7 @@ use clippy_utils::{is_from_proc_macro, is_must_use_func_call, paths};
 use rustc_hir::{Local, PatKind};
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_middle::lint::in_external_macro;
-use rustc_middle::ty::subst::GenericArgKind;
-use rustc_middle::ty::IsSuggestable;
+use rustc_middle::ty::{GenericArgKind, IsSuggestable};
 use rustc_session::{declare_lint_pass, declare_tool_lint};
 use rustc_span::{BytePos, Span};
 
diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs
index 4ea25e4be9d..358004cf460 100644
--- a/clippy_lints/src/lib.rs
+++ b/clippy_lints/src/lib.rs
@@ -65,6 +65,7 @@ mod declared_lints;
 mod renamed_lints;
 
 // begin lints modules, do not remove this comment, it’s used in `update_lints`
+mod absolute_paths;
 mod allow_attributes;
 mod almost_complete_range;
 mod approx_const;
@@ -120,6 +121,7 @@ mod entry;
 mod enum_clike;
 mod enum_variants;
 mod equatable_if_let;
+mod error_impl_error;
 mod escape;
 mod eta_reduction;
 mod excessive_bools;
@@ -145,6 +147,7 @@ mod future_not_send;
 mod if_let_mutex;
 mod if_not_else;
 mod if_then_some_else_none;
+mod ignored_unit_patterns;
 mod implicit_hasher;
 mod implicit_return;
 mod implicit_saturating_add;
@@ -273,6 +276,7 @@ mod redundant_clone;
 mod redundant_closure_call;
 mod redundant_else;
 mod redundant_field_names;
+mod redundant_locals;
 mod redundant_pub_crate;
 mod redundant_slicing;
 mod redundant_static_lifetimes;
@@ -910,7 +914,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
     store.register_late_pass(move |_| Box::new(if_then_some_else_none::IfThenSomeElseNone::new(msrv())));
     store.register_late_pass(|_| Box::new(bool_assert_comparison::BoolAssertComparison));
     store.register_early_pass(move || Box::new(module_style::ModStyle));
-    store.register_late_pass(|_| Box::new(unused_async::UnusedAsync));
+    store.register_late_pass(|_| Box::<unused_async::UnusedAsync>::default());
     let disallowed_types = conf.disallowed_types.clone();
     store.register_late_pass(move |_| Box::new(disallowed_types::DisallowedTypes::new(disallowed_types.clone())));
     let import_renames = conf.enforced_import_renames.clone();
@@ -1080,6 +1084,17 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
     store.register_late_pass(move |_| Box::new(tuple_array_conversions::TupleArrayConversions { msrv: msrv() }));
     store.register_late_pass(|_| Box::new(manual_float_methods::ManualFloatMethods));
     store.register_late_pass(|_| Box::new(four_forward_slashes::FourForwardSlashes));
+    store.register_late_pass(|_| Box::new(error_impl_error::ErrorImplError));
+    let absolute_paths_max_segments = conf.absolute_paths_max_segments;
+    let absolute_paths_allowed_crates = conf.absolute_paths_allowed_crates.clone();
+    store.register_late_pass(move |_| {
+        Box::new(absolute_paths::AbsolutePaths {
+            absolute_paths_max_segments,
+            absolute_paths_allowed_crates: absolute_paths_allowed_crates.clone(),
+        })
+    });
+    store.register_late_pass(|_| Box::new(redundant_locals::RedundantLocals));
+    store.register_late_pass(|_| Box::new(ignored_unit_patterns::IgnoredUnitPatterns));
     // add lints here, do not remove this comment, it's used in `new_lint`
 }
 
diff --git a/clippy_lints/src/lifetimes.rs b/clippy_lints/src/lifetimes.rs
index 852f6736585..0004a150d51 100644
--- a/clippy_lints/src/lifetimes.rs
+++ b/clippy_lints/src/lifetimes.rs
@@ -15,6 +15,7 @@ use rustc_hir::{
     PredicateOrigin, TraitFn, TraitItem, TraitItemKind, Ty, TyKind, WherePredicate,
 };
 use rustc_lint::{LateContext, LateLintPass, LintContext};
+use rustc_middle::hir::map::Map;
 use rustc_middle::hir::nested_filter as middle_nested_filter;
 use rustc_middle::lint::in_external_macro;
 use rustc_session::{declare_lint_pass, declare_tool_lint};
@@ -620,7 +621,7 @@ impl<'cx, 'tcx, F> Visitor<'tcx> for LifetimeChecker<'cx, 'tcx, F>
 where
     F: NestedFilter<'tcx>,
 {
-    type Map = rustc_middle::hir::map::Map<'tcx>;
+    type Map = Map<'tcx>;
     type NestedFilter = F;
 
     // for lifetimes as parameters of generics
diff --git a/clippy_lints/src/loops/explicit_iter_loop.rs b/clippy_lints/src/loops/explicit_iter_loop.rs
index 5c5a4cfce88..7b8c88235a9 100644
--- a/clippy_lints/src/loops/explicit_iter_loop.rs
+++ b/clippy_lints/src/loops/explicit_iter_loop.rs
@@ -109,7 +109,7 @@ fn is_ref_iterable<'tcx>(
         && let sig = cx.tcx.liberate_late_bound_regions(fn_id, cx.tcx.fn_sig(fn_id).skip_binder())
         && let &[req_self_ty, req_res_ty] = &**sig.inputs_and_output
         && let param_env = cx.tcx.param_env(fn_id)
-        && implements_trait_with_env(cx.tcx, param_env, req_self_ty, trait_id, [])
+        && implements_trait_with_env(cx.tcx, param_env, req_self_ty, trait_id, &[])
         && let Some(into_iter_ty) =
             make_normalized_projection_with_regions(cx.tcx, param_env, trait_id, sym!(IntoIter), [req_self_ty])
         && let req_res_ty = normalize_with_regions(cx.tcx, param_env, req_res_ty)
@@ -125,7 +125,7 @@ fn is_ref_iterable<'tcx>(
         }
 
         let res_ty = cx.tcx.erase_regions(EarlyBinder::bind(req_res_ty)
-            .subst(cx.tcx, typeck.node_substs(call_expr.hir_id)));
+            .instantiate(cx.tcx, typeck.node_args(call_expr.hir_id)));
         let mutbl = if let ty::Ref(_, _, mutbl) = *req_self_ty.kind() {
             Some(mutbl)
         } else {
diff --git a/clippy_lints/src/loops/missing_spin_loop.rs b/clippy_lints/src/loops/missing_spin_loop.rs
index f3bfe9e927d..7b7d19c753f 100644
--- a/clippy_lints/src/loops/missing_spin_loop.rs
+++ b/clippy_lints/src/loops/missing_spin_loop.rs
@@ -35,7 +35,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, cond: &'tcx Expr<'_>, body: &'
         if let ExprKind::Block(Block { stmts: [], expr: None, ..}, _) = body.kind;
         if let ExprKind::MethodCall(method, callee, ..) = unpack_cond(cond).kind;
         if [sym::load, sym::compare_exchange, sym::compare_exchange_weak].contains(&method.ident.name);
-        if let ty::Adt(def, _substs) = cx.typeck_results().expr_ty(callee).kind();
+        if let ty::Adt(def, _args) = cx.typeck_results().expr_ty(callee).kind();
         if cx.tcx.is_diagnostic_item(sym::AtomicBool, def.did());
         then {
             span_lint_and_sugg(
diff --git a/clippy_lints/src/loops/needless_range_loop.rs b/clippy_lints/src/loops/needless_range_loop.rs
index cb446567506..2c20e9e8693 100644
--- a/clippy_lints/src/loops/needless_range_loop.rs
+++ b/clippy_lints/src/loops/needless_range_loop.rs
@@ -370,7 +370,7 @@ impl<'a, 'tcx> Visitor<'tcx> for VarVisitor<'a, 'tcx> {
             ExprKind::MethodCall(_, receiver, args, _) => {
                 let def_id = self.cx.typeck_results().type_dependent_def_id(expr.hir_id).unwrap();
                 for (ty, expr) in iter::zip(
-                    self.cx.tcx.fn_sig(def_id).subst_identity().inputs().skip_binder(),
+                    self.cx.tcx.fn_sig(def_id).instantiate_identity().inputs().skip_binder(),
                     std::iter::once(receiver).chain(args.iter()),
                 ) {
                     self.prefer_mutable = false;
diff --git a/clippy_lints/src/loops/single_element_loop.rs b/clippy_lints/src/loops/single_element_loop.rs
index 744fd61bd13..dfb800ccf71 100644
--- a/clippy_lints/src/loops/single_element_loop.rs
+++ b/clippy_lints/src/loops/single_element_loop.rs
@@ -9,6 +9,7 @@ use rustc_errors::Applicability;
 use rustc_hir::{is_range_literal, BorrowKind, Expr, ExprKind, Pat};
 use rustc_lint::LateContext;
 use rustc_span::edition::Edition;
+use rustc_span::sym;
 
 pub(super) fn check<'tcx>(
     cx: &LateContext<'tcx>,
@@ -51,7 +52,7 @@ pub(super) fn check<'tcx>(
             },
             [],
             _,
-        ) if method.ident.name.as_str() == "iter_mut" => (arg, "&mut "),
+        ) if method.ident.name == sym::iter_mut => (arg, "&mut "),
         ExprKind::MethodCall(
             method,
             Expr {
diff --git a/clippy_lints/src/loops/utils.rs b/clippy_lints/src/loops/utils.rs
index 28ee24309cc..6edca2d55f6 100644
--- a/clippy_lints/src/loops/utils.rs
+++ b/clippy_lints/src/loops/utils.rs
@@ -76,7 +76,7 @@ impl<'a, 'tcx> Visitor<'tcx> for IncrementVisitor<'a, 'tcx> {
                     ExprKind::Assign(lhs, _, _) if lhs.hir_id == expr.hir_id => {
                         *state = IncrementVisitorVarState::DontWarn;
                     },
-                    ExprKind::AddrOf(BorrowKind::Ref, mutability, _) if mutability == Mutability::Mut => {
+                    ExprKind::AddrOf(BorrowKind::Ref, Mutability::Mut, _) => {
                         *state = IncrementVisitorVarState::DontWarn;
                     },
                     _ => (),
@@ -226,7 +226,7 @@ impl<'a, 'tcx> Visitor<'tcx> for InitializeVisitor<'a, 'tcx> {
                             InitializeVisitorState::DontWarn
                         }
                     },
-                    ExprKind::AddrOf(BorrowKind::Ref, mutability, _) if mutability == Mutability::Mut => {
+                    ExprKind::AddrOf(BorrowKind::Ref, Mutability::Mut, _) => {
                         self.state = InitializeVisitorState::DontWarn;
                     },
                     _ => (),
diff --git a/clippy_lints/src/manual_bits.rs b/clippy_lints/src/manual_bits.rs
index 4629b22d171..6c7c57ba1d6 100644
--- a/clippy_lints/src/manual_bits.rs
+++ b/clippy_lints/src/manual_bits.rs
@@ -110,7 +110,7 @@ fn get_size_of_ty<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) -> Option<
         if let Some(def_id) = cx.qpath_res(count_func_qpath, count_func.hir_id).opt_def_id();
         if cx.tcx.is_diagnostic_item(sym::mem_size_of, def_id);
         then {
-            cx.typeck_results().node_substs(count_func.hir_id).types().next().map(|resolved_ty| (*real_ty, resolved_ty))
+            cx.typeck_results().node_args(count_func.hir_id).types().next().map(|resolved_ty| (*real_ty, resolved_ty))
         } else {
             None
         }
diff --git a/clippy_lints/src/manual_slice_size_calculation.rs b/clippy_lints/src/manual_slice_size_calculation.rs
index 703a6b25840..f97600b53e4 100644
--- a/clippy_lints/src/manual_slice_size_calculation.rs
+++ b/clippy_lints/src/manual_slice_size_calculation.rs
@@ -92,7 +92,7 @@ fn simplify_half<'tcx>(
         && let ExprKind::Path(ref func_qpath) = func.kind
         && let Some(def_id) = cx.qpath_res(func_qpath, func.hir_id).opt_def_id()
         && cx.tcx.is_diagnostic_item(sym::mem_size_of, def_id)
-        && let Some(ty2) = cx.typeck_results().node_substs(func.hir_id).types().next()
+        && let Some(ty2) = cx.typeck_results().node_args(func.hir_id).types().next()
         // T1 == T2?
         && *ty1 == ty2
     {
diff --git a/clippy_lints/src/map_unit_fn.rs b/clippy_lints/src/map_unit_fn.rs
index 1b3a47e4acd..f0a0f482af2 100644
--- a/clippy_lints/src/map_unit_fn.rs
+++ b/clippy_lints/src/map_unit_fn.rs
@@ -104,7 +104,7 @@ fn is_unit_function(cx: &LateContext<'_>, expr: &hir::Expr<'_>) -> bool {
     let ty = cx.typeck_results().expr_ty(expr);
 
     if let ty::FnDef(id, _) = *ty.kind() {
-        if let Some(fn_type) = cx.tcx.fn_sig(id).subst_identity().no_bound_vars() {
+        if let Some(fn_type) = cx.tcx.fn_sig(id).instantiate_identity().no_bound_vars() {
             return is_unit_type(fn_type.output());
         }
     }
diff --git a/clippy_lints/src/matches/match_as_ref.rs b/clippy_lints/src/matches/match_as_ref.rs
index a6392b7aaec..d51cca040a2 100644
--- a/clippy_lints/src/matches/match_as_ref.rs
+++ b/clippy_lints/src/matches/match_as_ref.rs
@@ -27,10 +27,10 @@ pub(crate) fn check(cx: &LateContext<'_>, ex: &Expr<'_>, arms: &[Arm<'_>], expr:
             let input_ty = cx.typeck_results().expr_ty(ex);
 
             let cast = if_chain! {
-                if let ty::Adt(_, substs) = input_ty.kind();
-                let input_ty = substs.type_at(0);
-                if let ty::Adt(_, substs) = output_ty.kind();
-                let output_ty = substs.type_at(0);
+                if let ty::Adt(_, args) = input_ty.kind();
+                let input_ty = args.type_at(0);
+                if let ty::Adt(_, args) = output_ty.kind();
+                let output_ty = args.type_at(0);
                 if let ty::Ref(_, output_ty, _) = *output_ty.kind();
                 if input_ty != output_ty;
                 then {
diff --git a/clippy_lints/src/matches/mod.rs b/clippy_lints/src/matches/mod.rs
index d1061171e4d..6d16d188754 100644
--- a/clippy_lints/src/matches/mod.rs
+++ b/clippy_lints/src/matches/mod.rs
@@ -16,6 +16,7 @@ mod match_wild_enum;
 mod match_wild_err_arm;
 mod needless_match;
 mod overlapping_arms;
+mod redundant_guards;
 mod redundant_pattern_match;
 mod rest_pat_in_fully_bound_struct;
 mod significant_drop_in_scrutinee;
@@ -936,6 +937,36 @@ declare_clippy_lint! {
     "reimplementation of `filter`"
 }
 
+declare_clippy_lint! {
+    /// ### What it does
+    /// Checks for unnecessary guards in match expressions.
+    ///
+    /// ### Why is this bad?
+    /// It's more complex and much less readable. Making it part of the pattern can improve
+    /// exhaustiveness checking as well.
+    ///
+    /// ### Example
+    /// ```rust,ignore
+    /// match x {
+    ///     Some(x) if matches!(x, Some(1)) => ..,
+    ///     Some(x) if x == Some(2) => ..,
+    ///     _ => todo!(),
+    /// }
+    /// ```
+    /// Use instead:
+    /// ```rust,ignore
+    /// match x {
+    ///     Some(Some(1)) => ..,
+    ///     Some(Some(2)) => ..,
+    ///     _ => todo!(),
+    /// }
+    /// ```
+    #[clippy::version = "1.72.0"]
+    pub REDUNDANT_GUARDS,
+    complexity,
+    "checks for unnecessary guards in match expressions"
+}
+
 #[derive(Default)]
 pub struct Matches {
     msrv: Msrv,
@@ -978,6 +1009,7 @@ impl_lint_pass!(Matches => [
     TRY_ERR,
     MANUAL_MAP,
     MANUAL_FILTER,
+    REDUNDANT_GUARDS,
 ]);
 
 impl<'tcx> LateLintPass<'tcx> for Matches {
@@ -1025,6 +1057,7 @@ impl<'tcx> LateLintPass<'tcx> for Matches {
                     needless_match::check_match(cx, ex, arms, expr);
                     match_on_vec_items::check(cx, ex);
                     match_str_case_mismatch::check(cx, ex, arms);
+                    redundant_guards::check(cx, arms);
 
                     if !in_constant(cx, expr.hir_id) {
                         manual_unwrap_or::check(cx, expr, ex, arms);
diff --git a/clippy_lints/src/matches/redundant_guards.rs b/clippy_lints/src/matches/redundant_guards.rs
new file mode 100644
index 00000000000..6383326aa38
--- /dev/null
+++ b/clippy_lints/src/matches/redundant_guards.rs
@@ -0,0 +1,190 @@
+use clippy_utils::diagnostics::span_lint_and_then;
+use clippy_utils::path_to_local;
+use clippy_utils::source::snippet_with_applicability;
+use clippy_utils::visitors::{for_each_expr, is_local_used};
+use rustc_errors::Applicability;
+use rustc_hir::def::{DefKind, Res};
+use rustc_hir::{Arm, BinOpKind, Expr, ExprKind, Guard, MatchSource, Node, Pat, PatKind};
+use rustc_lint::LateContext;
+use rustc_span::Span;
+use std::ops::ControlFlow;
+
+use super::REDUNDANT_GUARDS;
+
+pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, arms: &'tcx [Arm<'tcx>]) {
+    for outer_arm in arms {
+        let Some(guard) = outer_arm.guard else {
+            continue;
+        };
+
+        // `Some(x) if matches!(x, y)`
+        if let Guard::If(if_expr) = guard
+            && let ExprKind::Match(
+                scrutinee,
+                [
+                    arm,
+                    Arm {
+                        pat: Pat {
+                            kind: PatKind::Wild,
+                            ..
+                        },
+                        ..
+                    },
+                ],
+                MatchSource::Normal,
+            ) = if_expr.kind
+        {
+            emit_redundant_guards(
+                cx,
+                outer_arm,
+                if_expr.span,
+                scrutinee,
+                arm.pat.span,
+                arm.guard,
+            );
+        }
+        // `Some(x) if let Some(2) = x`
+        else if let Guard::IfLet(let_expr) = guard {
+            emit_redundant_guards(
+                cx,
+                outer_arm,
+                let_expr.span,
+                let_expr.init,
+                let_expr.pat.span,
+                None,
+            );
+        }
+        // `Some(x) if x == Some(2)`
+        else if let Guard::If(if_expr) = guard
+            && let ExprKind::Binary(bin_op, local, pat) = if_expr.kind
+            && matches!(bin_op.node, BinOpKind::Eq)
+            && expr_can_be_pat(cx, pat)
+            // Ensure they have the same type. If they don't, we'd need deref coercion which isn't
+            // possible (currently) in a pattern. In some cases, you can use something like
+            // `as_deref` or similar but in general, we shouldn't lint this as it'd create an
+            // extraordinary amount of FPs.
+            //
+            // This isn't necessary in the other two checks, as they must be a pattern already.
+            && cx.typeck_results().expr_ty(local) == cx.typeck_results().expr_ty(pat)
+        {
+            emit_redundant_guards(
+                cx,
+                outer_arm,
+                if_expr.span,
+                local,
+                pat.span,
+                None,
+            );
+        }
+    }
+}
+
+fn get_pat_binding<'tcx>(cx: &LateContext<'tcx>, guard_expr: &Expr<'_>, outer_arm: &Arm<'tcx>) -> Option<(Span, bool)> {
+    if let Some(local) = path_to_local(guard_expr) && !is_local_used(cx, outer_arm.body, local) {
+        let mut span = None;
+        let mut multiple_bindings = false;
+        // `each_binding` gives the `HirId` of the `Pat` itself, not the binding
+        outer_arm.pat.walk(|pat| {
+            if let PatKind::Binding(_, hir_id, _, _) = pat.kind
+                && hir_id == local
+                && span.replace(pat.span).is_some()
+            {
+                multiple_bindings = true;
+                return false;
+            }
+
+            true
+        });
+
+        // Ignore bindings from or patterns, like `First(x) | Second(x, _) | Third(x, _, _)`
+        if !multiple_bindings {
+            return span.map(|span| {
+                (
+                    span,
+                    !matches!(cx.tcx.hir().get_parent(local), Node::PatField(_)),
+                )
+            });
+        }
+    }
+
+    None
+}
+
+fn emit_redundant_guards<'tcx>(
+    cx: &LateContext<'tcx>,
+    outer_arm: &Arm<'tcx>,
+    guard_span: Span,
+    local: &Expr<'_>,
+    pat_span: Span,
+    inner_guard: Option<Guard<'_>>,
+) {
+    let mut app = Applicability::MaybeIncorrect;
+    let Some((pat_binding, can_use_shorthand)) = get_pat_binding(cx, local, outer_arm) else {
+        return;
+    };
+
+    span_lint_and_then(
+        cx,
+        REDUNDANT_GUARDS,
+        guard_span.source_callsite(),
+        "redundant guard",
+        |diag| {
+            let binding_replacement = snippet_with_applicability(cx, pat_span, "<binding_repl>", &mut app);
+            diag.multipart_suggestion_verbose(
+                "try",
+                vec![
+                    if can_use_shorthand {
+                        (pat_binding, binding_replacement.into_owned())
+                    } else {
+                        (pat_binding.shrink_to_hi(), format!(": {binding_replacement}"))
+                    },
+                    (
+                        guard_span.source_callsite().with_lo(outer_arm.pat.span.hi()),
+                        inner_guard.map_or_else(String::new, |guard| {
+                            let (prefix, span) = match guard {
+                                Guard::If(e) => ("if", e.span),
+                                Guard::IfLet(l) => ("if let", l.span),
+                            };
+
+                            format!(
+                                " {prefix} {}",
+                                snippet_with_applicability(cx, span, "<guard>", &mut app),
+                            )
+                        }),
+                    ),
+                ],
+                app,
+            );
+        },
+    );
+}
+
+/// Checks if the given `Expr` can also be represented as a `Pat`.
+fn expr_can_be_pat(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
+    for_each_expr(expr, |expr| {
+        if match expr.kind {
+            ExprKind::ConstBlock(..) => cx.tcx.features().inline_const_pat,
+            ExprKind::Call(c, ..) if let ExprKind::Path(qpath) = c.kind => {
+                // Allow ctors
+                matches!(cx.qpath_res(&qpath, c.hir_id), Res::Def(DefKind::Ctor(..), ..))
+            },
+            ExprKind::Path(qpath) => {
+                matches!(
+                    cx.qpath_res(&qpath, expr.hir_id),
+                    Res::Def(DefKind::Struct | DefKind::Enum | DefKind::Ctor(..), ..),
+                )
+            },
+            ExprKind::AddrOf(..)
+            | ExprKind::Array(..)
+            | ExprKind::Tup(..)
+            | ExprKind::Struct(..)
+            | ExprKind::Lit(..) => true,
+            _ => false,
+        } {
+            return ControlFlow::Continue(());
+        }
+
+        ControlFlow::Break(())
+    })
+    .is_none()
+}
diff --git a/clippy_lints/src/matches/redundant_pattern_match.rs b/clippy_lints/src/matches/redundant_pattern_match.rs
index 3994533322d..9a7c00823b6 100644
--- a/clippy_lints/src/matches/redundant_pattern_match.rs
+++ b/clippy_lints/src/matches/redundant_pattern_match.rs
@@ -12,8 +12,7 @@ use rustc_hir::def::{DefKind, Res};
 use rustc_hir::LangItem::{self, OptionNone, OptionSome, PollPending, PollReady, ResultErr, ResultOk};
 use rustc_hir::{Arm, Expr, ExprKind, Guard, Node, Pat, PatKind, QPath, UnOp};
 use rustc_lint::LateContext;
-use rustc_middle::ty::subst::GenericArgKind;
-use rustc_middle::ty::{self, Ty};
+use rustc_middle::ty::{self, GenericArgKind, Ty};
 use rustc_span::{sym, Symbol};
 use std::fmt::Write;
 use std::ops::ControlFlow;
diff --git a/clippy_lints/src/matches/rest_pat_in_fully_bound_struct.rs b/clippy_lints/src/matches/rest_pat_in_fully_bound_struct.rs
index d06bcdaa27f..4efe93d4b54 100644
--- a/clippy_lints/src/matches/rest_pat_in_fully_bound_struct.rs
+++ b/clippy_lints/src/matches/rest_pat_in_fully_bound_struct.rs
@@ -10,7 +10,7 @@ pub(crate) fn check(cx: &LateContext<'_>, pat: &Pat<'_>) {
         if !pat.span.from_expansion();
         if let PatKind::Struct(QPath::Resolved(_, path), fields, true) = pat.kind;
         if let Some(def_id) = path.res.opt_def_id();
-        let ty = cx.tcx.type_of(def_id).subst_identity();
+        let ty = cx.tcx.type_of(def_id).instantiate_identity();
         if let ty::Adt(def, _) = ty.kind();
         if def.is_struct() || def.is_union();
         if fields.len() == def.non_enum_variant().fields.len();
diff --git a/clippy_lints/src/matches/significant_drop_in_scrutinee.rs b/clippy_lints/src/matches/significant_drop_in_scrutinee.rs
index 37528d9f7f2..ee0fdb35313 100644
--- a/clippy_lints/src/matches/significant_drop_in_scrutinee.rs
+++ b/clippy_lints/src/matches/significant_drop_in_scrutinee.rs
@@ -6,8 +6,7 @@ use rustc_errors::{Applicability, Diagnostic};
 use rustc_hir::intravisit::{walk_expr, Visitor};
 use rustc_hir::{Arm, Expr, ExprKind, MatchSource};
 use rustc_lint::{LateContext, LintContext};
-use rustc_middle::ty::subst::GenericArgKind;
-use rustc_middle::ty::{Ty, TypeAndMut};
+use rustc_middle::ty::{GenericArgKind, Ty, TypeAndMut};
 use rustc_span::Span;
 
 use super::SIGNIFICANT_DROP_IN_SCRUTINEE;
diff --git a/clippy_lints/src/methods/bytecount.rs b/clippy_lints/src/methods/bytecount.rs
index fef90f6eba4..f490a717554 100644
--- a/clippy_lints/src/methods/bytecount.rs
+++ b/clippy_lints/src/methods/bytecount.rs
@@ -45,7 +45,7 @@ pub(super) fn check<'tcx>(
             let haystack = if let ExprKind::MethodCall(path, receiver, [], _) =
                     filter_recv.kind {
                 let p = path.ident.name;
-                if p == sym::iter || p == sym!(iter_mut) {
+                if p == sym::iter || p == sym::iter_mut {
                     receiver
                 } else {
                     filter_recv
diff --git a/clippy_lints/src/methods/bytes_count_to_len.rs b/clippy_lints/src/methods/bytes_count_to_len.rs
index 46a20ad412b..649fc46e4ad 100644
--- a/clippy_lints/src/methods/bytes_count_to_len.rs
+++ b/clippy_lints/src/methods/bytes_count_to_len.rs
@@ -17,7 +17,7 @@ pub(super) fn check<'tcx>(
     if_chain! {
         if let Some(bytes_id) = cx.typeck_results().type_dependent_def_id(count_recv.hir_id);
         if let Some(impl_id) = cx.tcx.impl_of_method(bytes_id);
-        if cx.tcx.type_of(impl_id).subst_identity().is_str();
+        if cx.tcx.type_of(impl_id).instantiate_identity().is_str();
         let ty = cx.typeck_results().expr_ty(bytes_recv).peel_refs();
         if ty.is_str() || is_type_lang_item(cx, ty, hir::LangItem::String);
         then {
diff --git a/clippy_lints/src/methods/case_sensitive_file_extension_comparisons.rs b/clippy_lints/src/methods/case_sensitive_file_extension_comparisons.rs
index 41b5cc12d6d..d5897822eda 100644
--- a/clippy_lints/src/methods/case_sensitive_file_extension_comparisons.rs
+++ b/clippy_lints/src/methods/case_sensitive_file_extension_comparisons.rs
@@ -30,7 +30,7 @@ pub(super) fn check<'tcx>(
     if_chain! {
         if let Some(method_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id);
         if let Some(impl_id) = cx.tcx.impl_of_method(method_id);
-        if cx.tcx.type_of(impl_id).subst_identity().is_str();
+        if cx.tcx.type_of(impl_id).instantiate_identity().is_str();
         if let ExprKind::Lit(Spanned { node: LitKind::Str(ext_literal, ..), ..}) = arg.kind;
         if (2..=6).contains(&ext_literal.as_str().len());
         let ext_str = ext_literal.as_str();
diff --git a/clippy_lints/src/methods/err_expect.rs b/clippy_lints/src/methods/err_expect.rs
index 98f470dff8a..3d82441c0e6 100644
--- a/clippy_lints/src/methods/err_expect.rs
+++ b/clippy_lints/src/methods/err_expect.rs
@@ -46,7 +46,7 @@ pub(super) fn check(
 /// Given a `Result<T, E>` type, return its data (`T`).
 fn get_data_type<'a>(cx: &LateContext<'_>, ty: Ty<'a>) -> Option<Ty<'a>> {
     match ty.kind() {
-        ty::Adt(_, substs) if is_type_diagnostic_item(cx, ty, sym::Result) => substs.types().next(),
+        ty::Adt(_, args) if is_type_diagnostic_item(cx, ty, sym::Result) => args.types().next(),
         _ => None,
     }
 }
diff --git a/clippy_lints/src/methods/expect_fun_call.rs b/clippy_lints/src/methods/expect_fun_call.rs
index 862a7cec775..d3e90e4bba3 100644
--- a/clippy_lints/src/methods/expect_fun_call.rs
+++ b/clippy_lints/src/methods/expect_fun_call.rs
@@ -70,7 +70,7 @@ pub(super) fn check<'tcx>(
                 if let hir::ExprKind::Path(ref p) = fun.kind {
                     match cx.qpath_res(p, fun.hir_id) {
                         hir::def::Res::Def(hir::def::DefKind::Fn | hir::def::DefKind::AssocFn, def_id) => matches!(
-                            cx.tcx.fn_sig(def_id).subst_identity().output().skip_binder().kind(),
+                            cx.tcx.fn_sig(def_id).instantiate_identity().output().skip_binder().kind(),
                             ty::Ref(re, ..) if re.is_static(),
                         ),
                         _ => false,
@@ -84,7 +84,7 @@ pub(super) fn check<'tcx>(
                     .type_dependent_def_id(arg.hir_id)
                     .map_or(false, |method_id| {
                         matches!(
-                            cx.tcx.fn_sig(method_id).subst_identity().output().skip_binder().kind(),
+                            cx.tcx.fn_sig(method_id).instantiate_identity().output().skip_binder().kind(),
                             ty::Ref(re, ..) if re.is_static()
                         )
                     })
diff --git a/clippy_lints/src/methods/expect_used.rs b/clippy_lints/src/methods/expect_used.rs
deleted file mode 100644
index 614610335a1..00000000000
--- a/clippy_lints/src/methods/expect_used.rs
+++ /dev/null
@@ -1,44 +0,0 @@
-use clippy_utils::diagnostics::span_lint_and_help;
-use clippy_utils::ty::is_type_diagnostic_item;
-use clippy_utils::{is_in_cfg_test, is_in_test_function};
-use rustc_hir as hir;
-use rustc_lint::LateContext;
-use rustc_span::sym;
-
-use super::EXPECT_USED;
-
-/// lint use of `expect()` or `expect_err` for `Result` and `expect()` for `Option`.
-pub(super) fn check(
-    cx: &LateContext<'_>,
-    expr: &hir::Expr<'_>,
-    recv: &hir::Expr<'_>,
-    is_err: bool,
-    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) && !is_err {
-        Some((EXPECT_USED, "an `Option`", "None", ""))
-    } else if is_type_diagnostic_item(cx, obj_ty, sym::Result) {
-        Some((EXPECT_USED, "a `Result`", if is_err { "Ok" } else { "Err" }, "an "))
-    } else {
-        None
-    };
-
-    let method = if is_err { "expect_err" } else { "expect" };
-
-    if allow_expect_in_tests && (is_in_test_function(cx.tcx, expr.hir_id) || is_in_cfg_test(cx.tcx, expr.hir_id)) {
-        return;
-    }
-
-    if let Some((lint, kind, none_value, none_prefix)) = mess {
-        span_lint_and_help(
-            cx,
-            lint,
-            expr.span,
-            &format!("used `{method}()` on {kind} value"),
-            None,
-            &format!("if this value is {none_prefix}`{none_value}`, it will panic"),
-        );
-    }
-}
diff --git a/clippy_lints/src/methods/filter_map_bool_then.rs b/clippy_lints/src/methods/filter_map_bool_then.rs
new file mode 100644
index 00000000000..4aee22a4afc
--- /dev/null
+++ b/clippy_lints/src/methods/filter_map_bool_then.rs
@@ -0,0 +1,45 @@
+use clippy_utils::diagnostics::span_lint_and_sugg;
+use clippy_utils::paths::BOOL_THEN;
+use clippy_utils::source::snippet_opt;
+use clippy_utils::ty::is_copy;
+use clippy_utils::{is_from_proc_macro, is_trait_method, match_def_path, peel_blocks};
+use rustc_errors::Applicability;
+use rustc_hir::{Expr, ExprKind};
+use rustc_lint::{LateContext, LintContext};
+use rustc_middle::lint::in_external_macro;
+use rustc_span::{sym, Span};
+
+use super::FILTER_MAP_BOOL_THEN;
+
+pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>, arg: &Expr<'_>, call_span: Span) {
+    if !in_external_macro(cx.sess(), expr.span)
+        && is_trait_method(cx, expr, sym::Iterator)
+        && let ExprKind::Closure(closure) = arg.kind
+        && let body = cx.tcx.hir().body(closure.body)
+        && let value = peel_blocks(body.value)
+        // Indexing should be fine as `filter_map` always has 1 input, we unfortunately need both
+        // `inputs` and `params` here as we need both the type and the span
+        && let param_ty = closure.fn_decl.inputs[0]
+        && let param = body.params[0]
+        && is_copy(cx, cx.typeck_results().node_type(param_ty.hir_id).peel_refs())
+        && let ExprKind::MethodCall(_, recv, [then_arg], _) = value.kind
+        && let ExprKind::Closure(then_closure) = then_arg.kind
+        && let then_body = peel_blocks(cx.tcx.hir().body(then_closure.body).value)
+        && let Some(def_id) = cx.typeck_results().type_dependent_def_id(value.hir_id)
+        && match_def_path(cx, def_id, &BOOL_THEN)
+        && !is_from_proc_macro(cx, expr)
+        && let Some(param_snippet) = snippet_opt(cx, param.span)
+        && let Some(filter) = snippet_opt(cx, recv.span)
+        && let Some(map) = snippet_opt(cx, then_body.span)
+    {
+        span_lint_and_sugg(
+            cx,
+            FILTER_MAP_BOOL_THEN,
+            call_span,
+            "usage of `bool::then` in `filter_map`",
+            "use `filter` then `map` instead",
+            format!("filter(|&{param_snippet}| {filter}).map(|{param_snippet}| {map})"),
+            Applicability::MachineApplicable,
+        );
+    }
+}
diff --git a/clippy_lints/src/methods/flat_map_option.rs b/clippy_lints/src/methods/flat_map_option.rs
index 367a8ae82bd..172c397fbc8 100644
--- a/clippy_lints/src/methods/flat_map_option.rs
+++ b/clippy_lints/src/methods/flat_map_option.rs
@@ -16,7 +16,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>, arg
     }
     let arg_ty = cx.typeck_results().expr_ty_adjusted(arg);
     let sig = match arg_ty.kind() {
-        ty::Closure(_, substs) => substs.as_closure().sig(),
+        ty::Closure(_, args) => args.as_closure().sig(),
         _ if arg_ty.is_fn() => arg_ty.fn_sig(cx.tcx),
         _ => return,
     };
diff --git a/clippy_lints/src/methods/get_first.rs b/clippy_lints/src/methods/get_first.rs
index 945bbf53bcf..ee063adac64 100644
--- a/clippy_lints/src/methods/get_first.rs
+++ b/clippy_lints/src/methods/get_first.rs
@@ -19,7 +19,7 @@ pub(super) fn check<'tcx>(
     if_chain! {
         if let Some(method_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id);
         if let Some(impl_id) = cx.tcx.impl_of_method(method_id);
-        if cx.tcx.type_of(impl_id).subst_identity().is_slice();
+        if cx.tcx.type_of(impl_id).instantiate_identity().is_slice();
         if let Some(_) = is_slice_of_primitives(cx, recv);
         if let hir::ExprKind::Lit(Spanned { node: LitKind::Int(0, _), .. }) = arg.kind;
         then {
diff --git a/clippy_lints/src/methods/implicit_clone.rs b/clippy_lints/src/methods/implicit_clone.rs
index 5a78a416877..043425300d8 100644
--- a/clippy_lints/src/methods/implicit_clone.rs
+++ b/clippy_lints/src/methods/implicit_clone.rs
@@ -54,7 +54,7 @@ pub fn is_clone_like(cx: &LateContext<'_>, method_name: &str, method_def_id: hir
             .tcx
             .impl_of_method(method_def_id)
             .filter(|&impl_did| {
-                cx.tcx.type_of(impl_did).subst_identity().is_slice() && cx.tcx.impl_trait_ref(impl_did).is_none()
+                cx.tcx.type_of(impl_did).instantiate_identity().is_slice() && cx.tcx.impl_trait_ref(impl_did).is_none()
             })
             .is_some(),
         _ => false,
diff --git a/clippy_lints/src/methods/inefficient_to_string.rs b/clippy_lints/src/methods/inefficient_to_string.rs
index 122088f4857..631741d9290 100644
--- a/clippy_lints/src/methods/inefficient_to_string.rs
+++ b/clippy_lints/src/methods/inefficient_to_string.rs
@@ -23,9 +23,9 @@ pub fn check(
         if args.is_empty() && method_name == sym::to_string;
         if let Some(to_string_meth_did) = cx.typeck_results().type_dependent_def_id(expr.hir_id);
         if match_def_path(cx, to_string_meth_did, &paths::TO_STRING_METHOD);
-        if let Some(substs) = cx.typeck_results().node_substs_opt(expr.hir_id);
+        if let Some(args) = cx.typeck_results().node_args_opt(expr.hir_id);
         let arg_ty = cx.typeck_results().expr_ty_adjusted(receiver);
-        let self_ty = substs.type_at(0);
+        let self_ty = args.type_at(0);
         let (deref_self_ty, deref_count) = walk_ptrs_ty_depth(self_ty);
         if deref_count >= 1;
         if specializes_tostring(cx, deref_self_ty);
@@ -64,8 +64,8 @@ fn specializes_tostring(cx: &LateContext<'_>, ty: Ty<'_>) -> bool {
         return true;
     }
 
-    if let ty::Adt(adt, substs) = ty.kind() {
-        cx.tcx.is_diagnostic_item(sym::Cow, adt.did()) && substs.type_at(1).is_str()
+    if let ty::Adt(adt, args) = ty.kind() {
+        cx.tcx.is_diagnostic_item(sym::Cow, adt.did()) && args.type_at(1).is_str()
     } else {
         false
     }
diff --git a/clippy_lints/src/methods/manual_ok_or.rs b/clippy_lints/src/methods/manual_ok_or.rs
index b9a0ec77996..3031193e531 100644
--- a/clippy_lints/src/methods/manual_ok_or.rs
+++ b/clippy_lints/src/methods/manual_ok_or.rs
@@ -21,7 +21,7 @@ pub(super) fn check<'tcx>(
     if_chain! {
         if let Some(method_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id);
         if let Some(impl_id) = cx.tcx.impl_of_method(method_id);
-        if is_type_diagnostic_item(cx, cx.tcx.type_of(impl_id).subst_identity(), sym::Option);
+        if is_type_diagnostic_item(cx, cx.tcx.type_of(impl_id).instantiate_identity(), sym::Option);
         if let ExprKind::Call(err_path, [err_arg]) = or_expr.kind;
         if is_res_lang_ctor(cx, path_res(cx, err_path), ResultErr);
         if is_ok_wrapping(cx, map_expr);
diff --git a/clippy_lints/src/methods/map_clone.rs b/clippy_lints/src/methods/map_clone.rs
index 2b26ef01410..880efe60c1a 100644
--- a/clippy_lints/src/methods/map_clone.rs
+++ b/clippy_lints/src/methods/map_clone.rs
@@ -19,7 +19,7 @@ pub(super) fn check(cx: &LateContext<'_>, e: &hir::Expr<'_>, recv: &hir::Expr<'_
     if_chain! {
         if let Some(method_id) = cx.typeck_results().type_dependent_def_id(e.hir_id);
         if cx.tcx.impl_of_method(method_id)
-            .map_or(false, |id| is_type_diagnostic_item(cx, cx.tcx.type_of(id).subst_identity(), sym::Option))
+            .map_or(false, |id| is_type_diagnostic_item(cx, cx.tcx.type_of(id).instantiate_identity(), sym::Option))
             || is_diag_trait_item(cx, method_id, sym::Iterator);
         if let hir::ExprKind::Closure(&hir::Closure{ body, .. }) = arg.kind;
         then {
diff --git a/clippy_lints/src/methods/map_collect_result_unit.rs b/clippy_lints/src/methods/map_collect_result_unit.rs
index 36c7ddc973c..01cdd02e602 100644
--- a/clippy_lints/src/methods/map_collect_result_unit.rs
+++ b/clippy_lints/src/methods/map_collect_result_unit.rs
@@ -15,8 +15,8 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, iter: &hir::Expr
     let collect_ret_ty = cx.typeck_results().expr_ty(expr);
     if_chain! {
         if is_type_diagnostic_item(cx, collect_ret_ty, sym::Result);
-        if let ty::Adt(_, substs) = collect_ret_ty.kind();
-        if let Some(result_t) = substs.types().next();
+        if let ty::Adt(_, args) = collect_ret_ty.kind();
+        if let Some(result_t) = args.types().next();
         if result_t.is_unit();
         // get parts for snippet
         then {
diff --git a/clippy_lints/src/methods/map_err_ignore.rs b/clippy_lints/src/methods/map_err_ignore.rs
index a5beb291f32..fbb83c8ce56 100644
--- a/clippy_lints/src/methods/map_err_ignore.rs
+++ b/clippy_lints/src/methods/map_err_ignore.rs
@@ -9,7 +9,7 @@ use super::MAP_ERR_IGNORE;
 pub(super) fn check(cx: &LateContext<'_>, e: &Expr<'_>, arg: &Expr<'_>) {
     if let Some(method_id) = cx.typeck_results().type_dependent_def_id(e.hir_id)
         && let Some(impl_id) = cx.tcx.impl_of_method(method_id)
-        && is_type_diagnostic_item(cx, cx.tcx.type_of(impl_id).subst_identity(), sym::Result)
+        && is_type_diagnostic_item(cx, cx.tcx.type_of(impl_id).instantiate_identity(), sym::Result)
         && let ExprKind::Closure(&Closure {
             capture_clause: CaptureBy::Ref,
             body,
diff --git a/clippy_lints/src/methods/map_flatten.rs b/clippy_lints/src/methods/map_flatten.rs
index 349caa6ea6c..e74a764551c 100644
--- a/clippy_lints/src/methods/map_flatten.rs
+++ b/clippy_lints/src/methods/map_flatten.rs
@@ -60,7 +60,7 @@ fn is_map_to_option(cx: &LateContext<'_>, map_arg: &Expr<'_>) -> bool {
     match map_closure_ty.kind() {
         ty::Closure(_, _) | ty::FnDef(_, _) | ty::FnPtr(_) => {
             let map_closure_sig = match map_closure_ty.kind() {
-                ty::Closure(_, substs) => substs.as_closure().sig(),
+                ty::Closure(_, args) => args.as_closure().sig(),
                 _ => map_closure_ty.fn_sig(cx.tcx),
             };
             let map_closure_return_ty = cx.tcx.erase_late_bound_regions(map_closure_sig.output());
diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs
index be71072acd6..17483656cec 100644
--- a/clippy_lints/src/methods/mod.rs
+++ b/clippy_lints/src/methods/mod.rs
@@ -17,10 +17,10 @@ mod collapsible_str_replace;
 mod drain_collect;
 mod err_expect;
 mod expect_fun_call;
-mod expect_used;
 mod extend_with_drain;
 mod filetype_is_file;
 mod filter_map;
+mod filter_map_bool_then;
 mod filter_map_identity;
 mod filter_map_next;
 mod filter_next;
@@ -75,6 +75,7 @@ mod or_then_unwrap;
 mod path_buf_push_overwrite;
 mod range_zip_with_len;
 mod read_line_without_trim;
+mod readonly_write_lock;
 mod repeat_once;
 mod search_is_some;
 mod seek_from_current;
@@ -103,8 +104,7 @@ mod unnecessary_lazy_eval;
 mod unnecessary_literal_unwrap;
 mod unnecessary_sort_by;
 mod unnecessary_to_owned;
-mod unwrap_or_else_default;
-mod unwrap_used;
+mod unwrap_expect_used;
 mod useless_asref;
 mod utils;
 mod vec_resize_to_zero;
@@ -476,29 +476,40 @@ declare_clippy_lint! {
 
 declare_clippy_lint! {
     /// ### What it does
-    /// Checks for usage of `_.unwrap_or_else(Default::default)` on `Option` and
-    /// `Result` values.
+    /// Checks for usages of the following functions with an argument that constructs a default value
+    /// (e.g., `Default::default` or `String::new`):
+    /// - `unwrap_or`
+    /// - `unwrap_or_else`
+    /// - `or_insert`
+    /// - `or_insert_with`
     ///
     /// ### Why is this bad?
-    /// Readability, these can be written as `_.unwrap_or_default`, which is
-    /// simpler and more concise.
+    /// Readability. Using `unwrap_or_default` in place of `unwrap_or`/`unwrap_or_else`, or `or_default`
+    /// in place of `or_insert`/`or_insert_with`, is simpler and more concise.
+    ///
+    /// ### Known problems
+    /// In some cases, the argument of `unwrap_or`, etc. is needed for type inference. The lint uses a
+    /// heuristic to try to identify such cases. However, the heuristic can produce false negatives.
     ///
     /// ### Examples
     /// ```rust
     /// # let x = Some(1);
-    /// x.unwrap_or_else(Default::default);
-    /// x.unwrap_or_else(u32::default);
+    /// # let mut map = std::collections::HashMap::<u64, String>::new();
+    /// x.unwrap_or(Default::default());
+    /// map.entry(42).or_insert_with(String::new);
     /// ```
     ///
     /// Use instead:
     /// ```rust
     /// # let x = Some(1);
+    /// # let mut map = std::collections::HashMap::<u64, String>::new();
     /// x.unwrap_or_default();
+    /// map.entry(42).or_default();
     /// ```
     #[clippy::version = "1.56.0"]
-    pub UNWRAP_OR_ELSE_DEFAULT,
+    pub UNWRAP_OR_DEFAULT,
     style,
-    "using `.unwrap_or_else(Default::default)`, which is more succinctly expressed as `.unwrap_or_default()`"
+    "using `.unwrap_or`, etc. with an argument that constructs a default value"
 }
 
 declare_clippy_lint! {
@@ -3465,6 +3476,68 @@ declare_clippy_lint! {
     "disallows `.skip(0)`"
 }
 
+declare_clippy_lint! {
+    /// ### What it does
+    /// Checks for usage of `bool::then` in `Iterator::filter_map`.
+    ///
+    /// ### Why is this bad?
+    /// This can be written with `filter` then `map` instead, which would reduce nesting and
+    /// separates the filtering from the transformation phase. This comes with no cost to
+    /// performance and is just cleaner.
+    ///
+    /// ### Limitations
+    /// Does not lint `bool::then_some`, as it eagerly evaluates its arguments rather than lazily.
+    /// This can create differing behavior, so better safe than sorry.
+    ///
+    /// ### Example
+    /// ```rust
+    /// # fn really_expensive_fn(i: i32) -> i32 { i }
+    /// # let v = vec![];
+    /// _ = v.into_iter().filter_map(|i| (i % 2 == 0).then(|| really_expensive_fn(i)));
+    /// ```
+    /// Use instead:
+    /// ```rust
+    /// # fn really_expensive_fn(i: i32) -> i32 { i }
+    /// # let v = vec![];
+    /// _ = v.into_iter().filter(|i| i % 2 == 0).map(|i| really_expensive_fn(i));
+    /// ```
+    #[clippy::version = "1.72.0"]
+    pub FILTER_MAP_BOOL_THEN,
+    style,
+    "checks for usage of `bool::then` in `Iterator::filter_map`"
+}
+
+declare_clippy_lint! {
+    /// ### What it does
+    /// Looks for calls to `RwLock::write` where the lock is only used for reading.
+    ///
+    /// ### Why is this bad?
+    /// The write portion of `RwLock` is exclusive, meaning that no other thread
+    /// can access the lock while this writer is active.
+    ///
+    /// ### Example
+    /// ```rust
+    /// use std::sync::RwLock;
+    /// fn assert_is_zero(lock: &RwLock<i32>) {
+    ///     let num = lock.write().unwrap();
+    ///     assert_eq!(*num, 0);
+    /// }
+    /// ```
+    ///
+    /// Use instead:
+    /// ```rust
+    /// use std::sync::RwLock;
+    /// fn assert_is_zero(lock: &RwLock<i32>) {
+    ///     let num = lock.read().unwrap();
+    ///     assert_eq!(*num, 0);
+    /// }
+    /// ```
+    #[clippy::version = "1.73.0"]
+    pub READONLY_WRITE_LOCK,
+    nursery,
+    "acquiring a write lock when a read lock would work"
+}
+
 pub struct Methods {
     avoid_breaking_exported_api: bool,
     msrv: Msrv,
@@ -3495,7 +3568,7 @@ impl_lint_pass!(Methods => [
     SHOULD_IMPLEMENT_TRAIT,
     WRONG_SELF_CONVENTION,
     OK_EXPECT,
-    UNWRAP_OR_ELSE_DEFAULT,
+    UNWRAP_OR_DEFAULT,
     MAP_UNWRAP_OR,
     RESULT_MAP_OR_INTO_OPTION,
     OPTION_MAP_OR_NONE,
@@ -3602,6 +3675,8 @@ impl_lint_pass!(Methods => [
     FORMAT_COLLECT,
     STRING_LIT_CHARS_ANY,
     ITER_SKIP_ZERO,
+    FILTER_MAP_BOOL_THEN,
+    READONLY_WRITE_LOCK
 ]);
 
 /// Extracts a method call name, args, and `Span` of the method name.
@@ -3662,11 +3737,11 @@ impl<'tcx> LateLintPass<'tcx> for Methods {
         let name = impl_item.ident.name.as_str();
         let parent = cx.tcx.hir().get_parent_item(impl_item.hir_id()).def_id;
         let item = cx.tcx.hir().expect_item(parent);
-        let self_ty = cx.tcx.type_of(item.owner_id).subst_identity();
+        let self_ty = cx.tcx.type_of(item.owner_id).instantiate_identity();
 
         let implements_trait = matches!(item.kind, hir::ItemKind::Impl(hir::Impl { of_trait: Some(_), .. }));
         if let hir::ImplItemKind::Fn(ref sig, id) = impl_item.kind {
-            let method_sig = cx.tcx.fn_sig(impl_item.owner_id).subst_identity();
+            let method_sig = cx.tcx.fn_sig(impl_item.owner_id).instantiate_identity();
             let method_sig = cx.tcx.erase_late_bound_regions(method_sig);
             let first_arg_ty_opt = method_sig.inputs().iter().next().copied();
             // if this impl block implements a trait, lint in trait definition instead
@@ -3756,8 +3831,7 @@ impl<'tcx> LateLintPass<'tcx> for Methods {
             then {
                 let first_arg_span = first_arg_ty.span;
                 let first_arg_ty = hir_ty_to_ty(cx.tcx, first_arg_ty);
-                let self_ty = TraitRef::identity(cx.tcx, item.owner_id.to_def_id())
-                    .self_ty();
+                let self_ty = TraitRef::identity(cx.tcx, item.owner_id.to_def_id()).self_ty();
                 wrong_self_convention::check(
                     cx,
                     item.ident.name.as_str(),
@@ -3774,8 +3848,7 @@ impl<'tcx> LateLintPass<'tcx> for Methods {
             if item.ident.name == sym::new;
             if let TraitItemKind::Fn(_, _) = item.kind;
             let ret_ty = return_ty(cx, item.owner_id);
-            let self_ty = TraitRef::identity(cx.tcx, item.owner_id.to_def_id())
-                .self_ty();
+            let self_ty = TraitRef::identity(cx.tcx, item.owner_id.to_def_id()).self_ty();
             if !ret_ty.contains(self_ty);
 
             then {
@@ -3807,6 +3880,13 @@ impl Methods {
                         unnecessary_lazy_eval::check(cx, expr, recv, arg, "and");
                     }
                 },
+                ("any", [arg]) if let ExprKind::Closure(arg) = arg.kind
+                    && let body = cx.tcx.hir().body(arg.body)
+                    && let [param] = body.params
+                    && let Some(("chars", recv, _, _, _)) = method_call(recv) =>
+                {
+                    string_lit_chars_any::check(cx, expr, recv, param, peel_blocks(body.value), &self.msrv);
+                }
                 ("arg", [arg]) => {
                     suspicious_command_arg_space::check(cx, recv, arg, span);
                 }
@@ -3867,13 +3947,27 @@ impl Methods {
                     match method_call(recv) {
                         Some(("ok", recv, [], _, _)) => ok_expect::check(cx, expr, recv),
                         Some(("err", recv, [], err_span, _)) => err_expect::check(cx, expr, recv, span, err_span, &self.msrv),
-                        _ => expect_used::check(cx, expr, recv, false, self.allow_expect_in_tests),
+                        _ => unwrap_expect_used::check(
+                            cx,
+                            expr,
+                            recv,
+                            false,
+                            self.allow_expect_in_tests,
+                            unwrap_expect_used::Variant::Expect,
+                        ),
                     }
                     unnecessary_literal_unwrap::check(cx, expr, recv, name, args);
                 },
                 ("expect_err", [_]) => {
                     unnecessary_literal_unwrap::check(cx, expr, recv, name, args);
-                    expect_used::check(cx, expr, recv, true, self.allow_expect_in_tests);
+                    unwrap_expect_used::check(
+                        cx,
+                        expr,
+                        recv,
+                        true,
+                        self.allow_expect_in_tests,
+                        unwrap_expect_used::Variant::Expect,
+                    );
                 },
                 ("extend", [arg]) => {
                     string_extend_chars::check(cx, expr, recv, arg);
@@ -3881,6 +3975,7 @@ impl Methods {
                 },
                 ("filter_map", [arg]) => {
                     unnecessary_filter_map::check(cx, expr, arg, name);
+                    filter_map_bool_then::check(cx, expr, arg, call_span);
                     filter_map_identity::check(cx, expr, arg, span);
                 },
                 ("find_map", [arg]) => {
@@ -3924,15 +4019,6 @@ impl Methods {
                         unnecessary_join::check(cx, expr, recv, join_arg, span);
                     }
                 },
-                ("skip", [arg]) => {
-                    iter_skip_zero::check(cx, expr, arg);
-
-                    if let Some((name2, recv2, args2, _span2, _)) = method_call(recv) {
-                        if let ("cloned", []) = (name2, args2) {
-                            iter_overeager_cloned::check(cx, expr, recv, recv2, false, false);
-                        }
-                    }
-                }
                 ("last", []) => {
                     if let Some((name2, recv2, args2, _span2, _)) = method_call(recv) {
                         if let ("cloned", []) = (name2, args2) {
@@ -3985,13 +4071,6 @@ impl Methods {
                         }
                     }
                 },
-                ("any", [arg]) if let ExprKind::Closure(arg) = arg.kind
-                    && let body = cx.tcx.hir().body(arg.body)
-                    && let [param] = body.params
-                    && let Some(("chars", recv, _, _, _)) = method_call(recv) =>
-                {
-                    string_lit_chars_any::check(cx, expr, recv, param, peel_blocks(body.value), &self.msrv);
-                }
                 ("nth", [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, recv, recv2, false, false),
@@ -4045,6 +4124,15 @@ impl Methods {
                         seek_to_start_instead_of_rewind::check(cx, expr, recv, arg, span);
                     }
                 },
+                ("skip", [arg]) => {
+                    iter_skip_zero::check(cx, expr, arg);
+
+                    if let Some((name2, recv2, args2, _span2, _)) = method_call(recv) {
+                        if let ("cloned", []) = (name2, args2) {
+                            iter_overeager_cloned::check(cx, expr, recv, recv2, false, false);
+                        }
+                    }
+                }
                 ("sort", []) => {
                     stable_sort_primitive::check(cx, expr, recv);
                 },
@@ -4105,11 +4193,25 @@ impl Methods {
                         _ => {},
                     }
                     unnecessary_literal_unwrap::check(cx, expr, recv, name, args);
-                    unwrap_used::check(cx, expr, recv, false, self.allow_unwrap_in_tests);
+                    unwrap_expect_used::check(
+                        cx,
+                        expr,
+                        recv,
+                        false,
+                        self.allow_unwrap_in_tests,
+                        unwrap_expect_used::Variant::Unwrap,
+                    );
                 },
                 ("unwrap_err", []) => {
                     unnecessary_literal_unwrap::check(cx, expr, recv, name, args);
-                    unwrap_used::check(cx, expr, recv, true, self.allow_unwrap_in_tests);
+                    unwrap_expect_used::check(
+                        cx,
+                        expr,
+                        recv,
+                        true,
+                        self.allow_unwrap_in_tests,
+                        unwrap_expect_used::Variant::Unwrap,
+                    );
                 },
                 ("unwrap_or", [u_arg]) => {
                     match method_call(recv) {
@@ -4134,12 +4236,14 @@ impl Methods {
                         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");
                         },
                     }
                     unnecessary_literal_unwrap::check(cx, expr, recv, name, args);
                 },
+                ("write", []) => {
+                    readonly_write_lock::check(cx, expr, recv);
+                }
                 ("zip", [arg]) => {
                     if let ExprKind::MethodCall(name, iter_recv, [], _) = recv.kind
                         && name.ident.name == sym::iter
@@ -4290,8 +4394,8 @@ impl SelfKind {
             } else if ty.is_box() {
                 ty.boxed_ty() == parent_ty
             } else if is_type_diagnostic_item(cx, ty, sym::Rc) || is_type_diagnostic_item(cx, ty, sym::Arc) {
-                if let ty::Adt(_, substs) = ty.kind() {
-                    substs.types().next().map_or(false, |t| t == parent_ty)
+                if let ty::Adt(_, args) = ty.kind() {
+                    args.types().next().map_or(false, |t| t == parent_ty)
                 } else {
                     false
                 }
diff --git a/clippy_lints/src/methods/mut_mutex_lock.rs b/clippy_lints/src/methods/mut_mutex_lock.rs
index 161a7aa7fd4..2855e23bf5b 100644
--- a/clippy_lints/src/methods/mut_mutex_lock.rs
+++ b/clippy_lints/src/methods/mut_mutex_lock.rs
@@ -16,7 +16,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, ex: &'tcx Expr<'tcx>, recv: &'
         if let ty::Ref(_, _, Mutability::Mut) = cx.typeck_results().expr_ty(recv).kind();
         if let Some(method_id) = cx.typeck_results().type_dependent_def_id(ex.hir_id);
         if let Some(impl_id) = cx.tcx.impl_of_method(method_id);
-        if is_type_diagnostic_item(cx, cx.tcx.type_of(impl_id).subst_identity(), sym::Mutex);
+        if is_type_diagnostic_item(cx, cx.tcx.type_of(impl_id).instantiate_identity(), sym::Mutex);
         then {
             span_lint_and_sugg(
                 cx,
diff --git a/clippy_lints/src/methods/needless_collect.rs b/clippy_lints/src/methods/needless_collect.rs
index 9df268c437d..dbd965d6506 100644
--- a/clippy_lints/src/methods/needless_collect.rs
+++ b/clippy_lints/src/methods/needless_collect.rs
@@ -162,7 +162,7 @@ fn check_collect_into_intoiterator<'tcx>(
             // that contains `collect_expr`
             let inputs = cx
                 .tcx
-                .liberate_late_bound_regions(id, cx.tcx.fn_sig(id).subst_identity())
+                .liberate_late_bound_regions(id, cx.tcx.fn_sig(id).instantiate_identity())
                 .inputs();
 
             // map IntoIterator generic bounds to their signature
@@ -200,7 +200,7 @@ fn check_collect_into_intoiterator<'tcx>(
 /// Checks if the given method call matches the expected signature of `([&[mut]] self) -> bool`
 fn is_is_empty_sig(cx: &LateContext<'_>, call_id: HirId) -> bool {
     cx.typeck_results().type_dependent_def_id(call_id).map_or(false, |id| {
-        let sig = cx.tcx.fn_sig(id).subst_identity().skip_binder();
+        let sig = cx.tcx.fn_sig(id).instantiate_identity().skip_binder();
         sig.inputs().len() == 1 && sig.output().is_bool()
     })
 }
@@ -214,7 +214,7 @@ fn iterates_same_ty<'tcx>(cx: &LateContext<'tcx>, iter_ty: Ty<'tcx>, collect_ty:
         && let Some(into_iter_item_proj) = make_projection(cx.tcx, into_iter_trait, item, [collect_ty])
         && let Ok(into_iter_item_ty) = cx.tcx.try_normalize_erasing_regions(
             cx.param_env,
-            Ty::new_projection(cx.tcx,into_iter_item_proj.def_id, into_iter_item_proj.substs)
+            Ty::new_projection(cx.tcx,into_iter_item_proj.def_id, into_iter_item_proj.args)
         )
     {
         iter_item_ty == into_iter_item_ty
@@ -228,7 +228,7 @@ fn iterates_same_ty<'tcx>(cx: &LateContext<'tcx>, iter_ty: Ty<'tcx>, collect_ty:
 fn is_contains_sig(cx: &LateContext<'_>, call_id: HirId, iter_expr: &Expr<'_>) -> bool {
     let typeck = cx.typeck_results();
     if let Some(id) = typeck.type_dependent_def_id(call_id)
-        && let sig = cx.tcx.fn_sig(id).subst_identity()
+        && let sig = cx.tcx.fn_sig(id).instantiate_identity()
         && sig.skip_binder().output().is_bool()
         && let [_, search_ty] = *sig.skip_binder().inputs()
         && let ty::Ref(_, search_ty, Mutability::Not) = *cx.tcx.erase_late_bound_regions(sig.rebind(search_ty)).kind()
@@ -236,11 +236,11 @@ fn is_contains_sig(cx: &LateContext<'_>, call_id: HirId, iter_expr: &Expr<'_>) -
         && let Some(iter_item) = cx.tcx
             .associated_items(iter_trait)
             .find_by_name_and_kind(cx.tcx, Ident::with_dummy_span(Symbol::intern("Item")), AssocKind::Type, iter_trait)
-        && let substs = cx.tcx.mk_substs(&[GenericArg::from(typeck.expr_ty_adjusted(iter_expr))])
-        && let proj_ty = Ty::new_projection(cx.tcx,iter_item.def_id, substs)
+        && let args = cx.tcx.mk_args(&[GenericArg::from(typeck.expr_ty_adjusted(iter_expr))])
+        && let proj_ty = Ty::new_projection(cx.tcx,iter_item.def_id, args)
         && let Ok(item_ty) = cx.tcx.try_normalize_erasing_regions(cx.param_env, proj_ty)
     {
-        item_ty == EarlyBinder::bind(search_ty).subst(cx.tcx, cx.typeck_results().node_substs(call_id))
+        item_ty == EarlyBinder::bind(search_ty).instantiate(cx.tcx, cx.typeck_results().node_args(call_id))
     } else {
         false
     }
diff --git a/clippy_lints/src/methods/ok_expect.rs b/clippy_lints/src/methods/ok_expect.rs
index 646fc4a7bcf..f2ef42933df 100644
--- a/clippy_lints/src/methods/ok_expect.rs
+++ b/clippy_lints/src/methods/ok_expect.rs
@@ -33,7 +33,7 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, recv: &hir::Expr
 /// Given a `Result<T, E>` type, return its error type (`E`).
 fn get_error_type<'a>(cx: &LateContext<'_>, ty: Ty<'a>) -> Option<Ty<'a>> {
     match ty.kind() {
-        ty::Adt(_, substs) if is_type_diagnostic_item(cx, ty, sym::Result) => substs.types().nth(1),
+        ty::Adt(_, args) if is_type_diagnostic_item(cx, ty, sym::Result) => args.types().nth(1),
         _ => None,
     }
 }
diff --git a/clippy_lints/src/methods/open_options.rs b/clippy_lints/src/methods/open_options.rs
index bd625a6914c..1c664e76d74 100644
--- a/clippy_lints/src/methods/open_options.rs
+++ b/clippy_lints/src/methods/open_options.rs
@@ -11,7 +11,7 @@ use super::NONSENSICAL_OPEN_OPTIONS;
 pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>, recv: &'tcx Expr<'_>) {
     if let Some(method_id) = cx.typeck_results().type_dependent_def_id(e.hir_id)
         && let Some(impl_id) = cx.tcx.impl_of_method(method_id)
-        && match_type(cx, cx.tcx.type_of(impl_id).subst_identity(), &paths::OPEN_OPTIONS)
+        && match_type(cx, cx.tcx.type_of(impl_id).instantiate_identity(), &paths::OPEN_OPTIONS)
     {
         let mut options = Vec::new();
         get_open_options(cx, recv, &mut options);
diff --git a/clippy_lints/src/methods/or_fun_call.rs b/clippy_lints/src/methods/or_fun_call.rs
index 9165c1248f0..8b2f57160af 100644
--- a/clippy_lints/src/methods/or_fun_call.rs
+++ b/clippy_lints/src/methods/or_fun_call.rs
@@ -1,16 +1,17 @@
 use clippy_utils::diagnostics::span_lint_and_sugg;
 use clippy_utils::eager_or_lazy::switch_to_lazy_eval;
 use clippy_utils::source::snippet_with_context;
-use clippy_utils::ty::{implements_trait, is_type_diagnostic_item};
-use clippy_utils::{contains_return, is_trait_item, last_path_segment};
+use clippy_utils::ty::{expr_type_is_certain, implements_trait, is_type_diagnostic_item};
+use clippy_utils::{contains_return, is_default_equivalent, is_default_equivalent_call, last_path_segment};
 use if_chain::if_chain;
 use rustc_errors::Applicability;
-use rustc_hir as hir;
 use rustc_lint::LateContext;
+use rustc_middle::ty;
 use rustc_span::source_map::Span;
-use rustc_span::symbol::{kw, sym, Symbol};
+use rustc_span::symbol::{self, sym, Symbol};
+use {rustc_ast as ast, rustc_hir as hir};
 
-use super::OR_FUN_CALL;
+use super::{OR_FUN_CALL, UNWRAP_OR_DEFAULT};
 
 /// Checks for the `OR_FUN_CALL` lint.
 #[allow(clippy::too_many_lines)]
@@ -24,53 +25,72 @@ pub(super) fn check<'tcx>(
 ) {
     /// Checks for `unwrap_or(T::new())`, `unwrap_or(T::default())`,
     /// `or_insert(T::new())` or `or_insert(T::default())`.
+    /// Similarly checks for `unwrap_or_else(T::new)`, `unwrap_or_else(T::default)`,
+    /// `or_insert_with(T::new)` or `or_insert_with(T::default)`.
     #[allow(clippy::too_many_arguments)]
     fn check_unwrap_or_default(
         cx: &LateContext<'_>,
         name: &str,
+        receiver: &hir::Expr<'_>,
         fun: &hir::Expr<'_>,
-        arg: &hir::Expr<'_>,
-        or_has_args: bool,
+        call_expr: Option<&hir::Expr<'_>>,
         span: Span,
         method_span: Span,
     ) -> bool {
-        let is_default_default = || is_trait_item(cx, fun, sym::Default);
+        if !expr_type_is_certain(cx, receiver) {
+            return false;
+        }
 
-        let implements_default = |arg, default_trait_id| {
-            let arg_ty = cx.typeck_results().expr_ty(arg);
-            implements_trait(cx, arg_ty, default_trait_id, &[])
+        let is_new = |fun: &hir::Expr<'_>| {
+            if let hir::ExprKind::Path(ref qpath) = fun.kind {
+                let path = last_path_segment(qpath).ident.name;
+                matches!(path, sym::new)
+            } else {
+                false
+            }
         };
 
-        if_chain! {
-            if !or_has_args;
-            if let Some(sugg) = match name {
-                "unwrap_or" => Some("unwrap_or_default"),
-                "or_insert" => Some("or_default"),
-                _ => None,
-            };
-            if let hir::ExprKind::Path(ref qpath) = fun.kind;
-            if let Some(default_trait_id) = cx.tcx.get_diagnostic_item(sym::Default);
-            let path = last_path_segment(qpath).ident.name;
-            // needs to target Default::default in particular or be *::new and have a Default impl
-            // available
-            if (matches!(path, kw::Default) && is_default_default())
-                || (matches!(path, sym::new) && implements_default(arg, default_trait_id));
-
-            then {
-                span_lint_and_sugg(
-                    cx,
-                    OR_FUN_CALL,
-                    method_span.with_hi(span.hi()),
-                    &format!("use of `{name}` followed by a call to `{path}`"),
-                    "try",
-                    format!("{sugg}()"),
-                    Applicability::MachineApplicable,
-                );
-
-                true
+        let output_type_implements_default = |fun| {
+            let fun_ty = cx.typeck_results().expr_ty(fun);
+            if let ty::FnDef(def_id, args) = fun_ty.kind() {
+                let output_ty = cx.tcx.fn_sig(def_id).instantiate(cx.tcx, args).skip_binder().output();
+                cx.tcx
+                    .get_diagnostic_item(sym::Default)
+                    .map_or(false, |default_trait_id| {
+                        implements_trait(cx, output_ty, default_trait_id, &[])
+                    })
             } else {
                 false
             }
+        };
+
+        let sugg = match (name, call_expr.is_some()) {
+            ("unwrap_or", true) | ("unwrap_or_else", false) => "unwrap_or_default",
+            ("or_insert", true) | ("or_insert_with", false) => "or_default",
+            _ => return false,
+        };
+
+        // needs to target Default::default in particular or be *::new and have a Default impl
+        // available
+        if (is_new(fun) && output_type_implements_default(fun))
+            || match call_expr {
+                Some(call_expr) => is_default_equivalent(cx, call_expr),
+                None => is_default_equivalent_call(cx, fun) || closure_body_returns_empty_to_string(cx, fun),
+            }
+        {
+            span_lint_and_sugg(
+                cx,
+                UNWRAP_OR_DEFAULT,
+                method_span.with_hi(span.hi()),
+                &format!("use of `{name}` to construct default value"),
+                "try",
+                format!("{sugg}()"),
+                Applicability::MachineApplicable,
+            );
+
+            true
+        } else {
+            false
         }
     }
 
@@ -168,11 +188,16 @@ pub(super) fn check<'tcx>(
         match inner_arg.kind {
             hir::ExprKind::Call(fun, or_args) => {
                 let or_has_args = !or_args.is_empty();
-                if !check_unwrap_or_default(cx, name, fun, arg, or_has_args, expr.span, method_span) {
+                if or_has_args
+                    || !check_unwrap_or_default(cx, name, receiver, fun, Some(inner_arg), expr.span, method_span)
+                {
                     let fun_span = if or_has_args { None } else { Some(fun.span) };
                     check_general_case(cx, name, method_span, receiver, arg, None, expr.span, fun_span);
                 }
             },
+            hir::ExprKind::Path(..) | hir::ExprKind::Closure(..) => {
+                check_unwrap_or_default(cx, name, receiver, inner_arg, None, expr.span, method_span);
+            },
             hir::ExprKind::Index(..) | hir::ExprKind::MethodCall(..) => {
                 check_general_case(cx, name, method_span, receiver, arg, None, expr.span, None);
             },
@@ -189,3 +214,22 @@ pub(super) fn check<'tcx>(
         }
     }
 }
+
+fn closure_body_returns_empty_to_string(cx: &LateContext<'_>, e: &hir::Expr<'_>) -> bool {
+    if let hir::ExprKind::Closure(&hir::Closure { body, .. }) = e.kind {
+        let body = cx.tcx.hir().body(body);
+
+        if body.params.is_empty()
+            && let hir::Expr{ kind, .. } = &body.value
+            && let hir::ExprKind::MethodCall(hir::PathSegment {ident, ..}, self_arg, _, _) = kind
+            && ident.name == sym::to_string
+            && let hir::Expr{ kind, .. } = self_arg
+            && let hir::ExprKind::Lit(lit) = kind
+            && let ast::LitKind::Str(symbol::kw::Empty, _) = lit.node
+        {
+            return true;
+        }
+    }
+
+    false
+}
diff --git a/clippy_lints/src/methods/path_buf_push_overwrite.rs b/clippy_lints/src/methods/path_buf_push_overwrite.rs
index 0284d9dea30..1c07d2a3a59 100644
--- a/clippy_lints/src/methods/path_buf_push_overwrite.rs
+++ b/clippy_lints/src/methods/path_buf_push_overwrite.rs
@@ -14,7 +14,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, arg: &'t
     if_chain! {
         if let Some(method_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id);
         if let Some(impl_id) = cx.tcx.impl_of_method(method_id);
-        if is_type_diagnostic_item(cx, cx.tcx.type_of(impl_id).subst_identity(), sym::PathBuf);
+        if is_type_diagnostic_item(cx, cx.tcx.type_of(impl_id).instantiate_identity(), sym::PathBuf);
         if let ExprKind::Lit(lit) = arg.kind;
         if let LitKind::Str(ref path_lit, _) = lit.node;
         if let pushed_path = Path::new(path_lit.as_str());
diff --git a/clippy_lints/src/methods/read_line_without_trim.rs b/clippy_lints/src/methods/read_line_without_trim.rs
index 8add0656101..81f9e2a77fc 100644
--- a/clippy_lints/src/methods/read_line_without_trim.rs
+++ b/clippy_lints/src/methods/read_line_without_trim.rs
@@ -35,8 +35,8 @@ pub fn check(cx: &LateContext<'_>, call: &Expr<'_>, recv: &Expr<'_>, arg: &Expr<
                 && segment.ident.name == sym!(parse)
                 && let parse_result_ty = cx.typeck_results().expr_ty(parent)
                 && is_type_diagnostic_item(cx, parse_result_ty, sym::Result)
-                && let ty::Adt(_, substs) = parse_result_ty.kind()
-                && let Some(ok_ty) = substs[0].as_type()
+                && let ty::Adt(_, args) = parse_result_ty.kind()
+                && let Some(ok_ty) = args[0].as_type()
                 && parse_fails_on_trailing_newline(ok_ty)
             {
                 let local_snippet = snippet(cx, expr.span, "<expr>");
diff --git a/clippy_lints/src/methods/readonly_write_lock.rs b/clippy_lints/src/methods/readonly_write_lock.rs
new file mode 100644
index 00000000000..e3ec921da0c
--- /dev/null
+++ b/clippy_lints/src/methods/readonly_write_lock.rs
@@ -0,0 +1,52 @@
+use super::READONLY_WRITE_LOCK;
+use clippy_utils::diagnostics::span_lint_and_sugg;
+use clippy_utils::mir::{enclosing_mir, visit_local_usage};
+use clippy_utils::source::snippet;
+use clippy_utils::ty::is_type_diagnostic_item;
+use rustc_errors::Applicability;
+use rustc_hir::{Expr, ExprKind, Node};
+use rustc_lint::LateContext;
+use rustc_middle::mir::{Location, START_BLOCK};
+use rustc_span::sym;
+
+fn is_unwrap_call(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
+    if let ExprKind::MethodCall(path, receiver, ..) = expr.kind
+        && path.ident.name == sym::unwrap
+    {
+        is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(receiver).peel_refs(), sym::Result)
+    } else {
+        false
+    }
+}
+
+pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, receiver: &Expr<'_>) {
+    if is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(receiver).peel_refs(), sym::RwLock)
+        && let Node::Expr(unwrap_call_expr) = cx.tcx.hir().get_parent(expr.hir_id)
+        && is_unwrap_call(cx, unwrap_call_expr)
+        && let parent = cx.tcx.hir().get_parent(unwrap_call_expr.hir_id)
+        && let Node::Local(local) = parent
+        && let Some(mir) = enclosing_mir(cx.tcx, expr.hir_id)
+        && let Some((local, _)) = mir.local_decls.iter_enumerated().find(|(_, decl)| {
+            local.span.contains(decl.source_info.span)
+        })
+        && let Some(usages) = visit_local_usage(&[local], mir, Location {
+            block: START_BLOCK,
+            statement_index: 0,
+        })
+        && let [usage] = usages.as_slice()
+    {
+        let writer_never_mutated = usage.local_consume_or_mutate_locs.is_empty();
+
+        if writer_never_mutated {
+            span_lint_and_sugg(
+                cx,
+                READONLY_WRITE_LOCK,
+                expr.span,
+                "this write lock is used only for reading",
+                "consider using a read lock instead",
+                format!("{}.read()", snippet(cx, receiver.span, "<receiver>")),
+                Applicability::MaybeIncorrect // write lock might be intentional for enforcing exclusiveness
+            );
+        }
+    }
+}
diff --git a/clippy_lints/src/methods/stable_sort_primitive.rs b/clippy_lints/src/methods/stable_sort_primitive.rs
index b5fd0ad8ce5..0f4c97022db 100644
--- a/clippy_lints/src/methods/stable_sort_primitive.rs
+++ b/clippy_lints/src/methods/stable_sort_primitive.rs
@@ -10,7 +10,7 @@ use super::STABLE_SORT_PRIMITIVE;
 pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>, recv: &'tcx Expr<'_>) {
     if let Some(method_id) = cx.typeck_results().type_dependent_def_id(e.hir_id)
         && let Some(impl_id) = cx.tcx.impl_of_method(method_id)
-        && cx.tcx.type_of(impl_id).subst_identity().is_slice()
+        && cx.tcx.type_of(impl_id).instantiate_identity().is_slice()
         && let Some(slice_type) = is_slice_of_primitives(cx, recv)
     {
         span_lint_and_then(
diff --git a/clippy_lints/src/methods/suspicious_splitn.rs b/clippy_lints/src/methods/suspicious_splitn.rs
index 90ca66bd70c..3cb2719e4a0 100644
--- a/clippy_lints/src/methods/suspicious_splitn.rs
+++ b/clippy_lints/src/methods/suspicious_splitn.rs
@@ -13,7 +13,7 @@ pub(super) fn check(cx: &LateContext<'_>, method_name: &str, expr: &Expr<'_>, se
         if let Some(call_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id);
         if let Some(impl_id) = cx.tcx.impl_of_method(call_id);
         if cx.tcx.impl_trait_ref(impl_id).is_none();
-        let self_ty = cx.tcx.type_of(impl_id).subst_identity();
+        let self_ty = cx.tcx.type_of(impl_id).instantiate_identity();
         if self_ty.is_slice() || self_ty.is_str();
         then {
             // Ignore empty slice and string literals when used with a literal count.
diff --git a/clippy_lints/src/methods/type_id_on_box.rs b/clippy_lints/src/methods/type_id_on_box.rs
index 35137c97101..3404bdfe79b 100644
--- a/clippy_lints/src/methods/type_id_on_box.rs
+++ b/clippy_lints/src/methods/type_id_on_box.rs
@@ -24,9 +24,9 @@ pub(super) fn check(cx: &LateContext<'_>, receiver: &Expr<'_>, call_span: Span)
 
     if let Some(Adjustment { target: recv_ty, .. }) = recv_adjusts.last()
         && let ty::Ref(_, ty, _) = recv_ty.kind()
-        && let ty::Adt(adt, substs) = ty.kind()
+        && let ty::Adt(adt, args) = ty.kind()
         && adt.is_box()
-        && is_dyn_any(cx, substs.type_at(0))
+        && is_dyn_any(cx, args.type_at(0))
     {
         span_lint_and_then(
             cx,
diff --git a/clippy_lints/src/methods/unnecessary_filter_map.rs b/clippy_lints/src/methods/unnecessary_filter_map.rs
index cc64a2e7948..fabf3fa0c0c 100644
--- a/clippy_lints/src/methods/unnecessary_filter_map.rs
+++ b/clippy_lints/src/methods/unnecessary_filter_map.rs
@@ -77,6 +77,16 @@ fn check_expression<'tcx>(cx: &LateContext<'tcx>, arg_id: hir::HirId, expr: &'tc
             }
             (true, true)
         },
+        hir::ExprKind::MethodCall(segment, recv, [arg], _) => {
+            if segment.ident.name == sym!(then_some)
+                && cx.typeck_results().expr_ty(recv).is_bool()
+                && path_to_local_id(arg, arg_id)
+            {
+                (false, true)
+            } else {
+                (true, true)
+            }
+        },
         hir::ExprKind::Block(block, _) => block
             .expr
             .as_ref()
diff --git a/clippy_lints/src/methods/unnecessary_literal_unwrap.rs b/clippy_lints/src/methods/unnecessary_literal_unwrap.rs
index 111bcaaecec..937aac8d25e 100644
--- a/clippy_lints/src/methods/unnecessary_literal_unwrap.rs
+++ b/clippy_lints/src/methods/unnecessary_literal_unwrap.rs
@@ -3,6 +3,8 @@ use clippy_utils::{is_res_lang_ctor, last_path_segment, path_res, MaybePath};
 use rustc_errors::Applicability;
 use rustc_hir as hir;
 use rustc_lint::LateContext;
+use rustc_middle::ty;
+use rustc_middle::ty::print::with_forced_trimmed_paths;
 
 use super::UNNECESSARY_LITERAL_UNWRAP;
 
@@ -22,6 +24,7 @@ fn get_ty_from_args<'a>(args: Option<&'a [hir::GenericArg<'a>]>, index: usize) -
     }
 }
 
+#[expect(clippy::too_many_lines)]
 pub(super) fn check(
     cx: &LateContext<'_>,
     expr: &hir::Expr<'_>,
@@ -84,6 +87,34 @@ pub(super) fn check(
                 }
                 Some(suggs)
             },
+            ("None", "unwrap_or_default", _) => {
+                let ty = cx.typeck_results().expr_ty(expr);
+                let default_ty_string = if let ty::Adt(def, ..) = ty.kind() {
+                    with_forced_trimmed_paths!(format!("{}", cx.tcx.def_path_str(def.did())))
+                } else {
+                    "Default".to_string()
+                };
+                Some(vec![(expr.span, format!("{default_ty_string}::default()"))])
+            },
+            ("None", "unwrap_or", _) => Some(vec![
+                (expr.span.with_hi(args[0].span.lo()), String::new()),
+                (expr.span.with_lo(args[0].span.hi()), String::new()),
+            ]),
+            ("None", "unwrap_or_else", _) => match args[0].kind {
+                hir::ExprKind::Closure(hir::Closure {
+                    fn_decl:
+                        hir::FnDecl {
+                            output: hir::FnRetTy::DefaultReturn(span) | hir::FnRetTy::Return(hir::Ty { span, .. }),
+                            ..
+                        },
+                    ..
+                }) => Some(vec![
+                    (expr.span.with_hi(span.hi()), String::new()),
+                    (expr.span.with_lo(args[0].span.hi()), String::new()),
+                ]),
+                _ => None,
+            },
+            _ if call_args.is_empty() => None,
             (_, _, Some(_)) => None,
             ("Ok", "unwrap_err", None) | ("Err", "unwrap", None) => Some(vec![
                 (
diff --git a/clippy_lints/src/methods/unnecessary_sort_by.rs b/clippy_lints/src/methods/unnecessary_sort_by.rs
index 54b76bd04fe..79bff39379c 100644
--- a/clippy_lints/src/methods/unnecessary_sort_by.rs
+++ b/clippy_lints/src/methods/unnecessary_sort_by.rs
@@ -6,8 +6,8 @@ use if_chain::if_chain;
 use rustc_errors::Applicability;
 use rustc_hir::{Closure, Expr, ExprKind, Mutability, Param, Pat, PatKind, Path, PathSegment, QPath};
 use rustc_lint::LateContext;
-use rustc_middle::ty::subst::GenericArgKind;
-use rustc_middle::ty::{self};
+use rustc_middle::ty;
+use rustc_middle::ty::GenericArgKind;
 use rustc_span::sym;
 use rustc_span::symbol::Ident;
 use std::iter;
@@ -119,7 +119,7 @@ fn detect_lint(cx: &LateContext<'_>, expr: &Expr<'_>, recv: &Expr<'_>, arg: &Exp
     if_chain! {
         if let Some(method_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id);
         if let Some(impl_id) = cx.tcx.impl_of_method(method_id);
-        if cx.tcx.type_of(impl_id).subst_identity().is_slice();
+        if cx.tcx.type_of(impl_id).instantiate_identity().is_slice();
         if let ExprKind::Closure(&Closure { body, .. }) = arg.kind;
         if let closure_body = cx.tcx.hir().body(body);
         if let &[
diff --git a/clippy_lints/src/methods/unnecessary_to_owned.rs b/clippy_lints/src/methods/unnecessary_to_owned.rs
index 5c7d21ca663..5c5ee262052 100644
--- a/clippy_lints/src/methods/unnecessary_to_owned.rs
+++ b/clippy_lints/src/methods/unnecessary_to_owned.rs
@@ -14,8 +14,10 @@ use rustc_infer::infer::TyCtxtInferExt;
 use rustc_lint::LateContext;
 use rustc_middle::mir::Mutability;
 use rustc_middle::ty::adjustment::{Adjust, Adjustment, OverloadedDeref};
-use rustc_middle::ty::subst::{GenericArg, GenericArgKind, SubstsRef};
-use rustc_middle::ty::{self, ClauseKind, EarlyBinder, ParamTy, ProjectionPredicate, TraitPredicate, Ty};
+use rustc_middle::ty::{
+    self, ClauseKind, EarlyBinder, GenericArg, GenericArgKind, GenericArgsRef, ParamTy, ProjectionPredicate,
+    TraitPredicate, Ty,
+};
 use rustc_span::{sym, Symbol};
 use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt as _;
 use rustc_trait_selection::traits::{Obligation, ObligationCause};
@@ -252,8 +254,8 @@ fn check_other_call_arg<'tcx>(
 ) -> bool {
     if_chain! {
         if let Some((maybe_call, maybe_arg)) = skip_addr_of_ancestors(cx, expr);
-        if let Some((callee_def_id, _, recv, call_args)) = get_callee_substs_and_args(cx, maybe_call);
-        let fn_sig = cx.tcx.fn_sig(callee_def_id).subst_identity().skip_binder();
+        if let Some((callee_def_id, _, recv, call_args)) = get_callee_generic_args_and_args(cx, maybe_call);
+        let fn_sig = cx.tcx.fn_sig(callee_def_id).instantiate_identity().skip_binder();
         if let Some(i) = recv.into_iter().chain(call_args).position(|arg| arg.hir_id == maybe_arg.hir_id);
         if let Some(input) = fn_sig.inputs().get(i);
         let (input, n_refs) = peel_mid_ty_refs(*input);
@@ -317,26 +319,31 @@ fn skip_addr_of_ancestors<'tcx>(
 }
 
 /// Checks whether an expression is a function or method call and, if so, returns its `DefId`,
-/// `Substs`, and arguments.
-fn get_callee_substs_and_args<'tcx>(
+/// `GenericArgs`, and arguments.
+fn get_callee_generic_args_and_args<'tcx>(
     cx: &LateContext<'tcx>,
     expr: &'tcx Expr<'tcx>,
-) -> Option<(DefId, SubstsRef<'tcx>, Option<&'tcx Expr<'tcx>>, &'tcx [Expr<'tcx>])> {
+) -> Option<(
+    DefId,
+    GenericArgsRef<'tcx>,
+    Option<&'tcx Expr<'tcx>>,
+    &'tcx [Expr<'tcx>],
+)> {
     if_chain! {
         if let ExprKind::Call(callee, args) = expr.kind;
         let callee_ty = cx.typeck_results().expr_ty(callee);
         if let ty::FnDef(callee_def_id, _) = callee_ty.kind();
         then {
-            let substs = cx.typeck_results().node_substs(callee.hir_id);
-            return Some((*callee_def_id, substs, None, args));
+            let generic_args = cx.typeck_results().node_args(callee.hir_id);
+            return Some((*callee_def_id, generic_args, None, args));
         }
     }
     if_chain! {
         if let ExprKind::MethodCall(_, recv, args, _) = expr.kind;
         if let Some(method_def_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id);
         then {
-            let substs = cx.typeck_results().node_substs(expr.hir_id);
-            return Some((method_def_id, substs, Some(recv), args));
+            let generic_args = cx.typeck_results().node_args(expr.hir_id);
+            return Some((method_def_id, generic_args, Some(recv), args));
         }
     }
     None
@@ -390,17 +397,18 @@ fn can_change_type<'a>(cx: &LateContext<'a>, mut expr: &'a Expr<'a>, mut ty: Ty<
                 }
             }
             Node::Expr(parent_expr) => {
-                if let Some((callee_def_id, call_substs, recv, call_args)) = get_callee_substs_and_args(cx, parent_expr)
+                if let Some((callee_def_id, call_generic_args, recv, call_args))
+                    = get_callee_generic_args_and_args(cx, parent_expr)
                 {
-                    // FIXME: the `subst_identity()` below seems incorrect, since we eventually
+                    // FIXME: the `instantiate_identity()` below seems incorrect, since we eventually
                     // call `tcx.try_subst_and_normalize_erasing_regions` further down
                     // (i.e., we are explicitly not in the identity context).
-                    let fn_sig = cx.tcx.fn_sig(callee_def_id).subst_identity().skip_binder();
+                    let fn_sig = cx.tcx.fn_sig(callee_def_id).instantiate_identity().skip_binder();
                     if let Some(arg_index) = recv.into_iter().chain(call_args).position(|arg| arg.hir_id == expr.hir_id)
                         && let Some(param_ty) = fn_sig.inputs().get(arg_index)
                         && let ty::Param(ParamTy { index: param_index , ..}) = param_ty.kind()
                         // https://github.com/rust-lang/rust-clippy/issues/9504 and https://github.com/rust-lang/rust-clippy/issues/10021
-                        && (*param_index as usize) < call_substs.len()
+                        && (*param_index as usize) < call_generic_args.len()
                     {
                         if fn_sig
                             .inputs()
@@ -424,8 +432,8 @@ fn can_change_type<'a>(cx: &LateContext<'a>, mut expr: &'a Expr<'a>, mut ty: Ty<
                             }
                         });
 
-                        let new_subst = cx.tcx.mk_substs_from_iter(
-                            call_substs.iter()
+                        let new_subst = cx.tcx.mk_args_from_iter(
+                            call_generic_args.iter()
                                 .enumerate()
                                 .map(|(i, t)|
                                      if i == (*param_index as usize) {
@@ -435,7 +443,7 @@ fn can_change_type<'a>(cx: &LateContext<'a>, mut expr: &'a Expr<'a>, mut ty: Ty<
                                      }));
 
                         if trait_predicates.any(|predicate| {
-                            let predicate = EarlyBinder::bind(predicate).subst(cx.tcx, new_subst);
+                            let predicate = EarlyBinder::bind(predicate).instantiate(cx.tcx, new_subst);
                             let obligation = Obligation::new(cx.tcx, ObligationCause::dummy(), cx.param_env, predicate);
                             !cx.tcx.infer_ctxt().build().predicate_must_hold_modulo_regions(&obligation)
                         }) {
@@ -502,8 +510,8 @@ fn is_to_string_on_string_like<'a>(
         return false;
     }
 
-    if let Some(substs) = cx.typeck_results().node_substs_opt(call_expr.hir_id)
-        && let [generic_arg] = substs.as_slice()
+    if let Some(args) = cx.typeck_results().node_args_opt(call_expr.hir_id)
+        && let [generic_arg] = args.as_slice()
         && let GenericArgKind::Type(ty) = generic_arg.unpack()
         && let Some(deref_trait_id) = cx.tcx.get_diagnostic_item(sym::Deref)
         && let Some(as_ref_trait_id) = cx.tcx.get_diagnostic_item(sym::AsRef)
diff --git a/clippy_lints/src/methods/unwrap_expect_used.rs b/clippy_lints/src/methods/unwrap_expect_used.rs
new file mode 100644
index 00000000000..7bd16b473ce
--- /dev/null
+++ b/clippy_lints/src/methods/unwrap_expect_used.rs
@@ -0,0 +1,83 @@
+use clippy_utils::diagnostics::span_lint_and_then;
+use clippy_utils::ty::{is_never_like, is_type_diagnostic_item};
+use clippy_utils::{is_in_cfg_test, is_in_test_function, is_lint_allowed};
+use rustc_hir::Expr;
+use rustc_lint::{LateContext, Lint};
+use rustc_middle::ty;
+use rustc_span::sym;
+
+use super::{EXPECT_USED, UNWRAP_USED};
+
+#[derive(Clone, Copy, Eq, PartialEq)]
+pub(super) enum Variant {
+    Unwrap,
+    Expect,
+}
+
+impl Variant {
+    fn method_name(self, is_err: bool) -> &'static str {
+        match (self, is_err) {
+            (Variant::Unwrap, true) => "unwrap_err",
+            (Variant::Unwrap, false) => "unwrap",
+            (Variant::Expect, true) => "expect_err",
+            (Variant::Expect, false) => "expect",
+        }
+    }
+
+    fn lint(self) -> &'static Lint {
+        match self {
+            Variant::Unwrap => UNWRAP_USED,
+            Variant::Expect => EXPECT_USED,
+        }
+    }
+}
+
+/// Lint usage of `unwrap` or `unwrap_err` for `Result` and `unwrap()` for `Option` (and their
+/// `expect` counterparts).
+pub(super) fn check(
+    cx: &LateContext<'_>,
+    expr: &Expr<'_>,
+    recv: &Expr<'_>,
+    is_err: bool,
+    allow_unwrap_in_tests: bool,
+    variant: Variant,
+) {
+    let ty = cx.typeck_results().expr_ty(recv).peel_refs();
+
+    let (kind, none_value, none_prefix) = if is_type_diagnostic_item(cx, ty, sym::Option) && !is_err {
+        ("an `Option`", "None", "")
+    } else if is_type_diagnostic_item(cx, ty, sym::Result)
+        && let ty::Adt(_, substs) = ty.kind()
+        && let Some(t_or_e_ty) = substs[usize::from(!is_err)].as_type()
+    {
+        if is_never_like(t_or_e_ty) {
+            return;
+        }
+
+        ("a `Result`", if is_err { "Ok" } else { "Err" }, "an ")
+    } else {
+        return;
+    };
+
+    let method_suffix = if is_err { "_err" } else { "" };
+
+    if allow_unwrap_in_tests && (is_in_test_function(cx.tcx, expr.hir_id) || is_in_cfg_test(cx.tcx, expr.hir_id)) {
+        return;
+    }
+
+    span_lint_and_then(
+        cx,
+        variant.lint(),
+        expr.span,
+        &format!("used `{}()` on {kind} value", variant.method_name(is_err)),
+        |diag| {
+            diag.note(format!("if this value is {none_prefix}`{none_value}`, it will panic"));
+
+            if variant == Variant::Unwrap && is_lint_allowed(cx, EXPECT_USED, expr.hir_id) {
+                diag.help(format!(
+                    "consider using `expect{method_suffix}()` to provide a better panic message"
+                ));
+            }
+        },
+    );
+}
diff --git a/clippy_lints/src/methods/unwrap_or_else_default.rs b/clippy_lints/src/methods/unwrap_or_else_default.rs
deleted file mode 100644
index cfb1f7bbba8..00000000000
--- a/clippy_lints/src/methods/unwrap_or_else_default.rs
+++ /dev/null
@@ -1,70 +0,0 @@
-//! Lint for `some_result_or_option.unwrap_or_else(Default::default)`
-
-use super::UNWRAP_OR_ELSE_DEFAULT;
-use clippy_utils::diagnostics::span_lint_and_sugg;
-use clippy_utils::is_default_equivalent_call;
-use clippy_utils::source::snippet_with_applicability;
-use clippy_utils::ty::{expr_type_is_certain, is_type_diagnostic_item};
-use rustc_ast::ast::LitKind;
-use rustc_errors::Applicability;
-use rustc_hir as hir;
-use rustc_lint::LateContext;
-use rustc_span::{sym, symbol};
-
-pub(super) fn check<'tcx>(
-    cx: &LateContext<'tcx>,
-    expr: &'tcx hir::Expr<'_>,
-    recv: &'tcx hir::Expr<'_>,
-    u_arg: &'tcx hir::Expr<'_>,
-) {
-    if !expr_type_is_certain(cx, recv) {
-        return;
-    }
-
-    // something.unwrap_or_else(Default::default)
-    // ^^^^^^^^^- recv          ^^^^^^^^^^^^^^^^- u_arg
-    // ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^- expr
-    let recv_ty = cx.typeck_results().expr_ty(recv);
-    let is_option = is_type_diagnostic_item(cx, recv_ty, sym::Option);
-    let is_result = is_type_diagnostic_item(cx, recv_ty, sym::Result);
-
-    if_chain! {
-        if is_option || is_result;
-        if closure_body_returns_empty_to_string(cx, u_arg) || is_default_equivalent_call(cx, u_arg);
-        then {
-            let mut applicability = Applicability::MachineApplicable;
-
-            span_lint_and_sugg(
-                cx,
-                UNWRAP_OR_ELSE_DEFAULT,
-                expr.span,
-                "use of `.unwrap_or_else(..)` to construct default value",
-                "try",
-                format!(
-                    "{}.unwrap_or_default()",
-                    snippet_with_applicability(cx, recv.span, "..", &mut applicability)
-                ),
-                applicability,
-            );
-        }
-    }
-}
-
-fn closure_body_returns_empty_to_string(cx: &LateContext<'_>, e: &hir::Expr<'_>) -> bool {
-    if let hir::ExprKind::Closure(&hir::Closure { body, .. }) = e.kind {
-        let body = cx.tcx.hir().body(body);
-
-        if body.params.is_empty()
-            && let hir::Expr{ kind, .. } = &body.value
-            && let hir::ExprKind::MethodCall(hir::PathSegment {ident, ..}, self_arg, _, _) = kind
-            && ident == &symbol::Ident::from_str("to_string")
-            && let hir::Expr{ kind, .. } = self_arg
-            && let hir::ExprKind::Lit(lit) = kind
-            && let LitKind::Str(symbol::kw::Empty, _) = lit.node
-        {
-            return true;
-        }
-    }
-
-    false
-}
diff --git a/clippy_lints/src/methods/unwrap_used.rs b/clippy_lints/src/methods/unwrap_used.rs
deleted file mode 100644
index 5e4c3daee64..00000000000
--- a/clippy_lints/src/methods/unwrap_used.rs
+++ /dev/null
@@ -1,53 +0,0 @@
-use clippy_utils::diagnostics::span_lint_and_help;
-use clippy_utils::ty::is_type_diagnostic_item;
-use clippy_utils::{is_in_cfg_test, is_in_test_function, is_lint_allowed};
-use rustc_hir as hir;
-use rustc_lint::LateContext;
-use rustc_span::sym;
-
-use super::{EXPECT_USED, UNWRAP_USED};
-
-/// lint use of `unwrap()` or `unwrap_err` for `Result` and `unwrap()` for `Option`.
-pub(super) fn check(
-    cx: &LateContext<'_>,
-    expr: &hir::Expr<'_>,
-    recv: &hir::Expr<'_>,
-    is_err: bool,
-    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) && !is_err {
-        Some((UNWRAP_USED, "an `Option`", "None", ""))
-    } else if is_type_diagnostic_item(cx, obj_ty, sym::Result) {
-        Some((UNWRAP_USED, "a `Result`", if is_err { "Ok" } else { "Err" }, "an "))
-    } else {
-        None
-    };
-
-    let method_suffix = if is_err { "_err" } else { "" };
-
-    if allow_unwrap_in_tests && (is_in_test_function(cx.tcx, expr.hir_id) || is_in_cfg_test(cx.tcx, expr.hir_id)) {
-        return;
-    }
-
-    if let Some((lint, kind, none_value, none_prefix)) = mess {
-        let help = if is_lint_allowed(cx, EXPECT_USED, expr.hir_id) {
-            format!(
-                "if you don't want to handle the `{none_value}` case gracefully, consider \
-                using `expect{method_suffix}()` to provide a better panic message"
-            )
-        } else {
-            format!("if this value is {none_prefix}`{none_value}`, it will panic")
-        };
-
-        span_lint_and_help(
-            cx,
-            lint,
-            expr.span,
-            &format!("used `unwrap{method_suffix}()` on {kind} value"),
-            None,
-            &help,
-        );
-    }
-}
diff --git a/clippy_lints/src/methods/utils.rs b/clippy_lints/src/methods/utils.rs
index c96d6922697..9f1f73e6021 100644
--- a/clippy_lints/src/methods/utils.rs
+++ b/clippy_lints/src/methods/utils.rs
@@ -143,7 +143,7 @@ impl<'cx, 'tcx> Visitor<'tcx> for CloneOrCopyVisitor<'cx, 'tcx> {
                         if_chain! {
                             if args.iter().all(|arg| !self.is_binding(arg));
                             if let Some(method_def_id) = self.cx.typeck_results().type_dependent_def_id(parent.hir_id);
-                            let method_ty = self.cx.tcx.type_of(method_def_id).subst_identity();
+                            let method_ty = self.cx.tcx.type_of(method_def_id).instantiate_identity();
                             let self_ty = method_ty.fn_sig(self.cx.tcx).input(0).skip_binder();
                             if matches!(self_ty.kind(), ty::Ref(_, _, Mutability::Not));
                             then {
diff --git a/clippy_lints/src/methods/vec_resize_to_zero.rs b/clippy_lints/src/methods/vec_resize_to_zero.rs
index b0cfc163fd0..73072718678 100644
--- a/clippy_lints/src/methods/vec_resize_to_zero.rs
+++ b/clippy_lints/src/methods/vec_resize_to_zero.rs
@@ -20,7 +20,7 @@ pub(super) fn check<'tcx>(
     if_chain! {
         if let Some(method_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id);
         if let Some(impl_id) = cx.tcx.impl_of_method(method_id);
-        if is_type_diagnostic_item(cx, cx.tcx.type_of(impl_id).subst_identity(), sym::Vec);
+        if is_type_diagnostic_item(cx, cx.tcx.type_of(impl_id).instantiate_identity(), sym::Vec);
         if let ExprKind::Lit(Spanned { node: LitKind::Int(0, _), .. }) = count_arg.kind;
         if let ExprKind::Lit(Spanned { node: LitKind::Int(..), .. }) = default_arg.kind;
         then {
diff --git a/clippy_lints/src/min_ident_chars.rs b/clippy_lints/src/min_ident_chars.rs
index 2a60f2faca0..c79a1a7b9d4 100644
--- a/clippy_lints/src/min_ident_chars.rs
+++ b/clippy_lints/src/min_ident_chars.rs
@@ -129,6 +129,14 @@ impl Visitor<'_> for IdentVisitor<'_, '_> {
                 return;
             }
 
+            // `struct Array<T, const N: usize>([T; N])`
+            //                        ^
+            if let Node::GenericParam(generic_param) = node
+                && let GenericParamKind::Const { .. } = generic_param.kind
+            {
+                return;
+            }
+
             if is_from_proc_macro(cx, &ident) {
                 return;
             }
diff --git a/clippy_lints/src/mut_key.rs b/clippy_lints/src/mut_key.rs
index 309f67521a3..5878f899541 100644
--- a/clippy_lints/src/mut_key.rs
+++ b/clippy_lints/src/mut_key.rs
@@ -139,7 +139,7 @@ impl MutableKeyType {
     }
 
     fn check_sig(&self, cx: &LateContext<'_>, fn_def_id: LocalDefId, decl: &hir::FnDecl<'_>) {
-        let fn_sig = cx.tcx.fn_sig(fn_def_id).subst_identity();
+        let fn_sig = cx.tcx.fn_sig(fn_def_id).instantiate_identity();
         for (hir_ty, ty) in iter::zip(decl.inputs, fn_sig.inputs().skip_binder()) {
             self.check_ty_(cx, hir_ty.span, *ty);
         }
@@ -150,7 +150,7 @@ impl MutableKeyType {
     // generics (because the compiler cannot ensure immutability for unknown types).
     fn check_ty_<'tcx>(&self, cx: &LateContext<'tcx>, span: Span, ty: Ty<'tcx>) {
         let ty = ty.peel_refs();
-        if let Adt(def, substs) = ty.kind() {
+        if let Adt(def, args) = ty.kind() {
             let is_keyed_type = [sym::HashMap, sym::BTreeMap, sym::HashSet, sym::BTreeSet]
                 .iter()
                 .any(|diag_item| cx.tcx.is_diagnostic_item(*diag_item, def.did()));
@@ -158,7 +158,7 @@ impl MutableKeyType {
                 return;
             }
 
-            let subst_ty = substs.type_at(0);
+            let subst_ty = args.type_at(0);
             // Determines if a type contains interior mutability which would affect its implementation of
             // [`Hash`] or [`Ord`].
             if is_interior_mut_ty(cx, subst_ty)
diff --git a/clippy_lints/src/mut_reference.rs b/clippy_lints/src/mut_reference.rs
index e91aac41bc4..e53e146ec5d 100644
--- a/clippy_lints/src/mut_reference.rs
+++ b/clippy_lints/src/mut_reference.rs
@@ -37,6 +37,11 @@ declare_lint_pass!(UnnecessaryMutPassed => [UNNECESSARY_MUT_PASSED]);
 
 impl<'tcx> LateLintPass<'tcx> for UnnecessaryMutPassed {
     fn check_expr(&mut self, cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) {
+        if e.span.from_expansion() {
+            // Issue #11268
+            return;
+        }
+
         match e.kind {
             ExprKind::Call(fn_expr, arguments) => {
                 if let ExprKind::Path(ref path) = fn_expr.kind {
@@ -51,8 +56,8 @@ impl<'tcx> LateLintPass<'tcx> for UnnecessaryMutPassed {
             },
             ExprKind::MethodCall(path, receiver, arguments, _) => {
                 let def_id = cx.typeck_results().type_dependent_def_id(e.hir_id).unwrap();
-                let substs = cx.typeck_results().node_substs(e.hir_id);
-                let method_type = cx.tcx.type_of(def_id).subst(cx.tcx, substs);
+                let args = cx.typeck_results().node_args(e.hir_id);
+                let method_type = cx.tcx.type_of(def_id).instantiate(cx.tcx, args);
                 check_arguments(
                     cx,
                     std::iter::once(receiver).chain(arguments.iter()).collect(),
diff --git a/clippy_lints/src/needless_pass_by_ref_mut.rs b/clippy_lints/src/needless_pass_by_ref_mut.rs
index cdb7ee48305..c634de960d1 100644
--- a/clippy_lints/src/needless_pass_by_ref_mut.rs
+++ b/clippy_lints/src/needless_pass_by_ref_mut.rs
@@ -1,16 +1,18 @@
 use super::needless_pass_by_value::requires_exact_signature;
-use clippy_utils::diagnostics::span_lint_and_then;
+use clippy_utils::diagnostics::span_lint_hir_and_then;
 use clippy_utils::source::snippet;
-use clippy_utils::{is_from_proc_macro, is_self};
-use if_chain::if_chain;
+use clippy_utils::{get_parent_node, inherits_cfg, is_from_proc_macro, is_self};
+use rustc_data_structures::fx::{FxHashSet, FxIndexMap};
 use rustc_errors::Applicability;
-use rustc_hir::intravisit::FnKind;
-use rustc_hir::{Body, FnDecl, HirId, HirIdMap, HirIdSet, Impl, ItemKind, Mutability, Node, PatKind};
+use rustc_hir::intravisit::{walk_qpath, FnKind, Visitor};
+use rustc_hir::{Body, ExprKind, FnDecl, HirId, HirIdMap, HirIdSet, Impl, ItemKind, Mutability, Node, PatKind, QPath};
 use rustc_hir_typeck::expr_use_visitor as euv;
 use rustc_infer::infer::TyCtxtInferExt;
 use rustc_lint::{LateContext, LateLintPass};
+use rustc_middle::hir::map::associated_body;
+use rustc_middle::hir::nested_filter::OnlyBodies;
 use rustc_middle::mir::FakeReadCause;
-use rustc_middle::ty::{self, Ty};
+use rustc_middle::ty::{self, Ty, UpvarId, UpvarPath};
 use rustc_session::{declare_tool_lint, impl_lint_pass};
 use rustc_span::def_id::LocalDefId;
 use rustc_span::symbol::kw;
@@ -46,20 +48,24 @@ declare_clippy_lint! {
     "using a `&mut` argument when it's not mutated"
 }
 
-#[derive(Copy, Clone)]
-pub struct NeedlessPassByRefMut {
+#[derive(Clone)]
+pub struct NeedlessPassByRefMut<'tcx> {
     avoid_breaking_exported_api: bool,
+    used_fn_def_ids: FxHashSet<LocalDefId>,
+    fn_def_ids_to_maybe_unused_mut: FxIndexMap<LocalDefId, Vec<rustc_hir::Ty<'tcx>>>,
 }
 
-impl NeedlessPassByRefMut {
+impl NeedlessPassByRefMut<'_> {
     pub fn new(avoid_breaking_exported_api: bool) -> Self {
         Self {
             avoid_breaking_exported_api,
+            used_fn_def_ids: FxHashSet::default(),
+            fn_def_ids_to_maybe_unused_mut: FxIndexMap::default(),
         }
     }
 }
 
-impl_lint_pass!(NeedlessPassByRefMut => [NEEDLESS_PASS_BY_REF_MUT]);
+impl_lint_pass!(NeedlessPassByRefMut<'_> => [NEEDLESS_PASS_BY_REF_MUT]);
 
 fn should_skip<'tcx>(
     cx: &LateContext<'tcx>,
@@ -87,12 +93,12 @@ fn should_skip<'tcx>(
     is_from_proc_macro(cx, &input)
 }
 
-impl<'tcx> LateLintPass<'tcx> for NeedlessPassByRefMut {
+impl<'tcx> LateLintPass<'tcx> for NeedlessPassByRefMut<'tcx> {
     fn check_fn(
         &mut self,
         cx: &LateContext<'tcx>,
         kind: FnKind<'tcx>,
-        decl: &'tcx FnDecl<'_>,
+        decl: &'tcx FnDecl<'tcx>,
         body: &'tcx Body<'_>,
         span: Span,
         fn_def_id: LocalDefId,
@@ -102,17 +108,17 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessPassByRefMut {
         }
 
         let hir_id = cx.tcx.hir().local_def_id_to_hir_id(fn_def_id);
-
-        match kind {
+        let is_async = match kind {
             FnKind::ItemFn(.., header) => {
                 let attrs = cx.tcx.hir().attrs(hir_id);
                 if header.abi != Abi::Rust || requires_exact_signature(attrs) {
                     return;
                 }
+                header.is_async()
             },
-            FnKind::Method(..) => (),
+            FnKind::Method(.., sig) => sig.header.is_async(),
             FnKind::Closure => return,
-        }
+        };
 
         // Exclude non-inherent impls
         if let Some(Node::Item(item)) = cx.tcx.hir().find_parent(hir_id) {
@@ -124,67 +130,93 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessPassByRefMut {
             }
         }
 
-        let fn_sig = cx.tcx.fn_sig(fn_def_id).subst_identity();
+        let fn_sig = cx.tcx.fn_sig(fn_def_id).instantiate_identity();
         let fn_sig = cx.tcx.liberate_late_bound_regions(fn_def_id.to_def_id(), fn_sig);
 
         // If there are no `&mut` argument, no need to go any further.
-        if !decl
+        let mut it = decl
             .inputs
             .iter()
             .zip(fn_sig.inputs())
             .zip(body.params)
-            .any(|((&input, &ty), arg)| !should_skip(cx, input, ty, arg))
-        {
+            .filter(|((&input, &ty), arg)| !should_skip(cx, input, ty, arg))
+            .peekable();
+        if it.peek().is_none() {
             return;
         }
-
         // Collect variables mutably used and spans which will need dereferencings from the
         // function body.
         let MutablyUsedVariablesCtxt { mutably_used_vars, .. } = {
             let mut ctx = MutablyUsedVariablesCtxt::default();
             let infcx = cx.tcx.infer_ctxt().build();
             euv::ExprUseVisitor::new(&mut ctx, &infcx, fn_def_id, cx.param_env, cx.typeck_results()).consume_body(body);
+            if is_async {
+                let closures = ctx.async_closures.clone();
+                let hir = cx.tcx.hir();
+                for closure in closures {
+                    ctx.prev_bind = None;
+                    ctx.prev_move_to_closure.clear();
+                    if let Some(body) = hir
+                        .find_by_def_id(closure)
+                        .and_then(associated_body)
+                        .map(|(_, body_id)| hir.body(body_id))
+                    {
+                        euv::ExprUseVisitor::new(&mut ctx, &infcx, closure, cx.param_env, cx.typeck_results())
+                            .consume_body(body);
+                    }
+                }
+            }
             ctx
         };
-
-        let mut it = decl
-            .inputs
-            .iter()
-            .zip(fn_sig.inputs())
-            .zip(body.params)
-            .filter(|((&input, &ty), arg)| !should_skip(cx, input, ty, arg))
-            .peekable();
-        if it.peek().is_none() {
-            return;
-        }
-        let show_semver_warning = self.avoid_breaking_exported_api && cx.effective_visibilities.is_exported(fn_def_id);
         for ((&input, &_), arg) in it {
             // Only take `&mut` arguments.
-            if_chain! {
-                if let PatKind::Binding(_, canonical_id, ..) = arg.pat.kind;
-                if !mutably_used_vars.contains(&canonical_id);
-                if let rustc_hir::TyKind::Ref(_, inner_ty) = input.kind;
-                then {
-                    // If the argument is never used mutably, we emit the warning.
-                    let sp = input.span;
-                    span_lint_and_then(
+            if let PatKind::Binding(_, canonical_id, ..) = arg.pat.kind
+                && !mutably_used_vars.contains(&canonical_id)
+            {
+                self.fn_def_ids_to_maybe_unused_mut.entry(fn_def_id).or_default().push(input);
+            }
+        }
+    }
+
+    fn check_crate_post(&mut self, cx: &LateContext<'tcx>) {
+        cx.tcx.hir().visit_all_item_likes_in_crate(&mut FnNeedsMutVisitor {
+            cx,
+            used_fn_def_ids: &mut self.used_fn_def_ids,
+        });
+
+        for (fn_def_id, unused) in self
+            .fn_def_ids_to_maybe_unused_mut
+            .iter()
+            .filter(|(def_id, _)| !self.used_fn_def_ids.contains(def_id))
+        {
+            let show_semver_warning =
+                self.avoid_breaking_exported_api && cx.effective_visibilities.is_exported(*fn_def_id);
+
+            let mut is_cfged = None;
+            for input in unused {
+                // If the argument is never used mutably, we emit the warning.
+                let sp = input.span;
+                if let rustc_hir::TyKind::Ref(_, inner_ty) = input.kind {
+                    let is_cfged = is_cfged.get_or_insert_with(|| inherits_cfg(cx.tcx, *fn_def_id));
+                    span_lint_hir_and_then(
                         cx,
                         NEEDLESS_PASS_BY_REF_MUT,
+                        cx.tcx.hir().local_def_id_to_hir_id(*fn_def_id),
                         sp,
                         "this argument is a mutable reference, but not used mutably",
                         |diag| {
                             diag.span_suggestion(
                                 sp,
                                 "consider changing to".to_string(),
-                                format!(
-                                    "&{}",
-                                    snippet(cx, cx.tcx.hir().span(inner_ty.ty.hir_id), "_"),
-                                ),
+                                format!("&{}", snippet(cx, cx.tcx.hir().span(inner_ty.ty.hir_id), "_"),),
                                 Applicability::Unspecified,
                             );
                             if show_semver_warning {
                                 diag.warn("changing this function will impact semver compatibility");
                             }
+                            if *is_cfged {
+                                diag.note("this is cfg-gated and may require further changes");
+                            }
                         },
                     );
                 }
@@ -197,7 +229,9 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessPassByRefMut {
 struct MutablyUsedVariablesCtxt {
     mutably_used_vars: HirIdSet,
     prev_bind: Option<HirId>,
+    prev_move_to_closure: HirIdSet,
     aliases: HirIdMap<HirId>,
+    async_closures: FxHashSet<LocalDefId>,
 }
 
 impl MutablyUsedVariablesCtxt {
@@ -213,16 +247,27 @@ impl MutablyUsedVariablesCtxt {
 impl<'tcx> euv::Delegate<'tcx> for MutablyUsedVariablesCtxt {
     fn consume(&mut self, cmt: &euv::PlaceWithHirId<'tcx>, _id: HirId) {
         if let euv::Place {
-            base: euv::PlaceBase::Local(vid),
+            base:
+                euv::PlaceBase::Local(vid)
+                | euv::PlaceBase::Upvar(UpvarId {
+                    var_path: UpvarPath { hir_id: vid },
+                    ..
+                }),
             base_ty,
             ..
         } = &cmt.place
         {
             if let Some(bind_id) = self.prev_bind.take() {
-                self.aliases.insert(bind_id, *vid);
-            } else if matches!(base_ty.ref_mutability(), Some(Mutability::Mut)) {
+                if bind_id != *vid {
+                    self.aliases.insert(bind_id, *vid);
+                }
+            } else if !self.prev_move_to_closure.contains(vid)
+                && matches!(base_ty.ref_mutability(), Some(Mutability::Mut))
+            {
                 self.add_mutably_used_var(*vid);
             }
+            self.prev_bind = None;
+            self.prev_move_to_closure.remove(vid);
         }
     }
 
@@ -265,9 +310,73 @@ impl<'tcx> euv::Delegate<'tcx> for MutablyUsedVariablesCtxt {
         self.prev_bind = None;
     }
 
-    fn fake_read(&mut self, _: &rustc_hir_typeck::expr_use_visitor::PlaceWithHirId<'tcx>, _: FakeReadCause, _: HirId) {}
+    fn fake_read(
+        &mut self,
+        cmt: &rustc_hir_typeck::expr_use_visitor::PlaceWithHirId<'tcx>,
+        cause: FakeReadCause,
+        _id: HirId,
+    ) {
+        if let euv::Place {
+            base:
+                euv::PlaceBase::Upvar(UpvarId {
+                    var_path: UpvarPath { hir_id: vid },
+                    ..
+                }),
+            ..
+        } = &cmt.place
+        {
+            if let FakeReadCause::ForLet(Some(inner)) = cause {
+                // Seems like we are inside an async function. We need to store the closure `DefId`
+                // to go through it afterwards.
+                self.async_closures.insert(inner);
+                self.aliases.insert(cmt.hir_id, *vid);
+                self.prev_move_to_closure.insert(*vid);
+            }
+        }
+    }
 
     fn bind(&mut self, _cmt: &euv::PlaceWithHirId<'tcx>, id: HirId) {
         self.prev_bind = Some(id);
     }
 }
+
+/// A final pass to check for paths referencing this function that require the argument to be
+/// `&mut`, basically if the function is ever used as a `fn`-like argument.
+struct FnNeedsMutVisitor<'a, 'tcx> {
+    cx: &'a LateContext<'tcx>,
+    used_fn_def_ids: &'a mut FxHashSet<LocalDefId>,
+}
+
+impl<'tcx> Visitor<'tcx> for FnNeedsMutVisitor<'_, 'tcx> {
+    type NestedFilter = OnlyBodies;
+
+    fn nested_visit_map(&mut self) -> Self::Map {
+        self.cx.tcx.hir()
+    }
+
+    fn visit_qpath(&mut self, qpath: &'tcx QPath<'tcx>, hir_id: HirId, _: Span) {
+        walk_qpath(self, qpath, hir_id);
+
+        let Self { cx, used_fn_def_ids } = self;
+
+        // #11182; do not lint if mutability is required elsewhere
+        if let Node::Expr(expr) = cx.tcx.hir().get(hir_id)
+            && let Some(parent) = get_parent_node(cx.tcx, expr.hir_id)
+            && let ty::FnDef(def_id, _) = cx.tcx.typeck(cx.tcx.hir().enclosing_body_owner(hir_id)).expr_ty(expr).kind()
+            && let Some(def_id) = def_id.as_local()
+        {
+            if let Node::Expr(e) = parent
+                && let ExprKind::Call(call, _) = e.kind
+                && call.hir_id == expr.hir_id
+            {
+                return;
+            }
+
+            // We don't need to check each argument individually as you cannot coerce a function
+            // taking `&mut` -> `&`, for some reason, so if we've gotten this far we know it's
+            // passed as a `fn`-like argument (or is unified) and should ignore every "unused"
+            // argument entirely
+            used_fn_def_ids.insert(def_id);
+        }
+    }
+}
diff --git a/clippy_lints/src/needless_pass_by_value.rs b/clippy_lints/src/needless_pass_by_value.rs
index aee156c7691..5ee26966fa7 100644
--- a/clippy_lints/src/needless_pass_by_value.rs
+++ b/clippy_lints/src/needless_pass_by_value.rs
@@ -2,7 +2,7 @@ use clippy_utils::diagnostics::{multispan_sugg, span_lint_and_then};
 use clippy_utils::ptr::get_spans;
 use clippy_utils::source::{snippet, snippet_opt};
 use clippy_utils::ty::{
-    implements_trait, implements_trait_with_env, is_copy, is_type_diagnostic_item, is_type_lang_item,
+    implements_trait, implements_trait_with_env_from_iter, is_copy, is_type_diagnostic_item, is_type_lang_item,
 };
 use clippy_utils::{get_trait_def_id, is_self, paths};
 use if_chain::if_chain;
@@ -140,7 +140,7 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessPassByValue {
             ctx
         };
 
-        let fn_sig = cx.tcx.fn_sig(fn_def_id).subst_identity();
+        let fn_sig = cx.tcx.fn_sig(fn_def_id).instantiate_identity();
         let fn_sig = cx.tcx.liberate_late_bound_regions(fn_def_id.to_def_id(), fn_sig);
 
         for (idx, ((input, &ty), arg)) in decl.inputs.iter().zip(fn_sig.inputs()).zip(body.params).enumerate() {
@@ -170,7 +170,7 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessPassByValue {
                     !preds.is_empty() && {
                         let ty_empty_region = Ty::new_imm_ref(cx.tcx, cx.tcx.lifetimes.re_erased, ty);
                         preds.iter().all(|t| {
-                            let ty_params = t.trait_ref.substs.iter().skip(1).collect::<Vec<_>>();
+                            let ty_params = t.trait_ref.args.iter().skip(1).collect::<Vec<_>>();
                             implements_trait(cx, ty_empty_region, t.def_id(), &ty_params)
                         })
                     },
@@ -182,7 +182,13 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessPassByValue {
                 if !ty.is_mutable_ptr();
                 if !is_copy(cx, ty);
                 if ty.is_sized(cx.tcx, cx.param_env);
-                if !allowed_traits.iter().any(|&t| implements_trait_with_env(cx.tcx, cx.param_env, ty, t, [None]));
+                if !allowed_traits.iter().any(|&t| implements_trait_with_env_from_iter(
+                    cx.tcx,
+                    cx.param_env,
+                    ty,
+                    t,
+                    [Option::<ty::GenericArg<'tcx>>::None],
+                ));
                 if !implements_borrow_trait;
                 if !all_borrowable_trait;
 
diff --git a/clippy_lints/src/new_without_default.rs b/clippy_lints/src/new_without_default.rs
index 653b1a8a05f..cf7cd671dca 100644
--- a/clippy_lints/src/new_without_default.rs
+++ b/clippy_lints/src/new_without_default.rs
@@ -98,14 +98,14 @@ impl<'tcx> LateLintPass<'tcx> for NewWithoutDefault {
                             if name == sym::new;
                             if cx.effective_visibilities.is_reachable(impl_item.owner_id.def_id);
                             let self_def_id = cx.tcx.hir().get_parent_item(id.into());
-                            let self_ty = cx.tcx.type_of(self_def_id).subst_identity();
+                            let self_ty = cx.tcx.type_of(self_def_id).instantiate_identity();
                             if self_ty == return_ty(cx, id);
                             if let Some(default_trait_id) = cx.tcx.get_diagnostic_item(sym::Default);
                             then {
                                 if self.impling_types.is_none() {
                                     let mut impls = HirIdSet::default();
                                     cx.tcx.for_each_impl(default_trait_id, |d| {
-                                        let ty = cx.tcx.type_of(d).subst_identity();
+                                        let ty = cx.tcx.type_of(d).instantiate_identity();
                                         if let Some(ty_def) = ty.ty_adt_def() {
                                             if let Some(local_def_id) = ty_def.did().as_local() {
                                                 impls.insert(cx.tcx.hir().local_def_id_to_hir_id(local_def_id));
@@ -119,7 +119,7 @@ impl<'tcx> LateLintPass<'tcx> for NewWithoutDefault {
                                 // generics
                                 if_chain! {
                                     if let Some(ref impling_types) = self.impling_types;
-                                    let self_def = cx.tcx.type_of(self_def_id).subst_identity();
+                                    let self_def = cx.tcx.type_of(self_def_id).instantiate_identity();
                                     if let Some(self_def) = self_def.ty_adt_def();
                                     if let Some(self_local_did) = self_def.did().as_local();
                                     let self_id = cx.tcx.hir().local_def_id_to_hir_id(self_local_did);
diff --git a/clippy_lints/src/non_copy_const.rs b/clippy_lints/src/non_copy_const.rs
index e31fd20dfca..df87a6a0221 100644
--- a/clippy_lints/src/non_copy_const.rs
+++ b/clippy_lints/src/non_copy_const.rs
@@ -154,7 +154,7 @@ fn is_value_unfrozen_raw<'tcx>(
             ty::Adt(def, ..) if def.is_union() => false,
             ty::Array(ty, _) => val.unwrap_branch().iter().any(|field| inner(cx, *field, ty)),
             ty::Adt(def, _) if def.is_union() => false,
-            ty::Adt(def, substs) if def.is_enum() => {
+            ty::Adt(def, args) if def.is_enum() => {
                 let (&variant_index, fields) = val.unwrap_branch().split_first().unwrap();
                 let variant_index = VariantIdx::from_u32(variant_index.unwrap_leaf().try_to_u32().ok().unwrap());
                 fields
@@ -164,19 +164,14 @@ fn is_value_unfrozen_raw<'tcx>(
                         def.variants()[variant_index]
                             .fields
                             .iter()
-                            .map(|field| field.ty(cx.tcx, substs)),
+                            .map(|field| field.ty(cx.tcx, args)),
                     )
                     .any(|(field, ty)| inner(cx, field, ty))
             },
-            ty::Adt(def, substs) => val
+            ty::Adt(def, args) => val
                 .unwrap_branch()
                 .iter()
-                .zip(
-                    def.non_enum_variant()
-                        .fields
-                        .iter()
-                        .map(|field| field.ty(cx.tcx, substs)),
-                )
+                .zip(def.non_enum_variant().fields.iter().map(|field| field.ty(cx.tcx, args)))
                 .any(|(field, ty)| inner(cx, *field, ty)),
             ty::Tuple(tys) => val
                 .unwrap_branch()
@@ -217,8 +212,8 @@ fn is_value_unfrozen_raw<'tcx>(
 
 fn is_value_unfrozen_poly<'tcx>(cx: &LateContext<'tcx>, body_id: BodyId, ty: Ty<'tcx>) -> bool {
     let def_id = body_id.hir_id.owner.to_def_id();
-    let substs = ty::InternalSubsts::identity_for_item(cx.tcx, def_id);
-    let instance = ty::Instance::new(def_id, substs);
+    let args = ty::GenericArgs::identity_for_item(cx.tcx, def_id);
+    let instance = ty::Instance::new(def_id, args);
     let cid = rustc_middle::mir::interpret::GlobalId {
         instance,
         promoted: None,
@@ -229,9 +224,9 @@ fn is_value_unfrozen_poly<'tcx>(cx: &LateContext<'tcx>, body_id: BodyId, ty: Ty<
 }
 
 fn is_value_unfrozen_expr<'tcx>(cx: &LateContext<'tcx>, hir_id: HirId, def_id: DefId, ty: Ty<'tcx>) -> bool {
-    let substs = cx.typeck_results().node_substs(hir_id);
+    let args = cx.typeck_results().node_args(hir_id);
 
-    let result = const_eval_resolve(cx.tcx, cx.param_env, ty::UnevaluatedConst::new(def_id, substs), None);
+    let result = const_eval_resolve(cx.tcx, cx.param_env, ty::UnevaluatedConst::new(def_id, args), None);
     is_value_unfrozen_raw(cx, result, ty)
 }
 
@@ -241,7 +236,7 @@ pub fn const_eval_resolve<'tcx>(
     ct: ty::UnevaluatedConst<'tcx>,
     span: Option<Span>,
 ) -> EvalToValTreeResult<'tcx> {
-    match ty::Instance::resolve(tcx, param_env, ct.def, ct.substs) {
+    match ty::Instance::resolve(tcx, param_env, ct.def, ct.args) {
         Ok(Some(instance)) => {
             let cid = GlobalId {
                 instance,
@@ -363,7 +358,7 @@ impl<'tcx> LateLintPass<'tcx> for NonCopyConst {
                                 // and, in that case, the definition is *not* generic.
                                 cx.tcx.normalize_erasing_regions(
                                     cx.tcx.param_env(of_trait_def_id),
-                                    cx.tcx.type_of(of_assoc_item).subst_identity(),
+                                    cx.tcx.type_of(of_assoc_item).instantiate_identity(),
                                 ),
                             ))
                             .is_err();
diff --git a/clippy_lints/src/non_send_fields_in_send_ty.rs b/clippy_lints/src/non_send_fields_in_send_ty.rs
index 24875855de3..c5e777c2070 100644
--- a/clippy_lints/src/non_send_fields_in_send_ty.rs
+++ b/clippy_lints/src/non_send_fields_in_send_ty.rs
@@ -7,8 +7,7 @@ use rustc_hir::def_id::DefId;
 use rustc_hir::{FieldDef, Item, ItemKind, Node};
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_middle::lint::in_external_macro;
-use rustc_middle::ty::subst::GenericArgKind;
-use rustc_middle::ty::{self, Ty};
+use rustc_middle::ty::{self, GenericArgKind, Ty};
 use rustc_session::{declare_tool_lint, impl_lint_pass};
 use rustc_span::sym;
 
@@ -91,8 +90,8 @@ impl<'tcx> LateLintPass<'tcx> for NonSendFieldInSendTy {
             if send_trait == trait_id;
             if hir_impl.polarity == ImplPolarity::Positive;
             if let Some(ty_trait_ref) = cx.tcx.impl_trait_ref(item.owner_id);
-            if let self_ty = ty_trait_ref.subst_identity().self_ty();
-            if let ty::Adt(adt_def, impl_trait_substs) = self_ty.kind();
+            if let self_ty = ty_trait_ref.instantiate_identity().self_ty();
+            if let ty::Adt(adt_def, impl_trait_args) = self_ty.kind();
             then {
                 let mut non_send_fields = Vec::new();
 
@@ -105,7 +104,7 @@ impl<'tcx> LateLintPass<'tcx> for NonSendFieldInSendTy {
                                 .as_local()
                                 .map(|local_def_id| hir_map.local_def_id_to_hir_id(local_def_id));
                             if !is_lint_allowed(cx, NON_SEND_FIELDS_IN_SEND_TY, field_hir_id);
-                            if let field_ty = field.ty(cx.tcx, impl_trait_substs);
+                            if let field_ty = field.ty(cx.tcx, impl_trait_args);
                             if !ty_allowed_in_send(cx, field_ty, send_trait);
                             if let Node::Field(field_def) = hir_map.get(field_hir_id);
                             then {
@@ -207,10 +206,10 @@ fn ty_allowed_with_raw_pointer_heuristic<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'t
             .iter()
             .all(|ty| ty_allowed_with_raw_pointer_heuristic(cx, ty, send_trait)),
         ty::Array(ty, _) | ty::Slice(ty) => ty_allowed_with_raw_pointer_heuristic(cx, *ty, send_trait),
-        ty::Adt(_, substs) => {
+        ty::Adt(_, args) => {
             if contains_pointer_like(cx, ty) {
                 // descends only if ADT contains any raw pointers
-                substs.iter().all(|generic_arg| match generic_arg.unpack() {
+                args.iter().all(|generic_arg| match generic_arg.unpack() {
                     GenericArgKind::Type(ty) => ty_allowed_with_raw_pointer_heuristic(cx, ty, send_trait),
                     // Lifetimes and const generics are not solid part of ADT and ignored
                     GenericArgKind::Lifetime(_) | GenericArgKind::Const(_) => true,
@@ -225,7 +224,7 @@ fn ty_allowed_with_raw_pointer_heuristic<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'t
     }
 }
 
-/// Checks if the type contains any pointer-like types in substs (including nested ones)
+/// Checks if the type contains any pointer-like types in args (including nested ones)
 fn contains_pointer_like<'tcx>(cx: &LateContext<'tcx>, target_ty: Ty<'tcx>) -> bool {
     for ty_node in target_ty.walk() {
         if let GenericArgKind::Type(inner_ty) = ty_node.unpack() {
diff --git a/clippy_lints/src/only_used_in_recursion.rs b/clippy_lints/src/only_used_in_recursion.rs
index 8b77a5c99f7..3dc652f9dc0 100644
--- a/clippy_lints/src/only_used_in_recursion.rs
+++ b/clippy_lints/src/only_used_in_recursion.rs
@@ -7,8 +7,7 @@ use rustc_hir::def_id::DefId;
 use rustc_hir::hir_id::HirIdMap;
 use rustc_hir::{Body, Expr, ExprKind, HirId, ImplItem, ImplItemKind, Node, PatKind, TraitItem, TraitItemKind};
 use rustc_lint::{LateContext, LateLintPass};
-use rustc_middle::ty::subst::{EarlyBinder, GenericArgKind, SubstsRef};
-use rustc_middle::ty::{self, ConstKind};
+use rustc_middle::ty::{self, ConstKind, EarlyBinder, GenericArgKind, GenericArgsRef};
 use rustc_session::{declare_tool_lint, impl_lint_pass};
 use rustc_span::symbol::{kw, Ident};
 use rustc_span::Span;
@@ -90,7 +89,7 @@ impl_lint_pass!(OnlyUsedInRecursion => [ONLY_USED_IN_RECURSION]);
 enum FnKind {
     Fn,
     TraitFn,
-    // This is a hack. Ideally we would store a `SubstsRef<'tcx>` type here, but a lint pass must be `'static`.
+    // This is a hack. Ideally we would store a `GenericArgsRef<'tcx>` type here, but a lint pass must be `'static`.
     // Substitutions are, however, interned. This allows us to store the pointer as a `usize` when comparing for
     // equality.
     ImplTraitFn(usize),
@@ -244,12 +243,12 @@ impl<'tcx> LateLintPass<'tcx> for OnlyUsedInRecursion {
             })) => {
                 #[allow(trivial_casts)]
                 if let Some(Node::Item(item)) = get_parent_node(cx.tcx, owner_id.into())
-                    && let Some(trait_ref) = cx.tcx.impl_trait_ref(item.owner_id).map(EarlyBinder::subst_identity)
+                    && let Some(trait_ref) = cx.tcx.impl_trait_ref(item.owner_id).map(EarlyBinder::instantiate_identity)
                     && let Some(trait_item_id) = cx.tcx.associated_item(owner_id).trait_item_def_id
                 {
                     (
                         trait_item_id,
-                        FnKind::ImplTraitFn(cx.tcx.erase_regions(trait_ref.substs) as *const _ as usize),
+                        FnKind::ImplTraitFn(cx.tcx.erase_regions(trait_ref.args) as *const _ as usize),
                         usize::from(sig.decl.implicit_self.has_implicit_self()),
                     )
                 } else {
@@ -289,7 +288,7 @@ impl<'tcx> LateLintPass<'tcx> for OnlyUsedInRecursion {
                         ExprKind::Call(callee, args)
                             if path_def_id(cx, callee).map_or(false, |id| {
                                 id == param.fn_id
-                                    && has_matching_substs(param.fn_kind, typeck.node_substs(callee.hir_id))
+                                    && has_matching_args(param.fn_kind, typeck.node_args(callee.hir_id))
                             }) =>
                         {
                             if let Some(idx) = args.iter().position(|arg| arg.hir_id == child_id) {
@@ -300,7 +299,7 @@ impl<'tcx> LateLintPass<'tcx> for OnlyUsedInRecursion {
                         ExprKind::MethodCall(_, receiver, args, _)
                             if typeck.type_dependent_def_id(parent.hir_id).map_or(false, |id| {
                                 id == param.fn_id
-                                    && has_matching_substs(param.fn_kind, typeck.node_substs(parent.hir_id))
+                                    && has_matching_args(param.fn_kind, typeck.node_args(parent.hir_id))
                             }) =>
                         {
                             if let Some(idx) = iter::once(receiver).chain(args).position(|arg| arg.hir_id == child_id) {
@@ -381,15 +380,15 @@ impl<'tcx> LateLintPass<'tcx> for OnlyUsedInRecursion {
     }
 }
 
-fn has_matching_substs(kind: FnKind, substs: SubstsRef<'_>) -> bool {
+fn has_matching_args(kind: FnKind, args: GenericArgsRef<'_>) -> bool {
     match kind {
         FnKind::Fn => true,
-        FnKind::TraitFn => substs.iter().enumerate().all(|(idx, subst)| match subst.unpack() {
+        FnKind::TraitFn => args.iter().enumerate().all(|(idx, subst)| match subst.unpack() {
             GenericArgKind::Lifetime(_) => true,
             GenericArgKind::Type(ty) => matches!(*ty.kind(), ty::Param(ty) if ty.index as usize == idx),
             GenericArgKind::Const(c) => matches!(c.kind(), ConstKind::Param(c) if c.index as usize == idx),
         }),
         #[allow(trivial_casts)]
-        FnKind::ImplTraitFn(expected_substs) => substs as *const _ as usize == expected_substs,
+        FnKind::ImplTraitFn(expected_args) => args as *const _ as usize == expected_args,
     }
 }
diff --git a/clippy_lints/src/operators/arithmetic_side_effects.rs b/clippy_lints/src/operators/arithmetic_side_effects.rs
index 35dd8fabe6e..f9108145cdb 100644
--- a/clippy_lints/src/operators/arithmetic_side_effects.rs
+++ b/clippy_lints/src/operators/arithmetic_side_effects.rs
@@ -1,7 +1,7 @@
 use super::ARITHMETIC_SIDE_EFFECTS;
 use clippy_utils::consts::{constant, constant_simple, Constant};
 use clippy_utils::diagnostics::span_lint;
-use clippy_utils::{is_from_proc_macro, is_lint_allowed, peel_hir_expr_refs, peel_hir_expr_unary};
+use clippy_utils::{expr_or_init, is_from_proc_macro, is_lint_allowed, peel_hir_expr_refs, peel_hir_expr_unary};
 use rustc_data_structures::fx::{FxHashMap, FxHashSet};
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_middle::ty::Ty;
@@ -138,8 +138,10 @@ impl ArithmeticSideEffects {
         ) {
             return;
         };
-        let (actual_lhs, lhs_ref_counter) = peel_hir_expr_refs(lhs);
-        let (actual_rhs, rhs_ref_counter) = peel_hir_expr_refs(rhs);
+        let (mut actual_lhs, lhs_ref_counter) = peel_hir_expr_refs(lhs);
+        let (mut actual_rhs, rhs_ref_counter) = peel_hir_expr_refs(rhs);
+        actual_lhs = expr_or_init(cx, actual_lhs);
+        actual_rhs = expr_or_init(cx, actual_rhs);
         let lhs_ty = cx.typeck_results().expr_ty(actual_lhs).peel_refs();
         let rhs_ty = cx.typeck_results().expr_ty(actual_rhs).peel_refs();
         if self.has_allowed_binary(lhs_ty, rhs_ty) {
diff --git a/clippy_lints/src/operators/const_comparisons.rs b/clippy_lints/src/operators/const_comparisons.rs
new file mode 100644
index 00000000000..abe8df19543
--- /dev/null
+++ b/clippy_lints/src/operators/const_comparisons.rs
@@ -0,0 +1,207 @@
+#![allow(clippy::match_same_arms)]
+
+use std::cmp::Ordering;
+
+use clippy_utils::consts::{constant, Constant};
+use if_chain::if_chain;
+use rustc_hir::{BinOpKind, Expr, ExprKind};
+use rustc_lint::LateContext;
+use rustc_middle::ty::layout::HasTyCtxt;
+use rustc_middle::ty::{Ty, TypeckResults};
+use rustc_span::source_map::{Span, Spanned};
+
+use clippy_utils::diagnostics::span_lint_and_note;
+use clippy_utils::source::snippet;
+use clippy_utils::SpanlessEq;
+
+use super::{IMPOSSIBLE_COMPARISONS, REDUNDANT_COMPARISONS};
+
+// Extract a comparison between a const and non-const
+// Flip yoda conditionals, turnings expressions like `42 < x` into `x > 42`
+fn comparison_to_const<'tcx>(
+    cx: &LateContext<'tcx>,
+    typeck: &TypeckResults<'tcx>,
+    expr: &'tcx Expr<'tcx>,
+) -> Option<(CmpOp, &'tcx Expr<'tcx>, &'tcx Expr<'tcx>, Constant<'tcx>, Ty<'tcx>)> {
+    if_chain! {
+        if let ExprKind::Binary(operator, left, right) = expr.kind;
+        if let Ok(cmp_op) = CmpOp::try_from(operator.node);
+        then {
+            match (constant(cx, typeck, left), constant(cx, typeck, right)) {
+                (Some(_), Some(_)) => None,
+                (_, Some(con)) => Some((cmp_op, left, right, con, typeck.expr_ty(right))),
+                (Some(con), _) => Some((cmp_op.reverse(), right, left, con, typeck.expr_ty(left))),
+                _ => None,
+            }
+        } else {
+            None
+        }
+    }
+}
+
+pub(super) fn check<'tcx>(
+    cx: &LateContext<'tcx>,
+    and_op: Spanned<BinOpKind>,
+    left_cond: &'tcx Expr<'tcx>,
+    right_cond: &'tcx Expr<'tcx>,
+    span: Span,
+) {
+    if_chain! {
+        // Ensure that the binary operator is &&
+        if and_op.node == BinOpKind::And;
+
+        // Check that both operands to '&&' are themselves a binary operation
+        // The `comparison_to_const` step also checks this, so this step is just an optimization
+        if let ExprKind::Binary(_, _, _) = left_cond.kind;
+        if let ExprKind::Binary(_, _, _) = right_cond.kind;
+
+        let typeck = cx.typeck_results();
+
+        // Check that both operands to '&&' compare a non-literal to a literal
+        if let Some((left_cmp_op, left_expr, left_const_expr, left_const, left_type)) =
+            comparison_to_const(cx, typeck, left_cond);
+        if let Some((right_cmp_op, right_expr, right_const_expr, right_const, right_type)) =
+            comparison_to_const(cx, typeck, right_cond);
+
+        if left_type == right_type;
+
+        // Check that the same expression is compared in both comparisons
+        if SpanlessEq::new(cx).eq_expr(left_expr, right_expr);
+
+        if !left_expr.can_have_side_effects();
+
+        // Compare the two constant expressions
+        if let Some(ordering) = Constant::partial_cmp(cx.tcx(), left_type, &left_const, &right_const);
+
+        // Rule out the `x >= 42 && x <= 42` corner case immediately
+        // Mostly to simplify the implementation, but it is also covered by `clippy::double_comparisons`
+        if !matches!(
+            (&left_cmp_op, &right_cmp_op, ordering),
+            (CmpOp::Le | CmpOp::Ge, CmpOp::Le | CmpOp::Ge, Ordering::Equal)
+        );
+
+        then {
+            if left_cmp_op.direction() == right_cmp_op.direction() {
+                let lhs_str = snippet(cx, left_cond.span, "<lhs>");
+                let rhs_str = snippet(cx, right_cond.span, "<rhs>");
+                // We already know that either side of `&&` has no effect,
+                // but emit a different error message depending on which side it is
+                if left_side_is_useless(left_cmp_op, ordering) {
+                    span_lint_and_note(
+                        cx,
+                        REDUNDANT_COMPARISONS,
+                        span,
+                        "left-hand side of `&&` operator has no effect",
+                        Some(left_cond.span.until(right_cond.span)),
+                        &format!("`if `{rhs_str}` evaluates to true, {lhs_str}` will always evaluate to true as well"),
+                    );
+                } else {
+                    span_lint_and_note(
+                        cx,
+                        REDUNDANT_COMPARISONS,
+                        span,
+                        "right-hand side of `&&` operator has no effect",
+                        Some(and_op.span.to(right_cond.span)),
+                        &format!("`if `{lhs_str}` evaluates to true, {rhs_str}` will always evaluate to true as well"),
+                    );
+                }
+                // We could autofix this error but choose not to,
+                // because code triggering this lint probably not behaving correctly in the first place
+            }
+            else if !comparison_is_possible(left_cmp_op.direction(), ordering) {
+                let expr_str = snippet(cx, left_expr.span, "..");
+                let lhs_str = snippet(cx, left_const_expr.span, "<lhs>");
+                let rhs_str = snippet(cx, right_const_expr.span, "<rhs>");
+                let note = match ordering {
+                    Ordering::Less => format!("since `{lhs_str}` < `{rhs_str}`, the expression evaluates to false for any value of `{expr_str}`"),
+                    Ordering::Equal => format!("`{expr_str}` cannot simultaneously be greater than and less than `{lhs_str}`"),
+                    Ordering::Greater => format!("since `{lhs_str}` > `{rhs_str}`, the expression evaluates to false for any value of `{expr_str}`"),
+                };
+                span_lint_and_note(
+                    cx,
+                    IMPOSSIBLE_COMPARISONS,
+                    span,
+                    "boolean expression will never evaluate to 'true'",
+                    None,
+                    &note,
+                );
+            };
+        }
+    }
+}
+
+fn left_side_is_useless(left_cmp_op: CmpOp, ordering: Ordering) -> bool {
+    // Special-case for equal constants with an inclusive comparison
+    if ordering == Ordering::Equal {
+        match left_cmp_op {
+            CmpOp::Lt | CmpOp::Gt => false,
+            CmpOp::Le | CmpOp::Ge => true,
+        }
+    } else {
+        match (left_cmp_op.direction(), ordering) {
+            (CmpOpDirection::Lesser, Ordering::Less) => false,
+            (CmpOpDirection::Lesser, Ordering::Equal) => false,
+            (CmpOpDirection::Lesser, Ordering::Greater) => true,
+            (CmpOpDirection::Greater, Ordering::Less) => true,
+            (CmpOpDirection::Greater, Ordering::Equal) => false,
+            (CmpOpDirection::Greater, Ordering::Greater) => false,
+        }
+    }
+}
+
+fn comparison_is_possible(left_cmp_direction: CmpOpDirection, ordering: Ordering) -> bool {
+    match (left_cmp_direction, ordering) {
+        (CmpOpDirection::Lesser, Ordering::Less | Ordering::Equal) => false,
+        (CmpOpDirection::Lesser, Ordering::Greater) => true,
+        (CmpOpDirection::Greater, Ordering::Greater | Ordering::Equal) => false,
+        (CmpOpDirection::Greater, Ordering::Less) => true,
+    }
+}
+
+#[derive(PartialEq, Eq, Clone, Copy)]
+enum CmpOpDirection {
+    Lesser,
+    Greater,
+}
+
+#[derive(Clone, Copy)]
+enum CmpOp {
+    Lt,
+    Le,
+    Ge,
+    Gt,
+}
+
+impl CmpOp {
+    fn reverse(self) -> Self {
+        match self {
+            CmpOp::Lt => CmpOp::Gt,
+            CmpOp::Le => CmpOp::Ge,
+            CmpOp::Ge => CmpOp::Le,
+            CmpOp::Gt => CmpOp::Lt,
+        }
+    }
+
+    fn direction(self) -> CmpOpDirection {
+        match self {
+            CmpOp::Lt => CmpOpDirection::Lesser,
+            CmpOp::Le => CmpOpDirection::Lesser,
+            CmpOp::Ge => CmpOpDirection::Greater,
+            CmpOp::Gt => CmpOpDirection::Greater,
+        }
+    }
+}
+
+impl TryFrom<BinOpKind> for CmpOp {
+    type Error = ();
+
+    fn try_from(bin_op: BinOpKind) -> Result<Self, Self::Error> {
+        match bin_op {
+            BinOpKind::Lt => Ok(CmpOp::Lt),
+            BinOpKind::Le => Ok(CmpOp::Le),
+            BinOpKind::Ge => Ok(CmpOp::Ge),
+            BinOpKind::Gt => Ok(CmpOp::Gt),
+            _ => Err(()),
+        }
+    }
+}
diff --git a/clippy_lints/src/operators/mod.rs b/clippy_lints/src/operators/mod.rs
index 2cf15adda01..4635e1164cd 100644
--- a/clippy_lints/src/operators/mod.rs
+++ b/clippy_lints/src/operators/mod.rs
@@ -2,6 +2,7 @@ mod absurd_extreme_comparisons;
 mod assign_op_pattern;
 mod bit_mask;
 mod cmp_owned;
+mod const_comparisons;
 mod double_comparison;
 mod duration_subsec;
 mod eq_op;
@@ -300,6 +301,45 @@ declare_clippy_lint! {
 
 declare_clippy_lint! {
     /// ### What it does
+    /// Checks for double comparisons that can never succeed
+    ///
+    /// ### Why is this bad?
+    /// The whole expression can be replaced by `false`,
+    /// which is probably not the programmer's intention
+    ///
+    /// ### Example
+    /// ```rust
+    /// # let status_code = 200;
+    /// if status_code <= 400 && status_code > 500 {}
+    /// ```
+    #[clippy::version = "1.71.0"]
+    pub IMPOSSIBLE_COMPARISONS,
+    correctness,
+    "double comparisons that will never evaluate to `true`"
+}
+
+declare_clippy_lint! {
+    /// ### What it does
+    /// Checks for ineffective double comparisons against constants.
+    ///
+    /// ### Why is this bad?
+    /// Only one of the comparisons has any effect on the result, the programmer
+    /// probably intended to flip one of the comparison operators, or compare a
+    /// different value entirely.
+    ///
+    /// ### Example
+    /// ```rust
+    /// # let status_code = 200;
+    /// if status_code <= 400 && status_code < 500 {}
+    /// ```
+    #[clippy::version = "1.71.0"]
+    pub REDUNDANT_COMPARISONS,
+    correctness,
+    "double comparisons where one of them can be removed"
+}
+
+declare_clippy_lint! {
+    /// ### What it does
     /// Checks for calculation of subsecond microseconds or milliseconds
     /// from other `Duration` methods.
     ///
@@ -742,6 +782,8 @@ impl_lint_pass!(Operators => [
     INEFFECTIVE_BIT_MASK,
     VERBOSE_BIT_MASK,
     DOUBLE_COMPARISONS,
+    IMPOSSIBLE_COMPARISONS,
+    REDUNDANT_COMPARISONS,
     DURATION_SUBSEC,
     EQ_OP,
     OP_REF,
@@ -786,6 +828,7 @@ impl<'tcx> LateLintPass<'tcx> for Operators {
                 bit_mask::check(cx, e, op.node, lhs, rhs);
                 verbose_bit_mask::check(cx, e, op.node, lhs, rhs, self.verbose_bit_mask_threshold);
                 double_comparison::check(cx, op.node, lhs, rhs, e.span);
+                const_comparisons::check(cx, op, lhs, rhs, e.span);
                 duration_subsec::check(cx, e, op.node, lhs, rhs);
                 float_equality_without_abs::check(cx, e, op.node, lhs, rhs);
                 integer_division::check(cx, e, op.node, lhs, rhs);
diff --git a/clippy_lints/src/option_env_unwrap.rs b/clippy_lints/src/option_env_unwrap.rs
index 377bddeaa5f..9c7f7e1cd7f 100644
--- a/clippy_lints/src/option_env_unwrap.rs
+++ b/clippy_lints/src/option_env_unwrap.rs
@@ -1,10 +1,9 @@
 use clippy_utils::diagnostics::span_lint_and_help;
 use clippy_utils::is_direct_expn_of;
-use if_chain::if_chain;
 use rustc_ast::ast::{Expr, ExprKind, MethodCall};
 use rustc_lint::{EarlyContext, EarlyLintPass};
 use rustc_session::{declare_lint_pass, declare_tool_lint};
-use rustc_span::sym;
+use rustc_span::{sym, Span};
 
 declare_clippy_lint! {
     /// ### What it does
@@ -36,21 +35,27 @@ declare_lint_pass!(OptionEnvUnwrap => [OPTION_ENV_UNWRAP]);
 
 impl EarlyLintPass for OptionEnvUnwrap {
     fn check_expr(&mut self, cx: &EarlyContext<'_>, expr: &Expr) {
-        if_chain! {
-            if let ExprKind::MethodCall(box MethodCall { seg, receiver, .. }) = &expr.kind;
-            if matches!(seg.ident.name, sym::expect | sym::unwrap);
-            if let ExprKind::Call(caller, _) = &receiver.kind;
-            if is_direct_expn_of(caller.span, "option_env").is_some();
-            then {
-                span_lint_and_help(
-                    cx,
-                    OPTION_ENV_UNWRAP,
-                    expr.span,
-                    "this will panic at run-time if the environment variable doesn't exist at compile-time",
-                    None,
-                    "consider using the `env!` macro instead"
-                );
-            }
+        fn lint(cx: &EarlyContext<'_>, span: Span) {
+            span_lint_and_help(
+                cx,
+                OPTION_ENV_UNWRAP,
+                span,
+                "this will panic at run-time if the environment variable doesn't exist at compile-time",
+                None,
+                "consider using the `env!` macro instead",
+            );
         }
+
+        if let ExprKind::MethodCall(box MethodCall { seg, receiver, .. }) = &expr.kind &&
+		matches!(seg.ident.name, sym::expect | sym::unwrap) {
+			if let ExprKind::Call(caller, _) = &receiver.kind &&
+            // If it exists, it will be ::core::option::Option::Some("<env var>").unwrap() (A method call in the HIR)
+            is_direct_expn_of(caller.span, "option_env").is_some() {
+				lint(cx, expr.span);
+			} else if let ExprKind::Path(_, caller) = &receiver.kind && // If it doesn't exist, it will be ::core::option::Option::None::<&'static str>.unwrap() (A path in the HIR)
+            is_direct_expn_of(caller.span, "option_env").is_some() {
+				lint(cx, expr.span);
+			}
+		}
     }
 }
diff --git a/clippy_lints/src/option_if_let_else.rs b/clippy_lints/src/option_if_let_else.rs
index 40da002f4ff..a7a7f4fd8fa 100644
--- a/clippy_lints/src/option_if_let_else.rs
+++ b/clippy_lints/src/option_if_let_else.rs
@@ -155,7 +155,7 @@ fn try_get_option_occurrence<'tcx>(
                 });
                 if let ExprKind::Path(QPath::Resolved(None, Path { res: Res::Local(local_id), .. })) = e.kind {
                     match some_captures.get(local_id)
-                        .or_else(|| (method_sugg == "map_or_else").then_some(()).and_then(|_| none_captures.get(local_id)))
+                        .or_else(|| (method_sugg == "map_or_else").then_some(()).and_then(|()| none_captures.get(local_id)))
                     {
                         Some(CaptureKind::Value | CaptureKind::Ref(Mutability::Mut)) => return None,
                         Some(CaptureKind::Ref(Mutability::Not)) if as_mut => return None,
diff --git a/clippy_lints/src/pass_by_ref_or_value.rs b/clippy_lints/src/pass_by_ref_or_value.rs
index d20ea7245c1..41513647f05 100644
--- a/clippy_lints/src/pass_by_ref_or_value.rs
+++ b/clippy_lints/src/pass_by_ref_or_value.rs
@@ -142,7 +142,7 @@ impl<'tcx> PassByRefOrValue {
             return;
         }
 
-        let fn_sig = cx.tcx.fn_sig(def_id).subst_identity();
+        let fn_sig = cx.tcx.fn_sig(def_id).instantiate_identity();
         let fn_body = cx.enclosing_body.map(|id| cx.tcx.hir().body(id));
 
         // Gather all the lifetimes found in the output type which may affect whether
diff --git a/clippy_lints/src/ptr.rs b/clippy_lints/src/ptr.rs
index 82a55166aea..42299d8d42f 100644
--- a/clippy_lints/src/ptr.rs
+++ b/clippy_lints/src/ptr.rs
@@ -26,6 +26,7 @@ use rustc_session::{declare_lint_pass, declare_tool_lint};
 use rustc_span::source_map::Span;
 use rustc_span::sym;
 use rustc_span::symbol::Symbol;
+use rustc_target::spec::abi::Abi;
 use rustc_trait_selection::infer::InferCtxtExt as _;
 use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt as _;
 use std::{fmt, iter};
@@ -163,9 +164,19 @@ impl<'tcx> LateLintPass<'tcx> for Ptr {
             }
 
             check_mut_from_ref(cx, sig, None);
+
+            if !matches!(sig.header.abi, Abi::Rust) {
+                // Ignore `extern` functions with non-Rust calling conventions
+                return;
+            }
+
             for arg in check_fn_args(
                 cx,
-                cx.tcx.fn_sig(item.owner_id).subst_identity().skip_binder().inputs(),
+                cx.tcx
+                    .fn_sig(item.owner_id)
+                    .instantiate_identity()
+                    .skip_binder()
+                    .inputs(),
                 sig.decl.inputs,
                 &sig.decl.output,
                 &[],
@@ -218,8 +229,14 @@ impl<'tcx> LateLintPass<'tcx> for Ptr {
         };
 
         check_mut_from_ref(cx, sig, Some(body));
+
+        if !matches!(sig.header.abi, Abi::Rust) {
+            // Ignore `extern` functions with non-Rust calling conventions
+            return;
+        }
+
         let decl = sig.decl;
-        let sig = cx.tcx.fn_sig(item_id).subst_identity().skip_binder();
+        let sig = cx.tcx.fn_sig(item_id).instantiate_identity().skip_binder();
         let lint_args: Vec<_> = check_fn_args(cx, sig.inputs(), decl.inputs, &decl.output, body.params)
             .filter(|arg| !is_trait_item || arg.mutability() == Mutability::Not)
             .collect();
@@ -423,7 +440,7 @@ fn check_fn_args<'cx, 'tcx: 'cx>(
         .enumerate()
         .filter_map(move |(i, (ty, hir_ty))| {
             if let ty::Ref(_, ty, mutability) = *ty.kind()
-                && let  ty::Adt(adt, substs) = *ty.kind()
+                && let  ty::Adt(adt, args) = *ty.kind()
                 && let TyKind::Ref(lt, ref ty) = hir_ty.kind
                 && let TyKind::Path(QPath::Resolved(None, path)) = ty.ty.kind
                 // Check that the name as typed matches the actual name of the type.
@@ -443,7 +460,7 @@ fn check_fn_args<'cx, 'tcx: 'cx>(
                                     } else {
                                         None
                                     }),
-                                substs.type_at(0),
+                                args.type_at(0),
                             ),
                         ),
                         _ if Some(adt.did()) == cx.tcx.lang_items().string() => (
@@ -496,7 +513,7 @@ fn check_fn_args<'cx, 'tcx: 'cx>(
                                 }
 
                                 let ty_name =
-                                    snippet_opt(cx, ty.span()).unwrap_or_else(|| substs.type_at(1).to_string());
+                                    snippet_opt(cx, ty.span()).unwrap_or_else(|| args.type_at(1).to_string());
 
                                 span_lint_hir_and_then(
                                     cx,
@@ -659,7 +676,7 @@ fn check_ptr_arg_usage<'tcx>(cx: &LateContext<'tcx>, body: &'tcx Body<'_>, args:
                             return;
                         };
 
-                        match *self.cx.tcx.fn_sig(id).subst_identity().skip_binder().inputs()[i]
+                        match *self.cx.tcx.fn_sig(id).instantiate_identity().skip_binder().inputs()[i]
                             .peel_refs()
                             .kind()
                         {
@@ -725,7 +742,7 @@ fn matches_preds<'tcx>(
     let infcx = cx.tcx.infer_ctxt().build();
     preds.iter().all(|&p| match cx.tcx.erase_late_bound_regions(p) {
         ExistentialPredicate::Trait(p) => infcx
-            .type_implements_trait(p.def_id, [ty.into()].into_iter().chain(p.substs.iter()), cx.param_env)
+            .type_implements_trait(p.def_id, [ty.into()].into_iter().chain(p.args.iter()), cx.param_env)
             .must_apply_modulo_regions(),
         ExistentialPredicate::Projection(p) => infcx.predicate_must_hold_modulo_regions(&Obligation::new(
             cx.tcx,
diff --git a/clippy_lints/src/question_mark.rs b/clippy_lints/src/question_mark.rs
index f5502cffb66..734ca2914f5 100644
--- a/clippy_lints/src/question_mark.rs
+++ b/clippy_lints/src/question_mark.rs
@@ -1,11 +1,13 @@
 use crate::manual_let_else::{MatchLintBehaviour, MANUAL_LET_ELSE};
+use crate::question_mark_used::QUESTION_MARK_USED;
 use clippy_utils::diagnostics::span_lint_and_sugg;
 use clippy_utils::msrvs::Msrv;
 use clippy_utils::source::snippet_with_applicability;
 use clippy_utils::ty::is_type_diagnostic_item;
 use clippy_utils::{
-    eq_expr_value, get_parent_node, higher, in_constant, is_else_clause, is_path_lang_item, is_res_lang_ctor,
-    pat_and_expr_can_be_question_mark, path_to_local, path_to_local_id, peel_blocks, peel_blocks_with_stmt,
+    eq_expr_value, get_parent_node, higher, in_constant, is_else_clause, is_lint_allowed, is_path_lang_item,
+    is_res_lang_ctor, pat_and_expr_can_be_question_mark, path_to_local, path_to_local_id, peel_blocks,
+    peel_blocks_with_stmt,
 };
 use if_chain::if_chain;
 use rustc_errors::Applicability;
@@ -299,13 +301,17 @@ fn is_try_block(cx: &LateContext<'_>, bl: &rustc_hir::Block<'_>) -> bool {
 
 impl<'tcx> LateLintPass<'tcx> for QuestionMark {
     fn check_stmt(&mut self, cx: &LateContext<'tcx>, stmt: &'tcx Stmt<'_>) {
+        if !is_lint_allowed(cx, QUESTION_MARK_USED, stmt.hir_id) {
+            return;
+        }
+
         if !in_constant(cx, stmt.hir_id) {
             check_let_some_else_return_none(cx, stmt);
         }
         self.check_manual_let_else(cx, stmt);
     }
     fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
-        if !in_constant(cx, expr.hir_id) {
+        if !in_constant(cx, expr.hir_id) && is_lint_allowed(cx, QUESTION_MARK_USED, expr.hir_id) {
             self.check_is_none_or_err_and_early_return(cx, expr);
             self.check_if_let_some_or_err_and_early_return(cx, expr);
         }
diff --git a/clippy_lints/src/redundant_locals.rs b/clippy_lints/src/redundant_locals.rs
new file mode 100644
index 00000000000..140ae837a17
--- /dev/null
+++ b/clippy_lints/src/redundant_locals.rs
@@ -0,0 +1,103 @@
+use clippy_utils::diagnostics::span_lint_and_help;
+use clippy_utils::is_from_proc_macro;
+use clippy_utils::ty::needs_ordered_drop;
+use rustc_hir::def::Res;
+use rustc_hir::{BindingAnnotation, ByRef, Expr, ExprKind, HirId, Local, Node, Pat, PatKind, QPath};
+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::symbol::Ident;
+
+declare_clippy_lint! {
+    /// ### What it does
+    /// Checks for redundant redefinitions of local bindings.
+    ///
+    /// ### Why is this bad?
+    /// Redundant redefinitions of local bindings do not change behavior and are likely to be unintended.
+    ///
+    /// Note that although these bindings do not affect your code's meaning, they _may_ affect `rustc`'s stack allocation.
+    ///
+    /// ### Example
+    /// ```rust
+    /// let a = 0;
+    /// let a = a;
+    ///
+    /// fn foo(b: i32) {
+    ///    let b = b;
+    /// }
+    /// ```
+    /// Use instead:
+    /// ```rust
+    /// let a = 0;
+    /// // no redefinition with the same name
+    ///
+    /// fn foo(b: i32) {
+    ///   // no redefinition with the same name
+    /// }
+    /// ```
+    #[clippy::version = "1.72.0"]
+    pub REDUNDANT_LOCALS,
+    correctness,
+    "redundant redefinition of a local binding"
+}
+declare_lint_pass!(RedundantLocals => [REDUNDANT_LOCALS]);
+
+impl<'tcx> LateLintPass<'tcx> for RedundantLocals {
+    fn check_local(&mut self, cx: &LateContext<'tcx>, local: &'tcx Local<'tcx>) {
+        if_chain! {
+            // the pattern is a single by-value binding
+            if let PatKind::Binding(BindingAnnotation(ByRef::No, mutability), _, ident, None) = local.pat.kind;
+            // the binding is not type-ascribed
+            if local.ty.is_none();
+            // the expression is a resolved path
+            if let Some(expr) = local.init;
+            if let ExprKind::Path(qpath @ QPath::Resolved(None, path)) = expr.kind;
+            // the path is a single segment equal to the local's name
+            if let [last_segment] = path.segments;
+            if last_segment.ident == ident;
+            // resolve the path to its defining binding pattern
+            if let Res::Local(binding_id) = cx.qpath_res(&qpath, expr.hir_id);
+            if let Node::Pat(binding_pat) = cx.tcx.hir().get(binding_id);
+            // the previous binding has the same mutability
+            if find_binding(binding_pat, ident).unwrap().1 == mutability;
+            // the local does not affect the code's drop behavior
+            if !affects_drop_behavior(cx, binding_id, local.hir_id, expr);
+            // the local is user-controlled
+            if !in_external_macro(cx.sess(), local.span);
+            if !is_from_proc_macro(cx, expr);
+            then {
+                span_lint_and_help(
+                    cx,
+                    REDUNDANT_LOCALS,
+                    vec![binding_pat.span, local.span],
+                    "redundant redefinition of a binding",
+                    None,
+                    &format!("remove the redefinition of `{ident}`"),
+                );
+            }
+        }
+    }
+}
+
+/// Find the annotation of a binding introduced by a pattern, or `None` if it's not introduced.
+fn find_binding(pat: &Pat<'_>, name: Ident) -> Option<BindingAnnotation> {
+    let mut ret = None;
+
+    pat.each_binding_or_first(&mut |annotation, _, _, ident| {
+        if ident == name {
+            ret = Some(annotation);
+        }
+    });
+
+    ret
+}
+
+/// Check if a rebinding of a local affects the code's drop behavior.
+fn affects_drop_behavior<'tcx>(cx: &LateContext<'tcx>, bind: HirId, rebind: HirId, rebind_expr: &Expr<'tcx>) -> bool {
+    let hir = cx.tcx.hir();
+
+    // the rebinding is in a different scope than the original binding
+    // and the type of the binding cares about drop order
+    hir.get_enclosing_scope(bind) != hir.get_enclosing_scope(rebind)
+        && needs_ordered_drop(cx, cx.typeck_results().expr_ty(rebind_expr))
+}
diff --git a/clippy_lints/src/redundant_slicing.rs b/clippy_lints/src/redundant_slicing.rs
index 3a9bc56d6d9..8277ce724d4 100644
--- a/clippy_lints/src/redundant_slicing.rs
+++ b/clippy_lints/src/redundant_slicing.rs
@@ -8,8 +8,7 @@ use rustc_errors::Applicability;
 use rustc_hir::{BorrowKind, Expr, ExprKind, LangItem, Mutability};
 use rustc_lint::{LateContext, LateLintPass, Lint};
 use rustc_middle::ty::adjustment::{Adjust, AutoBorrow, AutoBorrowMutability};
-use rustc_middle::ty::subst::GenericArg;
-use rustc_middle::ty::Ty;
+use rustc_middle::ty::{GenericArg, Ty};
 use rustc_session::{declare_lint_pass, declare_tool_lint};
 
 declare_clippy_lint! {
@@ -135,7 +134,7 @@ impl<'tcx> LateLintPass<'tcx> for RedundantSlicing {
                 } else if let Some(target_id) = cx.tcx.lang_items().deref_target() {
                     if let Ok(deref_ty) = cx.tcx.try_normalize_erasing_regions(
                         cx.param_env,
-                        Ty::new_projection(cx.tcx,target_id, cx.tcx.mk_substs(&[GenericArg::from(indexed_ty)])),
+                        Ty::new_projection(cx.tcx,target_id, cx.tcx.mk_args(&[GenericArg::from(indexed_ty)])),
                     ) {
                         if deref_ty == expr_ty {
                             let snip = snippet_with_context(cx, indexed.span, ctxt, "..", &mut app).0;
diff --git a/clippy_lints/src/redundant_static_lifetimes.rs b/clippy_lints/src/redundant_static_lifetimes.rs
index 038dfe8e480..ed42a422b4b 100644
--- a/clippy_lints/src/redundant_static_lifetimes.rs
+++ b/clippy_lints/src/redundant_static_lifetimes.rs
@@ -5,6 +5,7 @@ use rustc_ast::ast::{ConstItem, Item, ItemKind, StaticItem, Ty, TyKind};
 use rustc_errors::Applicability;
 use rustc_lint::{EarlyContext, EarlyLintPass};
 use rustc_session::{declare_tool_lint, impl_lint_pass};
+use rustc_span::symbol::kw;
 
 declare_clippy_lint! {
     /// ### What it does
@@ -64,7 +65,7 @@ impl RedundantStaticLifetimes {
                 if let Some(lifetime) = *optional_lifetime {
                     match borrow_type.ty.kind {
                         TyKind::Path(..) | TyKind::Slice(..) | TyKind::Array(..) | TyKind::Tup(..) => {
-                            if lifetime.ident.name == rustc_span::symbol::kw::StaticLifetime {
+                            if lifetime.ident.name == kw::StaticLifetime {
                                 let snip = snippet(cx, borrow_type.ty.span, "<type>");
                                 let sugg = format!("&{}{snip}", borrow_type.mutbl.prefix_str());
                                 span_lint_and_then(
diff --git a/clippy_lints/src/renamed_lints.rs b/clippy_lints/src/renamed_lints.rs
index d24215c2292..13086f996ee 100644
--- a/clippy_lints/src/renamed_lints.rs
+++ b/clippy_lints/src/renamed_lints.rs
@@ -30,6 +30,7 @@ pub static RENAMED_LINTS: &[(&str, &str)] = &[
     ("clippy::single_char_push_str", "clippy::single_char_add_str"),
     ("clippy::stutter", "clippy::module_name_repetitions"),
     ("clippy::to_string_in_display", "clippy::recursive_format_impl"),
+    ("clippy::unwrap_or_else_default", "clippy::unwrap_or_default"),
     ("clippy::zero_width_space", "clippy::invisible_characters"),
     ("clippy::cast_ref_to_mut", "cast_ref_to_mut"),
     ("clippy::clone_double_ref", "suspicious_double_ref_op"),
diff --git a/clippy_lints/src/returns.rs b/clippy_lints/src/returns.rs
index fe797219073..351bacf5691 100644
--- a/clippy_lints/src/returns.rs
+++ b/clippy_lints/src/returns.rs
@@ -1,16 +1,17 @@
-use clippy_utils::diagnostics::{span_lint_and_then, span_lint_hir_and_then};
+use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_and_then, span_lint_hir_and_then};
 use clippy_utils::source::{snippet_opt, snippet_with_context};
 use clippy_utils::visitors::{for_each_expr_with_closures, Descend};
-use clippy_utils::{fn_def_id, path_to_local_id, span_find_starting_semi};
+use clippy_utils::{fn_def_id, is_from_proc_macro, path_to_local_id, span_find_starting_semi};
 use core::ops::ControlFlow;
 use if_chain::if_chain;
 use rustc_errors::Applicability;
 use rustc_hir::intravisit::FnKind;
-use rustc_hir::{Block, Body, Expr, ExprKind, FnDecl, LangItem, MatchSource, PatKind, QPath, StmtKind};
+use rustc_hir::{
+    Block, Body, Expr, ExprKind, FnDecl, ItemKind, LangItem, MatchSource, OwnerNode, PatKind, QPath, Stmt, StmtKind,
+};
 use rustc_lint::{LateContext, LateLintPass, LintContext};
 use rustc_middle::lint::in_external_macro;
-use rustc_middle::ty::subst::GenericArgKind;
-use rustc_middle::ty::{self, Ty};
+use rustc_middle::ty::{self, GenericArgKind, Ty};
 use rustc_session::{declare_lint_pass, declare_tool_lint};
 use rustc_span::def_id::LocalDefId;
 use rustc_span::source_map::Span;
@@ -77,6 +78,46 @@ declare_clippy_lint! {
     "using a return statement like `return expr;` where an expression would suffice"
 }
 
+declare_clippy_lint! {
+    /// ### What it does
+    /// Checks for return statements on `Err` paired with the `?` operator.
+    ///
+    /// ### Why is this bad?
+    /// The `return` is unnecessary.
+    ///
+    /// ### Example
+    /// ```rust,ignore
+    /// fn foo(x: usize) -> Result<(), Box<dyn Error>> {
+    ///     if x == 0 {
+    ///         return Err(...)?;
+    ///     }
+    ///     Ok(())
+    /// }
+    /// ```
+    /// simplify to
+    /// ```rust,ignore
+    /// fn foo(x: usize) -> Result<(), Box<dyn Error>> {
+    ///     if x == 0 {
+    ///         Err(...)?;
+    ///     }
+    ///     Ok(())
+    /// }
+    /// ```
+    /// if paired with `try_err`, use instead:
+    /// ```rust,ignore
+    /// fn foo(x: usize) -> Result<(), Box<dyn Error>> {
+    ///     if x == 0 {
+    ///         return Err(...);
+    ///     }
+    ///     Ok(())
+    /// }
+    /// ```
+    #[clippy::version = "1.73.0"]
+    pub NEEDLESS_RETURN_WITH_QUESTION_MARK,
+    style,
+    "using a return statement like `return Err(expr)?;` where removing it would suffice"
+}
+
 #[derive(PartialEq, Eq)]
 enum RetReplacement<'tcx> {
     Empty,
@@ -116,9 +157,35 @@ impl<'tcx> ToString for RetReplacement<'tcx> {
     }
 }
 
-declare_lint_pass!(Return => [LET_AND_RETURN, NEEDLESS_RETURN]);
+declare_lint_pass!(Return => [LET_AND_RETURN, NEEDLESS_RETURN, NEEDLESS_RETURN_WITH_QUESTION_MARK]);
 
 impl<'tcx> LateLintPass<'tcx> for Return {
+    fn check_stmt(&mut self, cx: &LateContext<'tcx>, stmt: &'tcx Stmt<'_>) {
+        if !in_external_macro(cx.sess(), stmt.span)
+            && let StmtKind::Semi(expr) = stmt.kind
+            && let ExprKind::Ret(Some(ret)) = expr.kind
+            && let ExprKind::Match(.., MatchSource::TryDesugar) = ret.kind
+            // Ensure this is not the final stmt, otherwise removing it would cause a compile error
+            && let OwnerNode::Item(item) = cx.tcx.hir().owner(cx.tcx.hir().get_parent_item(expr.hir_id))
+            && let ItemKind::Fn(_, _, body) = item.kind
+            && let block = cx.tcx.hir().body(body).value
+            && let ExprKind::Block(block, _) = block.kind
+            && let [.., final_stmt] = block.stmts
+            && final_stmt.hir_id != stmt.hir_id
+            && !is_from_proc_macro(cx, expr)
+        {
+            span_lint_and_sugg(
+                cx,
+                NEEDLESS_RETURN_WITH_QUESTION_MARK,
+                expr.span.until(ret.span),
+                "unneeded `return` statement with `?` operator",
+                "remove it",
+                String::new(),
+                Applicability::MachineApplicable,
+            );
+        }
+    }
+
     fn check_block(&mut self, cx: &LateContext<'tcx>, block: &'tcx Block<'_>) {
         // we need both a let-binding stmt and an expr
         if_chain! {
@@ -338,7 +405,7 @@ fn last_statement_borrows<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>)
             && cx
                 .tcx
                 .fn_sig(def_id)
-                .subst_identity()
+                .instantiate_identity()
                 .skip_binder()
                 .output()
                 .walk()
diff --git a/clippy_lints/src/self_named_constructors.rs b/clippy_lints/src/self_named_constructors.rs
index beca203c868..b92014f68b3 100644
--- a/clippy_lints/src/self_named_constructors.rs
+++ b/clippy_lints/src/self_named_constructors.rs
@@ -53,7 +53,7 @@ impl<'tcx> LateLintPass<'tcx> for SelfNamedConstructors {
 
         let parent = cx.tcx.hir().get_parent_item(impl_item.hir_id()).def_id;
         let item = cx.tcx.hir().expect_item(parent);
-        let self_ty = cx.tcx.type_of(item.owner_id).subst_identity();
+        let self_ty = cx.tcx.type_of(item.owner_id).instantiate_identity();
         let ret_ty = return_ty(cx, impl_item.owner_id);
 
         // Do not check trait impls
diff --git a/clippy_lints/src/significant_drop_tightening.rs b/clippy_lints/src/significant_drop_tightening.rs
index bf1059a8b29..4b248c9c790 100644
--- a/clippy_lints/src/significant_drop_tightening.rs
+++ b/clippy_lints/src/significant_drop_tightening.rs
@@ -1,14 +1,13 @@
 use clippy_utils::diagnostics::span_lint_and_then;
 use clippy_utils::source::{indent_of, snippet};
-use clippy_utils::{expr_or_init, get_attr, path_to_local};
+use clippy_utils::{expr_or_init, get_attr, path_to_local, peel_hir_expr_unary};
 use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexMap};
 use rustc_errors::Applicability;
 use rustc_hir::def::{DefKind, Res};
 use rustc_hir::intravisit::{walk_expr, Visitor};
 use rustc_hir::{self as hir};
 use rustc_lint::{LateContext, LateLintPass, LintContext};
-use rustc_middle::ty::subst::GenericArgKind;
-use rustc_middle::ty::{Ty, TypeAndMut};
+use rustc_middle::ty::{GenericArgKind, Ty, TypeAndMut};
 use rustc_session::{declare_tool_lint, impl_lint_pass};
 use rustc_span::symbol::Ident;
 use rustc_span::{sym, Span, DUMMY_SP};
@@ -236,7 +235,7 @@ impl<'ap, 'lc, 'others, 'stmt, 'tcx> StmtsChecker<'ap, 'lc, 'others, 'stmt, 'tcx
 
     fn manage_has_expensive_expr_after_last_attr(&mut self) {
         let has_expensive_stmt = match self.ap.curr_stmt.kind {
-            hir::StmtKind::Expr(expr) if !is_expensive_expr(expr) => false,
+            hir::StmtKind::Expr(expr) if is_inexpensive_expr(expr) => false,
             hir::StmtKind::Local(local) if let Some(expr) = local.init
                 && let hir::ExprKind::Path(_) = expr.kind => false,
             _ => true
@@ -331,13 +330,13 @@ impl<'ap, 'lc, 'others, 'stmt, 'tcx> Visitor<'tcx> for StmtsChecker<'ap, 'lc, 'o
                             apa.last_method_span = span;
                         }
                     },
-                    hir::StmtKind::Semi(expr) => {
-                        if has_drop(expr, &apa.first_bind_ident, self.cx) {
+                    hir::StmtKind::Semi(semi_expr) => {
+                        if has_drop(semi_expr, &apa.first_bind_ident, self.cx) {
                             apa.has_expensive_expr_after_last_attr = false;
                             apa.last_stmt_span = DUMMY_SP;
                             return;
                         }
-                        if let hir::ExprKind::MethodCall(_, _, _, span) = expr.kind {
+                        if let hir::ExprKind::MethodCall(_, _, _, span) = semi_expr.kind {
                             apa.last_method_span = span;
                         }
                     },
@@ -435,16 +434,31 @@ fn has_drop(expr: &hir::Expr<'_>, first_bind_ident: &Ident, lcx: &LateContext<'_
         && let Res::Def(DefKind::Fn, did) = fun_path.res
         && lcx.tcx.is_diagnostic_item(sym::mem_drop, did)
         && let [first_arg, ..] = args
-        && let hir::ExprKind::Path(hir::QPath::Resolved(_, arg_path)) = &first_arg.kind
-        && let [first_arg_ps, .. ] = arg_path.segments
     {
-        &first_arg_ps.ident == first_bind_ident
-    }
-    else {
-        false
+        let has_ident = |local_expr: &hir::Expr<'_>| {
+            if let hir::ExprKind::Path(hir::QPath::Resolved(_, arg_path)) = &local_expr.kind
+                && let [first_arg_ps, .. ] = arg_path.segments
+                && &first_arg_ps.ident == first_bind_ident
+            {
+                true
+            }
+            else {
+                false
+            }
+        };
+        if has_ident(first_arg) {
+            return true;
+        }
+        if let hir::ExprKind::Tup(value) = &first_arg.kind && value.iter().any(has_ident) {
+            return true;
+        }
     }
+    false
 }
 
-fn is_expensive_expr(expr: &hir::Expr<'_>) -> bool {
-    !matches!(expr.kind, hir::ExprKind::Path(_))
+fn is_inexpensive_expr(expr: &hir::Expr<'_>) -> bool {
+    let actual = peel_hir_expr_unary(expr).0;
+    let is_path = matches!(actual.kind, hir::ExprKind::Path(_));
+    let is_lit = matches!(actual.kind, hir::ExprKind::Lit(_));
+    is_path || is_lit
 }
diff --git a/clippy_lints/src/size_of_in_element_count.rs b/clippy_lints/src/size_of_in_element_count.rs
index a91dd21269c..bd783b4e005 100644
--- a/clippy_lints/src/size_of_in_element_count.rs
+++ b/clippy_lints/src/size_of_in_element_count.rs
@@ -46,7 +46,7 @@ fn get_size_of_ty<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, inverted:
                 if let Some(def_id) = cx.qpath_res(count_func_qpath, count_func.hir_id).opt_def_id();
                 if matches!(cx.tcx.get_diagnostic_name(def_id), Some(sym::mem_size_of | sym::mem_size_of_val));
                 then {
-                    cx.typeck_results().node_substs(count_func.hir_id).types().next()
+                    cx.typeck_results().node_args(count_func.hir_id).types().next()
                 } else {
                     None
                 }
@@ -100,7 +100,7 @@ fn get_pointee_ty_and_count_expr<'tcx>(
         if FUNCTIONS.iter().any(|func_path| match_def_path(cx, def_id, func_path));
 
         // Get the pointee type
-        if let Some(pointee_ty) = cx.typeck_results().node_substs(func.hir_id).types().next();
+        if let Some(pointee_ty) = cx.typeck_results().node_args(func.hir_id).types().next();
         then {
             return Some((pointee_ty, count));
         }
diff --git a/clippy_lints/src/slow_vector_initialization.rs b/clippy_lints/src/slow_vector_initialization.rs
index 858135c8d46..54a33eb2986 100644
--- a/clippy_lints/src/slow_vector_initialization.rs
+++ b/clippy_lints/src/slow_vector_initialization.rs
@@ -1,13 +1,13 @@
 use clippy_utils::diagnostics::span_lint_and_then;
 use clippy_utils::sugg::Sugg;
-use clippy_utils::ty::is_type_diagnostic_item;
 use clippy_utils::{
-    get_enclosing_block, is_integer_literal, is_path_diagnostic_item, path_to_local, path_to_local_id, SpanlessEq,
+    get_enclosing_block, is_expr_path_def_path, is_integer_literal, is_path_diagnostic_item, path_to_local,
+    path_to_local_id, paths, SpanlessEq,
 };
 use if_chain::if_chain;
 use rustc_errors::Applicability;
 use rustc_hir::intravisit::{walk_block, walk_expr, walk_stmt, Visitor};
-use rustc_hir::{BindingAnnotation, Block, Expr, ExprKind, HirId, PatKind, QPath, Stmt, StmtKind};
+use rustc_hir::{BindingAnnotation, Block, Expr, ExprKind, HirId, PatKind, Stmt, StmtKind};
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_session::{declare_lint_pass, declare_tool_lint};
 use rustc_span::symbol::sym;
@@ -60,7 +60,24 @@ struct VecAllocation<'tcx> {
 
     /// Reference to the expression used as argument on `with_capacity` call. This is used
     /// to only match slow zero-filling idioms of the same length than vector initialization.
-    len_expr: &'tcx Expr<'tcx>,
+    size_expr: InitializedSize<'tcx>,
+}
+
+/// Initializer for the creation of the vector.
+///
+/// When `Vec::with_capacity(size)` is found, the `size` expression will be in
+/// `InitializedSize::Initialized`.
+///
+/// Otherwise, for `Vec::new()` calls, there is no allocation initializer yet, so
+/// `InitializedSize::Uninitialized` is used.
+/// Later, when a call to `.resize(size, 0)` or similar is found, it's set
+/// to `InitializedSize::Initialized(size)`.
+///
+/// Since it will be set to `InitializedSize::Initialized(size)` when a slow initialization is
+/// found, it is always safe to "unwrap" it at lint time.
+enum InitializedSize<'tcx> {
+    Initialized(&'tcx Expr<'tcx>),
+    Uninitialized,
 }
 
 /// Type of slow initialization
@@ -77,18 +94,14 @@ impl<'tcx> LateLintPass<'tcx> for SlowVectorInit {
         // Matches initialization on reassignments. For example: `vec = Vec::with_capacity(100)`
         if_chain! {
             if let ExprKind::Assign(left, right, _) = expr.kind;
-
-            // Extract variable
             if let Some(local_id) = path_to_local(left);
-
-            // Extract len argument
-            if let Some(len_arg) = Self::is_vec_with_capacity(cx, right);
+            if let Some(size_expr) = Self::as_vec_initializer(cx, right);
 
             then {
                 let vi = VecAllocation {
                     local_id,
                     allocation_expr: right,
-                    len_expr: len_arg,
+                    size_expr,
                 };
 
                 Self::search_initialization(cx, vi, expr.hir_id);
@@ -98,17 +111,18 @@ impl<'tcx> LateLintPass<'tcx> for SlowVectorInit {
 
     fn check_stmt(&mut self, cx: &LateContext<'tcx>, stmt: &'tcx Stmt<'_>) {
         // Matches statements which initializes vectors. For example: `let mut vec = Vec::with_capacity(10)`
+        // or `Vec::new()`
         if_chain! {
             if let StmtKind::Local(local) = stmt.kind;
             if let PatKind::Binding(BindingAnnotation::MUT, local_id, _, None) = local.pat.kind;
             if let Some(init) = local.init;
-            if let Some(len_arg) = Self::is_vec_with_capacity(cx, init);
+            if let Some(size_expr) = Self::as_vec_initializer(cx, init);
 
             then {
                 let vi = VecAllocation {
                     local_id,
                     allocation_expr: init,
-                    len_expr: len_arg,
+                    size_expr,
                 };
 
                 Self::search_initialization(cx, vi, stmt.hir_id);
@@ -118,19 +132,20 @@ impl<'tcx> LateLintPass<'tcx> for SlowVectorInit {
 }
 
 impl SlowVectorInit {
-    /// Checks if the given expression is `Vec::with_capacity(..)`. It will return the expression
-    /// of the first argument of `with_capacity` call if it matches or `None` if it does not.
-    fn is_vec_with_capacity<'tcx>(cx: &LateContext<'_>, expr: &Expr<'tcx>) -> Option<&'tcx Expr<'tcx>> {
-        if_chain! {
-            if let ExprKind::Call(func, [arg]) = expr.kind;
-            if let ExprKind::Path(QPath::TypeRelative(ty, name)) = func.kind;
-            if name.ident.as_str() == "with_capacity";
-            if is_type_diagnostic_item(cx, cx.typeck_results().node_type(ty.hir_id), sym::Vec);
-            then {
-                Some(arg)
-            } else {
-                None
-            }
+    /// Looks for `Vec::with_capacity(size)` or `Vec::new()` calls and returns the initialized size,
+    /// if any. More specifically, it returns:
+    /// - `Some(InitializedSize::Initialized(size))` for `Vec::with_capacity(size)`
+    /// - `Some(InitializedSize::Uninitialized)` for `Vec::new()`
+    /// - `None` for other, unrelated kinds of expressions
+    fn as_vec_initializer<'tcx>(cx: &LateContext<'_>, expr: &'tcx Expr<'tcx>) -> Option<InitializedSize<'tcx>> {
+        if let ExprKind::Call(func, [len_expr]) = expr.kind
+            && is_expr_path_def_path(cx, func, &paths::VEC_WITH_CAPACITY)
+        {
+            Some(InitializedSize::Initialized(len_expr))
+        } else if matches!(expr.kind, ExprKind::Call(func, _) if is_expr_path_def_path(cx, func, &paths::VEC_NEW)) {
+            Some(InitializedSize::Uninitialized)
+        } else {
+            None
         }
     }
 
@@ -169,12 +184,19 @@ impl SlowVectorInit {
     }
 
     fn emit_lint(cx: &LateContext<'_>, slow_fill: &Expr<'_>, vec_alloc: &VecAllocation<'_>, msg: &str) {
-        let len_expr = Sugg::hir(cx, vec_alloc.len_expr, "len");
+        let len_expr = Sugg::hir(
+            cx,
+            match vec_alloc.size_expr {
+                InitializedSize::Initialized(expr) => expr,
+                InitializedSize::Uninitialized => unreachable!("size expression must be set by this point"),
+            },
+            "len",
+        );
 
         span_lint_and_then(cx, SLOW_VECTOR_INITIALIZATION, slow_fill.span, msg, |diag| {
             diag.span_suggestion(
                 vec_alloc.allocation_expr.span,
-                "consider replace allocation with",
+                "consider replacing this with",
                 format!("vec![0; {len_expr}]"),
                 Applicability::Unspecified,
             );
@@ -214,36 +236,45 @@ impl<'a, 'tcx> VectorInitializationVisitor<'a, 'tcx> {
     }
 
     /// Checks if the given expression is resizing a vector with 0
-    fn search_slow_resize_filling(&mut self, expr: &'tcx Expr<'_>) {
+    fn search_slow_resize_filling(&mut self, expr: &'tcx Expr<'tcx>) {
         if self.initialization_found
             && let ExprKind::MethodCall(path, self_arg, [len_arg, fill_arg], _) = expr.kind
             && path_to_local_id(self_arg, self.vec_alloc.local_id)
             && path.ident.name == sym!(resize)
             // Check that is filled with 0
-            && is_integer_literal(fill_arg, 0) {
-                // Check that len expression is equals to `with_capacity` expression
-                if SpanlessEq::new(self.cx).eq_expr(len_arg, self.vec_alloc.len_expr) {
-                    self.slow_expression = Some(InitializationType::Resize(expr));
-                } else if let ExprKind::MethodCall(path, ..) = len_arg.kind && path.ident.as_str() == "capacity" {
-                    self.slow_expression = Some(InitializationType::Resize(expr));
-                }
+            && is_integer_literal(fill_arg, 0)
+        {
+            let is_matching_resize = if let InitializedSize::Initialized(size_expr) = self.vec_alloc.size_expr {
+                // If we have a size expression, check that it is equal to what's passed to `resize`
+                SpanlessEq::new(self.cx).eq_expr(len_arg, size_expr)
+                    || matches!(len_arg.kind, ExprKind::MethodCall(path, ..) if path.ident.as_str() == "capacity")
+            } else {
+                self.vec_alloc.size_expr = InitializedSize::Initialized(len_arg);
+                true
+            };
+
+            if is_matching_resize {
+                self.slow_expression = Some(InitializationType::Resize(expr));
             }
+        }
     }
 
     /// Returns `true` if give expression is `repeat(0).take(...)`
-    fn is_repeat_take(&self, expr: &Expr<'_>) -> bool {
+    fn is_repeat_take(&mut self, expr: &'tcx Expr<'tcx>) -> bool {
         if_chain! {
             if let ExprKind::MethodCall(take_path, recv, [len_arg, ..], _) = expr.kind;
             if take_path.ident.name == sym!(take);
             // Check that take is applied to `repeat(0)`
             if self.is_repeat_zero(recv);
             then {
-                // Check that len expression is equals to `with_capacity` expression
-                if SpanlessEq::new(self.cx).eq_expr(len_arg, self.vec_alloc.len_expr) {
-                    return true;
-                } else if let ExprKind::MethodCall(path, ..) = len_arg.kind && path.ident.as_str() == "capacity" {
-                    return true;
+                if let InitializedSize::Initialized(size_expr) = self.vec_alloc.size_expr {
+                    // Check that len expression is equals to `with_capacity` expression
+                    return SpanlessEq::new(self.cx).eq_expr(len_arg, size_expr)
+                        || matches!(len_arg.kind, ExprKind::MethodCall(path, ..) if path.ident.as_str() == "capacity")
                 }
+
+                self.vec_alloc.size_expr = InitializedSize::Initialized(len_arg);
+                return true;
             }
         }
 
diff --git a/clippy_lints/src/strings.rs b/clippy_lints/src/strings.rs
index 58724852b3c..4d45091f4b5 100644
--- a/clippy_lints/src/strings.rs
+++ b/clippy_lints/src/strings.rs
@@ -328,7 +328,7 @@ impl<'tcx> LateLintPass<'tcx> for StringLitAsBytes {
                     {
                         // Don't lint. Byte strings produce `&[u8; N]` whereas `as_bytes()` produces
                         // `&[u8]`. This change would prevent matching with different sized slices.
-                    } else {
+                    } else if !callsite.starts_with("env!") {
                         span_lint_and_sugg(
                             cx,
                             STRING_LIT_AS_BYTES,
diff --git a/clippy_lints/src/suspicious_xor_used_as_pow.rs b/clippy_lints/src/suspicious_xor_used_as_pow.rs
index 6fa49afe0ec..8e156b8829b 100644
--- a/clippy_lints/src/suspicious_xor_used_as_pow.rs
+++ b/clippy_lints/src/suspicious_xor_used_as_pow.rs
@@ -1,5 +1,7 @@
+use clippy_utils::diagnostics::span_lint_and_sugg;
 use clippy_utils::numeric_literal::NumericLiteral;
-use clippy_utils::source::snippet_with_context;
+use clippy_utils::source::snippet;
+use rustc_ast::LitKind;
 use rustc_errors::Applicability;
 use rustc_hir::{BinOpKind, Expr, ExprKind};
 use rustc_lint::{LateContext, LateLintPass, LintContext};
@@ -28,27 +30,29 @@ declare_lint_pass!(ConfusingXorAndPow => [SUSPICIOUS_XOR_USED_AS_POW]);
 
 impl LateLintPass<'_> for ConfusingXorAndPow {
     fn check_expr(&mut self, cx: &LateContext<'_>, expr: &Expr<'_>) {
-        if !in_external_macro(cx.sess(), expr.span) &&
-        	let ExprKind::Binary(op, left, right) = &expr.kind &&
-            op.node == BinOpKind::BitXor &&
-            left.span.ctxt() == right.span.ctxt() &&
-            let ExprKind::Lit(lit_left) = &left.kind &&
-            let ExprKind::Lit(lit_right) = &right.kind &&
-            let snip_left = snippet_with_context(cx, lit_left.span, lit_left.span.ctxt(), "..", &mut Applicability::MaybeIncorrect) &&
-            let snip_right = snippet_with_context(cx, lit_right.span, lit_right.span.ctxt(), "..", &mut Applicability::MaybeIncorrect) &&
-            let Some(left_val) = NumericLiteral::from_lit_kind(&snip_left.0, &lit_left.node) &&
-            let Some(right_val) = NumericLiteral::from_lit_kind(&snip_right.0, &lit_right.node) &&
-			left_val.is_decimal() &&
-			right_val.is_decimal() {
-					clippy_utils::diagnostics::span_lint_and_sugg(
-					        cx,
-					        SUSPICIOUS_XOR_USED_AS_POW,
-					        expr.span,
-					        "`^` is not the exponentiation operator",
-					        "did you mean to write",
-					        format!("{}.pow({})", left_val.format(), right_val.format()),
-					        Applicability::MaybeIncorrect,
-					    );
+        if !in_external_macro(cx.sess(), expr.span)
+            && let ExprKind::Binary(op, left, right) = &expr.kind
+            && op.node == BinOpKind::BitXor
+            && left.span.ctxt() == right.span.ctxt()
+            && let ExprKind::Lit(lit_left) = &left.kind
+            && let ExprKind::Lit(lit_right) = &right.kind
+            && matches!(lit_right.node, LitKind::Int(..) | LitKind::Float(..))
+            && matches!(lit_left.node, LitKind::Int(..) | LitKind::Float(..))
+            && NumericLiteral::from_lit_kind(&snippet(cx, lit_right.span, ".."), &lit_right.node).is_some_and(|x| x.is_decimal())
+            {
+                span_lint_and_sugg(
+                    cx,
+                    SUSPICIOUS_XOR_USED_AS_POW,
+                    expr.span,
+                    "`^` is not the exponentiation operator",
+                    "did you mean to write",
+                    format!(
+                        "{}.pow({})",
+                        lit_left.node,
+                        lit_right.node
+                    ),
+                    Applicability::MaybeIncorrect,
+                );
 		}
     }
 }
diff --git a/clippy_lints/src/transmute/transmute_undefined_repr.rs b/clippy_lints/src/transmute/transmute_undefined_repr.rs
index 13b7eeb43a6..c61eb0a9311 100644
--- a/clippy_lints/src/transmute/transmute_undefined_repr.rs
+++ b/clippy_lints/src/transmute/transmute_undefined_repr.rs
@@ -3,7 +3,7 @@ use clippy_utils::diagnostics::span_lint_and_then;
 use clippy_utils::ty::is_c_void;
 use rustc_hir::Expr;
 use rustc_lint::LateContext;
-use rustc_middle::ty::{self, IntTy, SubstsRef, Ty, TypeAndMut, UintTy};
+use rustc_middle::ty::{self, GenericArgsRef, IntTy, Ty, TypeAndMut, UintTy};
 
 #[expect(clippy::too_many_lines)]
 pub(super) fn check<'tcx>(
@@ -267,12 +267,12 @@ fn reduce_ty<'tcx>(cx: &LateContext<'tcx>, mut ty: Ty<'tcx>) -> ReducedTy<'tcx>
                 }
                 ReducedTy::UnorderedFields(ty)
             },
-            ty::Adt(def, substs) if def.is_struct() => {
+            ty::Adt(def, args) if def.is_struct() => {
                 let mut iter = def
                     .non_enum_variant()
                     .fields
                     .iter()
-                    .map(|f| cx.tcx.type_of(f.did).subst(cx.tcx, substs));
+                    .map(|f| cx.tcx.type_of(f.did).instantiate(cx.tcx, args));
                 let Some(sized_ty) = iter.find(|&ty| !is_zero_sized_ty(cx, ty)) else {
                     return ReducedTy::TypeErasure { raw_ptr_only: false };
                 };
@@ -321,7 +321,7 @@ fn is_size_pair(ty: Ty<'_>) -> bool {
     }
 }
 
-fn same_except_params<'tcx>(subs1: SubstsRef<'tcx>, subs2: SubstsRef<'tcx>) -> bool {
+fn same_except_params<'tcx>(subs1: GenericArgsRef<'tcx>, subs2: GenericArgsRef<'tcx>) -> bool {
     // TODO: check const parameters as well. Currently this will consider `Array<5>` the same as
     // `Array<6>`
     for (ty1, ty2) in subs1.types().zip(subs2.types()).filter(|(ty1, ty2)| ty1 != ty2) {
diff --git a/clippy_lints/src/transmute/unsound_collection_transmute.rs b/clippy_lints/src/transmute/unsound_collection_transmute.rs
index b1445311b71..891fefc17a6 100644
--- a/clippy_lints/src/transmute/unsound_collection_transmute.rs
+++ b/clippy_lints/src/transmute/unsound_collection_transmute.rs
@@ -10,7 +10,7 @@ use rustc_span::symbol::sym;
 /// Returns `true` if it's triggered, otherwise returns `false`.
 pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>, from_ty: Ty<'tcx>, to_ty: Ty<'tcx>) -> bool {
     match (&from_ty.kind(), &to_ty.kind()) {
-        (ty::Adt(from_adt, from_substs), ty::Adt(to_adt, to_substs)) => {
+        (ty::Adt(from_adt, from_args), ty::Adt(to_adt, to_args)) => {
             if from_adt.did() != to_adt.did() {
                 return false;
             }
@@ -28,9 +28,9 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>, from_ty: Ty
             ) {
                 return false;
             }
-            if from_substs
+            if from_args
                 .types()
-                .zip(to_substs.types())
+                .zip(to_args.types())
                 .any(|(from_ty, to_ty)| is_layout_incompatible(cx, from_ty, to_ty))
             {
                 span_lint(
diff --git a/clippy_lints/src/uninit_vec.rs b/clippy_lints/src/uninit_vec.rs
index 1ab0162a881..6756df8e716 100644
--- a/clippy_lints/src/uninit_vec.rs
+++ b/clippy_lints/src/uninit_vec.rs
@@ -88,7 +88,7 @@ fn handle_uninit_vec_pair<'tcx>(
         if let Some((set_len_self, call_span)) = extract_set_len_self(cx, maybe_set_len);
         if vec.location.eq_expr(cx, set_len_self);
         if let ty::Ref(_, vec_ty, _) = cx.typeck_results().expr_ty_adjusted(set_len_self).kind();
-        if let ty::Adt(_, substs) = vec_ty.kind();
+        if let ty::Adt(_, args) = vec_ty.kind();
         // `#[allow(...)]` attribute can be set on enclosing unsafe block of `set_len()`
         if !is_lint_allowed(cx, UNINIT_VEC, maybe_set_len.hir_id);
         then {
@@ -96,7 +96,7 @@ fn handle_uninit_vec_pair<'tcx>(
                 // with_capacity / reserve -> set_len
 
                 // Check T of Vec<T>
-                if !is_uninit_value_valid_for_ty(cx, substs.type_at(0)) {
+                if !is_uninit_value_valid_for_ty(cx, args.type_at(0)) {
                     // FIXME: #7698, false positive of the internal lints
                     #[expect(clippy::collapsible_span_lint_calls)]
                     span_lint_and_then(
diff --git a/clippy_lints/src/unit_return_expecting_ord.rs b/clippy_lints/src/unit_return_expecting_ord.rs
index 99a1d197678..dd829ded0d0 100644
--- a/clippy_lints/src/unit_return_expecting_ord.rs
+++ b/clippy_lints/src/unit_return_expecting_ord.rs
@@ -65,7 +65,7 @@ fn get_projection_pred<'tcx>(
     generics.predicates.iter().find_map(|(proj_pred, _)| {
         if let ClauseKind::Projection(pred) = proj_pred.kind().skip_binder() {
             let projection_pred = cx.tcx.erase_late_bound_regions(proj_pred.kind().rebind(pred));
-            if projection_pred.projection_ty.substs == trait_pred.trait_ref.substs {
+            if projection_pred.projection_ty.args == trait_pred.trait_ref.args {
                 return Some(projection_pred);
             }
         }
@@ -76,7 +76,7 @@ fn get_projection_pred<'tcx>(
 fn get_args_to_check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) -> Vec<(usize, String)> {
     let mut args_to_check = Vec::new();
     if let Some(def_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id) {
-        let fn_sig = cx.tcx.fn_sig(def_id).subst_identity();
+        let fn_sig = cx.tcx.fn_sig(def_id).instantiate_identity();
         let generics = cx.tcx.predicates_of(def_id);
         let fn_mut_preds = get_trait_predicates_for_trait_id(cx, generics, cx.tcx.lang_items().fn_mut_trait());
         let ord_preds = get_trait_predicates_for_trait_id(cx, generics, cx.tcx.get_diagnostic_item(sym::Ord));
@@ -120,8 +120,8 @@ fn get_args_to_check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) -> Ve
 fn check_arg<'tcx>(cx: &LateContext<'tcx>, arg: &'tcx Expr<'tcx>) -> Option<(Span, Option<Span>)> {
     if_chain! {
         if let ExprKind::Closure(&Closure { body, fn_decl_span, .. }) = arg.kind;
-        if let ty::Closure(_def_id, substs) = &cx.typeck_results().node_type(arg.hir_id).kind();
-        let ret_ty = substs.as_closure().sig().output();
+        if let ty::Closure(_def_id, args) = &cx.typeck_results().node_type(arg.hir_id).kind();
+        let ret_ty = args.as_closure().sig().output();
         let ty = cx.tcx.erase_late_bound_regions(ret_ty);
         if ty.is_unit();
         then {
diff --git a/clippy_lints/src/unit_types/let_unit_value.rs b/clippy_lints/src/unit_types/let_unit_value.rs
index cc7c2b039f2..704d7abd7e5 100644
--- a/clippy_lints/src/unit_types/let_unit_value.rs
+++ b/clippy_lints/src/unit_types/let_unit_value.rs
@@ -161,7 +161,7 @@ fn needs_inferred_result_ty(
         },
         _ => return false,
     };
-    let sig = cx.tcx.fn_sig(id).subst_identity().skip_binder();
+    let sig = cx.tcx.fn_sig(id).instantiate_identity().skip_binder();
     if let ty::Param(output_ty) = *sig.output().kind() {
         let args: Vec<&Expr<'_>> = if let Some(receiver) = receiver {
             std::iter::once(receiver).chain(args.iter()).collect()
diff --git a/clippy_lints/src/unnamed_address.rs b/clippy_lints/src/unnamed_address.rs
index 0f5cdb6aaea..dea8a1e35bb 100644
--- a/clippy_lints/src/unnamed_address.rs
+++ b/clippy_lints/src/unnamed_address.rs
@@ -97,7 +97,7 @@ impl LateLintPass<'_> for UnnamedAddress {
             if let ExprKind::Path(ref func_qpath) = func.kind;
             if let Some(def_id) = cx.qpath_res(func_qpath, func.hir_id).opt_def_id();
             if match_def_path(cx, def_id, &paths::PTR_EQ);
-            let ty_param = cx.typeck_results().node_substs(func.hir_id).type_at(0);
+            let ty_param = cx.typeck_results().node_args(func.hir_id).type_at(0);
             if ty_param.is_trait();
             then {
                 span_lint_and_help(
diff --git a/clippy_lints/src/unused_async.rs b/clippy_lints/src/unused_async.rs
index 5e42cf7e4f3..bc7c3897a6e 100644
--- a/clippy_lints/src/unused_async.rs
+++ b/clippy_lints/src/unused_async.rs
@@ -1,11 +1,12 @@
-use clippy_utils::diagnostics::span_lint_and_then;
+use clippy_utils::diagnostics::span_lint_hir_and_then;
 use clippy_utils::is_def_id_trait_method;
+use rustc_hir::def::DefKind;
 use rustc_hir::intravisit::{walk_body, walk_expr, walk_fn, FnKind, Visitor};
-use rustc_hir::{Body, Expr, ExprKind, FnDecl, YieldSource};
+use rustc_hir::{Body, Expr, ExprKind, FnDecl, Node, YieldSource};
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_middle::hir::nested_filter;
-use rustc_session::{declare_lint_pass, declare_tool_lint};
-use rustc_span::def_id::LocalDefId;
+use rustc_session::{declare_tool_lint, impl_lint_pass};
+use rustc_span::def_id::{LocalDefId, LocalDefIdSet};
 use rustc_span::Span;
 
 declare_clippy_lint! {
@@ -38,7 +39,24 @@ declare_clippy_lint! {
     "finds async functions with no await statements"
 }
 
-declare_lint_pass!(UnusedAsync => [UNUSED_ASYNC]);
+#[derive(Default)]
+pub struct UnusedAsync {
+    /// Keeps track of async functions used as values (i.e. path expressions to async functions that
+    /// are not immediately called)
+    async_fns_as_value: LocalDefIdSet,
+    /// Functions with unused `async`, linted post-crate after we've found all uses of local async
+    /// functions
+    unused_async_fns: Vec<UnusedAsyncFn>,
+}
+
+#[derive(Copy, Clone)]
+struct UnusedAsyncFn {
+    def_id: LocalDefId,
+    fn_span: Span,
+    await_in_async_block: Option<Span>,
+}
+
+impl_lint_pass!(UnusedAsync => [UNUSED_ASYNC]);
 
 struct AsyncFnVisitor<'a, 'tcx> {
     cx: &'a LateContext<'tcx>,
@@ -101,24 +119,70 @@ impl<'tcx> LateLintPass<'tcx> for UnusedAsync {
             };
             walk_fn(&mut visitor, fn_kind, fn_decl, body.id(), def_id);
             if !visitor.found_await {
-                span_lint_and_then(
-                    cx,
-                    UNUSED_ASYNC,
-                    span,
-                    "unused `async` for function with no await statements",
-                    |diag| {
-                        diag.help("consider removing the `async` from this function");
-
-                        if let Some(span) = visitor.await_in_async_block {
-                            diag.span_note(
-                                span,
-                                "`await` used in an async block, which does not require \
-                                the enclosing function to be `async`",
-                            );
-                        }
-                    },
-                );
+                // Don't lint just yet, but store the necessary information for later.
+                // The actual linting happens in `check_crate_post`, once we've found all
+                // uses of local async functions that do require asyncness to pass typeck
+                self.unused_async_fns.push(UnusedAsyncFn {
+                    await_in_async_block: visitor.await_in_async_block,
+                    fn_span: span,
+                    def_id,
+                });
             }
         }
     }
+
+    fn check_path(&mut self, cx: &LateContext<'tcx>, path: &rustc_hir::Path<'tcx>, hir_id: rustc_hir::HirId) {
+        fn is_node_func_call(node: Node<'_>, expected_receiver: Span) -> bool {
+            matches!(
+                node,
+                Node::Expr(Expr {
+                    kind: ExprKind::Call(Expr { span, .. }, _) | ExprKind::MethodCall(_, Expr { span, .. }, ..),
+                    ..
+                }) if *span == expected_receiver
+            )
+        }
+
+        // Find paths to local async functions that aren't immediately called.
+        // E.g. `async fn f() {}; let x = f;`
+        // Depending on how `x` is used, f's asyncness might be required despite not having any `await`
+        // statements, so don't lint at all if there are any such paths.
+        if let Some(def_id) = path.res.opt_def_id()
+            && let Some(local_def_id) = def_id.as_local()
+            && let Some(DefKind::Fn) = cx.tcx.opt_def_kind(def_id)
+            && cx.tcx.asyncness(def_id).is_async()
+            && !is_node_func_call(cx.tcx.hir().get_parent(hir_id), path.span)
+        {
+            self.async_fns_as_value.insert(local_def_id);
+        }
+    }
+
+    // After collecting all unused `async` and problematic paths to such functions,
+    // lint those unused ones that didn't have any path expressions to them.
+    fn check_crate_post(&mut self, cx: &LateContext<'tcx>) {
+        let iter = self
+            .unused_async_fns
+            .iter()
+            .filter(|UnusedAsyncFn { def_id, .. }| (!self.async_fns_as_value.contains(def_id)));
+
+        for fun in iter {
+            span_lint_hir_and_then(
+                cx,
+                UNUSED_ASYNC,
+                cx.tcx.local_def_id_to_hir_id(fun.def_id),
+                fun.fn_span,
+                "unused `async` for function with no await statements",
+                |diag| {
+                    diag.help("consider removing the `async` from this function");
+
+                    if let Some(span) = fun.await_in_async_block {
+                        diag.span_note(
+                            span,
+                            "`await` used in an async block, which does not require \
+                            the enclosing function to be `async`",
+                        );
+                    }
+                },
+            );
+        }
+    }
 }
diff --git a/clippy_lints/src/use_self.rs b/clippy_lints/src/use_self.rs
index fcf77e8eab9..50231d930d0 100644
--- a/clippy_lints/src/use_self.rs
+++ b/clippy_lints/src/use_self.rs
@@ -144,7 +144,7 @@ impl<'tcx> LateLintPass<'tcx> for UseSelf {
             then {
                 // `self_ty` is the semantic self type of `impl <trait> for <type>`. This cannot be
                 // `Self`.
-                let self_ty = impl_trait_ref.subst_identity().self_ty();
+                let self_ty = impl_trait_ref.instantiate_identity().self_ty();
 
                 // `trait_method_sig` is the signature of the function, how it is declared in the
                 // trait, not in the impl of the trait.
@@ -153,7 +153,7 @@ impl<'tcx> LateLintPass<'tcx> for UseSelf {
                     .associated_item(impl_item.owner_id)
                     .trait_item_def_id
                     .expect("impl method matches a trait method");
-                let trait_method_sig = cx.tcx.fn_sig(trait_method).subst_identity();
+                let trait_method_sig = cx.tcx.fn_sig(trait_method).instantiate_identity();
                 let trait_method_sig = cx.tcx.erase_late_bound_regions(trait_method_sig);
 
                 // `impl_inputs_outputs` is an iterator over the types (`hir::Ty`) declared in the
@@ -225,7 +225,7 @@ impl<'tcx> LateLintPass<'tcx> for UseSelf {
             } else {
                 hir_ty_to_ty(cx.tcx, hir_ty)
             };
-            if same_type_and_consts(ty, cx.tcx.type_of(impl_id).subst_identity());
+            if same_type_and_consts(ty, cx.tcx.type_of(impl_id).instantiate_identity());
             then {
                 span_lint(cx, hir_ty.span);
             }
@@ -237,7 +237,7 @@ impl<'tcx> LateLintPass<'tcx> for UseSelf {
             if !expr.span.from_expansion();
             if self.msrv.meets(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).subst_identity();
+            if cx.typeck_results().expr_ty(expr) == cx.tcx.type_of(impl_id).instantiate_identity();
             then {} else { return; }
         }
         match expr.kind {
@@ -261,7 +261,7 @@ impl<'tcx> LateLintPass<'tcx> for UseSelf {
             if let PatKind::Path(QPath::Resolved(_, path))
                  | PatKind::TupleStruct(QPath::Resolved(_, path), _, _)
                  | PatKind::Struct(QPath::Resolved(_, path), _, _) = pat.kind;
-            if cx.typeck_results().pat_ty(pat) == cx.tcx.type_of(impl_id).subst_identity();
+            if cx.typeck_results().pat_ty(pat) == cx.tcx.type_of(impl_id).instantiate_identity();
             then {
                 check_path(cx, path);
             }
diff --git a/clippy_lints/src/useless_conversion.rs b/clippy_lints/src/useless_conversion.rs
index 9e07da8995b..92b694d3076 100644
--- a/clippy_lints/src/useless_conversion.rs
+++ b/clippy_lints/src/useless_conversion.rs
@@ -226,8 +226,8 @@ impl<'tcx> LateLintPass<'tcx> for UselessConversion {
                     let a = cx.typeck_results().expr_ty(e);
                     let b = cx.typeck_results().expr_ty(recv);
                     if is_type_diagnostic_item(cx, a, sym::Result);
-                    if let ty::Adt(_, substs) = a.kind();
-                    if let Some(a_type) = substs.types().next();
+                    if let ty::Adt(_, args) = a.kind();
+                    if let Some(a_type) = args.types().next();
                     if same_type_and_consts(a_type, b);
 
                     then {
@@ -254,8 +254,8 @@ impl<'tcx> LateLintPass<'tcx> for UselessConversion {
                         if_chain! {
                             if match_def_path(cx, def_id, &paths::TRY_FROM);
                             if is_type_diagnostic_item(cx, a, sym::Result);
-                            if let ty::Adt(_, substs) = a.kind();
-                            if let Some(a_type) = substs.types().next();
+                            if let ty::Adt(_, args) = a.kind();
+                            if let Some(a_type) = args.types().next();
                             if same_type_and_consts(a_type, b);
 
                             then {
diff --git a/clippy_lints/src/utils/conf.rs b/clippy_lints/src/utils/conf.rs
index 76654bfe536..58ae0656db7 100644
--- a/clippy_lints/src/utils/conf.rs
+++ b/clippy_lints/src/utils/conf.rs
@@ -551,6 +551,16 @@ define_Conf! {
     ///
     /// Whether to allow `r#""#` when `r""` can be used
     (allow_one_hash_in_raw_strings: bool = false),
+    /// Lint: ABSOLUTE_PATHS.
+    ///
+    /// The maximum number of segments a path can have before being linted, anything above this will
+    /// be linted.
+    (absolute_paths_max_segments: u64 = 2),
+    /// Lint: ABSOLUTE_PATHS.
+    ///
+    /// Which crates to allow absolute paths from
+    (absolute_paths_allowed_crates: rustc_data_structures::fx::FxHashSet<String> =
+        rustc_data_structures::fx::FxHashSet::default()),
 }
 
 /// Search for the configuration file.
diff --git a/clippy_lints/src/utils/internal_lints/interning_defined_symbol.rs b/clippy_lints/src/utils/internal_lints/interning_defined_symbol.rs
index dced9fcf9ab..da8654d9388 100644
--- a/clippy_lints/src/utils/internal_lints/interning_defined_symbol.rs
+++ b/clippy_lints/src/utils/internal_lints/interning_defined_symbol.rs
@@ -78,7 +78,7 @@ impl<'tcx> LateLintPass<'tcx> for InterningDefinedSymbol {
                 for item in cx.tcx.module_children(def_id) {
                     if_chain! {
                         if let Res::Def(DefKind::Const, item_def_id) = item.res;
-                        let ty = cx.tcx.type_of(item_def_id).subst_identity();
+                        let ty = cx.tcx.type_of(item_def_id).instantiate_identity();
                         if match_type(cx, ty, &paths::SYMBOL);
                         if let Ok(ConstValue::Scalar(value)) = cx.tcx.const_eval_poly(item_def_id);
                         if let Ok(value) = value.to_u32();
diff --git a/clippy_lints/src/utils/internal_lints/invalid_paths.rs b/clippy_lints/src/utils/internal_lints/invalid_paths.rs
index 94b56304bca..e4906944c8d 100644
--- a/clippy_lints/src/utils/internal_lints/invalid_paths.rs
+++ b/clippy_lints/src/utils/internal_lints/invalid_paths.rs
@@ -74,10 +74,10 @@ pub fn check_path(cx: &LateContext<'_>, path: &[&str]) -> bool {
     let lang_items = cx.tcx.lang_items();
     // This list isn't complete, but good enough for our current list of paths.
     let incoherent_impls = [
-        SimplifiedType::FloatSimplifiedType(FloatTy::F32),
-        SimplifiedType::FloatSimplifiedType(FloatTy::F64),
-        SimplifiedType::SliceSimplifiedType,
-        SimplifiedType::StrSimplifiedType,
+        SimplifiedType::Float(FloatTy::F32),
+        SimplifiedType::Float(FloatTy::F64),
+        SimplifiedType::Slice,
+        SimplifiedType::Str,
     ]
     .iter()
     .flat_map(|&ty| cx.tcx.incoherent_impls(ty).iter().copied());
diff --git a/clippy_lints/src/utils/internal_lints/msrv_attr_impl.rs b/clippy_lints/src/utils/internal_lints/msrv_attr_impl.rs
index 14855e9c331..bf835f89cfc 100644
--- a/clippy_lints/src/utils/internal_lints/msrv_attr_impl.rs
+++ b/clippy_lints/src/utils/internal_lints/msrv_attr_impl.rs
@@ -7,8 +7,7 @@ use rustc_errors::Applicability;
 use rustc_hir as hir;
 use rustc_hir_analysis::hir_ty_to_ty;
 use rustc_lint::{LateContext, LateLintPass, LintContext};
-use rustc_middle::ty::subst::GenericArgKind;
-use rustc_middle::ty::{self};
+use rustc_middle::ty::{self, GenericArgKind};
 use rustc_session::{declare_lint_pass, declare_tool_lint};
 
 declare_clippy_lint! {
@@ -40,7 +39,7 @@ impl LateLintPass<'_> for MsrvAttrImpl {
             if self_ty_def.all_fields().any(|f| {
                 cx.tcx
                     .type_of(f.did)
-                    .subst_identity()
+                    .instantiate_identity()
                     .walk()
                     .filter(|t| matches!(t.unpack(), GenericArgKind::Type(_)))
                     .any(|t| match_type(cx, t.expect_ty(), &paths::MSRV))
diff --git a/clippy_lints/src/utils/internal_lints/unnecessary_def_path.rs b/clippy_lints/src/utils/internal_lints/unnecessary_def_path.rs
index 00842376628..f66f33fee16 100644
--- a/clippy_lints/src/utils/internal_lints/unnecessary_def_path.rs
+++ b/clippy_lints/src/utils/internal_lints/unnecessary_def_path.rs
@@ -229,11 +229,11 @@ fn path_to_matched_type(cx: &LateContext<'_>, expr: &hir::Expr<'_>) -> Option<Ve
             Res::Def(DefKind::Static(_), def_id) => read_mir_alloc_def_path(
                 cx,
                 cx.tcx.eval_static_initializer(def_id).ok()?.inner(),
-                cx.tcx.type_of(def_id).subst_identity(),
+                cx.tcx.type_of(def_id).instantiate_identity(),
             ),
             Res::Def(DefKind::Const, def_id) => match cx.tcx.const_eval_poly(def_id).ok()? {
                 ConstValue::ByRef { alloc, offset } if offset.bytes() == 0 => {
-                    read_mir_alloc_def_path(cx, alloc.inner(), cx.tcx.type_of(def_id).subst_identity())
+                    read_mir_alloc_def_path(cx, alloc.inner(), cx.tcx.type_of(def_id).instantiate_identity())
                 },
                 _ => None,
             },
diff --git a/clippy_lints/src/utils/mod.rs b/clippy_lints/src/utils/mod.rs
index fb08256931f..4fef8c0717d 100644
--- a/clippy_lints/src/utils/mod.rs
+++ b/clippy_lints/src/utils/mod.rs
@@ -18,7 +18,7 @@ const BOOK_CONFIGS_PATH: &str = "https://doc.rust-lang.org/clippy/lint_configura
 // ==================================================================
 // Configuration
 // ==================================================================
-#[derive(Debug, Clone, Default)] //~ ERROR no such field
+#[derive(Debug, Clone, Default)]
 pub struct ClippyConfiguration {
     pub name: String,
     #[allow(dead_code)]
diff --git a/clippy_lints/src/vec.rs b/clippy_lints/src/vec.rs
index 6a96114ae76..fc17e7c6d5a 100644
--- a/clippy_lints/src/vec.rs
+++ b/clippy_lints/src/vec.rs
@@ -234,8 +234,8 @@ fn size_of(cx: &LateContext<'_>, expr: &Expr<'_>) -> u64 {
 
 /// Returns the item type of the vector (i.e., the `T` in `Vec<T>`).
 fn vec_type(ty: Ty<'_>) -> Ty<'_> {
-    if let ty::Adt(_, substs) = ty.kind() {
-        substs.type_at(0)
+    if let ty::Adt(_, args) = ty.kind() {
+        args.type_at(0)
     } else {
         panic!("The type of `vec!` is a not a struct?");
     }
diff --git a/clippy_lints/src/zero_sized_map_values.rs b/clippy_lints/src/zero_sized_map_values.rs
index 93e4b023c5c..002304f8840 100644
--- a/clippy_lints/src/zero_sized_map_values.rs
+++ b/clippy_lints/src/zero_sized_map_values.rs
@@ -51,8 +51,8 @@ impl LateLintPass<'_> for ZeroSizedMapValues {
             if !in_trait_impl(cx, hir_ty.hir_id);
             let ty = ty_from_hir_ty(cx, hir_ty);
             if is_type_diagnostic_item(cx, ty, sym::HashMap) || is_type_diagnostic_item(cx, ty, sym::BTreeMap);
-            if let Adt(_, substs) = ty.kind();
-            let ty = substs.type_at(1);
+            if let Adt(_, args) = ty.kind();
+            let ty = args.type_at(1);
             // Fixes https://github.com/rust-lang/rust-clippy/issues/7447 because of
             // https://github.com/rust-lang/rust/blob/master/compiler/rustc_middle/src/ty/sty.rs#L968
             if !ty.has_escaping_bound_vars();
diff --git a/clippy_utils/src/consts.rs b/clippy_utils/src/consts.rs
index 419b139f400..63dfd2145b8 100644
--- a/clippy_utils/src/consts.rs
+++ b/clippy_utils/src/consts.rs
@@ -10,7 +10,7 @@ use rustc_hir::{BinOp, BinOpKind, Block, ConstBlock, Expr, ExprKind, HirId, Item
 use rustc_lexer::tokenize;
 use rustc_lint::LateContext;
 use rustc_middle::mir::interpret::Scalar;
-use rustc_middle::ty::{self, EarlyBinder, FloatTy, List, ScalarInt, SubstsRef, Ty, TyCtxt};
+use rustc_middle::ty::{self, EarlyBinder, FloatTy, GenericArgsRef, List, ScalarInt, Ty, TyCtxt};
 use rustc_middle::{bug, mir, span_bug};
 use rustc_span::symbol::{Ident, Symbol};
 use rustc_span::SyntaxContext;
@@ -325,17 +325,17 @@ pub struct ConstEvalLateContext<'a, 'tcx> {
     typeck_results: &'a ty::TypeckResults<'tcx>,
     param_env: ty::ParamEnv<'tcx>,
     source: ConstantSource,
-    substs: SubstsRef<'tcx>,
+    args: GenericArgsRef<'tcx>,
 }
 
 impl<'a, 'tcx> ConstEvalLateContext<'a, 'tcx> {
-    fn new(lcx: &'a LateContext<'tcx>, typeck_results: &'a ty::TypeckResults<'tcx>) -> Self {
+    pub fn new(lcx: &'a LateContext<'tcx>, typeck_results: &'a ty::TypeckResults<'tcx>) -> Self {
         Self {
             lcx,
             typeck_results,
             param_env: lcx.param_env,
             source: ConstantSource::Local,
-            substs: List::empty(),
+            args: List::empty(),
         }
     }
 
@@ -471,16 +471,16 @@ impl<'a, 'tcx> ConstEvalLateContext<'a, 'tcx> {
                     return None;
                 }
 
-                let substs = self.typeck_results.node_substs(id);
-                let substs = if self.substs.is_empty() {
-                    substs
+                let args = self.typeck_results.node_args(id);
+                let args = if self.args.is_empty() {
+                    args
                 } else {
-                    EarlyBinder::bind(substs).subst(self.lcx.tcx, self.substs)
+                    EarlyBinder::bind(args).instantiate(self.lcx.tcx, self.args)
                 };
                 let result = self
                     .lcx
                     .tcx
-                    .const_eval_resolve(self.param_env, mir::UnevaluatedConst::new(def_id, substs), None)
+                    .const_eval_resolve(self.param_env, mir::UnevaluatedConst::new(def_id, args), None)
                     .ok()
                     .map(|val| rustc_middle::mir::ConstantKind::from_value(val, ty))?;
                 let result = miri_to_const(self.lcx, result)?;
diff --git a/clippy_utils/src/eager_or_lazy.rs b/clippy_utils/src/eager_or_lazy.rs
index 29b73ab4cd5..3c969572b8e 100644
--- a/clippy_utils/src/eager_or_lazy.rs
+++ b/clippy_utils/src/eager_or_lazy.rs
@@ -51,7 +51,7 @@ fn fn_eagerness(cx: &LateContext<'_>, fn_id: DefId, name: Symbol, have_one_arg:
     let name = name.as_str();
 
     let ty = match cx.tcx.impl_of_method(fn_id) {
-        Some(id) => cx.tcx.type_of(id).subst_identity(),
+        Some(id) => cx.tcx.type_of(id).instantiate_identity(),
         None => return Lazy,
     };
 
@@ -68,19 +68,24 @@ fn fn_eagerness(cx: &LateContext<'_>, fn_id: DefId, name: Symbol, have_one_arg:
         // Types where the only fields are generic types (or references to) with no trait bounds other
         // than marker traits.
         // Due to the limited operations on these types functions should be fairly cheap.
-        if def
-            .variants()
-            .iter()
-            .flat_map(|v| v.fields.iter())
-            .any(|x| matches!(cx.tcx.type_of(x.did).subst_identity().peel_refs().kind(), ty::Param(_)))
-            && all_predicates_of(cx.tcx, fn_id).all(|(pred, _)| match pred.kind().skip_binder() {
-                ty::ClauseKind::Trait(pred) => cx.tcx.trait_def(pred.trait_ref.def_id).is_marker,
-                _ => true,
-            })
-            && subs.types().all(|x| matches!(x.peel_refs().kind(), ty::Param(_)))
+        if def.variants().iter().flat_map(|v| v.fields.iter()).any(|x| {
+            matches!(
+                cx.tcx.type_of(x.did).instantiate_identity().peel_refs().kind(),
+                ty::Param(_)
+            )
+        }) && all_predicates_of(cx.tcx, fn_id).all(|(pred, _)| match pred.kind().skip_binder() {
+            ty::ClauseKind::Trait(pred) => cx.tcx.trait_def(pred.trait_ref.def_id).is_marker,
+            _ => true,
+        }) && subs.types().all(|x| matches!(x.peel_refs().kind(), ty::Param(_)))
         {
             // Limit the function to either `(self) -> bool` or `(&self) -> bool`
-            match &**cx.tcx.fn_sig(fn_id).subst_identity().skip_binder().inputs_and_output {
+            match &**cx
+                .tcx
+                .fn_sig(fn_id)
+                .instantiate_identity()
+                .skip_binder()
+                .inputs_and_output
+            {
                 [arg, res] if !arg.is_mutable_ptr() && arg.peel_refs() == ty && res.is_bool() => NoChange,
                 _ => Lazy,
             }
diff --git a/clippy_utils/src/hir_utils.rs b/clippy_utils/src/hir_utils.rs
index fb359ee3bbe..85b3b005f93 100644
--- a/clippy_utils/src/hir_utils.rs
+++ b/clippy_utils/src/hir_utils.rs
@@ -252,15 +252,15 @@ impl HirEqInterExpr<'_, '_, '_> {
             return false;
         }
 
-        if let Some((typeck_lhs, typeck_rhs)) = self.inner.maybe_typeck_results {
-            if let (Some(l), Some(r)) = (
+        if let Some((typeck_lhs, typeck_rhs)) = self.inner.maybe_typeck_results
+            && typeck_lhs.expr_ty(left) == typeck_rhs.expr_ty(right)
+            && let (Some(l), Some(r)) = (
                 constant_simple(self.inner.cx, typeck_lhs, left),
                 constant_simple(self.inner.cx, typeck_rhs, right),
-            ) {
-                if l == r {
-                    return true;
-                }
-            }
+            )
+            && l == r
+        {
+            return true;
         }
 
         let is_eq = match (
@@ -494,10 +494,13 @@ impl HirEqInterExpr<'_, '_, '_> {
             loop {
                 use TokenKind::{BlockComment, LineComment, Whitespace};
                 if left_data.macro_def_id != right_data.macro_def_id
-                    || (matches!(left_data.kind, ExpnKind::Macro(MacroKind::Bang, name) if name == sym::cfg)
-                        && !eq_span_tokens(self.inner.cx, left_data.call_site, right_data.call_site, |t| {
-                            !matches!(t, Whitespace | LineComment { .. } | BlockComment { .. })
-                        }))
+                    || (matches!(
+                        left_data.kind,
+                        ExpnKind::Macro(MacroKind::Bang, name)
+                        if name == sym::cfg || name == sym::option_env
+                    ) && !eq_span_tokens(self.inner.cx, left_data.call_site, right_data.call_site, |t| {
+                        !matches!(t, Whitespace | LineComment { .. } | BlockComment { .. })
+                    }))
                 {
                     // Either a different chain of macro calls, or different arguments to the `cfg` macro.
                     return false;
diff --git a/clippy_utils/src/lib.rs b/clippy_utils/src/lib.rs
index cf33076d356..d3a219f5326 100644
--- a/clippy_utils/src/lib.rs
+++ b/clippy_utils/src/lib.rs
@@ -89,24 +89,21 @@ use rustc_hir::intravisit::{walk_expr, FnKind, Visitor};
 use rustc_hir::LangItem::{OptionNone, OptionSome, ResultErr, ResultOk};
 use rustc_hir::{
     self as hir, def, Arm, ArrayLen, BindingAnnotation, Block, BlockCheckMode, Body, Closure, Destination, Expr,
-    ExprKind, FnDecl, HirId, Impl, ImplItem, ImplItemKind, ImplItemRef, IsAsync, Item, ItemKind, LangItem, Local,
-    MatchSource, Mutability, Node, OwnerId, Param, Pat, PatKind, Path, PathSegment, PrimTy, QPath, Stmt, StmtKind,
-    TraitItem, TraitItemRef, TraitRef, TyKind, UnOp,
+    ExprField, ExprKind, FnDecl, FnRetTy, GenericArgs, HirId, Impl, ImplItem, ImplItemKind, ImplItemRef, IsAsync, Item,
+    ItemKind, LangItem, Local, MatchSource, Mutability, Node, OwnerId, Param, Pat, PatKind, Path, PathSegment, PrimTy,
+    QPath, Stmt, StmtKind, TraitItem, TraitItemKind, TraitItemRef, TraitRef, TyKind, UnOp,
 };
 use rustc_lexer::{tokenize, TokenKind};
 use rustc_lint::{LateContext, Level, Lint, LintContext};
 use rustc_middle::hir::place::PlaceBase;
 use rustc_middle::mir::ConstantKind;
-use rustc_middle::ty as rustc_ty;
 use rustc_middle::ty::adjustment::{Adjust, Adjustment, AutoBorrow};
 use rustc_middle::ty::binding::BindingMode;
-use rustc_middle::ty::fast_reject::SimplifiedType::{
-    ArraySimplifiedType, BoolSimplifiedType, CharSimplifiedType, FloatSimplifiedType, IntSimplifiedType,
-    PtrSimplifiedType, SliceSimplifiedType, StrSimplifiedType, UintSimplifiedType,
-};
+use rustc_middle::ty::fast_reject::SimplifiedType;
 use rustc_middle::ty::layout::IntegerExt;
 use rustc_middle::ty::{
-    BorrowKind, ClosureKind, FloatTy, IntTy, Ty, TyCtxt, TypeAndMut, TypeVisitableExt, UintTy, UpvarCapture,
+    self as rustc_ty, Binder, BorrowKind, ClosureKind, FloatTy, IntTy, ParamEnv, ParamEnvAnd, Ty, TyCtxt, TypeAndMut,
+    TypeVisitableExt, UintTy, UpvarCapture,
 };
 use rustc_span::hygiene::{ExpnKind, MacroKind};
 use rustc_span::source_map::SourceMap;
@@ -116,7 +113,10 @@ use rustc_target::abi::Integer;
 
 use crate::consts::{constant, miri_to_const, Constant};
 use crate::higher::Range;
-use crate::ty::{can_partially_move_ty, expr_sig, is_copy, is_recursively_primitive_type, ty_is_fn_once_param};
+use crate::ty::{
+    adt_and_variant_of_res, can_partially_move_ty, expr_sig, is_copy, is_recursively_primitive_type,
+    ty_is_fn_once_param,
+};
 use crate::visitors::for_each_expr;
 
 use rustc_middle::hir::nested_filter;
@@ -303,7 +303,7 @@ pub fn match_trait_method(cx: &LateContext<'_>, expr: &Expr<'_>, path: &[&str])
 /// Checks if a method is defined in an impl of a diagnostic item
 pub fn is_diag_item_method(cx: &LateContext<'_>, def_id: DefId, diag_item: Symbol) -> bool {
     if let Some(impl_did) = cx.tcx.impl_of_method(def_id) {
-        if let Some(adt) = cx.tcx.type_of(impl_did).subst_identity().ty_adt_def() {
+        if let Some(adt) = cx.tcx.type_of(impl_did).instantiate_identity().ty_adt_def() {
             return cx.tcx.is_diagnostic_item(diag_item, adt.did());
         }
     }
@@ -512,30 +512,30 @@ pub fn path_def_id<'tcx>(cx: &LateContext<'_>, maybe_path: &impl MaybePath<'tcx>
 
 fn find_primitive_impls<'tcx>(tcx: TyCtxt<'tcx>, name: &str) -> impl Iterator<Item = DefId> + 'tcx {
     let ty = match name {
-        "bool" => BoolSimplifiedType,
-        "char" => CharSimplifiedType,
-        "str" => StrSimplifiedType,
-        "array" => ArraySimplifiedType,
-        "slice" => SliceSimplifiedType,
+        "bool" => SimplifiedType::Bool,
+        "char" => SimplifiedType::Char,
+        "str" => SimplifiedType::Str,
+        "array" => SimplifiedType::Array,
+        "slice" => SimplifiedType::Slice,
         // FIXME: rustdoc documents these two using just `pointer`.
         //
         // Maybe this is something we should do here too.
-        "const_ptr" => PtrSimplifiedType(Mutability::Not),
-        "mut_ptr" => PtrSimplifiedType(Mutability::Mut),
-        "isize" => IntSimplifiedType(IntTy::Isize),
-        "i8" => IntSimplifiedType(IntTy::I8),
-        "i16" => IntSimplifiedType(IntTy::I16),
-        "i32" => IntSimplifiedType(IntTy::I32),
-        "i64" => IntSimplifiedType(IntTy::I64),
-        "i128" => IntSimplifiedType(IntTy::I128),
-        "usize" => UintSimplifiedType(UintTy::Usize),
-        "u8" => UintSimplifiedType(UintTy::U8),
-        "u16" => UintSimplifiedType(UintTy::U16),
-        "u32" => UintSimplifiedType(UintTy::U32),
-        "u64" => UintSimplifiedType(UintTy::U64),
-        "u128" => UintSimplifiedType(UintTy::U128),
-        "f32" => FloatSimplifiedType(FloatTy::F32),
-        "f64" => FloatSimplifiedType(FloatTy::F64),
+        "const_ptr" => SimplifiedType::Ptr(Mutability::Not),
+        "mut_ptr" => SimplifiedType::Ptr(Mutability::Mut),
+        "isize" => SimplifiedType::Int(IntTy::Isize),
+        "i8" => SimplifiedType::Int(IntTy::I8),
+        "i16" => SimplifiedType::Int(IntTy::I16),
+        "i32" => SimplifiedType::Int(IntTy::I32),
+        "i64" => SimplifiedType::Int(IntTy::I64),
+        "i128" => SimplifiedType::Int(IntTy::I128),
+        "usize" => SimplifiedType::Uint(UintTy::Usize),
+        "u8" => SimplifiedType::Uint(UintTy::U8),
+        "u16" => SimplifiedType::Uint(UintTy::U16),
+        "u32" => SimplifiedType::Uint(UintTy::U32),
+        "u64" => SimplifiedType::Uint(UintTy::U64),
+        "u128" => SimplifiedType::Uint(UintTy::U128),
+        "f32" => SimplifiedType::Float(FloatTy::F32),
+        "f64" => SimplifiedType::Float(FloatTy::F64),
         _ => return [].iter().copied(),
     };
 
@@ -810,7 +810,7 @@ fn is_default_equivalent_ctor(cx: &LateContext<'_>, def_id: DefId, path: &QPath<
     if let QPath::TypeRelative(_, method) = path {
         if method.ident.name == sym::new {
             if let Some(impl_did) = cx.tcx.impl_of_method(def_id) {
-                if let Some(adt) = cx.tcx.type_of(impl_did).subst_identity().ty_adt_def() {
+                if let Some(adt) = cx.tcx.type_of(impl_did).instantiate_identity().ty_adt_def() {
                     return std_types_symbols.iter().any(|&symbol| {
                         cx.tcx.is_diagnostic_item(symbol, adt.did()) || Some(adt.did()) == cx.tcx.lang_items().string()
                     });
@@ -1375,7 +1375,7 @@ pub fn get_enclosing_loop_or_multi_call_closure<'tcx>(
                                     .chain(args.iter())
                                     .position(|arg| arg.hir_id == id)?;
                                 let id = cx.typeck_results().type_dependent_def_id(e.hir_id)?;
-                                let ty = cx.tcx.fn_sig(id).subst_identity().skip_binder().inputs()[i];
+                                let ty = cx.tcx.fn_sig(id).instantiate_identity().skip_binder().inputs()[i];
                                 ty_is_fn_once_param(cx.tcx, ty, cx.tcx.param_env(id).caller_bounds()).then_some(())
                             },
                             _ => None,
@@ -1637,13 +1637,13 @@ pub fn is_direct_expn_of(span: Span, name: &str) -> Option<Span> {
 
 /// Convenience function to get the return type of a function.
 pub fn return_ty<'tcx>(cx: &LateContext<'tcx>, fn_def_id: hir::OwnerId) -> Ty<'tcx> {
-    let ret_ty = cx.tcx.fn_sig(fn_def_id).subst_identity().output();
+    let ret_ty = cx.tcx.fn_sig(fn_def_id).instantiate_identity().output();
     cx.tcx.erase_late_bound_regions(ret_ty)
 }
 
 /// Convenience function to get the nth argument type of a function.
 pub fn nth_arg<'tcx>(cx: &LateContext<'tcx>, fn_def_id: hir::OwnerId, nth: usize) -> Ty<'tcx> {
-    let arg = cx.tcx.fn_sig(fn_def_id).subst_identity().input(nth);
+    let arg = cx.tcx.fn_sig(fn_def_id).instantiate_identity().input(nth);
     cx.tcx.erase_late_bound_regions(arg)
 }
 
@@ -2448,6 +2448,17 @@ pub fn is_in_cfg_test(tcx: TyCtxt<'_>, id: hir::HirId) -> bool {
         .any(is_cfg_test)
 }
 
+/// Checks if the item of any of its parents has `#[cfg(...)]` attribute applied.
+pub fn inherits_cfg(tcx: TyCtxt<'_>, def_id: LocalDefId) -> bool {
+    let hir = tcx.hir();
+
+    tcx.has_attr(def_id, sym::cfg)
+        || hir
+            .parent_iter(hir.local_def_id_to_hir_id(def_id))
+            .flat_map(|(parent_id, _)| hir.attrs(parent_id))
+            .any(|attr| attr.has_name(sym::cfg))
+}
+
 /// Checks whether item either has `test` attribute applied, or
 /// is a module with `test` in its name.
 ///
@@ -2502,6 +2513,262 @@ pub fn walk_to_expr_usage<'tcx, T>(
     None
 }
 
+/// A type definition as it would be viewed from within a function.
+#[derive(Clone, Copy)]
+pub enum DefinedTy<'tcx> {
+    // Used for locals and closures defined within the function.
+    Hir(&'tcx hir::Ty<'tcx>),
+    /// Used for function signatures, and constant and static values. This includes the `ParamEnv`
+    /// from the definition site.
+    Mir(ParamEnvAnd<'tcx, Binder<'tcx, Ty<'tcx>>>),
+}
+
+/// The context an expressions value is used in.
+pub struct ExprUseCtxt<'tcx> {
+    /// The parent node which consumes the value.
+    pub node: ExprUseNode<'tcx>,
+    /// Any adjustments applied to the type.
+    pub adjustments: &'tcx [Adjustment<'tcx>],
+    /// Whether or not the type must unify with another code path.
+    pub is_ty_unified: bool,
+    /// Whether or not the value will be moved before it's used.
+    pub moved_before_use: bool,
+}
+
+/// The node which consumes a value.
+pub enum ExprUseNode<'tcx> {
+    /// Assignment to, or initializer for, a local
+    Local(&'tcx Local<'tcx>),
+    /// Initializer for a const or static item.
+    ConstStatic(OwnerId),
+    /// Implicit or explicit return from a function.
+    Return(OwnerId),
+    /// Initialization of a struct field.
+    Field(&'tcx ExprField<'tcx>),
+    /// An argument to a function.
+    FnArg(&'tcx Expr<'tcx>, usize),
+    /// An argument to a method.
+    MethodArg(HirId, Option<&'tcx GenericArgs<'tcx>>, usize),
+    /// The callee of a function call.
+    Callee,
+    /// Access of a field.
+    FieldAccess(Ident),
+}
+impl<'tcx> ExprUseNode<'tcx> {
+    /// Checks if the value is returned from the function.
+    pub fn is_return(&self) -> bool {
+        matches!(self, Self::Return(_))
+    }
+
+    /// Checks if the value is used as a method call receiver.
+    pub fn is_recv(&self) -> bool {
+        matches!(self, Self::MethodArg(_, _, 0))
+    }
+
+    /// Gets the needed type as it's defined without any type inference.
+    pub fn defined_ty(&self, cx: &LateContext<'tcx>) -> Option<DefinedTy<'tcx>> {
+        match *self {
+            Self::Local(Local { ty: Some(ty), .. }) => Some(DefinedTy::Hir(ty)),
+            Self::ConstStatic(id) => Some(DefinedTy::Mir(
+                cx.param_env
+                    .and(Binder::dummy(cx.tcx.type_of(id).instantiate_identity())),
+            )),
+            Self::Return(id) => {
+                let hir_id = cx.tcx.hir().local_def_id_to_hir_id(id.def_id);
+                if let Some(Node::Expr(Expr {
+                    kind: ExprKind::Closure(c),
+                    ..
+                })) = cx.tcx.hir().find(hir_id)
+                {
+                    match c.fn_decl.output {
+                        FnRetTy::DefaultReturn(_) => None,
+                        FnRetTy::Return(ty) => Some(DefinedTy::Hir(ty)),
+                    }
+                } else {
+                    Some(DefinedTy::Mir(
+                        cx.param_env.and(cx.tcx.fn_sig(id).instantiate_identity().output()),
+                    ))
+                }
+            },
+            Self::Field(field) => match get_parent_expr_for_hir(cx, field.hir_id) {
+                Some(Expr {
+                    hir_id,
+                    kind: ExprKind::Struct(path, ..),
+                    ..
+                }) => adt_and_variant_of_res(cx, cx.qpath_res(path, *hir_id))
+                    .and_then(|(adt, variant)| {
+                        variant
+                            .fields
+                            .iter()
+                            .find(|f| f.name == field.ident.name)
+                            .map(|f| (adt, f))
+                    })
+                    .map(|(adt, field_def)| {
+                        DefinedTy::Mir(
+                            cx.tcx
+                                .param_env(adt.did())
+                                .and(Binder::dummy(cx.tcx.type_of(field_def.did).instantiate_identity())),
+                        )
+                    }),
+                _ => None,
+            },
+            Self::FnArg(callee, i) => {
+                let sig = expr_sig(cx, callee)?;
+                let (hir_ty, ty) = sig.input_with_hir(i)?;
+                Some(match hir_ty {
+                    Some(hir_ty) => DefinedTy::Hir(hir_ty),
+                    None => DefinedTy::Mir(
+                        sig.predicates_id()
+                            .map_or(ParamEnv::empty(), |id| cx.tcx.param_env(id))
+                            .and(ty),
+                    ),
+                })
+            },
+            Self::MethodArg(id, _, i) => {
+                let id = cx.typeck_results().type_dependent_def_id(id)?;
+                let sig = cx.tcx.fn_sig(id).skip_binder();
+                Some(DefinedTy::Mir(cx.tcx.param_env(id).and(sig.input(i))))
+            },
+            Self::Local(_) | Self::FieldAccess(..) | Self::Callee => None,
+        }
+    }
+}
+
+/// Gets the context an expression's value is used in.
+#[expect(clippy::too_many_lines)]
+pub fn expr_use_ctxt<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'tcx>) -> Option<ExprUseCtxt<'tcx>> {
+    let mut adjustments = [].as_slice();
+    let mut is_ty_unified = false;
+    let mut moved_before_use = false;
+    let ctxt = e.span.ctxt();
+    walk_to_expr_usage(cx, e, &mut |parent, child_id| {
+        // LocalTableInContext returns the wrong lifetime, so go use `expr_adjustments` instead.
+        if adjustments.is_empty() && let Node::Expr(e) = cx.tcx.hir().get(child_id) {
+            adjustments = cx.typeck_results().expr_adjustments(e);
+        }
+        match parent {
+            Node::Local(l) if l.span.ctxt() == ctxt => Some(ExprUseCtxt {
+                node: ExprUseNode::Local(l),
+                adjustments,
+                is_ty_unified,
+                moved_before_use,
+            }),
+            Node::Item(&Item {
+                kind: ItemKind::Static(..) | ItemKind::Const(..),
+                owner_id,
+                span,
+                ..
+            })
+            | Node::TraitItem(&TraitItem {
+                kind: TraitItemKind::Const(..),
+                owner_id,
+                span,
+                ..
+            })
+            | Node::ImplItem(&ImplItem {
+                kind: ImplItemKind::Const(..),
+                owner_id,
+                span,
+                ..
+            }) if span.ctxt() == ctxt => Some(ExprUseCtxt {
+                node: ExprUseNode::ConstStatic(owner_id),
+                adjustments,
+                is_ty_unified,
+                moved_before_use,
+            }),
+
+            Node::Item(&Item {
+                kind: ItemKind::Fn(..),
+                owner_id,
+                span,
+                ..
+            })
+            | Node::TraitItem(&TraitItem {
+                kind: TraitItemKind::Fn(..),
+                owner_id,
+                span,
+                ..
+            })
+            | Node::ImplItem(&ImplItem {
+                kind: ImplItemKind::Fn(..),
+                owner_id,
+                span,
+                ..
+            }) if span.ctxt() == ctxt => Some(ExprUseCtxt {
+                node: ExprUseNode::Return(owner_id),
+                adjustments,
+                is_ty_unified,
+                moved_before_use,
+            }),
+
+            Node::ExprField(field) if field.span.ctxt() == ctxt => Some(ExprUseCtxt {
+                node: ExprUseNode::Field(field),
+                adjustments,
+                is_ty_unified,
+                moved_before_use,
+            }),
+
+            Node::Expr(parent) if parent.span.ctxt() == ctxt => match parent.kind {
+                ExprKind::Ret(_) => Some(ExprUseCtxt {
+                    node: ExprUseNode::Return(OwnerId {
+                        def_id: cx.tcx.hir().body_owner_def_id(cx.enclosing_body.unwrap()),
+                    }),
+                    adjustments,
+                    is_ty_unified,
+                    moved_before_use,
+                }),
+                ExprKind::Closure(closure) => Some(ExprUseCtxt {
+                    node: ExprUseNode::Return(OwnerId { def_id: closure.def_id }),
+                    adjustments,
+                    is_ty_unified,
+                    moved_before_use,
+                }),
+                ExprKind::Call(func, args) => Some(ExprUseCtxt {
+                    node: match args.iter().position(|arg| arg.hir_id == child_id) {
+                        Some(i) => ExprUseNode::FnArg(func, i),
+                        None => ExprUseNode::Callee,
+                    },
+                    adjustments,
+                    is_ty_unified,
+                    moved_before_use,
+                }),
+                ExprKind::MethodCall(name, _, args, _) => Some(ExprUseCtxt {
+                    node: ExprUseNode::MethodArg(
+                        parent.hir_id,
+                        name.args,
+                        args.iter().position(|arg| arg.hir_id == child_id).map_or(0, |i| i + 1),
+                    ),
+                    adjustments,
+                    is_ty_unified,
+                    moved_before_use,
+                }),
+                ExprKind::Field(child, name) if child.hir_id == e.hir_id => Some(ExprUseCtxt {
+                    node: ExprUseNode::FieldAccess(name),
+                    adjustments,
+                    is_ty_unified,
+                    moved_before_use,
+                }),
+                ExprKind::If(e, _, _) | ExprKind::Match(e, _, _) if e.hir_id != child_id => {
+                    is_ty_unified = true;
+                    moved_before_use = true;
+                    None
+                },
+                ExprKind::Block(_, Some(_)) | ExprKind::Break(..) => {
+                    is_ty_unified = true;
+                    moved_before_use = true;
+                    None
+                },
+                ExprKind::Block(..) => {
+                    moved_before_use = true;
+                    None
+                },
+                _ => None,
+            },
+            _ => None,
+        }
+    })
+}
+
 /// Tokenizes the input while keeping the text associated with each token.
 pub fn tokenize_with_text(s: &str) -> impl Iterator<Item = (TokenKind, &str)> {
     let mut pos = 0;
diff --git a/clippy_utils/src/mir/possible_origin.rs b/clippy_utils/src/mir/possible_origin.rs
index 8e7513d740a..da04266863f 100644
--- a/clippy_utils/src/mir/possible_origin.rs
+++ b/clippy_utils/src/mir/possible_origin.rs
@@ -44,7 +44,7 @@ impl<'a, 'tcx> mir::visit::Visitor<'tcx> for PossibleOriginVisitor<'a, 'tcx> {
         let lhs = place.local;
         match rvalue {
             // Only consider `&mut`, which can modify origin place
-            mir::Rvalue::Ref(_, rustc_middle::mir::BorrowKind::Mut { .. }, borrowed) |
+            mir::Rvalue::Ref(_, mir::BorrowKind::Mut { .. }, borrowed) |
             // _2: &mut _;
             // _3 = move _2
             mir::Rvalue::Use(mir::Operand::Move(borrowed))  |
diff --git a/clippy_utils/src/paths.rs b/clippy_utils/src/paths.rs
index f3677e6f614..914ea85ac28 100644
--- a/clippy_utils/src/paths.rs
+++ b/clippy_utils/src/paths.rs
@@ -149,6 +149,7 @@ pub const VEC_AS_SLICE: [&str; 4] = ["alloc", "vec", "Vec", "as_slice"];
 pub const VEC_DEQUE_ITER: [&str; 5] = ["alloc", "collections", "vec_deque", "VecDeque", "iter"];
 pub const VEC_FROM_ELEM: [&str; 3] = ["alloc", "vec", "from_elem"];
 pub const VEC_NEW: [&str; 4] = ["alloc", "vec", "Vec", "new"];
+pub const VEC_WITH_CAPACITY: [&str; 4] = ["alloc", "vec", "Vec", "with_capacity"];
 pub const VEC_RESIZE: [&str; 4] = ["alloc", "vec", "Vec", "resize"];
 pub const WEAK_ARC: [&str; 3] = ["alloc", "sync", "Weak"];
 pub const WEAK_RC: [&str; 3] = ["alloc", "rc", "Weak"];
@@ -161,3 +162,6 @@ pub const OPTION_UNWRAP: [&str; 4] = ["core", "option", "Option", "unwrap"];
 pub const OPTION_EXPECT: [&str; 4] = ["core", "option", "Option", "expect"];
 pub const FORMATTER: [&str; 3] = ["core", "fmt", "Formatter"];
 pub const DEBUG_STRUCT: [&str; 4] = ["core", "fmt", "builders", "DebugStruct"];
+pub const ORD_CMP: [&str; 4] = ["core", "cmp", "Ord", "cmp"];
+#[expect(clippy::invalid_paths)] // not sure why it thinks this, it works so
+pub const BOOL_THEN: [&str; 4] = ["core", "bool", "<impl bool>", "then"];
diff --git a/clippy_utils/src/qualify_min_const_fn.rs b/clippy_utils/src/qualify_min_const_fn.rs
index 1c7469081a3..7a7ed41e527 100644
--- a/clippy_utils/src/qualify_min_const_fn.rs
+++ b/clippy_utils/src/qualify_min_const_fn.rs
@@ -14,10 +14,9 @@ use rustc_middle::mir::{
     Body, CastKind, NonDivergingIntrinsic, NullOp, Operand, Place, ProjectionElem, Rvalue, Statement, StatementKind,
     Terminator, TerminatorKind,
 };
-use rustc_middle::traits::{ImplSource, ObligationCause};
+use rustc_middle::traits::{BuiltinImplSource, ImplSource, ObligationCause};
 use rustc_middle::ty::adjustment::PointerCoercion;
-use rustc_middle::ty::subst::GenericArgKind;
-use rustc_middle::ty::{self, BoundConstness, TraitRef, Ty, TyCtxt};
+use rustc_middle::ty::{self, BoundConstness, GenericArgKind, TraitRef, Ty, TyCtxt};
 use rustc_semver::RustcVersion;
 use rustc_span::symbol::sym;
 use rustc_span::Span;
@@ -35,7 +34,7 @@ pub fn is_min_const_fn<'tcx>(tcx: TyCtxt<'tcx>, body: &Body<'tcx>, msrv: &Msrv)
     // impl trait is gone in MIR, so check the return type manually
     check_ty(
         tcx,
-        tcx.fn_sig(def_id).subst_identity().output().skip_binder(),
+        tcx.fn_sig(def_id).instantiate_identity().output().skip_binder(),
         body.local_decls.iter().next().unwrap().source_info.span,
     )?;
 
@@ -412,7 +411,7 @@ fn is_ty_const_destruct<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>, body: &Body<'tcx>
 
     if !matches!(
         impl_src,
-        ImplSource::Builtin(_) | ImplSource::Param(_, ty::BoundConstness::ConstIfConst)
+        ImplSource::Builtin(BuiltinImplSource::Misc, _) | ImplSource::Param(ty::BoundConstness::ConstIfConst, _)
     ) {
         return false;
     }
diff --git a/clippy_utils/src/sugg.rs b/clippy_utils/src/sugg.rs
index de3aad64757..5d7e1494fcf 100644
--- a/clippy_utils/src/sugg.rs
+++ b/clippy_utils/src/sugg.rs
@@ -877,7 +877,7 @@ impl<'tcx> DerefDelegate<'_, 'tcx> {
                     .cx
                     .typeck_results()
                     .type_dependent_def_id(parent_expr.hir_id)
-                    .map(|did| self.cx.tcx.fn_sig(did).subst_identity().skip_binder())
+                    .map(|did| self.cx.tcx.fn_sig(did).instantiate_identity().skip_binder())
                 {
                     std::iter::once(receiver)
                         .chain(call_args.iter())
diff --git a/clippy_utils/src/ty.rs b/clippy_utils/src/ty.rs
index 53152ab7e13..98e163abc58 100644
--- a/clippy_utils/src/ty.rs
+++ b/clippy_utils/src/ty.rs
@@ -3,6 +3,7 @@
 #![allow(clippy::module_name_repetitions)]
 
 use core::ops::ControlFlow;
+use itertools::Itertools;
 use rustc_ast::ast::Mutability;
 use rustc_data_structures::fx::{FxHashMap, FxHashSet};
 use rustc_hir as hir;
@@ -13,17 +14,19 @@ use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKi
 use rustc_infer::infer::TyCtxtInferExt;
 use rustc_lint::LateContext;
 use rustc_middle::mir::interpret::{ConstValue, Scalar};
+use rustc_middle::traits::EvaluationResult;
 use rustc_middle::ty::layout::ValidityRequirement;
 use rustc_middle::ty::{
-    self, AdtDef, AliasTy, AssocKind, Binder, BoundRegion, FnSig, GenericArg, GenericArgKind, IntTy, List, ParamEnv,
-    Region, RegionKind, SubstsRef, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable, TypeVisitableExt, TypeVisitor,
-    UintTy, VariantDef, VariantDiscr,
+    self, AdtDef, AliasTy, AssocKind, Binder, BoundRegion, FnSig, GenericArg, GenericArgKind, GenericArgsRef,
+    GenericParamDefKind, IntTy, List, ParamEnv, Region, RegionKind, ToPredicate, TraitRef, Ty, TyCtxt,
+    TypeSuperVisitable, TypeVisitable, TypeVisitableExt, TypeVisitor, UintTy, VariantDef, VariantDiscr,
 };
 use rustc_span::symbol::Ident;
 use rustc_span::{sym, Span, Symbol, DUMMY_SP};
 use rustc_target::abi::{Size, VariantIdx};
-use rustc_trait_selection::infer::InferCtxtExt;
+use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt as _;
 use rustc_trait_selection::traits::query::normalize::QueryNormalizeExt;
+use rustc_trait_selection::traits::{Obligation, ObligationCause};
 use std::iter;
 
 use crate::{match_def_path, path_res, paths};
@@ -91,14 +94,14 @@ pub fn contains_ty_adt_constructor_opaque<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'
                         return false;
                     }
 
-                    for (predicate, _span) in cx.tcx.explicit_item_bounds(def_id).subst_identity_iter_copied() {
+                    for (predicate, _span) in cx.tcx.explicit_item_bounds(def_id).instantiate_identity_iter_copied() {
                         match predicate.kind().skip_binder() {
                             // For `impl Trait<U>`, it will register a predicate of `T: Trait<U>`, so we go through
                             // and check substitutions to find `U`.
                             ty::ClauseKind::Trait(trait_predicate) => {
                                 if trait_predicate
                                     .trait_ref
-                                    .substs
+                                    .args
                                     .types()
                                     .skip(1) // Skip the implicit `Self` generic parameter
                                     .any(|ty| contains_ty_adt_constructor_opaque_inner(cx, ty, needle, seen))
@@ -207,15 +210,9 @@ pub fn implements_trait<'tcx>(
     cx: &LateContext<'tcx>,
     ty: Ty<'tcx>,
     trait_id: DefId,
-    ty_params: &[GenericArg<'tcx>],
+    args: &[GenericArg<'tcx>],
 ) -> bool {
-    implements_trait_with_env(
-        cx.tcx,
-        cx.param_env,
-        ty,
-        trait_id,
-        ty_params.iter().map(|&arg| Some(arg)),
-    )
+    implements_trait_with_env_from_iter(cx.tcx, cx.param_env, ty, trait_id, args.iter().map(|&x| Some(x)))
 }
 
 /// Same as `implements_trait` but allows using a `ParamEnv` different from the lint context.
@@ -224,7 +221,18 @@ pub fn implements_trait_with_env<'tcx>(
     param_env: ParamEnv<'tcx>,
     ty: Ty<'tcx>,
     trait_id: DefId,
-    ty_params: impl IntoIterator<Item = Option<GenericArg<'tcx>>>,
+    args: &[GenericArg<'tcx>],
+) -> bool {
+    implements_trait_with_env_from_iter(tcx, param_env, ty, trait_id, args.iter().map(|&x| Some(x)))
+}
+
+/// Same as `implements_trait_from_env` but takes the arguments as an iterator.
+pub fn implements_trait_with_env_from_iter<'tcx>(
+    tcx: TyCtxt<'tcx>,
+    param_env: ParamEnv<'tcx>,
+    ty: Ty<'tcx>,
+    trait_id: DefId,
+    args: impl IntoIterator<Item = impl Into<Option<GenericArg<'tcx>>>>,
 ) -> bool {
     // Clippy shouldn't have infer types
     assert!(!ty.has_infer());
@@ -233,19 +241,37 @@ pub fn implements_trait_with_env<'tcx>(
     if ty.has_escaping_bound_vars() {
         return false;
     }
+
     let infcx = tcx.infer_ctxt().build();
-    let orig = TypeVariableOrigin {
-        kind: TypeVariableOriginKind::MiscVariable,
-        span: DUMMY_SP,
-    };
-    let ty_params = tcx.mk_substs_from_iter(
-        ty_params
+    let trait_ref = TraitRef::new(
+        tcx,
+        trait_id,
+        Some(GenericArg::from(ty))
             .into_iter()
-            .map(|arg| arg.unwrap_or_else(|| infcx.next_ty_var(orig).into())),
+            .chain(args.into_iter().map(|arg| {
+                arg.into().unwrap_or_else(|| {
+                    let orig = TypeVariableOrigin {
+                        kind: TypeVariableOriginKind::MiscVariable,
+                        span: DUMMY_SP,
+                    };
+                    infcx.next_ty_var(orig).into()
+                })
+            })),
     );
+
+    debug_assert_eq!(tcx.def_kind(trait_id), DefKind::Trait);
+    #[cfg(debug_assertions)]
+    assert_generic_args_match(tcx, trait_id, trait_ref.args);
+
+    let obligation = Obligation {
+        cause: ObligationCause::dummy(),
+        param_env,
+        recursion_depth: 0,
+        predicate: ty::Binder::dummy(trait_ref).without_const().to_predicate(tcx),
+    };
     infcx
-        .type_implements_trait(trait_id, [ty.into()].into_iter().chain(ty_params), param_env)
-        .must_apply_modulo_regions()
+        .evaluate_obligation(&obligation)
+        .is_ok_and(EvaluationResult::must_apply_modulo_regions)
 }
 
 /// Checks whether this type implements `Drop`.
@@ -266,7 +292,7 @@ pub fn is_must_use_ty<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool {
             // because we don't want to lint functions returning empty arrays
             is_must_use_ty(cx, *ty)
         },
-        ty::Tuple(substs) => substs.iter().any(|ty| is_must_use_ty(cx, ty)),
+        ty::Tuple(args) => args.iter().any(|ty| is_must_use_ty(cx, ty)),
         ty::Alias(ty::Opaque, ty::AliasTy { def_id, .. }) => {
             for (predicate, _) in cx.tcx.explicit_item_bounds(def_id).skip_binder() {
                 if let ty::ClauseKind::Trait(trait_predicate) = predicate.kind().skip_binder() {
@@ -315,11 +341,11 @@ fn is_normalizable_helper<'tcx>(
     let cause = rustc_middle::traits::ObligationCause::dummy();
     let result = if infcx.at(&cause, param_env).query_normalize(ty).is_ok() {
         match ty.kind() {
-            ty::Adt(def, substs) => def.variants().iter().all(|variant| {
+            ty::Adt(def, args) => def.variants().iter().all(|variant| {
                 variant
                     .fields
                     .iter()
-                    .all(|field| is_normalizable_helper(cx, param_env, field.ty(cx.tcx, substs), cache))
+                    .all(|field| is_normalizable_helper(cx, param_env, field.ty(cx.tcx, args), cache))
             }),
             _ => ty.walk().all(|generic_arg| match generic_arg.unpack() {
                 GenericArgKind::Type(inner_ty) if inner_ty != ty => {
@@ -393,6 +419,11 @@ pub fn is_type_lang_item(cx: &LateContext<'_>, ty: Ty<'_>, lang_item: hir::LangI
     }
 }
 
+/// Gets the diagnostic name of the type, if it has one
+pub fn type_diagnostic_name(cx: &LateContext<'_>, ty: Ty<'_>) -> Option<Symbol> {
+    ty.ty_adt_def().and_then(|adt| cx.tcx.get_diagnostic_name(adt.did()))
+}
+
 /// Return `true` if the passed `typ` is `isize` or `usize`.
 pub fn is_isize_or_usize(typ: Ty<'_>) -> bool {
     matches!(typ.kind(), ty::Int(IntTy::Isize) | ty::Uint(UintTy::Usize))
@@ -518,14 +549,14 @@ pub fn walk_ptrs_ty_depth(ty: Ty<'_>) -> (Ty<'_>, usize) {
 /// otherwise returns `false`
 pub fn same_type_and_consts<'tcx>(a: Ty<'tcx>, b: Ty<'tcx>) -> bool {
     match (&a.kind(), &b.kind()) {
-        (&ty::Adt(did_a, substs_a), &ty::Adt(did_b, substs_b)) => {
+        (&ty::Adt(did_a, args_a), &ty::Adt(did_b, args_b)) => {
             if did_a != did_b {
                 return false;
             }
 
-            substs_a
+            args_a
                 .iter()
-                .zip(substs_b.iter())
+                .zip(args_b.iter())
                 .all(|(arg_a, arg_b)| match (arg_a.unpack(), arg_b.unpack()) {
                     (GenericArgKind::Const(inner_a), GenericArgKind::Const(inner_b)) => inner_a == inner_b,
                     (GenericArgKind::Type(type_a), GenericArgKind::Type(type_b)) => {
@@ -644,7 +675,7 @@ impl<'tcx> ExprFnSig<'tcx> {
 /// If the expression is function like, get the signature for it.
 pub fn expr_sig<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'_>) -> Option<ExprFnSig<'tcx>> {
     if let Res::Def(DefKind::Fn | DefKind::Ctor(_, CtorKind::Fn) | DefKind::AssocFn, id) = path_res(cx, expr) {
-        Some(ExprFnSig::Sig(cx.tcx.fn_sig(id).subst_identity(), Some(id)))
+        Some(ExprFnSig::Sig(cx.tcx.fn_sig(id).instantiate_identity(), Some(id)))
     } else {
         ty_sig(cx, cx.typeck_results().expr_ty_adjusted(expr).peel_refs())
     }
@@ -662,11 +693,11 @@ pub fn ty_sig<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> Option<ExprFnSig<'t
                 .and_then(|id| cx.tcx.hir().fn_decl_by_hir_id(cx.tcx.hir().local_def_id_to_hir_id(id)));
             Some(ExprFnSig::Closure(decl, subs.as_closure().sig()))
         },
-        ty::FnDef(id, subs) => Some(ExprFnSig::Sig(cx.tcx.fn_sig(id).subst(cx.tcx, subs), Some(id))),
-        ty::Alias(ty::Opaque, ty::AliasTy { def_id, substs, .. }) => sig_from_bounds(
+        ty::FnDef(id, subs) => Some(ExprFnSig::Sig(cx.tcx.fn_sig(id).instantiate(cx.tcx, subs), Some(id))),
+        ty::Alias(ty::Opaque, ty::AliasTy { def_id, args, .. }) => sig_from_bounds(
             cx,
             ty,
-            cx.tcx.item_bounds(def_id).subst_iter(cx.tcx, substs),
+            cx.tcx.item_bounds(def_id).iter_instantiated(cx.tcx, args),
             cx.tcx.opt_parent(def_id),
         ),
         ty::FnPtr(sig) => Some(ExprFnSig::Sig(sig, None)),
@@ -682,7 +713,7 @@ pub fn ty_sig<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> Option<ExprFnSig<'t
                         .projection_bounds()
                         .find(|p| lang_items.fn_once_output().map_or(false, |id| id == p.item_def_id()))
                         .map(|p| p.map_bound(|p| p.term.ty().unwrap()));
-                    Some(ExprFnSig::Trait(bound.map_bound(|b| b.substs.type_at(0)), output, None))
+                    Some(ExprFnSig::Trait(bound.map_bound(|b| b.args.type_at(0)), output, None))
                 },
                 _ => None,
             }
@@ -714,7 +745,7 @@ fn sig_from_bounds<'tcx>(
                     || lang_items.fn_once_trait() == Some(p.def_id()))
                     && p.self_ty() == ty =>
             {
-                let i = pred.kind().rebind(p.trait_ref.substs.type_at(1));
+                let i = pred.kind().rebind(p.trait_ref.args.type_at(1));
                 if inputs.map_or(false, |inputs| i != inputs) {
                     // Multiple different fn trait impls. Is this even allowed?
                     return None;
@@ -745,7 +776,7 @@ fn sig_for_projection<'tcx>(cx: &LateContext<'tcx>, ty: AliasTy<'tcx>) -> Option
     for (pred, _) in cx
         .tcx
         .explicit_item_bounds(ty.def_id)
-        .subst_iter_copied(cx.tcx, ty.substs)
+        .iter_instantiated_copied(cx.tcx, ty.args)
     {
         match pred.kind().skip_binder() {
             ty::ClauseKind::Trait(p)
@@ -753,7 +784,7 @@ fn sig_for_projection<'tcx>(cx: &LateContext<'tcx>, ty: AliasTy<'tcx>) -> Option
                     || lang_items.fn_mut_trait() == Some(p.def_id())
                     || lang_items.fn_once_trait() == Some(p.def_id())) =>
             {
-                let i = pred.kind().rebind(p.trait_ref.substs.type_at(1));
+                let i = pred.kind().rebind(p.trait_ref.args.type_at(1));
 
                 if inputs.map_or(false, |inputs| inputs != i) {
                     // Multiple different fn trait impls. Is this even allowed?
@@ -794,7 +825,7 @@ impl core::ops::Add<u32> for EnumValue {
 #[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).subst_identity().kind() {
+        match tcx.type_of(id).instantiate_identity().kind() {
             ty::Int(_) => Some(EnumValue::Signed(match value.size().bytes() {
                 1 => i128::from(value.assert_bits(Size::from_bytes(1)) as u8 as i8),
                 2 => i128::from(value.assert_bits(Size::from_bytes(2)) as u16 as i16),
@@ -928,7 +959,7 @@ pub fn adt_and_variant_of_res<'tcx>(cx: &LateContext<'tcx>, res: Res) -> Option<
             Some((adt, adt.variant_with_id(var_id)))
         },
         Res::SelfCtor(id) => {
-            let adt = cx.tcx.type_of(id).subst_identity().ty_adt_def().unwrap();
+            let adt = cx.tcx.type_of(id).instantiate_identity().ty_adt_def().unwrap();
             Some((adt, adt.non_enum_variant()))
         },
         _ => None,
@@ -1014,24 +1045,77 @@ pub fn approx_ty_size<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> u64 {
     }
 }
 
+/// Asserts that the given arguments match the generic parameters of the given item.
+#[allow(dead_code)]
+fn assert_generic_args_match<'tcx>(tcx: TyCtxt<'tcx>, did: DefId, args: &[GenericArg<'tcx>]) {
+    let g = tcx.generics_of(did);
+    let parent = g.parent.map(|did| tcx.generics_of(did));
+    let count = g.parent_count + g.params.len();
+    let params = parent
+        .map_or([].as_slice(), |p| p.params.as_slice())
+        .iter()
+        .chain(&g.params)
+        .map(|x| &x.kind);
+
+    assert!(
+        count == args.len(),
+        "wrong number of arguments for `{did:?}`: expected `{count}`, found {}\n\
+            note: the expected arguments are: `[{}]`\n\
+            the given arguments are: `{args:#?}`",
+        args.len(),
+        params.clone().map(GenericParamDefKind::descr).format(", "),
+    );
+
+    if let Some((idx, (param, arg))) =
+        params
+            .clone()
+            .zip(args.iter().map(|&x| x.unpack()))
+            .enumerate()
+            .find(|(_, (param, arg))| match (param, arg) {
+                (GenericParamDefKind::Lifetime, GenericArgKind::Lifetime(_))
+                | (GenericParamDefKind::Type { .. }, GenericArgKind::Type(_))
+                | (GenericParamDefKind::Const { .. }, GenericArgKind::Const(_)) => false,
+                (
+                    GenericParamDefKind::Lifetime
+                    | GenericParamDefKind::Type { .. }
+                    | GenericParamDefKind::Const { .. },
+                    _,
+                ) => true,
+            })
+    {
+        panic!(
+            "incorrect argument for `{did:?}` at index `{idx}`: expected a {}, found `{arg:?}`\n\
+                note: the expected arguments are `[{}]`\n\
+                the given arguments are `{args:#?}`",
+            param.descr(),
+            params.clone().map(GenericParamDefKind::descr).format(", "),
+        );
+    }
+}
+
+/// Returns whether `ty` is never-like; i.e., `!` (never) or an enum with zero variants.
+pub fn is_never_like(ty: Ty<'_>) -> bool {
+    ty.is_never() || (ty.is_enum() && ty.ty_adt_def().is_some_and(|def| def.variants().is_empty()))
+}
+
 /// Makes the projection type for the named associated type in the given impl or trait impl.
 ///
 /// This function is for associated types which are "known" to exist, and as such, will only return
 /// `None` when debug assertions are disabled in order to prevent ICE's. With debug assertions
 /// enabled this will check that the named associated type exists, the correct number of
-/// substitutions are given, and that the correct kinds of substitutions are given (lifetime,
+/// arguments are given, and that the correct kinds of arguments are given (lifetime,
 /// constant or type). This will not check if type normalization would succeed.
 pub fn make_projection<'tcx>(
     tcx: TyCtxt<'tcx>,
     container_id: DefId,
     assoc_ty: Symbol,
-    substs: impl IntoIterator<Item = impl Into<GenericArg<'tcx>>>,
+    args: impl IntoIterator<Item = impl Into<GenericArg<'tcx>>>,
 ) -> Option<AliasTy<'tcx>> {
     fn helper<'tcx>(
         tcx: TyCtxt<'tcx>,
         container_id: DefId,
         assoc_ty: Symbol,
-        substs: SubstsRef<'tcx>,
+        args: GenericArgsRef<'tcx>,
     ) -> Option<AliasTy<'tcx>> {
         let Some(assoc_item) = tcx.associated_items(container_id).find_by_name_and_kind(
             tcx,
@@ -1043,64 +1127,22 @@ pub fn make_projection<'tcx>(
             return None;
         };
         #[cfg(debug_assertions)]
-        {
-            let generics = tcx.generics_of(assoc_item.def_id);
-            let generic_count = generics.parent_count + generics.params.len();
-            let params = generics
-                .parent
-                .map_or([].as_slice(), |id| &*tcx.generics_of(id).params)
-                .iter()
-                .chain(&generics.params)
-                .map(|x| &x.kind);
-
-            debug_assert!(
-                generic_count == substs.len(),
-                "wrong number of substs for `{:?}`: found `{}` expected `{generic_count}`.\n\
-                    note: the expected parameters are: {:#?}\n\
-                    the given arguments are: `{substs:#?}`",
-                assoc_item.def_id,
-                substs.len(),
-                params.map(ty::GenericParamDefKind::descr).collect::<Vec<_>>(),
-            );
+        assert_generic_args_match(tcx, assoc_item.def_id, args);
 
-            if let Some((idx, (param, arg))) = params
-                .clone()
-                .zip(substs.iter().map(GenericArg::unpack))
-                .enumerate()
-                .find(|(_, (param, arg))| {
-                    !matches!(
-                        (param, arg),
-                        (ty::GenericParamDefKind::Lifetime, GenericArgKind::Lifetime(_))
-                            | (ty::GenericParamDefKind::Type { .. }, GenericArgKind::Type(_))
-                            | (ty::GenericParamDefKind::Const { .. }, GenericArgKind::Const(_))
-                    )
-                })
-            {
-                debug_assert!(
-                    false,
-                    "mismatched subst type at index {idx}: expected a {}, found `{arg:?}`\n\
-                        note: the expected parameters are {:#?}\n\
-                        the given arguments are {substs:#?}",
-                    param.descr(),
-                    params.map(ty::GenericParamDefKind::descr).collect::<Vec<_>>()
-                );
-            }
-        }
-
-        Some(tcx.mk_alias_ty(assoc_item.def_id, substs))
+        Some(tcx.mk_alias_ty(assoc_item.def_id, args))
     }
     helper(
         tcx,
         container_id,
         assoc_ty,
-        tcx.mk_substs_from_iter(substs.into_iter().map(Into::into)),
+        tcx.mk_args_from_iter(args.into_iter().map(Into::into)),
     )
 }
 
 /// Normalizes the named associated type in the given impl or trait impl.
 ///
 /// This function is for associated types which are "known" to be valid with the given
-/// substitutions, and as such, will only return `None` when debug assertions are disabled in order
+/// arguments, and as such, will only return `None` when debug assertions are disabled in order
 /// to prevent ICE's. With debug assertions enabled this will check that type normalization
 /// succeeds as well as everything checked by `make_projection`.
 pub fn make_normalized_projection<'tcx>(
@@ -1108,25 +1150,20 @@ pub fn make_normalized_projection<'tcx>(
     param_env: ParamEnv<'tcx>,
     container_id: DefId,
     assoc_ty: Symbol,
-    substs: impl IntoIterator<Item = impl Into<GenericArg<'tcx>>>,
+    args: impl IntoIterator<Item = impl Into<GenericArg<'tcx>>>,
 ) -> Option<Ty<'tcx>> {
     fn helper<'tcx>(tcx: TyCtxt<'tcx>, param_env: ParamEnv<'tcx>, ty: AliasTy<'tcx>) -> Option<Ty<'tcx>> {
         #[cfg(debug_assertions)]
-        if let Some((i, subst)) = ty
-            .substs
-            .iter()
-            .enumerate()
-            .find(|(_, subst)| subst.has_late_bound_regions())
-        {
+        if let Some((i, arg)) = ty.args.iter().enumerate().find(|(_, arg)| arg.has_late_bound_regions()) {
             debug_assert!(
                 false,
-                "substs contain late-bound region at index `{i}` which can't be normalized.\n\
+                "args contain late-bound region at index `{i}` which can't be normalized.\n\
                     use `TyCtxt::erase_late_bound_regions`\n\
-                    note: subst is `{subst:#?}`",
+                    note: arg is `{arg:#?}`",
             );
             return None;
         }
-        match tcx.try_normalize_erasing_regions(param_env, Ty::new_projection(tcx, ty.def_id, ty.substs)) {
+        match tcx.try_normalize_erasing_regions(param_env, Ty::new_projection(tcx, ty.def_id, ty.args)) {
             Ok(ty) => Some(ty),
             Err(e) => {
                 debug_assert!(false, "failed to normalize type `{ty}`: {e:#?}");
@@ -1134,7 +1171,7 @@ pub fn make_normalized_projection<'tcx>(
             },
         }
     }
-    helper(tcx, param_env, make_projection(tcx, container_id, assoc_ty, substs)?)
+    helper(tcx, param_env, make_projection(tcx, container_id, assoc_ty, args)?)
 }
 
 /// Check if given type has inner mutability such as [`std::cell::Cell`] or [`std::cell::RefCell`]
@@ -1149,7 +1186,7 @@ pub fn is_interior_mut_ty<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool {
                 && is_interior_mut_ty(cx, inner_ty)
         },
         ty::Tuple(fields) => fields.iter().any(|ty| is_interior_mut_ty(cx, ty)),
-        ty::Adt(def, substs) => {
+        ty::Adt(def, args) => {
             // Special case for collections in `std` who's impl of `Hash` or `Ord` delegates to
             // that of their type parameters.  Note: we don't include `HashSet` and `HashMap`
             // because they have no impl for `Hash` or `Ord`.
@@ -1170,7 +1207,7 @@ pub fn is_interior_mut_ty<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool {
             let is_box = Some(def_id) == cx.tcx.lang_items().owned_box();
             if is_std_collection || is_box {
                 // The type is mutable if any of its type parameters are
-                substs.types().any(|ty| is_interior_mut_ty(cx, ty))
+                args.types().any(|ty| is_interior_mut_ty(cx, ty))
             } else {
                 !ty.has_escaping_bound_vars()
                     && cx.tcx.layout_of(cx.param_env.and(ty)).is_ok()
@@ -1186,21 +1223,16 @@ pub fn make_normalized_projection_with_regions<'tcx>(
     param_env: ParamEnv<'tcx>,
     container_id: DefId,
     assoc_ty: Symbol,
-    substs: impl IntoIterator<Item = impl Into<GenericArg<'tcx>>>,
+    args: impl IntoIterator<Item = impl Into<GenericArg<'tcx>>>,
 ) -> Option<Ty<'tcx>> {
     fn helper<'tcx>(tcx: TyCtxt<'tcx>, param_env: ParamEnv<'tcx>, ty: AliasTy<'tcx>) -> Option<Ty<'tcx>> {
         #[cfg(debug_assertions)]
-        if let Some((i, subst)) = ty
-            .substs
-            .iter()
-            .enumerate()
-            .find(|(_, subst)| subst.has_late_bound_regions())
-        {
+        if let Some((i, arg)) = ty.args.iter().enumerate().find(|(_, arg)| arg.has_late_bound_regions()) {
             debug_assert!(
                 false,
-                "substs contain late-bound region at index `{i}` which can't be normalized.\n\
+                "args contain late-bound region at index `{i}` which can't be normalized.\n\
                     use `TyCtxt::erase_late_bound_regions`\n\
-                    note: subst is `{subst:#?}`",
+                    note: arg is `{arg:#?}`",
             );
             return None;
         }
@@ -1209,7 +1241,7 @@ pub fn make_normalized_projection_with_regions<'tcx>(
             .infer_ctxt()
             .build()
             .at(&cause, param_env)
-            .query_normalize(Ty::new_projection(tcx, ty.def_id, ty.substs))
+            .query_normalize(Ty::new_projection(tcx, ty.def_id, ty.args))
         {
             Ok(ty) => Some(ty.value),
             Err(e) => {
@@ -1218,7 +1250,7 @@ pub fn make_normalized_projection_with_regions<'tcx>(
             },
         }
     }
-    helper(tcx, param_env, make_projection(tcx, container_id, assoc_ty, substs)?)
+    helper(tcx, param_env, make_projection(tcx, container_id, assoc_ty, args)?)
 }
 
 pub fn normalize_with_regions<'tcx>(tcx: TyCtxt<'tcx>, param_env: ParamEnv<'tcx>, ty: Ty<'tcx>) -> Ty<'tcx> {
diff --git a/clippy_utils/src/ty/type_certainty/mod.rs b/clippy_utils/src/ty/type_certainty/mod.rs
index 67c4a293a86..45b5483e323 100644
--- a/clippy_utils/src/ty/type_certainty/mod.rs
+++ b/clippy_utils/src/ty/type_certainty/mod.rs
@@ -12,7 +12,7 @@
 //! be considered a bug.
 
 use crate::def_path_res;
-use rustc_hir::def::Res;
+use rustc_hir::def::{DefKind, Res};
 use rustc_hir::def_id::DefId;
 use rustc_hir::intravisit::{walk_qpath, walk_ty, Visitor};
 use rustc_hir::{self as hir, Expr, ExprKind, GenericArgs, HirId, Node, PathSegment, QPath, TyKind};
@@ -219,7 +219,12 @@ fn path_segment_certainty(
                 // See the comment preceding `qpath_certainty`. `def_id` could refer to a type or a value.
                 let certainty = lhs.join_clearing_def_ids(rhs);
                 if resolves_to_type {
-                    certainty.with_def_id(def_id)
+                    if cx.tcx.def_kind(def_id) == DefKind::TyAlias {
+                        adt_def_id(cx.tcx.type_of(def_id).instantiate_identity())
+                            .map_or(certainty, |def_id| certainty.with_def_id(def_id))
+                    } else {
+                        certainty.with_def_id(def_id)
+                    }
                 } else {
                     certainty
                 }
diff --git a/clippy_utils/src/usage.rs b/clippy_utils/src/usage.rs
index 20993398d1b..39ef76348d7 100644
--- a/clippy_utils/src/usage.rs
+++ b/clippy_utils/src/usage.rs
@@ -1,14 +1,15 @@
-use crate::visitors::{for_each_expr, for_each_expr_with_closures, Descend};
+use crate::visitors::{for_each_expr, for_each_expr_with_closures, Descend, Visitable};
+use crate::{self as utils, get_enclosing_loop_or_multi_call_closure};
 use core::ops::ControlFlow;
+use hir::def::Res;
 use rustc_hir::intravisit::{self, Visitor};
-use rustc_hir::{Expr, ExprKind, HirId, HirIdSet, Node};
+use rustc_hir::{self as hir, Expr, ExprKind, HirId, HirIdSet};
 use rustc_hir_typeck::expr_use_visitor::{Delegate, ExprUseVisitor, PlaceBase, PlaceWithHirId};
 use rustc_infer::infer::TyCtxtInferExt;
 use rustc_lint::LateContext;
 use rustc_middle::hir::nested_filter;
 use rustc_middle::mir::FakeReadCause;
 use rustc_middle::ty;
-use {crate as utils, rustc_hir as hir};
 
 /// Returns a set of mutated local variable IDs, or `None` if mutations could not be determined.
 pub fn mutated_variables<'tcx>(expr: &'tcx Expr<'_>, cx: &LateContext<'tcx>) -> Option<HirIdSet> {
@@ -127,7 +128,7 @@ impl<'a, 'tcx> intravisit::Visitor<'tcx> for BindingUsageFinder<'a, 'tcx> {
     }
 
     fn visit_path(&mut self, path: &hir::Path<'tcx>, _: hir::HirId) {
-        if let hir::def::Res::Local(id) = path.res {
+        if let Res::Local(id) = path.res {
             if self.binding_ids.contains(&id) {
                 self.usage_found = true;
             }
@@ -153,6 +154,17 @@ pub fn contains_return_break_continue_macro(expression: &Expr<'_>) -> bool {
     .is_some()
 }
 
+pub fn local_used_in<'tcx>(cx: &LateContext<'tcx>, local_id: HirId, v: impl Visitable<'tcx>) -> bool {
+    for_each_expr_with_closures(cx, v, |e| {
+        if utils::path_to_local_id(e, local_id) {
+            ControlFlow::Break(())
+        } else {
+            ControlFlow::Continue(())
+        }
+    })
+    .is_some()
+}
+
 pub fn local_used_after_expr(cx: &LateContext<'_>, local_id: HirId, after: &Expr<'_>) -> bool {
     let Some(block) = utils::get_enclosing_block(cx, local_id) else {
         return false;
@@ -165,32 +177,21 @@ pub fn local_used_after_expr(cx: &LateContext<'_>, local_id: HirId, after: &Expr
     // let closure = || local;
     // closure();
     // closure();
-    let in_loop_or_closure = cx
-        .tcx
-        .hir()
-        .parent_iter(after.hir_id)
-        .take_while(|&(id, _)| id != block.hir_id)
-        .any(|(_, node)| {
-            matches!(
-                node,
-                Node::Expr(Expr {
-                    kind: ExprKind::Loop(..) | ExprKind::Closure { .. },
-                    ..
-                })
-            )
-        });
-    if in_loop_or_closure {
-        return true;
-    }
+    let loop_start = get_enclosing_loop_or_multi_call_closure(cx, after).map(|e| e.hir_id);
 
     let mut past_expr = false;
     for_each_expr_with_closures(cx, block, |e| {
-        if e.hir_id == after.hir_id {
+        if past_expr {
+            if utils::path_to_local_id(e, local_id) {
+                ControlFlow::Break(())
+            } else {
+                ControlFlow::Continue(Descend::Yes)
+            }
+        } else if e.hir_id == after.hir_id {
             past_expr = true;
             ControlFlow::Continue(Descend::No)
-        } else if past_expr && utils::path_to_local_id(e, local_id) {
-            ControlFlow::Break(())
         } else {
+            past_expr = Some(e.hir_id) == loop_start;
             ControlFlow::Continue(Descend::Yes)
         }
     })
diff --git a/clippy_utils/src/visitors.rs b/clippy_utils/src/visitors.rs
index 8dafa723afa..09f447b27eb 100644
--- a/clippy_utils/src/visitors.rs
+++ b/clippy_utils/src/visitors.rs
@@ -52,6 +52,16 @@ pub trait Visitable<'tcx> {
     /// Calls the corresponding `visit_*` function on the visitor.
     fn visit<V: Visitor<'tcx>>(self, visitor: &mut V);
 }
+impl<'tcx, T> Visitable<'tcx> for &'tcx [T]
+where
+    &'tcx T: Visitable<'tcx>,
+{
+    fn visit<V: Visitor<'tcx>>(self, visitor: &mut V) {
+        for x in self {
+            x.visit(visitor);
+        }
+    }
+}
 macro_rules! visitable_ref {
     ($t:ident, $f:ident) => {
         impl<'tcx> Visitable<'tcx> for &'tcx $t<'tcx> {
diff --git a/rust-toolchain b/rust-toolchain
index b658101a10d..833608faff0 100644
--- a/rust-toolchain
+++ b/rust-toolchain
@@ -1,3 +1,3 @@
 [toolchain]
-channel = "nightly-2023-07-14"
+channel = "nightly-2023-07-28"
 components = ["cargo", "llvm-tools", "rust-src", "rust-std", "rustc", "rustc-dev", "rustfmt"]
diff --git a/tests/compile-test.rs b/tests/compile-test.rs
index d70c4ea34cb..385e25ce6b8 100644
--- a/tests/compile-test.rs
+++ b/tests/compile-test.rs
@@ -5,7 +5,7 @@
 #![warn(rust_2018_idioms, unused_lifetimes)]
 #![allow(unused_extern_crates)]
 
-use compiletest::{status_emitter, CommandBuilder};
+use compiletest::{status_emitter, CommandBuilder, OutputConflictHandling};
 use ui_test as compiletest;
 use ui_test::Mode as TestMode;
 
@@ -115,10 +115,12 @@ fn base_config(test_dir: &str) -> compiletest::Config {
         mode: TestMode::Yolo,
         stderr_filters: vec![],
         stdout_filters: vec![],
-        output_conflict_handling: if var_os("BLESS").is_some() || env::args().any(|arg| arg == "--bless") {
-            compiletest::OutputConflictHandling::Bless
+        output_conflict_handling: if var_os("RUSTC_BLESS").is_some_and(|v| v != "0")
+            || env::args().any(|arg| arg == "--bless")
+        {
+            OutputConflictHandling::Bless
         } else {
-            compiletest::OutputConflictHandling::Error("cargo test -- -- --bless".into())
+            OutputConflictHandling::Error("cargo uibless".into())
         },
         target: None,
         out_dir: PathBuf::from(std::env::var_os("CARGO_TARGET_DIR").unwrap_or("target".into())).join("ui_test"),
@@ -187,9 +189,6 @@ fn run_ui() {
                 .to_string()
         }),
     );
-    eprintln!("   Compiler: {}", config.program.display());
-
-    let name = config.root_dir.display().to_string();
 
     let test_filter = test_filter();
 
@@ -197,7 +196,7 @@ fn run_ui() {
         config,
         move |path| compiletest::default_file_filter(path) && test_filter(path),
         compiletest::default_per_file_config,
-        (status_emitter::Text, status_emitter::Gha::<true> { name }),
+        status_emitter::Text,
     )
     .unwrap();
     check_rustfix_coverage();
@@ -208,8 +207,19 @@ fn run_internal_tests() {
     if !RUN_INTERNAL_TESTS {
         return;
     }
-    let config = base_config("ui-internal");
-    compiletest::run_tests(config).unwrap();
+    let mut config = base_config("ui-internal");
+    if let OutputConflictHandling::Error(err) = &mut config.output_conflict_handling {
+        *err = "cargo uitest --features internal -- -- --bless".into();
+    }
+    let test_filter = test_filter();
+
+    compiletest::run_tests_generic(
+        config,
+        move |path| compiletest::default_file_filter(path) && test_filter(path),
+        compiletest::default_per_file_config,
+        status_emitter::Text,
+    )
+    .unwrap();
 }
 
 fn run_ui_toml() {
@@ -228,13 +238,11 @@ fn run_ui_toml() {
         "$$DIR",
     );
 
-    let name = config.root_dir.display().to_string();
-
     let test_filter = test_filter();
 
     ui_test::run_tests_generic(
         config,
-        |path| test_filter(path) && path.extension() == Some("rs".as_ref()),
+        |path| compiletest::default_file_filter(path) && test_filter(path),
         |config, path| {
             let mut config = config.clone();
             config
@@ -243,7 +251,7 @@ fn run_ui_toml() {
                 .push(("CLIPPY_CONF_DIR".into(), Some(path.parent().unwrap().into())));
             Some(config)
         },
-        (status_emitter::Text, status_emitter::Gha::<true> { name }),
+        status_emitter::Text,
     )
     .unwrap();
 }
@@ -284,8 +292,6 @@ fn run_ui_cargo() {
         "$$DIR",
     );
 
-    let name = config.root_dir.display().to_string();
-
     let test_filter = test_filter();
 
     ui_test::run_tests_generic(
@@ -296,7 +302,7 @@ fn run_ui_cargo() {
             config.out_dir = PathBuf::from("target/ui_test_cargo/").join(path.parent().unwrap());
             Some(config)
         },
-        (status_emitter::Text, status_emitter::Gha::<true> { name }),
+        status_emitter::Text,
     )
     .unwrap();
 }
diff --git a/tests/integration.rs b/tests/integration.rs
index a771d8b87c8..031982edbe9 100644
--- a/tests/integration.rs
+++ b/tests/integration.rs
@@ -65,6 +65,30 @@ fn integration_test() {
         .expect("unable to run clippy");
 
     let stderr = String::from_utf8_lossy(&output.stderr);
+
+    // debug:
+    eprintln!("{stderr}");
+
+    // this is an internal test to make sure we would correctly panic on a delay_span_bug
+    if repo_name == "matthiaskrgr/clippy_ci_panic_test" {
+        // we need to kind of switch around our logic here:
+        // if we find a panic, everything is fine, if we don't panic, SOMETHING is broken about our testing
+
+        // the repo basically just contains a delay_span_bug that forces rustc/clippy to panic:
+        /*
+           #![feature(rustc_attrs)]
+           #[rustc_error(delay_span_bug_from_inside_query)]
+           fn main() {}
+        */
+
+        if stderr.find("error: internal compiler error").is_some() {
+            eprintln!("we saw that we intentionally panicked, yay");
+            return;
+        }
+
+        panic!("panic caused by delay_span_bug was NOT detected! Something is broken!");
+    }
+
     if let Some(backtrace_start) = stderr.find("error: internal compiler error") {
         static BACKTRACE_END_MSG: &str = "end of query stack";
         let backtrace_end = stderr[backtrace_start..]
diff --git a/tests/ui-toml/absolute_paths/absolute_paths.allow_crates.stderr b/tests/ui-toml/absolute_paths/absolute_paths.allow_crates.stderr
new file mode 100644
index 00000000000..a8900da4e6e
--- /dev/null
+++ b/tests/ui-toml/absolute_paths/absolute_paths.allow_crates.stderr
@@ -0,0 +1,28 @@
+error: consider bringing this path into scope with the `use` keyword
+  --> $DIR/absolute_paths.rs:40:5
+   |
+LL |     std::f32::MAX;
+   |     ^^^^^^^^^^^^^
+   |
+   = note: `-D clippy::absolute-paths` implied by `-D warnings`
+
+error: consider bringing this path into scope with the `use` keyword
+  --> $DIR/absolute_paths.rs:41:5
+   |
+LL |     core::f32::MAX;
+   |     ^^^^^^^^^^^^^^
+
+error: consider bringing this path into scope with the `use` keyword
+  --> $DIR/absolute_paths.rs:42:5
+   |
+LL |     ::core::f32::MAX;
+   |     ^^^^^^^^^^^^^^^^
+
+error: consider bringing this path into scope with the `use` keyword
+  --> $DIR/absolute_paths.rs:58:5
+   |
+LL |     ::std::f32::MAX;
+   |     ^^^^^^^^^^^^^^^
+
+error: aborting due to 4 previous errors
+
diff --git a/tests/ui-toml/absolute_paths/absolute_paths.disallow_crates.stderr b/tests/ui-toml/absolute_paths/absolute_paths.disallow_crates.stderr
new file mode 100644
index 00000000000..41b70644be8
--- /dev/null
+++ b/tests/ui-toml/absolute_paths/absolute_paths.disallow_crates.stderr
@@ -0,0 +1,70 @@
+error: consider bringing this path into scope with the `use` keyword
+  --> $DIR/absolute_paths.rs:40:5
+   |
+LL |     std::f32::MAX;
+   |     ^^^^^^^^^^^^^
+   |
+   = note: `-D clippy::absolute-paths` implied by `-D warnings`
+
+error: consider bringing this path into scope with the `use` keyword
+  --> $DIR/absolute_paths.rs:41:5
+   |
+LL |     core::f32::MAX;
+   |     ^^^^^^^^^^^^^^
+
+error: consider bringing this path into scope with the `use` keyword
+  --> $DIR/absolute_paths.rs:42:5
+   |
+LL |     ::core::f32::MAX;
+   |     ^^^^^^^^^^^^^^^^
+
+error: consider bringing this path into scope with the `use` keyword
+  --> $DIR/absolute_paths.rs:43:5
+   |
+LL |     crate::a::b::c::C;
+   |     ^^^^^^^^^^^^^^^^^
+
+error: consider bringing this path into scope with the `use` keyword
+  --> $DIR/absolute_paths.rs:44:5
+   |
+LL |     crate::a::b::c::d::e::f::F;
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: consider bringing this path into scope with the `use` keyword
+  --> $DIR/absolute_paths.rs:45:5
+   |
+LL |     crate::a::A;
+   |     ^^^^^^^^^^^
+
+error: consider bringing this path into scope with the `use` keyword
+  --> $DIR/absolute_paths.rs:46:5
+   |
+LL |     crate::a::b::B;
+   |     ^^^^^^^^^^^^^^
+
+error: consider bringing this path into scope with the `use` keyword
+  --> $DIR/absolute_paths.rs:47:5
+   |
+LL |     crate::a::b::c::C::ZERO;
+   |     ^^^^^^^^^^^^^^^^^
+
+error: consider bringing this path into scope with the `use` keyword
+  --> $DIR/absolute_paths.rs:48:5
+   |
+LL |     helper::b::c::d::e::f();
+   |     ^^^^^^^^^^^^^^^^^^^^^
+
+error: consider bringing this path into scope with the `use` keyword
+  --> $DIR/absolute_paths.rs:49:5
+   |
+LL |     ::helper::b::c::d::e::f();
+   |     ^^^^^^^^^^^^^^^^^^^^^^^
+
+error: consider bringing this path into scope with the `use` keyword
+  --> $DIR/absolute_paths.rs:58:5
+   |
+LL |     ::std::f32::MAX;
+   |     ^^^^^^^^^^^^^^^
+
+error: aborting due to 11 previous errors
+
diff --git a/tests/ui-toml/absolute_paths/absolute_paths.rs b/tests/ui-toml/absolute_paths/absolute_paths.rs
new file mode 100644
index 00000000000..d4c250a8ff2
--- /dev/null
+++ b/tests/ui-toml/absolute_paths/absolute_paths.rs
@@ -0,0 +1,97 @@
+//@aux-build:../../ui/auxiliary/proc_macros.rs:proc-macro
+//@aux-build:helper.rs
+//@revisions: allow_crates disallow_crates
+//@[allow_crates] rustc-env:CLIPPY_CONF_DIR=tests/ui-toml/absolute_paths/allow_crates
+//@[disallow_crates] rustc-env:CLIPPY_CONF_DIR=tests/ui-toml/absolute_paths/disallow_crates
+#![allow(clippy::no_effect, unused)]
+#![warn(clippy::absolute_paths)]
+#![feature(decl_macro)]
+
+extern crate helper;
+#[macro_use]
+extern crate proc_macros;
+
+pub mod a {
+    pub mod b {
+        pub mod c {
+            pub struct C;
+
+            impl C {
+                pub const ZERO: u32 = 0;
+            }
+
+            pub mod d {
+                pub mod e {
+                    pub mod f {
+                        pub struct F;
+                    }
+                }
+            }
+        }
+
+        pub struct B;
+    }
+
+    pub struct A;
+}
+
+fn main() {
+    f32::max(1.0, 2.0);
+    std::f32::MAX;
+    core::f32::MAX;
+    ::core::f32::MAX;
+    crate::a::b::c::C;
+    crate::a::b::c::d::e::f::F;
+    crate::a::A;
+    crate::a::b::B;
+    crate::a::b::c::C::ZERO;
+    helper::b::c::d::e::f();
+    ::helper::b::c::d::e::f();
+    fn b() -> a::b::B {
+        todo!()
+    }
+    std::println!("a");
+    let x = 1;
+    std::ptr::addr_of!(x);
+    // Test we handle max segments with `PathRoot` properly; this has 4 segments but we should say it
+    // has 3
+    ::std::f32::MAX;
+    // Do not lint due to the above
+    ::helper::a();
+    // Do not lint
+    helper::a();
+    use crate::a::b::c::C;
+    use a::b;
+    use std::f32::MAX;
+    a::b::c::d::e::f::F;
+    b::c::C;
+    fn a() -> a::A {
+        todo!()
+    }
+    use a::b::c;
+
+    fn c() -> c::C {
+        todo!()
+    }
+    fn d() -> Result<(), ()> {
+        todo!()
+    }
+    external! {
+        crate::a::b::c::C::ZERO;
+    }
+    // For some reason, `path.span.from_expansion()` takes care of this for us
+    with_span! {
+        span
+        crate::a::b::c::C::ZERO;
+    }
+    macro_rules! local_crate {
+        () => {
+            crate::a::b::c::C::ZERO;
+        };
+    }
+    macro local_crate_2_0() {
+        crate::a::b::c::C::ZERO;
+    }
+    local_crate!();
+    local_crate_2_0!();
+}
diff --git a/tests/ui-toml/absolute_paths/allow_crates/clippy.toml b/tests/ui-toml/absolute_paths/allow_crates/clippy.toml
new file mode 100644
index 00000000000..59a621e9d1d
--- /dev/null
+++ b/tests/ui-toml/absolute_paths/allow_crates/clippy.toml
@@ -0,0 +1,2 @@
+absolute-paths-max-segments = 2
+absolute-paths-allowed-crates = ["crate", "helper"]
diff --git a/tests/ui-toml/absolute_paths/auxiliary/helper.rs b/tests/ui-toml/absolute_paths/auxiliary/helper.rs
new file mode 100644
index 00000000000..8e2678f5fe6
--- /dev/null
+++ b/tests/ui-toml/absolute_paths/auxiliary/helper.rs
@@ -0,0 +1,11 @@
+pub fn a() {}
+
+pub mod b {
+    pub mod c {
+        pub mod d {
+            pub mod e {
+                pub fn f() {}
+            }
+        }
+    }
+}
diff --git a/tests/ui-toml/absolute_paths/disallow_crates/clippy.toml b/tests/ui-toml/absolute_paths/disallow_crates/clippy.toml
new file mode 100644
index 00000000000..d44d648c641
--- /dev/null
+++ b/tests/ui-toml/absolute_paths/disallow_crates/clippy.toml
@@ -0,0 +1 @@
+absolute-paths-max-segments = 2
diff --git a/tests/ui-toml/expect_used/expect_used.stderr b/tests/ui-toml/expect_used/expect_used.stderr
index 9eef0e1bfaa..815d009350f 100644
--- a/tests/ui-toml/expect_used/expect_used.stderr
+++ b/tests/ui-toml/expect_used/expect_used.stderr
@@ -4,7 +4,7 @@ error: used `expect()` on an `Option` value
 LL |     let _ = opt.expect("");
    |             ^^^^^^^^^^^^^^
    |
-   = help: if this value is `None`, it will panic
+   = note: if this value is `None`, it will panic
    = note: `-D clippy::expect-used` implied by `-D warnings`
 
 error: used `expect()` on a `Result` value
@@ -13,7 +13,7 @@ error: used `expect()` on a `Result` value
 LL |     let _ = res.expect("");
    |             ^^^^^^^^^^^^^^
    |
-   = help: if this value is an `Err`, it will panic
+   = note: if this value is an `Err`, it will panic
 
 error: aborting due to 2 previous errors
 
diff --git a/tests/ui-toml/toml_unknown_key/conf_unknown_key.stderr b/tests/ui-toml/toml_unknown_key/conf_unknown_key.stderr
index 6ba26e97730..cdabe6460cd 100644
--- a/tests/ui-toml/toml_unknown_key/conf_unknown_key.stderr
+++ b/tests/ui-toml/toml_unknown_key/conf_unknown_key.stderr
@@ -1,4 +1,6 @@
 error: error reading Clippy's configuration file: unknown field `foobar`, expected one of
+           absolute-paths-allowed-crates
+           absolute-paths-max-segments
            accept-comment-above-attributes
            accept-comment-above-statement
            allow-dbg-in-tests
@@ -68,6 +70,8 @@ LL | foobar = 42
    | ^^^^^^
 
 error: error reading Clippy's configuration file: unknown field `barfoo`, expected one of
+           absolute-paths-allowed-crates
+           absolute-paths-max-segments
            accept-comment-above-attributes
            accept-comment-above-statement
            allow-dbg-in-tests
diff --git a/tests/ui-toml/unwrap_used/unwrap_used.stderr b/tests/ui-toml/unwrap_used/unwrap_used.stderr
index 4c9bdfa9dba..10219beaf97 100644
--- a/tests/ui-toml/unwrap_used/unwrap_used.stderr
+++ b/tests/ui-toml/unwrap_used/unwrap_used.stderr
@@ -12,7 +12,8 @@ error: used `unwrap()` on an `Option` value
 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
+   = note: if this value is `None`, it will panic
+   = help: consider using `expect()` to provide a better panic message
    = note: `-D clippy::unwrap-used` implied by `-D warnings`
 
 error: called `.get().unwrap()` on a slice. Using `[]` is more clear and more concise
@@ -27,7 +28,8 @@ error: used `unwrap()` on an `Option` value
 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
+   = note: if this value is `None`, it will panic
+   = help: 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:40:17
@@ -41,7 +43,8 @@ error: used `unwrap()` on an `Option` value
 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
+   = note: if this value is `None`, it will panic
+   = help: 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:41:17
@@ -55,7 +58,8 @@ error: used `unwrap()` on an `Option` value
 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
+   = note: if this value is `None`, it will panic
+   = help: 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:42:17
@@ -69,7 +73,8 @@ error: used `unwrap()` on an `Option` value
 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
+   = note: if this value is `None`, it will panic
+   = help: 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:43:17
@@ -83,7 +88,8 @@ error: used `unwrap()` on an `Option` value
 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
+   = note: if this value is `None`, it will panic
+   = help: 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:47:21
@@ -97,7 +103,8 @@ error: used `unwrap()` on an `Option` value
 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
+   = note: if this value is `None`, it will panic
+   = help: 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:52:9
@@ -111,7 +118,8 @@ error: used `unwrap()` on an `Option` value
 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
+   = note: if this value is `None`, it will panic
+   = help: 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:53:9
@@ -125,7 +133,8 @@ error: used `unwrap()` on an `Option` value
 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
+   = note: if this value is `None`, it will panic
+   = help: 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:54:9
@@ -139,7 +148,8 @@ error: used `unwrap()` on an `Option` value
 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
+   = note: if this value is `None`, it will panic
+   = help: 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:55:9
@@ -153,7 +163,8 @@ error: used `unwrap()` on an `Option` value
 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
+   = note: if this value is `None`, it will panic
+   = help: 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:67:17
@@ -167,7 +178,8 @@ error: used `unwrap()` on an `Option` value
 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
+   = note: if this value is `None`, it will panic
+   = help: 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:68:17
@@ -181,7 +193,8 @@ error: used `unwrap()` on an `Option` value
 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
+   = note: if this value is `None`, it will panic
+   = help: 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:75:13
diff --git a/tests/ui/arc_with_non_send_sync.rs b/tests/ui/arc_with_non_send_sync.rs
index b6fcca0a791..2940c273255 100644
--- a/tests/ui/arc_with_non_send_sync.rs
+++ b/tests/ui/arc_with_non_send_sync.rs
@@ -1,6 +1,12 @@
+//@aux-build:proc_macros.rs:proc-macro
 #![warn(clippy::arc_with_non_send_sync)]
 #![allow(unused_variables)]
+
+#[macro_use]
+extern crate proc_macros;
+
 use std::cell::RefCell;
+use std::ptr::{null, null_mut};
 use std::sync::{Arc, Mutex};
 
 fn foo<T>(x: T) {
@@ -11,14 +17,32 @@ fn issue11076<T>() {
     let a: Arc<Vec<T>> = Arc::new(Vec::new());
 }
 
+fn issue11232() {
+    external! {
+        let a: Arc<*const u8> = Arc::new(null());
+        let a: Arc<*mut u8> = Arc::new(null_mut());
+    }
+    with_span! {
+        span
+        let a: Arc<*const u8> = Arc::new(null());
+        let a: Arc<*mut u8> = Arc::new(null_mut());
+    }
+}
+
 fn main() {
     let _ = Arc::new(42);
 
-    // !Sync
     let _ = Arc::new(RefCell::new(42));
+    //~^ ERROR: usage of an `Arc` that is not `Send` or `Sync`
+    //~| NOTE: the trait `Sync` is not implemented for `RefCell<i32>`
+
     let mutex = Mutex::new(1);
-    // !Send
     let _ = Arc::new(mutex.lock().unwrap());
-    // !Send + !Sync
+    //~^ ERROR: usage of an `Arc` that is not `Send` or `Sync`
+    //~| NOTE: the trait `Send` is not implemented for `MutexGuard<'_, i32>`
+
     let _ = Arc::new(&42 as *const i32);
+    //~^ ERROR: usage of an `Arc` that is not `Send` or `Sync`
+    //~| NOTE: the trait `Send` is not implemented for `*const i32`
+    //~| NOTE: the trait `Sync` is not implemented for `*const i32`
 }
diff --git a/tests/ui/arc_with_non_send_sync.stderr b/tests/ui/arc_with_non_send_sync.stderr
index 7633b38dfb5..de3f2fb9e16 100644
--- a/tests/ui/arc_with_non_send_sync.stderr
+++ b/tests/ui/arc_with_non_send_sync.stderr
@@ -1,5 +1,5 @@
 error: usage of an `Arc` that is not `Send` or `Sync`
-  --> $DIR/arc_with_non_send_sync.rs:18:13
+  --> $DIR/arc_with_non_send_sync.rs:35:13
    |
 LL |     let _ = Arc::new(RefCell::new(42));
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -10,7 +10,7 @@ LL |     let _ = Arc::new(RefCell::new(42));
    = note: `-D clippy::arc-with-non-send-sync` implied by `-D warnings`
 
 error: usage of an `Arc` that is not `Send` or `Sync`
-  --> $DIR/arc_with_non_send_sync.rs:21:13
+  --> $DIR/arc_with_non_send_sync.rs:40:13
    |
 LL |     let _ = Arc::new(mutex.lock().unwrap());
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -20,7 +20,7 @@ LL |     let _ = Arc::new(mutex.lock().unwrap());
    = help: consider using an `Rc` instead or wrapping the inner type with a `Mutex`
 
 error: usage of an `Arc` that is not `Send` or `Sync`
-  --> $DIR/arc_with_non_send_sync.rs:23:13
+  --> $DIR/arc_with_non_send_sync.rs:44:13
    |
 LL |     let _ = Arc::new(&42 as *const i32);
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^
diff --git a/tests/ui/arithmetic_side_effects.rs b/tests/ui/arithmetic_side_effects.rs
index ed75acee8a2..2ac2fa22086 100644
--- a/tests/ui/arithmetic_side_effects.rs
+++ b/tests/ui/arithmetic_side_effects.rs
@@ -486,4 +486,11 @@ pub fn issue_11145() {
     x += 1;
 }
 
+pub fn issue_11262() {
+    let one = 1;
+    let zero = 0;
+    let _ = 2 / one;
+    let _ = 2 / zero;
+}
+
 fn main() {}
diff --git a/tests/ui/comparison_to_empty.fixed b/tests/ui/comparison_to_empty.fixed
index c92dd509ebb..af219eed0b8 100644
--- a/tests/ui/comparison_to_empty.fixed
+++ b/tests/ui/comparison_to_empty.fixed
@@ -1,7 +1,8 @@
 //@run-rustfix
 
 #![warn(clippy::comparison_to_empty)]
-#![allow(clippy::useless_vec)]
+#![allow(clippy::borrow_deref_ref, clippy::needless_if, clippy::useless_vec)]
+#![feature(let_chains)]
 
 fn main() {
     // Disallow comparisons to empty
@@ -12,6 +13,11 @@ fn main() {
     let v = vec![0];
     let _ = v.is_empty();
     let _ = !v.is_empty();
+    if (*v).is_empty() {}
+    let s = [0].as_slice();
+    if s.is_empty() {}
+    if s.is_empty() {}
+    if s.is_empty() && s.is_empty() {}
 
     // Allow comparisons to non-empty
     let s = String::new();
@@ -21,4 +27,8 @@ fn main() {
     let v = vec![0];
     let _ = v == [0];
     let _ = v != [0];
+    if let [0] = &*v {}
+    let s = [0].as_slice();
+    if let [0] = s {}
+    if let [0] = &*s && s == [0] {}
 }
diff --git a/tests/ui/comparison_to_empty.rs b/tests/ui/comparison_to_empty.rs
index b3489714380..21e65184d50 100644
--- a/tests/ui/comparison_to_empty.rs
+++ b/tests/ui/comparison_to_empty.rs
@@ -1,7 +1,8 @@
 //@run-rustfix
 
 #![warn(clippy::comparison_to_empty)]
-#![allow(clippy::useless_vec)]
+#![allow(clippy::borrow_deref_ref, clippy::needless_if, clippy::useless_vec)]
+#![feature(let_chains)]
 
 fn main() {
     // Disallow comparisons to empty
@@ -12,6 +13,11 @@ fn main() {
     let v = vec![0];
     let _ = v == [];
     let _ = v != [];
+    if let [] = &*v {}
+    let s = [0].as_slice();
+    if let [] = s {}
+    if let [] = &*s {}
+    if let [] = &*s && s == [] {}
 
     // Allow comparisons to non-empty
     let s = String::new();
@@ -21,4 +27,8 @@ fn main() {
     let v = vec![0];
     let _ = v == [0];
     let _ = v != [0];
+    if let [0] = &*v {}
+    let s = [0].as_slice();
+    if let [0] = s {}
+    if let [0] = &*s && s == [0] {}
 }
diff --git a/tests/ui/comparison_to_empty.stderr b/tests/ui/comparison_to_empty.stderr
index cc09b17eb89..f29782ed80d 100644
--- a/tests/ui/comparison_to_empty.stderr
+++ b/tests/ui/comparison_to_empty.stderr
@@ -1,5 +1,5 @@
 error: comparison to empty slice
-  --> $DIR/comparison_to_empty.rs:9:13
+  --> $DIR/comparison_to_empty.rs:10:13
    |
 LL |     let _ = s == "";
    |             ^^^^^^^ help: using `is_empty` is clearer and more explicit: `s.is_empty()`
@@ -7,22 +7,52 @@ LL |     let _ = s == "";
    = note: `-D clippy::comparison-to-empty` implied by `-D warnings`
 
 error: comparison to empty slice
-  --> $DIR/comparison_to_empty.rs:10:13
+  --> $DIR/comparison_to_empty.rs:11:13
    |
 LL |     let _ = s != "";
    |             ^^^^^^^ help: using `!is_empty` is clearer and more explicit: `!s.is_empty()`
 
 error: comparison to empty slice
-  --> $DIR/comparison_to_empty.rs:13:13
+  --> $DIR/comparison_to_empty.rs:14:13
    |
 LL |     let _ = v == [];
    |             ^^^^^^^ help: using `is_empty` is clearer and more explicit: `v.is_empty()`
 
 error: comparison to empty slice
-  --> $DIR/comparison_to_empty.rs:14:13
+  --> $DIR/comparison_to_empty.rs:15:13
    |
 LL |     let _ = v != [];
    |             ^^^^^^^ help: using `!is_empty` is clearer and more explicit: `!v.is_empty()`
 
-error: aborting due to 4 previous errors
+error: comparison to empty slice using `if let`
+  --> $DIR/comparison_to_empty.rs:16:8
+   |
+LL |     if let [] = &*v {}
+   |        ^^^^^^^^^^^^ help: using `is_empty` is clearer and more explicit: `(*v).is_empty()`
+
+error: comparison to empty slice using `if let`
+  --> $DIR/comparison_to_empty.rs:18:8
+   |
+LL |     if let [] = s {}
+   |        ^^^^^^^^^^ help: using `is_empty` is clearer and more explicit: `s.is_empty()`
+
+error: comparison to empty slice using `if let`
+  --> $DIR/comparison_to_empty.rs:19:8
+   |
+LL |     if let [] = &*s {}
+   |        ^^^^^^^^^^^^ help: using `is_empty` is clearer and more explicit: `s.is_empty()`
+
+error: comparison to empty slice using `if let`
+  --> $DIR/comparison_to_empty.rs:20:8
+   |
+LL |     if let [] = &*s && s == [] {}
+   |        ^^^^^^^^^^^^ help: using `is_empty` is clearer and more explicit: `s.is_empty()`
+
+error: comparison to empty slice
+  --> $DIR/comparison_to_empty.rs:20:24
+   |
+LL |     if let [] = &*s && s == [] {}
+   |                        ^^^^^^^ help: using `is_empty` is clearer and more explicit: `s.is_empty()`
+
+error: aborting due to 9 previous errors
 
diff --git a/tests/ui/const_comparisons.rs b/tests/ui/const_comparisons.rs
new file mode 100644
index 00000000000..8e265c9141c
--- /dev/null
+++ b/tests/ui/const_comparisons.rs
@@ -0,0 +1,93 @@
+#![allow(unused)]
+#![warn(clippy::impossible_comparisons)]
+#![warn(clippy::redundant_comparisons)]
+#![allow(clippy::no_effect)]
+#![allow(clippy::short_circuit_statement)]
+#![allow(clippy::manual_range_contains)]
+
+const STATUS_BAD_REQUEST: u16 = 400;
+const STATUS_SERVER_ERROR: u16 = 500;
+
+struct Status {
+    code: u16,
+}
+
+impl PartialEq<u16> for Status {
+    fn eq(&self, other: &u16) -> bool {
+        self.code == *other
+    }
+}
+
+impl PartialOrd<u16> for Status {
+    fn partial_cmp(&self, other: &u16) -> Option<std::cmp::Ordering> {
+        self.code.partial_cmp(other)
+    }
+}
+
+impl PartialEq<Status> for u16 {
+    fn eq(&self, other: &Status) -> bool {
+        *self == other.code
+    }
+}
+
+impl PartialOrd<Status> for u16 {
+    fn partial_cmp(&self, other: &Status) -> Option<std::cmp::Ordering> {
+        self.partial_cmp(&other.code)
+    }
+}
+
+fn main() {
+    let status_code = 500; // Value doesn't matter for the lint
+    let status = Status { code: status_code };
+
+    status_code >= 400 && status_code < 500; // Correct
+    status_code <= 400 && status_code > 500;
+    status_code > 500 && status_code < 400;
+    status_code < 500 && status_code > 500;
+
+    // More complex expressions
+    status_code < { 400 } && status_code > { 500 };
+    status_code < STATUS_BAD_REQUEST && status_code > STATUS_SERVER_ERROR;
+    status_code <= u16::MIN + 1 && status_code > STATUS_SERVER_ERROR;
+    status_code < STATUS_SERVER_ERROR && status_code > STATUS_SERVER_ERROR;
+
+    // Comparing two different types, via the `impl PartialOrd<u16> for Status`
+    status < { 400 } && status > { 500 };
+    status < STATUS_BAD_REQUEST && status > STATUS_SERVER_ERROR;
+    status <= u16::MIN + 1 && status > STATUS_SERVER_ERROR;
+    status < STATUS_SERVER_ERROR && status > STATUS_SERVER_ERROR;
+
+    // Yoda conditions
+    500 <= status_code && 600 > status_code; // Correct
+    500 <= status_code && status_code <= 600; // Correct
+    500 >= status_code && 600 < status_code; // Incorrect
+    500 >= status_code && status_code > 600; // Incorrect
+
+    // Yoda conditions, comparing two different types
+    500 <= status && 600 > status; // Correct
+    500 <= status && status <= 600; // Correct
+    500 >= status && 600 < status; // Incorrect
+    500 >= status && status > 600; // Incorrect
+
+    // Expressions where one of the sides has no effect
+    status_code < 200 && status_code <= 299;
+    status_code > 200 && status_code >= 299;
+
+    status_code >= 500 && status_code > 500; // Useless left
+    status_code > 500 && status_code >= 500; // Useless right
+    status_code <= 500 && status_code < 500; // Useless left
+    status_code < 500 && status_code <= 500; // Useless right
+
+    // Other types
+    let name = "Steve";
+    name < "Jennifer" && name > "Shannon";
+
+    let numbers = [1, 2];
+    numbers < [3, 4] && numbers > [5, 6];
+
+    let letter = 'a';
+    letter < 'b' && letter > 'c';
+
+    let area = 42.0;
+    area < std::f32::consts::E && area > std::f32::consts::PI;
+}
diff --git a/tests/ui/const_comparisons.stderr b/tests/ui/const_comparisons.stderr
new file mode 100644
index 00000000000..90e6db64762
--- /dev/null
+++ b/tests/ui/const_comparisons.stderr
@@ -0,0 +1,228 @@
+error: boolean expression will never evaluate to 'true'
+  --> $DIR/const_comparisons.rs:44:5
+   |
+LL |     status_code <= 400 && status_code > 500;
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: since `400` < `500`, the expression evaluates to false for any value of `status_code`
+   = note: `-D clippy::impossible-comparisons` implied by `-D warnings`
+
+error: boolean expression will never evaluate to 'true'
+  --> $DIR/const_comparisons.rs:45:5
+   |
+LL |     status_code > 500 && status_code < 400;
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: since `500` > `400`, the expression evaluates to false for any value of `status_code`
+
+error: boolean expression will never evaluate to 'true'
+  --> $DIR/const_comparisons.rs:46:5
+   |
+LL |     status_code < 500 && status_code > 500;
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: `status_code` cannot simultaneously be greater than and less than `500`
+
+error: boolean expression will never evaluate to 'true'
+  --> $DIR/const_comparisons.rs:49:5
+   |
+LL |     status_code < { 400 } && status_code > { 500 };
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: since `{ 400 }` < `{ 500 }`, the expression evaluates to false for any value of `status_code`
+
+error: boolean expression will never evaluate to 'true'
+  --> $DIR/const_comparisons.rs:50:5
+   |
+LL |     status_code < STATUS_BAD_REQUEST && status_code > STATUS_SERVER_ERROR;
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: since `STATUS_BAD_REQUEST` < `STATUS_SERVER_ERROR`, the expression evaluates to false for any value of `status_code`
+
+error: boolean expression will never evaluate to 'true'
+  --> $DIR/const_comparisons.rs:51:5
+   |
+LL |     status_code <= u16::MIN + 1 && status_code > STATUS_SERVER_ERROR;
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: since `u16::MIN + 1` < `STATUS_SERVER_ERROR`, the expression evaluates to false for any value of `status_code`
+
+error: boolean expression will never evaluate to 'true'
+  --> $DIR/const_comparisons.rs:52:5
+   |
+LL |     status_code < STATUS_SERVER_ERROR && status_code > STATUS_SERVER_ERROR;
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: `status_code` cannot simultaneously be greater than and less than `STATUS_SERVER_ERROR`
+
+error: boolean expression will never evaluate to 'true'
+  --> $DIR/const_comparisons.rs:55:5
+   |
+LL |     status < { 400 } && status > { 500 };
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: since `{ 400 }` < `{ 500 }`, the expression evaluates to false for any value of `status`
+
+error: boolean expression will never evaluate to 'true'
+  --> $DIR/const_comparisons.rs:56:5
+   |
+LL |     status < STATUS_BAD_REQUEST && status > STATUS_SERVER_ERROR;
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: since `STATUS_BAD_REQUEST` < `STATUS_SERVER_ERROR`, the expression evaluates to false for any value of `status`
+
+error: boolean expression will never evaluate to 'true'
+  --> $DIR/const_comparisons.rs:57:5
+   |
+LL |     status <= u16::MIN + 1 && status > STATUS_SERVER_ERROR;
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: since `u16::MIN + 1` < `STATUS_SERVER_ERROR`, the expression evaluates to false for any value of `status`
+
+error: boolean expression will never evaluate to 'true'
+  --> $DIR/const_comparisons.rs:58:5
+   |
+LL |     status < STATUS_SERVER_ERROR && status > STATUS_SERVER_ERROR;
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: `status` cannot simultaneously be greater than and less than `STATUS_SERVER_ERROR`
+
+error: boolean expression will never evaluate to 'true'
+  --> $DIR/const_comparisons.rs:63:5
+   |
+LL |     500 >= status_code && 600 < status_code; // Incorrect
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: since `500` < `600`, the expression evaluates to false for any value of `status_code`
+
+error: boolean expression will never evaluate to 'true'
+  --> $DIR/const_comparisons.rs:64:5
+   |
+LL |     500 >= status_code && status_code > 600; // Incorrect
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: since `500` < `600`, the expression evaluates to false for any value of `status_code`
+
+error: boolean expression will never evaluate to 'true'
+  --> $DIR/const_comparisons.rs:69:5
+   |
+LL |     500 >= status && 600 < status; // Incorrect
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: since `500` < `600`, the expression evaluates to false for any value of `status`
+
+error: boolean expression will never evaluate to 'true'
+  --> $DIR/const_comparisons.rs:70:5
+   |
+LL |     500 >= status && status > 600; // Incorrect
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: since `500` < `600`, the expression evaluates to false for any value of `status`
+
+error: right-hand side of `&&` operator has no effect
+  --> $DIR/const_comparisons.rs:73:5
+   |
+LL |     status_code < 200 && status_code <= 299;
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+note: `if `status_code < 200` evaluates to true, status_code <= 299` will always evaluate to true as well
+  --> $DIR/const_comparisons.rs:73:23
+   |
+LL |     status_code < 200 && status_code <= 299;
+   |                       ^^^^^^^^^^^^^^^^^^^^^
+   = note: `-D clippy::redundant-comparisons` implied by `-D warnings`
+
+error: left-hand side of `&&` operator has no effect
+  --> $DIR/const_comparisons.rs:74:5
+   |
+LL |     status_code > 200 && status_code >= 299;
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+note: `if `status_code >= 299` evaluates to true, status_code > 200` will always evaluate to true as well
+  --> $DIR/const_comparisons.rs:74:5
+   |
+LL |     status_code > 200 && status_code >= 299;
+   |     ^^^^^^^^^^^^^^^^^^^^^
+
+error: left-hand side of `&&` operator has no effect
+  --> $DIR/const_comparisons.rs:76:5
+   |
+LL |     status_code >= 500 && status_code > 500; // Useless left
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+note: `if `status_code > 500` evaluates to true, status_code >= 500` will always evaluate to true as well
+  --> $DIR/const_comparisons.rs:76:5
+   |
+LL |     status_code >= 500 && status_code > 500; // Useless left
+   |     ^^^^^^^^^^^^^^^^^^^^^^
+
+error: right-hand side of `&&` operator has no effect
+  --> $DIR/const_comparisons.rs:77:5
+   |
+LL |     status_code > 500 && status_code >= 500; // Useless right
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+note: `if `status_code > 500` evaluates to true, status_code >= 500` will always evaluate to true as well
+  --> $DIR/const_comparisons.rs:77:23
+   |
+LL |     status_code > 500 && status_code >= 500; // Useless right
+   |                       ^^^^^^^^^^^^^^^^^^^^^
+
+error: left-hand side of `&&` operator has no effect
+  --> $DIR/const_comparisons.rs:78:5
+   |
+LL |     status_code <= 500 && status_code < 500; // Useless left
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+note: `if `status_code < 500` evaluates to true, status_code <= 500` will always evaluate to true as well
+  --> $DIR/const_comparisons.rs:78:5
+   |
+LL |     status_code <= 500 && status_code < 500; // Useless left
+   |     ^^^^^^^^^^^^^^^^^^^^^^
+
+error: right-hand side of `&&` operator has no effect
+  --> $DIR/const_comparisons.rs:79:5
+   |
+LL |     status_code < 500 && status_code <= 500; // Useless right
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+note: `if `status_code < 500` evaluates to true, status_code <= 500` will always evaluate to true as well
+  --> $DIR/const_comparisons.rs:79:23
+   |
+LL |     status_code < 500 && status_code <= 500; // Useless right
+   |                       ^^^^^^^^^^^^^^^^^^^^^
+
+error: boolean expression will never evaluate to 'true'
+  --> $DIR/const_comparisons.rs:83:5
+   |
+LL |     name < "Jennifer" && name > "Shannon";
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: since `"Jennifer"` < `"Shannon"`, the expression evaluates to false for any value of `name`
+
+error: boolean expression will never evaluate to 'true'
+  --> $DIR/const_comparisons.rs:86:5
+   |
+LL |     numbers < [3, 4] && numbers > [5, 6];
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: since `[3, 4]` < `[5, 6]`, the expression evaluates to false for any value of `numbers`
+
+error: boolean expression will never evaluate to 'true'
+  --> $DIR/const_comparisons.rs:89:5
+   |
+LL |     letter < 'b' && letter > 'c';
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: since `'b'` < `'c'`, the expression evaluates to false for any value of `letter`
+
+error: boolean expression will never evaluate to 'true'
+  --> $DIR/const_comparisons.rs:92:5
+   |
+LL |     area < std::f32::consts::E && area > std::f32::consts::PI;
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: since `std::f32::consts::E` < `std::f32::consts::PI`, the expression evaluates to false for any value of `area`
+
+error: aborting due to 25 previous errors
+
diff --git a/tests/ui/crashes/ice-6256.rs b/tests/ui/crashes/ice-6256.rs
index 1d336b3cdc0..bb488c2dcb3 100644
--- a/tests/ui/crashes/ice-6256.rs
+++ b/tests/ui/crashes/ice-6256.rs
@@ -1,5 +1,5 @@
 // originally from rustc ./tests/ui/regions/issue-78262.rs
-// ICE: to get the signature of a closure, use substs.as_closure().sig() not fn_sig()
+// ICE: to get the signature of a closure, use args.as_closure().sig() not fn_sig()
 #![allow(clippy::upper_case_acronyms)]
 
 trait TT {}
diff --git a/tests/ui/error_impl_error.rs b/tests/ui/error_impl_error.rs
new file mode 100644
index 00000000000..40ce4181bf3
--- /dev/null
+++ b/tests/ui/error_impl_error.rs
@@ -0,0 +1,90 @@
+#![allow(unused)]
+#![warn(clippy::error_impl_error)]
+#![no_main]
+
+pub mod a {
+    #[derive(Debug)]
+    pub struct Error;
+
+    impl std::fmt::Display for Error {
+        fn fmt(&self, _: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+            todo!()
+        }
+    }
+
+    impl std::error::Error for Error {}
+}
+
+mod b {
+    #[derive(Debug)]
+    pub(super) enum Error {}
+
+    impl std::fmt::Display for Error {
+        fn fmt(&self, _: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+            todo!()
+        }
+    }
+
+    impl std::error::Error for Error {}
+}
+
+pub mod c {
+    pub union Error {
+        a: u32,
+        b: u32,
+    }
+
+    impl std::fmt::Debug for Error {
+        fn fmt(&self, _: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+            todo!()
+        }
+    }
+
+    impl std::fmt::Display for Error {
+        fn fmt(&self, _: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+            todo!()
+        }
+    }
+
+    impl std::error::Error for Error {}
+}
+
+pub mod d {
+    pub type Error = std::fmt::Error;
+}
+
+mod e {
+    #[derive(Debug)]
+    pub(super) struct MyError;
+
+    impl std::fmt::Display for MyError {
+        fn fmt(&self, _: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+            todo!()
+        }
+    }
+
+    impl std::error::Error for MyError {}
+}
+
+pub mod f {
+    pub type MyError = std::fmt::Error;
+}
+
+// Do not lint module-private types
+
+mod g {
+    #[derive(Debug)]
+    enum Error {}
+
+    impl std::fmt::Display for Error {
+        fn fmt(&self, _: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+            todo!()
+        }
+    }
+
+    impl std::error::Error for Error {}
+}
+
+mod h {
+    type Error = std::fmt::Error;
+}
diff --git a/tests/ui/error_impl_error.stderr b/tests/ui/error_impl_error.stderr
new file mode 100644
index 00000000000..f3e04b64167
--- /dev/null
+++ b/tests/ui/error_impl_error.stderr
@@ -0,0 +1,45 @@
+error: exported type named `Error` that implements `Error`
+  --> $DIR/error_impl_error.rs:7:16
+   |
+LL |     pub struct Error;
+   |                ^^^^^
+   |
+note: `Error` was implemented here
+  --> $DIR/error_impl_error.rs:15:5
+   |
+LL |     impl std::error::Error for Error {}
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   = note: `-D clippy::error-impl-error` implied by `-D warnings`
+
+error: exported type named `Error` that implements `Error`
+  --> $DIR/error_impl_error.rs:20:21
+   |
+LL |     pub(super) enum Error {}
+   |                     ^^^^^
+   |
+note: `Error` was implemented here
+  --> $DIR/error_impl_error.rs:28:5
+   |
+LL |     impl std::error::Error for Error {}
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: exported type named `Error` that implements `Error`
+  --> $DIR/error_impl_error.rs:32:15
+   |
+LL |     pub union Error {
+   |               ^^^^^
+   |
+note: `Error` was implemented here
+  --> $DIR/error_impl_error.rs:49:5
+   |
+LL |     impl std::error::Error for Error {}
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: exported type alias named `Error` that implements `Error`
+  --> $DIR/error_impl_error.rs:53:14
+   |
+LL |     pub type Error = std::fmt::Error;
+   |              ^^^^^
+
+error: aborting due to 4 previous errors
+
diff --git a/tests/ui/eta.fixed b/tests/ui/eta.fixed
index bf44bcb564e..ddabe7616d0 100644
--- a/tests/ui/eta.fixed
+++ b/tests/ui/eta.fixed
@@ -331,7 +331,7 @@ impl dyn TestTrait + '_ {
 }
 
 // https://github.com/rust-lang/rust-clippy/issues/7746
-fn angle_brackets_and_substs() {
+fn angle_brackets_and_args() {
     let array_opt: Option<&[u8; 3]> = Some(&[4, 8, 7]);
     array_opt.map(<[u8; 3]>::as_slice);
 
@@ -345,3 +345,58 @@ fn angle_brackets_and_substs() {
     let dyn_opt: Option<&dyn TestTrait> = Some(&test_struct);
     dyn_opt.map(<dyn TestTrait>::method_on_dyn);
 }
+
+fn _late_bound_to_early_bound_regions() {
+    struct Foo<'a>(&'a u32);
+    impl<'a> Foo<'a> {
+        fn f(x: &'a u32) -> Self {
+            Foo(x)
+        }
+    }
+    fn f(f: impl for<'a> Fn(&'a u32) -> Foo<'a>) -> Foo<'static> {
+        f(&0)
+    }
+
+    let _ = f(|x| Foo::f(x));
+
+    struct Bar;
+    impl<'a> From<&'a u32> for Bar {
+        fn from(x: &'a u32) -> Bar {
+            Bar
+        }
+    }
+    fn f2(f: impl for<'a> Fn(&'a u32) -> Bar) -> Bar {
+        f(&0)
+    }
+
+    let _ = f2(|x| <Bar>::from(x));
+
+    struct Baz<'a>(&'a u32);
+    fn f3(f: impl Fn(&u32) -> Baz<'_>) -> Baz<'static> {
+        f(&0)
+    }
+
+    let _ = f3(|x| Baz(x));
+}
+
+fn _mixed_late_bound_and_early_bound_regions() {
+    fn f<T>(t: T, f: impl Fn(T, &u32) -> u32) -> u32 {
+        f(t, &0)
+    }
+    fn f2<'a, T: 'a>(_: &'a T, y: &u32) -> u32 {
+        *y
+    }
+    let _ = f(&0, f2);
+}
+
+fn _closure_with_types() {
+    fn f<T>(x: T) -> T {
+        x
+    }
+    fn f2<T: Default>(f: impl Fn(T) -> T) -> T {
+        f(T::default())
+    }
+
+    let _ = f2(|x: u32| f(x));
+    let _ = f2(|x| -> u32 { f(x) });
+}
diff --git a/tests/ui/eta.rs b/tests/ui/eta.rs
index b2af4bf0953..92ecff6eb1a 100644
--- a/tests/ui/eta.rs
+++ b/tests/ui/eta.rs
@@ -331,7 +331,7 @@ impl dyn TestTrait + '_ {
 }
 
 // https://github.com/rust-lang/rust-clippy/issues/7746
-fn angle_brackets_and_substs() {
+fn angle_brackets_and_args() {
     let array_opt: Option<&[u8; 3]> = Some(&[4, 8, 7]);
     array_opt.map(|a| a.as_slice());
 
@@ -345,3 +345,58 @@ fn angle_brackets_and_substs() {
     let dyn_opt: Option<&dyn TestTrait> = Some(&test_struct);
     dyn_opt.map(|d| d.method_on_dyn());
 }
+
+fn _late_bound_to_early_bound_regions() {
+    struct Foo<'a>(&'a u32);
+    impl<'a> Foo<'a> {
+        fn f(x: &'a u32) -> Self {
+            Foo(x)
+        }
+    }
+    fn f(f: impl for<'a> Fn(&'a u32) -> Foo<'a>) -> Foo<'static> {
+        f(&0)
+    }
+
+    let _ = f(|x| Foo::f(x));
+
+    struct Bar;
+    impl<'a> From<&'a u32> for Bar {
+        fn from(x: &'a u32) -> Bar {
+            Bar
+        }
+    }
+    fn f2(f: impl for<'a> Fn(&'a u32) -> Bar) -> Bar {
+        f(&0)
+    }
+
+    let _ = f2(|x| <Bar>::from(x));
+
+    struct Baz<'a>(&'a u32);
+    fn f3(f: impl Fn(&u32) -> Baz<'_>) -> Baz<'static> {
+        f(&0)
+    }
+
+    let _ = f3(|x| Baz(x));
+}
+
+fn _mixed_late_bound_and_early_bound_regions() {
+    fn f<T>(t: T, f: impl Fn(T, &u32) -> u32) -> u32 {
+        f(t, &0)
+    }
+    fn f2<'a, T: 'a>(_: &'a T, y: &u32) -> u32 {
+        *y
+    }
+    let _ = f(&0, |x, y| f2(x, y));
+}
+
+fn _closure_with_types() {
+    fn f<T>(x: T) -> T {
+        x
+    }
+    fn f2<T: Default>(f: impl Fn(T) -> T) -> T {
+        f(T::default())
+    }
+
+    let _ = f2(|x: u32| f(x));
+    let _ = f2(|x| -> u32 { f(x) });
+}
diff --git a/tests/ui/eta.stderr b/tests/ui/eta.stderr
index 0ac0b901df4..ff40a2074e5 100644
--- a/tests/ui/eta.stderr
+++ b/tests/ui/eta.stderr
@@ -158,5 +158,11 @@ error: redundant closure
 LL |     dyn_opt.map(|d| d.method_on_dyn());
    |                 ^^^^^^^^^^^^^^^^^^^^^ help: replace the closure with the method itself: `<dyn TestTrait>::method_on_dyn`
 
-error: aborting due to 26 previous errors
+error: redundant closure
+  --> $DIR/eta.rs:389:19
+   |
+LL |     let _ = f(&0, |x, y| f2(x, y));
+   |                   ^^^^^^^^^^^^^^^ help: replace the closure with the function itself: `f2`
+
+error: aborting due to 27 previous errors
 
diff --git a/tests/ui/expect.stderr b/tests/ui/expect.stderr
index be340340d47..f787fa973a3 100644
--- a/tests/ui/expect.stderr
+++ b/tests/ui/expect.stderr
@@ -4,7 +4,7 @@ error: used `expect()` on an `Option` value
 LL |     let _ = opt.expect("");
    |             ^^^^^^^^^^^^^^
    |
-   = help: if this value is `None`, it will panic
+   = note: if this value is `None`, it will panic
    = note: `-D clippy::expect-used` implied by `-D warnings`
 
 error: used `expect()` on a `Result` value
@@ -13,7 +13,7 @@ error: used `expect()` on a `Result` value
 LL |     let _ = res.expect("");
    |             ^^^^^^^^^^^^^^
    |
-   = help: if this value is an `Err`, it will panic
+   = note: if this value is an `Err`, it will panic
 
 error: used `expect_err()` on a `Result` value
   --> $DIR/expect.rs:12:13
@@ -21,7 +21,7 @@ error: used `expect_err()` on a `Result` value
 LL |     let _ = res.expect_err("");
    |             ^^^^^^^^^^^^^^^^^^
    |
-   = help: if this value is an `Ok`, it will panic
+   = note: if this value is an `Ok`, it will panic
 
 error: aborting due to 3 previous errors
 
diff --git a/tests/ui/filter_map_bool_then.fixed b/tests/ui/filter_map_bool_then.fixed
new file mode 100644
index 00000000000..3e72fee4b07
--- /dev/null
+++ b/tests/ui/filter_map_bool_then.fixed
@@ -0,0 +1,44 @@
+//@run-rustfix
+//@aux-build:proc_macros.rs:proc-macro
+#![allow(
+    clippy::clone_on_copy,
+    clippy::map_identity,
+    clippy::unnecessary_lazy_evaluations,
+    unused
+)]
+#![warn(clippy::filter_map_bool_then)]
+
+#[macro_use]
+extern crate proc_macros;
+
+#[derive(Clone, PartialEq)]
+struct NonCopy;
+
+fn main() {
+    let v = vec![1, 2, 3, 4, 5, 6];
+    v.clone().iter().filter(|&i| (i % 2 == 0)).map(|i| i + 1);
+    v.clone().into_iter().filter(|&i| (i % 2 == 0)).map(|i| i + 1);
+    v.clone()
+        .into_iter()
+        .filter(|&i| (i % 2 == 0)).map(|i| i + 1);
+    v.clone()
+        .into_iter()
+        .filter(|&i| i != 1000)
+        .filter(|&i| (i % 2 == 0)).map(|i| i + 1);
+    v.iter()
+        .copied()
+        .filter(|&i| i != 1000)
+        .filter(|&i| (i.clone() % 2 == 0)).map(|i| i + 1);
+    // Do not lint
+    let v = vec![NonCopy, NonCopy];
+    v.clone().iter().filter_map(|i| (i == &NonCopy).then(|| i));
+    external! {
+        let v = vec![1, 2, 3, 4, 5, 6];
+        v.clone().into_iter().filter_map(|i| (i % 2 == 0).then(|| i + 1));
+    }
+    with_span! {
+        span
+        let v = vec![1, 2, 3, 4, 5, 6];
+        v.clone().into_iter().filter_map(|i| (i % 2 == 0).then(|| i + 1));
+    }
+}
diff --git a/tests/ui/filter_map_bool_then.rs b/tests/ui/filter_map_bool_then.rs
new file mode 100644
index 00000000000..38a04e57de4
--- /dev/null
+++ b/tests/ui/filter_map_bool_then.rs
@@ -0,0 +1,44 @@
+//@run-rustfix
+//@aux-build:proc_macros.rs:proc-macro
+#![allow(
+    clippy::clone_on_copy,
+    clippy::map_identity,
+    clippy::unnecessary_lazy_evaluations,
+    unused
+)]
+#![warn(clippy::filter_map_bool_then)]
+
+#[macro_use]
+extern crate proc_macros;
+
+#[derive(Clone, PartialEq)]
+struct NonCopy;
+
+fn main() {
+    let v = vec![1, 2, 3, 4, 5, 6];
+    v.clone().iter().filter_map(|i| (i % 2 == 0).then(|| i + 1));
+    v.clone().into_iter().filter_map(|i| (i % 2 == 0).then(|| i + 1));
+    v.clone()
+        .into_iter()
+        .filter_map(|i| -> Option<_> { (i % 2 == 0).then(|| i + 1) });
+    v.clone()
+        .into_iter()
+        .filter(|&i| i != 1000)
+        .filter_map(|i| (i % 2 == 0).then(|| i + 1));
+    v.iter()
+        .copied()
+        .filter(|&i| i != 1000)
+        .filter_map(|i| (i.clone() % 2 == 0).then(|| i + 1));
+    // Do not lint
+    let v = vec![NonCopy, NonCopy];
+    v.clone().iter().filter_map(|i| (i == &NonCopy).then(|| i));
+    external! {
+        let v = vec![1, 2, 3, 4, 5, 6];
+        v.clone().into_iter().filter_map(|i| (i % 2 == 0).then(|| i + 1));
+    }
+    with_span! {
+        span
+        let v = vec![1, 2, 3, 4, 5, 6];
+        v.clone().into_iter().filter_map(|i| (i % 2 == 0).then(|| i + 1));
+    }
+}
diff --git a/tests/ui/filter_map_bool_then.stderr b/tests/ui/filter_map_bool_then.stderr
new file mode 100644
index 00000000000..b411cd83dfd
--- /dev/null
+++ b/tests/ui/filter_map_bool_then.stderr
@@ -0,0 +1,34 @@
+error: usage of `bool::then` in `filter_map`
+  --> $DIR/filter_map_bool_then.rs:19:22
+   |
+LL |     v.clone().iter().filter_map(|i| (i % 2 == 0).then(|| i + 1));
+   |                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `filter` then `map` instead: `filter(|&i| (i % 2 == 0)).map(|i| i + 1)`
+   |
+   = note: `-D clippy::filter-map-bool-then` implied by `-D warnings`
+
+error: usage of `bool::then` in `filter_map`
+  --> $DIR/filter_map_bool_then.rs:20:27
+   |
+LL |     v.clone().into_iter().filter_map(|i| (i % 2 == 0).then(|| i + 1));
+   |                           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `filter` then `map` instead: `filter(|&i| (i % 2 == 0)).map(|i| i + 1)`
+
+error: usage of `bool::then` in `filter_map`
+  --> $DIR/filter_map_bool_then.rs:23:10
+   |
+LL |         .filter_map(|i| -> Option<_> { (i % 2 == 0).then(|| i + 1) });
+   |          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `filter` then `map` instead: `filter(|&i| (i % 2 == 0)).map(|i| i + 1)`
+
+error: usage of `bool::then` in `filter_map`
+  --> $DIR/filter_map_bool_then.rs:27:10
+   |
+LL |         .filter_map(|i| (i % 2 == 0).then(|| i + 1));
+   |          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `filter` then `map` instead: `filter(|&i| (i % 2 == 0)).map(|i| i + 1)`
+
+error: usage of `bool::then` in `filter_map`
+  --> $DIR/filter_map_bool_then.rs:31:10
+   |
+LL |         .filter_map(|i| (i.clone() % 2 == 0).then(|| i + 1));
+   |          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `filter` then `map` instead: `filter(|&i| (i.clone() % 2 == 0)).map(|i| i + 1)`
+
+error: aborting due to 5 previous errors
+
diff --git a/tests/ui/get_unwrap.stderr b/tests/ui/get_unwrap.stderr
index c567ed319b5..19dc9071fe7 100644
--- a/tests/ui/get_unwrap.stderr
+++ b/tests/ui/get_unwrap.stderr
@@ -16,7 +16,8 @@ error: used `unwrap()` on an `Option` value
 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
+   = note: if this value is `None`, it will panic
+   = help: consider using `expect()` to provide a better panic message
    = note: `-D clippy::unwrap-used` implied by `-D warnings`
 
 error: called `.get().unwrap()` on a slice. Using `[]` is more clear and more concise
@@ -31,7 +32,8 @@ error: used `unwrap()` on an `Option` value
 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
+   = note: if this value is `None`, it will panic
+   = help: 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:40:17
@@ -45,7 +47,8 @@ error: used `unwrap()` on an `Option` value
 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
+   = note: if this value is `None`, it will panic
+   = help: 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:41:17
@@ -59,7 +62,8 @@ error: used `unwrap()` on an `Option` value
 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
+   = note: if this value is `None`, it will panic
+   = help: 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:42:17
@@ -73,7 +77,8 @@ error: used `unwrap()` on an `Option` value
 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
+   = note: if this value is `None`, it will panic
+   = help: 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:43:17
@@ -87,7 +92,8 @@ error: used `unwrap()` on an `Option` value
 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
+   = note: if this value is `None`, it will panic
+   = help: 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:47:21
@@ -101,7 +107,8 @@ error: used `unwrap()` on an `Option` value
 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
+   = note: if this value is `None`, it will panic
+   = help: 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:52:9
@@ -115,7 +122,8 @@ error: used `unwrap()` on an `Option` value
 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
+   = note: if this value is `None`, it will panic
+   = help: 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:53:9
@@ -129,7 +137,8 @@ error: used `unwrap()` on an `Option` value
 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
+   = note: if this value is `None`, it will panic
+   = help: 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:54:9
@@ -143,7 +152,8 @@ error: used `unwrap()` on an `Option` value
 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
+   = note: if this value is `None`, it will panic
+   = help: 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:55:9
@@ -157,7 +167,8 @@ error: used `unwrap()` on an `Option` value
 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
+   = note: if this value is `None`, it will panic
+   = help: 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:67:17
@@ -171,7 +182,8 @@ error: used `unwrap()` on an `Option` value
 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
+   = note: if this value is `None`, it will panic
+   = help: 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:68:17
@@ -185,7 +197,8 @@ error: used `unwrap()` on an `Option` value
 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
+   = note: if this value is `None`, it will panic
+   = help: 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:78:24
diff --git a/tests/ui/if_same_then_else.rs b/tests/ui/if_same_then_else.rs
index dad4543f84c..e84b20e9fef 100644
--- a/tests/ui/if_same_then_else.rs
+++ b/tests/ui/if_same_then_else.rs
@@ -214,4 +214,45 @@ mod issue_8836 {
     }
 }
 
+mod issue_11213 {
+    fn reproducer(x: bool) -> bool {
+        if x {
+            0_u8.is_power_of_two()
+        } else {
+            0_u16.is_power_of_two()
+        }
+    }
+
+    // a more obvious reproducer that shows
+    // why the code above is problematic:
+    fn v2(x: bool) -> bool {
+        trait Helper {
+            fn is_u8(&self) -> bool;
+        }
+        impl Helper for u8 {
+            fn is_u8(&self) -> bool {
+                true
+            }
+        }
+        impl Helper for u16 {
+            fn is_u8(&self) -> bool {
+                false
+            }
+        }
+
+        // this is certainly not the same code in both branches
+        // it returns a different bool depending on the branch.
+        if x { 0_u8.is_u8() } else { 0_u16.is_u8() }
+    }
+
+    fn do_lint(x: bool) -> bool {
+        // but do lint if the type of the literal is the same
+        if x {
+            0_u8.is_power_of_two()
+        } else {
+            0_u8.is_power_of_two()
+        }
+    }
+}
+
 fn main() {}
diff --git a/tests/ui/if_same_then_else.stderr b/tests/ui/if_same_then_else.stderr
index a34fc565590..774cc08685a 100644
--- a/tests/ui/if_same_then_else.stderr
+++ b/tests/ui/if_same_then_else.stderr
@@ -108,5 +108,23 @@ LL | |         bar + 1;
 LL | |     }
    | |_____^
 
-error: aborting due to 5 previous errors
+error: this `if` has identical blocks
+  --> $DIR/if_same_then_else.rs:250:14
+   |
+LL |           if x {
+   |  ______________^
+LL | |             0_u8.is_power_of_two()
+LL | |         } else {
+   | |_________^
+   |
+note: same as this
+  --> $DIR/if_same_then_else.rs:252:16
+   |
+LL |           } else {
+   |  ________________^
+LL | |             0_u8.is_power_of_two()
+LL | |         }
+   | |_________^
+
+error: aborting due to 6 previous errors
 
diff --git a/tests/ui/ifs_same_cond.rs b/tests/ui/ifs_same_cond.rs
index 5c338e3c5c8..ad77346b75f 100644
--- a/tests/ui/ifs_same_cond.rs
+++ b/tests/ui/ifs_same_cond.rs
@@ -46,6 +46,10 @@ fn ifs_same_cond() {
         // ok, functions
     } else if v.len() == 42 {
     }
+
+    if let Some(env1) = option_env!("ENV1") {
+    } else if let Some(env2) = option_env!("ENV2") {
+    }
 }
 
 fn issue10272() {
diff --git a/tests/ui/ifs_same_cond.stderr b/tests/ui/ifs_same_cond.stderr
index 8d70934476c..3f52c10b762 100644
--- a/tests/ui/ifs_same_cond.stderr
+++ b/tests/ui/ifs_same_cond.stderr
@@ -36,13 +36,13 @@ LL |     if 2 * a == 1 {
    |        ^^^^^^^^^^
 
 error: this `if` has the same condition as a previous `if`
-  --> $DIR/ifs_same_cond.rs:54:15
+  --> $DIR/ifs_same_cond.rs:58:15
    |
 LL |     } else if a.contains("ah") {
    |               ^^^^^^^^^^^^^^^^
    |
 note: same as this
-  --> $DIR/ifs_same_cond.rs:53:8
+  --> $DIR/ifs_same_cond.rs:57:8
    |
 LL |     if a.contains("ah") {
    |        ^^^^^^^^^^^^^^^^
diff --git a/tests/ui/ignored_unit_patterns.fixed b/tests/ui/ignored_unit_patterns.fixed
new file mode 100644
index 00000000000..492219fe447
--- /dev/null
+++ b/tests/ui/ignored_unit_patterns.fixed
@@ -0,0 +1,17 @@
+//@run-rustfix
+
+#![warn(clippy::ignored_unit_patterns)]
+#![allow(clippy::redundant_pattern_matching, clippy::single_match)]
+
+fn foo() -> Result<(), ()> {
+    unimplemented!()
+}
+
+fn main() {
+    match foo() {
+        Ok(()) => {},
+        Err(()) => {},
+    }
+    if let Ok(()) = foo() {}
+    let _ = foo().map_err(|()| todo!());
+}
diff --git a/tests/ui/ignored_unit_patterns.rs b/tests/ui/ignored_unit_patterns.rs
new file mode 100644
index 00000000000..90af36f8e5e
--- /dev/null
+++ b/tests/ui/ignored_unit_patterns.rs
@@ -0,0 +1,17 @@
+//@run-rustfix
+
+#![warn(clippy::ignored_unit_patterns)]
+#![allow(clippy::redundant_pattern_matching, clippy::single_match)]
+
+fn foo() -> Result<(), ()> {
+    unimplemented!()
+}
+
+fn main() {
+    match foo() {
+        Ok(_) => {},
+        Err(_) => {},
+    }
+    if let Ok(_) = foo() {}
+    let _ = foo().map_err(|_| todo!());
+}
diff --git a/tests/ui/ignored_unit_patterns.stderr b/tests/ui/ignored_unit_patterns.stderr
new file mode 100644
index 00000000000..8feea3cc2a8
--- /dev/null
+++ b/tests/ui/ignored_unit_patterns.stderr
@@ -0,0 +1,28 @@
+error: matching over `()` is more explicit
+  --> $DIR/ignored_unit_patterns.rs:12:12
+   |
+LL |         Ok(_) => {},
+   |            ^ help: use `()` instead of `_`: `()`
+   |
+   = note: `-D clippy::ignored-unit-patterns` implied by `-D warnings`
+
+error: matching over `()` is more explicit
+  --> $DIR/ignored_unit_patterns.rs:13:13
+   |
+LL |         Err(_) => {},
+   |             ^ help: use `()` instead of `_`: `()`
+
+error: matching over `()` is more explicit
+  --> $DIR/ignored_unit_patterns.rs:15:15
+   |
+LL |     if let Ok(_) = foo() {}
+   |               ^ help: use `()` instead of `_`: `()`
+
+error: matching over `()` is more explicit
+  --> $DIR/ignored_unit_patterns.rs:16:28
+   |
+LL |     let _ = foo().map_err(|_| todo!());
+   |                            ^ help: use `()` instead of `_`: `()`
+
+error: aborting due to 4 previous errors
+
diff --git a/tests/ui/incorrect_partial_ord_impl_on_ord_type.fixed b/tests/ui/incorrect_partial_ord_impl_on_ord_type.fixed
index dd4fdd98822..2f51bf27480 100644
--- a/tests/ui/incorrect_partial_ord_impl_on_ord_type.fixed
+++ b/tests/ui/incorrect_partial_ord_impl_on_ord_type.fixed
@@ -1,5 +1,4 @@
 //@run-rustfix
-#![allow(unused)]
 #![no_main]
 
 use std::cmp::Ordering;
@@ -112,3 +111,35 @@ impl PartialOrd<u32> for F {
         todo!();
     }
 }
+
+// #11178, do not lint
+
+#[derive(Eq, PartialEq)]
+struct G(u32);
+
+impl Ord for G {
+    fn cmp(&self, other: &Self) -> Ordering {
+        todo!();
+    }
+}
+
+impl PartialOrd for G {
+    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
+        Some(Self::cmp(self, other))
+    }
+}
+
+#[derive(Eq, PartialEq)]
+struct H(u32);
+
+impl Ord for H {
+    fn cmp(&self, other: &Self) -> Ordering {
+        todo!();
+    }
+}
+
+impl PartialOrd for H {
+    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
+        Some(Ord::cmp(self, other))
+    }
+}
diff --git a/tests/ui/incorrect_partial_ord_impl_on_ord_type.rs b/tests/ui/incorrect_partial_ord_impl_on_ord_type.rs
index 522e82299c0..47127bdaec2 100644
--- a/tests/ui/incorrect_partial_ord_impl_on_ord_type.rs
+++ b/tests/ui/incorrect_partial_ord_impl_on_ord_type.rs
@@ -1,5 +1,4 @@
 //@run-rustfix
-#![allow(unused)]
 #![no_main]
 
 use std::cmp::Ordering;
@@ -116,3 +115,35 @@ impl PartialOrd<u32> for F {
         todo!();
     }
 }
+
+// #11178, do not lint
+
+#[derive(Eq, PartialEq)]
+struct G(u32);
+
+impl Ord for G {
+    fn cmp(&self, other: &Self) -> Ordering {
+        todo!();
+    }
+}
+
+impl PartialOrd for G {
+    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
+        Some(Self::cmp(self, other))
+    }
+}
+
+#[derive(Eq, PartialEq)]
+struct H(u32);
+
+impl Ord for H {
+    fn cmp(&self, other: &Self) -> Ordering {
+        todo!();
+    }
+}
+
+impl PartialOrd for H {
+    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
+        Some(Ord::cmp(self, other))
+    }
+}
diff --git a/tests/ui/incorrect_partial_ord_impl_on_ord_type.stderr b/tests/ui/incorrect_partial_ord_impl_on_ord_type.stderr
index 0e477798c40..66048fc9000 100644
--- a/tests/ui/incorrect_partial_ord_impl_on_ord_type.stderr
+++ b/tests/ui/incorrect_partial_ord_impl_on_ord_type.stderr
@@ -1,5 +1,5 @@
 error: incorrect implementation of `partial_cmp` on an `Ord` type
-  --> $DIR/incorrect_partial_ord_impl_on_ord_type.rs:18:1
+  --> $DIR/incorrect_partial_ord_impl_on_ord_type.rs:17:1
    |
 LL | /  impl PartialOrd for A {
 LL | |      fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
@@ -13,7 +13,7 @@ LL | |  }
    = note: `#[deny(clippy::incorrect_partial_ord_impl_on_ord_type)]` on by default
 
 error: incorrect implementation of `partial_cmp` on an `Ord` type
-  --> $DIR/incorrect_partial_ord_impl_on_ord_type.rs:52:1
+  --> $DIR/incorrect_partial_ord_impl_on_ord_type.rs:51:1
    |
 LL | / impl PartialOrd for C {
 LL | |     fn partial_cmp(&self, _: &Self) -> Option<Ordering> {
diff --git a/tests/ui/incorrect_partial_ord_impl_on_ord_type_fully_qual.rs b/tests/ui/incorrect_partial_ord_impl_on_ord_type_fully_qual.rs
new file mode 100644
index 00000000000..3a3b84f93c4
--- /dev/null
+++ b/tests/ui/incorrect_partial_ord_impl_on_ord_type_fully_qual.rs
@@ -0,0 +1,51 @@
+// This test's filename is... a bit verbose. But it ensures we suggest the correct code when `Ord`
+// is not in scope.
+#![no_main]
+#![no_implicit_prelude]
+
+extern crate std;
+
+use std::cmp::{self, Eq, Ordering, PartialEq, PartialOrd};
+use std::option::Option::{self, Some};
+use std::todo;
+
+// lint
+
+#[derive(Eq, PartialEq)]
+struct A(u32);
+
+impl cmp::Ord for A {
+    fn cmp(&self, other: &Self) -> Ordering {
+        todo!();
+    }
+}
+
+impl PartialOrd for A {
+    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
+        // NOTE: This suggestion is wrong, as `Ord` is not in scope. But this should be fine as it isn't
+        // automatically applied
+        todo!();
+    }
+}
+
+#[derive(Eq, PartialEq)]
+struct B(u32);
+
+impl B {
+    fn cmp(&self, other: &Self) -> Ordering {
+        todo!();
+    }
+}
+
+impl cmp::Ord for B {
+    fn cmp(&self, other: &Self) -> Ordering {
+        todo!();
+    }
+}
+
+impl PartialOrd for B {
+    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
+        // This calls `B.cmp`, not `Ord::cmp`!
+        Some(self.cmp(other))
+    }
+}
diff --git a/tests/ui/incorrect_partial_ord_impl_on_ord_type_fully_qual.stderr b/tests/ui/incorrect_partial_ord_impl_on_ord_type_fully_qual.stderr
new file mode 100644
index 00000000000..f4374c28128
--- /dev/null
+++ b/tests/ui/incorrect_partial_ord_impl_on_ord_type_fully_qual.stderr
@@ -0,0 +1,31 @@
+error: incorrect implementation of `partial_cmp` on an `Ord` type
+  --> $DIR/incorrect_partial_ord_impl_on_ord_type_fully_qual.rs:23:1
+   |
+LL | /  impl PartialOrd for A {
+LL | |      fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
+   | | _____________________________________________________________-
+LL | ||         // NOTE: This suggestion is wrong, as `Ord` is not in scope. But this should be fine as it isn't
+LL | ||         // automatically applied
+LL | ||         todo!();
+LL | ||     }
+   | ||_____- help: change this to: `{ Some(self.cmp(other)) }`
+LL | |  }
+   | |__^
+   |
+   = note: `#[deny(clippy::incorrect_partial_ord_impl_on_ord_type)]` on by default
+
+error: incorrect implementation of `partial_cmp` on an `Ord` type
+  --> $DIR/incorrect_partial_ord_impl_on_ord_type_fully_qual.rs:46:1
+   |
+LL | /  impl PartialOrd for B {
+LL | |      fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
+   | | _____________________________________________________________-
+LL | ||         // This calls `B.cmp`, not `Ord::cmp`!
+LL | ||         Some(self.cmp(other))
+LL | ||     }
+   | ||_____- help: change this to: `{ Some(std::cmp::Ord::cmp(self, other)) }`
+LL | |  }
+   | |__^
+
+error: aborting due to 2 previous errors
+
diff --git a/tests/ui/infinite_loop.stderr b/tests/ui/infinite_loop.stderr
index 701b3cd1904..04559f9ada4 100644
--- a/tests/ui/infinite_loop.stderr
+++ b/tests/ui/infinite_loop.stderr
@@ -1,11 +1,3 @@
-error: this argument is a mutable reference, but not used mutably
-  --> $DIR/infinite_loop.rs:7:17
-   |
-LL | fn fn_mutref(i: &mut i32) {
-   |                 ^^^^^^^^ help: consider changing to: `&i32`
-   |
-   = note: `-D clippy::needless-pass-by-ref-mut` implied by `-D warnings`
-
 error: variables in the condition are not mutated in the loop body
   --> $DIR/infinite_loop.rs:20:11
    |
@@ -99,5 +91,13 @@ LL |     while y < 10 {
    = note: this loop contains `return`s or `break`s
    = help: rewrite it as `if cond { loop { } }`
 
+error: this argument is a mutable reference, but not used mutably
+  --> $DIR/infinite_loop.rs:7:17
+   |
+LL | fn fn_mutref(i: &mut i32) {
+   |                 ^^^^^^^^ help: consider changing to: `&i32`
+   |
+   = note: `-D clippy::needless-pass-by-ref-mut` implied by `-D warnings`
+
 error: aborting due to 12 previous errors
 
diff --git a/tests/ui/inherent_to_string.rs b/tests/ui/inherent_to_string.rs
index aeb0a0c1e2e..adb0389a043 100644
--- a/tests/ui/inherent_to_string.rs
+++ b/tests/ui/inherent_to_string.rs
@@ -1,5 +1,4 @@
-#![warn(clippy::inherent_to_string)]
-#![deny(clippy::inherent_to_string_shadow_display)]
+#![allow(improper_ctypes_definitions)]
 
 use std::fmt;
 
@@ -14,6 +13,9 @@ struct D;
 struct E;
 struct F;
 struct G;
+struct H;
+struct I;
+struct J;
 
 impl A {
     // Should be detected; emit warning
@@ -80,6 +82,26 @@ impl G {
     }
 }
 
+// Issue #11201
+
+impl H {
+    unsafe fn to_string(&self) -> String {
+        "G.to_string()".to_string()
+    }
+}
+
+impl I {
+    extern "C" fn to_string(&self) -> String {
+        "G.to_string()".to_string()
+    }
+}
+
+impl J {
+    unsafe extern "C" fn to_string(&self) -> String {
+        "G.to_string()".to_string()
+    }
+}
+
 fn main() {
     let a = A;
     a.to_string();
diff --git a/tests/ui/inherent_to_string.stderr b/tests/ui/inherent_to_string.stderr
index 443fecae1aa..579b3c8c56f 100644
--- a/tests/ui/inherent_to_string.stderr
+++ b/tests/ui/inherent_to_string.stderr
@@ -1,5 +1,5 @@
 error: implementation of inherent method `to_string(&self) -> String` for type `A`
-  --> $DIR/inherent_to_string.rs:20:5
+  --> $DIR/inherent_to_string.rs:22:5
    |
 LL | /     fn to_string(&self) -> String {
 LL | |         "A.to_string()".to_string()
@@ -10,7 +10,7 @@ LL | |     }
    = note: `-D clippy::inherent-to-string` implied by `-D warnings`
 
 error: type `C` implements inherent method `to_string(&self) -> String` which shadows the implementation of `Display`
-  --> $DIR/inherent_to_string.rs:44:5
+  --> $DIR/inherent_to_string.rs:46:5
    |
 LL | /     fn to_string(&self) -> String {
 LL | |         "C.to_string()".to_string()
@@ -18,11 +18,7 @@ LL | |     }
    | |_____^
    |
    = help: remove the inherent method from type `C`
-note: the lint level is defined here
-  --> $DIR/inherent_to_string.rs:2:9
-   |
-LL | #![deny(clippy::inherent_to_string_shadow_display)]
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   = note: `#[deny(clippy::inherent_to_string_shadow_display)]` on by default
 
 error: aborting due to 2 previous errors
 
diff --git a/tests/ui/let_underscore_future.stderr b/tests/ui/let_underscore_future.stderr
index 9e69fb04133..ff1e2b8c901 100644
--- a/tests/ui/let_underscore_future.stderr
+++ b/tests/ui/let_underscore_future.stderr
@@ -1,11 +1,3 @@
-error: this argument is a mutable reference, but not used mutably
-  --> $DIR/let_underscore_future.rs:11:35
-   |
-LL | fn do_something_to_future(future: &mut impl Future<Output = ()>) {}
-   |                                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider changing to: `&impl Future<Output = ()>`
-   |
-   = note: `-D clippy::needless-pass-by-ref-mut` implied by `-D warnings`
-
 error: non-binding `let` on a future
   --> $DIR/let_underscore_future.rs:14:5
    |
@@ -31,5 +23,13 @@ LL |     let _ = future;
    |
    = help: consider awaiting the future or dropping explicitly with `std::mem::drop`
 
+error: this argument is a mutable reference, but not used mutably
+  --> $DIR/let_underscore_future.rs:11:35
+   |
+LL | fn do_something_to_future(future: &mut impl Future<Output = ()>) {}
+   |                                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider changing to: `&impl Future<Output = ()>`
+   |
+   = note: `-D clippy::needless-pass-by-ref-mut` implied by `-D warnings`
+
 error: aborting due to 4 previous errors
 
diff --git a/tests/ui/match_expr_like_matches_macro.fixed b/tests/ui/match_expr_like_matches_macro.fixed
index 60f59066173..f19149cf9de 100644
--- a/tests/ui/match_expr_like_matches_macro.fixed
+++ b/tests/ui/match_expr_like_matches_macro.fixed
@@ -5,7 +5,8 @@
     unreachable_patterns,
     dead_code,
     clippy::equatable_if_let,
-    clippy::needless_borrowed_reference
+    clippy::needless_borrowed_reference,
+    clippy::redundant_guards
 )]
 
 fn main() {
diff --git a/tests/ui/match_expr_like_matches_macro.rs b/tests/ui/match_expr_like_matches_macro.rs
index afdf1069f5e..8f4e58981ea 100644
--- a/tests/ui/match_expr_like_matches_macro.rs
+++ b/tests/ui/match_expr_like_matches_macro.rs
@@ -5,7 +5,8 @@
     unreachable_patterns,
     dead_code,
     clippy::equatable_if_let,
-    clippy::needless_borrowed_reference
+    clippy::needless_borrowed_reference,
+    clippy::redundant_guards
 )]
 
 fn main() {
diff --git a/tests/ui/match_expr_like_matches_macro.stderr b/tests/ui/match_expr_like_matches_macro.stderr
index c8c1e5da05f..b57b26284ff 100644
--- a/tests/ui/match_expr_like_matches_macro.stderr
+++ b/tests/ui/match_expr_like_matches_macro.stderr
@@ -1,5 +1,5 @@
 error: match expression looks like `matches!` macro
-  --> $DIR/match_expr_like_matches_macro.rs:15:14
+  --> $DIR/match_expr_like_matches_macro.rs:16:14
    |
 LL |       let _y = match x {
    |  ______________^
@@ -11,7 +11,7 @@ LL | |     };
    = note: `-D clippy::match-like-matches-macro` implied by `-D warnings`
 
 error: redundant pattern matching, consider using `is_some()`
-  --> $DIR/match_expr_like_matches_macro.rs:21:14
+  --> $DIR/match_expr_like_matches_macro.rs:22:14
    |
 LL |       let _w = match x {
    |  ______________^
@@ -23,7 +23,7 @@ LL | |     };
    = note: `-D clippy::redundant-pattern-matching` implied by `-D warnings`
 
 error: redundant pattern matching, consider using `is_none()`
-  --> $DIR/match_expr_like_matches_macro.rs:27:14
+  --> $DIR/match_expr_like_matches_macro.rs:28:14
    |
 LL |       let _z = match x {
    |  ______________^
@@ -33,7 +33,7 @@ LL | |     };
    | |_____^ help: try: `x.is_none()`
 
 error: match expression looks like `matches!` macro
-  --> $DIR/match_expr_like_matches_macro.rs:33:15
+  --> $DIR/match_expr_like_matches_macro.rs:34:15
    |
 LL |       let _zz = match x {
    |  _______________^
@@ -43,13 +43,13 @@ LL | |     };
    | |_____^ help: try: `!matches!(x, Some(r) if r == 0)`
 
 error: if let .. else expression looks like `matches!` macro
-  --> $DIR/match_expr_like_matches_macro.rs:39:16
+  --> $DIR/match_expr_like_matches_macro.rs:40:16
    |
 LL |     let _zzz = if let Some(5) = x { true } else { false };
    |                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `matches!(x, Some(5))`
 
 error: match expression looks like `matches!` macro
-  --> $DIR/match_expr_like_matches_macro.rs:63:20
+  --> $DIR/match_expr_like_matches_macro.rs:64:20
    |
 LL |           let _ans = match x {
    |  ____________________^
@@ -60,7 +60,7 @@ LL | |         };
    | |_________^ help: try: `matches!(x, E::A(_) | E::B(_))`
 
 error: match expression looks like `matches!` macro
-  --> $DIR/match_expr_like_matches_macro.rs:73:20
+  --> $DIR/match_expr_like_matches_macro.rs:74:20
    |
 LL |           let _ans = match x {
    |  ____________________^
@@ -73,7 +73,7 @@ LL | |         };
    | |_________^ help: try: `matches!(x, E::A(_) | E::B(_))`
 
 error: match expression looks like `matches!` macro
-  --> $DIR/match_expr_like_matches_macro.rs:83:20
+  --> $DIR/match_expr_like_matches_macro.rs:84:20
    |
 LL |           let _ans = match x {
    |  ____________________^
@@ -84,7 +84,7 @@ LL | |         };
    | |_________^ help: try: `!matches!(x, E::B(_) | E::C)`
 
 error: match expression looks like `matches!` macro
-  --> $DIR/match_expr_like_matches_macro.rs:143:18
+  --> $DIR/match_expr_like_matches_macro.rs:144:18
    |
 LL |           let _z = match &z {
    |  __________________^
@@ -94,7 +94,7 @@ LL | |         };
    | |_________^ help: try: `matches!(z, Some(3))`
 
 error: match expression looks like `matches!` macro
-  --> $DIR/match_expr_like_matches_macro.rs:152:18
+  --> $DIR/match_expr_like_matches_macro.rs:153:18
    |
 LL |           let _z = match &z {
    |  __________________^
@@ -104,7 +104,7 @@ LL | |         };
    | |_________^ help: try: `matches!(&z, Some(3))`
 
 error: match expression looks like `matches!` macro
-  --> $DIR/match_expr_like_matches_macro.rs:169:21
+  --> $DIR/match_expr_like_matches_macro.rs:170:21
    |
 LL |               let _ = match &z {
    |  _____________________^
@@ -114,7 +114,7 @@ LL | |             };
    | |_____________^ help: try: `matches!(&z, AnEnum::X)`
 
 error: match expression looks like `matches!` macro
-  --> $DIR/match_expr_like_matches_macro.rs:183:20
+  --> $DIR/match_expr_like_matches_macro.rs:184:20
    |
 LL |           let _res = match &val {
    |  ____________________^
@@ -124,7 +124,7 @@ LL | |         };
    | |_________^ help: try: `matches!(&val, &Some(ref _a))`
 
 error: match expression looks like `matches!` macro
-  --> $DIR/match_expr_like_matches_macro.rs:195:20
+  --> $DIR/match_expr_like_matches_macro.rs:196:20
    |
 LL |           let _res = match &val {
    |  ____________________^
@@ -134,7 +134,7 @@ LL | |         };
    | |_________^ help: try: `matches!(&val, &Some(ref _a))`
 
 error: match expression looks like `matches!` macro
-  --> $DIR/match_expr_like_matches_macro.rs:253:14
+  --> $DIR/match_expr_like_matches_macro.rs:254:14
    |
 LL |       let _y = match Some(5) {
    |  ______________^
diff --git a/tests/ui/min_ident_chars.rs b/tests/ui/min_ident_chars.rs
index 0fab224a29d..03784442e2c 100644
--- a/tests/ui/min_ident_chars.rs
+++ b/tests/ui/min_ident_chars.rs
@@ -81,3 +81,7 @@ fn b() {}
 fn wrong_pythagoras(a: f32, b: f32) -> f32 {
     a * a + a * b
 }
+
+mod issue_11163 {
+    struct Array<T, const N: usize>([T; N]);
+}
diff --git a/tests/ui/mut_key.stderr b/tests/ui/mut_key.stderr
index 02a0da86a4b..3f756f5f0e5 100644
--- a/tests/ui/mut_key.stderr
+++ b/tests/ui/mut_key.stderr
@@ -12,14 +12,6 @@ error: mutable key type
 LL | fn should_not_take_this_arg(m: &mut HashMap<Key, usize>, _n: usize) -> HashSet<Key> {
    |                                                                        ^^^^^^^^^^^^
 
-error: this argument is a mutable reference, but not used mutably
-  --> $DIR/mut_key.rs:31:32
-   |
-LL | fn should_not_take_this_arg(m: &mut HashMap<Key, usize>, _n: usize) -> HashSet<Key> {
-   |                                ^^^^^^^^^^^^^^^^^^^^^^^^ help: consider changing to: `&HashMap<Key, usize>`
-   |
-   = note: `-D clippy::needless-pass-by-ref-mut` implied by `-D warnings`
-
 error: mutable key type
   --> $DIR/mut_key.rs:32:5
    |
@@ -110,5 +102,13 @@ error: mutable key type
 LL |     let _map = HashMap::<Arc<Cell<usize>>, usize>::new();
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
+error: this argument is a mutable reference, but not used mutably
+  --> $DIR/mut_key.rs:31:32
+   |
+LL | fn should_not_take_this_arg(m: &mut HashMap<Key, usize>, _n: usize) -> HashSet<Key> {
+   |                                ^^^^^^^^^^^^^^^^^^^^^^^^ help: consider changing to: `&HashMap<Key, usize>`
+   |
+   = note: `-D clippy::needless-pass-by-ref-mut` implied by `-D warnings`
+
 error: aborting due to 18 previous errors
 
diff --git a/tests/ui/mut_reference.rs b/tests/ui/mut_reference.rs
index 73906121c40..00661c51a78 100644
--- a/tests/ui/mut_reference.rs
+++ b/tests/ui/mut_reference.rs
@@ -1,8 +1,21 @@
-#![allow(unused_variables)]
+#![allow(unused_variables, dead_code)]
 
 fn takes_an_immutable_reference(a: &i32) {}
 fn takes_a_mutable_reference(a: &mut i32) {}
 
+mod issue11268 {
+    macro_rules! x {
+        ($f:expr) => {
+            $f(&mut 1);
+        };
+    }
+
+    fn f() {
+        x!(super::takes_an_immutable_reference);
+        x!(super::takes_a_mutable_reference);
+    }
+}
+
 struct MyStruct;
 
 impl MyStruct {
diff --git a/tests/ui/mut_reference.stderr b/tests/ui/mut_reference.stderr
index 23c812475c2..d8a71d26461 100644
--- a/tests/ui/mut_reference.stderr
+++ b/tests/ui/mut_reference.stderr
@@ -1,19 +1,5 @@
-error: this argument is a mutable reference, but not used mutably
-  --> $DIR/mut_reference.rs:4:33
-   |
-LL | fn takes_a_mutable_reference(a: &mut i32) {}
-   |                                 ^^^^^^^^ help: consider changing to: `&i32`
-   |
-   = note: `-D clippy::needless-pass-by-ref-mut` implied by `-D warnings`
-
-error: this argument is a mutable reference, but not used mutably
-  --> $DIR/mut_reference.rs:11:44
-   |
-LL |     fn takes_a_mutable_reference(&self, a: &mut i32) {}
-   |                                            ^^^^^^^^ help: consider changing to: `&i32`
-
 error: the function `takes_an_immutable_reference` doesn't need a mutable reference
-  --> $DIR/mut_reference.rs:17:34
+  --> $DIR/mut_reference.rs:30:34
    |
 LL |     takes_an_immutable_reference(&mut 42);
    |                                  ^^^^^^^
@@ -21,16 +7,24 @@ LL |     takes_an_immutable_reference(&mut 42);
    = note: `-D clippy::unnecessary-mut-passed` implied by `-D warnings`
 
 error: the function `as_ptr` doesn't need a mutable reference
-  --> $DIR/mut_reference.rs:19:12
+  --> $DIR/mut_reference.rs:32:12
    |
 LL |     as_ptr(&mut 42);
    |            ^^^^^^^
 
 error: the method `takes_an_immutable_reference` doesn't need a mutable reference
-  --> $DIR/mut_reference.rs:23:44
+  --> $DIR/mut_reference.rs:36:44
    |
 LL |     my_struct.takes_an_immutable_reference(&mut 42);
    |                                            ^^^^^^^
 
-error: aborting due to 5 previous errors
+error: this argument is a mutable reference, but not used mutably
+  --> $DIR/mut_reference.rs:24:44
+   |
+LL |     fn takes_a_mutable_reference(&self, a: &mut i32) {}
+   |                                            ^^^^^^^^ help: consider changing to: `&i32`
+   |
+   = note: `-D clippy::needless-pass-by-ref-mut` implied by `-D warnings`
+
+error: aborting due to 4 previous errors
 
diff --git a/tests/ui/needless_pass_by_ref_mut.rs b/tests/ui/needless_pass_by_ref_mut.rs
index 5e7280995c6..ae7b018d0e2 100644
--- a/tests/ui/needless_pass_by_ref_mut.rs
+++ b/tests/ui/needless_pass_by_ref_mut.rs
@@ -1,9 +1,10 @@
-#![allow(unused)]
+#![allow(clippy::if_same_then_else, clippy::no_effect)]
+#![feature(lint_reasons)]
 
 use std::ptr::NonNull;
 
-// Should only warn for `s`.
 fn foo(s: &mut Vec<u32>, b: &u32, x: &mut u32) {
+    //~^ ERROR: this argument is a mutable reference, but not used mutably
     *x += *b + s.len() as u32;
 }
 
@@ -27,8 +28,8 @@ fn foo5(s: &mut Vec<u32>) {
     foo2(s);
 }
 
-// Should warn.
 fn foo6(s: &mut Vec<u32>) {
+    //~^ ERROR: this argument is a mutable reference, but not used mutably
     non_mut_ref(s);
 }
 
@@ -40,13 +41,13 @@ impl Bar {
     // Should not warn on `&mut self`.
     fn bar(&mut self) {}
 
-    // Should warn about `vec`
     fn mushroom(&self, vec: &mut Vec<i32>) -> usize {
+        //~^ ERROR: this argument is a mutable reference, but not used mutably
         vec.len()
     }
 
-    // Should warn about `vec` (and not `self`).
     fn badger(&mut self, vec: &mut Vec<i32>) -> usize {
+        //~^ ERROR: this argument is a mutable reference, but not used mutably
         vec.len()
     }
 }
@@ -91,6 +92,110 @@ impl<T> Mut<T> {
 // Should not warn.
 fn unused(_: &mut u32, _b: &mut u8) {}
 
+// Should not warn.
+async fn f1(x: &mut i32) {
+    *x += 1;
+}
+// Should not warn.
+async fn f2(x: &mut i32, y: String) {
+    *x += 1;
+}
+// Should not warn.
+async fn f3(x: &mut i32, y: String, z: String) {
+    *x += 1;
+}
+// Should not warn.
+async fn f4(x: &mut i32, y: i32) {
+    *x += 1;
+}
+// Should not warn.
+async fn f5(x: i32, y: &mut i32) {
+    *y += 1;
+}
+// Should not warn.
+async fn f6(x: i32, y: &mut i32, z: &mut i32) {
+    *y += 1;
+    *z += 1;
+}
+// Should not warn.
+async fn f7(x: &mut i32, y: i32, z: &mut i32, a: i32) {
+    *x += 1;
+    *z += 1;
+}
+
+async fn a1(x: &mut i32) {
+    //~^ ERROR: this argument is a mutable reference, but not used mutably
+    println!("{:?}", x);
+}
+async fn a2(x: &mut i32, y: String) {
+    //~^ ERROR: this argument is a mutable reference, but not used mutably
+    println!("{:?}", x);
+}
+async fn a3(x: &mut i32, y: String, z: String) {
+    //~^ ERROR: this argument is a mutable reference, but not used mutably
+    println!("{:?}", x);
+}
+async fn a4(x: &mut i32, y: i32) {
+    //~^ ERROR: this argument is a mutable reference, but not used mutably
+    println!("{:?}", x);
+}
+async fn a5(x: i32, y: &mut i32) {
+    //~^ ERROR: this argument is a mutable reference, but not used mutably
+    println!("{:?}", x);
+}
+async fn a6(x: i32, y: &mut i32) {
+    //~^ ERROR: this argument is a mutable reference, but not used mutably
+    println!("{:?}", x);
+}
+async fn a7(x: i32, y: i32, z: &mut i32) {
+    //~^ ERROR: this argument is a mutable reference, but not used mutably
+    println!("{:?}", z);
+}
+async fn a8(x: i32, a: &mut i32, y: i32, z: &mut i32) {
+    //~^ ERROR: this argument is a mutable reference, but not used mutably
+    println!("{:?}", z);
+}
+
+// Should not warn (passed as closure which takes `&mut`).
+fn passed_as_closure(s: &mut u32) {}
+
+// Should not warn.
+fn passed_as_local(s: &mut u32) {}
+
+// Should not warn.
+fn ty_unify_1(s: &mut u32) {}
+
+// Should not warn.
+fn ty_unify_2(s: &mut u32) {}
+
+// Should not warn.
+fn passed_as_field(s: &mut u32) {}
+
+fn closure_takes_mut(s: fn(&mut u32)) {}
+
+struct A {
+    s: fn(&mut u32),
+}
+
+// Should warn.
+fn used_as_path(s: &mut u32) {}
+
+// Make sure lint attributes work fine
+#[expect(clippy::needless_pass_by_ref_mut)]
+fn lint_attr(s: &mut u32) {}
+
+#[cfg(not(feature = "a"))]
+fn cfg_warn(s: &mut u32) {}
+//~^ ERROR: this argument is a mutable reference, but not used mutably
+//~| NOTE: this is cfg-gated and may require further changes
+
+#[cfg(not(feature = "a"))]
+mod foo {
+    fn cfg_warn(s: &mut u32) {}
+    //~^ ERROR: this argument is a mutable reference, but not used mutably
+    //~| NOTE: this is cfg-gated and may require further changes
+}
+
 fn main() {
     let mut u = 0;
     let mut v = vec![0];
@@ -102,4 +207,9 @@ fn main() {
     alias_check(&mut v);
     alias_check2(&mut v);
     println!("{u}");
+    closure_takes_mut(passed_as_closure);
+    A { s: passed_as_field };
+    used_as_path;
+    let _: fn(&mut u32) = passed_as_local;
+    let _ = if v[0] == 0 { ty_unify_1 } else { ty_unify_2 };
 }
diff --git a/tests/ui/needless_pass_by_ref_mut.stderr b/tests/ui/needless_pass_by_ref_mut.stderr
index 5e9d80bb6c4..0d426ce32f9 100644
--- a/tests/ui/needless_pass_by_ref_mut.stderr
+++ b/tests/ui/needless_pass_by_ref_mut.stderr
@@ -24,5 +24,75 @@ error: this argument is a mutable reference, but not used mutably
 LL |     fn badger(&mut self, vec: &mut Vec<i32>) -> usize {
    |                               ^^^^^^^^^^^^^ help: consider changing to: `&Vec<i32>`
 
-error: aborting due to 4 previous errors
+error: this argument is a mutable reference, but not used mutably
+  --> $DIR/needless_pass_by_ref_mut.rs:126:16
+   |
+LL | async fn a1(x: &mut i32) {
+   |                ^^^^^^^^ help: consider changing to: `&i32`
+
+error: this argument is a mutable reference, but not used mutably
+  --> $DIR/needless_pass_by_ref_mut.rs:130:16
+   |
+LL | async fn a2(x: &mut i32, y: String) {
+   |                ^^^^^^^^ help: consider changing to: `&i32`
+
+error: this argument is a mutable reference, but not used mutably
+  --> $DIR/needless_pass_by_ref_mut.rs:134:16
+   |
+LL | async fn a3(x: &mut i32, y: String, z: String) {
+   |                ^^^^^^^^ help: consider changing to: `&i32`
+
+error: this argument is a mutable reference, but not used mutably
+  --> $DIR/needless_pass_by_ref_mut.rs:138:16
+   |
+LL | async fn a4(x: &mut i32, y: i32) {
+   |                ^^^^^^^^ help: consider changing to: `&i32`
+
+error: this argument is a mutable reference, but not used mutably
+  --> $DIR/needless_pass_by_ref_mut.rs:142:24
+   |
+LL | async fn a5(x: i32, y: &mut i32) {
+   |                        ^^^^^^^^ help: consider changing to: `&i32`
+
+error: this argument is a mutable reference, but not used mutably
+  --> $DIR/needless_pass_by_ref_mut.rs:146:24
+   |
+LL | async fn a6(x: i32, y: &mut i32) {
+   |                        ^^^^^^^^ help: consider changing to: `&i32`
+
+error: this argument is a mutable reference, but not used mutably
+  --> $DIR/needless_pass_by_ref_mut.rs:150:32
+   |
+LL | async fn a7(x: i32, y: i32, z: &mut i32) {
+   |                                ^^^^^^^^ help: consider changing to: `&i32`
+
+error: this argument is a mutable reference, but not used mutably
+  --> $DIR/needless_pass_by_ref_mut.rs:154:24
+   |
+LL | async fn a8(x: i32, a: &mut i32, y: i32, z: &mut i32) {
+   |                        ^^^^^^^^ help: consider changing to: `&i32`
+
+error: this argument is a mutable reference, but not used mutably
+  --> $DIR/needless_pass_by_ref_mut.rs:154:45
+   |
+LL | async fn a8(x: i32, a: &mut i32, y: i32, z: &mut i32) {
+   |                                             ^^^^^^^^ help: consider changing to: `&i32`
+
+error: this argument is a mutable reference, but not used mutably
+  --> $DIR/needless_pass_by_ref_mut.rs:188:16
+   |
+LL | fn cfg_warn(s: &mut u32) {}
+   |                ^^^^^^^^ help: consider changing to: `&u32`
+   |
+   = note: this is cfg-gated and may require further changes
+
+error: this argument is a mutable reference, but not used mutably
+  --> $DIR/needless_pass_by_ref_mut.rs:194:20
+   |
+LL |     fn cfg_warn(s: &mut u32) {}
+   |                    ^^^^^^^^ help: consider changing to: `&u32`
+   |
+   = note: this is cfg-gated and may require further changes
+
+error: aborting due to 15 previous errors
 
diff --git a/tests/ui/needless_return_with_question_mark.fixed b/tests/ui/needless_return_with_question_mark.fixed
new file mode 100644
index 00000000000..d6e47d07b0f
--- /dev/null
+++ b/tests/ui/needless_return_with_question_mark.fixed
@@ -0,0 +1,40 @@
+//@run-rustfix
+//@aux-build:proc_macros.rs:proc-macro
+#![allow(
+    clippy::needless_return,
+    clippy::no_effect,
+    clippy::unit_arg,
+    clippy::useless_conversion,
+    unused
+)]
+
+#[macro_use]
+extern crate proc_macros;
+
+fn a() -> u32 {
+    return 0;
+}
+
+fn b() -> Result<u32, u32> {
+    return Err(0);
+}
+
+// Do not lint
+fn c() -> Option<()> {
+    return None?;
+}
+
+fn main() -> Result<(), ()> {
+    Err(())?;
+    return Ok::<(), ()>(());
+    Err(())?;
+    Ok::<(), ()>(());
+    return Err(().into());
+    external! {
+        return Err(())?;
+    }
+    with_span! {
+        return Err(())?;
+    }
+    Err(())
+}
diff --git a/tests/ui/needless_return_with_question_mark.rs b/tests/ui/needless_return_with_question_mark.rs
new file mode 100644
index 00000000000..4fc04d363a9
--- /dev/null
+++ b/tests/ui/needless_return_with_question_mark.rs
@@ -0,0 +1,40 @@
+//@run-rustfix
+//@aux-build:proc_macros.rs:proc-macro
+#![allow(
+    clippy::needless_return,
+    clippy::no_effect,
+    clippy::unit_arg,
+    clippy::useless_conversion,
+    unused
+)]
+
+#[macro_use]
+extern crate proc_macros;
+
+fn a() -> u32 {
+    return 0;
+}
+
+fn b() -> Result<u32, u32> {
+    return Err(0);
+}
+
+// Do not lint
+fn c() -> Option<()> {
+    return None?;
+}
+
+fn main() -> Result<(), ()> {
+    return Err(())?;
+    return Ok::<(), ()>(());
+    Err(())?;
+    Ok::<(), ()>(());
+    return Err(().into());
+    external! {
+        return Err(())?;
+    }
+    with_span! {
+        return Err(())?;
+    }
+    Err(())
+}
diff --git a/tests/ui/needless_return_with_question_mark.stderr b/tests/ui/needless_return_with_question_mark.stderr
new file mode 100644
index 00000000000..e1d91638d2c
--- /dev/null
+++ b/tests/ui/needless_return_with_question_mark.stderr
@@ -0,0 +1,10 @@
+error: unneeded `return` statement with `?` operator
+  --> $DIR/needless_return_with_question_mark.rs:28:5
+   |
+LL |     return Err(())?;
+   |     ^^^^^^^ help: remove it
+   |
+   = note: `-D clippy::needless-return-with-question-mark` implied by `-D warnings`
+
+error: aborting due to previous error
+
diff --git a/tests/ui/option_env_unwrap.rs b/tests/ui/option_env_unwrap.rs
index 65a1b467f81..61dbad939db 100644
--- a/tests/ui/option_env_unwrap.rs
+++ b/tests/ui/option_env_unwrap.rs
@@ -9,6 +9,7 @@ use proc_macros::{external, inline_macros};
 fn main() {
     let _ = option_env!("PATH").unwrap();
     let _ = option_env!("PATH").expect("environment variable PATH isn't set");
+    let _ = option_env!("__Y__do_not_use").unwrap(); // This test only works if you don't have a __Y__do_not_use env variable in your environment.
     let _ = inline!(option_env!($"PATH").unwrap());
     let _ = inline!(option_env!($"PATH").expect($"environment variable PATH isn't set"));
     let _ = external!(option_env!($"PATH").unwrap());
diff --git a/tests/ui/option_env_unwrap.stderr b/tests/ui/option_env_unwrap.stderr
index 7bba62686ee..cfa9dd58a30 100644
--- a/tests/ui/option_env_unwrap.stderr
+++ b/tests/ui/option_env_unwrap.stderr
@@ -16,7 +16,15 @@ LL |     let _ = option_env!("PATH").expect("environment variable PATH isn't set
    = help: consider using the `env!` macro instead
 
 error: this will panic at run-time if the environment variable doesn't exist at compile-time
-  --> $DIR/option_env_unwrap.rs:12:21
+  --> $DIR/option_env_unwrap.rs:12:13
+   |
+LL |     let _ = option_env!("__Y__do_not_use").unwrap(); // This test only works if you don't have a __Y__do_not_use env variable in your env...
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = help: consider using the `env!` macro instead
+
+error: this will panic at run-time if the environment variable doesn't exist at compile-time
+  --> $DIR/option_env_unwrap.rs:13:21
    |
 LL |     let _ = inline!(option_env!($"PATH").unwrap());
    |                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -25,7 +33,7 @@ LL |     let _ = inline!(option_env!($"PATH").unwrap());
    = note: this error originates in the macro `__inline_mac_fn_main` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error: this will panic at run-time if the environment variable doesn't exist at compile-time
-  --> $DIR/option_env_unwrap.rs:13:21
+  --> $DIR/option_env_unwrap.rs:14:21
    |
 LL |     let _ = inline!(option_env!($"PATH").expect($"environment variable PATH isn't set"));
    |                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -34,7 +42,7 @@ LL |     let _ = inline!(option_env!($"PATH").expect($"environment variable PATH
    = note: this error originates in the macro `__inline_mac_fn_main` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error: this will panic at run-time if the environment variable doesn't exist at compile-time
-  --> $DIR/option_env_unwrap.rs:14:13
+  --> $DIR/option_env_unwrap.rs:15:13
    |
 LL |     let _ = external!(option_env!($"PATH").unwrap());
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -43,7 +51,7 @@ LL |     let _ = external!(option_env!($"PATH").unwrap());
    = note: this error originates in the macro `external` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error: this will panic at run-time if the environment variable doesn't exist at compile-time
-  --> $DIR/option_env_unwrap.rs:15:13
+  --> $DIR/option_env_unwrap.rs:16:13
    |
 LL |     let _ = external!(option_env!($"PATH").expect($"environment variable PATH isn't set"));
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -51,5 +59,5 @@ LL |     let _ = external!(option_env!($"PATH").expect($"environment variable PA
    = help: consider using the `env!` macro instead
    = note: this error originates in the macro `external` (in Nightly builds, run with -Z macro-backtrace for more info)
 
-error: aborting due to 6 previous errors
+error: aborting due to 7 previous errors
 
diff --git a/tests/ui/option_if_let_else.fixed b/tests/ui/option_if_let_else.fixed
index 8e59e4375d2..6fee3cce619 100644
--- a/tests/ui/option_if_let_else.fixed
+++ b/tests/ui/option_if_let_else.fixed
@@ -5,7 +5,8 @@
     clippy::redundant_closure,
     clippy::ref_option_ref,
     clippy::equatable_if_let,
-    clippy::let_unit_value
+    clippy::let_unit_value,
+    clippy::redundant_locals
 )]
 
 fn bad1(string: Option<&str>) -> (bool, &str) {
diff --git a/tests/ui/option_if_let_else.rs b/tests/ui/option_if_let_else.rs
index e72edf2a8e3..4b3cf948a1b 100644
--- a/tests/ui/option_if_let_else.rs
+++ b/tests/ui/option_if_let_else.rs
@@ -5,7 +5,8 @@
     clippy::redundant_closure,
     clippy::ref_option_ref,
     clippy::equatable_if_let,
-    clippy::let_unit_value
+    clippy::let_unit_value,
+    clippy::redundant_locals
 )]
 
 fn bad1(string: Option<&str>) -> (bool, &str) {
diff --git a/tests/ui/option_if_let_else.stderr b/tests/ui/option_if_let_else.stderr
index aa2da217400..350f0f07e13 100644
--- a/tests/ui/option_if_let_else.stderr
+++ b/tests/ui/option_if_let_else.stderr
@@ -1,5 +1,5 @@
 error: use Option::map_or instead of an if let/else
-  --> $DIR/option_if_let_else.rs:12:5
+  --> $DIR/option_if_let_else.rs:13:5
    |
 LL | /     if let Some(x) = string {
 LL | |         (true, x)
@@ -11,19 +11,19 @@ LL | |     }
    = note: `-D clippy::option-if-let-else` implied by `-D warnings`
 
 error: use Option::map_or instead of an if let/else
-  --> $DIR/option_if_let_else.rs:30:13
+  --> $DIR/option_if_let_else.rs:31:13
    |
 LL |     let _ = if let Some(s) = *string { s.len() } else { 0 };
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `string.map_or(0, |s| s.len())`
 
 error: use Option::map_or instead of an if let/else
-  --> $DIR/option_if_let_else.rs:31:13
+  --> $DIR/option_if_let_else.rs:32:13
    |
 LL |     let _ = if let Some(s) = &num { s } else { &0 };
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `num.as_ref().map_or(&0, |s| s)`
 
 error: use Option::map_or instead of an if let/else
-  --> $DIR/option_if_let_else.rs:32:13
+  --> $DIR/option_if_let_else.rs:33:13
    |
 LL |       let _ = if let Some(s) = &mut num {
    |  _____________^
@@ -43,13 +43,13 @@ LL ~     });
    |
 
 error: use Option::map_or instead of an if let/else
-  --> $DIR/option_if_let_else.rs:38:13
+  --> $DIR/option_if_let_else.rs:39:13
    |
 LL |     let _ = if let Some(ref s) = num { s } else { &0 };
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `num.as_ref().map_or(&0, |s| s)`
 
 error: use Option::map_or instead of an if let/else
-  --> $DIR/option_if_let_else.rs:39:13
+  --> $DIR/option_if_let_else.rs:40:13
    |
 LL |       let _ = if let Some(mut s) = num {
    |  _____________^
@@ -69,7 +69,7 @@ LL ~     });
    |
 
 error: use Option::map_or instead of an if let/else
-  --> $DIR/option_if_let_else.rs:45:13
+  --> $DIR/option_if_let_else.rs:46:13
    |
 LL |       let _ = if let Some(ref mut s) = num {
    |  _____________^
@@ -89,7 +89,7 @@ LL ~     });
    |
 
 error: use Option::map_or instead of an if let/else
-  --> $DIR/option_if_let_else.rs:54:5
+  --> $DIR/option_if_let_else.rs:55:5
    |
 LL | /     if let Some(x) = arg {
 LL | |         let y = x * x;
@@ -108,7 +108,7 @@ LL +     })
    |
 
 error: use Option::map_or_else instead of an if let/else
-  --> $DIR/option_if_let_else.rs:67:13
+  --> $DIR/option_if_let_else.rs:68:13
    |
 LL |       let _ = if let Some(x) = arg {
    |  _____________^
@@ -120,7 +120,7 @@ LL | |     };
    | |_____^ help: try: `arg.map_or_else(|| side_effect(), |x| x)`
 
 error: use Option::map_or_else instead of an if let/else
-  --> $DIR/option_if_let_else.rs:76:13
+  --> $DIR/option_if_let_else.rs:77:13
    |
 LL |       let _ = if let Some(x) = arg {
    |  _____________^
@@ -143,7 +143,7 @@ LL ~     }, |x| x * x * x * x);
    |
 
 error: use Option::map_or_else instead of an if let/else
-  --> $DIR/option_if_let_else.rs:109:13
+  --> $DIR/option_if_let_else.rs:110:13
    |
 LL | /             if let Some(idx) = s.find('.') {
 LL | |                 vec![s[..idx].to_string(), s[idx..].to_string()]
@@ -153,7 +153,7 @@ LL | |             }
    | |_____________^ help: try: `s.find('.').map_or_else(|| vec![s.to_string()], |idx| vec![s[..idx].to_string(), s[idx..].to_string()])`
 
 error: use Option::map_or_else instead of an if let/else
-  --> $DIR/option_if_let_else.rs:120:5
+  --> $DIR/option_if_let_else.rs:121:5
    |
 LL | /     if let Ok(binding) = variable {
 LL | |         println!("Ok {binding}");
@@ -172,13 +172,13 @@ LL +     })
    |
 
 error: use Option::map_or instead of an if let/else
-  --> $DIR/option_if_let_else.rs:142:13
+  --> $DIR/option_if_let_else.rs:143:13
    |
 LL |     let _ = if let Some(x) = optional { x + 2 } else { 5 };
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `optional.map_or(5, |x| x + 2)`
 
 error: use Option::map_or instead of an if let/else
-  --> $DIR/option_if_let_else.rs:152:13
+  --> $DIR/option_if_let_else.rs:153:13
    |
 LL |       let _ = if let Some(x) = Some(0) {
    |  _____________^
@@ -200,13 +200,13 @@ LL ~         });
    |
 
 error: use Option::map_or instead of an if let/else
-  --> $DIR/option_if_let_else.rs:180:13
+  --> $DIR/option_if_let_else.rs:181:13
    |
 LL |     let _ = if let Some(x) = Some(0) { s.len() + x } else { s.len() };
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Some(0).map_or(s.len(), |x| s.len() + x)`
 
 error: use Option::map_or instead of an if let/else
-  --> $DIR/option_if_let_else.rs:184:13
+  --> $DIR/option_if_let_else.rs:185:13
    |
 LL |       let _ = if let Some(x) = Some(0) {
    |  _____________^
@@ -226,7 +226,7 @@ LL ~     });
    |
 
 error: use Option::map_or instead of an if let/else
-  --> $DIR/option_if_let_else.rs:223:13
+  --> $DIR/option_if_let_else.rs:224:13
    |
 LL |       let _ = match s {
    |  _____________^
@@ -236,7 +236,7 @@ LL | |     };
    | |_____^ help: try: `s.map_or(1, |string| string.len())`
 
 error: use Option::map_or instead of an if let/else
-  --> $DIR/option_if_let_else.rs:227:13
+  --> $DIR/option_if_let_else.rs:228:13
    |
 LL |       let _ = match Some(10) {
    |  _____________^
@@ -246,7 +246,7 @@ LL | |     };
    | |_____^ help: try: `Some(10).map_or(5, |a| a + 1)`
 
 error: use Option::map_or instead of an if let/else
-  --> $DIR/option_if_let_else.rs:233:13
+  --> $DIR/option_if_let_else.rs:234:13
    |
 LL |       let _ = match res {
    |  _____________^
@@ -256,7 +256,7 @@ LL | |     };
    | |_____^ help: try: `res.map_or(1, |a| a + 1)`
 
 error: use Option::map_or instead of an if let/else
-  --> $DIR/option_if_let_else.rs:237:13
+  --> $DIR/option_if_let_else.rs:238:13
    |
 LL |       let _ = match res {
    |  _____________^
@@ -266,13 +266,13 @@ LL | |     };
    | |_____^ help: try: `res.map_or(1, |a| a + 1)`
 
 error: use Option::map_or instead of an if let/else
-  --> $DIR/option_if_let_else.rs:241:13
+  --> $DIR/option_if_let_else.rs:242:13
    |
 LL |     let _ = if let Ok(a) = res { a + 1 } else { 5 };
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `res.map_or(5, |a| a + 1)`
 
 error: use Option::map_or instead of an if let/else
-  --> $DIR/option_if_let_else.rs:258:9
+  --> $DIR/option_if_let_else.rs:259:9
    |
 LL | /         match initial {
 LL | |             Some(value) => do_something(value),
@@ -281,7 +281,7 @@ LL | |         }
    | |_________^ help: try: `initial.as_ref().map_or({}, |value| do_something(value))`
 
 error: use Option::map_or instead of an if let/else
-  --> $DIR/option_if_let_else.rs:265:9
+  --> $DIR/option_if_let_else.rs:266:9
    |
 LL | /         match initial {
 LL | |             Some(value) => do_something2(value),
diff --git a/tests/ui/or_fun_call.fixed b/tests/ui/or_fun_call.fixed
index 6deff0f3240..581f3ad45c7 100644
--- a/tests/ui/or_fun_call.fixed
+++ b/tests/ui/or_fun_call.fixed
@@ -190,7 +190,7 @@ mod issue8239 {
                 acc.push_str(&f);
                 acc
             })
-            .unwrap_or_default();
+            .unwrap_or(String::new());
     }
 
     fn more_to_max_suggestion_highest_lines_1() {
@@ -203,7 +203,7 @@ mod issue8239 {
                 acc.push_str(&f);
                 acc
             })
-            .unwrap_or_default();
+            .unwrap_or(String::new());
     }
 
     fn equal_to_max_suggestion_highest_lines() {
@@ -215,7 +215,7 @@ mod issue8239 {
                 acc.push_str(&f);
                 acc
             })
-            .unwrap_or_default();
+            .unwrap_or(String::new());
     }
 
     fn less_than_max_suggestion_highest_lines() {
@@ -226,7 +226,7 @@ mod issue8239 {
             acc.push_str(&f);
             acc
         })
-        .unwrap_or_default();
+        .unwrap_or(String::new());
     }
 }
 
@@ -257,4 +257,59 @@ mod issue8993 {
     }
 }
 
+mod lazy {
+    use super::*;
+
+    fn foo() {
+        struct Foo;
+
+        impl Foo {
+            fn new() -> Foo {
+                Foo
+            }
+        }
+
+        struct FakeDefault;
+        impl FakeDefault {
+            fn default() -> Self {
+                FakeDefault
+            }
+        }
+
+        impl Default for FakeDefault {
+            fn default() -> Self {
+                FakeDefault
+            }
+        }
+
+        let with_new = Some(vec![1]);
+        with_new.unwrap_or_default();
+
+        let with_default_trait = Some(1);
+        with_default_trait.unwrap_or_default();
+
+        let with_default_type = Some(1);
+        with_default_type.unwrap_or_default();
+
+        let real_default = None::<FakeDefault>;
+        real_default.unwrap_or_default();
+
+        let mut map = HashMap::<u64, String>::new();
+        map.entry(42).or_default();
+
+        let mut btree = BTreeMap::<u64, String>::new();
+        btree.entry(42).or_default();
+
+        let stringy = Some(String::new());
+        let _ = stringy.unwrap_or_default();
+
+        // negative tests
+        let self_default = None::<FakeDefault>;
+        self_default.unwrap_or_else(<FakeDefault>::default);
+
+        let without_default = Some(Foo);
+        without_default.unwrap_or_else(Foo::new);
+    }
+}
+
 fn main() {}
diff --git a/tests/ui/or_fun_call.rs b/tests/ui/or_fun_call.rs
index b05b33e6ee2..1f3987eb891 100644
--- a/tests/ui/or_fun_call.rs
+++ b/tests/ui/or_fun_call.rs
@@ -257,4 +257,59 @@ mod issue8993 {
     }
 }
 
+mod lazy {
+    use super::*;
+
+    fn foo() {
+        struct Foo;
+
+        impl Foo {
+            fn new() -> Foo {
+                Foo
+            }
+        }
+
+        struct FakeDefault;
+        impl FakeDefault {
+            fn default() -> Self {
+                FakeDefault
+            }
+        }
+
+        impl Default for FakeDefault {
+            fn default() -> Self {
+                FakeDefault
+            }
+        }
+
+        let with_new = Some(vec![1]);
+        with_new.unwrap_or_else(Vec::new);
+
+        let with_default_trait = Some(1);
+        with_default_trait.unwrap_or_else(Default::default);
+
+        let with_default_type = Some(1);
+        with_default_type.unwrap_or_else(u64::default);
+
+        let real_default = None::<FakeDefault>;
+        real_default.unwrap_or_else(<FakeDefault as Default>::default);
+
+        let mut map = HashMap::<u64, String>::new();
+        map.entry(42).or_insert_with(String::new);
+
+        let mut btree = BTreeMap::<u64, String>::new();
+        btree.entry(42).or_insert_with(String::new);
+
+        let stringy = Some(String::new());
+        let _ = stringy.unwrap_or_else(String::new);
+
+        // negative tests
+        let self_default = None::<FakeDefault>;
+        self_default.unwrap_or_else(<FakeDefault>::default);
+
+        let without_default = Some(Foo);
+        without_default.unwrap_or_else(Foo::new);
+    }
+}
+
 fn main() {}
diff --git a/tests/ui/or_fun_call.stderr b/tests/ui/or_fun_call.stderr
index 7342b0c2914..519f0916562 100644
--- a/tests/ui/or_fun_call.stderr
+++ b/tests/ui/or_fun_call.stderr
@@ -6,11 +6,13 @@ LL |     with_constructor.unwrap_or(make());
    |
    = note: `-D clippy::or-fun-call` implied by `-D warnings`
 
-error: use of `unwrap_or` followed by a call to `new`
+error: use of `unwrap_or` to construct default value
   --> $DIR/or_fun_call.rs:56:14
    |
 LL |     with_new.unwrap_or(Vec::new());
    |              ^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_default()`
+   |
+   = note: `-D clippy::unwrap-or-default` implied by `-D warnings`
 
 error: use of `unwrap_or` followed by a function call
   --> $DIR/or_fun_call.rs:59:21
@@ -30,13 +32,13 @@ error: use of `unwrap_or` followed by a function call
 LL |     with_err_args.unwrap_or(Vec::with_capacity(12));
    |                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_else(|_| Vec::with_capacity(12))`
 
-error: use of `unwrap_or` followed by a call to `default`
+error: use of `unwrap_or` to construct default value
   --> $DIR/or_fun_call.rs:68:24
    |
 LL |     with_default_trait.unwrap_or(Default::default());
    |                        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_default()`
 
-error: use of `unwrap_or` followed by a call to `default`
+error: use of `unwrap_or` to construct default value
   --> $DIR/or_fun_call.rs:71:23
    |
 LL |     with_default_type.unwrap_or(u64::default());
@@ -48,13 +50,13 @@ error: use of `unwrap_or` followed by a function call
 LL |     self_default.unwrap_or(<FakeDefault>::default());
    |                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_else(<FakeDefault>::default)`
 
-error: use of `unwrap_or` followed by a call to `default`
+error: use of `unwrap_or` to construct default value
   --> $DIR/or_fun_call.rs:77:18
    |
 LL |     real_default.unwrap_or(<FakeDefault as Default>::default());
    |                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_default()`
 
-error: use of `unwrap_or` followed by a call to `new`
+error: use of `unwrap_or` to construct default value
   --> $DIR/or_fun_call.rs:80:14
    |
 LL |     with_vec.unwrap_or(vec![]);
@@ -66,31 +68,31 @@ error: use of `unwrap_or` followed by a function call
 LL |     without_default.unwrap_or(Foo::new());
    |                     ^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_else(Foo::new)`
 
-error: use of `or_insert` followed by a call to `new`
+error: use of `or_insert` to construct default value
   --> $DIR/or_fun_call.rs:86:19
    |
 LL |     map.entry(42).or_insert(String::new());
    |                   ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `or_default()`
 
-error: use of `or_insert` followed by a call to `new`
+error: use of `or_insert` to construct default value
   --> $DIR/or_fun_call.rs:89:23
    |
 LL |     map_vec.entry(42).or_insert(vec![]);
    |                       ^^^^^^^^^^^^^^^^^ help: try: `or_default()`
 
-error: use of `or_insert` followed by a call to `new`
+error: use of `or_insert` to construct default value
   --> $DIR/or_fun_call.rs:92:21
    |
 LL |     btree.entry(42).or_insert(String::new());
    |                     ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `or_default()`
 
-error: use of `or_insert` followed by a call to `new`
+error: use of `or_insert` to construct default value
   --> $DIR/or_fun_call.rs:95:25
    |
 LL |     btree_vec.entry(42).or_insert(vec![]);
    |                         ^^^^^^^^^^^^^^^^^ help: try: `or_default()`
 
-error: use of `unwrap_or` followed by a call to `new`
+error: use of `unwrap_or` to construct default value
   --> $DIR/or_fun_call.rs:98:21
    |
 LL |     let _ = stringy.unwrap_or(String::new());
@@ -132,30 +134,6 @@ error: use of `unwrap_or` followed by a function call
 LL |         None.unwrap_or( unsafe { ptr_to_ref(s) }    );
    |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_else(|| unsafe { ptr_to_ref(s) })`
 
-error: use of `unwrap_or` followed by a call to `new`
-  --> $DIR/or_fun_call.rs:193:14
-   |
-LL |             .unwrap_or(String::new());
-   |              ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_default()`
-
-error: use of `unwrap_or` followed by a call to `new`
-  --> $DIR/or_fun_call.rs:206:14
-   |
-LL |             .unwrap_or(String::new());
-   |              ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_default()`
-
-error: use of `unwrap_or` followed by a call to `new`
-  --> $DIR/or_fun_call.rs:218:14
-   |
-LL |             .unwrap_or(String::new());
-   |              ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_default()`
-
-error: use of `unwrap_or` followed by a call to `new`
-  --> $DIR/or_fun_call.rs:229:10
-   |
-LL |         .unwrap_or(String::new());
-   |          ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_default()`
-
 error: use of `map_or` followed by a function call
   --> $DIR/or_fun_call.rs:254:25
    |
@@ -168,5 +146,47 @@ error: use of `map_or` followed by a function call
 LL |         let _ = Some(4).map_or(g(), f);
    |                         ^^^^^^^^^^^^^^ help: try: `map_or_else(g, f)`
 
-error: aborting due to 28 previous errors
+error: use of `unwrap_or_else` to construct default value
+  --> $DIR/or_fun_call.rs:286:18
+   |
+LL |         with_new.unwrap_or_else(Vec::new);
+   |                  ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_default()`
+
+error: use of `unwrap_or_else` to construct default value
+  --> $DIR/or_fun_call.rs:289:28
+   |
+LL |         with_default_trait.unwrap_or_else(Default::default);
+   |                            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_default()`
+
+error: use of `unwrap_or_else` to construct default value
+  --> $DIR/or_fun_call.rs:292:27
+   |
+LL |         with_default_type.unwrap_or_else(u64::default);
+   |                           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_default()`
+
+error: use of `unwrap_or_else` to construct default value
+  --> $DIR/or_fun_call.rs:295:22
+   |
+LL |         real_default.unwrap_or_else(<FakeDefault as Default>::default);
+   |                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_default()`
+
+error: use of `or_insert_with` to construct default value
+  --> $DIR/or_fun_call.rs:298:23
+   |
+LL |         map.entry(42).or_insert_with(String::new);
+   |                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `or_default()`
+
+error: use of `or_insert_with` to construct default value
+  --> $DIR/or_fun_call.rs:301:25
+   |
+LL |         btree.entry(42).or_insert_with(String::new);
+   |                         ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `or_default()`
+
+error: use of `unwrap_or_else` to construct default value
+  --> $DIR/or_fun_call.rs:304:25
+   |
+LL |         let _ = stringy.unwrap_or_else(String::new);
+   |                         ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_default()`
+
+error: aborting due to 31 previous errors
 
diff --git a/tests/ui/ptr_arg.rs b/tests/ui/ptr_arg.rs
index 13e993d247b..08075c382a2 100644
--- a/tests/ui/ptr_arg.rs
+++ b/tests/ui/ptr_arg.rs
@@ -267,3 +267,16 @@ mod issue_9218 {
         todo!()
     }
 }
+
+mod issue_11181 {
+    extern "C" fn allowed(_v: &Vec<u32>) {}
+
+    struct S;
+    impl S {
+        extern "C" fn allowed(_v: &Vec<u32>) {}
+    }
+
+    trait T {
+        extern "C" fn allowed(_v: &Vec<u32>) {}
+    }
+}
diff --git a/tests/ui/ptr_as_ptr.fixed b/tests/ui/ptr_as_ptr.fixed
index 26a64c861cf..84babb97416 100644
--- a/tests/ui/ptr_as_ptr.fixed
+++ b/tests/ui/ptr_as_ptr.fixed
@@ -3,8 +3,22 @@
 
 #![warn(clippy::ptr_as_ptr)]
 
+#[macro_use]
 extern crate proc_macros;
-use proc_macros::{external, inline_macros};
+
+mod issue_11278_a {
+    #[derive(Debug)]
+    pub struct T<D: std::fmt::Debug + ?Sized> {
+        pub p: D,
+    }
+}
+
+mod issue_11278_b {
+    pub fn f(o: &mut super::issue_11278_a::T<dyn std::fmt::Debug>) -> super::issue_11278_a::T<String> {
+        // Retain `super`
+        *unsafe { Box::from_raw(Box::into_raw(Box::new(o)).cast::<super::issue_11278_a::T<String>>()) }
+    }
+}
 
 #[inline_macros]
 fn main() {
diff --git a/tests/ui/ptr_as_ptr.rs b/tests/ui/ptr_as_ptr.rs
index ea40d494733..34fd76428b2 100644
--- a/tests/ui/ptr_as_ptr.rs
+++ b/tests/ui/ptr_as_ptr.rs
@@ -3,8 +3,22 @@
 
 #![warn(clippy::ptr_as_ptr)]
 
+#[macro_use]
 extern crate proc_macros;
-use proc_macros::{external, inline_macros};
+
+mod issue_11278_a {
+    #[derive(Debug)]
+    pub struct T<D: std::fmt::Debug + ?Sized> {
+        pub p: D,
+    }
+}
+
+mod issue_11278_b {
+    pub fn f(o: &mut super::issue_11278_a::T<dyn std::fmt::Debug>) -> super::issue_11278_a::T<String> {
+        // Retain `super`
+        *unsafe { Box::from_raw(Box::into_raw(Box::new(o)) as *mut super::issue_11278_a::T<String>) }
+    }
+}
 
 #[inline_macros]
 fn main() {
diff --git a/tests/ui/ptr_as_ptr.stderr b/tests/ui/ptr_as_ptr.stderr
index 78d733994ac..e64f3351505 100644
--- a/tests/ui/ptr_as_ptr.stderr
+++ b/tests/ui/ptr_as_ptr.stderr
@@ -1,37 +1,43 @@
 error: `as` casting between raw pointers without changing its mutability
-  --> $DIR/ptr_as_ptr.rs:14:13
+  --> $DIR/ptr_as_ptr.rs:19:33
    |
-LL |     let _ = ptr as *const i32;
-   |             ^^^^^^^^^^^^^^^^^ help: try `pointer::cast`, a safer alternative: `ptr.cast::<i32>()`
+LL |         *unsafe { Box::from_raw(Box::into_raw(Box::new(o)) as *mut super::issue_11278_a::T<String>) }
+   |                                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try `pointer::cast`, a safer alternative: `Box::into_raw(Box::new(o)).cast::<super::issue_11278_a::T<String>>()`
    |
    = note: `-D clippy::ptr-as-ptr` implied by `-D warnings`
 
 error: `as` casting between raw pointers without changing its mutability
-  --> $DIR/ptr_as_ptr.rs:15:13
+  --> $DIR/ptr_as_ptr.rs:28:13
+   |
+LL |     let _ = ptr as *const i32;
+   |             ^^^^^^^^^^^^^^^^^ help: try `pointer::cast`, a safer alternative: `ptr.cast::<i32>()`
+
+error: `as` casting between raw pointers without changing its mutability
+  --> $DIR/ptr_as_ptr.rs:29:13
    |
 LL |     let _ = mut_ptr as *mut i32;
    |             ^^^^^^^^^^^^^^^^^^^ help: try `pointer::cast`, a safer alternative: `mut_ptr.cast::<i32>()`
 
 error: `as` casting between raw pointers without changing its mutability
-  --> $DIR/ptr_as_ptr.rs:20:17
+  --> $DIR/ptr_as_ptr.rs:34:17
    |
 LL |         let _ = *ptr_ptr as *const i32;
    |                 ^^^^^^^^^^^^^^^^^^^^^^ help: try `pointer::cast`, a safer alternative: `(*ptr_ptr).cast::<i32>()`
 
 error: `as` casting between raw pointers without changing its mutability
-  --> $DIR/ptr_as_ptr.rs:33:25
+  --> $DIR/ptr_as_ptr.rs:47:25
    |
 LL |     let _: *const i32 = ptr as *const _;
    |                         ^^^^^^^^^^^^^^^ help: try `pointer::cast`, a safer alternative: `ptr.cast()`
 
 error: `as` casting between raw pointers without changing its mutability
-  --> $DIR/ptr_as_ptr.rs:34:23
+  --> $DIR/ptr_as_ptr.rs:48:23
    |
 LL |     let _: *mut i32 = mut_ptr as _;
    |                       ^^^^^^^^^^^^ help: try `pointer::cast`, a safer alternative: `mut_ptr.cast()`
 
 error: `as` casting between raw pointers without changing its mutability
-  --> $DIR/ptr_as_ptr.rs:37:21
+  --> $DIR/ptr_as_ptr.rs:51:21
    |
 LL |     let _ = inline!($ptr as *const i32);
    |                     ^^^^^^^^^^^^^^^^^^ help: try `pointer::cast`, a safer alternative: `$ptr.cast::<i32>()`
@@ -39,16 +45,16 @@ LL |     let _ = inline!($ptr as *const i32);
    = note: this error originates in the macro `__inline_mac_fn_main` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error: `as` casting between raw pointers without changing its mutability
-  --> $DIR/ptr_as_ptr.rs:58:13
+  --> $DIR/ptr_as_ptr.rs:72:13
    |
 LL |     let _ = ptr as *const i32;
    |             ^^^^^^^^^^^^^^^^^ help: try `pointer::cast`, a safer alternative: `ptr.cast::<i32>()`
 
 error: `as` casting between raw pointers without changing its mutability
-  --> $DIR/ptr_as_ptr.rs:59:13
+  --> $DIR/ptr_as_ptr.rs:73:13
    |
 LL |     let _ = mut_ptr as *mut i32;
    |             ^^^^^^^^^^^^^^^^^^^ help: try `pointer::cast`, a safer alternative: `mut_ptr.cast::<i32>()`
 
-error: aborting due to 8 previous errors
+error: aborting due to 9 previous errors
 
diff --git a/tests/ui/question_mark.fixed b/tests/ui/question_mark.fixed
index 2d8920ccc42..20b9e42a7aa 100644
--- a/tests/ui/question_mark.fixed
+++ b/tests/ui/question_mark.fixed
@@ -138,6 +138,23 @@ fn result_func(x: Result<i32, i32>) -> Result<i32, i32> {
     // no warning
     let _ = if let Err(e) = x { Err(e) } else { Ok(0) };
 
+    // issue #11283
+    // no warning
+    #[warn(clippy::question_mark_used)]
+    {
+        if let Err(err) = Ok(()) {
+            return Err(err);
+        }
+
+        if Err::<i32, _>(0).is_err() {
+            return Err(0);
+        } else {
+            return Ok(0);
+        }
+
+        unreachable!()
+    }
+
     Ok(y)
 }
 
diff --git a/tests/ui/question_mark.rs b/tests/ui/question_mark.rs
index 69451c17ee7..8bdafd46e8f 100644
--- a/tests/ui/question_mark.rs
+++ b/tests/ui/question_mark.rs
@@ -170,6 +170,23 @@ fn result_func(x: Result<i32, i32>) -> Result<i32, i32> {
     // no warning
     let _ = if let Err(e) = x { Err(e) } else { Ok(0) };
 
+    // issue #11283
+    // no warning
+    #[warn(clippy::question_mark_used)]
+    {
+        if let Err(err) = Ok(()) {
+            return Err(err);
+        }
+
+        if Err::<i32, _>(0).is_err() {
+            return Err(0);
+        } else {
+            return Ok(0);
+        }
+
+        unreachable!()
+    }
+
     Ok(y)
 }
 
diff --git a/tests/ui/question_mark.stderr b/tests/ui/question_mark.stderr
index 2cfd7586308..62489c8c8c4 100644
--- a/tests/ui/question_mark.stderr
+++ b/tests/ui/question_mark.stderr
@@ -115,7 +115,7 @@ LL | |     }
    | |_____^ help: replace it with: `x?;`
 
 error: this block may be rewritten with the `?` operator
-  --> $DIR/question_mark.rs:197:5
+  --> $DIR/question_mark.rs:214:5
    |
 LL | /     if let Err(err) = func_returning_result() {
 LL | |         return Err(err);
@@ -123,7 +123,7 @@ LL | |     }
    | |_____^ help: replace it with: `func_returning_result()?;`
 
 error: this block may be rewritten with the `?` operator
-  --> $DIR/question_mark.rs:204:5
+  --> $DIR/question_mark.rs:221:5
    |
 LL | /     if let Err(err) = func_returning_result() {
 LL | |         return Err(err);
@@ -131,7 +131,7 @@ LL | |     }
    | |_____^ help: replace it with: `func_returning_result()?;`
 
 error: this block may be rewritten with the `?` operator
-  --> $DIR/question_mark.rs:281:13
+  --> $DIR/question_mark.rs:298:13
    |
 LL | /             if a.is_none() {
 LL | |                 return None;
diff --git a/tests/ui/range_contains.fixed b/tests/ui/range_contains.fixed
index 0a92ee7c8dd..47c5248118e 100644
--- a/tests/ui/range_contains.fixed
+++ b/tests/ui/range_contains.fixed
@@ -5,6 +5,8 @@
 #![allow(clippy::no_effect)]
 #![allow(clippy::short_circuit_statement)]
 #![allow(clippy::unnecessary_operation)]
+#![allow(clippy::impossible_comparisons)]
+#![allow(clippy::redundant_comparisons)]
 
 fn main() {
     let x = 9_i32;
diff --git a/tests/ui/range_contains.rs b/tests/ui/range_contains.rs
index 7a83be60957..a35315a649d 100644
--- a/tests/ui/range_contains.rs
+++ b/tests/ui/range_contains.rs
@@ -5,6 +5,8 @@
 #![allow(clippy::no_effect)]
 #![allow(clippy::short_circuit_statement)]
 #![allow(clippy::unnecessary_operation)]
+#![allow(clippy::impossible_comparisons)]
+#![allow(clippy::redundant_comparisons)]
 
 fn main() {
     let x = 9_i32;
diff --git a/tests/ui/range_contains.stderr b/tests/ui/range_contains.stderr
index ea34023a466..1265db695bf 100644
--- a/tests/ui/range_contains.stderr
+++ b/tests/ui/range_contains.stderr
@@ -1,5 +1,5 @@
 error: manual `Range::contains` implementation
-  --> $DIR/range_contains.rs:13:5
+  --> $DIR/range_contains.rs:15:5
    |
 LL |     x >= 8 && x < 12;
    |     ^^^^^^^^^^^^^^^^ help: use: `(8..12).contains(&x)`
@@ -7,121 +7,121 @@ LL |     x >= 8 && x < 12;
    = note: `-D clippy::manual-range-contains` implied by `-D warnings`
 
 error: manual `Range::contains` implementation
-  --> $DIR/range_contains.rs:14:5
+  --> $DIR/range_contains.rs:16:5
    |
 LL |     x < 42 && x >= 21;
    |     ^^^^^^^^^^^^^^^^^ help: use: `(21..42).contains(&x)`
 
 error: manual `Range::contains` implementation
-  --> $DIR/range_contains.rs:15:5
+  --> $DIR/range_contains.rs:17:5
    |
 LL |     100 > x && 1 <= x;
    |     ^^^^^^^^^^^^^^^^^ help: use: `(1..100).contains(&x)`
 
 error: manual `RangeInclusive::contains` implementation
-  --> $DIR/range_contains.rs:18:5
+  --> $DIR/range_contains.rs:20:5
    |
 LL |     x >= 9 && x <= 99;
    |     ^^^^^^^^^^^^^^^^^ help: use: `(9..=99).contains(&x)`
 
 error: manual `RangeInclusive::contains` implementation
-  --> $DIR/range_contains.rs:19:5
+  --> $DIR/range_contains.rs:21:5
    |
 LL |     x <= 33 && x >= 1;
    |     ^^^^^^^^^^^^^^^^^ help: use: `(1..=33).contains(&x)`
 
 error: manual `RangeInclusive::contains` implementation
-  --> $DIR/range_contains.rs:20:5
+  --> $DIR/range_contains.rs:22:5
    |
 LL |     999 >= x && 1 <= x;
    |     ^^^^^^^^^^^^^^^^^^ help: use: `(1..=999).contains(&x)`
 
 error: manual `!Range::contains` implementation
-  --> $DIR/range_contains.rs:23:5
+  --> $DIR/range_contains.rs:25:5
    |
 LL |     x < 8 || x >= 12;
    |     ^^^^^^^^^^^^^^^^ help: use: `!(8..12).contains(&x)`
 
 error: manual `!Range::contains` implementation
-  --> $DIR/range_contains.rs:24:5
+  --> $DIR/range_contains.rs:26:5
    |
 LL |     x >= 42 || x < 21;
    |     ^^^^^^^^^^^^^^^^^ help: use: `!(21..42).contains(&x)`
 
 error: manual `!Range::contains` implementation
-  --> $DIR/range_contains.rs:25:5
+  --> $DIR/range_contains.rs:27:5
    |
 LL |     100 <= x || 1 > x;
    |     ^^^^^^^^^^^^^^^^^ help: use: `!(1..100).contains(&x)`
 
 error: manual `!RangeInclusive::contains` implementation
-  --> $DIR/range_contains.rs:28:5
+  --> $DIR/range_contains.rs:30:5
    |
 LL |     x < 9 || x > 99;
    |     ^^^^^^^^^^^^^^^ help: use: `!(9..=99).contains(&x)`
 
 error: manual `!RangeInclusive::contains` implementation
-  --> $DIR/range_contains.rs:29:5
+  --> $DIR/range_contains.rs:31:5
    |
 LL |     x > 33 || x < 1;
    |     ^^^^^^^^^^^^^^^ help: use: `!(1..=33).contains(&x)`
 
 error: manual `!RangeInclusive::contains` implementation
-  --> $DIR/range_contains.rs:30:5
+  --> $DIR/range_contains.rs:32:5
    |
 LL |     999 < x || 1 > x;
    |     ^^^^^^^^^^^^^^^^ help: use: `!(1..=999).contains(&x)`
 
 error: manual `Range::contains` implementation
-  --> $DIR/range_contains.rs:45:5
+  --> $DIR/range_contains.rs:47:5
    |
 LL |     y >= 0. && y < 1.;
    |     ^^^^^^^^^^^^^^^^^ help: use: `(0. ..1.).contains(&y)`
 
 error: manual `!RangeInclusive::contains` implementation
-  --> $DIR/range_contains.rs:46:5
+  --> $DIR/range_contains.rs:48:5
    |
 LL |     y < 0. || y > 1.;
    |     ^^^^^^^^^^^^^^^^ help: use: `!(0. ..=1.).contains(&y)`
 
 error: manual `RangeInclusive::contains` implementation
-  --> $DIR/range_contains.rs:49:5
+  --> $DIR/range_contains.rs:51:5
    |
 LL |     x >= -10 && x <= 10;
    |     ^^^^^^^^^^^^^^^^^^^ help: use: `(-10..=10).contains(&x)`
 
 error: manual `RangeInclusive::contains` implementation
-  --> $DIR/range_contains.rs:51:5
+  --> $DIR/range_contains.rs:53:5
    |
 LL |     y >= -3. && y <= 3.;
    |     ^^^^^^^^^^^^^^^^^^^ help: use: `(-3. ..=3.).contains(&y)`
 
 error: manual `RangeInclusive::contains` implementation
-  --> $DIR/range_contains.rs:56:30
+  --> $DIR/range_contains.rs:58:30
    |
 LL |     (x >= 0) && (x <= 10) && (z >= 0) && (z <= 10);
    |                              ^^^^^^^^^^^^^^^^^^^^^ help: use: `(0..=10).contains(&z)`
 
 error: manual `RangeInclusive::contains` implementation
-  --> $DIR/range_contains.rs:56:5
+  --> $DIR/range_contains.rs:58:5
    |
 LL |     (x >= 0) && (x <= 10) && (z >= 0) && (z <= 10);
    |     ^^^^^^^^^^^^^^^^^^^^^ help: use: `(0..=10).contains(&x)`
 
 error: manual `!Range::contains` implementation
-  --> $DIR/range_contains.rs:57:29
+  --> $DIR/range_contains.rs:59:29
    |
 LL |     (x < 0) || (x >= 10) || (z < 0) || (z >= 10);
    |                             ^^^^^^^^^^^^^^^^^^^^ help: use: `!(0..10).contains(&z)`
 
 error: manual `!Range::contains` implementation
-  --> $DIR/range_contains.rs:57:5
+  --> $DIR/range_contains.rs:59:5
    |
 LL |     (x < 0) || (x >= 10) || (z < 0) || (z >= 10);
    |     ^^^^^^^^^^^^^^^^^^^^ help: use: `!(0..10).contains(&x)`
 
 error: manual `Range::contains` implementation
-  --> $DIR/range_contains.rs:76:5
+  --> $DIR/range_contains.rs:78:5
    |
 LL |     x >= 8 && x < 35;
    |     ^^^^^^^^^^^^^^^^ help: use: `(8..35).contains(&x)`
diff --git a/tests/ui/read_zero_byte_vec.rs b/tests/ui/read_zero_byte_vec.rs
index c6025ef1f4d..ff2ad8644b4 100644
--- a/tests/ui/read_zero_byte_vec.rs
+++ b/tests/ui/read_zero_byte_vec.rs
@@ -1,5 +1,9 @@
 #![warn(clippy::read_zero_byte_vec)]
-#![allow(clippy::unused_io_amount, clippy::needless_pass_by_ref_mut)]
+#![allow(
+    clippy::unused_io_amount,
+    clippy::needless_pass_by_ref_mut,
+    clippy::slow_vector_initialization
+)]
 use std::fs::File;
 use std::io;
 use std::io::prelude::*;
diff --git a/tests/ui/read_zero_byte_vec.stderr b/tests/ui/read_zero_byte_vec.stderr
index 08ba9753d7c..4c7f605f4c2 100644
--- a/tests/ui/read_zero_byte_vec.stderr
+++ b/tests/ui/read_zero_byte_vec.stderr
@@ -1,5 +1,5 @@
 error: reading zero byte data to `Vec`
-  --> $DIR/read_zero_byte_vec.rs:17:5
+  --> $DIR/read_zero_byte_vec.rs:21:5
    |
 LL |     f.read_exact(&mut data).unwrap();
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `data.resize(20, 0); f.read_exact(&mut data).unwrap();`
@@ -7,55 +7,55 @@ LL |     f.read_exact(&mut data).unwrap();
    = note: `-D clippy::read-zero-byte-vec` implied by `-D warnings`
 
 error: reading zero byte data to `Vec`
-  --> $DIR/read_zero_byte_vec.rs:21:5
+  --> $DIR/read_zero_byte_vec.rs:25:5
    |
 LL |     f.read_exact(&mut data2)?;
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `data2.resize(cap, 0); f.read_exact(&mut data2)?;`
 
 error: reading zero byte data to `Vec`
-  --> $DIR/read_zero_byte_vec.rs:25:5
+  --> $DIR/read_zero_byte_vec.rs:29:5
    |
 LL |     f.read_exact(&mut data3)?;
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: reading zero byte data to `Vec`
-  --> $DIR/read_zero_byte_vec.rs:29:5
+  --> $DIR/read_zero_byte_vec.rs:33:5
    |
 LL |     let _ = f.read(&mut data4)?;
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: reading zero byte data to `Vec`
-  --> $DIR/read_zero_byte_vec.rs:34:9
+  --> $DIR/read_zero_byte_vec.rs:38:9
    |
 LL |         f.read(&mut data5)
    |         ^^^^^^^^^^^^^^^^^^
 
 error: reading zero byte data to `Vec`
-  --> $DIR/read_zero_byte_vec.rs:40:9
+  --> $DIR/read_zero_byte_vec.rs:44:9
    |
 LL |         f.read(&mut data6)
    |         ^^^^^^^^^^^^^^^^^^
 
 error: reading zero byte data to `Vec`
-  --> $DIR/read_zero_byte_vec.rs:70:5
+  --> $DIR/read_zero_byte_vec.rs:74:5
    |
 LL |     r.read(&mut data).await.unwrap();
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: reading zero byte data to `Vec`
-  --> $DIR/read_zero_byte_vec.rs:74:5
+  --> $DIR/read_zero_byte_vec.rs:78:5
    |
 LL |     r.read_exact(&mut data2).await.unwrap();
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: reading zero byte data to `Vec`
-  --> $DIR/read_zero_byte_vec.rs:80:5
+  --> $DIR/read_zero_byte_vec.rs:84:5
    |
 LL |     r.read(&mut data).await.unwrap();
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: reading zero byte data to `Vec`
-  --> $DIR/read_zero_byte_vec.rs:84:5
+  --> $DIR/read_zero_byte_vec.rs:88:5
    |
 LL |     r.read_exact(&mut data2).await.unwrap();
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
diff --git a/tests/ui/readonly_write_lock.rs b/tests/ui/readonly_write_lock.rs
new file mode 100644
index 00000000000..656b45787e8
--- /dev/null
+++ b/tests/ui/readonly_write_lock.rs
@@ -0,0 +1,42 @@
+#![warn(clippy::readonly_write_lock)]
+
+use std::sync::RwLock;
+
+fn mutate_i32(x: &mut i32) {
+    *x += 1;
+}
+
+fn accept_i32(_: i32) {}
+
+fn main() {
+    let lock = RwLock::new(42);
+    let lock2 = RwLock::new(1234);
+
+    {
+        let writer = lock.write().unwrap();
+        dbg!(&writer);
+    }
+
+    {
+        let writer = lock.write().unwrap();
+        accept_i32(*writer);
+    }
+
+    {
+        let mut writer = lock.write().unwrap();
+        mutate_i32(&mut writer);
+        dbg!(&writer);
+    }
+
+    {
+        let mut writer = lock.write().unwrap();
+        *writer += 1;
+    }
+
+    {
+        let mut writer1 = lock.write().unwrap();
+        let mut writer2 = lock2.write().unwrap();
+        *writer2 += 1;
+        *writer1 = *writer2;
+    }
+}
diff --git a/tests/ui/readonly_write_lock.stderr b/tests/ui/readonly_write_lock.stderr
new file mode 100644
index 00000000000..e3d8fce7b2c
--- /dev/null
+++ b/tests/ui/readonly_write_lock.stderr
@@ -0,0 +1,16 @@
+error: this write lock is used only for reading
+  --> $DIR/readonly_write_lock.rs:16:22
+   |
+LL |         let writer = lock.write().unwrap();
+   |                      ^^^^^^^^^^^^ help: consider using a read lock instead: `lock.read()`
+   |
+   = note: `-D clippy::readonly-write-lock` implied by `-D warnings`
+
+error: this write lock is used only for reading
+  --> $DIR/readonly_write_lock.rs:21:22
+   |
+LL |         let writer = lock.write().unwrap();
+   |                      ^^^^^^^^^^^^ help: consider using a read lock instead: `lock.read()`
+
+error: aborting due to 2 previous errors
+
diff --git a/tests/ui/redundant_guards.fixed b/tests/ui/redundant_guards.fixed
new file mode 100644
index 00000000000..77ac7666864
--- /dev/null
+++ b/tests/ui/redundant_guards.fixed
@@ -0,0 +1,133 @@
+//@run-rustfix
+//@aux-build:proc_macros.rs:proc-macro
+#![feature(if_let_guard)]
+#![allow(clippy::no_effect, unused)]
+#![warn(clippy::redundant_guards)]
+
+#[macro_use]
+extern crate proc_macros;
+
+struct A(u32);
+
+struct B {
+    e: Option<A>,
+}
+
+struct C(u32, u32);
+
+fn main() {
+    let c = C(1, 2);
+    match c {
+        C(x, 1) => ..,
+        _ => todo!(),
+    };
+
+    let x = Some(Some(1));
+    match x {
+        Some(Some(1)) if true => ..,
+        Some(Some(1)) => {
+            println!("a");
+            ..
+        },
+        Some(Some(1)) => ..,
+        Some(Some(2)) => ..,
+        // Don't lint, since x is used in the body
+        Some(x) if let Some(1) = x => {
+            x;
+            ..
+        }
+        _ => todo!(),
+    };
+    let y = 1;
+    match x {
+        // Don't inline these, since y is not from the pat
+        Some(x) if matches!(y, 1 if true) => ..,
+        Some(x) if let 1 = y => ..,
+        Some(x) if y == 2 => ..,
+        _ => todo!(),
+    };
+    let a = A(1);
+    match a {
+        _ if a.0 == 1 => {},
+        _ => todo!(),
+    }
+    let b = B { e: Some(A(0)) };
+    match b {
+        B { e: Some(A(2)) } => ..,
+        _ => todo!(),
+    };
+    // Do not lint, since we cannot represent this as a pattern (at least, without a conversion)
+    let v = Some(vec![1u8, 2, 3]);
+    match v {
+        Some(x) if x == [1] => {},
+        _ => {},
+    }
+
+    external! {
+        let x = Some(Some(1));
+        match x {
+            Some(x) if let Some(1) = x => ..,
+            _ => todo!(),
+        };
+    }
+    with_span! {
+        span
+        let x = Some(Some(1));
+        match x {
+            Some(x) if let Some(1) = x => ..,
+            _ => todo!(),
+        };
+    }
+}
+
+enum E {
+    A(&'static str),
+    B(&'static str),
+    C(&'static str),
+}
+
+fn i() {
+    match E::A("") {
+        // Do not lint
+        E::A(x) | E::B(x) | E::C(x) if x == "from an or pattern" => {},
+        E::A("not from an or pattern") => {},
+        _ => {},
+    };
+}
+
+fn h(v: Option<u32>) {
+    match v {
+        Some(0) => ..,
+        _ => ..,
+    };
+}
+
+// Do not lint
+
+fn f(s: Option<std::ffi::OsString>) {
+    match s {
+        Some(x) if x == "a" => {},
+        _ => {},
+    }
+}
+
+struct S {
+    a: usize,
+}
+
+impl PartialEq for S {
+    fn eq(&self, _: &Self) -> bool {
+        true
+    }
+}
+
+impl Eq for S {}
+
+static CONST_S: S = S { a: 1 };
+
+fn g(opt_s: Option<S>) {
+    match opt_s {
+        Some(x) if x == CONST_S => {},
+        _ => {},
+    }
+}
diff --git a/tests/ui/redundant_guards.rs b/tests/ui/redundant_guards.rs
new file mode 100644
index 00000000000..b072e4ea14d
--- /dev/null
+++ b/tests/ui/redundant_guards.rs
@@ -0,0 +1,133 @@
+//@run-rustfix
+//@aux-build:proc_macros.rs:proc-macro
+#![feature(if_let_guard)]
+#![allow(clippy::no_effect, unused)]
+#![warn(clippy::redundant_guards)]
+
+#[macro_use]
+extern crate proc_macros;
+
+struct A(u32);
+
+struct B {
+    e: Option<A>,
+}
+
+struct C(u32, u32);
+
+fn main() {
+    let c = C(1, 2);
+    match c {
+        C(x, y) if let 1 = y => ..,
+        _ => todo!(),
+    };
+
+    let x = Some(Some(1));
+    match x {
+        Some(x) if matches!(x, Some(1) if true) => ..,
+        Some(x) if matches!(x, Some(1)) => {
+            println!("a");
+            ..
+        },
+        Some(x) if let Some(1) = x => ..,
+        Some(x) if x == Some(2) => ..,
+        // Don't lint, since x is used in the body
+        Some(x) if let Some(1) = x => {
+            x;
+            ..
+        }
+        _ => todo!(),
+    };
+    let y = 1;
+    match x {
+        // Don't inline these, since y is not from the pat
+        Some(x) if matches!(y, 1 if true) => ..,
+        Some(x) if let 1 = y => ..,
+        Some(x) if y == 2 => ..,
+        _ => todo!(),
+    };
+    let a = A(1);
+    match a {
+        _ if a.0 == 1 => {},
+        _ => todo!(),
+    }
+    let b = B { e: Some(A(0)) };
+    match b {
+        B { e } if matches!(e, Some(A(2))) => ..,
+        _ => todo!(),
+    };
+    // Do not lint, since we cannot represent this as a pattern (at least, without a conversion)
+    let v = Some(vec![1u8, 2, 3]);
+    match v {
+        Some(x) if x == [1] => {},
+        _ => {},
+    }
+
+    external! {
+        let x = Some(Some(1));
+        match x {
+            Some(x) if let Some(1) = x => ..,
+            _ => todo!(),
+        };
+    }
+    with_span! {
+        span
+        let x = Some(Some(1));
+        match x {
+            Some(x) if let Some(1) = x => ..,
+            _ => todo!(),
+        };
+    }
+}
+
+enum E {
+    A(&'static str),
+    B(&'static str),
+    C(&'static str),
+}
+
+fn i() {
+    match E::A("") {
+        // Do not lint
+        E::A(x) | E::B(x) | E::C(x) if x == "from an or pattern" => {},
+        E::A(y) if y == "not from an or pattern" => {},
+        _ => {},
+    };
+}
+
+fn h(v: Option<u32>) {
+    match v {
+        x if matches!(x, Some(0)) => ..,
+        _ => ..,
+    };
+}
+
+// Do not lint
+
+fn f(s: Option<std::ffi::OsString>) {
+    match s {
+        Some(x) if x == "a" => {},
+        _ => {},
+    }
+}
+
+struct S {
+    a: usize,
+}
+
+impl PartialEq for S {
+    fn eq(&self, _: &Self) -> bool {
+        true
+    }
+}
+
+impl Eq for S {}
+
+static CONST_S: S = S { a: 1 };
+
+fn g(opt_s: Option<S>) {
+    match opt_s {
+        Some(x) if x == CONST_S => {},
+        _ => {},
+    }
+}
diff --git a/tests/ui/redundant_guards.stderr b/tests/ui/redundant_guards.stderr
new file mode 100644
index 00000000000..c2a92071d1d
--- /dev/null
+++ b/tests/ui/redundant_guards.stderr
@@ -0,0 +1,98 @@
+error: redundant guard
+  --> $DIR/redundant_guards.rs:21:20
+   |
+LL |         C(x, y) if let 1 = y => ..,
+   |                    ^^^^^^^^^
+   |
+   = note: `-D clippy::redundant-guards` implied by `-D warnings`
+help: try
+   |
+LL -         C(x, y) if let 1 = y => ..,
+LL +         C(x, 1) => ..,
+   |
+
+error: redundant guard
+  --> $DIR/redundant_guards.rs:27:20
+   |
+LL |         Some(x) if matches!(x, Some(1) if true) => ..,
+   |                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: try
+   |
+LL |         Some(Some(1)) if true => ..,
+   |              ~~~~~~~  ~~~~~~~
+
+error: redundant guard
+  --> $DIR/redundant_guards.rs:28:20
+   |
+LL |         Some(x) if matches!(x, Some(1)) => {
+   |                    ^^^^^^^^^^^^^^^^^^^^
+   |
+help: try
+   |
+LL -         Some(x) if matches!(x, Some(1)) => {
+LL +         Some(Some(1)) => {
+   |
+
+error: redundant guard
+  --> $DIR/redundant_guards.rs:32:20
+   |
+LL |         Some(x) if let Some(1) = x => ..,
+   |                    ^^^^^^^^^^^^^^^
+   |
+help: try
+   |
+LL -         Some(x) if let Some(1) = x => ..,
+LL +         Some(Some(1)) => ..,
+   |
+
+error: redundant guard
+  --> $DIR/redundant_guards.rs:33:20
+   |
+LL |         Some(x) if x == Some(2) => ..,
+   |                    ^^^^^^^^^^^^
+   |
+help: try
+   |
+LL -         Some(x) if x == Some(2) => ..,
+LL +         Some(Some(2)) => ..,
+   |
+
+error: redundant guard
+  --> $DIR/redundant_guards.rs:56:20
+   |
+LL |         B { e } if matches!(e, Some(A(2))) => ..,
+   |                    ^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: try
+   |
+LL -         B { e } if matches!(e, Some(A(2))) => ..,
+LL +         B { e: Some(A(2)) } => ..,
+   |
+
+error: redundant guard
+  --> $DIR/redundant_guards.rs:93:20
+   |
+LL |         E::A(y) if y == "not from an or pattern" => {},
+   |                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: try
+   |
+LL -         E::A(y) if y == "not from an or pattern" => {},
+LL +         E::A("not from an or pattern") => {},
+   |
+
+error: redundant guard
+  --> $DIR/redundant_guards.rs:100:14
+   |
+LL |         x if matches!(x, Some(0)) => ..,
+   |              ^^^^^^^^^^^^^^^^^^^^
+   |
+help: try
+   |
+LL -         x if matches!(x, Some(0)) => ..,
+LL +         Some(0) => ..,
+   |
+
+error: aborting due to 8 previous errors
+
diff --git a/tests/ui/redundant_locals.rs b/tests/ui/redundant_locals.rs
new file mode 100644
index 00000000000..e74c78a50b6
--- /dev/null
+++ b/tests/ui/redundant_locals.rs
@@ -0,0 +1,111 @@
+//@aux-build:proc_macros.rs:proc-macro
+#![allow(unused, clippy::no_effect, clippy::needless_pass_by_ref_mut)]
+#![warn(clippy::redundant_locals)]
+
+extern crate proc_macros;
+use proc_macros::{external, with_span};
+
+fn main() {}
+
+fn immutable() {
+    let x = 1;
+    let x = x;
+}
+
+fn mutable() {
+    let mut x = 1;
+    let mut x = x;
+}
+
+fn upgraded_mutability() {
+    let x = 1;
+    let mut x = x;
+}
+
+fn downgraded_mutability() {
+    let mut x = 1;
+    let x = x;
+}
+
+fn coercion(par: &mut i32) {
+    let par: &i32 = par;
+
+    let x: &mut i32 = &mut 1;
+    let x: &i32 = x;
+}
+
+fn parameter(x: i32) {
+    let x = x;
+}
+
+fn many() {
+    let x = 1;
+    let x = x;
+    let x = x;
+    let x = x;
+    let x = x;
+}
+
+fn interleaved() {
+    let a = 1;
+    let b = 2;
+    let a = a;
+    let b = b;
+}
+
+fn block() {
+    {
+        let x = 1;
+        let x = x;
+    }
+}
+
+fn closure() {
+    || {
+        let x = 1;
+        let x = x;
+    };
+    |x: i32| {
+        let x = x;
+    };
+}
+
+fn consequential_drop_order() {
+    use std::sync::Mutex;
+
+    let mutex = Mutex::new(1);
+    let guard = mutex.lock().unwrap();
+
+    {
+        let guard = guard;
+    }
+}
+
+fn inconsequential_drop_order() {
+    let x = 1;
+
+    {
+        let x = x;
+    }
+}
+
+fn macros() {
+    macro_rules! rebind {
+        ($x:ident) => {
+            let $x = 1;
+            let $x = $x;
+        };
+    }
+
+    rebind!(x);
+
+    external! {
+        let x = 1;
+        let x = x;
+    }
+    with_span! {
+        span
+        let x = 1;
+        let x = x;
+    }
+}
diff --git a/tests/ui/redundant_locals.stderr b/tests/ui/redundant_locals.stderr
new file mode 100644
index 00000000000..df07dd2f453
--- /dev/null
+++ b/tests/ui/redundant_locals.stderr
@@ -0,0 +1,136 @@
+error: redundant redefinition of a binding
+  --> $DIR/redundant_locals.rs:11:9
+   |
+LL |     let x = 1;
+   |         ^
+LL |     let x = x;
+   |     ^^^^^^^^^^
+   |
+   = help: remove the redefinition of `x`
+   = note: `-D clippy::redundant-locals` implied by `-D warnings`
+
+error: redundant redefinition of a binding
+  --> $DIR/redundant_locals.rs:16:9
+   |
+LL |     let mut x = 1;
+   |         ^^^^^
+LL |     let mut x = x;
+   |     ^^^^^^^^^^^^^^
+   |
+   = help: remove the redefinition of `x`
+
+error: redundant redefinition of a binding
+  --> $DIR/redundant_locals.rs:37:14
+   |
+LL | fn parameter(x: i32) {
+   |              ^
+LL |     let x = x;
+   |     ^^^^^^^^^^
+   |
+   = help: remove the redefinition of `x`
+
+error: redundant redefinition of a binding
+  --> $DIR/redundant_locals.rs:42:9
+   |
+LL |     let x = 1;
+   |         ^
+LL |     let x = x;
+   |     ^^^^^^^^^^
+   |
+   = help: remove the redefinition of `x`
+
+error: redundant redefinition of a binding
+  --> $DIR/redundant_locals.rs:43:9
+   |
+LL |     let x = x;
+   |         ^
+LL |     let x = x;
+   |     ^^^^^^^^^^
+   |
+   = help: remove the redefinition of `x`
+
+error: redundant redefinition of a binding
+  --> $DIR/redundant_locals.rs:44:9
+   |
+LL |     let x = x;
+   |         ^
+LL |     let x = x;
+   |     ^^^^^^^^^^
+   |
+   = help: remove the redefinition of `x`
+
+error: redundant redefinition of a binding
+  --> $DIR/redundant_locals.rs:45:9
+   |
+LL |     let x = x;
+   |         ^
+LL |     let x = x;
+   |     ^^^^^^^^^^
+   |
+   = help: remove the redefinition of `x`
+
+error: redundant redefinition of a binding
+  --> $DIR/redundant_locals.rs:50:9
+   |
+LL |     let a = 1;
+   |         ^
+LL |     let b = 2;
+LL |     let a = a;
+   |     ^^^^^^^^^^
+   |
+   = help: remove the redefinition of `a`
+
+error: redundant redefinition of a binding
+  --> $DIR/redundant_locals.rs:51:9
+   |
+LL |     let b = 2;
+   |         ^
+LL |     let a = a;
+LL |     let b = b;
+   |     ^^^^^^^^^^
+   |
+   = help: remove the redefinition of `b`
+
+error: redundant redefinition of a binding
+  --> $DIR/redundant_locals.rs:58:13
+   |
+LL |         let x = 1;
+   |             ^
+LL |         let x = x;
+   |         ^^^^^^^^^^
+   |
+   = help: remove the redefinition of `x`
+
+error: redundant redefinition of a binding
+  --> $DIR/redundant_locals.rs:65:13
+   |
+LL |         let x = 1;
+   |             ^
+LL |         let x = x;
+   |         ^^^^^^^^^^
+   |
+   = help: remove the redefinition of `x`
+
+error: redundant redefinition of a binding
+  --> $DIR/redundant_locals.rs:68:6
+   |
+LL |     |x: i32| {
+   |      ^
+LL |         let x = x;
+   |         ^^^^^^^^^^
+   |
+   = help: remove the redefinition of `x`
+
+error: redundant redefinition of a binding
+  --> $DIR/redundant_locals.rs:85:9
+   |
+LL |     let x = 1;
+   |         ^
+...
+LL |         let x = x;
+   |         ^^^^^^^^^^
+   |
+   = help: remove the redefinition of `x`
+
+error: aborting due to 13 previous errors
+
diff --git a/tests/ui/rename.fixed b/tests/ui/rename.fixed
index cab02bb93c9..6936d526aeb 100644
--- a/tests/ui/rename.fixed
+++ b/tests/ui/rename.fixed
@@ -27,6 +27,7 @@
 #![allow(clippy::single_char_add_str)]
 #![allow(clippy::module_name_repetitions)]
 #![allow(clippy::recursive_format_impl)]
+#![allow(clippy::unwrap_or_default)]
 #![allow(clippy::invisible_characters)]
 #![allow(cast_ref_to_mut)]
 #![allow(suspicious_double_ref_op)]
@@ -78,6 +79,7 @@
 #![warn(clippy::single_char_add_str)]
 #![warn(clippy::module_name_repetitions)]
 #![warn(clippy::recursive_format_impl)]
+#![warn(clippy::unwrap_or_default)]
 #![warn(clippy::invisible_characters)]
 #![warn(cast_ref_to_mut)]
 #![warn(suspicious_double_ref_op)]
diff --git a/tests/ui/rename.rs b/tests/ui/rename.rs
index e5e31452149..626e5202025 100644
--- a/tests/ui/rename.rs
+++ b/tests/ui/rename.rs
@@ -27,6 +27,7 @@
 #![allow(clippy::single_char_add_str)]
 #![allow(clippy::module_name_repetitions)]
 #![allow(clippy::recursive_format_impl)]
+#![allow(clippy::unwrap_or_default)]
 #![allow(clippy::invisible_characters)]
 #![allow(cast_ref_to_mut)]
 #![allow(suspicious_double_ref_op)]
@@ -78,6 +79,7 @@
 #![warn(clippy::single_char_push_str)]
 #![warn(clippy::stutter)]
 #![warn(clippy::to_string_in_display)]
+#![warn(clippy::unwrap_or_else_default)]
 #![warn(clippy::zero_width_space)]
 #![warn(clippy::cast_ref_to_mut)]
 #![warn(clippy::clone_double_ref)]
diff --git a/tests/ui/rename.stderr b/tests/ui/rename.stderr
index 783608a0841..a0e0a66892e 100644
--- a/tests/ui/rename.stderr
+++ b/tests/ui/rename.stderr
@@ -1,5 +1,5 @@
 error: lint `clippy::almost_complete_letter_range` has been renamed to `clippy::almost_complete_range`
-  --> $DIR/rename.rs:53:9
+  --> $DIR/rename.rs:54:9
    |
 LL | #![warn(clippy::almost_complete_letter_range)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::almost_complete_range`
@@ -7,316 +7,322 @@ LL | #![warn(clippy::almost_complete_letter_range)]
    = note: `-D renamed-and-removed-lints` implied by `-D warnings`
 
 error: lint `clippy::blacklisted_name` has been renamed to `clippy::disallowed_names`
-  --> $DIR/rename.rs:54:9
+  --> $DIR/rename.rs:55:9
    |
 LL | #![warn(clippy::blacklisted_name)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::disallowed_names`
 
 error: lint `clippy::block_in_if_condition_expr` has been renamed to `clippy::blocks_in_if_conditions`
-  --> $DIR/rename.rs:55:9
+  --> $DIR/rename.rs:56:9
    |
 LL | #![warn(clippy::block_in_if_condition_expr)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::blocks_in_if_conditions`
 
 error: lint `clippy::block_in_if_condition_stmt` has been renamed to `clippy::blocks_in_if_conditions`
-  --> $DIR/rename.rs:56:9
+  --> $DIR/rename.rs:57: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:57:9
+  --> $DIR/rename.rs:58: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:58:9
+  --> $DIR/rename.rs:59: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:59:9
+  --> $DIR/rename.rs:60:9
    |
 LL | #![warn(clippy::cyclomatic_complexity)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::cognitive_complexity`
 
 error: lint `clippy::derive_hash_xor_eq` has been renamed to `clippy::derived_hash_with_manual_eq`
-  --> $DIR/rename.rs:60:9
+  --> $DIR/rename.rs:61:9
    |
 LL | #![warn(clippy::derive_hash_xor_eq)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::derived_hash_with_manual_eq`
 
 error: lint `clippy::disallowed_method` has been renamed to `clippy::disallowed_methods`
-  --> $DIR/rename.rs:61:9
+  --> $DIR/rename.rs:62: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:62:9
+  --> $DIR/rename.rs:63: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:63:9
+  --> $DIR/rename.rs:64:9
    |
 LL | #![warn(clippy::eval_order_dependence)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::mixed_read_write_in_expression`
 
 error: lint `clippy::identity_conversion` has been renamed to `clippy::useless_conversion`
-  --> $DIR/rename.rs:64:9
+  --> $DIR/rename.rs:65: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:65:9
+  --> $DIR/rename.rs:66:9
    |
 LL | #![warn(clippy::if_let_some_result)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::match_result_ok`
 
 error: lint `clippy::integer_arithmetic` has been renamed to `clippy::arithmetic_side_effects`
-  --> $DIR/rename.rs:66:9
+  --> $DIR/rename.rs:67:9
    |
 LL | #![warn(clippy::integer_arithmetic)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::arithmetic_side_effects`
 
 error: lint `clippy::logic_bug` has been renamed to `clippy::overly_complex_bool_expr`
-  --> $DIR/rename.rs:67:9
+  --> $DIR/rename.rs:68:9
    |
 LL | #![warn(clippy::logic_bug)]
    |         ^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::overly_complex_bool_expr`
 
 error: lint `clippy::new_without_default_derive` has been renamed to `clippy::new_without_default`
-  --> $DIR/rename.rs:68:9
+  --> $DIR/rename.rs:69: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:69:9
+  --> $DIR/rename.rs:70: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:70:9
+  --> $DIR/rename.rs:71: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:71:9
+  --> $DIR/rename.rs:72: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:72:9
+  --> $DIR/rename.rs:73: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:73:9
+  --> $DIR/rename.rs:74: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:74:9
+  --> $DIR/rename.rs:75: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:75:9
+  --> $DIR/rename.rs:76: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:76:9
+  --> $DIR/rename.rs:77: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:77:9
+  --> $DIR/rename.rs:78: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:78:9
+  --> $DIR/rename.rs:79: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:79:9
+  --> $DIR/rename.rs:80: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:80:9
+  --> $DIR/rename.rs:81:9
    |
 LL | #![warn(clippy::to_string_in_display)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::recursive_format_impl`
 
+error: lint `clippy::unwrap_or_else_default` has been renamed to `clippy::unwrap_or_default`
+  --> $DIR/rename.rs:82:9
+   |
+LL | #![warn(clippy::unwrap_or_else_default)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::unwrap_or_default`
+
 error: lint `clippy::zero_width_space` has been renamed to `clippy::invisible_characters`
-  --> $DIR/rename.rs:81:9
+  --> $DIR/rename.rs:83:9
    |
 LL | #![warn(clippy::zero_width_space)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::invisible_characters`
 
 error: lint `clippy::cast_ref_to_mut` has been renamed to `cast_ref_to_mut`
-  --> $DIR/rename.rs:82:9
+  --> $DIR/rename.rs:84:9
    |
 LL | #![warn(clippy::cast_ref_to_mut)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `cast_ref_to_mut`
 
 error: lint `clippy::clone_double_ref` has been renamed to `suspicious_double_ref_op`
-  --> $DIR/rename.rs:83:9
+  --> $DIR/rename.rs:85:9
    |
 LL | #![warn(clippy::clone_double_ref)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `suspicious_double_ref_op`
 
 error: lint `clippy::cmp_nan` has been renamed to `invalid_nan_comparisons`
-  --> $DIR/rename.rs:84:9
+  --> $DIR/rename.rs:86:9
    |
 LL | #![warn(clippy::cmp_nan)]
    |         ^^^^^^^^^^^^^^^ help: use the new name: `invalid_nan_comparisons`
 
 error: lint `clippy::drop_bounds` has been renamed to `drop_bounds`
-  --> $DIR/rename.rs:85:9
+  --> $DIR/rename.rs:87:9
    |
 LL | #![warn(clippy::drop_bounds)]
    |         ^^^^^^^^^^^^^^^^^^^ help: use the new name: `drop_bounds`
 
 error: lint `clippy::drop_copy` has been renamed to `dropping_copy_types`
-  --> $DIR/rename.rs:86:9
+  --> $DIR/rename.rs:88:9
    |
 LL | #![warn(clippy::drop_copy)]
    |         ^^^^^^^^^^^^^^^^^ help: use the new name: `dropping_copy_types`
 
 error: lint `clippy::drop_ref` has been renamed to `dropping_references`
-  --> $DIR/rename.rs:87:9
+  --> $DIR/rename.rs:89:9
    |
 LL | #![warn(clippy::drop_ref)]
    |         ^^^^^^^^^^^^^^^^ help: use the new name: `dropping_references`
 
 error: lint `clippy::for_loop_over_option` has been renamed to `for_loops_over_fallibles`
-  --> $DIR/rename.rs:88:9
+  --> $DIR/rename.rs:90:9
    |
 LL | #![warn(clippy::for_loop_over_option)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `for_loops_over_fallibles`
 
 error: lint `clippy::for_loop_over_result` has been renamed to `for_loops_over_fallibles`
-  --> $DIR/rename.rs:89:9
+  --> $DIR/rename.rs:91:9
    |
 LL | #![warn(clippy::for_loop_over_result)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `for_loops_over_fallibles`
 
 error: lint `clippy::for_loops_over_fallibles` has been renamed to `for_loops_over_fallibles`
-  --> $DIR/rename.rs:90:9
+  --> $DIR/rename.rs:92:9
    |
 LL | #![warn(clippy::for_loops_over_fallibles)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `for_loops_over_fallibles`
 
 error: lint `clippy::forget_copy` has been renamed to `forgetting_copy_types`
-  --> $DIR/rename.rs:91:9
+  --> $DIR/rename.rs:93:9
    |
 LL | #![warn(clippy::forget_copy)]
    |         ^^^^^^^^^^^^^^^^^^^ help: use the new name: `forgetting_copy_types`
 
 error: lint `clippy::forget_ref` has been renamed to `forgetting_references`
-  --> $DIR/rename.rs:92:9
+  --> $DIR/rename.rs:94:9
    |
 LL | #![warn(clippy::forget_ref)]
    |         ^^^^^^^^^^^^^^^^^^ help: use the new name: `forgetting_references`
 
 error: lint `clippy::fn_null_check` has been renamed to `incorrect_fn_null_checks`
-  --> $DIR/rename.rs:93:9
+  --> $DIR/rename.rs:95:9
    |
 LL | #![warn(clippy::fn_null_check)]
    |         ^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `incorrect_fn_null_checks`
 
 error: lint `clippy::into_iter_on_array` has been renamed to `array_into_iter`
-  --> $DIR/rename.rs:94:9
+  --> $DIR/rename.rs:96: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:95:9
+  --> $DIR/rename.rs:97: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:96:9
+  --> $DIR/rename.rs:98:9
    |
 LL | #![warn(clippy::invalid_ref)]
    |         ^^^^^^^^^^^^^^^^^^^ help: use the new name: `invalid_value`
 
 error: lint `clippy::invalid_utf8_in_unchecked` has been renamed to `invalid_from_utf8_unchecked`
-  --> $DIR/rename.rs:97:9
+  --> $DIR/rename.rs:99:9
    |
 LL | #![warn(clippy::invalid_utf8_in_unchecked)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `invalid_from_utf8_unchecked`
 
 error: lint `clippy::let_underscore_drop` has been renamed to `let_underscore_drop`
-  --> $DIR/rename.rs:98:9
+  --> $DIR/rename.rs:100:9
    |
 LL | #![warn(clippy::let_underscore_drop)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `let_underscore_drop`
 
 error: lint `clippy::mem_discriminant_non_enum` has been renamed to `enum_intrinsics_non_enums`
-  --> $DIR/rename.rs:99:9
+  --> $DIR/rename.rs:101: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:100:9
+  --> $DIR/rename.rs:102:9
    |
 LL | #![warn(clippy::panic_params)]
    |         ^^^^^^^^^^^^^^^^^^^^ help: use the new name: `non_fmt_panics`
 
 error: lint `clippy::positional_named_format_parameters` has been renamed to `named_arguments_used_positionally`
-  --> $DIR/rename.rs:101:9
+  --> $DIR/rename.rs:103:9
    |
 LL | #![warn(clippy::positional_named_format_parameters)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `named_arguments_used_positionally`
 
 error: lint `clippy::temporary_cstring_as_ptr` has been renamed to `temporary_cstring_as_ptr`
-  --> $DIR/rename.rs:102:9
+  --> $DIR/rename.rs:104:9
    |
 LL | #![warn(clippy::temporary_cstring_as_ptr)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `temporary_cstring_as_ptr`
 
 error: lint `clippy::undropped_manually_drops` has been renamed to `undropped_manually_drops`
-  --> $DIR/rename.rs:103:9
+  --> $DIR/rename.rs:105:9
    |
 LL | #![warn(clippy::undropped_manually_drops)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `undropped_manually_drops`
 
 error: lint `clippy::unknown_clippy_lints` has been renamed to `unknown_lints`
-  --> $DIR/rename.rs:104:9
+  --> $DIR/rename.rs:106: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:105:9
+  --> $DIR/rename.rs:107:9
    |
 LL | #![warn(clippy::unused_label)]
    |         ^^^^^^^^^^^^^^^^^^^^ help: use the new name: `unused_labels`
 
-error: aborting due to 53 previous errors
+error: aborting due to 54 previous errors
 
diff --git a/tests/ui/self_assignment.rs b/tests/ui/self_assignment.rs
index d6682cc63dc..a7f9fbaae7c 100644
--- a/tests/ui/self_assignment.rs
+++ b/tests/ui/self_assignment.rs
@@ -14,7 +14,7 @@ pub fn positives(mut a: usize, b: &mut u32, mut s: S) {
     *b = *b;
     s = s;
     s.a = s.a;
-    s.b[10] = s.b[5 + 5];
+    s.b[9] = s.b[5 + 4];
     s.c[0][1] = s.c[0][1];
     s.b[a] = s.b[a];
     *s.e = *s.e;
diff --git a/tests/ui/self_assignment.stderr b/tests/ui/self_assignment.stderr
index bed88244eea..25b8569fa3d 100644
--- a/tests/ui/self_assignment.stderr
+++ b/tests/ui/self_assignment.stderr
@@ -24,11 +24,11 @@ error: self-assignment of `s.a` to `s.a`
 LL |     s.a = s.a;
    |     ^^^^^^^^^
 
-error: self-assignment of `s.b[5 + 5]` to `s.b[10]`
+error: self-assignment of `s.b[5 + 4]` to `s.b[9]`
   --> $DIR/self_assignment.rs:17:5
    |
-LL |     s.b[10] = s.b[5 + 5];
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     s.b[9] = s.b[5 + 4];
+   |     ^^^^^^^^^^^^^^^^^^^
 
 error: self-assignment of `s.c[0][1]` to `s.c[0][1]`
   --> $DIR/self_assignment.rs:18:5
diff --git a/tests/ui/shadow.rs b/tests/ui/shadow.rs
index 9be8c5e59d0..1b40a43d019 100644
--- a/tests/ui/shadow.rs
+++ b/tests/ui/shadow.rs
@@ -1,7 +1,12 @@
 //@aux-build:proc_macro_derive.rs:proc-macro
 
 #![warn(clippy::shadow_same, clippy::shadow_reuse, clippy::shadow_unrelated)]
-#![allow(clippy::let_unit_value, clippy::needless_if)]
+#![allow(
+    clippy::let_unit_value,
+    clippy::needless_if,
+    clippy::redundant_guards,
+    clippy::redundant_locals
+)]
 
 extern crate proc_macro_derive;
 
diff --git a/tests/ui/shadow.stderr b/tests/ui/shadow.stderr
index 8321f6df224..88b02f53be1 100644
--- a/tests/ui/shadow.stderr
+++ b/tests/ui/shadow.stderr
@@ -1,278 +1,278 @@
 error: `x` is shadowed by itself in `x`
-  --> $DIR/shadow.rs:19:9
+  --> $DIR/shadow.rs:24:9
    |
 LL |     let x = x;
    |         ^
    |
 note: previous binding is here
-  --> $DIR/shadow.rs:18:9
+  --> $DIR/shadow.rs:23:9
    |
 LL |     let x = 1;
    |         ^
    = note: `-D clippy::shadow-same` implied by `-D warnings`
 
 error: `mut x` is shadowed by itself in `&x`
-  --> $DIR/shadow.rs:20:13
+  --> $DIR/shadow.rs:25:13
    |
 LL |     let mut x = &x;
    |             ^
    |
 note: previous binding is here
-  --> $DIR/shadow.rs:19:9
+  --> $DIR/shadow.rs:24:9
    |
 LL |     let x = x;
    |         ^
 
 error: `x` is shadowed by itself in `&mut x`
-  --> $DIR/shadow.rs:21:9
+  --> $DIR/shadow.rs:26:9
    |
 LL |     let x = &mut x;
    |         ^
    |
 note: previous binding is here
-  --> $DIR/shadow.rs:20:9
+  --> $DIR/shadow.rs:25:9
    |
 LL |     let mut x = &x;
    |         ^^^^^
 
 error: `x` is shadowed by itself in `*x`
-  --> $DIR/shadow.rs:22:9
+  --> $DIR/shadow.rs:27:9
    |
 LL |     let x = *x;
    |         ^
    |
 note: previous binding is here
-  --> $DIR/shadow.rs:21:9
+  --> $DIR/shadow.rs:26:9
    |
 LL |     let x = &mut x;
    |         ^
 
 error: `x` is shadowed
-  --> $DIR/shadow.rs:27:9
+  --> $DIR/shadow.rs:32:9
    |
 LL |     let x = x.0;
    |         ^
    |
 note: previous binding is here
-  --> $DIR/shadow.rs:26:9
+  --> $DIR/shadow.rs:31:9
    |
 LL |     let x = ([[0]], ());
    |         ^
    = note: `-D clippy::shadow-reuse` implied by `-D warnings`
 
 error: `x` is shadowed
-  --> $DIR/shadow.rs:28:9
+  --> $DIR/shadow.rs:33:9
    |
 LL |     let x = x[0];
    |         ^
    |
 note: previous binding is here
-  --> $DIR/shadow.rs:27:9
+  --> $DIR/shadow.rs:32:9
    |
 LL |     let x = x.0;
    |         ^
 
 error: `x` is shadowed
-  --> $DIR/shadow.rs:29:10
+  --> $DIR/shadow.rs:34:10
    |
 LL |     let [x] = x;
    |          ^
    |
 note: previous binding is here
-  --> $DIR/shadow.rs:28:9
+  --> $DIR/shadow.rs:33:9
    |
 LL |     let x = x[0];
    |         ^
 
 error: `x` is shadowed
-  --> $DIR/shadow.rs:30:9
+  --> $DIR/shadow.rs:35:9
    |
 LL |     let x = Some(x);
    |         ^
    |
 note: previous binding is here
-  --> $DIR/shadow.rs:29:10
+  --> $DIR/shadow.rs:34:10
    |
 LL |     let [x] = x;
    |          ^
 
 error: `x` is shadowed
-  --> $DIR/shadow.rs:31:9
+  --> $DIR/shadow.rs:36:9
    |
 LL |     let x = foo(x);
    |         ^
    |
 note: previous binding is here
-  --> $DIR/shadow.rs:30:9
+  --> $DIR/shadow.rs:35:9
    |
 LL |     let x = Some(x);
    |         ^
 
 error: `x` is shadowed
-  --> $DIR/shadow.rs:32:9
+  --> $DIR/shadow.rs:37:9
    |
 LL |     let x = || x;
    |         ^
    |
 note: previous binding is here
-  --> $DIR/shadow.rs:31:9
+  --> $DIR/shadow.rs:36:9
    |
 LL |     let x = foo(x);
    |         ^
 
 error: `x` is shadowed
-  --> $DIR/shadow.rs:33:9
+  --> $DIR/shadow.rs:38:9
    |
 LL |     let x = Some(1).map(|_| x)?;
    |         ^
    |
 note: previous binding is here
-  --> $DIR/shadow.rs:32:9
+  --> $DIR/shadow.rs:37:9
    |
 LL |     let x = || x;
    |         ^
 
 error: `y` is shadowed
-  --> $DIR/shadow.rs:35:9
+  --> $DIR/shadow.rs:40:9
    |
 LL |     let y = match y {
    |         ^
    |
 note: previous binding is here
-  --> $DIR/shadow.rs:34:9
+  --> $DIR/shadow.rs:39:9
    |
 LL |     let y = 1;
    |         ^
 
 error: `x` shadows a previous, unrelated binding
-  --> $DIR/shadow.rs:50:9
+  --> $DIR/shadow.rs:55:9
    |
 LL |     let x = 2;
    |         ^
    |
 note: previous binding is here
-  --> $DIR/shadow.rs:49:9
+  --> $DIR/shadow.rs:54:9
    |
 LL |     let x = 1;
    |         ^
    = note: `-D clippy::shadow-unrelated` implied by `-D warnings`
 
 error: `x` shadows a previous, unrelated binding
-  --> $DIR/shadow.rs:55:13
+  --> $DIR/shadow.rs:60:13
    |
 LL |         let x = 1;
    |             ^
    |
 note: previous binding is here
-  --> $DIR/shadow.rs:54:10
+  --> $DIR/shadow.rs:59:10
    |
 LL |     fn f(x: u32) {
    |          ^
 
 error: `x` shadows a previous, unrelated binding
-  --> $DIR/shadow.rs:60:14
+  --> $DIR/shadow.rs:65:14
    |
 LL |         Some(x) => {
    |              ^
    |
 note: previous binding is here
-  --> $DIR/shadow.rs:57:9
+  --> $DIR/shadow.rs:62:9
    |
 LL |     let x = 1;
    |         ^
 
 error: `x` shadows a previous, unrelated binding
-  --> $DIR/shadow.rs:61:17
+  --> $DIR/shadow.rs:66:17
    |
 LL |             let x = 1;
    |                 ^
    |
 note: previous binding is here
-  --> $DIR/shadow.rs:60:14
+  --> $DIR/shadow.rs:65:14
    |
 LL |         Some(x) => {
    |              ^
 
 error: `x` shadows a previous, unrelated binding
-  --> $DIR/shadow.rs:65:17
+  --> $DIR/shadow.rs:70:17
    |
 LL |     if let Some(x) = Some(1) {}
    |                 ^
    |
 note: previous binding is here
-  --> $DIR/shadow.rs:57:9
+  --> $DIR/shadow.rs:62:9
    |
 LL |     let x = 1;
    |         ^
 
 error: `x` shadows a previous, unrelated binding
-  --> $DIR/shadow.rs:66:20
+  --> $DIR/shadow.rs:71:20
    |
 LL |     while let Some(x) = Some(1) {}
    |                    ^
    |
 note: previous binding is here
-  --> $DIR/shadow.rs:57:9
+  --> $DIR/shadow.rs:62:9
    |
 LL |     let x = 1;
    |         ^
 
 error: `x` shadows a previous, unrelated binding
-  --> $DIR/shadow.rs:67:15
+  --> $DIR/shadow.rs:72:15
    |
 LL |     let _ = |[x]: [u32; 1]| {
    |               ^
    |
 note: previous binding is here
-  --> $DIR/shadow.rs:57:9
+  --> $DIR/shadow.rs:62:9
    |
 LL |     let x = 1;
    |         ^
 
 error: `x` shadows a previous, unrelated binding
-  --> $DIR/shadow.rs:68:13
+  --> $DIR/shadow.rs:73:13
    |
 LL |         let x = 1;
    |             ^
    |
 note: previous binding is here
-  --> $DIR/shadow.rs:67:15
+  --> $DIR/shadow.rs:72:15
    |
 LL |     let _ = |[x]: [u32; 1]| {
    |               ^
 
 error: `y` is shadowed
-  --> $DIR/shadow.rs:71:17
+  --> $DIR/shadow.rs:76:17
    |
 LL |     if let Some(y) = y {}
    |                 ^
    |
 note: previous binding is here
-  --> $DIR/shadow.rs:70:9
+  --> $DIR/shadow.rs:75:9
    |
 LL |     let y = Some(1);
    |         ^
 
 error: `_b` shadows a previous, unrelated binding
-  --> $DIR/shadow.rs:107:9
+  --> $DIR/shadow.rs:112:9
    |
 LL |     let _b = _a;
    |         ^^
    |
 note: previous binding is here
-  --> $DIR/shadow.rs:106:28
+  --> $DIR/shadow.rs:111:28
    |
 LL | pub async fn foo2(_a: i32, _b: i64) {
    |                            ^^
 
 error: `x` shadows a previous, unrelated binding
-  --> $DIR/shadow.rs:113:21
+  --> $DIR/shadow.rs:118:21
    |
 LL |         if let Some(x) = Some(1) { x } else { 1 }
    |                     ^
    |
 note: previous binding is here
-  --> $DIR/shadow.rs:112:13
+  --> $DIR/shadow.rs:117:13
    |
 LL |         let x = 1;
    |             ^
diff --git a/tests/ui/should_impl_trait/method_list_2.stderr b/tests/ui/should_impl_trait/method_list_2.stderr
index 2ae9fa34d14..a3bb05bf176 100644
--- a/tests/ui/should_impl_trait/method_list_2.stderr
+++ b/tests/ui/should_impl_trait/method_list_2.stderr
@@ -39,15 +39,6 @@ LL | |     }
    |
    = help: consider implementing the trait `std::hash::Hash` or choosing a less ambiguous method name
 
-error: this argument is a mutable reference, but not used mutably
-  --> $DIR/method_list_2.rs:38:31
-   |
-LL |     pub fn hash(&self, state: &mut T) {
-   |                               ^^^^^^ help: consider changing to: `&T`
-   |
-   = warning: changing this function will impact semver compatibility
-   = note: `-D clippy::needless-pass-by-ref-mut` implied by `-D warnings`
-
 error: method `index` can be confused for the standard trait method `std::ops::Index::index`
   --> $DIR/method_list_2.rs:42:5
    |
@@ -158,5 +149,14 @@ LL | |     }
    |
    = help: consider implementing the trait `std::ops::Sub` or choosing a less ambiguous method name
 
+error: this argument is a mutable reference, but not used mutably
+  --> $DIR/method_list_2.rs:38:31
+   |
+LL |     pub fn hash(&self, state: &mut T) {
+   |                               ^^^^^^ help: consider changing to: `&T`
+   |
+   = warning: changing this function will impact semver compatibility
+   = note: `-D clippy::needless-pass-by-ref-mut` implied by `-D warnings`
+
 error: aborting due to 16 previous errors
 
diff --git a/tests/ui/significant_drop_tightening.fixed b/tests/ui/significant_drop_tightening.fixed
index eb8524167c4..8065e9e5fbc 100644
--- a/tests/ui/significant_drop_tightening.fixed
+++ b/tests/ui/significant_drop_tightening.fixed
@@ -51,6 +51,33 @@ pub fn issue_11128() {
     }
 }
 
+pub fn issue_11160() -> bool {
+    let mutex = Mutex::new(1i32);
+    let lock = mutex.lock().unwrap();
+    let _ = lock.abs();
+    true
+}
+
+pub fn issue_11189() {
+    struct Number {
+        pub value: u32,
+    }
+
+    fn do_something() -> Result<(), ()> {
+        let number = Mutex::new(Number { value: 1 });
+        let number2 = Mutex::new(Number { value: 2 });
+        let number3 = Mutex::new(Number { value: 3 });
+        let mut lock = number.lock().unwrap();
+        let mut lock2 = number2.lock().unwrap();
+        let mut lock3 = number3.lock().unwrap();
+        lock.value += 1;
+        lock2.value += 1;
+        lock3.value += 1;
+        drop((lock, lock2, lock3));
+        Ok(())
+    }
+}
+
 pub fn path_return_can_be_ignored() -> i32 {
     let mutex = Mutex::new(1);
     let lock = mutex.lock().unwrap();
diff --git a/tests/ui/significant_drop_tightening.rs b/tests/ui/significant_drop_tightening.rs
index f7fa65ea922..1620b76843a 100644
--- a/tests/ui/significant_drop_tightening.rs
+++ b/tests/ui/significant_drop_tightening.rs
@@ -50,6 +50,33 @@ pub fn issue_11128() {
     }
 }
 
+pub fn issue_11160() -> bool {
+    let mutex = Mutex::new(1i32);
+    let lock = mutex.lock().unwrap();
+    let _ = lock.abs();
+    true
+}
+
+pub fn issue_11189() {
+    struct Number {
+        pub value: u32,
+    }
+
+    fn do_something() -> Result<(), ()> {
+        let number = Mutex::new(Number { value: 1 });
+        let number2 = Mutex::new(Number { value: 2 });
+        let number3 = Mutex::new(Number { value: 3 });
+        let mut lock = number.lock().unwrap();
+        let mut lock2 = number2.lock().unwrap();
+        let mut lock3 = number3.lock().unwrap();
+        lock.value += 1;
+        lock2.value += 1;
+        lock3.value += 1;
+        drop((lock, lock2, lock3));
+        Ok(())
+    }
+}
+
 pub fn path_return_can_be_ignored() -> i32 {
     let mutex = Mutex::new(1);
     let lock = mutex.lock().unwrap();
diff --git a/tests/ui/significant_drop_tightening.stderr b/tests/ui/significant_drop_tightening.stderr
index ca4fede17c9..b5cad88ad3f 100644
--- a/tests/ui/significant_drop_tightening.stderr
+++ b/tests/ui/significant_drop_tightening.stderr
@@ -23,7 +23,7 @@ LL +     drop(lock);
    |
 
 error: temporary with significant `Drop` can be early dropped
-  --> $DIR/significant_drop_tightening.rs:79:13
+  --> $DIR/significant_drop_tightening.rs:106:13
    |
 LL | /     {
 LL | |         let mutex = Mutex::new(1i32);
@@ -43,7 +43,7 @@ LL +         drop(lock);
    |
 
 error: temporary with significant `Drop` can be early dropped
-  --> $DIR/significant_drop_tightening.rs:100:13
+  --> $DIR/significant_drop_tightening.rs:127:13
    |
 LL | /     {
 LL | |         let mutex = Mutex::new(1i32);
@@ -67,7 +67,7 @@ LL +
    |
 
 error: temporary with significant `Drop` can be early dropped
-  --> $DIR/significant_drop_tightening.rs:106:17
+  --> $DIR/significant_drop_tightening.rs:133:17
    |
 LL | /     {
 LL | |         let mutex = Mutex::new(vec![1i32]);
diff --git a/tests/ui/single_match.fixed b/tests/ui/single_match.fixed
index e7b1fd6a85f..163ba94aff8 100644
--- a/tests/ui/single_match.fixed
+++ b/tests/ui/single_match.fixed
@@ -4,6 +4,7 @@
     unused,
     clippy::uninlined_format_args,
     clippy::needless_if,
+    clippy::redundant_guards,
     clippy::redundant_pattern_matching
 )]
 fn dummy() {}
diff --git a/tests/ui/single_match.rs b/tests/ui/single_match.rs
index 1515a7053e5..0dcdb125ffd 100644
--- a/tests/ui/single_match.rs
+++ b/tests/ui/single_match.rs
@@ -4,6 +4,7 @@
     unused,
     clippy::uninlined_format_args,
     clippy::needless_if,
+    clippy::redundant_guards,
     clippy::redundant_pattern_matching
 )]
 fn dummy() {}
diff --git a/tests/ui/single_match.stderr b/tests/ui/single_match.stderr
index 76f7e789589..d3536159949 100644
--- a/tests/ui/single_match.stderr
+++ b/tests/ui/single_match.stderr
@@ -1,5 +1,5 @@
 error: you seem to be trying to use `match` for destructuring a single pattern. Consider using `if let`
-  --> $DIR/single_match.rs:14:5
+  --> $DIR/single_match.rs:15:5
    |
 LL | /     match x {
 LL | |         Some(y) => {
@@ -18,7 +18,7 @@ LL ~     };
    |
 
 error: you seem to be trying to use `match` for destructuring a single pattern. Consider using `if let`
-  --> $DIR/single_match.rs:22:5
+  --> $DIR/single_match.rs:23:5
    |
 LL | /     match x {
 LL | |         // Note the missing block braces.
@@ -30,7 +30,7 @@ LL | |     }
    | |_____^ help: try: `if let Some(y) = x { println!("{:?}", y) }`
 
 error: you seem to be trying to use `match` for destructuring a single pattern. Consider using `if let`
-  --> $DIR/single_match.rs:31:5
+  --> $DIR/single_match.rs:32:5
    |
 LL | /     match z {
 LL | |         (2..=3, 7..=9) => dummy(),
@@ -39,7 +39,7 @@ LL | |     };
    | |_____^ help: try: `if let (2..=3, 7..=9) = z { dummy() }`
 
 error: you seem to be trying to use `match` for destructuring a single pattern. Consider using `if let`
-  --> $DIR/single_match.rs:60:5
+  --> $DIR/single_match.rs:61:5
    |
 LL | /     match x {
 LL | |         Some(y) => dummy(),
@@ -48,7 +48,7 @@ LL | |     };
    | |_____^ help: try: `if let Some(y) = x { dummy() }`
 
 error: you seem to be trying to use `match` for destructuring a single pattern. Consider using `if let`
-  --> $DIR/single_match.rs:65:5
+  --> $DIR/single_match.rs:66:5
    |
 LL | /     match y {
 LL | |         Ok(y) => dummy(),
@@ -57,7 +57,7 @@ LL | |     };
    | |_____^ help: try: `if let Ok(y) = y { dummy() }`
 
 error: you seem to be trying to use `match` for destructuring a single pattern. Consider using `if let`
-  --> $DIR/single_match.rs:72:5
+  --> $DIR/single_match.rs:73:5
    |
 LL | /     match c {
 LL | |         Cow::Borrowed(..) => dummy(),
@@ -66,7 +66,7 @@ LL | |     };
    | |_____^ help: try: `if let Cow::Borrowed(..) = c { dummy() }`
 
 error: you seem to be trying to use `match` for an equality check. Consider using `if`
-  --> $DIR/single_match.rs:93:5
+  --> $DIR/single_match.rs:94:5
    |
 LL | /     match x {
 LL | |         "test" => println!(),
@@ -75,7 +75,7 @@ LL | |     }
    | |_____^ help: try: `if x == "test" { println!() }`
 
 error: you seem to be trying to use `match` for an equality check. Consider using `if`
-  --> $DIR/single_match.rs:106:5
+  --> $DIR/single_match.rs:107:5
    |
 LL | /     match x {
 LL | |         Foo::A => println!(),
@@ -84,7 +84,7 @@ LL | |     }
    | |_____^ help: try: `if x == Foo::A { println!() }`
 
 error: you seem to be trying to use `match` for an equality check. Consider using `if`
-  --> $DIR/single_match.rs:112:5
+  --> $DIR/single_match.rs:113:5
    |
 LL | /     match x {
 LL | |         FOO_C => println!(),
@@ -93,7 +93,7 @@ LL | |     }
    | |_____^ help: try: `if x == FOO_C { println!() }`
 
 error: you seem to be trying to use `match` for an equality check. Consider using `if`
-  --> $DIR/single_match.rs:117:5
+  --> $DIR/single_match.rs:118:5
    |
 LL | /     match &&x {
 LL | |         Foo::A => println!(),
@@ -102,7 +102,7 @@ LL | |     }
    | |_____^ help: try: `if x == Foo::A { println!() }`
 
 error: you seem to be trying to use `match` for an equality check. Consider using `if`
-  --> $DIR/single_match.rs:123:5
+  --> $DIR/single_match.rs:124:5
    |
 LL | /     match &x {
 LL | |         Foo::A => println!(),
@@ -111,7 +111,7 @@ LL | |     }
    | |_____^ help: try: `if x == &Foo::A { println!() }`
 
 error: you seem to be trying to use `match` for destructuring a single pattern. Consider using `if let`
-  --> $DIR/single_match.rs:140:5
+  --> $DIR/single_match.rs:141:5
    |
 LL | /     match x {
 LL | |         Bar::A => println!(),
@@ -120,7 +120,7 @@ LL | |     }
    | |_____^ help: try: `if let Bar::A = x { println!() }`
 
 error: you seem to be trying to use `match` for destructuring a single pattern. Consider using `if let`
-  --> $DIR/single_match.rs:148:5
+  --> $DIR/single_match.rs:149:5
    |
 LL | /     match x {
 LL | |         None => println!(),
@@ -129,7 +129,7 @@ LL | |     };
    | |_____^ help: try: `if let None = x { println!() }`
 
 error: you seem to be trying to use `match` for destructuring a single pattern. Consider using `if let`
-  --> $DIR/single_match.rs:170:5
+  --> $DIR/single_match.rs:171:5
    |
 LL | /     match x {
 LL | |         (Some(_), _) => {},
@@ -138,7 +138,7 @@ LL | |     }
    | |_____^ help: try: `if let (Some(_), _) = x {}`
 
 error: you seem to be trying to use `match` for destructuring a single pattern. Consider using `if let`
-  --> $DIR/single_match.rs:176:5
+  --> $DIR/single_match.rs:177:5
    |
 LL | /     match x {
 LL | |         (Some(E::V), _) => todo!(),
@@ -147,7 +147,7 @@ LL | |     }
    | |_____^ help: try: `if let (Some(E::V), _) = x { todo!() }`
 
 error: you seem to be trying to use `match` for destructuring a single pattern. Consider using `if let`
-  --> $DIR/single_match.rs:182:5
+  --> $DIR/single_match.rs:183:5
    |
 LL | /     match (Some(42), Some(E::V), Some(42)) {
 LL | |         (.., Some(E::V), _) => {},
@@ -156,7 +156,7 @@ LL | |     }
    | |_____^ help: try: `if let (.., Some(E::V), _) = (Some(42), Some(E::V), Some(42)) {}`
 
 error: you seem to be trying to use `match` for destructuring a single pattern. Consider using `if let`
-  --> $DIR/single_match.rs:254:5
+  --> $DIR/single_match.rs:255:5
    |
 LL | /     match bar {
 LL | |         Some(v) => unsafe {
@@ -176,7 +176,7 @@ LL +     } }
    |
 
 error: you seem to be trying to use `match` for destructuring a single pattern. Consider using `if let`
-  --> $DIR/single_match.rs:262:5
+  --> $DIR/single_match.rs:263:5
    |
 LL | /     match bar {
 LL | |         #[rustfmt::skip]
diff --git a/tests/ui/slow_vector_initialization.rs b/tests/ui/slow_vector_initialization.rs
index 16be9f6d203..cfb856861b8 100644
--- a/tests/ui/slow_vector_initialization.rs
+++ b/tests/ui/slow_vector_initialization.rs
@@ -4,6 +4,7 @@ fn main() {
     resize_vector();
     extend_vector();
     mixed_extend_resize_vector();
+    from_empty_vec();
 }
 
 fn extend_vector() {
@@ -59,6 +60,21 @@ fn resize_vector() {
     vec1.resize(10, 0);
 }
 
+fn from_empty_vec() {
+    // Resize with constant expression
+    let len = 300;
+    let mut vec1 = Vec::new();
+    vec1.resize(len, 0);
+
+    // Resize with len expression
+    let mut vec3 = Vec::new();
+    vec3.resize(len - 10, 0);
+
+    // Reinitialization should be warned
+    vec1 = Vec::new();
+    vec1.resize(10, 0);
+}
+
 fn do_stuff(vec: &mut [u8]) {}
 
 fn extend_vector_with_manipulations_between() {
diff --git a/tests/ui/slow_vector_initialization.stderr b/tests/ui/slow_vector_initialization.stderr
index 22376680a8e..532ce4ac191 100644
--- a/tests/ui/slow_vector_initialization.stderr
+++ b/tests/ui/slow_vector_initialization.stderr
@@ -1,84 +1,108 @@
 error: slow zero-filling initialization
-  --> $DIR/slow_vector_initialization.rs:13:5
+  --> $DIR/slow_vector_initialization.rs:14:5
    |
 LL |     let mut vec1 = Vec::with_capacity(len);
-   |                    ----------------------- help: consider replace allocation with: `vec![0; len]`
+   |                    ----------------------- help: consider replacing this with: `vec![0; len]`
 LL |     vec1.extend(repeat(0).take(len));
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
    = note: `-D clippy::slow-vector-initialization` implied by `-D warnings`
 
 error: slow zero-filling initialization
-  --> $DIR/slow_vector_initialization.rs:17:5
+  --> $DIR/slow_vector_initialization.rs:18:5
    |
 LL |     let mut vec2 = Vec::with_capacity(len - 10);
-   |                    ---------------------------- help: consider replace allocation with: `vec![0; len - 10]`
+   |                    ---------------------------- help: consider replacing this with: `vec![0; len - 10]`
 LL |     vec2.extend(repeat(0).take(len - 10));
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: slow zero-filling initialization
-  --> $DIR/slow_vector_initialization.rs:24:5
+  --> $DIR/slow_vector_initialization.rs:25:5
    |
 LL |     let mut vec4 = Vec::with_capacity(len);
-   |                    ----------------------- help: consider replace allocation with: `vec![0; len]`
+   |                    ----------------------- help: consider replacing this with: `vec![0; len]`
 LL |     vec4.extend(repeat(0).take(vec4.capacity()));
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: slow zero-filling initialization
-  --> $DIR/slow_vector_initialization.rs:34:5
+  --> $DIR/slow_vector_initialization.rs:35:5
    |
 LL |     let mut resized_vec = Vec::with_capacity(30);
-   |                           ---------------------- help: consider replace allocation with: `vec![0; 30]`
+   |                           ---------------------- help: consider replacing this with: `vec![0; 30]`
 LL |     resized_vec.resize(30, 0);
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: slow zero-filling initialization
-  --> $DIR/slow_vector_initialization.rs:37:5
+  --> $DIR/slow_vector_initialization.rs:38:5
    |
 LL |     let mut extend_vec = Vec::with_capacity(30);
-   |                          ---------------------- help: consider replace allocation with: `vec![0; 30]`
+   |                          ---------------------- help: consider replacing this with: `vec![0; 30]`
 LL |     extend_vec.extend(repeat(0).take(30));
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: slow zero-filling initialization
-  --> $DIR/slow_vector_initialization.rs:44:5
+  --> $DIR/slow_vector_initialization.rs:45:5
    |
 LL |     let mut vec1 = Vec::with_capacity(len);
-   |                    ----------------------- help: consider replace allocation with: `vec![0; len]`
+   |                    ----------------------- help: consider replacing this with: `vec![0; len]`
 LL |     vec1.resize(len, 0);
    |     ^^^^^^^^^^^^^^^^^^^
 
 error: slow zero-filling initialization
-  --> $DIR/slow_vector_initialization.rs:52:5
+  --> $DIR/slow_vector_initialization.rs:53:5
    |
 LL |     let mut vec3 = Vec::with_capacity(len - 10);
-   |                    ---------------------------- help: consider replace allocation with: `vec![0; len - 10]`
+   |                    ---------------------------- help: consider replacing this with: `vec![0; len - 10]`
 LL |     vec3.resize(len - 10, 0);
    |     ^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: slow zero-filling initialization
-  --> $DIR/slow_vector_initialization.rs:55:5
+  --> $DIR/slow_vector_initialization.rs:56:5
    |
 LL |     let mut vec4 = Vec::with_capacity(len);
-   |                    ----------------------- help: consider replace allocation with: `vec![0; len]`
+   |                    ----------------------- help: consider replacing this with: `vec![0; len]`
 LL |     vec4.resize(vec4.capacity(), 0);
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: slow zero-filling initialization
-  --> $DIR/slow_vector_initialization.rs:59:5
+  --> $DIR/slow_vector_initialization.rs:60:5
    |
 LL |     vec1 = Vec::with_capacity(10);
-   |            ---------------------- help: consider replace allocation with: `vec![0; 10]`
+   |            ---------------------- help: consider replacing this with: `vec![0; 10]`
+LL |     vec1.resize(10, 0);
+   |     ^^^^^^^^^^^^^^^^^^
+
+error: slow zero-filling initialization
+  --> $DIR/slow_vector_initialization.rs:67:5
+   |
+LL |     let mut vec1 = Vec::new();
+   |                    ---------- help: consider replacing this with: `vec![0; len]`
+LL |     vec1.resize(len, 0);
+   |     ^^^^^^^^^^^^^^^^^^^
+
+error: slow zero-filling initialization
+  --> $DIR/slow_vector_initialization.rs:71:5
+   |
+LL |     let mut vec3 = Vec::new();
+   |                    ---------- help: consider replacing this with: `vec![0; len - 10]`
+LL |     vec3.resize(len - 10, 0);
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: slow zero-filling initialization
+  --> $DIR/slow_vector_initialization.rs:75:5
+   |
+LL |     vec1 = Vec::new();
+   |            ---------- help: consider replacing this with: `vec![0; 10]`
 LL |     vec1.resize(10, 0);
    |     ^^^^^^^^^^^^^^^^^^
 
 error: this argument is a mutable reference, but not used mutably
-  --> $DIR/slow_vector_initialization.rs:62:18
+  --> $DIR/slow_vector_initialization.rs:78:18
    |
 LL | fn do_stuff(vec: &mut [u8]) {}
    |                  ^^^^^^^^^ help: consider changing to: `&[u8]`
    |
    = note: `-D clippy::needless-pass-by-ref-mut` implied by `-D warnings`
 
-error: aborting due to 10 previous errors
+error: aborting due to 13 previous errors
 
diff --git a/tests/ui/suspicious_xor_used_as_pow.stderr b/tests/ui/suspicious_xor_used_as_pow.stderr
index 8bb3c8fbeeb..d93a55ba906 100644
--- a/tests/ui/suspicious_xor_used_as_pow.stderr
+++ b/tests/ui/suspicious_xor_used_as_pow.stderr
@@ -10,31 +10,31 @@ error: `^` is not the exponentiation operator
   --> $DIR/suspicious_xor_used_as_pow.rs:20:13
    |
 LL |     let _ = 2i32 ^ 9i32;
-   |             ^^^^^^^^^^^ help: did you mean to write: `2_i32.pow(9_i32)`
+   |             ^^^^^^^^^^^ help: did you mean to write: `2i32.pow(9i32)`
 
 error: `^` is not the exponentiation operator
   --> $DIR/suspicious_xor_used_as_pow.rs:21:13
    |
 LL |     let _ = 2i32 ^ 2i32;
-   |             ^^^^^^^^^^^ help: did you mean to write: `2_i32.pow(2_i32)`
+   |             ^^^^^^^^^^^ help: did you mean to write: `2i32.pow(2i32)`
 
 error: `^` is not the exponentiation operator
   --> $DIR/suspicious_xor_used_as_pow.rs:22:13
    |
 LL |     let _ = 50i32 ^ 3i32;
-   |             ^^^^^^^^^^^^ help: did you mean to write: `50_i32.pow(3_i32)`
+   |             ^^^^^^^^^^^^ help: did you mean to write: `50i32.pow(3i32)`
 
 error: `^` is not the exponentiation operator
   --> $DIR/suspicious_xor_used_as_pow.rs:23:13
    |
 LL |     let _ = 5i32 ^ 8i32;
-   |             ^^^^^^^^^^^ help: did you mean to write: `5_i32.pow(8_i32)`
+   |             ^^^^^^^^^^^ help: did you mean to write: `5i32.pow(8i32)`
 
 error: `^` is not the exponentiation operator
   --> $DIR/suspicious_xor_used_as_pow.rs:24:13
    |
 LL |     let _ = 2i32 ^ 32i32;
-   |             ^^^^^^^^^^^^ help: did you mean to write: `2_i32.pow(32_i32)`
+   |             ^^^^^^^^^^^^ help: did you mean to write: `2i32.pow(32i32)`
 
 error: `^` is not the exponentiation operator
   --> $DIR/suspicious_xor_used_as_pow.rs:13:9
diff --git a/tests/ui/swap.fixed b/tests/ui/swap.fixed
index 22f904e3fd9..7b74a83b6df 100644
--- a/tests/ui/swap.fixed
+++ b/tests/ui/swap.fixed
@@ -11,7 +11,8 @@
     unused_assignments,
     unused_variables,
     clippy::let_and_return,
-    clippy::useless_vec
+    clippy::useless_vec,
+    clippy::redundant_locals
 )]
 
 struct Foo(u32);
diff --git a/tests/ui/swap.rs b/tests/ui/swap.rs
index ada64f89e6d..93855cd7b5c 100644
--- a/tests/ui/swap.rs
+++ b/tests/ui/swap.rs
@@ -11,7 +11,8 @@
     unused_assignments,
     unused_variables,
     clippy::let_and_return,
-    clippy::useless_vec
+    clippy::useless_vec,
+    clippy::redundant_locals
 )]
 
 struct Foo(u32);
diff --git a/tests/ui/swap.stderr b/tests/ui/swap.stderr
index a3b9c2b744c..1097b29bba0 100644
--- a/tests/ui/swap.stderr
+++ b/tests/ui/swap.stderr
@@ -1,5 +1,5 @@
 error: this looks like you are swapping `bar.a` and `bar.b` manually
-  --> $DIR/swap.rs:28:5
+  --> $DIR/swap.rs:29:5
    |
 LL | /     let temp = bar.a;
 LL | |     bar.a = bar.b;
@@ -10,7 +10,7 @@ LL | |     bar.b = temp;
    = note: `-D clippy::manual-swap` implied by `-D warnings`
 
 error: this looks like you are swapping elements of `foo` manually
-  --> $DIR/swap.rs:40:5
+  --> $DIR/swap.rs:41:5
    |
 LL | /     let temp = foo[0];
 LL | |     foo[0] = foo[1];
@@ -18,7 +18,7 @@ LL | |     foo[1] = temp;
    | |__________________^ help: try: `foo.swap(0, 1);`
 
 error: this looks like you are swapping elements of `foo` manually
-  --> $DIR/swap.rs:49:5
+  --> $DIR/swap.rs:50:5
    |
 LL | /     let temp = foo[0];
 LL | |     foo[0] = foo[1];
@@ -26,7 +26,7 @@ LL | |     foo[1] = temp;
    | |__________________^ help: try: `foo.swap(0, 1);`
 
 error: this looks like you are swapping elements of `foo` manually
-  --> $DIR/swap.rs:68:5
+  --> $DIR/swap.rs:69:5
    |
 LL | /     let temp = foo[0];
 LL | |     foo[0] = foo[1];
@@ -34,7 +34,7 @@ LL | |     foo[1] = temp;
    | |__________________^ help: try: `foo.swap(0, 1);`
 
 error: this looks like you are swapping `a` and `b` manually
-  --> $DIR/swap.rs:79:5
+  --> $DIR/swap.rs:80:5
    |
 LL | /     a ^= b;
 LL | |     b ^= a;
@@ -42,7 +42,7 @@ LL | |     a ^= b;
    | |___________^ help: try: `std::mem::swap(&mut a, &mut b);`
 
 error: this looks like you are swapping `bar.a` and `bar.b` manually
-  --> $DIR/swap.rs:87:5
+  --> $DIR/swap.rs:88:5
    |
 LL | /     bar.a ^= bar.b;
 LL | |     bar.b ^= bar.a;
@@ -50,7 +50,7 @@ LL | |     bar.a ^= bar.b;
    | |___________________^ help: try: `std::mem::swap(&mut bar.a, &mut bar.b);`
 
 error: this looks like you are swapping elements of `foo` manually
-  --> $DIR/swap.rs:95:5
+  --> $DIR/swap.rs:96:5
    |
 LL | /     foo[0] ^= foo[1];
 LL | |     foo[1] ^= foo[0];
@@ -58,7 +58,7 @@ LL | |     foo[0] ^= foo[1];
    | |_____________________^ help: try: `foo.swap(0, 1);`
 
 error: this looks like you are swapping `foo[0][1]` and `bar[1][0]` manually
-  --> $DIR/swap.rs:124:5
+  --> $DIR/swap.rs:125:5
    |
 LL | /     let temp = foo[0][1];
 LL | |     foo[0][1] = bar[1][0];
@@ -68,7 +68,7 @@ LL | |     bar[1][0] = temp;
    = note: or maybe you should use `std::mem::replace`?
 
 error: this looks like you are swapping `a` and `b` manually
-  --> $DIR/swap.rs:138:7
+  --> $DIR/swap.rs:139:7
    |
 LL |       ; let t = a;
    |  _______^
@@ -79,7 +79,7 @@ LL | |     b = t;
    = note: or maybe you should use `std::mem::replace`?
 
 error: this looks like you are swapping `c.0` and `a` manually
-  --> $DIR/swap.rs:147:7
+  --> $DIR/swap.rs:148:7
    |
 LL |       ; let t = c.0;
    |  _______^
@@ -90,7 +90,7 @@ LL | |     a = t;
    = note: or maybe you should use `std::mem::replace`?
 
 error: this looks like you are swapping `b` and `a` manually
-  --> $DIR/swap.rs:173:5
+  --> $DIR/swap.rs:174:5
    |
 LL | /     let t = b;
 LL | |     b = a;
@@ -100,7 +100,7 @@ LL | |     a = t;
    = note: or maybe you should use `std::mem::replace`?
 
 error: this looks like you are trying to swap `a` and `b`
-  --> $DIR/swap.rs:135:5
+  --> $DIR/swap.rs:136:5
    |
 LL | /     a = b;
 LL | |     b = a;
@@ -110,7 +110,7 @@ LL | |     b = a;
    = note: `-D clippy::almost-swapped` implied by `-D warnings`
 
 error: this looks like you are trying to swap `c.0` and `a`
-  --> $DIR/swap.rs:144:5
+  --> $DIR/swap.rs:145:5
    |
 LL | /     c.0 = a;
 LL | |     a = c.0;
@@ -119,7 +119,7 @@ LL | |     a = c.0;
    = note: or maybe you should use `std::mem::replace`?
 
 error: this looks like you are trying to swap `a` and `b`
-  --> $DIR/swap.rs:151:5
+  --> $DIR/swap.rs:152:5
    |
 LL | /     let a = b;
 LL | |     let b = a;
@@ -128,7 +128,7 @@ LL | |     let b = a;
    = note: or maybe you should use `std::mem::replace`?
 
 error: this looks like you are trying to swap `d` and `c`
-  --> $DIR/swap.rs:156:5
+  --> $DIR/swap.rs:157:5
    |
 LL | /     d = c;
 LL | |     c = d;
@@ -137,7 +137,7 @@ LL | |     c = d;
    = note: or maybe you should use `std::mem::replace`?
 
 error: this looks like you are trying to swap `a` and `b`
-  --> $DIR/swap.rs:160:5
+  --> $DIR/swap.rs:161:5
    |
 LL | /     let a = b;
 LL | |     b = a;
@@ -146,7 +146,7 @@ LL | |     b = a;
    = note: or maybe you should use `std::mem::replace`?
 
 error: this looks like you are swapping `s.0.x` and `s.0.y` manually
-  --> $DIR/swap.rs:208:5
+  --> $DIR/swap.rs:209:5
    |
 LL | /     let t = s.0.x;
 LL | |     s.0.x = s.0.y;
diff --git a/tests/ui/try_err.fixed b/tests/ui/try_err.fixed
index 1816740870a..930489fab76 100644
--- a/tests/ui/try_err.fixed
+++ b/tests/ui/try_err.fixed
@@ -2,7 +2,11 @@
 //@aux-build:proc_macros.rs:proc-macro
 
 #![deny(clippy::try_err)]
-#![allow(clippy::unnecessary_wraps, clippy::needless_question_mark)]
+#![allow(
+    clippy::unnecessary_wraps,
+    clippy::needless_question_mark,
+    clippy::needless_return_with_question_mark
+)]
 
 extern crate proc_macros;
 use proc_macros::{external, inline_macros};
diff --git a/tests/ui/try_err.rs b/tests/ui/try_err.rs
index 0e47c4d023e..f5baf3d8f74 100644
--- a/tests/ui/try_err.rs
+++ b/tests/ui/try_err.rs
@@ -2,7 +2,11 @@
 //@aux-build:proc_macros.rs:proc-macro
 
 #![deny(clippy::try_err)]
-#![allow(clippy::unnecessary_wraps, clippy::needless_question_mark)]
+#![allow(
+    clippy::unnecessary_wraps,
+    clippy::needless_question_mark,
+    clippy::needless_return_with_question_mark
+)]
 
 extern crate proc_macros;
 use proc_macros::{external, inline_macros};
diff --git a/tests/ui/try_err.stderr b/tests/ui/try_err.stderr
index 79f7b70224a..9968b383ebb 100644
--- a/tests/ui/try_err.stderr
+++ b/tests/ui/try_err.stderr
@@ -1,5 +1,5 @@
 error: returning an `Err(_)` with the `?` operator
-  --> $DIR/try_err.rs:19:9
+  --> $DIR/try_err.rs:23:9
    |
 LL |         Err(err)?;
    |         ^^^^^^^^^ help: try: `return Err(err)`
@@ -11,25 +11,25 @@ LL | #![deny(clippy::try_err)]
    |         ^^^^^^^^^^^^^^^
 
 error: returning an `Err(_)` with the `?` operator
-  --> $DIR/try_err.rs:29:9
+  --> $DIR/try_err.rs:33:9
    |
 LL |         Err(err)?;
    |         ^^^^^^^^^ help: try: `return Err(err.into())`
 
 error: returning an `Err(_)` with the `?` operator
-  --> $DIR/try_err.rs:49:17
+  --> $DIR/try_err.rs:53:17
    |
 LL |                 Err(err)?;
    |                 ^^^^^^^^^ help: try: `return Err(err)`
 
 error: returning an `Err(_)` with the `?` operator
-  --> $DIR/try_err.rs:68:17
+  --> $DIR/try_err.rs:72:17
    |
 LL |                 Err(err)?;
    |                 ^^^^^^^^^ help: try: `return Err(err.into())`
 
 error: returning an `Err(_)` with the `?` operator
-  --> $DIR/try_err.rs:88:23
+  --> $DIR/try_err.rs:92:23
    |
 LL |             Err(_) => Err(1)?,
    |                       ^^^^^^^ help: try: `return Err(1)`
@@ -37,7 +37,7 @@ LL |             Err(_) => Err(1)?,
    = note: this error originates in the macro `__inline_mac_fn_calling_macro` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error: returning an `Err(_)` with the `?` operator
-  --> $DIR/try_err.rs:95:23
+  --> $DIR/try_err.rs:99:23
    |
 LL |             Err(_) => Err(inline!(1))?,
    |                       ^^^^^^^^^^^^^^^^ help: try: `return Err(inline!(1))`
@@ -45,31 +45,31 @@ LL |             Err(_) => Err(inline!(1))?,
    = note: this error originates in the macro `__inline_mac_fn_calling_macro` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error: returning an `Err(_)` with the `?` operator
-  --> $DIR/try_err.rs:122:9
+  --> $DIR/try_err.rs:126:9
    |
 LL |         Err(inline!(inline!(String::from("aasdfasdfasdfa"))))?;
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `return Err(inline!(inline!(String::from("aasdfasdfasdfa"))))`
 
 error: returning an `Err(_)` with the `?` operator
-  --> $DIR/try_err.rs:129:9
+  --> $DIR/try_err.rs:133:9
    |
 LL |         Err(io::ErrorKind::WriteZero)?
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `return Poll::Ready(Err(io::ErrorKind::WriteZero.into()))`
 
 error: returning an `Err(_)` with the `?` operator
-  --> $DIR/try_err.rs:131:9
+  --> $DIR/try_err.rs:135:9
    |
 LL |         Err(io::Error::new(io::ErrorKind::InvalidInput, "error"))?
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `return Poll::Ready(Err(io::Error::new(io::ErrorKind::InvalidInput, "error")))`
 
 error: returning an `Err(_)` with the `?` operator
-  --> $DIR/try_err.rs:139:9
+  --> $DIR/try_err.rs:143:9
    |
 LL |         Err(io::ErrorKind::NotFound)?
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `return Poll::Ready(Some(Err(io::ErrorKind::NotFound.into())))`
 
 error: returning an `Err(_)` with the `?` operator
-  --> $DIR/try_err.rs:148:16
+  --> $DIR/try_err.rs:152:16
    |
 LL |         return Err(42)?;
    |                ^^^^^^^^ help: try: `Err(42)`
diff --git a/tests/ui/unnecessary_cast.fixed b/tests/ui/unnecessary_cast.fixed
index 8efd44baf59..2bf02f13414 100644
--- a/tests/ui/unnecessary_cast.fixed
+++ b/tests/ui/unnecessary_cast.fixed
@@ -38,6 +38,16 @@ mod fake_libc {
     }
 }
 
+fn aaa() -> ::std::primitive::u32 {
+    0
+}
+
+use std::primitive::u32 as UnsignedThirtyTwoBitInteger;
+
+fn bbb() -> UnsignedThirtyTwoBitInteger {
+    0
+}
+
 #[rustfmt::skip]
 fn main() {
     // Test cast_unnecessary
@@ -105,6 +115,13 @@ fn main() {
     extern_fake_libc::getpid_SAFE_TRUTH() as i32;
     let pid = unsafe { fake_libc::getpid() };
     pid as i32;
+    aaa();
+    let x = aaa();
+    aaa();
+    // Will not lint currently.
+    bbb() as u32;
+    let x = bbb();
+    bbb() as u32;
 
     let i8_ptr: *const i8 = &1;
     let u8_ptr: *const u8 = &1;
diff --git a/tests/ui/unnecessary_cast.rs b/tests/ui/unnecessary_cast.rs
index c7723ef51f9..25b6b0f9b07 100644
--- a/tests/ui/unnecessary_cast.rs
+++ b/tests/ui/unnecessary_cast.rs
@@ -38,6 +38,16 @@ mod fake_libc {
     }
 }
 
+fn aaa() -> ::std::primitive::u32 {
+    0
+}
+
+use std::primitive::u32 as UnsignedThirtyTwoBitInteger;
+
+fn bbb() -> UnsignedThirtyTwoBitInteger {
+    0
+}
+
 #[rustfmt::skip]
 fn main() {
     // Test cast_unnecessary
@@ -105,6 +115,13 @@ fn main() {
     extern_fake_libc::getpid_SAFE_TRUTH() as i32;
     let pid = unsafe { fake_libc::getpid() };
     pid as i32;
+    aaa() as u32;
+    let x = aaa();
+    aaa() as u32;
+    // Will not lint currently.
+    bbb() as u32;
+    let x = bbb();
+    bbb() as u32;
 
     let i8_ptr: *const i8 = &1;
     let u8_ptr: *const u8 = &1;
diff --git a/tests/ui/unnecessary_cast.stderr b/tests/ui/unnecessary_cast.stderr
index f0443556fb4..19411a01b67 100644
--- a/tests/ui/unnecessary_cast.stderr
+++ b/tests/ui/unnecessary_cast.stderr
@@ -7,226 +7,238 @@ LL |     ptr as *const T
    = note: `-D clippy::unnecessary-cast` implied by `-D warnings`
 
 error: casting integer literal to `i32` is unnecessary
-  --> $DIR/unnecessary_cast.rs:44:5
+  --> $DIR/unnecessary_cast.rs:54:5
    |
 LL |     1i32 as i32;
    |     ^^^^^^^^^^^ help: try: `1_i32`
 
 error: casting float literal to `f32` is unnecessary
-  --> $DIR/unnecessary_cast.rs:45:5
+  --> $DIR/unnecessary_cast.rs:55:5
    |
 LL |     1f32 as f32;
    |     ^^^^^^^^^^^ help: try: `1_f32`
 
 error: casting to the same type is unnecessary (`bool` -> `bool`)
-  --> $DIR/unnecessary_cast.rs:46:5
+  --> $DIR/unnecessary_cast.rs:56:5
    |
 LL |     false as bool;
    |     ^^^^^^^^^^^^^ help: try: `false`
 
 error: casting integer literal to `i32` is unnecessary
-  --> $DIR/unnecessary_cast.rs:49:5
+  --> $DIR/unnecessary_cast.rs:59:5
    |
 LL |     -1_i32 as i32;
    |     ^^^^^^^^^^^^^ help: try: `-1_i32`
 
 error: casting integer literal to `i32` is unnecessary
-  --> $DIR/unnecessary_cast.rs:50:5
+  --> $DIR/unnecessary_cast.rs:60:5
    |
 LL |     - 1_i32 as i32;
    |     ^^^^^^^^^^^^^^ help: try: `- 1_i32`
 
 error: casting float literal to `f32` is unnecessary
-  --> $DIR/unnecessary_cast.rs:51:5
+  --> $DIR/unnecessary_cast.rs:61:5
    |
 LL |     -1f32 as f32;
    |     ^^^^^^^^^^^^ help: try: `-1_f32`
 
 error: casting integer literal to `i32` is unnecessary
-  --> $DIR/unnecessary_cast.rs:52:5
+  --> $DIR/unnecessary_cast.rs:62:5
    |
 LL |     1_i32 as i32;
    |     ^^^^^^^^^^^^ help: try: `1_i32`
 
 error: casting float literal to `f32` is unnecessary
-  --> $DIR/unnecessary_cast.rs:53:5
+  --> $DIR/unnecessary_cast.rs:63:5
    |
 LL |     1_f32 as f32;
    |     ^^^^^^^^^^^^ help: try: `1_f32`
 
 error: casting raw pointers to the same type and constness is unnecessary (`*const u8` -> `*const u8`)
-  --> $DIR/unnecessary_cast.rs:55:22
+  --> $DIR/unnecessary_cast.rs:65:22
    |
 LL |     let _: *mut u8 = [1u8, 2].as_ptr() as *const u8 as *mut u8;
    |                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `[1u8, 2].as_ptr()`
 
 error: casting raw pointers to the same type and constness is unnecessary (`*const u8` -> `*const u8`)
-  --> $DIR/unnecessary_cast.rs:57:5
+  --> $DIR/unnecessary_cast.rs:67:5
    |
 LL |     [1u8, 2].as_ptr() as *const u8;
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `[1u8, 2].as_ptr()`
 
 error: casting raw pointers to the same type and constness is unnecessary (`*mut u8` -> `*mut u8`)
-  --> $DIR/unnecessary_cast.rs:59:5
+  --> $DIR/unnecessary_cast.rs:69:5
    |
 LL |     [1u8, 2].as_mut_ptr() as *mut u8;
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `[1u8, 2].as_mut_ptr()`
 
 error: casting raw pointers to the same type and constness is unnecessary (`*const u32` -> `*const u32`)
-  --> $DIR/unnecessary_cast.rs:70:5
+  --> $DIR/unnecessary_cast.rs:80:5
    |
 LL |     owo::<u32>([1u32].as_ptr()) as *const u32;
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `owo::<u32>([1u32].as_ptr())`
 
 error: casting raw pointers to the same type and constness is unnecessary (`*const u8` -> `*const u8`)
-  --> $DIR/unnecessary_cast.rs:71:5
+  --> $DIR/unnecessary_cast.rs:81:5
    |
 LL |     uwu::<u32, u8>([1u32].as_ptr()) as *const u8;
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `uwu::<u32, u8>([1u32].as_ptr())`
 
 error: casting raw pointers to the same type and constness is unnecessary (`*const u32` -> `*const u32`)
-  --> $DIR/unnecessary_cast.rs:73:5
+  --> $DIR/unnecessary_cast.rs:83:5
    |
 LL |     uwu::<u32, u32>([1u32].as_ptr()) as *const u32;
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `uwu::<u32, u32>([1u32].as_ptr())`
 
+error: casting to the same type is unnecessary (`u32` -> `u32`)
+  --> $DIR/unnecessary_cast.rs:118:5
+   |
+LL |     aaa() as u32;
+   |     ^^^^^^^^^^^^ help: try: `aaa()`
+
+error: casting to the same type is unnecessary (`u32` -> `u32`)
+  --> $DIR/unnecessary_cast.rs:120:5
+   |
+LL |     aaa() as u32;
+   |     ^^^^^^^^^^^^ help: try: `aaa()`
+
 error: casting integer literal to `f32` is unnecessary
-  --> $DIR/unnecessary_cast.rs:139:9
+  --> $DIR/unnecessary_cast.rs:156:9
    |
 LL |         100 as f32;
    |         ^^^^^^^^^^ help: try: `100_f32`
 
 error: casting integer literal to `f64` is unnecessary
-  --> $DIR/unnecessary_cast.rs:140:9
+  --> $DIR/unnecessary_cast.rs:157:9
    |
 LL |         100 as f64;
    |         ^^^^^^^^^^ help: try: `100_f64`
 
 error: casting integer literal to `f64` is unnecessary
-  --> $DIR/unnecessary_cast.rs:141:9
+  --> $DIR/unnecessary_cast.rs:158:9
    |
 LL |         100_i32 as f64;
    |         ^^^^^^^^^^^^^^ help: try: `100_f64`
 
 error: casting integer literal to `f32` is unnecessary
-  --> $DIR/unnecessary_cast.rs:142:17
+  --> $DIR/unnecessary_cast.rs:159:17
    |
 LL |         let _ = -100 as f32;
    |                 ^^^^^^^^^^^ help: try: `-100_f32`
 
 error: casting integer literal to `f64` is unnecessary
-  --> $DIR/unnecessary_cast.rs:143:17
+  --> $DIR/unnecessary_cast.rs:160:17
    |
 LL |         let _ = -100 as f64;
    |                 ^^^^^^^^^^^ help: try: `-100_f64`
 
 error: casting integer literal to `f64` is unnecessary
-  --> $DIR/unnecessary_cast.rs:144:17
+  --> $DIR/unnecessary_cast.rs:161:17
    |
 LL |         let _ = -100_i32 as f64;
    |                 ^^^^^^^^^^^^^^^ help: try: `-100_f64`
 
 error: casting float literal to `f32` is unnecessary
-  --> $DIR/unnecessary_cast.rs:145:9
+  --> $DIR/unnecessary_cast.rs:162:9
    |
 LL |         100. as f32;
    |         ^^^^^^^^^^^ help: try: `100_f32`
 
 error: casting float literal to `f64` is unnecessary
-  --> $DIR/unnecessary_cast.rs:146:9
+  --> $DIR/unnecessary_cast.rs:163:9
    |
 LL |         100. as f64;
    |         ^^^^^^^^^^^ help: try: `100_f64`
 
 error: casting integer literal to `u32` is unnecessary
-  --> $DIR/unnecessary_cast.rs:158:9
+  --> $DIR/unnecessary_cast.rs:175:9
    |
 LL |         1 as u32;
    |         ^^^^^^^^ help: try: `1_u32`
 
 error: casting integer literal to `i32` is unnecessary
-  --> $DIR/unnecessary_cast.rs:159:9
+  --> $DIR/unnecessary_cast.rs:176:9
    |
 LL |         0x10 as i32;
    |         ^^^^^^^^^^^ help: try: `0x10_i32`
 
 error: casting integer literal to `usize` is unnecessary
-  --> $DIR/unnecessary_cast.rs:160:9
+  --> $DIR/unnecessary_cast.rs:177:9
    |
 LL |         0b10 as usize;
    |         ^^^^^^^^^^^^^ help: try: `0b10_usize`
 
 error: casting integer literal to `u16` is unnecessary
-  --> $DIR/unnecessary_cast.rs:161:9
+  --> $DIR/unnecessary_cast.rs:178:9
    |
 LL |         0o73 as u16;
    |         ^^^^^^^^^^^ help: try: `0o73_u16`
 
 error: casting integer literal to `u32` is unnecessary
-  --> $DIR/unnecessary_cast.rs:162:9
+  --> $DIR/unnecessary_cast.rs:179:9
    |
 LL |         1_000_000_000 as u32;
    |         ^^^^^^^^^^^^^^^^^^^^ help: try: `1_000_000_000_u32`
 
 error: casting float literal to `f64` is unnecessary
-  --> $DIR/unnecessary_cast.rs:164:9
+  --> $DIR/unnecessary_cast.rs:181:9
    |
 LL |         1.0 as f64;
    |         ^^^^^^^^^^ help: try: `1.0_f64`
 
 error: casting float literal to `f32` is unnecessary
-  --> $DIR/unnecessary_cast.rs:165:9
+  --> $DIR/unnecessary_cast.rs:182:9
    |
 LL |         0.5 as f32;
    |         ^^^^^^^^^^ help: try: `0.5_f32`
 
 error: casting integer literal to `i32` is unnecessary
-  --> $DIR/unnecessary_cast.rs:169:17
+  --> $DIR/unnecessary_cast.rs:186:17
    |
 LL |         let _ = -1 as i32;
    |                 ^^^^^^^^^ help: try: `-1_i32`
 
 error: casting float literal to `f32` is unnecessary
-  --> $DIR/unnecessary_cast.rs:170:17
+  --> $DIR/unnecessary_cast.rs:187:17
    |
 LL |         let _ = -1.0 as f32;
    |                 ^^^^^^^^^^^ help: try: `-1.0_f32`
 
 error: casting to the same type is unnecessary (`i32` -> `i32`)
-  --> $DIR/unnecessary_cast.rs:176:18
+  --> $DIR/unnecessary_cast.rs:193:18
    |
 LL |         let _ = &(x as i32);
    |                  ^^^^^^^^^^ help: try: `{ x }`
 
 error: casting integer literal to `i32` is unnecessary
-  --> $DIR/unnecessary_cast.rs:182:22
+  --> $DIR/unnecessary_cast.rs:199:22
    |
 LL |         let _: i32 = -(1) as i32;
    |                      ^^^^^^^^^^^ help: try: `-1_i32`
 
 error: casting integer literal to `i64` is unnecessary
-  --> $DIR/unnecessary_cast.rs:184:22
+  --> $DIR/unnecessary_cast.rs:201:22
    |
 LL |         let _: i64 = -(1) as i64;
    |                      ^^^^^^^^^^^ help: try: `-1_i64`
 
 error: casting float literal to `f64` is unnecessary
-  --> $DIR/unnecessary_cast.rs:191:22
+  --> $DIR/unnecessary_cast.rs:208:22
    |
 LL |         let _: f64 = (-8.0 as f64).exp();
    |                      ^^^^^^^^^^^^^ help: try: `(-8.0_f64)`
 
 error: casting float literal to `f64` is unnecessary
-  --> $DIR/unnecessary_cast.rs:193:23
+  --> $DIR/unnecessary_cast.rs:210:23
    |
 LL |         let _: f64 = -(8.0 as f64).exp(); // should suggest `-8.0_f64.exp()` here not to change code behavior
    |                       ^^^^^^^^^^^^ help: try: `8.0_f64`
 
 error: casting to the same type is unnecessary (`f32` -> `f32`)
-  --> $DIR/unnecessary_cast.rs:201:20
+  --> $DIR/unnecessary_cast.rs:218:20
    |
 LL |         let _num = foo() as f32;
    |                    ^^^^^^^^^^^^ help: try: `foo()`
 
-error: aborting due to 38 previous errors
+error: aborting due to 40 previous errors
 
diff --git a/tests/ui/unnecessary_filter_map.rs b/tests/ui/unnecessary_filter_map.rs
index 8e01c2674f1..3c8c6ec94c1 100644
--- a/tests/ui/unnecessary_filter_map.rs
+++ b/tests/ui/unnecessary_filter_map.rs
@@ -148,3 +148,9 @@ mod comment_1052978898 {
         })
     }
 }
+
+fn issue11260() {
+    // #11260 is about unnecessary_find_map, but the fix also kind of applies to
+    // unnecessary_filter_map
+    let _x = std::iter::once(1).filter_map(|n| (n > 1).then_some(n));
+}
diff --git a/tests/ui/unnecessary_filter_map.stderr b/tests/ui/unnecessary_filter_map.stderr
index 5585b10ab90..2d5403ce394 100644
--- a/tests/ui/unnecessary_filter_map.stderr
+++ b/tests/ui/unnecessary_filter_map.stderr
@@ -34,5 +34,11 @@ error: this `.filter_map` can be written more simply using `.map`
 LL |     let _ = (0..4).filter_map(|x| Some(x + 1));
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
-error: aborting due to 4 previous errors
+error: this `.filter_map` can be written more simply using `.filter`
+  --> $DIR/unnecessary_filter_map.rs:155:14
+   |
+LL |     let _x = std::iter::once(1).filter_map(|n| (n > 1).then_some(n));
+   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 5 previous errors
 
diff --git a/tests/ui/unnecessary_find_map.rs b/tests/ui/unnecessary_find_map.rs
index a52390861b4..2c228fbbc95 100644
--- a/tests/ui/unnecessary_find_map.rs
+++ b/tests/ui/unnecessary_find_map.rs
@@ -21,3 +21,9 @@ fn main() {
 fn find_map_none_changes_item_type() -> Option<bool> {
     "".chars().find_map(|_| None)
 }
+
+fn issue11260() {
+    let y = Some(1);
+    let _x = std::iter::once(1).find_map(|n| (n > 1).then_some(n));
+    let _x = std::iter::once(1).find_map(|n| (n > 1).then_some(y)); // different option, so can't be just `.find()`
+}
diff --git a/tests/ui/unnecessary_find_map.stderr b/tests/ui/unnecessary_find_map.stderr
index fb33c122fe3..3a995b41b17 100644
--- a/tests/ui/unnecessary_find_map.stderr
+++ b/tests/ui/unnecessary_find_map.stderr
@@ -34,5 +34,11 @@ error: this `.find_map` can be written more simply using `.map(..).next()`
 LL |     let _ = (0..4).find_map(|x| Some(x + 1));
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
-error: aborting due to 4 previous errors
+error: this `.find_map` can be written more simply using `.find`
+  --> $DIR/unnecessary_find_map.rs:27:14
+   |
+LL |     let _x = std::iter::once(1).find_map(|n| (n > 1).then_some(n));
+   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 5 previous errors
 
diff --git a/tests/ui/unnecessary_literal_unwrap.fixed b/tests/ui/unnecessary_literal_unwrap.fixed
index 276cd800b89..72d52c62355 100644
--- a/tests/ui/unnecessary_literal_unwrap.fixed
+++ b/tests/ui/unnecessary_literal_unwrap.fixed
@@ -16,12 +16,23 @@ fn unwrap_option_some() {
     1;
 }
 
+#[rustfmt::skip] // force rustfmt not to remove braces in `|| { 234 }`
 fn unwrap_option_none() {
     let _val = panic!();
     let _val = panic!("this always happens");
+    let _val: String = String::default();
+    let _val: u16 = 234;
+    let _val: u16 = 234;
+    let _val: u16 = { 234 };
+    let _val: u16 =  { 234 };
 
     panic!();
     panic!("this always happens");
+    String::default();
+    234;
+    234;
+    { 234 };
+     { 234 };
 }
 
 fn unwrap_result_ok() {
diff --git a/tests/ui/unnecessary_literal_unwrap.rs b/tests/ui/unnecessary_literal_unwrap.rs
index 3065778d779..7d713ea205f 100644
--- a/tests/ui/unnecessary_literal_unwrap.rs
+++ b/tests/ui/unnecessary_literal_unwrap.rs
@@ -16,12 +16,23 @@ fn unwrap_option_some() {
     Some(1).expect("this never happens");
 }
 
+#[rustfmt::skip] // force rustfmt not to remove braces in `|| { 234 }`
 fn unwrap_option_none() {
     let _val = None::<()>.unwrap();
     let _val = None::<()>.expect("this always happens");
+    let _val: String = None.unwrap_or_default();
+    let _val: u16 = None.unwrap_or(234);
+    let _val: u16 = None.unwrap_or_else(|| 234);
+    let _val: u16 = None.unwrap_or_else(|| { 234 });
+    let _val: u16 = None.unwrap_or_else(|| -> u16 { 234 });
 
     None::<()>.unwrap();
     None::<()>.expect("this always happens");
+    None::<String>.unwrap_or_default();
+    None::<u16>.unwrap_or(234);
+    None::<u16>.unwrap_or_else(|| 234);
+    None::<u16>.unwrap_or_else(|| { 234 });
+    None::<u16>.unwrap_or_else(|| -> u16 { 234 });
 }
 
 fn unwrap_result_ok() {
diff --git a/tests/ui/unnecessary_literal_unwrap.stderr b/tests/ui/unnecessary_literal_unwrap.stderr
index 5823313b736..7f603d6ef58 100644
--- a/tests/ui/unnecessary_literal_unwrap.stderr
+++ b/tests/ui/unnecessary_literal_unwrap.stderr
@@ -48,13 +48,13 @@ LL +     1;
    |
 
 error: used `unwrap()` on `None` value
-  --> $DIR/unnecessary_literal_unwrap.rs:20:16
+  --> $DIR/unnecessary_literal_unwrap.rs:21:16
    |
 LL |     let _val = None::<()>.unwrap();
    |                ^^^^^^^^^^^^^^^^^^^ help: remove the `None` and `unwrap()`: `panic!()`
 
 error: used `expect()` on `None` value
-  --> $DIR/unnecessary_literal_unwrap.rs:21:16
+  --> $DIR/unnecessary_literal_unwrap.rs:22:16
    |
 LL |     let _val = None::<()>.expect("this always happens");
    |                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -64,14 +64,68 @@ help: remove the `None` and `expect()`
 LL |     let _val = panic!("this always happens");
    |                ~~~~~~~                     ~
 
+error: used `unwrap_or_default()` on `None` value
+  --> $DIR/unnecessary_literal_unwrap.rs:23:24
+   |
+LL |     let _val: String = None.unwrap_or_default();
+   |                        ^^^^^^^^^^^^^^^^^^^^^^^^ help: remove the `None` and `unwrap_or_default()`: `String::default()`
+
+error: used `unwrap_or()` on `None` value
+  --> $DIR/unnecessary_literal_unwrap.rs:24:21
+   |
+LL |     let _val: u16 = None.unwrap_or(234);
+   |                     ^^^^^^^^^^^^^^^^^^^
+   |
+help: remove the `None` and `unwrap_or()`
+   |
+LL -     let _val: u16 = None.unwrap_or(234);
+LL +     let _val: u16 = 234;
+   |
+
+error: used `unwrap_or_else()` on `None` value
+  --> $DIR/unnecessary_literal_unwrap.rs:25:21
+   |
+LL |     let _val: u16 = None.unwrap_or_else(|| 234);
+   |                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: remove the `None` and `unwrap_or_else()`
+   |
+LL -     let _val: u16 = None.unwrap_or_else(|| 234);
+LL +     let _val: u16 = 234;
+   |
+
+error: used `unwrap_or_else()` on `None` value
+  --> $DIR/unnecessary_literal_unwrap.rs:26:21
+   |
+LL |     let _val: u16 = None.unwrap_or_else(|| { 234 });
+   |                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: remove the `None` and `unwrap_or_else()`
+   |
+LL -     let _val: u16 = None.unwrap_or_else(|| { 234 });
+LL +     let _val: u16 = { 234 };
+   |
+
+error: used `unwrap_or_else()` on `None` value
+  --> $DIR/unnecessary_literal_unwrap.rs:27:21
+   |
+LL |     let _val: u16 = None.unwrap_or_else(|| -> u16 { 234 });
+   |                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: remove the `None` and `unwrap_or_else()`
+   |
+LL -     let _val: u16 = None.unwrap_or_else(|| -> u16 { 234 });
+LL +     let _val: u16 =  { 234 };
+   |
+
 error: used `unwrap()` on `None` value
-  --> $DIR/unnecessary_literal_unwrap.rs:23:5
+  --> $DIR/unnecessary_literal_unwrap.rs:29:5
    |
 LL |     None::<()>.unwrap();
    |     ^^^^^^^^^^^^^^^^^^^ help: remove the `None` and `unwrap()`: `panic!()`
 
 error: used `expect()` on `None` value
-  --> $DIR/unnecessary_literal_unwrap.rs:24:5
+  --> $DIR/unnecessary_literal_unwrap.rs:30:5
    |
 LL |     None::<()>.expect("this always happens");
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -81,8 +135,62 @@ help: remove the `None` and `expect()`
 LL |     panic!("this always happens");
    |     ~~~~~~~                     ~
 
+error: used `unwrap_or_default()` on `None` value
+  --> $DIR/unnecessary_literal_unwrap.rs:31:5
+   |
+LL |     None::<String>.unwrap_or_default();
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: remove the `None` and `unwrap_or_default()`: `String::default()`
+
+error: used `unwrap_or()` on `None` value
+  --> $DIR/unnecessary_literal_unwrap.rs:32:5
+   |
+LL |     None::<u16>.unwrap_or(234);
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: remove the `None` and `unwrap_or()`
+   |
+LL -     None::<u16>.unwrap_or(234);
+LL +     234;
+   |
+
+error: used `unwrap_or_else()` on `None` value
+  --> $DIR/unnecessary_literal_unwrap.rs:33:5
+   |
+LL |     None::<u16>.unwrap_or_else(|| 234);
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: remove the `None` and `unwrap_or_else()`
+   |
+LL -     None::<u16>.unwrap_or_else(|| 234);
+LL +     234;
+   |
+
+error: used `unwrap_or_else()` on `None` value
+  --> $DIR/unnecessary_literal_unwrap.rs:34:5
+   |
+LL |     None::<u16>.unwrap_or_else(|| { 234 });
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: remove the `None` and `unwrap_or_else()`
+   |
+LL -     None::<u16>.unwrap_or_else(|| { 234 });
+LL +     { 234 };
+   |
+
+error: used `unwrap_or_else()` on `None` value
+  --> $DIR/unnecessary_literal_unwrap.rs:35:5
+   |
+LL |     None::<u16>.unwrap_or_else(|| -> u16 { 234 });
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: remove the `None` and `unwrap_or_else()`
+   |
+LL -     None::<u16>.unwrap_or_else(|| -> u16 { 234 });
+LL +      { 234 };
+   |
+
 error: used `unwrap()` on `Ok` value
-  --> $DIR/unnecessary_literal_unwrap.rs:28:16
+  --> $DIR/unnecessary_literal_unwrap.rs:39:16
    |
 LL |     let _val = Ok::<_, ()>(1).unwrap();
    |                ^^^^^^^^^^^^^^^^^^^^^^^
@@ -94,7 +202,7 @@ LL +     let _val = 1;
    |
 
 error: used `expect()` on `Ok` value
-  --> $DIR/unnecessary_literal_unwrap.rs:29:16
+  --> $DIR/unnecessary_literal_unwrap.rs:40:16
    |
 LL |     let _val = Ok::<_, ()>(1).expect("this never happens");
    |                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -106,7 +214,7 @@ LL +     let _val = 1;
    |
 
 error: used `unwrap_err()` on `Ok` value
-  --> $DIR/unnecessary_literal_unwrap.rs:30:16
+  --> $DIR/unnecessary_literal_unwrap.rs:41:16
    |
 LL |     let _val = Ok::<_, ()>(1).unwrap_err();
    |                ^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -117,7 +225,7 @@ LL |     let _val = panic!("{:?}", 1);
    |                ~~~~~~~~~~~~~~  ~
 
 error: used `expect_err()` on `Ok` value
-  --> $DIR/unnecessary_literal_unwrap.rs:31:16
+  --> $DIR/unnecessary_literal_unwrap.rs:42:16
    |
 LL |     let _val = Ok::<_, ()>(1).expect_err("this always happens");
    |                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -128,7 +236,7 @@ LL |     let _val = panic!("{1}: {:?}", 1, "this always happens");
    |                ~~~~~~~~~~~~~~~~~~~  ~
 
 error: used `unwrap()` on `Ok` value
-  --> $DIR/unnecessary_literal_unwrap.rs:33:5
+  --> $DIR/unnecessary_literal_unwrap.rs:44:5
    |
 LL |     Ok::<_, ()>(1).unwrap();
    |     ^^^^^^^^^^^^^^^^^^^^^^^
@@ -140,7 +248,7 @@ LL +     1;
    |
 
 error: used `expect()` on `Ok` value
-  --> $DIR/unnecessary_literal_unwrap.rs:34:5
+  --> $DIR/unnecessary_literal_unwrap.rs:45:5
    |
 LL |     Ok::<_, ()>(1).expect("this never happens");
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -152,7 +260,7 @@ LL +     1;
    |
 
 error: used `unwrap_err()` on `Ok` value
-  --> $DIR/unnecessary_literal_unwrap.rs:35:5
+  --> $DIR/unnecessary_literal_unwrap.rs:46:5
    |
 LL |     Ok::<_, ()>(1).unwrap_err();
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -163,7 +271,7 @@ LL |     panic!("{:?}", 1);
    |     ~~~~~~~~~~~~~~  ~
 
 error: used `expect_err()` on `Ok` value
-  --> $DIR/unnecessary_literal_unwrap.rs:36:5
+  --> $DIR/unnecessary_literal_unwrap.rs:47:5
    |
 LL |     Ok::<_, ()>(1).expect_err("this always happens");
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -174,7 +282,7 @@ LL |     panic!("{1}: {:?}", 1, "this always happens");
    |     ~~~~~~~~~~~~~~~~~~~  ~
 
 error: used `unwrap_err()` on `Err` value
-  --> $DIR/unnecessary_literal_unwrap.rs:40:16
+  --> $DIR/unnecessary_literal_unwrap.rs:51:16
    |
 LL |     let _val = Err::<(), _>(1).unwrap_err();
    |                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -186,7 +294,7 @@ LL +     let _val = 1;
    |
 
 error: used `expect_err()` on `Err` value
-  --> $DIR/unnecessary_literal_unwrap.rs:41:16
+  --> $DIR/unnecessary_literal_unwrap.rs:52:16
    |
 LL |     let _val = Err::<(), _>(1).expect_err("this never happens");
    |                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -198,7 +306,7 @@ LL +     let _val = 1;
    |
 
 error: used `unwrap()` on `Err` value
-  --> $DIR/unnecessary_literal_unwrap.rs:42:16
+  --> $DIR/unnecessary_literal_unwrap.rs:53:16
    |
 LL |     let _val = Err::<(), _>(1).unwrap();
    |                ^^^^^^^^^^^^^^^^^^^^^^^^
@@ -209,7 +317,7 @@ LL |     let _val = panic!("{:?}", 1);
    |                ~~~~~~~~~~~~~~  ~
 
 error: used `expect()` on `Err` value
-  --> $DIR/unnecessary_literal_unwrap.rs:43:16
+  --> $DIR/unnecessary_literal_unwrap.rs:54:16
    |
 LL |     let _val = Err::<(), _>(1).expect("this always happens");
    |                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -220,7 +328,7 @@ LL |     let _val = panic!("{1}: {:?}", 1, "this always happens");
    |                ~~~~~~~~~~~~~~~~~~~  ~
 
 error: used `unwrap_err()` on `Err` value
-  --> $DIR/unnecessary_literal_unwrap.rs:45:5
+  --> $DIR/unnecessary_literal_unwrap.rs:56:5
    |
 LL |     Err::<(), _>(1).unwrap_err();
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -232,7 +340,7 @@ LL +     1;
    |
 
 error: used `expect_err()` on `Err` value
-  --> $DIR/unnecessary_literal_unwrap.rs:46:5
+  --> $DIR/unnecessary_literal_unwrap.rs:57:5
    |
 LL |     Err::<(), _>(1).expect_err("this never happens");
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -244,7 +352,7 @@ LL +     1;
    |
 
 error: used `unwrap()` on `Err` value
-  --> $DIR/unnecessary_literal_unwrap.rs:47:5
+  --> $DIR/unnecessary_literal_unwrap.rs:58:5
    |
 LL |     Err::<(), _>(1).unwrap();
    |     ^^^^^^^^^^^^^^^^^^^^^^^^
@@ -255,7 +363,7 @@ LL |     panic!("{:?}", 1);
    |     ~~~~~~~~~~~~~~  ~
 
 error: used `expect()` on `Err` value
-  --> $DIR/unnecessary_literal_unwrap.rs:48:5
+  --> $DIR/unnecessary_literal_unwrap.rs:59:5
    |
 LL |     Err::<(), _>(1).expect("this always happens");
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -266,7 +374,7 @@ LL |     panic!("{1}: {:?}", 1, "this always happens");
    |     ~~~~~~~~~~~~~~~~~~~  ~
 
 error: used `unwrap_or()` on `Some` value
-  --> $DIR/unnecessary_literal_unwrap.rs:52:16
+  --> $DIR/unnecessary_literal_unwrap.rs:63:16
    |
 LL |     let _val = Some(1).unwrap_or(2);
    |                ^^^^^^^^^^^^^^^^^^^^
@@ -278,7 +386,7 @@ LL +     let _val = 1;
    |
 
 error: used `unwrap_or_default()` on `Some` value
-  --> $DIR/unnecessary_literal_unwrap.rs:53:16
+  --> $DIR/unnecessary_literal_unwrap.rs:64:16
    |
 LL |     let _val = Some(1).unwrap_or_default();
    |                ^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -290,7 +398,7 @@ LL +     let _val = 1;
    |
 
 error: used `unwrap_or_else()` on `Some` value
-  --> $DIR/unnecessary_literal_unwrap.rs:54:16
+  --> $DIR/unnecessary_literal_unwrap.rs:65:16
    |
 LL |     let _val = Some(1).unwrap_or_else(|| 2);
    |                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -302,7 +410,7 @@ LL +     let _val = 1;
    |
 
 error: used `unwrap_or()` on `Some` value
-  --> $DIR/unnecessary_literal_unwrap.rs:56:5
+  --> $DIR/unnecessary_literal_unwrap.rs:67:5
    |
 LL |     Some(1).unwrap_or(2);
    |     ^^^^^^^^^^^^^^^^^^^^
@@ -314,7 +422,7 @@ LL +     1;
    |
 
 error: used `unwrap_or_default()` on `Some` value
-  --> $DIR/unnecessary_literal_unwrap.rs:57:5
+  --> $DIR/unnecessary_literal_unwrap.rs:68:5
    |
 LL |     Some(1).unwrap_or_default();
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -326,7 +434,7 @@ LL +     1;
    |
 
 error: used `unwrap_or_else()` on `Some` value
-  --> $DIR/unnecessary_literal_unwrap.rs:58:5
+  --> $DIR/unnecessary_literal_unwrap.rs:69:5
    |
 LL |     Some(1).unwrap_or_else(|| 2);
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -338,7 +446,7 @@ LL +     1;
    |
 
 error: used `unwrap_or()` on `Ok` value
-  --> $DIR/unnecessary_literal_unwrap.rs:62:16
+  --> $DIR/unnecessary_literal_unwrap.rs:73:16
    |
 LL |     let _val = Ok::<_, ()>(1).unwrap_or(2);
    |                ^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -350,7 +458,7 @@ LL +     let _val = 1;
    |
 
 error: used `unwrap_or_default()` on `Ok` value
-  --> $DIR/unnecessary_literal_unwrap.rs:63:16
+  --> $DIR/unnecessary_literal_unwrap.rs:74:16
    |
 LL |     let _val = Ok::<_, ()>(1).unwrap_or_default();
    |                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -362,7 +470,7 @@ LL +     let _val = 1;
    |
 
 error: used `unwrap_or_else()` on `Ok` value
-  --> $DIR/unnecessary_literal_unwrap.rs:64:16
+  --> $DIR/unnecessary_literal_unwrap.rs:75:16
    |
 LL |     let _val = Ok::<_, ()>(1).unwrap_or_else(|_| 2);
    |                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -374,7 +482,7 @@ LL +     let _val = 1;
    |
 
 error: used `unwrap_or()` on `Ok` value
-  --> $DIR/unnecessary_literal_unwrap.rs:66:5
+  --> $DIR/unnecessary_literal_unwrap.rs:77:5
    |
 LL |     Ok::<_, ()>(1).unwrap_or(2);
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -386,7 +494,7 @@ LL +     1;
    |
 
 error: used `unwrap_or_default()` on `Ok` value
-  --> $DIR/unnecessary_literal_unwrap.rs:67:5
+  --> $DIR/unnecessary_literal_unwrap.rs:78:5
    |
 LL |     Ok::<_, ()>(1).unwrap_or_default();
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -398,7 +506,7 @@ LL +     1;
    |
 
 error: used `unwrap_or_else()` on `Ok` value
-  --> $DIR/unnecessary_literal_unwrap.rs:68:5
+  --> $DIR/unnecessary_literal_unwrap.rs:79:5
    |
 LL |     Ok::<_, ()>(1).unwrap_or_else(|_| 2);
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -410,7 +518,7 @@ LL +     1;
    |
 
 error: used `unwrap_unchecked()` on `Some` value
-  --> $DIR/unnecessary_literal_unwrap.rs:82:22
+  --> $DIR/unnecessary_literal_unwrap.rs:93:22
    |
 LL |     let _ = unsafe { Some(1).unwrap_unchecked() };
    |                      ^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -422,7 +530,7 @@ LL +     let _ = 1;
    |
 
 error: used `unwrap_unchecked()` on `Some` value
-  --> $DIR/unnecessary_literal_unwrap.rs:83:22
+  --> $DIR/unnecessary_literal_unwrap.rs:94:22
    |
 LL |     let _ = unsafe { Some(1).unwrap_unchecked() + *(&1 as *const i32) }; // needs to keep the unsafe block
    |                      ^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -434,7 +542,7 @@ LL +     let _ = unsafe { 1 + *(&1 as *const i32) }; // needs to keep the unsafe
    |
 
 error: used `unwrap_unchecked()` on `Some` value
-  --> $DIR/unnecessary_literal_unwrap.rs:84:22
+  --> $DIR/unnecessary_literal_unwrap.rs:95:22
    |
 LL |     let _ = unsafe { Some(1).unwrap_unchecked() } + 1;
    |                      ^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -446,7 +554,7 @@ LL +     let _ = 1 + 1;
    |
 
 error: used `unwrap_unchecked()` on `Ok` value
-  --> $DIR/unnecessary_literal_unwrap.rs:85:22
+  --> $DIR/unnecessary_literal_unwrap.rs:96:22
    |
 LL |     let _ = unsafe { Ok::<_, ()>(1).unwrap_unchecked() };
    |                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -458,7 +566,7 @@ LL +     let _ = 1;
    |
 
 error: used `unwrap_unchecked()` on `Ok` value
-  --> $DIR/unnecessary_literal_unwrap.rs:86:22
+  --> $DIR/unnecessary_literal_unwrap.rs:97:22
    |
 LL |     let _ = unsafe { Ok::<_, ()>(1).unwrap_unchecked() + *(&1 as *const i32) };
    |                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -470,7 +578,7 @@ LL +     let _ = unsafe { 1 + *(&1 as *const i32) };
    |
 
 error: used `unwrap_unchecked()` on `Ok` value
-  --> $DIR/unnecessary_literal_unwrap.rs:87:22
+  --> $DIR/unnecessary_literal_unwrap.rs:98:22
    |
 LL |     let _ = unsafe { Ok::<_, ()>(1).unwrap_unchecked() } + 1;
    |                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -482,7 +590,7 @@ LL +     let _ = 1 + 1;
    |
 
 error: used `unwrap_err_unchecked()` on `Err` value
-  --> $DIR/unnecessary_literal_unwrap.rs:88:22
+  --> $DIR/unnecessary_literal_unwrap.rs:99:22
    |
 LL |     let _ = unsafe { Err::<(), i32>(123).unwrap_err_unchecked() };
    |                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -493,5 +601,5 @@ LL -     let _ = unsafe { Err::<(), i32>(123).unwrap_err_unchecked() };
 LL +     let _ = 123;
    |
 
-error: aborting due to 43 previous errors
+error: aborting due to 53 previous errors
 
diff --git a/tests/ui/unnecessary_literal_unwrap_unfixable.rs b/tests/ui/unnecessary_literal_unwrap_unfixable.rs
index 711fdce3962..41300aceb41 100644
--- a/tests/ui/unnecessary_literal_unwrap_unfixable.rs
+++ b/tests/ui/unnecessary_literal_unwrap_unfixable.rs
@@ -21,6 +21,8 @@ fn unwrap_option_none() {
     let val = None::<()>;
     let _val2 = val.unwrap();
     let _val2 = val.expect("this always happens");
+    let _val3: u8 = None.unwrap_or_default();
+    None::<()>.unwrap_or_default();
 }
 
 fn unwrap_result_ok() {
diff --git a/tests/ui/unnecessary_literal_unwrap_unfixable.stderr b/tests/ui/unnecessary_literal_unwrap_unfixable.stderr
index feb9325b77a..2d1270d4717 100644
--- a/tests/ui/unnecessary_literal_unwrap_unfixable.stderr
+++ b/tests/ui/unnecessary_literal_unwrap_unfixable.stderr
@@ -95,509 +95,521 @@ help: remove the `None` and `expect()`
 LL |     let val = None::<()>;
    |               ^^^^^^^^^^
 
+error: used `unwrap_or_default()` on `None` value
+  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:24:21
+   |
+LL |     let _val3: u8 = None.unwrap_or_default();
+   |                     ^^^^^^^^^^^^^^^^^^^^^^^^ help: remove the `None` and `unwrap_or_default()`: `Default::default()`
+
+error: used `unwrap_or_default()` on `None` value
+  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:25:5
+   |
+LL |     None::<()>.unwrap_or_default();
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: remove the `None` and `unwrap_or_default()`: `Default::default()`
+
 error: used `unwrap()` on `Ok` value
-  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:28:17
+  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:30:17
    |
 LL |     let _val2 = val.unwrap();
    |                 ^^^^^^^^^^^^
    |
 help: remove the `Ok` and `unwrap()`
-  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:27:15
+  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:29:15
    |
 LL |     let val = Ok::<_, ()>(1);
    |               ^^^^^^^^^^^^^^
 
 error: used `expect()` on `Ok` value
-  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:29:17
+  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:31:17
    |
 LL |     let _val2 = val.expect("this never happens");
    |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
 help: remove the `Ok` and `expect()`
-  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:27:15
+  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:29:15
    |
 LL |     let val = Ok::<_, ()>(1);
    |               ^^^^^^^^^^^^^^
 
 error: used `unwrap_err()` on `Ok` value
-  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:30:17
+  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:32:17
    |
 LL |     let _val2 = val.unwrap_err();
    |                 ^^^^^^^^^^^^^^^^
    |
 help: remove the `Ok` and `unwrap_err()`
-  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:27:15
+  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:29:15
    |
 LL |     let val = Ok::<_, ()>(1);
    |               ^^^^^^^^^^^^^^
 
 error: used `expect_err()` on `Ok` value
-  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:31:17
+  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:33:17
    |
 LL |     let _val2 = val.expect_err("this always happens");
    |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
 help: remove the `Ok` and `expect_err()`
-  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:27:15
+  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:29:15
    |
 LL |     let val = Ok::<_, ()>(1);
    |               ^^^^^^^^^^^^^^
 
 error: used `unwrap()` on `Ok` value
-  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:35:16
+  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:37:16
    |
 LL |     let _val = Ok::<usize, ()>([1, 2, 3].iter().sum()).unwrap();
    |                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
 help: remove the `Ok` and `unwrap()`
-  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:35:16
+  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:37:16
    |
 LL |     let _val = Ok::<usize, ()>([1, 2, 3].iter().sum()).unwrap();
    |                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: used `expect()` on `Ok` value
-  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:36:16
+  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:38:16
    |
 LL |     let _val = Ok::<usize, ()>([1, 2, 3].iter().sum()).expect("this never happens");
    |                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
 help: remove the `Ok` and `expect()`
-  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:36:16
+  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:38:16
    |
 LL |     let _val = Ok::<usize, ()>([1, 2, 3].iter().sum()).expect("this never happens");
    |                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: used `unwrap_err()` on `Ok` value
-  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:37:16
+  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:39:16
    |
 LL |     let _val = Ok::<usize, ()>([1, 2, 3].iter().sum()).unwrap_err();
    |                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
 help: remove the `Ok` and `unwrap_err()`
-  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:37:16
+  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:39:16
    |
 LL |     let _val = Ok::<usize, ()>([1, 2, 3].iter().sum()).unwrap_err();
    |                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: used `expect_err()` on `Ok` value
-  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:38:16
+  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:40:16
    |
 LL |     let _val = Ok::<usize, ()>([1, 2, 3].iter().sum()).expect_err("this always happens");
    |                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
 help: remove the `Ok` and `expect_err()`
-  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:38:16
+  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:40:16
    |
 LL |     let _val = Ok::<usize, ()>([1, 2, 3].iter().sum()).expect_err("this always happens");
    |                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: used `unwrap()` on `Ok` value
-  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:41:17
+  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:43:17
    |
 LL |     let _val2 = val.unwrap();
    |                 ^^^^^^^^^^^^
    |
 help: remove the `Ok` and `unwrap()`
-  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:40:15
+  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:42:15
    |
 LL |     let val = Ok::<usize, ()>([1, 2, 3].iter().sum());
    |               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: used `expect()` on `Ok` value
-  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:42:17
+  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:44:17
    |
 LL |     let _val2 = val.expect("this never happens");
    |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
 help: remove the `Ok` and `expect()`
-  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:40:15
+  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:42:15
    |
 LL |     let val = Ok::<usize, ()>([1, 2, 3].iter().sum());
    |               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: used `unwrap_err()` on `Ok` value
-  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:43:17
+  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:45:17
    |
 LL |     let _val2 = val.unwrap_err();
    |                 ^^^^^^^^^^^^^^^^
    |
 help: remove the `Ok` and `unwrap_err()`
-  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:40:15
+  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:42:15
    |
 LL |     let val = Ok::<usize, ()>([1, 2, 3].iter().sum());
    |               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: used `expect_err()` on `Ok` value
-  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:44:17
+  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:46:17
    |
 LL |     let _val2 = val.expect_err("this always happens");
    |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
 help: remove the `Ok` and `expect_err()`
-  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:40:15
+  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:42:15
    |
 LL |     let val = Ok::<usize, ()>([1, 2, 3].iter().sum());
    |               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: used `unwrap_err()` on `Err` value
-  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:49:17
+  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:51:17
    |
 LL |     let _val2 = val.unwrap_err();
    |                 ^^^^^^^^^^^^^^^^
    |
 help: remove the `Err` and `unwrap_err()`
-  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:48:15
+  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:50:15
    |
 LL |     let val = Err::<(), _>(1);
    |               ^^^^^^^^^^^^^^^
 
 error: used `expect_err()` on `Err` value
-  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:50:17
+  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:52:17
    |
 LL |     let _val2 = val.expect_err("this never happens");
    |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
 help: remove the `Err` and `expect_err()`
-  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:48:15
+  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:50:15
    |
 LL |     let val = Err::<(), _>(1);
    |               ^^^^^^^^^^^^^^^
 
 error: used `unwrap()` on `Err` value
-  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:51:17
+  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:53:17
    |
 LL |     let _val2 = val.unwrap();
    |                 ^^^^^^^^^^^^
    |
 help: remove the `Err` and `unwrap()`
-  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:48:15
+  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:50:15
    |
 LL |     let val = Err::<(), _>(1);
    |               ^^^^^^^^^^^^^^^
 
 error: used `expect()` on `Err` value
-  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:52:17
+  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:54:17
    |
 LL |     let _val2 = val.expect("this always happens");
    |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
 help: remove the `Err` and `expect()`
-  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:48:15
+  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:50:15
    |
 LL |     let val = Err::<(), _>(1);
    |               ^^^^^^^^^^^^^^^
 
 error: used `unwrap_err()` on `Err` value
-  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:56:16
+  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:58:16
    |
 LL |     let _val = Err::<(), usize>([1, 2, 3].iter().sum()).unwrap_err();
    |                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
 help: remove the `Err` and `unwrap_err()`
-  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:56:16
+  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:58:16
    |
 LL |     let _val = Err::<(), usize>([1, 2, 3].iter().sum()).unwrap_err();
    |                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: used `expect_err()` on `Err` value
-  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:57:16
+  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:59:16
    |
 LL |     let _val = Err::<(), usize>([1, 2, 3].iter().sum()).expect_err("this never happens");
    |                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
 help: remove the `Err` and `expect_err()`
-  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:57:16
+  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:59:16
    |
 LL |     let _val = Err::<(), usize>([1, 2, 3].iter().sum()).expect_err("this never happens");
    |                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: used `unwrap()` on `Err` value
-  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:58:16
+  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:60:16
    |
 LL |     let _val = Err::<(), usize>([1, 2, 3].iter().sum()).unwrap();
    |                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
 help: remove the `Err` and `unwrap()`
-  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:58:16
+  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:60:16
    |
 LL |     let _val = Err::<(), usize>([1, 2, 3].iter().sum()).unwrap();
    |                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: used `expect()` on `Err` value
-  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:59:16
+  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:61:16
    |
 LL |     let _val = Err::<(), usize>([1, 2, 3].iter().sum()).expect("this always happens");
    |                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
 help: remove the `Err` and `expect()`
-  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:59:16
+  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:61:16
    |
 LL |     let _val = Err::<(), usize>([1, 2, 3].iter().sum()).expect("this always happens");
    |                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: used `unwrap_err()` on `Err` value
-  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:62:17
+  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:64:17
    |
 LL |     let _val2 = val.unwrap_err();
    |                 ^^^^^^^^^^^^^^^^
    |
 help: remove the `Err` and `unwrap_err()`
-  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:61:15
+  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:63:15
    |
 LL |     let val = Err::<(), usize>([1, 2, 3].iter().sum());
    |               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: used `expect_err()` on `Err` value
-  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:63:17
+  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:65:17
    |
 LL |     let _val2 = val.expect_err("this never happens");
    |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
 help: remove the `Err` and `expect_err()`
-  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:61:15
+  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:63:15
    |
 LL |     let val = Err::<(), usize>([1, 2, 3].iter().sum());
    |               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: used `unwrap()` on `Err` value
-  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:64:17
+  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:66:17
    |
 LL |     let _val2 = val.unwrap();
    |                 ^^^^^^^^^^^^
    |
 help: remove the `Err` and `unwrap()`
-  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:61:15
+  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:63:15
    |
 LL |     let val = Err::<(), usize>([1, 2, 3].iter().sum());
    |               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: used `expect()` on `Err` value
-  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:65:17
+  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:67:17
    |
 LL |     let _val2 = val.expect("this always happens");
    |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
 help: remove the `Err` and `expect()`
-  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:61:15
+  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:63:15
    |
 LL |     let val = Err::<(), usize>([1, 2, 3].iter().sum());
    |               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: used `unwrap_or()` on `Some` value
-  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:70:17
+  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:72:17
    |
 LL |     let _val2 = val.unwrap_or(2);
    |                 ^^^^^^^^^^^^^^^^
    |
 help: remove the `Some` and `unwrap_or()`
-  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:69:15
+  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:71:15
    |
 LL |     let val = Some(1);
    |               ^^^^^^^
 
 error: used `unwrap_or_default()` on `Some` value
-  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:71:17
+  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:73:17
    |
 LL |     let _val2 = val.unwrap_or_default();
    |                 ^^^^^^^^^^^^^^^^^^^^^^^
    |
 help: remove the `Some` and `unwrap_or_default()`
-  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:69:15
+  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:71:15
    |
 LL |     let val = Some(1);
    |               ^^^^^^^
 
 error: used `unwrap_or_else()` on `Some` value
-  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:72:17
+  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:74:17
    |
 LL |     let _val2 = val.unwrap_or_else(|| 2);
    |                 ^^^^^^^^^^^^^^^^^^^^^^^^
    |
 help: remove the `Some` and `unwrap_or_else()`
-  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:69:15
+  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:71:15
    |
 LL |     let val = Some(1);
    |               ^^^^^^^
 
 error: used `unwrap_or()` on `Some` value
-  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:76:16
+  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:78:16
    |
 LL |     let _val = Some::<usize>([1, 2, 3].iter().sum()).unwrap_or(2);
    |                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
 help: remove the `Some` and `unwrap_or()`
-  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:76:16
+  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:78:16
    |
 LL |     let _val = Some::<usize>([1, 2, 3].iter().sum()).unwrap_or(2);
    |                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: used `unwrap_or_default()` on `Some` value
-  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:77:16
+  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:79:16
    |
 LL |     let _val = Some::<usize>([1, 2, 3].iter().sum()).unwrap_or_default();
    |                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
 help: remove the `Some` and `unwrap_or_default()`
-  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:77:16
+  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:79:16
    |
 LL |     let _val = Some::<usize>([1, 2, 3].iter().sum()).unwrap_or_default();
    |                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: used `unwrap_or_else()` on `Some` value
-  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:78:16
+  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:80:16
    |
 LL |     let _val = Some::<usize>([1, 2, 3].iter().sum()).unwrap_or_else(|| 2);
    |                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
 help: remove the `Some` and `unwrap_or_else()`
-  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:78:16
+  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:80:16
    |
 LL |     let _val = Some::<usize>([1, 2, 3].iter().sum()).unwrap_or_else(|| 2);
    |                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: used `unwrap_or()` on `Some` value
-  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:81:17
+  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:83:17
    |
 LL |     let _val2 = val.unwrap_or(2);
    |                 ^^^^^^^^^^^^^^^^
    |
 help: remove the `Some` and `unwrap_or()`
-  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:80:15
+  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:82:15
    |
 LL |     let val = Some::<usize>([1, 2, 3].iter().sum());
    |               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: used `unwrap_or_default()` on `Some` value
-  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:82:17
+  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:84:17
    |
 LL |     let _val2 = val.unwrap_or_default();
    |                 ^^^^^^^^^^^^^^^^^^^^^^^
    |
 help: remove the `Some` and `unwrap_or_default()`
-  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:80:15
+  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:82:15
    |
 LL |     let val = Some::<usize>([1, 2, 3].iter().sum());
    |               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: used `unwrap_or_else()` on `Some` value
-  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:83:17
+  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:85:17
    |
 LL |     let _val2 = val.unwrap_or_else(|| 2);
    |                 ^^^^^^^^^^^^^^^^^^^^^^^^
    |
 help: remove the `Some` and `unwrap_or_else()`
-  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:80:15
+  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:82:15
    |
 LL |     let val = Some::<usize>([1, 2, 3].iter().sum());
    |               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: used `unwrap_or()` on `Ok` value
-  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:88:17
+  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:90:17
    |
 LL |     let _val2 = val.unwrap_or(2);
    |                 ^^^^^^^^^^^^^^^^
    |
 help: remove the `Ok` and `unwrap_or()`
-  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:87:15
+  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:89:15
    |
 LL |     let val = Ok::<_, ()>(1);
    |               ^^^^^^^^^^^^^^
 
 error: used `unwrap_or_default()` on `Ok` value
-  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:89:17
+  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:91:17
    |
 LL |     let _val2 = val.unwrap_or_default();
    |                 ^^^^^^^^^^^^^^^^^^^^^^^
    |
 help: remove the `Ok` and `unwrap_or_default()`
-  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:87:15
+  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:89:15
    |
 LL |     let val = Ok::<_, ()>(1);
    |               ^^^^^^^^^^^^^^
 
 error: used `unwrap_or_else()` on `Ok` value
-  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:90:17
+  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:92:17
    |
 LL |     let _val2 = val.unwrap_or_else(|_| 2);
    |                 ^^^^^^^^^^^^^^^^^^^^^^^^^
    |
 help: remove the `Ok` and `unwrap_or_else()`
-  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:87:15
+  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:89:15
    |
 LL |     let val = Ok::<_, ()>(1);
    |               ^^^^^^^^^^^^^^
 
 error: used `unwrap_or()` on `Ok` value
-  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:94:16
+  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:96:16
    |
 LL |     let _val = Ok::<usize, ()>([1, 2, 3].iter().sum()).unwrap_or(2);
    |                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
 help: remove the `Ok` and `unwrap_or()`
-  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:94:16
+  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:96:16
    |
 LL |     let _val = Ok::<usize, ()>([1, 2, 3].iter().sum()).unwrap_or(2);
    |                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: used `unwrap_or_default()` on `Ok` value
-  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:95:16
+  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:97:16
    |
 LL |     let _val = Ok::<usize, ()>([1, 2, 3].iter().sum()).unwrap_or_default();
    |                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
 help: remove the `Ok` and `unwrap_or_default()`
-  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:95:16
+  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:97:16
    |
 LL |     let _val = Ok::<usize, ()>([1, 2, 3].iter().sum()).unwrap_or_default();
    |                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: used `unwrap_or_else()` on `Ok` value
-  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:96:16
+  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:98:16
    |
 LL |     let _val = Ok::<usize, ()>([1, 2, 3].iter().sum()).unwrap_or_else(|_| 2);
    |                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
 help: remove the `Ok` and `unwrap_or_else()`
-  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:96:16
+  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:98:16
    |
 LL |     let _val = Ok::<usize, ()>([1, 2, 3].iter().sum()).unwrap_or_else(|_| 2);
    |                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: used `unwrap_or()` on `Ok` value
-  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:99:17
+  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:101:17
    |
 LL |     let _val2 = val.unwrap_or(2);
    |                 ^^^^^^^^^^^^^^^^
    |
 help: remove the `Ok` and `unwrap_or()`
-  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:98:15
+  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:100:15
    |
 LL |     let val = Ok::<usize, ()>([1, 2, 3].iter().sum());
    |               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: used `unwrap_or_default()` on `Ok` value
-  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:100:17
+  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:102:17
    |
 LL |     let _val2 = val.unwrap_or_default();
    |                 ^^^^^^^^^^^^^^^^^^^^^^^
    |
 help: remove the `Ok` and `unwrap_or_default()`
-  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:98:15
+  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:100:15
    |
 LL |     let val = Ok::<usize, ()>([1, 2, 3].iter().sum());
    |               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: used `unwrap_or_else()` on `Ok` value
-  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:101:17
+  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:103:17
    |
 LL |     let _val2 = val.unwrap_or_else(|_| 2);
    |                 ^^^^^^^^^^^^^^^^^^^^^^^^^
    |
 help: remove the `Ok` and `unwrap_or_else()`
-  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:98:15
+  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:100:15
    |
 LL |     let val = Ok::<usize, ()>([1, 2, 3].iter().sum());
    |               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
-error: aborting due to 50 previous errors
+error: aborting due to 52 previous errors
 
diff --git a/tests/ui/unused_async.rs b/tests/ui/unused_async.rs
index 69e46ab4736..1d188025e41 100644
--- a/tests/ui/unused_async.rs
+++ b/tests/ui/unused_async.rs
@@ -37,6 +37,23 @@ mod issue10459 {
     }
 }
 
+mod issue9695 {
+    use std::future::Future;
+
+    async fn f() {}
+    async fn f2() {}
+    async fn f3() {}
+
+    fn needs_async_fn<F: Future<Output = ()>>(_: fn() -> F) {}
+
+    fn test() {
+        let x = f;
+        needs_async_fn(x); // async needed in f
+        needs_async_fn(f2); // async needed in f2
+        f3(); // async not needed in f3
+    }
+}
+
 async fn foo() -> i32 {
     4
 }
diff --git a/tests/ui/unused_async.stderr b/tests/ui/unused_async.stderr
index ffae8366b88..8d9b72c4886 100644
--- a/tests/ui/unused_async.stderr
+++ b/tests/ui/unused_async.stderr
@@ -17,7 +17,15 @@ LL |             ready(()).await;
    = note: `-D clippy::unused-async` implied by `-D warnings`
 
 error: unused `async` for function with no await statements
-  --> $DIR/unused_async.rs:40:1
+  --> $DIR/unused_async.rs:45:5
+   |
+LL |     async fn f3() {}
+   |     ^^^^^^^^^^^^^^^^
+   |
+   = help: consider removing the `async` from this function
+
+error: unused `async` for function with no await statements
+  --> $DIR/unused_async.rs:57:1
    |
 LL | / async fn foo() -> i32 {
 LL | |     4
@@ -27,7 +35,7 @@ LL | | }
    = help: consider removing the `async` from this function
 
 error: unused `async` for function with no await statements
-  --> $DIR/unused_async.rs:51:5
+  --> $DIR/unused_async.rs:68:5
    |
 LL | /     async fn unused(&self) -> i32 {
 LL | |         1
@@ -36,5 +44,5 @@ LL | |     }
    |
    = help: consider removing the `async` from this function
 
-error: aborting due to 3 previous errors
+error: aborting due to 4 previous errors
 
diff --git a/tests/ui/unwrap.stderr b/tests/ui/unwrap.stderr
index 3796d942ff9..41db819f6fb 100644
--- a/tests/ui/unwrap.stderr
+++ b/tests/ui/unwrap.stderr
@@ -4,7 +4,8 @@ error: used `unwrap()` on an `Option` value
 LL |     let _ = opt.unwrap();
    |             ^^^^^^^^^^^^
    |
-   = help: if you don't want to handle the `None` case gracefully, consider using `expect()` to provide a better panic message
+   = note: if this value is `None`, it will panic
+   = help: consider using `expect()` to provide a better panic message
    = note: `-D clippy::unwrap-used` implied by `-D warnings`
 
 error: used `unwrap()` on a `Result` value
@@ -13,7 +14,8 @@ error: used `unwrap()` on a `Result` value
 LL |     let _ = res.unwrap();
    |             ^^^^^^^^^^^^
    |
-   = help: if you don't want to handle the `Err` case gracefully, consider using `expect()` to provide a better panic message
+   = note: if this value is an `Err`, it will panic
+   = help: consider using `expect()` to provide a better panic message
 
 error: used `unwrap_err()` on a `Result` value
   --> $DIR/unwrap.rs:12:13
@@ -21,7 +23,8 @@ error: used `unwrap_err()` on a `Result` value
 LL |     let _ = res.unwrap_err();
    |             ^^^^^^^^^^^^^^^^
    |
-   = help: if you don't want to handle the `Ok` case gracefully, consider using `expect_err()` to provide a better panic message
+   = note: if this value is an `Ok`, it will panic
+   = help: consider using `expect_err()` to provide a better panic message
 
 error: aborting due to 3 previous errors
 
diff --git a/tests/ui/unwrap_expect_used.rs b/tests/ui/unwrap_expect_used.rs
index 7f57efc53c9..26f92ccdefa 100644
--- a/tests/ui/unwrap_expect_used.rs
+++ b/tests/ui/unwrap_expect_used.rs
@@ -1,5 +1,8 @@
 #![warn(clippy::unwrap_used, clippy::expect_used)]
 #![allow(clippy::unnecessary_literal_unwrap)]
+#![feature(never_type)]
+
+use std::convert::Infallible;
 
 trait OptionExt {
     type Item;
@@ -28,6 +31,14 @@ fn main() {
     Some(3).unwrap_err();
     Some(3).expect_err("Hellow none!");
 
+    // Issue #11245: The `Err` variant can never be constructed so do not lint this.
+    let x: Result<(), !> = Ok(());
+    x.unwrap();
+    x.expect("is `!` (never)");
+    let x: Result<(), Infallible> = Ok(());
+    x.unwrap();
+    x.expect("is never-like (0 variants)");
+
     let a: Result<i32, i32> = Ok(3);
     a.unwrap();
     a.expect("Hello world!");
diff --git a/tests/ui/unwrap_expect_used.stderr b/tests/ui/unwrap_expect_used.stderr
index 1a551ab5ab8..f66e47612ad 100644
--- a/tests/ui/unwrap_expect_used.stderr
+++ b/tests/ui/unwrap_expect_used.stderr
@@ -1,52 +1,52 @@
 error: used `unwrap()` on an `Option` value
-  --> $DIR/unwrap_expect_used.rs:24:5
+  --> $DIR/unwrap_expect_used.rs:27:5
    |
 LL |     Some(3).unwrap();
    |     ^^^^^^^^^^^^^^^^
    |
-   = help: if this value is `None`, it will panic
+   = note: if this value is `None`, it will panic
    = note: `-D clippy::unwrap-used` implied by `-D warnings`
 
 error: used `expect()` on an `Option` value
-  --> $DIR/unwrap_expect_used.rs:25:5
+  --> $DIR/unwrap_expect_used.rs:28:5
    |
 LL |     Some(3).expect("Hello world!");
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
-   = help: if this value is `None`, it will panic
+   = note: if this value is `None`, it will panic
    = note: `-D clippy::expect-used` implied by `-D warnings`
 
 error: used `unwrap()` on a `Result` value
-  --> $DIR/unwrap_expect_used.rs:32:5
+  --> $DIR/unwrap_expect_used.rs:43:5
    |
 LL |     a.unwrap();
    |     ^^^^^^^^^^
    |
-   = help: if this value is an `Err`, it will panic
+   = note: if this value is an `Err`, it will panic
 
 error: used `expect()` on a `Result` value
-  --> $DIR/unwrap_expect_used.rs:33:5
+  --> $DIR/unwrap_expect_used.rs:44:5
    |
 LL |     a.expect("Hello world!");
    |     ^^^^^^^^^^^^^^^^^^^^^^^^
    |
-   = help: if this value is an `Err`, it will panic
+   = note: if this value is an `Err`, it will panic
 
 error: used `unwrap_err()` on a `Result` value
-  --> $DIR/unwrap_expect_used.rs:34:5
+  --> $DIR/unwrap_expect_used.rs:45:5
    |
 LL |     a.unwrap_err();
    |     ^^^^^^^^^^^^^^
    |
-   = help: if this value is an `Ok`, it will panic
+   = note: if this value is an `Ok`, it will panic
 
 error: used `expect_err()` on a `Result` value
-  --> $DIR/unwrap_expect_used.rs:35:5
+  --> $DIR/unwrap_expect_used.rs:46:5
    |
 LL |     a.expect_err("Hello error!");
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
-   = help: if this value is an `Ok`, it will panic
+   = note: if this value is an `Ok`, it will panic
 
 error: aborting due to 6 previous errors
 
diff --git a/tests/ui/unwrap_or_else_default.fixed b/tests/ui/unwrap_or_else_default.fixed
index e6b6ab359df..acdb96942ba 100644
--- a/tests/ui/unwrap_or_else_default.fixed
+++ b/tests/ui/unwrap_or_else_default.fixed
@@ -1,10 +1,10 @@
 //@run-rustfix
 
-#![warn(clippy::unwrap_or_else_default)]
+#![warn(clippy::unwrap_or_default)]
 #![allow(dead_code)]
 #![allow(clippy::unnecessary_wraps, clippy::unnecessary_literal_unwrap)]
 
-/// Checks implementation of the `UNWRAP_OR_ELSE_DEFAULT` lint.
+/// Checks implementation of the `UNWRAP_OR_DEFAULT` lint.
 fn unwrap_or_else_default() {
     struct Foo;
 
@@ -109,6 +109,27 @@ fn type_certainty(option: Option<Vec<u64>>) {
     // should not be changed: no type annotation, unconcretized initializer
     let option = None;
     option.unwrap_or_else(Vec::new).push(1);
+
+    type Alias = Option<Vec<u32>>;
+    let option: Alias = Option::<Vec<u32>>::Some(Vec::new());
+    option.unwrap_or_default().push(1);
+}
+
+fn method_call_with_deref() {
+    use std::cell::RefCell;
+    use std::collections::HashMap;
+
+    let cell = RefCell::new(HashMap::<u64, HashMap<u64, String>>::new());
+
+    let mut outer_map = cell.borrow_mut();
+
+    #[allow(unused_assignments)]
+    let mut option = None;
+    option = Some(0);
+
+    let inner_map = outer_map.get_mut(&option.unwrap()).unwrap();
+
+    let _ = inner_map.entry(0).or_default();
 }
 
 fn main() {}
diff --git a/tests/ui/unwrap_or_else_default.rs b/tests/ui/unwrap_or_else_default.rs
index 38fa2e4595d..55ccd00e1a2 100644
--- a/tests/ui/unwrap_or_else_default.rs
+++ b/tests/ui/unwrap_or_else_default.rs
@@ -1,10 +1,10 @@
 //@run-rustfix
 
-#![warn(clippy::unwrap_or_else_default)]
+#![warn(clippy::unwrap_or_default)]
 #![allow(dead_code)]
 #![allow(clippy::unnecessary_wraps, clippy::unnecessary_literal_unwrap)]
 
-/// Checks implementation of the `UNWRAP_OR_ELSE_DEFAULT` lint.
+/// Checks implementation of the `UNWRAP_OR_DEFAULT` lint.
 fn unwrap_or_else_default() {
     struct Foo;
 
@@ -109,6 +109,27 @@ fn type_certainty(option: Option<Vec<u64>>) {
     // should not be changed: no type annotation, unconcretized initializer
     let option = None;
     option.unwrap_or_else(Vec::new).push(1);
+
+    type Alias = Option<Vec<u32>>;
+    let option: Alias = Option::<Vec<u32>>::Some(Vec::new());
+    option.unwrap_or_else(Vec::new).push(1);
+}
+
+fn method_call_with_deref() {
+    use std::cell::RefCell;
+    use std::collections::HashMap;
+
+    let cell = RefCell::new(HashMap::<u64, HashMap<u64, String>>::new());
+
+    let mut outer_map = cell.borrow_mut();
+
+    #[allow(unused_assignments)]
+    let mut option = None;
+    option = Some(0);
+
+    let inner_map = outer_map.get_mut(&option.unwrap()).unwrap();
+
+    let _ = inner_map.entry(0).or_insert_with(Default::default);
 }
 
 fn main() {}
diff --git a/tests/ui/unwrap_or_else_default.stderr b/tests/ui/unwrap_or_else_default.stderr
index a6815e8f916..af662c6def7 100644
--- a/tests/ui/unwrap_or_else_default.stderr
+++ b/tests/ui/unwrap_or_else_default.stderr
@@ -1,88 +1,100 @@
-error: use of `.unwrap_or_else(..)` to construct default value
-  --> $DIR/unwrap_or_else_default.rs:48:5
+error: use of `unwrap_or_else` to construct default value
+  --> $DIR/unwrap_or_else_default.rs:48:14
    |
 LL |     with_new.unwrap_or_else(Vec::new);
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `with_new.unwrap_or_default()`
+   |              ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_default()`
    |
-   = note: `-D clippy::unwrap-or-else-default` implied by `-D warnings`
+   = note: `-D clippy::unwrap-or-default` implied by `-D warnings`
 
-error: use of `.unwrap_or_else(..)` to construct default value
-  --> $DIR/unwrap_or_else_default.rs:62:5
+error: use of `unwrap_or_else` to construct default value
+  --> $DIR/unwrap_or_else_default.rs:62:23
    |
 LL |     with_real_default.unwrap_or_else(<HasDefaultAndDuplicate as Default>::default);
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `with_real_default.unwrap_or_default()`
+   |                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_default()`
 
-error: use of `.unwrap_or_else(..)` to construct default value
-  --> $DIR/unwrap_or_else_default.rs:65:5
+error: use of `unwrap_or_else` to construct default value
+  --> $DIR/unwrap_or_else_default.rs:65:24
    |
 LL |     with_default_trait.unwrap_or_else(Default::default);
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `with_default_trait.unwrap_or_default()`
+   |                        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_default()`
 
-error: use of `.unwrap_or_else(..)` to construct default value
-  --> $DIR/unwrap_or_else_default.rs:68:5
+error: use of `unwrap_or_else` to construct default value
+  --> $DIR/unwrap_or_else_default.rs:68:23
    |
 LL |     with_default_type.unwrap_or_else(u64::default);
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `with_default_type.unwrap_or_default()`
+   |                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_default()`
 
-error: use of `.unwrap_or_else(..)` to construct default value
-  --> $DIR/unwrap_or_else_default.rs:71:5
+error: use of `unwrap_or_else` to construct default value
+  --> $DIR/unwrap_or_else_default.rs:71:23
    |
 LL |     with_default_type.unwrap_or_else(Vec::new);
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `with_default_type.unwrap_or_default()`
+   |                       ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_default()`
 
-error: use of `.unwrap_or_else(..)` to construct default value
-  --> $DIR/unwrap_or_else_default.rs:74:5
+error: use of `unwrap_or_else` to construct default value
+  --> $DIR/unwrap_or_else_default.rs:74:18
    |
 LL |     empty_string.unwrap_or_else(|| "".to_string());
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `empty_string.unwrap_or_default()`
+   |                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_default()`
 
-error: use of `.unwrap_or_else(..)` to construct default value
-  --> $DIR/unwrap_or_else_default.rs:78:5
+error: use of `unwrap_or_else` to construct default value
+  --> $DIR/unwrap_or_else_default.rs:78:12
    |
 LL |     option.unwrap_or_else(Vec::new).push(1);
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `option.unwrap_or_default()`
+   |            ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_default()`
 
-error: use of `.unwrap_or_else(..)` to construct default value
-  --> $DIR/unwrap_or_else_default.rs:81:5
+error: use of `unwrap_or_else` to construct default value
+  --> $DIR/unwrap_or_else_default.rs:81:12
    |
 LL |     option.unwrap_or_else(Vec::new).push(1);
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `option.unwrap_or_default()`
+   |            ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_default()`
 
-error: use of `.unwrap_or_else(..)` to construct default value
-  --> $DIR/unwrap_or_else_default.rs:84:5
+error: use of `unwrap_or_else` to construct default value
+  --> $DIR/unwrap_or_else_default.rs:84:12
    |
 LL |     option.unwrap_or_else(Vec::new).push(1);
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `option.unwrap_or_default()`
+   |            ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_default()`
 
-error: use of `.unwrap_or_else(..)` to construct default value
-  --> $DIR/unwrap_or_else_default.rs:87:5
+error: use of `unwrap_or_else` to construct default value
+  --> $DIR/unwrap_or_else_default.rs:87:12
    |
 LL |     option.unwrap_or_else(Vec::new).push(1);
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `option.unwrap_or_default()`
+   |            ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_default()`
 
-error: use of `.unwrap_or_else(..)` to construct default value
-  --> $DIR/unwrap_or_else_default.rs:90:5
+error: use of `unwrap_or_else` to construct default value
+  --> $DIR/unwrap_or_else_default.rs:90:12
    |
 LL |     option.unwrap_or_else(Vec::new).push(1);
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `option.unwrap_or_default()`
+   |            ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_default()`
 
-error: use of `.unwrap_or_else(..)` to construct default value
-  --> $DIR/unwrap_or_else_default.rs:93:5
+error: use of `unwrap_or_else` to construct default value
+  --> $DIR/unwrap_or_else_default.rs:93:12
    |
 LL |     option.unwrap_or_else(Vec::new).push(1);
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `option.unwrap_or_default()`
+   |            ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_default()`
 
-error: use of `.unwrap_or_else(..)` to construct default value
-  --> $DIR/unwrap_or_else_default.rs:96:5
+error: use of `unwrap_or_else` to construct default value
+  --> $DIR/unwrap_or_else_default.rs:96:12
    |
 LL |     option.unwrap_or_else(Vec::new).push(1);
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `option.unwrap_or_default()`
+   |            ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_default()`
 
-error: use of `.unwrap_or_else(..)` to construct default value
-  --> $DIR/unwrap_or_else_default.rs:99:5
+error: use of `unwrap_or_else` to construct default value
+  --> $DIR/unwrap_or_else_default.rs:99:12
    |
 LL |     option.unwrap_or_else(Vec::new).push(1);
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `option.unwrap_or_default()`
+   |            ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_default()`
 
-error: aborting due to 14 previous errors
+error: use of `unwrap_or_else` to construct default value
+  --> $DIR/unwrap_or_else_default.rs:115:12
+   |
+LL |     option.unwrap_or_else(Vec::new).push(1);
+   |            ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_default()`
+
+error: use of `or_insert_with` to construct default value
+  --> $DIR/unwrap_or_else_default.rs:132:32
+   |
+LL |     let _ = inner_map.entry(0).or_insert_with(Default::default);
+   |                                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `or_default()`
+
+error: aborting due to 16 previous errors
 
diff --git a/triagebot.toml b/triagebot.toml
index c40b71f6ca7..6856bb0ab37 100644
--- a/triagebot.toml
+++ b/triagebot.toml
@@ -9,6 +9,9 @@ allow-unauthenticated = [
 # See https://github.com/rust-lang/triagebot/wiki/Shortcuts
 [shortcut]
 
+# Have rustbot inform users about the *No Merge Policy*
+[no-merges]
+
 [autolabel."S-waiting-on-review"]
 new_pr = true
 
@@ -27,4 +30,6 @@ contributing_url = "https://github.com/rust-lang/rust-clippy/blob/master/CONTRIB
     "@Alexendoo",
     "@dswij",
     "@Jarcho",
+    "@blyxyas",
+    "@Centri3",
 ]