about summary refs log tree commit diff
diff options
context:
space:
mode:
authorPhilipp Krones <hello@philkrones.com>2023-06-02 11:41:57 +0200
committerPhilipp Krones <hello@philkrones.com>2023-06-02 11:41:57 +0200
commit1c161271de14f3c3e252e729a0344735914cde3a (patch)
tree835e7d5b683bccfda69ee916d990352564c73a8e
parent33c3d101280c8eb3cd8af421bfb56a8afcc3881d (diff)
parent30448e8cf98d4754350db0c959644564f317bc0f (diff)
downloadrust-1c161271de14f3c3e252e729a0344735914cde3a.tar.gz
rust-1c161271de14f3c3e252e729a0344735914cde3a.zip
Merge commit '30448e8cf98d4754350db0c959644564f317bc0f' into clippyup
-rw-r--r--src/tools/clippy/.github/ISSUE_TEMPLATE/new_lint.yml23
-rw-r--r--src/tools/clippy/CHANGELOG.md130
-rw-r--r--src/tools/clippy/Cargo.toml9
-rw-r--r--src/tools/clippy/book/src/configuration.md10
-rw-r--r--src/tools/clippy/book/src/development/adding_lints.md10
-rw-r--r--src/tools/clippy/clippy_dev/src/main.rs4
-rw-r--r--src/tools/clippy/clippy_lints/Cargo.toml10
-rw-r--r--src/tools/clippy/clippy_lints/src/allow_attributes.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/booleans.rs5
-rw-r--r--src/tools/clippy/clippy_lints/src/casts/mod.rs33
-rw-r--r--src/tools/clippy/clippy_lints/src/casts/ptr_cast_constness.rs44
-rw-r--r--src/tools/clippy/clippy_lints/src/collection_is_never_read.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/declared_lints.rs3
-rw-r--r--src/tools/clippy/clippy_lints/src/default_constructed_unit_structs.rs15
-rw-r--r--src/tools/clippy/clippy_lints/src/large_futures.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/large_stack_arrays.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/let_with_type_underscore.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/lib.rs43
-rw-r--r--src/tools/clippy/clippy_lints/src/manual_let_else.rs164
-rw-r--r--src/tools/clippy/clippy_lints/src/matches/match_wild_err_arm.rs7
-rw-r--r--src/tools/clippy/clippy_lints/src/matches/mod.rs8
-rw-r--r--src/tools/clippy/clippy_lints/src/matches/redundant_pattern_match.rs21
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/mod.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/missing_assert_message.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/missing_fields_in_debug.rs234
-rw-r--r--src/tools/clippy/clippy_lints/src/needless_else.rs61
-rw-r--r--src/tools/clippy/clippy_lints/src/nonstandard_macro_braces.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/redundant_async_block.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/regex.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/returns.rs28
-rw-r--r--src/tools/clippy/clippy_lints/src/strings.rs5
-rw-r--r--src/tools/clippy/clippy_lints/src/unused_async.rs50
-rw-r--r--src/tools/clippy/clippy_lints/src/utils/conf.rs209
-rw-r--r--src/tools/clippy/clippy_lints/src/wildcard_imports.rs9
-rw-r--r--src/tools/clippy/clippy_utils/Cargo.toml2
-rw-r--r--src/tools/clippy/clippy_utils/src/lib.rs2
-rw-r--r--src/tools/clippy/clippy_utils/src/msrvs.rs2
-rw-r--r--src/tools/clippy/clippy_utils/src/paths.rs4
-rw-r--r--src/tools/clippy/clippy_utils/src/source.rs13
-rw-r--r--src/tools/clippy/declare_clippy_lint/Cargo.toml2
-rw-r--r--src/tools/clippy/lintcheck/Cargo.toml2
-rw-r--r--src/tools/clippy/rust-toolchain2
-rw-r--r--src/tools/clippy/src/driver.rs15
-rw-r--r--src/tools/clippy/tests/ui-cargo/multiple_crate_versions/fail/Cargo.lock67
-rw-r--r--src/tools/clippy/tests/ui-cargo/multiple_crate_versions/fail/Cargo.toml2
-rw-r--r--src/tools/clippy/tests/ui-internal/custom_ice_message.rs2
-rw-r--r--src/tools/clippy/tests/ui-internal/custom_ice_message.stderr7
-rw-r--r--src/tools/clippy/tests/ui-toml/bad_toml/conf_bad_toml.stderr6
-rw-r--r--src/tools/clippy/tests/ui-toml/bad_toml_type/conf_bad_type.stderr6
-rw-r--r--src/tools/clippy/tests/ui-toml/conf_deprecated_key/conf_deprecated_key.stderr12
-rw-r--r--src/tools/clippy/tests/ui-toml/duplicated_keys/clippy.toml3
-rw-r--r--src/tools/clippy/tests/ui-toml/duplicated_keys/duplicated_keys.stderr12
-rw-r--r--src/tools/clippy/tests/ui-toml/duplicated_keys_deprecated/clippy.toml3
-rw-r--r--src/tools/clippy/tests/ui-toml/duplicated_keys_deprecated/duplicated_keys.rs1
-rw-r--r--src/tools/clippy/tests/ui-toml/duplicated_keys_deprecated/duplicated_keys.stderr14
-rw-r--r--src/tools/clippy/tests/ui-toml/duplicated_keys_deprecated_2/clippy.toml4
-rw-r--r--src/tools/clippy/tests/ui-toml/duplicated_keys_deprecated_2/duplicated_keys.rs1
-rw-r--r--src/tools/clippy/tests/ui-toml/duplicated_keys_deprecated_2/duplicated_keys.stderr14
-rw-r--r--src/tools/clippy/tests/ui-toml/ifs_same_cond/ifs_same_cond.rs2
-rw-r--r--src/tools/clippy/tests/ui-toml/toml_unknown_key/clippy.toml4
-rw-r--r--src/tools/clippy/tests/ui-toml/toml_unknown_key/conf_unknown_key.stderr70
-rw-r--r--src/tools/clippy/tests/ui/auxiliary/wildcard_imports_helper.rs6
-rw-r--r--src/tools/clippy/tests/ui/branches_sharing_code/valid_if_blocks.rs6
-rw-r--r--src/tools/clippy/tests/ui/branches_sharing_code/valid_if_blocks.stderr20
-rw-r--r--src/tools/clippy/tests/ui/crashes/ice-7410.rs1
-rw-r--r--src/tools/clippy/tests/ui/default_constructed_unit_structs.fixed22
-rw-r--r--src/tools/clippy/tests/ui/default_constructed_unit_structs.rs22
-rw-r--r--src/tools/clippy/tests/ui/default_constructed_unit_structs.stderr8
-rw-r--r--src/tools/clippy/tests/ui/ifs_same_cond.rs2
-rw-r--r--src/tools/clippy/tests/ui/large_stack_arrays.rs13
-rw-r--r--src/tools/clippy/tests/ui/large_stack_arrays.stderr30
-rw-r--r--src/tools/clippy/tests/ui/manual_let_else.rs16
-rw-r--r--src/tools/clippy/tests/ui/manual_let_else.stderr35
-rw-r--r--src/tools/clippy/tests/ui/manual_let_else_match.rs2
-rw-r--r--src/tools/clippy/tests/ui/manual_let_else_match.stderr4
-rw-r--r--src/tools/clippy/tests/ui/match_wild_err_arm.rs15
-rw-r--r--src/tools/clippy/tests/ui/match_wild_err_arm.stderr8
-rw-r--r--src/tools/clippy/tests/ui/missing_fields_in_debug.rs191
-rw-r--r--src/tools/clippy/tests/ui/missing_fields_in_debug.stderr73
-rw-r--r--src/tools/clippy/tests/ui/needless_else.fixed57
-rw-r--r--src/tools/clippy/tests/ui/needless_else.rs58
-rw-r--r--src/tools/clippy/tests/ui/needless_else.stderr12
-rw-r--r--src/tools/clippy/tests/ui/needless_return.fixed3
-rw-r--r--src/tools/clippy/tests/ui/needless_return.rs3
-rw-r--r--src/tools/clippy/tests/ui/needless_return.stderr426
-rw-r--r--src/tools/clippy/tests/ui/nonminimal_bool.rs14
-rw-r--r--src/tools/clippy/tests/ui/ptr_cast_constness.fixed55
-rw-r--r--src/tools/clippy/tests/ui/ptr_cast_constness.rs55
-rw-r--r--src/tools/clippy/tests/ui/ptr_cast_constness.stderr34
-rw-r--r--src/tools/clippy/tests/ui/redundant_pattern_matching_drop_order.fixed2
-rw-r--r--src/tools/clippy/tests/ui/redundant_pattern_matching_drop_order.rs2
-rw-r--r--src/tools/clippy/tests/ui/redundant_pattern_matching_option.fixed12
-rw-r--r--src/tools/clippy/tests/ui/redundant_pattern_matching_option.rs12
-rw-r--r--src/tools/clippy/tests/ui/redundant_pattern_matching_option.stderr44
-rw-r--r--src/tools/clippy/tests/ui/redundant_pattern_matching_result.fixed15
-rw-r--r--src/tools/clippy/tests/ui/redundant_pattern_matching_result.rs15
-rw-r--r--src/tools/clippy/tests/ui/redundant_pattern_matching_result.stderr46
-rw-r--r--src/tools/clippy/tests/ui/regex.rs7
-rw-r--r--src/tools/clippy/tests/ui/regex.stderr30
-rw-r--r--src/tools/clippy/tests/ui/rename.fixed1
-rw-r--r--src/tools/clippy/tests/ui/rename.rs1
-rw-r--r--src/tools/clippy/tests/ui/rename.stderr100
-rw-r--r--src/tools/clippy/tests/ui/single_match.fixed209
-rw-r--r--src/tools/clippy/tests/ui/single_match.rs25
-rw-r--r--src/tools/clippy/tests/ui/single_match.stderr44
-rw-r--r--src/tools/clippy/tests/ui/single_match_else.fixed173
-rw-r--r--src/tools/clippy/tests/ui/single_match_else.rs88
-rw-r--r--src/tools/clippy/tests/ui/single_match_else.stderr98
-rw-r--r--src/tools/clippy/tests/ui/suspicious_else_formatting.rs2
-rw-r--r--src/tools/clippy/tests/ui/unused_async.rs20
-rw-r--r--src/tools/clippy/tests/ui/unused_async.stderr25
-rw-r--r--src/tools/clippy/tests/ui/wildcard_imports.fixed2
-rw-r--r--src/tools/clippy/tests/ui/wildcard_imports.rs2
-rw-r--r--src/tools/clippy/tests/ui/wildcard_imports.stderr30
114 files changed, 2971 insertions, 654 deletions
diff --git a/src/tools/clippy/.github/ISSUE_TEMPLATE/new_lint.yml b/src/tools/clippy/.github/ISSUE_TEMPLATE/new_lint.yml
index 0b43d8d70c0..b49493edce1 100644
--- a/src/tools/clippy/.github/ISSUE_TEMPLATE/new_lint.yml
+++ b/src/tools/clippy/.github/ISSUE_TEMPLATE/new_lint.yml
@@ -12,29 +12,6 @@ body:
       description: What does this lint do?
     validations:
       required: true
-  - type: input
-    id: lint-name
-    attributes:
-      label: Lint Name
-      description: Please provide the lint name.
-  - type: dropdown
-    id: category
-    attributes:
-      label: Category
-      description: >
-        What category should this lint go into? If you're unsure you can select
-        multiple categories. You can find a category description in the
-        `README`.
-      multiple: true
-      options:
-        - correctness
-        - suspicious
-        - style
-        - complexity
-        - perf
-        - pedantic
-        - restriction
-        - cargo
   - type: textarea
     id: advantage
     attributes:
diff --git a/src/tools/clippy/CHANGELOG.md b/src/tools/clippy/CHANGELOG.md
index 79f2a47110b..8b609b47d81 100644
--- a/src/tools/clippy/CHANGELOG.md
+++ b/src/tools/clippy/CHANGELOG.md
@@ -6,7 +6,132 @@ document.
 
 ## Unreleased / Beta / In Rust Nightly
 
-[149392b0...master](https://github.com/rust-lang/rust-clippy/compare/149392b0...master)
+[83e42a23...master](https://github.com/rust-lang/rust-clippy/compare/83e42a23...master)
+
+## Rust 1.70
+
+Current beta, released 2023-06-01
+
+[149392b0...83e42a23](https://github.com/rust-lang/rust-clippy/compare/149392b0...83e42a23)
+
+### New Lints
+
+* [`large_futures`]
+  [#10414](https://github.com/rust-lang/rust-clippy/pull/10414)
+* [`missing_assert_message`]
+  [#10362](https://github.com/rust-lang/rust-clippy/pull/10362)
+* [`clear_with_drain`]
+  [#10528](https://github.com/rust-lang/rust-clippy/pull/10528)
+* [`redundant_async_block`]
+  [#10448](https://github.com/rust-lang/rust-clippy/pull/10448)
+* [`collection_is_never_read`]
+  [#10415](https://github.com/rust-lang/rust-clippy/pull/10415)
+* [`let_with_type_underscore`]
+  [#10467](https://github.com/rust-lang/rust-clippy/pull/10467)
+* [`tests_outside_test_module`]
+  [#10543](https://github.com/rust-lang/rust-clippy/pull/10543)
+* [`allow_attributes`]
+  [#10481](https://github.com/rust-lang/rust-clippy/pull/10481)
+* [`suspicious_doc_comments`]
+  [#10497](https://github.com/rust-lang/rust-clippy/pull/10497)
+* [`unnecessary_box_returns`]
+  [#9102](https://github.com/rust-lang/rust-clippy/pull/9102)
+* [`manual_main_separator_str`]
+  [#10483](https://github.com/rust-lang/rust-clippy/pull/10483)
+* [`unnecessary_struct_initialization`]
+  [#10489](https://github.com/rust-lang/rust-clippy/pull/10489)
+* [`manual_slice_size_calculation`]
+  [#10601](https://github.com/rust-lang/rust-clippy/pull/10601)
+* [`lines_filter_map_ok`]
+  [#10534](https://github.com/rust-lang/rust-clippy/pull/10534)
+
+### Moves and Deprecations
+
+* Moved [`let_underscore_untyped`] to `restriction`
+  [#10442](https://github.com/rust-lang/rust-clippy/pull/10442)
+
+### Enhancements
+
+* [`extra_unused_type_parameters`]: No longer lints on public items if `avoid-breaking-exported-api` is set
+  [#10536](https://github.com/rust-lang/rust-clippy/pull/10536)
+* [`len_without_is_empty`]: Now also detects `async` functions
+  [#10359](https://github.com/rust-lang/rust-clippy/pull/10359)
+* [`arithmetic_side_effects`]: Now correctly handles divisions and modulo expressions if the right-hand-side
+  is unknown
+  [#10585](https://github.com/rust-lang/rust-clippy/pull/10585)
+* [`nonminimal_bool`]: No longer ignores `#[allow]` attributes
+  [#10588](https://github.com/rust-lang/rust-clippy/pull/10588)
+* [`uninit_vec`], [`uninit_assumed_init`]: Now uses a better heuristic
+  [#10520](https://github.com/rust-lang/rust-clippy/pull/10520)
+* [`ifs_same_cond`]: Now also detects immutable method calls.
+  [#10350](https://github.com/rust-lang/rust-clippy/pull/10350)
+* [`arithmetic_side_effects`]: No longer lints on right or left shifts with constant integers, as the
+  compiler warns about them
+  [#10309](https://github.com/rust-lang/rust-clippy/pull/10309)
+* [`items_after_statements`]: `#[allow(items_after_statements)]` now works on items
+  [#10542](https://github.com/rust-lang/rust-clippy/pull/10542)
+* [`significant_drop_tightening`]: Was optimized
+  [#10533](https://github.com/rust-lang/rust-clippy/pull/10533)
+
+### False Positive Fixes
+
+* [`single_component_path_imports`]: No longer lints if the import is used relative to `self`
+  [#10566](https://github.com/rust-lang/rust-clippy/pull/10566)
+* [`derivable_impls`]: No longer suggests deriving `Default` on generics with implicit arguments
+  [#10399](https://github.com/rust-lang/rust-clippy/pull/10399)
+* [`let_unit_value`]: No longer lints if the expression contains an `await`
+  [#10439](https://github.com/rust-lang/rust-clippy/pull/10439)
+* [`double_must_use`]: Now ignores `async` functions
+  [#10589](https://github.com/rust-lang/rust-clippy/pull/10589)
+* [`manual_clamp`]: No longer lints in constant context
+  [#10479](https://github.com/rust-lang/rust-clippy/pull/10479)
+* [`almost_swapped`]: Now ignores external macros
+  [#10502](https://github.com/rust-lang/rust-clippy/pull/10502)
+* [`nonminimal_bool`]: Now ignores macros
+  [#10527](https://github.com/rust-lang/rust-clippy/pull/10527)
+* [`needless_return`]: No longer lints match statements with incompatible branches
+  [#10593](https://github.com/rust-lang/rust-clippy/pull/10593)
+* [`use_self`]: Do not suggest using `Self` in const generic parameters
+  [#10375](https://github.com/rust-lang/rust-clippy/pull/10375)
+* [`mem_replace_option_with_none`]: No longer lints on field expressions
+  [#10594](https://github.com/rust-lang/rust-clippy/pull/10594)
+* [`items_after_statements`]: No longer lints on times from macros
+  [#10542](https://github.com/rust-lang/rust-clippy/pull/10542)
+* [`print_literal`], [`write_literal`]: No longer lint strings coming from the `file!()` macro
+  [#10573](https://github.com/rust-lang/rust-clippy/pull/10573)
+* [`uninit_vec`], [`uninit_assumed_init`]: Now check the types inside arrays and tuples
+  [#10553](https://github.com/rust-lang/rust-clippy/pull/10553)
+* [`almost_swapped`]: No longer lints if a variable is assigned to itself
+  [#10499](https://github.com/rust-lang/rust-clippy/pull/10499)
+* [`missing_docs_in_private_items`]: No longer lints on public items
+  [#10324](https://github.com/rust-lang/rust-clippy/pull/10324)
+
+### Suggestion Fixes/Improvements
+
+* [`extra_unused_type_parameters`]: The suggestion is now machine applicable
+  [#10536](https://github.com/rust-lang/rust-clippy/pull/10536)
+* [`match_single_binding`]: Now adds a semicolon after the suggestion
+  [#10470](https://github.com/rust-lang/rust-clippy/pull/10470)
+* [`missing_const_for_fn`]: Now includes a note if the change could break compatibility
+  [#10618](https://github.com/rust-lang/rust-clippy/pull/10618)
+* [`cast_possible_truncation`]: Corrected suggestion for float and wildcard casts
+  [#10496](https://github.com/rust-lang/rust-clippy/pull/10496)
+* [`transmutes_expressible_as_ptr_casts`]: The suggestion now includes parentheses when they are required
+  [#10454](https://github.com/rust-lang/rust-clippy/pull/10454)
+
+### ICE Fixes
+
+* [`needless_borrow`]: No longer panics on ambiguous projections
+  [#10403](https://github.com/rust-lang/rust-clippy/pull/10403)
+* [`multiple_unsafe_ops_per_block`]: Fix ICE when calling a function-like object in an unsafe block
+  [#10405](https://github.com/rust-lang/rust-clippy/pull/10405)
+
+### Others
+
+* `clippy-driver` now searches parent directories for `clippy.toml` files
+  [#10592](https://github.com/rust-lang/rust-clippy/pull/10592)
+* Fixed a deserialization error for the `array-size-threshold` config value
+  [#10423](https://github.com/rust-lang/rust-clippy/pull/10423)
 
 ## Rust 1.69
 
@@ -4838,6 +4963,7 @@ Released 2018-09-13
 [`missing_docs_in_private_items`]: https://rust-lang.github.io/rust-clippy/master/index.html#missing_docs_in_private_items
 [`missing_enforced_import_renames`]: https://rust-lang.github.io/rust-clippy/master/index.html#missing_enforced_import_renames
 [`missing_errors_doc`]: https://rust-lang.github.io/rust-clippy/master/index.html#missing_errors_doc
+[`missing_fields_in_debug`]: https://rust-lang.github.io/rust-clippy/master/index.html#missing_fields_in_debug
 [`missing_inline_in_public_items`]: https://rust-lang.github.io/rust-clippy/master/index.html#missing_inline_in_public_items
 [`missing_panics_doc`]: https://rust-lang.github.io/rust-clippy/master/index.html#missing_panics_doc
 [`missing_safety_doc`]: https://rust-lang.github.io/rust-clippy/master/index.html#missing_safety_doc
@@ -4874,6 +5000,7 @@ Released 2018-09-13
 [`needless_collect`]: https://rust-lang.github.io/rust-clippy/master/index.html#needless_collect
 [`needless_continue`]: https://rust-lang.github.io/rust-clippy/master/index.html#needless_continue
 [`needless_doctest_main`]: https://rust-lang.github.io/rust-clippy/master/index.html#needless_doctest_main
+[`needless_else`]: https://rust-lang.github.io/rust-clippy/master/index.html#needless_else
 [`needless_for_each`]: https://rust-lang.github.io/rust-clippy/master/index.html#needless_for_each
 [`needless_late_init`]: https://rust-lang.github.io/rust-clippy/master/index.html#needless_late_init
 [`needless_lifetimes`]: https://rust-lang.github.io/rust-clippy/master/index.html#needless_lifetimes
@@ -4949,6 +5076,7 @@ Released 2018-09-13
 [`println_empty_string`]: https://rust-lang.github.io/rust-clippy/master/index.html#println_empty_string
 [`ptr_arg`]: https://rust-lang.github.io/rust-clippy/master/index.html#ptr_arg
 [`ptr_as_ptr`]: https://rust-lang.github.io/rust-clippy/master/index.html#ptr_as_ptr
+[`ptr_cast_constness`]: https://rust-lang.github.io/rust-clippy/master/index.html#ptr_cast_constness
 [`ptr_eq`]: https://rust-lang.github.io/rust-clippy/master/index.html#ptr_eq
 [`ptr_offset_with_cast`]: https://rust-lang.github.io/rust-clippy/master/index.html#ptr_offset_with_cast
 [`pub_enum_variant_names`]: https://rust-lang.github.io/rust-clippy/master/index.html#pub_enum_variant_names
diff --git a/src/tools/clippy/Cargo.toml b/src/tools/clippy/Cargo.toml
index 3c72bb62ed1..ca8bf9fac91 100644
--- a/src/tools/clippy/Cargo.toml
+++ b/src/tools/clippy/Cargo.toml
@@ -1,6 +1,6 @@
 [package]
 name = "clippy"
-version = "0.1.71"
+version = "0.1.72"
 description = "A bunch of helpful lints to avoid common pitfalls in Rust"
 repository = "https://github.com/rust-lang/rust-clippy"
 readme = "README.md"
@@ -30,16 +30,11 @@ termize = "0.1"
 compiletest_rs = { version = "0.10", features = ["tmp"] }
 tester = "0.9"
 regex = "1.5"
-toml = "0.5"
+toml = "0.7.3"
 walkdir = "2.3"
 # This is used by the `collect-metadata` alias.
 filetime = "0.2"
 
-# A noop dependency that changes in the Rust repository, it's a bit of a hack.
-# See the `src/tools/rustc-workspace-hack/README.md` file in `rust-lang/rust`
-# for more information.
-rustc-workspace-hack = "1.0"
-
 # UI test dependencies
 clap = { version = "4.1.4", features = ["derive"] }
 clippy_utils = { path = "clippy_utils" }
diff --git a/src/tools/clippy/book/src/configuration.md b/src/tools/clippy/book/src/configuration.md
index 1304f6a8c2f..e8274bc4575 100644
--- a/src/tools/clippy/book/src/configuration.md
+++ b/src/tools/clippy/book/src/configuration.md
@@ -2,8 +2,14 @@
 
 > **Note:** The configuration file is unstable and may be deprecated in the future.
 
-Some lints can be configured in a TOML file named `clippy.toml` or `.clippy.toml`. It contains a
-basic `variable = value` mapping e.g.
+Some lints can be configured in a TOML file named `clippy.toml` or `.clippy.toml`, which is searched for in:
+
+1. The directory specified by the `CLIPPY_CONF_DIR` environment variable, or
+2. The directory specified by the
+[CARGO_MANIFEST_DIR](https://doc.rust-lang.org/cargo/reference/environment-variables.html) environment variable, or
+3. The current directory.
+
+It contains a basic `variable = value` mapping e.g.
 
 ```toml
 avoid-breaking-exported-api = false
diff --git a/src/tools/clippy/book/src/development/adding_lints.md b/src/tools/clippy/book/src/development/adding_lints.md
index ccae8d37420..c26aa883eba 100644
--- a/src/tools/clippy/book/src/development/adding_lints.md
+++ b/src/tools/clippy/book/src/development/adding_lints.md
@@ -630,8 +630,14 @@ Before submitting your PR make sure you followed all the basic requirements:
 
 ## Adding configuration to a lint
 
-Clippy supports the configuration of lints values using a `clippy.toml` file in
-the workspace directory. Adding a configuration to a lint can be useful for
+Clippy supports the configuration of lints values using a `clippy.toml` file which is searched for in:
+
+1. The directory specified by the `CLIPPY_CONF_DIR` environment variable, or
+2. The directory specified by the
+[CARGO_MANIFEST_DIR](https://doc.rust-lang.org/cargo/reference/environment-variables.html) environment variable, or
+3. The current directory.
+
+Adding a configuration to a lint can be useful for
 thresholds or to constrain some behavior that can be seen as a false positive
 for some users. Adding a configuration is done in the following steps:
 
diff --git a/src/tools/clippy/clippy_dev/src/main.rs b/src/tools/clippy/clippy_dev/src/main.rs
index e2457e5a8a5..c03fbe9d275 100644
--- a/src/tools/clippy/clippy_dev/src/main.rs
+++ b/src/tools/clippy/clippy_dev/src/main.rs
@@ -5,6 +5,7 @@
 use clap::{Arg, ArgAction, ArgMatches, Command};
 use clippy_dev::{bless, dogfood, fmt, lint, new_lint, serve, setup, update_lints};
 use indoc::indoc;
+use std::convert::Infallible;
 
 fn main() {
     let matches = get_clap_config();
@@ -180,7 +181,8 @@ fn get_clap_config() -> ArgMatches {
                         .short('n')
                         .long("name")
                         .help("Name of the new lint in snake case, ex: fn_too_long")
-                        .required(true),
+                        .required(true)
+                        .value_parser(|name: &str| Ok::<_, Infallible>(name.replace('-', "_"))),
                     Arg::new("category")
                         .short('c')
                         .long("category")
diff --git a/src/tools/clippy/clippy_lints/Cargo.toml b/src/tools/clippy/clippy_lints/Cargo.toml
index 98e69c7fd26..be9261a4704 100644
--- a/src/tools/clippy/clippy_lints/Cargo.toml
+++ b/src/tools/clippy/clippy_lints/Cargo.toml
@@ -1,6 +1,6 @@
 [package]
 name = "clippy_lints"
-version = "0.1.71"
+version = "0.1.72"
 description = "A bunch of helpful lints to avoid common pitfalls in Rust"
 repository = "https://github.com/rust-lang/rust-clippy"
 readme = "README.md"
@@ -20,15 +20,13 @@ quine-mc_cluskey = "0.2"
 regex-syntax = "0.7"
 serde = { version = "1.0", features = ["derive"] }
 serde_json = { version = "1.0", optional = true }
-tempfile = { version = "3.2", optional = true }
-toml = "0.5"
+tempfile = { version = "3.3.0", optional = true }
+toml = "0.7.3"
 unicode-normalization = "0.1"
 unicode-script = { version = "0.5", default-features = false }
 semver = "1.0"
 rustc-semver = "1.1"
-# NOTE: cargo requires serde feat in its url dep
-# see <https://github.com/rust-lang/rust/pull/63587#issuecomment-522343864>
-url = { version = "2.2", features = ["serde"] }
+url = "2.2"
 
 [features]
 deny-warnings = ["clippy_utils/deny-warnings"]
diff --git a/src/tools/clippy/clippy_lints/src/allow_attributes.rs b/src/tools/clippy/clippy_lints/src/allow_attributes.rs
index add73d0aeee..554efdc58e1 100644
--- a/src/tools/clippy/clippy_lints/src/allow_attributes.rs
+++ b/src/tools/clippy/clippy_lints/src/allow_attributes.rs
@@ -40,7 +40,7 @@ declare_clippy_lint! {
     ///     a.len()
     /// }
     /// ```
-    #[clippy::version = "1.69.0"]
+    #[clippy::version = "1.70.0"]
     pub ALLOW_ATTRIBUTES,
     restriction,
     "`#[allow]` will not trigger if a warning isn't found. `#[expect]` triggers if there are no warnings."
diff --git a/src/tools/clippy/clippy_lints/src/booleans.rs b/src/tools/clippy/clippy_lints/src/booleans.rs
index 455f0df7cd0..ff0102255a0 100644
--- a/src/tools/clippy/clippy_lints/src/booleans.rs
+++ b/src/tools/clippy/clippy_lints/src/booleans.rs
@@ -88,7 +88,6 @@ impl<'tcx> LateLintPass<'tcx> for NonminimalBool {
         NonminimalBoolVisitor { cx }.visit_body(body);
     }
 }
-
 struct NonminimalBoolVisitor<'a, 'tcx> {
     cx: &'a LateContext<'tcx>,
 }
@@ -473,6 +472,10 @@ impl<'a, 'tcx> Visitor<'tcx> for NonminimalBoolVisitor<'a, 'tcx> {
                     self.bool_expr(e);
                 },
                 ExprKind::Unary(UnOp::Not, inner) => {
+                    if let ExprKind::Unary(UnOp::Not, ex) = inner.kind &&
+                    !self.cx.typeck_results().node_types()[ex.hir_id].is_bool() {
+                        return;
+                    }
                     if self.cx.typeck_results().node_types()[inner.hir_id].is_bool() {
                         self.bool_expr(e);
                     }
diff --git a/src/tools/clippy/clippy_lints/src/casts/mod.rs b/src/tools/clippy/clippy_lints/src/casts/mod.rs
index 0c175372aab..b90dab07a27 100644
--- a/src/tools/clippy/clippy_lints/src/casts/mod.rs
+++ b/src/tools/clippy/clippy_lints/src/casts/mod.rs
@@ -17,6 +17,7 @@ mod fn_to_numeric_cast;
 mod fn_to_numeric_cast_any;
 mod fn_to_numeric_cast_with_truncation;
 mod ptr_as_ptr;
+mod ptr_cast_constness;
 mod unnecessary_cast;
 mod utils;
 
@@ -363,7 +364,7 @@ declare_clippy_lint! {
     /// namely `*const T` to `*const U` and `*mut T` to `*mut U`.
     ///
     /// ### Why is this bad?
-    /// Though `as` casts between raw pointers is not terrible, `pointer::cast` is safer because
+    /// Though `as` casts between raw pointers are not terrible, `pointer::cast` is safer because
     /// it cannot accidentally change the pointer's mutability nor cast the pointer to other types like `usize`.
     ///
     /// ### Example
@@ -388,6 +389,34 @@ declare_clippy_lint! {
 
 declare_clippy_lint! {
     /// ### What it does
+    /// Checks for `as` casts between raw pointers which change its constness, namely `*const T` to
+    /// `*mut T` and `*mut T` to `*const T`.
+    ///
+    /// ### Why is this bad?
+    /// Though `as` casts between raw pointers are not terrible, `pointer::cast_mut` and
+    /// `pointer::cast_const` are safer because they cannot accidentally cast the pointer to another
+    /// type.
+    ///
+    /// ### Example
+    /// ```rust
+    /// let ptr: *const u32 = &42_u32;
+    /// let mut_ptr = ptr as *mut u32;
+    /// let ptr = mut_ptr as *const u32;
+    /// ```
+    /// Use instead:
+    /// ```rust
+    /// let ptr: *const u32 = &42_u32;
+    /// let mut_ptr = ptr.cast_mut();
+    /// let ptr = mut_ptr.cast_const();
+    /// ```
+    #[clippy::version = "1.71.0"]
+    pub PTR_CAST_CONSTNESS,
+    pedantic,
+    "casting using `as` from and to raw pointers to change constness when specialized methods apply"
+}
+
+declare_clippy_lint! {
+    /// ### What it does
     /// Checks for casts from an enum type to an integral type which will definitely truncate the
     /// value.
     ///
@@ -652,6 +681,7 @@ impl_lint_pass!(Casts => [
     FN_TO_NUMERIC_CAST_WITH_TRUNCATION,
     CHAR_LIT_AS_U8,
     PTR_AS_PTR,
+    PTR_CAST_CONSTNESS,
     CAST_ENUM_TRUNCATION,
     CAST_ENUM_CONSTRUCTOR,
     CAST_ABS_TO_UNSIGNED,
@@ -685,6 +715,7 @@ impl<'tcx> LateLintPass<'tcx> for Casts {
                 return;
             }
             cast_slice_from_raw_parts::check(cx, expr, cast_expr, cast_to, &self.msrv);
+            ptr_cast_constness::check(cx, expr, cast_expr, cast_from, cast_to, &self.msrv);
             as_ptr_cast_mut::check(cx, expr, cast_expr, cast_to);
             fn_to_numeric_cast_any::check(cx, expr, cast_expr, cast_from, cast_to);
             fn_to_numeric_cast::check(cx, expr, cast_expr, cast_from, cast_to);
diff --git a/src/tools/clippy/clippy_lints/src/casts/ptr_cast_constness.rs b/src/tools/clippy/clippy_lints/src/casts/ptr_cast_constness.rs
new file mode 100644
index 00000000000..ab015f8822e
--- /dev/null
+++ b/src/tools/clippy/clippy_lints/src/casts/ptr_cast_constness.rs
@@ -0,0 +1,44 @@
+use clippy_utils::msrvs::POINTER_CAST_CONSTNESS;
+use clippy_utils::sugg::Sugg;
+use clippy_utils::{diagnostics::span_lint_and_sugg, msrvs::Msrv};
+use if_chain::if_chain;
+use rustc_errors::Applicability;
+use rustc_hir::{Expr, Mutability};
+use rustc_lint::LateContext;
+use rustc_middle::ty::{self, Ty, TypeAndMut};
+
+use super::PTR_CAST_CONSTNESS;
+
+pub(super) fn check(
+    cx: &LateContext<'_>,
+    expr: &Expr<'_>,
+    cast_expr: &Expr<'_>,
+    cast_from: Ty<'_>,
+    cast_to: Ty<'_>,
+    msrv: &Msrv,
+) {
+    if_chain! {
+        if msrv.meets(POINTER_CAST_CONSTNESS);
+        if let ty::RawPtr(TypeAndMut { mutbl: from_mutbl, .. }) = cast_from.kind();
+        if let ty::RawPtr(TypeAndMut { mutbl: to_mutbl, .. }) = cast_to.kind();
+        if matches!((from_mutbl, to_mutbl),
+            (Mutability::Not, Mutability::Mut) | (Mutability::Mut, Mutability::Not));
+        then {
+            let sugg = Sugg::hir(cx, cast_expr, "_");
+            let constness = match *to_mutbl {
+                Mutability::Not => "const",
+                Mutability::Mut => "mut",
+            };
+
+            span_lint_and_sugg(
+                cx,
+                PTR_CAST_CONSTNESS,
+                expr.span,
+                "`as` casting between raw pointers while changing its constness",
+                &format!("try `pointer::cast_{constness}`, a safer alternative"),
+                format!("{}.cast_{constness}()", sugg.maybe_par()),
+                Applicability::MachineApplicable,
+            );
+        }
+    }
+}
diff --git a/src/tools/clippy/clippy_lints/src/collection_is_never_read.rs b/src/tools/clippy/clippy_lints/src/collection_is_never_read.rs
index 5e2eb5789f6..ac5ac542cf9 100644
--- a/src/tools/clippy/clippy_lints/src/collection_is_never_read.rs
+++ b/src/tools/clippy/clippy_lints/src/collection_is_never_read.rs
@@ -37,7 +37,7 @@ declare_clippy_lint! {
     ///     println!("{sample}");
     /// }
     /// ```
-    #[clippy::version = "1.69.0"]
+    #[clippy::version = "1.70.0"]
     pub COLLECTION_IS_NEVER_READ,
     nursery,
     "a collection is never queried"
diff --git a/src/tools/clippy/clippy_lints/src/declared_lints.rs b/src/tools/clippy/clippy_lints/src/declared_lints.rs
index 212e809d4c5..15ff8be0fd9 100644
--- a/src/tools/clippy/clippy_lints/src/declared_lints.rs
+++ b/src/tools/clippy/clippy_lints/src/declared_lints.rs
@@ -89,6 +89,7 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[
     crate::casts::FN_TO_NUMERIC_CAST_ANY_INFO,
     crate::casts::FN_TO_NUMERIC_CAST_WITH_TRUNCATION_INFO,
     crate::casts::PTR_AS_PTR_INFO,
+    crate::casts::PTR_CAST_CONSTNESS_INFO,
     crate::casts::UNNECESSARY_CAST_INFO,
     crate::checked_conversions::CHECKED_CONVERSIONS_INFO,
     crate::cognitive_complexity::COGNITIVE_COMPLEXITY_INFO,
@@ -427,6 +428,7 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[
     crate::missing_const_for_fn::MISSING_CONST_FOR_FN_INFO,
     crate::missing_doc::MISSING_DOCS_IN_PRIVATE_ITEMS_INFO,
     crate::missing_enforced_import_rename::MISSING_ENFORCED_IMPORT_RENAMES_INFO,
+    crate::missing_fields_in_debug::MISSING_FIELDS_IN_DEBUG_INFO,
     crate::missing_inline::MISSING_INLINE_IN_PUBLIC_ITEMS_INFO,
     crate::missing_trait_methods::MISSING_TRAIT_METHODS_INFO,
     crate::mixed_read_write_in_expression::DIVERGING_SUB_EXPRESSION_INFO,
@@ -447,6 +449,7 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[
     crate::needless_bool::NEEDLESS_BOOL_ASSIGN_INFO,
     crate::needless_borrowed_ref::NEEDLESS_BORROWED_REFERENCE_INFO,
     crate::needless_continue::NEEDLESS_CONTINUE_INFO,
+    crate::needless_else::NEEDLESS_ELSE_INFO,
     crate::needless_for_each::NEEDLESS_FOR_EACH_INFO,
     crate::needless_late_init::NEEDLESS_LATE_INIT_INFO,
     crate::needless_parens_on_range_literals::NEEDLESS_PARENS_ON_RANGE_LITERALS_INFO,
diff --git a/src/tools/clippy/clippy_lints/src/default_constructed_unit_structs.rs b/src/tools/clippy/clippy_lints/src/default_constructed_unit_structs.rs
index 9bd7a0dc0f3..fb037bbcbf3 100644
--- a/src/tools/clippy/clippy_lints/src/default_constructed_unit_structs.rs
+++ b/src/tools/clippy/clippy_lints/src/default_constructed_unit_structs.rs
@@ -1,4 +1,4 @@
-use clippy_utils::{diagnostics::span_lint_and_sugg, match_def_path, paths};
+use clippy_utils::{diagnostics::span_lint_and_sugg, is_ty_alias, match_def_path, paths};
 use hir::{def::Res, ExprKind};
 use rustc_errors::Applicability;
 use rustc_hir as hir;
@@ -43,12 +43,23 @@ declare_clippy_lint! {
 }
 declare_lint_pass!(DefaultConstructedUnitStructs => [DEFAULT_CONSTRUCTED_UNIT_STRUCTS]);
 
+fn is_alias(ty: hir::Ty<'_>) -> bool {
+    if let hir::TyKind::Path(ref qpath) = ty.kind {
+        is_ty_alias(qpath)
+    } else {
+        false
+    }
+}
+
 impl LateLintPass<'_> for DefaultConstructedUnitStructs {
     fn check_expr<'tcx>(&mut self, cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'tcx>) {
         if_chain!(
             // make sure we have a call to `Default::default`
             if let hir::ExprKind::Call(fn_expr, &[]) = expr.kind;
-            if let ExprKind::Path(ref qpath@ hir::QPath::TypeRelative(_,_)) = fn_expr.kind;
+            if let ExprKind::Path(ref qpath @ hir::QPath::TypeRelative(base, _)) = fn_expr.kind;
+            // make sure this isn't a type alias:
+            // `<Foo as Bar>::Assoc` cannot be used as a constructor
+            if !is_alias(*base);
             if let Res::Def(_, def_id) = cx.qpath_res(qpath, fn_expr.hir_id);
             if match_def_path(cx, def_id, &paths::DEFAULT_TRAIT_METHOD);
             // make sure we have a struct with no fields (unit struct)
diff --git a/src/tools/clippy/clippy_lints/src/large_futures.rs b/src/tools/clippy/clippy_lints/src/large_futures.rs
index 0ca31033b16..087c4a65250 100644
--- a/src/tools/clippy/clippy_lints/src/large_futures.rs
+++ b/src/tools/clippy/clippy_lints/src/large_futures.rs
@@ -38,7 +38,7 @@ declare_clippy_lint! {
     ///     wait(fut).await;
     /// }
     /// ```
-    #[clippy::version = "1.68.0"]
+    #[clippy::version = "1.70.0"]
     pub LARGE_FUTURES,
     pedantic,
     "large future may lead to unexpected stack overflows"
diff --git a/src/tools/clippy/clippy_lints/src/large_stack_arrays.rs b/src/tools/clippy/clippy_lints/src/large_stack_arrays.rs
index 32c6312e069..0a5901bce04 100644
--- a/src/tools/clippy/clippy_lints/src/large_stack_arrays.rs
+++ b/src/tools/clippy/clippy_lints/src/large_stack_arrays.rs
@@ -38,7 +38,7 @@ impl_lint_pass!(LargeStackArrays => [LARGE_STACK_ARRAYS]);
 
 impl<'tcx> LateLintPass<'tcx> for LargeStackArrays {
     fn check_expr(&mut self, cx: &LateContext<'_>, expr: &Expr<'_>) {
-        if let ExprKind::Repeat(_, _) = expr.kind
+        if let ExprKind::Repeat(_, _) | ExprKind::Array(_) = expr.kind
           && let ty::Array(element_type, cst) = cx.typeck_results().expr_ty(expr).kind()
           && let ConstKind::Value(ty::ValTree::Leaf(element_count)) = cst.kind()
           && let Ok(element_count) = element_count.try_to_target_usize(cx.tcx)
diff --git a/src/tools/clippy/clippy_lints/src/let_with_type_underscore.rs b/src/tools/clippy/clippy_lints/src/let_with_type_underscore.rs
index c01e3882d52..2f10e3d2581 100644
--- a/src/tools/clippy/clippy_lints/src/let_with_type_underscore.rs
+++ b/src/tools/clippy/clippy_lints/src/let_with_type_underscore.rs
@@ -17,7 +17,7 @@ declare_clippy_lint! {
     /// ```rust,ignore
     /// let my_number = 1;
     /// ```
-    #[clippy::version = "1.69.0"]
+    #[clippy::version = "1.70.0"]
     pub LET_WITH_TYPE_UNDERSCORE,
     complexity,
     "unneeded underscore type (`_`) in a variable declaration"
diff --git a/src/tools/clippy/clippy_lints/src/lib.rs b/src/tools/clippy/clippy_lints/src/lib.rs
index fcca595c2bc..4a23edb58aa 100644
--- a/src/tools/clippy/clippy_lints/src/lib.rs
+++ b/src/tools/clippy/clippy_lints/src/lib.rs
@@ -202,6 +202,7 @@ mod missing_assert_message;
 mod missing_const_for_fn;
 mod missing_doc;
 mod missing_enforced_import_rename;
+mod missing_fields_in_debug;
 mod missing_inline;
 mod missing_trait_methods;
 mod mixed_read_write_in_expression;
@@ -217,6 +218,7 @@ mod needless_arbitrary_self_type;
 mod needless_bool;
 mod needless_borrowed_ref;
 mod needless_continue;
+mod needless_else;
 mod needless_for_each;
 mod needless_late_init;
 mod needless_parens_on_range_literals;
@@ -333,7 +335,7 @@ mod zero_sized_map_values;
 
 pub use crate::utils::conf::{lookup_conf_file, Conf};
 use crate::utils::{
-    conf::{format_error, metadata::get_configuration_metadata, TryConf},
+    conf::{metadata::get_configuration_metadata, TryConf},
     FindAll,
 };
 
@@ -369,23 +371,36 @@ pub fn read_conf(sess: &Session, path: &io::Result<(Option<PathBuf>, Vec<String>
         },
     };
 
-    let TryConf { conf, errors, warnings } = utils::conf::read(file_name);
+    let TryConf { conf, errors, warnings } = utils::conf::read(sess, file_name);
     // all conf errors are non-fatal, we just use the default conf in case of error
     for error in errors {
-        sess.err(format!(
-            "error reading Clippy's configuration file `{}`: {}",
-            file_name.display(),
-            format_error(error)
-        ));
+        if let Some(span) = error.span {
+            sess.span_err(
+                span,
+                format!("error reading Clippy's configuration file: {}", error.message),
+            );
+        } else {
+            sess.err(format!(
+                "error reading Clippy's configuration file `{}`: {}",
+                file_name.display(),
+                error.message
+            ));
+        }
     }
 
     for warning in warnings {
-        sess.struct_warn(format!(
-            "error reading Clippy's configuration file `{}`: {}",
-            file_name.display(),
-            format_error(warning)
-        ))
-        .emit();
+        if let Some(span) = warning.span {
+            sess.span_warn(
+                span,
+                format!("error reading Clippy's configuration file: {}", warning.message),
+            );
+        } else {
+            sess.warn(format!(
+                "error reading Clippy's configuration file `{}`: {}",
+                file_name.display(),
+                warning.message
+            ));
+        }
     }
 
     conf
@@ -990,6 +1005,8 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
     store.register_late_pass(|_| Box::new(items_after_test_module::ItemsAfterTestModule));
     store.register_early_pass(|| Box::new(ref_patterns::RefPatterns));
     store.register_late_pass(|_| Box::new(default_constructed_unit_structs::DefaultConstructedUnitStructs));
+    store.register_early_pass(|| Box::new(needless_else::NeedlessElse));
+    store.register_late_pass(|_| Box::new(missing_fields_in_debug::MissingFieldsInDebug));
     // add lints here, do not remove this comment, it's used in `new_lint`
 }
 
diff --git a/src/tools/clippy/clippy_lints/src/manual_let_else.rs b/src/tools/clippy/clippy_lints/src/manual_let_else.rs
index 3f8b42ffe80..389b0a4a62d 100644
--- a/src/tools/clippy/clippy_lints/src/manual_let_else.rs
+++ b/src/tools/clippy/clippy_lints/src/manual_let_else.rs
@@ -77,53 +77,54 @@ impl<'tcx> LateLintPass<'tcx> for ManualLetElse {
             local.els.is_none() &&
             local.ty.is_none() &&
             init.span.ctxt() == stmt.span.ctxt() &&
-            let Some(if_let_or_match) = IfLetOrMatch::parse(cx, init) {
-        match if_let_or_match {
-            IfLetOrMatch::IfLet(if_let_expr, let_pat, if_then, if_else) => if_chain! {
-                if expr_is_simple_identity(let_pat, if_then);
-                if let Some(if_else) = if_else;
-                if expr_diverges(cx, if_else);
-                then {
-                    emit_manual_let_else(cx, stmt.span, if_let_expr, local.pat, let_pat, if_else);
-                }
-            },
-            IfLetOrMatch::Match(match_expr, arms, source) => {
-                if self.matches_behaviour == MatchLintBehaviour::Never {
-                    return;
-                }
-                if source != MatchSource::Normal {
-                    return;
-                }
-                // Any other number than two arms doesn't (necessarily)
-                // have a trivial mapping to let else.
-                if arms.len() != 2 {
-                    return;
-                }
-                // Guards don't give us an easy mapping either
-                if arms.iter().any(|arm| arm.guard.is_some()) {
-                    return;
-                }
-                let check_types = self.matches_behaviour == MatchLintBehaviour::WellKnownTypes;
-                let diverging_arm_opt = arms
-                    .iter()
-                    .enumerate()
-                    .find(|(_, arm)| expr_diverges(cx, arm.body) && pat_allowed_for_else(cx, arm.pat, check_types));
-                let Some((idx, diverging_arm)) = diverging_arm_opt else { return; };
-                // If the non-diverging arm is the first one, its pattern can be reused in a let/else statement.
-                // However, if it arrives in second position, its pattern may cover some cases already covered
-                // by the diverging one.
-                // TODO: accept the non-diverging arm as a second position if patterns are disjointed.
-                if idx == 0 {
-                    return;
-                }
-                let pat_arm = &arms[1 - idx];
-                if !expr_is_simple_identity(pat_arm.pat, pat_arm.body) {
-                    return;
-                }
+            let Some(if_let_or_match) = IfLetOrMatch::parse(cx, init)
+        {
+            match if_let_or_match {
+                IfLetOrMatch::IfLet(if_let_expr, let_pat, if_then, if_else) => if_chain! {
+                    if expr_is_simple_identity(let_pat, if_then);
+                    if let Some(if_else) = if_else;
+                    if expr_diverges(cx, if_else);
+                    then {
+                        emit_manual_let_else(cx, stmt.span, if_let_expr, local.pat, let_pat, if_else);
+                    }
+                },
+                IfLetOrMatch::Match(match_expr, arms, source) => {
+                    if self.matches_behaviour == MatchLintBehaviour::Never {
+                        return;
+                    }
+                    if source != MatchSource::Normal {
+                        return;
+                    }
+                    // Any other number than two arms doesn't (necessarily)
+                    // have a trivial mapping to let else.
+                    if arms.len() != 2 {
+                        return;
+                    }
+                    // Guards don't give us an easy mapping either
+                    if arms.iter().any(|arm| arm.guard.is_some()) {
+                        return;
+                    }
+                    let check_types = self.matches_behaviour == MatchLintBehaviour::WellKnownTypes;
+                    let diverging_arm_opt = arms
+                        .iter()
+                        .enumerate()
+                        .find(|(_, arm)| expr_diverges(cx, arm.body) && pat_allowed_for_else(cx, arm.pat, check_types));
+                    let Some((idx, diverging_arm)) = diverging_arm_opt else { return; };
+                    // If the non-diverging arm is the first one, its pattern can be reused in a let/else statement.
+                    // However, if it arrives in second position, its pattern may cover some cases already covered
+                    // by the diverging one.
+                    // TODO: accept the non-diverging arm as a second position if patterns are disjointed.
+                    if idx == 0 {
+                        return;
+                    }
+                    let pat_arm = &arms[1 - idx];
+                    if !expr_is_simple_identity(pat_arm.pat, pat_arm.body) {
+                        return;
+                    }
 
-                emit_manual_let_else(cx, stmt.span, match_expr, local.pat, pat_arm.pat, diverging_arm.body);
-            },
-        }
+                    emit_manual_let_else(cx, stmt.span, match_expr, local.pat, pat_arm.pat, diverging_arm.body);
+                },
+            }
         };
     }
 
@@ -145,10 +146,9 @@ fn emit_manual_let_else(
         "this could be rewritten as `let...else`",
         |diag| {
             // This is far from perfect, for example there needs to be:
-            // * mut additions for the bindings
-            // * renamings of the bindings for `PatKind::Or`
+            // * tracking for multi-binding cases: let (foo, bar) = if let (Some(foo), Ok(bar)) = ...
+            // * renamings of the bindings for many `PatKind`s like structs, slices, etc.
             // * unused binding collision detection with existing ones
-            // * putting patterns with at the top level | inside ()
             // for this to be machine applicable.
             let mut app = Applicability::HasPlaceholders;
             let (sn_expr, _) = snippet_with_context(cx, expr.span, span.ctxt(), "", &mut app);
@@ -159,28 +159,62 @@ fn emit_manual_let_else(
             } else {
                 format!("{{ {sn_else} }}")
             };
-            let sn_bl = match pat.kind {
-                PatKind::Or(..) => {
-                    let (sn_pat, _) = snippet_with_context(cx, pat.span, span.ctxt(), "", &mut app);
-                    format!("({sn_pat})")
-                },
-                // Replace the variable name iff `TupleStruct` has one argument like `Variant(v)`.
-                PatKind::TupleStruct(ref w, args, ..) if args.len() == 1 => {
-                    let sn_wrapper = cx.sess().source_map().span_to_snippet(w.span()).unwrap_or_default();
-                    let (sn_inner, _) = snippet_with_context(cx, local.span, span.ctxt(), "", &mut app);
-                    format!("{sn_wrapper}({sn_inner})")
-                },
-                _ => {
-                    let (sn_pat, _) = snippet_with_context(cx, pat.span, span.ctxt(), "", &mut app);
-                    sn_pat.into_owned()
-                },
-            };
+            let sn_bl = replace_in_pattern(cx, span, local, pat, &mut app);
             let sugg = format!("let {sn_bl} = {sn_expr} else {else_bl};");
             diag.span_suggestion(span, "consider writing", sugg, app);
         },
     );
 }
 
+// replaces the locals in the pattern
+fn replace_in_pattern(
+    cx: &LateContext<'_>,
+    span: Span,
+    local: &Pat<'_>,
+    pat: &Pat<'_>,
+    app: &mut Applicability,
+) -> String {
+    let mut bindings_count = 0;
+    pat.each_binding_or_first(&mut |_, _, _, _| bindings_count += 1);
+    // If the pattern creates multiple bindings, exit early,
+    // as otherwise we might paste the pattern to the positions of multiple bindings.
+    if bindings_count > 1 {
+        let (sn_pat, _) = snippet_with_context(cx, pat.span, span.ctxt(), "", app);
+        return sn_pat.into_owned();
+    }
+
+    match pat.kind {
+        PatKind::Binding(..) => {
+            let (sn_bdg, _) = snippet_with_context(cx, local.span, span.ctxt(), "", app);
+            return sn_bdg.to_string();
+        },
+        PatKind::Or(pats) => {
+            let patterns = pats
+                .iter()
+                .map(|pat| replace_in_pattern(cx, span, local, pat, app))
+                .collect::<Vec<_>>();
+            let or_pat = patterns.join(" | ");
+            return format!("({or_pat})");
+        },
+        // Replace the variable name iff `TupleStruct` has one argument like `Variant(v)`.
+        PatKind::TupleStruct(ref w, args, dot_dot_pos) => {
+            let mut args = args
+                .iter()
+                .map(|pat| replace_in_pattern(cx, span, local, pat, app))
+                .collect::<Vec<_>>();
+            if let Some(pos) = dot_dot_pos.as_opt_usize() {
+                args.insert(pos, "..".to_owned());
+            }
+            let args = args.join(", ");
+            let sn_wrapper = cx.sess().source_map().span_to_snippet(w.span()).unwrap_or_default();
+            return format!("{sn_wrapper}({args})");
+        },
+        _ => {},
+    }
+    let (sn_pat, _) = snippet_with_context(cx, pat.span, span.ctxt(), "", app);
+    sn_pat.into_owned()
+}
+
 /// Check whether an expression is divergent. May give false negatives.
 fn expr_diverges(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
     struct V<'cx, 'tcx> {
diff --git a/src/tools/clippy/clippy_lints/src/matches/match_wild_err_arm.rs b/src/tools/clippy/clippy_lints/src/matches/match_wild_err_arm.rs
index 42f1e2629d4..6424ac31d9f 100644
--- a/src/tools/clippy/clippy_lints/src/matches/match_wild_err_arm.rs
+++ b/src/tools/clippy/clippy_lints/src/matches/match_wild_err_arm.rs
@@ -2,7 +2,7 @@ use clippy_utils::diagnostics::span_lint_and_note;
 use clippy_utils::macros::{is_panic, root_macro_call};
 use clippy_utils::ty::is_type_diagnostic_item;
 use clippy_utils::visitors::is_local_used;
-use clippy_utils::{is_wild, peel_blocks_with_stmt};
+use clippy_utils::{in_constant, is_wild, peel_blocks_with_stmt};
 use rustc_hir::{Arm, Expr, PatKind};
 use rustc_lint::LateContext;
 use rustc_span::symbol::{kw, sym};
@@ -10,6 +10,11 @@ use rustc_span::symbol::{kw, sym};
 use super::MATCH_WILD_ERR_ARM;
 
 pub(crate) fn check<'tcx>(cx: &LateContext<'tcx>, ex: &Expr<'tcx>, arms: &[Arm<'tcx>]) {
+    // `unwrap`/`expect` is not (yet) const, so we want to allow this in const contexts for now
+    if in_constant(cx, ex.hir_id) {
+        return;
+    }
+
     let ex_ty = cx.typeck_results().expr_ty(ex).peel_refs();
     if is_type_diagnostic_item(cx, ex_ty, sym::Result) {
         for arm in arms {
diff --git a/src/tools/clippy/clippy_lints/src/matches/mod.rs b/src/tools/clippy/clippy_lints/src/matches/mod.rs
index 55ec9d4474f..0d91051632a 100644
--- a/src/tools/clippy/clippy_lints/src/matches/mod.rs
+++ b/src/tools/clippy/clippy_lints/src/matches/mod.rs
@@ -25,7 +25,7 @@ mod wild_in_or_pats;
 
 use clippy_utils::msrvs::{self, Msrv};
 use clippy_utils::source::{snippet_opt, walk_span_to_context};
-use clippy_utils::{higher, in_constant, is_span_match, tokenize_with_text};
+use clippy_utils::{higher, in_constant, is_direct_expn_of, is_span_match, tokenize_with_text};
 use rustc_hir::{Arm, Expr, ExprKind, Local, MatchSource, Pat};
 use rustc_lexer::TokenKind;
 use rustc_lint::{LateContext, LateLintPass, LintContext};
@@ -974,12 +974,16 @@ impl_lint_pass!(Matches => [
 
 impl<'tcx> LateLintPass<'tcx> for Matches {
     fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
-        if in_external_macro(cx.sess(), expr.span) {
+        if is_direct_expn_of(expr.span, "matches").is_none() && in_external_macro(cx.sess(), expr.span) {
             return;
         }
         let from_expansion = expr.span.from_expansion();
 
         if let ExprKind::Match(ex, arms, source) = expr.kind {
+            if is_direct_expn_of(expr.span, "matches").is_some() {
+                redundant_pattern_match::check_match(cx, expr, ex, arms);
+            }
+
             if source == MatchSource::Normal && !is_span_match(cx, expr.span) {
                 return;
             }
diff --git a/src/tools/clippy/clippy_lints/src/matches/redundant_pattern_match.rs b/src/tools/clippy/clippy_lints/src/matches/redundant_pattern_match.rs
index e81e09da425..479cfd83512 100644
--- a/src/tools/clippy/clippy_lints/src/matches/redundant_pattern_match.rs
+++ b/src/tools/clippy/clippy_lints/src/matches/redundant_pattern_match.rs
@@ -1,10 +1,10 @@
 use super::REDUNDANT_PATTERN_MATCHING;
-use clippy_utils::diagnostics::span_lint_and_then;
+use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_and_then};
 use clippy_utils::source::{snippet, walk_span_to_context};
 use clippy_utils::sugg::Sugg;
 use clippy_utils::ty::{is_type_diagnostic_item, needs_ordered_drop};
 use clippy_utils::visitors::any_temporaries_need_ordered_drop;
-use clippy_utils::{higher, is_trait_method};
+use clippy_utils::{higher, is_expn_of, is_trait_method};
 use if_chain::if_chain;
 use rustc_ast::ast::LitKind;
 use rustc_errors::Applicability;
@@ -190,24 +190,19 @@ pub(super) fn check_match<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, op
         let node_pair = (&arms[0].pat.kind, &arms[1].pat.kind);
 
         if let Some(good_method) = found_good_method(cx, arms, node_pair) {
-            let span = expr.span.to(op.span);
+            let span = is_expn_of(expr.span, "matches").unwrap_or(expr.span.to(op.span));
             let result_expr = match &op.kind {
                 ExprKind::AddrOf(_, _, borrowed) => borrowed,
                 _ => op,
             };
-            span_lint_and_then(
+            span_lint_and_sugg(
                 cx,
                 REDUNDANT_PATTERN_MATCHING,
-                expr.span,
+                span,
                 &format!("redundant pattern matching, consider using `{good_method}`"),
-                |diag| {
-                    diag.span_suggestion(
-                        span,
-                        "try this",
-                        format!("{}.{good_method}", snippet(cx, result_expr.span, "_")),
-                        Applicability::MaybeIncorrect, // snippet
-                    );
-                },
+                "try this",
+                format!("{}.{good_method}", snippet(cx, result_expr.span, "_")),
+                Applicability::MachineApplicable,
             );
         }
     }
diff --git a/src/tools/clippy/clippy_lints/src/methods/mod.rs b/src/tools/clippy/clippy_lints/src/methods/mod.rs
index 9a594d964ab..88cbefbb5d3 100644
--- a/src/tools/clippy/clippy_lints/src/methods/mod.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/mod.rs
@@ -3191,7 +3191,7 @@ declare_clippy_lint! {
     /// let mut v = vec![1, 2, 3];
     /// v.clear();
     /// ```
-    #[clippy::version = "1.69.0"]
+    #[clippy::version = "1.70.0"]
     pub CLEAR_WITH_DRAIN,
     nursery,
     "calling `drain` in order to `clear` a container"
diff --git a/src/tools/clippy/clippy_lints/src/missing_assert_message.rs b/src/tools/clippy/clippy_lints/src/missing_assert_message.rs
index 2214a568d9c..4dbb79334ca 100644
--- a/src/tools/clippy/clippy_lints/src/missing_assert_message.rs
+++ b/src/tools/clippy/clippy_lints/src/missing_assert_message.rs
@@ -36,7 +36,7 @@ declare_clippy_lint! {
     ///     assert!(service.ready, "`service.poll_ready()` must be called first to ensure that service is ready to receive requests");
     /// }
     /// ```
-    #[clippy::version = "1.69.0"]
+    #[clippy::version = "1.70.0"]
     pub MISSING_ASSERT_MESSAGE,
     restriction,
     "checks assertions without a custom panic message"
diff --git a/src/tools/clippy/clippy_lints/src/missing_fields_in_debug.rs b/src/tools/clippy/clippy_lints/src/missing_fields_in_debug.rs
new file mode 100644
index 00000000000..b6f0de7e504
--- /dev/null
+++ b/src/tools/clippy/clippy_lints/src/missing_fields_in_debug.rs
@@ -0,0 +1,234 @@
+use std::ops::ControlFlow;
+
+use clippy_utils::{
+    diagnostics::span_lint_and_then,
+    is_path_lang_item, paths,
+    ty::match_type,
+    visitors::{for_each_expr, Visitable},
+};
+use rustc_ast::LitKind;
+use rustc_data_structures::fx::FxHashSet;
+use rustc_hir::Block;
+use rustc_hir::{
+    def::{DefKind, Res},
+    Expr, ImplItemKind, LangItem, Node,
+};
+use rustc_hir::{ExprKind, Impl, ItemKind, QPath, TyKind};
+use rustc_hir::{ImplItem, Item, VariantData};
+use rustc_lint::{LateContext, LateLintPass};
+use rustc_middle::ty::Ty;
+use rustc_middle::ty::TypeckResults;
+use rustc_session::{declare_lint_pass, declare_tool_lint};
+use rustc_span::{sym, Span, Symbol};
+
+declare_clippy_lint! {
+    /// ### What it does
+    /// Checks for manual [`core::fmt::Debug`](https://doc.rust-lang.org/core/fmt/trait.Debug.html) implementations that do not use all fields.
+    ///
+    /// ### Why is this bad?
+    /// A common mistake is to forget to update manual `Debug` implementations when adding a new field
+    /// to a struct or a new variant to an enum.
+    ///
+    /// At the same time, it also acts as a style lint to suggest using [`core::fmt::DebugStruct::finish_non_exhaustive`](https://doc.rust-lang.org/core/fmt/struct.DebugStruct.html#method.finish_non_exhaustive)
+    /// for the times when the user intentionally wants to leave out certain fields (e.g. to hide implementation details).
+    ///
+    /// ### Known problems
+    /// This lint works based on the `DebugStruct` helper types provided by the `Formatter`,
+    /// so this won't detect `Debug` impls that use the `write!` macro.
+    /// Oftentimes there is more logic to a `Debug` impl if it uses `write!` macro, so it tries
+    /// to be on the conservative side and not lint in those cases in an attempt to prevent false positives.
+    ///
+    /// This lint also does not look through function calls, so calling a function does not consider fields
+    /// used inside of that function as used by the `Debug` impl.
+    ///
+    /// Lastly, it also ignores tuple structs as their `DebugTuple` formatter does not have a `finish_non_exhaustive`
+    /// method, as well as enums because their exhaustiveness is already checked by the compiler when matching on the enum,
+    /// making it much less likely to accidentally forget to update the `Debug` impl when adding a new variant.
+    ///
+    /// ### Example
+    /// ```rust
+    /// use std::fmt;
+    /// struct Foo {
+    ///     data: String,
+    ///     // implementation detail
+    ///     hidden_data: i32
+    /// }
+    /// impl fmt::Debug for Foo {
+    ///     fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
+    ///         formatter
+    ///             .debug_struct("Foo")
+    ///             .field("data", &self.data)
+    ///             .finish()
+    ///     }
+    /// }
+    /// ```
+    /// Use instead:
+    /// ```rust
+    /// use std::fmt;
+    /// struct Foo {
+    ///     data: String,
+    ///     // implementation detail
+    ///     hidden_data: i32
+    /// }
+    /// impl fmt::Debug for Foo {
+    ///     fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
+    ///         formatter
+    ///             .debug_struct("Foo")
+    ///             .field("data", &self.data)
+    ///             .finish_non_exhaustive()
+    ///     }
+    /// }
+    /// ```
+    #[clippy::version = "1.70.0"]
+    pub MISSING_FIELDS_IN_DEBUG,
+    pedantic,
+    "missing fields in manual `Debug` implementation"
+}
+declare_lint_pass!(MissingFieldsInDebug => [MISSING_FIELDS_IN_DEBUG]);
+
+fn report_lints(cx: &LateContext<'_>, span: Span, span_notes: Vec<(Span, &'static str)>) {
+    span_lint_and_then(
+        cx,
+        MISSING_FIELDS_IN_DEBUG,
+        span,
+        "manual `Debug` impl does not include all fields",
+        |diag| {
+            for (span, note) in span_notes {
+                diag.span_note(span, note);
+            }
+            diag.help("consider including all fields in this `Debug` impl")
+                .help("consider calling `.finish_non_exhaustive()` if you intend to ignore fields");
+        },
+    );
+}
+
+/// Checks if we should lint in a block of code
+///
+/// The way we check for this condition is by checking if there is
+/// a call to `Formatter::debug_struct` but no call to `.finish_non_exhaustive()`.
+fn should_lint<'tcx>(
+    cx: &LateContext<'tcx>,
+    typeck_results: &TypeckResults<'tcx>,
+    block: impl Visitable<'tcx>,
+) -> bool {
+    // Is there a call to `DebugStruct::finish_non_exhaustive`? Don't lint if there is.
+    let mut has_finish_non_exhaustive = false;
+    // Is there a call to `DebugStruct::debug_struct`? Do lint if there is.
+    let mut has_debug_struct = false;
+
+    for_each_expr(block, |expr| {
+        if let ExprKind::MethodCall(path, recv, ..) = &expr.kind {
+            let recv_ty = typeck_results.expr_ty(recv).peel_refs();
+
+            if path.ident.name == sym::debug_struct && match_type(cx, recv_ty, &paths::FORMATTER) {
+                has_debug_struct = true;
+            } else if path.ident.name == sym!(finish_non_exhaustive) && match_type(cx, recv_ty, &paths::DEBUG_STRUCT) {
+                has_finish_non_exhaustive = true;
+            }
+        }
+        ControlFlow::<!, _>::Continue(())
+    });
+
+    !has_finish_non_exhaustive && has_debug_struct
+}
+
+/// Checks if the given expression is a call to `DebugStruct::field`
+/// and the first argument to it is a string literal and if so, returns it
+///
+/// Example: `.field("foo", ....)` returns `Some("foo")`
+fn as_field_call<'tcx>(
+    cx: &LateContext<'tcx>,
+    typeck_results: &TypeckResults<'tcx>,
+    expr: &Expr<'_>,
+) -> Option<Symbol> {
+    if let ExprKind::MethodCall(path, recv, [debug_field, _], _) = &expr.kind
+        && let recv_ty = typeck_results.expr_ty(recv).peel_refs()
+        && match_type(cx, recv_ty, &paths::DEBUG_STRUCT)
+        && path.ident.name == sym::field
+        && let ExprKind::Lit(lit) = &debug_field.kind
+        && let LitKind::Str(sym, ..) = lit.node
+    {
+        Some(sym)
+    } else {
+        None
+    }
+}
+
+/// Attempts to find unused fields assuming that the item is a struct
+fn check_struct<'tcx>(
+    cx: &LateContext<'tcx>,
+    typeck_results: &TypeckResults<'tcx>,
+    block: &'tcx Block<'tcx>,
+    self_ty: Ty<'tcx>,
+    item: &'tcx Item<'tcx>,
+    data: &VariantData<'_>,
+) {
+    // Is there a "direct" field access anywhere (i.e. self.foo)?
+    // We don't want to lint if there is not, because the user might have
+    // a newtype struct and use fields from the wrapped type only.
+    let mut has_direct_field_access = false;
+    let mut field_accesses = FxHashSet::default();
+
+    for_each_expr(block, |expr| {
+        if let ExprKind::Field(target, ident) = expr.kind
+            && let target_ty = typeck_results.expr_ty_adjusted(target).peel_refs()
+            && target_ty == self_ty
+        {
+            field_accesses.insert(ident.name);
+            has_direct_field_access = true;
+        } else if let Some(sym) = as_field_call(cx, typeck_results, expr) {
+            field_accesses.insert(sym);
+        }
+        ControlFlow::<!, _>::Continue(())
+    });
+
+    let span_notes = data
+        .fields()
+        .iter()
+        .filter_map(|field| {
+            if field_accesses.contains(&field.ident.name) || is_path_lang_item(cx, field.ty, LangItem::PhantomData) {
+                None
+            } else {
+                Some((field.span, "this field is unused"))
+            }
+        })
+        .collect::<Vec<_>>();
+
+    // only lint if there's also at least one direct field access to allow patterns
+    // where one might have a newtype struct and uses fields from the wrapped type
+    if !span_notes.is_empty() && has_direct_field_access {
+        report_lints(cx, item.span, span_notes);
+    }
+}
+
+impl<'tcx> LateLintPass<'tcx> for MissingFieldsInDebug {
+    fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx rustc_hir::Item<'tcx>) {
+        // is this an `impl Debug for X` block?
+        if let ItemKind::Impl(Impl { of_trait: Some(trait_ref), self_ty, items, .. }) = item.kind
+            && let Res::Def(DefKind::Trait, trait_def_id) = trait_ref.path.res
+            && let TyKind::Path(QPath::Resolved(_, self_path)) = &self_ty.kind
+            && cx.match_def_path(trait_def_id, &[sym::core, sym::fmt, sym::Debug])
+            // don't trigger if this impl was derived
+            && !cx.tcx.has_attr(item.owner_id, sym::automatically_derived)
+            && !item.span.from_expansion()
+            // find `Debug::fmt` function
+            && let Some(fmt_item) = items.iter().find(|i| i.ident.name == sym::fmt)
+            && let ImplItem { kind: ImplItemKind::Fn(_, body_id), .. } = cx.tcx.hir().impl_item(fmt_item.id)
+            && let body = cx.tcx.hir().body(*body_id)
+            && let ExprKind::Block(block, _) = body.value.kind
+            // inspect `self`
+            && let self_ty = cx.tcx.type_of(self_path.res.def_id()).skip_binder().peel_refs()
+            && let Some(self_adt) = self_ty.ty_adt_def()
+            && let Some(self_def_id) = self_adt.did().as_local()
+            && let Some(Node::Item(self_item)) = cx.tcx.hir().find_by_def_id(self_def_id)
+            // NB: can't call cx.typeck_results() as we are not in a body
+            && let typeck_results = cx.tcx.typeck_body(*body_id)
+            && should_lint(cx, typeck_results, block)
+        {
+            // we intentionally only lint structs, see lint description
+            if let ItemKind::Struct(data, _) = &self_item.kind {
+                check_struct(cx, typeck_results, block, self_ty, item, data);
+            }
+        }
+    }
+}
diff --git a/src/tools/clippy/clippy_lints/src/needless_else.rs b/src/tools/clippy/clippy_lints/src/needless_else.rs
new file mode 100644
index 00000000000..4ff1bf7ffc0
--- /dev/null
+++ b/src/tools/clippy/clippy_lints/src/needless_else.rs
@@ -0,0 +1,61 @@
+use clippy_utils::source::snippet_opt;
+use clippy_utils::{diagnostics::span_lint_and_sugg, source::trim_span};
+use rustc_ast::ast::{Expr, ExprKind};
+use rustc_errors::Applicability;
+use rustc_lint::{EarlyContext, EarlyLintPass, LintContext};
+use rustc_session::{declare_lint_pass, declare_tool_lint};
+
+declare_clippy_lint! {
+    /// ### What it does
+    /// Checks for empty `else` branches.
+    ///
+    /// ### Why is this bad?
+    /// An empty else branch does nothing and can be removed.
+    ///
+    /// ### Example
+    /// ```rust
+    ///# fn check() -> bool { true }
+    /// if check() {
+    ///     println!("Check successful!");
+    /// } else {
+    /// }
+    /// ```
+    /// Use instead:
+    /// ```rust
+    ///# fn check() -> bool { true }
+    /// if check() {
+    ///     println!("Check successful!");
+    /// }
+    /// ```
+    #[clippy::version = "1.71.0"]
+    pub NEEDLESS_ELSE,
+    style,
+    "empty else branch"
+}
+declare_lint_pass!(NeedlessElse => [NEEDLESS_ELSE]);
+
+impl EarlyLintPass for NeedlessElse {
+    fn check_expr(&mut self, cx: &EarlyContext<'_>, expr: &Expr) {
+        if let ExprKind::If(_, then_block, Some(else_clause)) = &expr.kind
+            && let ExprKind::Block(block, _) = &else_clause.kind
+            && !expr.span.from_expansion()
+            && !else_clause.span.from_expansion()
+            && block.stmts.is_empty()
+            && let Some(trimmed) = expr.span.trim_start(then_block.span)
+            && let span = trim_span(cx.sess().source_map(), trimmed)
+            && let Some(else_snippet) = snippet_opt(cx, span)
+            // Ignore else blocks that contain comments or #[cfg]s
+            && !else_snippet.contains(['/', '#'])
+        {
+            span_lint_and_sugg(
+                cx,
+                NEEDLESS_ELSE,
+                span,
+                "this else branch is empty",
+                "you can remove it",
+                String::new(),
+                Applicability::MachineApplicable,
+            );
+        }
+    }
+}
diff --git a/src/tools/clippy/clippy_lints/src/nonstandard_macro_braces.rs b/src/tools/clippy/clippy_lints/src/nonstandard_macro_braces.rs
index 6c909e5ed73..2d79a5c9008 100644
--- a/src/tools/clippy/clippy_lints/src/nonstandard_macro_braces.rs
+++ b/src/tools/clippy/clippy_lints/src/nonstandard_macro_braces.rs
@@ -241,7 +241,7 @@ impl<'de> Deserialize<'de> for MacroMatcher {
                 V: de::MapAccess<'de>,
             {
                 let mut name = None;
-                let mut brace: Option<&str> = None;
+                let mut brace: Option<String> = None;
                 while let Some(key) = map.next_key()? {
                     match key {
                         Field::Name => {
diff --git a/src/tools/clippy/clippy_lints/src/redundant_async_block.rs b/src/tools/clippy/clippy_lints/src/redundant_async_block.rs
index a0f831764d0..05e52e6b38b 100644
--- a/src/tools/clippy/clippy_lints/src/redundant_async_block.rs
+++ b/src/tools/clippy/clippy_lints/src/redundant_async_block.rs
@@ -35,7 +35,7 @@ declare_clippy_lint! {
     /// };
     /// let fut = f;
     /// ```
-    #[clippy::version = "1.69.0"]
+    #[clippy::version = "1.70.0"]
     pub REDUNDANT_ASYNC_BLOCK,
     complexity,
     "`async { future.await }` can be replaced by `future`"
diff --git a/src/tools/clippy/clippy_lints/src/regex.rs b/src/tools/clippy/clippy_lints/src/regex.rs
index ef19c6f4617..674f8bf4c0f 100644
--- a/src/tools/clippy/clippy_lints/src/regex.rs
+++ b/src/tools/clippy/clippy_lints/src/regex.rs
@@ -177,7 +177,7 @@ fn check_set<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, utf8: bool) {
 }
 
 fn check_regex<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, utf8: bool) {
-    let mut parser = regex_syntax::ParserBuilder::new().unicode(true).utf8(!utf8).build();
+    let mut parser = regex_syntax::ParserBuilder::new().unicode(true).utf8(utf8).build();
 
     if let ExprKind::Lit(lit) = expr.kind {
         if let LitKind::Str(ref r, style) = lit.node {
diff --git a/src/tools/clippy/clippy_lints/src/returns.rs b/src/tools/clippy/clippy_lints/src/returns.rs
index df126d7617e..631ecf1428d 100644
--- a/src/tools/clippy/clippy_lints/src/returns.rs
+++ b/src/tools/clippy/clippy_lints/src/returns.rs
@@ -70,7 +70,7 @@ declare_clippy_lint! {
     "using a return statement like `return expr;` where an expression would suffice"
 }
 
-#[derive(PartialEq, Eq, Clone)]
+#[derive(PartialEq, Eq)]
 enum RetReplacement<'tcx> {
     Empty,
     Block,
@@ -80,7 +80,7 @@ enum RetReplacement<'tcx> {
 }
 
 impl<'tcx> RetReplacement<'tcx> {
-    fn sugg_help(self) -> &'static str {
+    fn sugg_help(&self) -> &'static str {
         match self {
             Self::Empty | Self::Expr(..) => "remove `return`",
             Self::Block => "replace `return` with an empty block",
@@ -88,10 +88,11 @@ impl<'tcx> RetReplacement<'tcx> {
             Self::IfSequence(..) => "remove `return` and wrap the sequence with parentheses",
         }
     }
-    fn applicability(&self) -> Option<Applicability> {
+
+    fn applicability(&self) -> Applicability {
         match self {
-            Self::Expr(_, ap) | Self::IfSequence(_, ap) => Some(*ap),
-            _ => None,
+            Self::Expr(_, ap) | Self::IfSequence(_, ap) => *ap,
+            _ => Applicability::MachineApplicable,
         }
     }
 }
@@ -271,7 +272,7 @@ fn check_final_expr<'tcx>(
                 return;
             }
 
-            emit_return_lint(cx, ret_span, semi_spans, replacement);
+            emit_return_lint(cx, ret_span, semi_spans, &replacement);
         },
         ExprKind::If(_, then, else_clause_opt) => {
             check_block_return(cx, &then.kind, peeled_drop_expr.span, semi_spans.clone());
@@ -306,20 +307,17 @@ fn expr_contains_conjunctive_ifs<'tcx>(expr: &'tcx Expr<'tcx>) -> bool {
     contains_if(expr, false)
 }
 
-fn emit_return_lint(cx: &LateContext<'_>, ret_span: Span, semi_spans: Vec<Span>, replacement: RetReplacement<'_>) {
+fn emit_return_lint(cx: &LateContext<'_>, ret_span: Span, semi_spans: Vec<Span>, replacement: &RetReplacement<'_>) {
     if ret_span.from_expansion() {
         return;
     }
 
-    let applicability = replacement.applicability().unwrap_or(Applicability::MachineApplicable);
-    let return_replacement = replacement.to_string();
-    let sugg_help = replacement.sugg_help();
     span_lint_and_then(cx, NEEDLESS_RETURN, ret_span, "unneeded `return` statement", |diag| {
-        diag.span_suggestion_hidden(ret_span, sugg_help, return_replacement, applicability);
-        // for each parent statement, we need to remove the semicolon
-        for semi_stmt_span in semi_spans {
-            diag.tool_only_span_suggestion(semi_stmt_span, "remove this semicolon", "", applicability);
-        }
+        let suggestions = std::iter::once((ret_span, replacement.to_string()))
+            .chain(semi_spans.into_iter().map(|span| (span, String::new())))
+            .collect();
+
+        diag.multipart_suggestion_verbose(replacement.sugg_help(), suggestions, replacement.applicability());
     });
 }
 
diff --git a/src/tools/clippy/clippy_lints/src/strings.rs b/src/tools/clippy/clippy_lints/src/strings.rs
index 483f860a8b5..8658009eba4 100644
--- a/src/tools/clippy/clippy_lints/src/strings.rs
+++ b/src/tools/clippy/clippy_lints/src/strings.rs
@@ -2,7 +2,7 @@ use clippy_utils::diagnostics::{span_lint, span_lint_and_help, span_lint_and_sug
 use clippy_utils::source::{snippet, snippet_with_applicability};
 use clippy_utils::ty::is_type_lang_item;
 use clippy_utils::{get_expr_use_or_unification_node, peel_blocks, SpanlessEq};
-use clippy_utils::{get_parent_expr, is_lint_allowed, match_function_call, method_calls, paths};
+use clippy_utils::{get_parent_expr, is_lint_allowed, is_path_diagnostic_item, method_calls};
 use if_chain::if_chain;
 use rustc_errors::Applicability;
 use rustc_hir::def_id::DefId;
@@ -255,7 +255,8 @@ impl<'tcx> LateLintPass<'tcx> for StringLitAsBytes {
 
         if_chain! {
             // Find std::str::converts::from_utf8
-            if let Some(args) = match_function_call(cx, e, &paths::STR_FROM_UTF8);
+            if let ExprKind::Call(fun, args) = e.kind;
+            if is_path_diagnostic_item(cx, fun, sym::str_from_utf8);
 
             // Find string::as_bytes
             if let ExprKind::AddrOf(BorrowKind::Ref, _, args) = args[0].kind;
diff --git a/src/tools/clippy/clippy_lints/src/unused_async.rs b/src/tools/clippy/clippy_lints/src/unused_async.rs
index 55651a28be9..117dda09222 100644
--- a/src/tools/clippy/clippy_lints/src/unused_async.rs
+++ b/src/tools/clippy/clippy_lints/src/unused_async.rs
@@ -1,5 +1,5 @@
-use clippy_utils::diagnostics::span_lint_and_help;
-use rustc_hir::intravisit::{walk_expr, walk_fn, FnKind, Visitor};
+use clippy_utils::diagnostics::span_lint_and_then;
+use rustc_hir::intravisit::{walk_body, walk_expr, walk_fn, FnKind, Visitor};
 use rustc_hir::{Body, Expr, ExprKind, FnDecl, YieldSource};
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_middle::hir::nested_filter;
@@ -42,6 +42,10 @@ declare_lint_pass!(UnusedAsync => [UNUSED_ASYNC]);
 struct AsyncFnVisitor<'a, 'tcx> {
     cx: &'a LateContext<'tcx>,
     found_await: bool,
+    /// Also keep track of `await`s in nested async blocks so we can mention
+    /// it in a note
+    await_in_async_block: Option<Span>,
+    async_depth: usize,
 }
 
 impl<'a, 'tcx> Visitor<'tcx> for AsyncFnVisitor<'a, 'tcx> {
@@ -49,7 +53,11 @@ impl<'a, 'tcx> Visitor<'tcx> for AsyncFnVisitor<'a, 'tcx> {
 
     fn visit_expr(&mut self, ex: &'tcx Expr<'tcx>) {
         if let ExprKind::Yield(_, YieldSource::Await { .. }) = ex.kind {
-            self.found_await = true;
+            if self.async_depth == 1 {
+                self.found_await = true;
+            } else if self.await_in_async_block.is_none() {
+                self.await_in_async_block = Some(ex.span);
+            }
         }
         walk_expr(self, ex);
     }
@@ -57,6 +65,20 @@ impl<'a, 'tcx> Visitor<'tcx> for AsyncFnVisitor<'a, 'tcx> {
     fn nested_visit_map(&mut self) -> Self::Map {
         self.cx.tcx.hir()
     }
+
+    fn visit_body(&mut self, b: &'tcx Body<'tcx>) {
+        let is_async_block = matches!(b.generator_kind, Some(rustc_hir::GeneratorKind::Async(_)));
+
+        if is_async_block {
+            self.async_depth += 1;
+        }
+
+        walk_body(self, b);
+
+        if is_async_block {
+            self.async_depth -= 1;
+        }
+    }
 }
 
 impl<'tcx> LateLintPass<'tcx> for UnusedAsync {
@@ -70,16 +92,30 @@ impl<'tcx> LateLintPass<'tcx> for UnusedAsync {
         def_id: LocalDefId,
     ) {
         if !span.from_expansion() && fn_kind.asyncness().is_async() {
-            let mut visitor = AsyncFnVisitor { cx, found_await: false };
+            let mut visitor = AsyncFnVisitor {
+                cx,
+                found_await: false,
+                async_depth: 0,
+                await_in_async_block: None,
+            };
             walk_fn(&mut visitor, fn_kind, fn_decl, body.id(), def_id);
             if !visitor.found_await {
-                span_lint_and_help(
+                span_lint_and_then(
                     cx,
                     UNUSED_ASYNC,
                     span,
                     "unused `async` for function with no await statements",
-                    None,
-                    "consider removing the `async` from this function",
+                    |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`",
+                            );
+                        }
+                    },
                 );
             }
         }
diff --git a/src/tools/clippy/clippy_lints/src/utils/conf.rs b/src/tools/clippy/clippy_lints/src/utils/conf.rs
index f6de66bb514..35f40830681 100644
--- a/src/tools/clippy/clippy_lints/src/utils/conf.rs
+++ b/src/tools/clippy/clippy_lints/src/utils/conf.rs
@@ -2,12 +2,15 @@
 
 #![allow(clippy::module_name_repetitions)]
 
+use rustc_session::Session;
+use rustc_span::{BytePos, Pos, SourceFile, Span, SyntaxContext};
 use serde::de::{Deserializer, IgnoredAny, IntoDeserializer, MapAccess, Visitor};
 use serde::Deserialize;
-use std::error::Error;
+use std::fmt::{Debug, Display, Formatter};
+use std::ops::Range;
 use std::path::{Path, PathBuf};
 use std::str::FromStr;
-use std::{cmp, env, fmt, fs, io, iter};
+use std::{cmp, env, fmt, fs, io};
 
 #[rustfmt::skip]
 const DEFAULT_DOC_VALID_IDENTS: &[&str] = &[
@@ -67,33 +70,70 @@ impl DisallowedPath {
 #[derive(Default)]
 pub struct TryConf {
     pub conf: Conf,
-    pub errors: Vec<Box<dyn Error>>,
-    pub warnings: Vec<Box<dyn Error>>,
+    pub errors: Vec<ConfError>,
+    pub warnings: Vec<ConfError>,
 }
 
 impl TryConf {
-    fn from_error(error: impl Error + 'static) -> Self {
+    fn from_toml_error(file: &SourceFile, error: &toml::de::Error) -> Self {
+        ConfError::from_toml(file, error).into()
+    }
+}
+
+impl From<ConfError> for TryConf {
+    fn from(value: ConfError) -> Self {
         Self {
             conf: Conf::default(),
-            errors: vec![Box::new(error)],
+            errors: vec![value],
             warnings: vec![],
         }
     }
 }
 
+impl From<io::Error> for TryConf {
+    fn from(value: io::Error) -> Self {
+        ConfError::from(value).into()
+    }
+}
+
 #[derive(Debug)]
-struct ConfError(String);
+pub struct ConfError {
+    pub message: String,
+    pub span: Option<Span>,
+}
+
+impl ConfError {
+    fn from_toml(file: &SourceFile, error: &toml::de::Error) -> Self {
+        if let Some(span) = error.span() {
+            Self::spanned(file, error.message(), span)
+        } else {
+            Self {
+                message: error.message().to_string(),
+                span: None,
+            }
+        }
+    }
 
-impl fmt::Display for ConfError {
-    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        <String as fmt::Display>::fmt(&self.0, f)
+    fn spanned(file: &SourceFile, message: impl Into<String>, span: Range<usize>) -> Self {
+        Self {
+            message: message.into(),
+            span: Some(Span::new(
+                file.start_pos + BytePos::from_usize(span.start),
+                file.start_pos + BytePos::from_usize(span.end),
+                SyntaxContext::root(),
+                None,
+            )),
+        }
     }
 }
 
-impl Error for ConfError {}
-
-fn conf_error(s: impl Into<String>) -> Box<dyn Error> {
-    Box::new(ConfError(s.into()))
+impl From<io::Error> for ConfError {
+    fn from(value: io::Error) -> Self {
+        Self {
+            message: value.to_string(),
+            span: None,
+        }
+    }
 }
 
 macro_rules! define_Conf {
@@ -117,20 +157,14 @@ macro_rules! define_Conf {
             }
         }
 
-        impl<'de> Deserialize<'de> for TryConf {
-            fn deserialize<D>(deserializer: D) -> Result<Self, D::Error> where D: Deserializer<'de> {
-                deserializer.deserialize_map(ConfVisitor)
-            }
-        }
-
         #[derive(Deserialize)]
         #[serde(field_identifier, rename_all = "kebab-case")]
         #[allow(non_camel_case_types)]
         enum Field { $($name,)* third_party, }
 
-        struct ConfVisitor;
+        struct ConfVisitor<'a>(&'a SourceFile);
 
-        impl<'de> Visitor<'de> for ConfVisitor {
+        impl<'de> Visitor<'de> for ConfVisitor<'_> {
             type Value = TryConf;
 
             fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
@@ -141,32 +175,38 @@ macro_rules! define_Conf {
                 let mut errors = Vec::new();
                 let mut warnings = Vec::new();
                 $(let mut $name = None;)*
-                // could get `Field` here directly, but get `str` first for diagnostics
-                while let Some(name) = map.next_key::<&str>()? {
-                    match Field::deserialize(name.into_deserializer())? {
-                        $(Field::$name => {
-                            $(warnings.push(conf_error(format!("deprecated field `{}`. {}", name, $dep)));)?
-                            match map.next_value() {
-                                Err(e) => errors.push(conf_error(e.to_string())),
+                // could get `Field` here directly, but get `String` first for diagnostics
+                while let Some(name) = map.next_key::<toml::Spanned<String>>()? {
+                    match Field::deserialize(name.get_ref().as_str().into_deserializer()) {
+                        Err(e) => {
+                            let e: FieldError = e;
+                            errors.push(ConfError::spanned(self.0, e.0, name.span()));
+                        }
+                        $(Ok(Field::$name) => {
+                            $(warnings.push(ConfError::spanned(self.0, format!("deprecated field `{}`. {}", name.get_ref(), $dep), name.span()));)?
+                            let raw_value = map.next_value::<toml::Spanned<toml::Value>>()?;
+                            let value_span = raw_value.span();
+                            match <$ty>::deserialize(raw_value.into_inner()) {
+                                Err(e) => errors.push(ConfError::spanned(self.0, e.to_string().replace('\n', " ").trim(), value_span)),
                                 Ok(value) => match $name {
-                                    Some(_) => errors.push(conf_error(format!("duplicate field `{}`", name))),
+                                    Some(_) => errors.push(ConfError::spanned(self.0, format!("duplicate field `{}`", name.get_ref()), name.span())),
                                     None => {
                                         $name = Some(value);
                                         // $new_conf is the same as one of the defined `$name`s, so
                                         // this variable is defined in line 2 of this function.
                                         $(match $new_conf {
-                                            Some(_) => errors.push(conf_error(concat!(
+                                            Some(_) => errors.push(ConfError::spanned(self.0, concat!(
                                                 "duplicate field `", stringify!($new_conf),
                                                 "` (provided as `", stringify!($name), "`)"
-                                            ))),
+                                            ), name.span())),
                                             None => $new_conf = $name.clone(),
                                         })?
                                     },
                                 }
                             }
                         })*
-                        // white-listed; ignore
-                        Field::third_party => drop(map.next_value::<IgnoredAny>())
+                        // ignore contents of the third_party key
+                        Ok(Field::third_party) => drop(map.next_value::<IgnoredAny>())
                     }
                 }
                 let conf = Conf { $($name: $name.unwrap_or_else(defaults::$name),)* };
@@ -486,7 +526,7 @@ pub fn lookup_conf_file() -> io::Result<(Option<PathBuf>, Vec<String>)> {
     const CONFIG_FILE_NAMES: [&str; 2] = [".clippy.toml", "clippy.toml"];
 
     // Start looking for a config file in CLIPPY_CONF_DIR, or failing that, CARGO_MANIFEST_DIR.
-    // If neither of those exist, use ".".
+    // If neither of those exist, use ".". (Update documentation if this priority changes)
     let mut current = env::var_os("CLIPPY_CONF_DIR")
         .or_else(|| env::var_os("CARGO_MANIFEST_DIR"))
         .map_or_else(|| PathBuf::from("."), PathBuf::from)
@@ -532,19 +572,19 @@ pub fn lookup_conf_file() -> io::Result<(Option<PathBuf>, Vec<String>)> {
 /// Read the `toml` configuration file.
 ///
 /// In case of error, the function tries to continue as much as possible.
-pub fn read(path: &Path) -> TryConf {
-    let content = match fs::read_to_string(path) {
-        Err(e) => return TryConf::from_error(e),
-        Ok(content) => content,
+pub fn read(sess: &Session, path: &Path) -> TryConf {
+    let file = match sess.source_map().load_file(path) {
+        Err(e) => return e.into(),
+        Ok(file) => file,
     };
-    match toml::from_str::<TryConf>(&content) {
+    match toml::de::Deserializer::new(file.src.as_ref().unwrap()).deserialize_map(ConfVisitor(&file)) {
         Ok(mut conf) => {
             extend_vec_if_indicator_present(&mut conf.conf.doc_valid_idents, DEFAULT_DOC_VALID_IDENTS);
             extend_vec_if_indicator_present(&mut conf.conf.disallowed_names, DEFAULT_DISALLOWED_NAMES);
 
             conf
         },
-        Err(e) => TryConf::from_error(e),
+        Err(e) => TryConf::from_toml_error(&file, &e),
     }
 }
 
@@ -556,65 +596,42 @@ fn extend_vec_if_indicator_present(vec: &mut Vec<String>, default: &[&str]) {
 
 const SEPARATOR_WIDTH: usize = 4;
 
-// Check whether the error is "unknown field" and, if so, list the available fields sorted and at
-// least one per line, more if `CLIPPY_TERMINAL_WIDTH` is set and allows it.
-pub fn format_error(error: Box<dyn Error>) -> String {
-    let s = error.to_string();
-
-    if_chain! {
-        if error.downcast::<toml::de::Error>().is_ok();
-        if let Some((prefix, mut fields, suffix)) = parse_unknown_field_message(&s);
-        then {
-            use fmt::Write;
-
-            fields.sort_unstable();
-
-            let (rows, column_widths) = calculate_dimensions(&fields);
-
-            let mut msg = String::from(prefix);
-            for row in 0..rows {
-                writeln!(msg).unwrap();
-                for (column, column_width) in column_widths.iter().copied().enumerate() {
-                    let index = column * rows + row;
-                    let field = fields.get(index).copied().unwrap_or_default();
-                    write!(
-                        msg,
-                        "{:SEPARATOR_WIDTH$}{field:column_width$}",
-                        " "
-                    )
-                    .unwrap();
-                }
-            }
-            write!(msg, "\n{suffix}").unwrap();
-            msg
-        } else {
-            s
-        }
+#[derive(Debug)]
+struct FieldError(String);
+
+impl std::error::Error for FieldError {}
+
+impl Display for FieldError {
+    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
+        f.pad(&self.0)
     }
 }
 
-// `parse_unknown_field_message` will become unnecessary if
-// https://github.com/alexcrichton/toml-rs/pull/364 is merged.
-fn parse_unknown_field_message(s: &str) -> Option<(&str, Vec<&str>, &str)> {
-    // An "unknown field" message has the following form:
-    //   unknown field `UNKNOWN`, expected one of `FIELD0`, `FIELD1`, ..., `FIELDN` at line X column Y
-    //                                           ^^      ^^^^                     ^^
-    if_chain! {
-        if s.starts_with("unknown field");
-        let slices = s.split("`, `").collect::<Vec<_>>();
-        let n = slices.len();
-        if n >= 2;
-        if let Some((prefix, first_field)) = slices[0].rsplit_once(" `");
-        if let Some((last_field, suffix)) = slices[n - 1].split_once("` ");
-        then {
-            let fields = iter::once(first_field)
-                .chain(slices[1..n - 1].iter().copied())
-                .chain(iter::once(last_field))
-                .collect::<Vec<_>>();
-            Some((prefix, fields, suffix))
-        } else {
-            None
+impl serde::de::Error for FieldError {
+    fn custom<T: Display>(msg: T) -> Self {
+        Self(msg.to_string())
+    }
+
+    fn unknown_field(field: &str, expected: &'static [&'static str]) -> Self {
+        // List the available fields sorted and at least one per line, more if `CLIPPY_TERMINAL_WIDTH` is
+        // set and allows it.
+        use fmt::Write;
+
+        let mut expected = expected.to_vec();
+        expected.sort_unstable();
+
+        let (rows, column_widths) = calculate_dimensions(&expected);
+
+        let mut msg = format!("unknown field `{field}`, expected one of");
+        for row in 0..rows {
+            writeln!(msg).unwrap();
+            for (column, column_width) in column_widths.iter().copied().enumerate() {
+                let index = column * rows + row;
+                let field = expected.get(index).copied().unwrap_or_default();
+                write!(msg, "{:SEPARATOR_WIDTH$}{field:column_width$}", " ").unwrap();
+            }
         }
+        Self(msg)
     }
 }
 
diff --git a/src/tools/clippy/clippy_lints/src/wildcard_imports.rs b/src/tools/clippy/clippy_lints/src/wildcard_imports.rs
index a9089fba3c5..b6e4cd22789 100644
--- a/src/tools/clippy/clippy_lints/src/wildcard_imports.rs
+++ b/src/tools/clippy/clippy_lints/src/wildcard_imports.rs
@@ -65,8 +65,9 @@ declare_clippy_lint! {
     /// This can lead to confusing error messages at best and to unexpected behavior at worst.
     ///
     /// ### Exceptions
-    /// Wildcard imports are allowed from modules named `prelude`. Many crates (including the standard library)
-    /// provide modules named "prelude" specifically designed for wildcard import.
+    /// Wildcard imports are allowed from modules that their name contains `prelude`. Many crates
+    /// (including the standard library) provide modules named "prelude" specifically designed
+    /// for wildcard import.
     ///
     /// `use super::*` is allowed in test modules. This is defined as any module with "test" in the name.
     ///
@@ -212,7 +213,9 @@ impl WildcardImports {
 // Allow "...prelude::..::*" imports.
 // Many crates have a prelude, and it is imported as a glob by design.
 fn is_prelude_import(segments: &[PathSegment<'_>]) -> bool {
-    segments.iter().any(|ps| ps.ident.name == sym::prelude)
+    segments
+        .iter()
+        .any(|ps| ps.ident.name.as_str().contains(sym::prelude.as_str()))
 }
 
 // Allow "super::*" imports in tests.
diff --git a/src/tools/clippy/clippy_utils/Cargo.toml b/src/tools/clippy/clippy_utils/Cargo.toml
index 66a5079fa85..cfe686eb9b0 100644
--- a/src/tools/clippy/clippy_utils/Cargo.toml
+++ b/src/tools/clippy/clippy_utils/Cargo.toml
@@ -1,6 +1,6 @@
 [package]
 name = "clippy_utils"
-version = "0.1.71"
+version = "0.1.72"
 edition = "2021"
 publish = false
 
diff --git a/src/tools/clippy/clippy_utils/src/lib.rs b/src/tools/clippy/clippy_utils/src/lib.rs
index 575c29a6b6f..8c883445a79 100644
--- a/src/tools/clippy/clippy_utils/src/lib.rs
+++ b/src/tools/clippy/clippy_utils/src/lib.rs
@@ -287,7 +287,7 @@ pub fn is_wild(pat: &Pat<'_>) -> bool {
 /// Checks if the given `QPath` belongs to a type alias.
 pub fn is_ty_alias(qpath: &QPath<'_>) -> bool {
     match *qpath {
-        QPath::Resolved(_, path) => matches!(path.res, Res::Def(DefKind::TyAlias, ..)),
+        QPath::Resolved(_, path) => matches!(path.res, Res::Def(DefKind::TyAlias | DefKind::AssocTy, ..)),
         QPath::TypeRelative(ty, _) if let TyKind::Path(qpath) = ty.kind => { is_ty_alias(&qpath) },
         _ => false,
     }
diff --git a/src/tools/clippy/clippy_utils/src/msrvs.rs b/src/tools/clippy/clippy_utils/src/msrvs.rs
index e05de2dc99c..6f102308f0b 100644
--- a/src/tools/clippy/clippy_utils/src/msrvs.rs
+++ b/src/tools/clippy/clippy_utils/src/msrvs.rs
@@ -20,7 +20,7 @@ macro_rules! msrv_aliases {
 // names may refer to stabilized feature flags or library items
 msrv_aliases! {
     1,68,0 { PATH_MAIN_SEPARATOR_STR }
-    1,65,0 { LET_ELSE }
+    1,65,0 { LET_ELSE, POINTER_CAST_CONSTNESS }
     1,62,0 { BOOL_THEN_SOME, DEFAULT_ENUM_ATTRIBUTE }
     1,58,0 { FORMAT_ARGS_CAPTURE, PATTERN_TRAIT_CHAR_ARRAY }
     1,55,0 { SEEK_REWIND }
diff --git a/src/tools/clippy/clippy_utils/src/paths.rs b/src/tools/clippy/clippy_utils/src/paths.rs
index 0f0792fdaa9..38ee84fb76c 100644
--- a/src/tools/clippy/clippy_utils/src/paths.rs
+++ b/src/tools/clippy/clippy_utils/src/paths.rs
@@ -125,8 +125,6 @@ pub const STRING_NEW: [&str; 4] = ["alloc", "string", "String", "new"];
 pub const STR_BYTES: [&str; 4] = ["core", "str", "<impl str>", "bytes"];
 pub const STR_CHARS: [&str; 4] = ["core", "str", "<impl str>", "chars"];
 pub const STR_ENDS_WITH: [&str; 4] = ["core", "str", "<impl str>", "ends_with"];
-pub const STR_FROM_UTF8: [&str; 4] = ["core", "str", "converts", "from_utf8"];
-pub const STR_FROM_UTF8_UNCHECKED: [&str; 4] = ["core", "str", "converts", "from_utf8_unchecked"];
 pub const STR_LEN: [&str; 4] = ["core", "str", "<impl str>", "len"];
 pub const STR_STARTS_WITH: [&str; 4] = ["core", "str", "<impl str>", "starts_with"];
 #[cfg(feature = "internal")]
@@ -163,3 +161,5 @@ pub const VEC_IS_EMPTY: [&str; 4] = ["alloc", "vec", "Vec", "is_empty"];
 pub const VEC_POP: [&str; 4] = ["alloc", "vec", "Vec", "pop"];
 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"];
diff --git a/src/tools/clippy/clippy_utils/src/source.rs b/src/tools/clippy/clippy_utils/src/source.rs
index 0f60290644a..582337b47e8 100644
--- a/src/tools/clippy/clippy_utils/src/source.rs
+++ b/src/tools/clippy/clippy_utils/src/source.rs
@@ -4,7 +4,7 @@
 
 use rustc_data_structures::sync::Lrc;
 use rustc_errors::Applicability;
-use rustc_hir::{Expr, ExprKind};
+use rustc_hir::{BlockCheckMode, Expr, ExprKind, UnsafeSource};
 use rustc_lint::{LateContext, LintContext};
 use rustc_session::Session;
 use rustc_span::source_map::{original_sp, SourceMap};
@@ -71,11 +71,16 @@ pub fn expr_block<T: LintContext>(
     app: &mut Applicability,
 ) -> String {
     let (code, from_macro) = snippet_block_with_context(cx, expr.span, outer, default, indent_relative_to, app);
-    if from_macro {
-        format!("{{ {code} }}")
-    } else if let ExprKind::Block(_, _) = expr.kind {
+    if !from_macro &&
+        let ExprKind::Block(block, _) = expr.kind &&
+        block.rules != BlockCheckMode::UnsafeBlock(UnsafeSource::UserProvided)
+    {
         format!("{code}")
     } else {
+        // FIXME: add extra indent for the unsafe blocks:
+        //     original code:   unsafe { ... }
+        //     result code:     { unsafe { ... } }
+        //     desired code:    {\n  unsafe { ... }\n}
         format!("{{ {code} }}")
     }
 }
diff --git a/src/tools/clippy/declare_clippy_lint/Cargo.toml b/src/tools/clippy/declare_clippy_lint/Cargo.toml
index 139102798c4..4dc906d00db 100644
--- a/src/tools/clippy/declare_clippy_lint/Cargo.toml
+++ b/src/tools/clippy/declare_clippy_lint/Cargo.toml
@@ -1,6 +1,6 @@
 [package]
 name = "declare_clippy_lint"
-version = "0.1.71"
+version = "0.1.72"
 edition = "2021"
 publish = false
 
diff --git a/src/tools/clippy/lintcheck/Cargo.toml b/src/tools/clippy/lintcheck/Cargo.toml
index 27d32f39003..a828d123704 100644
--- a/src/tools/clippy/lintcheck/Cargo.toml
+++ b/src/tools/clippy/lintcheck/Cargo.toml
@@ -22,7 +22,7 @@ rayon = "1.5.1"
 serde = { version = "1.0", features = ["derive"] }
 serde_json = "1.0.85"
 tar = "0.4"
-toml = "0.5"
+toml = "0.7.3"
 ureq = "2.2"
 walkdir = "2.3"
 
diff --git a/src/tools/clippy/rust-toolchain b/src/tools/clippy/rust-toolchain
index bc7fb711ed8..0d2e1eee643 100644
--- a/src/tools/clippy/rust-toolchain
+++ b/src/tools/clippy/rust-toolchain
@@ -1,3 +1,3 @@
 [toolchain]
-channel = "nightly-2023-05-20"
+channel = "nightly-2023-06-02"
 components = ["cargo", "llvm-tools", "rust-src", "rust-std", "rustc", "rustc-dev", "rustfmt"]
diff --git a/src/tools/clippy/src/driver.rs b/src/tools/clippy/src/driver.rs
index 59bf447a7cd..3c5b6e12b96 100644
--- a/src/tools/clippy/src/driver.rs
+++ b/src/tools/clippy/src/driver.rs
@@ -70,7 +70,7 @@ fn track_clippy_args(parse_sess: &mut ParseSess, args_env_var: &Option<String>)
 
 /// Track files that may be accessed at runtime in `file_depinfo` so that cargo will re-run clippy
 /// when any of them are modified
-fn track_files(parse_sess: &mut ParseSess, conf_path_string: Option<String>) {
+fn track_files(parse_sess: &mut ParseSess) {
     let file_depinfo = parse_sess.file_depinfo.get_mut();
 
     // Used by `clippy::cargo` lints and to determine the MSRV. `cargo clippy` executes `clippy-driver`
@@ -79,10 +79,7 @@ fn track_files(parse_sess: &mut ParseSess, conf_path_string: Option<String>) {
         file_depinfo.insert(Symbol::intern("Cargo.toml"));
     }
 
-    // `clippy.toml`
-    if let Some(path) = conf_path_string {
-        file_depinfo.insert(Symbol::intern(&path));
-    }
+    // `clippy.toml` will be automatically tracked as it's loaded with `sess.source_map().load_file()`
 
     // During development track the `clippy-driver` executable so that cargo will re-run clippy whenever
     // it is rebuilt
@@ -126,17 +123,11 @@ impl rustc_driver::Callbacks for ClippyCallbacks {
     #[allow(rustc::bad_opt_access)]
     fn config(&mut self, config: &mut interface::Config) {
         let conf_path = clippy_lints::lookup_conf_file();
-        let conf_path_string = if let Ok((Some(path), _)) = &conf_path {
-            path.to_str().map(String::from)
-        } else {
-            None
-        };
-
         let previous = config.register_lints.take();
         let clippy_args_var = self.clippy_args_var.take();
         config.parse_sess_created = Some(Box::new(move |parse_sess| {
             track_clippy_args(parse_sess, &clippy_args_var);
-            track_files(parse_sess, conf_path_string);
+            track_files(parse_sess);
         }));
         config.register_lints = Some(Box::new(move |sess, lint_store| {
             // technically we're ~guaranteed that this is none but might as well call anything that
diff --git a/src/tools/clippy/tests/ui-cargo/multiple_crate_versions/fail/Cargo.lock b/src/tools/clippy/tests/ui-cargo/multiple_crate_versions/fail/Cargo.lock
index 7e96aa36feb..e4de82ad3b8 100644
--- a/src/tools/clippy/tests/ui-cargo/multiple_crate_versions/fail/Cargo.lock
+++ b/src/tools/clippy/tests/ui-cargo/multiple_crate_versions/fail/Cargo.lock
@@ -1,5 +1,7 @@
 # This file is automatically @generated by Cargo.
 # It is not intended for manual editing.
+version = 3
+
 [[package]]
 name = "ansi_term"
 version = "0.11.0"
@@ -10,71 +12,14 @@ dependencies = [
 ]
 
 [[package]]
-name = "bitflags"
-version = "0.9.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4efd02e230a02e18f92fc2735f44597385ed02ad8f831e7c1c1156ee5e1ab3a5"
-
-[[package]]
-name = "cfg-if"
-version = "0.1.10"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822"
-
-[[package]]
-name = "ctrlc"
-version = "3.1.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "653abc99aa905f693d89df4797fadc08085baee379db92be9f2496cefe8a6f2c"
-dependencies = [
- "kernel32-sys",
- "nix",
- "winapi 0.2.8",
-]
-
-[[package]]
-name = "kernel32-sys"
-version = "0.2.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7507624b29483431c0ba2d82aece8ca6cdba9382bff4ddd0f7490560c056098d"
-dependencies = [
- "winapi 0.2.8",
- "winapi-build",
-]
-
-[[package]]
-name = "libc"
-version = "0.2.71"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9457b06509d27052635f90d6466700c65095fdf75409b3fbdd903e988b886f49"
-
-[[package]]
 name = "multiple_crate_versions"
 version = "0.1.0"
 dependencies = [
  "ansi_term",
- "ctrlc",
-]
-
-[[package]]
-name = "nix"
-version = "0.9.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a2c5afeb0198ec7be8569d666644b574345aad2e95a53baf3a532da3e0f3fb32"
-dependencies = [
- "bitflags",
- "cfg-if",
- "libc",
- "void",
+ "winapi 0.2.8",
 ]
 
 [[package]]
-name = "void"
-version = "1.0.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d"
-
-[[package]]
 name = "winapi"
 version = "0.2.8"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -91,12 +36,6 @@ dependencies = [
 ]
 
 [[package]]
-name = "winapi-build"
-version = "0.1.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2d315eee3b34aca4797b2da6b13ed88266e6d612562a0c46390af8299fc699bc"
-
-[[package]]
 name = "winapi-i686-pc-windows-gnu"
 version = "0.4.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
diff --git a/src/tools/clippy/tests/ui-cargo/multiple_crate_versions/fail/Cargo.toml b/src/tools/clippy/tests/ui-cargo/multiple_crate_versions/fail/Cargo.toml
index 4f97b011334..79317659ac0 100644
--- a/src/tools/clippy/tests/ui-cargo/multiple_crate_versions/fail/Cargo.toml
+++ b/src/tools/clippy/tests/ui-cargo/multiple_crate_versions/fail/Cargo.toml
@@ -6,5 +6,5 @@ publish = false
 [workspace]
 
 [dependencies]
-ctrlc = "=3.1.0"
+winapi = "0.2"
 ansi_term = "=0.11.0"
diff --git a/src/tools/clippy/tests/ui-internal/custom_ice_message.rs b/src/tools/clippy/tests/ui-internal/custom_ice_message.rs
index 99ce7028390..9b0db660c99 100644
--- a/src/tools/clippy/tests/ui-internal/custom_ice_message.rs
+++ b/src/tools/clippy/tests/ui-internal/custom_ice_message.rs
@@ -3,7 +3,7 @@
 //@normalize-stderr-test: "produce_ice.rs:\d*:\d*" -> "produce_ice.rs"
 //@normalize-stderr-test: "', .*clippy_lints" -> "', clippy_lints"
 //@normalize-stderr-test: "'rustc'" -> "'<unnamed>'"
-//@normalize-stderr-test: "running on .*" -> "running on <target>"
+//@normalize-stderr-test: "rustc 1\.\d+.* running on .*" -> "rustc <version> running on <target>"
 //@normalize-stderr-test: "(?ms)query stack during panic:\n.*end of query stack\n" -> ""
 
 #![deny(clippy::internal)]
diff --git a/src/tools/clippy/tests/ui-internal/custom_ice_message.stderr b/src/tools/clippy/tests/ui-internal/custom_ice_message.stderr
index 0fc385cd693..b9ea5a64de7 100644
--- a/src/tools/clippy/tests/ui-internal/custom_ice_message.stderr
+++ b/src/tools/clippy/tests/ui-internal/custom_ice_message.stderr
@@ -5,10 +5,9 @@ error: the compiler unexpectedly panicked. this is a bug.
 
 note: we would appreciate a bug report: https://github.com/rust-lang/rust-clippy/issues/new
 
-note: rustc 1.71.0-nightly (521f4dae1 2023-05-19) running on <target>
+note: rustc <version> running on <target>
 
 note: compiler flags: -C prefer-dynamic -Z ui-testing
 
-note: Clippy version: foo
-
-thread panicked while panicking. aborting.
+query stack during panic:
+thread panicked while processing panic. aborting.
diff --git a/src/tools/clippy/tests/ui-toml/bad_toml/conf_bad_toml.stderr b/src/tools/clippy/tests/ui-toml/bad_toml/conf_bad_toml.stderr
index 28c1a568a63..5b7e8c0db74 100644
--- a/src/tools/clippy/tests/ui-toml/bad_toml/conf_bad_toml.stderr
+++ b/src/tools/clippy/tests/ui-toml/bad_toml/conf_bad_toml.stderr
@@ -1,4 +1,8 @@
-error: error reading Clippy's configuration file `$DIR/clippy.toml`: expected an equals, found an identifier at line 1 column 4
+error: error reading Clippy's configuration file: expected `.`, `=`
+  --> $DIR/clippy.toml:1:4
+   |
+LL | fn this_is_obviously(not: a, toml: file) {
+   |    ^
 
 error: aborting due to previous error
 
diff --git a/src/tools/clippy/tests/ui-toml/bad_toml_type/conf_bad_type.stderr b/src/tools/clippy/tests/ui-toml/bad_toml_type/conf_bad_type.stderr
index e3ec6019204..386e1135df9 100644
--- a/src/tools/clippy/tests/ui-toml/bad_toml_type/conf_bad_type.stderr
+++ b/src/tools/clippy/tests/ui-toml/bad_toml_type/conf_bad_type.stderr
@@ -1,4 +1,8 @@
-error: error reading Clippy's configuration file `$DIR/clippy.toml`: invalid type: integer `42`, expected a sequence for key `disallowed-names`
+error: error reading Clippy's configuration file: invalid type: integer `42`, expected a sequence
+  --> $DIR/clippy.toml:1:20
+   |
+LL | disallowed-names = 42
+   |                    ^^
 
 error: aborting due to previous error
 
diff --git a/src/tools/clippy/tests/ui-toml/conf_deprecated_key/conf_deprecated_key.stderr b/src/tools/clippy/tests/ui-toml/conf_deprecated_key/conf_deprecated_key.stderr
index 630bad07c5b..123ad94dd09 100644
--- a/src/tools/clippy/tests/ui-toml/conf_deprecated_key/conf_deprecated_key.stderr
+++ b/src/tools/clippy/tests/ui-toml/conf_deprecated_key/conf_deprecated_key.stderr
@@ -1,6 +1,14 @@
-warning: error reading Clippy's configuration file `$DIR/clippy.toml`: deprecated field `cyclomatic-complexity-threshold`. Please use `cognitive-complexity-threshold` instead
+warning: error reading Clippy's configuration file: deprecated field `cyclomatic-complexity-threshold`. Please use `cognitive-complexity-threshold` instead
+  --> $DIR/clippy.toml:2:1
+   |
+LL | cyclomatic-complexity-threshold = 2
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
-warning: error reading Clippy's configuration file `$DIR/clippy.toml`: deprecated field `blacklisted-names`. Please use `disallowed-names` instead
+warning: error reading Clippy's configuration file: deprecated field `blacklisted-names`. Please use `disallowed-names` instead
+  --> $DIR/clippy.toml:3:1
+   |
+LL | blacklisted-names = [ "..", "wibble" ]
+   | ^^^^^^^^^^^^^^^^^
 
 error: the function has a cognitive complexity of (3/2)
   --> $DIR/conf_deprecated_key.rs:6:4
diff --git a/src/tools/clippy/tests/ui-toml/duplicated_keys/clippy.toml b/src/tools/clippy/tests/ui-toml/duplicated_keys/clippy.toml
index 63a893cc6c7..55789afc1b7 100644
--- a/src/tools/clippy/tests/ui-toml/duplicated_keys/clippy.toml
+++ b/src/tools/clippy/tests/ui-toml/duplicated_keys/clippy.toml
@@ -1,5 +1,2 @@
 cognitive-complexity-threshold = 2
-# This is the deprecated name for the same key
-cyclomatic-complexity-threshold = 3
-# Check we get duplication warning regardless of order
 cognitive-complexity-threshold = 4
diff --git a/src/tools/clippy/tests/ui-toml/duplicated_keys/duplicated_keys.stderr b/src/tools/clippy/tests/ui-toml/duplicated_keys/duplicated_keys.stderr
index d99490a242d..54997735274 100644
--- a/src/tools/clippy/tests/ui-toml/duplicated_keys/duplicated_keys.stderr
+++ b/src/tools/clippy/tests/ui-toml/duplicated_keys/duplicated_keys.stderr
@@ -1,8 +1,8 @@
-error: error reading Clippy's configuration file `$DIR/clippy.toml`: duplicate field `cognitive_complexity_threshold` (provided as `cyclomatic_complexity_threshold`)
+error: error reading Clippy's configuration file: duplicate key `cognitive-complexity-threshold` in document root
+  --> $DIR/clippy.toml:2:1
+   |
+LL | cognitive-complexity-threshold = 4
+   | ^
 
-error: error reading Clippy's configuration file `$DIR/clippy.toml`: duplicate field `cognitive-complexity-threshold`
-
-warning: error reading Clippy's configuration file `$DIR/clippy.toml`: deprecated field `cyclomatic-complexity-threshold`. Please use `cognitive-complexity-threshold` instead
-
-error: aborting due to 2 previous errors; 1 warning emitted
+error: aborting due to previous error
 
diff --git a/src/tools/clippy/tests/ui-toml/duplicated_keys_deprecated/clippy.toml b/src/tools/clippy/tests/ui-toml/duplicated_keys_deprecated/clippy.toml
new file mode 100644
index 00000000000..7932c43ebd2
--- /dev/null
+++ b/src/tools/clippy/tests/ui-toml/duplicated_keys_deprecated/clippy.toml
@@ -0,0 +1,3 @@
+cognitive-complexity-threshold = 2
+# This is the deprecated name for the same key
+cyclomatic-complexity-threshold = 3
diff --git a/src/tools/clippy/tests/ui-toml/duplicated_keys_deprecated/duplicated_keys.rs b/src/tools/clippy/tests/ui-toml/duplicated_keys_deprecated/duplicated_keys.rs
new file mode 100644
index 00000000000..f328e4d9d04
--- /dev/null
+++ b/src/tools/clippy/tests/ui-toml/duplicated_keys_deprecated/duplicated_keys.rs
@@ -0,0 +1 @@
+fn main() {}
diff --git a/src/tools/clippy/tests/ui-toml/duplicated_keys_deprecated/duplicated_keys.stderr b/src/tools/clippy/tests/ui-toml/duplicated_keys_deprecated/duplicated_keys.stderr
new file mode 100644
index 00000000000..2ae7848f183
--- /dev/null
+++ b/src/tools/clippy/tests/ui-toml/duplicated_keys_deprecated/duplicated_keys.stderr
@@ -0,0 +1,14 @@
+error: error reading Clippy's configuration file: duplicate field `cognitive_complexity_threshold` (provided as `cyclomatic_complexity_threshold`)
+  --> $DIR/clippy.toml:3:1
+   |
+LL | cyclomatic-complexity-threshold = 3
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+warning: error reading Clippy's configuration file: deprecated field `cyclomatic-complexity-threshold`. Please use `cognitive-complexity-threshold` instead
+  --> $DIR/clippy.toml:3:1
+   |
+LL | cyclomatic-complexity-threshold = 3
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to previous error; 1 warning emitted
+
diff --git a/src/tools/clippy/tests/ui-toml/duplicated_keys_deprecated_2/clippy.toml b/src/tools/clippy/tests/ui-toml/duplicated_keys_deprecated_2/clippy.toml
new file mode 100644
index 00000000000..53c634b727e
--- /dev/null
+++ b/src/tools/clippy/tests/ui-toml/duplicated_keys_deprecated_2/clippy.toml
@@ -0,0 +1,4 @@
+# This is the deprecated name for cognitive-complexity-threshold
+cyclomatic-complexity-threshold = 3
+# Check we get duplication warning regardless of order
+cognitive-complexity-threshold = 4
diff --git a/src/tools/clippy/tests/ui-toml/duplicated_keys_deprecated_2/duplicated_keys.rs b/src/tools/clippy/tests/ui-toml/duplicated_keys_deprecated_2/duplicated_keys.rs
new file mode 100644
index 00000000000..f328e4d9d04
--- /dev/null
+++ b/src/tools/clippy/tests/ui-toml/duplicated_keys_deprecated_2/duplicated_keys.rs
@@ -0,0 +1 @@
+fn main() {}
diff --git a/src/tools/clippy/tests/ui-toml/duplicated_keys_deprecated_2/duplicated_keys.stderr b/src/tools/clippy/tests/ui-toml/duplicated_keys_deprecated_2/duplicated_keys.stderr
new file mode 100644
index 00000000000..53ad4271246
--- /dev/null
+++ b/src/tools/clippy/tests/ui-toml/duplicated_keys_deprecated_2/duplicated_keys.stderr
@@ -0,0 +1,14 @@
+error: error reading Clippy's configuration file: duplicate field `cognitive-complexity-threshold`
+  --> $DIR/clippy.toml:4:1
+   |
+LL | cognitive-complexity-threshold = 4
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+warning: error reading Clippy's configuration file: deprecated field `cyclomatic-complexity-threshold`. Please use `cognitive-complexity-threshold` instead
+  --> $DIR/clippy.toml:2:1
+   |
+LL | cyclomatic-complexity-threshold = 3
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to previous error; 1 warning emitted
+
diff --git a/src/tools/clippy/tests/ui-toml/ifs_same_cond/ifs_same_cond.rs b/src/tools/clippy/tests/ui-toml/ifs_same_cond/ifs_same_cond.rs
index d623ac7e020..4882416c414 100644
--- a/src/tools/clippy/tests/ui-toml/ifs_same_cond/ifs_same_cond.rs
+++ b/src/tools/clippy/tests/ui-toml/ifs_same_cond/ifs_same_cond.rs
@@ -1,5 +1,5 @@
 #![warn(clippy::ifs_same_cond)]
-#![allow(clippy::if_same_then_else, clippy::comparison_chain)]
+#![allow(clippy::if_same_then_else, clippy::comparison_chain, clippy::needless_else)]
 
 fn main() {}
 
diff --git a/src/tools/clippy/tests/ui-toml/toml_unknown_key/clippy.toml b/src/tools/clippy/tests/ui-toml/toml_unknown_key/clippy.toml
index 554b87cc50b..b77b4580051 100644
--- a/src/tools/clippy/tests/ui-toml/toml_unknown_key/clippy.toml
+++ b/src/tools/clippy/tests/ui-toml/toml_unknown_key/clippy.toml
@@ -1,6 +1,8 @@
 # that one is an error
 foobar = 42
+# so is this one
+barfoo = 53
 
-# that one is white-listed
+# that one is ignored
 [third-party]
 clippy-feature = "nightly"
diff --git a/src/tools/clippy/tests/ui-toml/toml_unknown_key/conf_unknown_key.stderr b/src/tools/clippy/tests/ui-toml/toml_unknown_key/conf_unknown_key.stderr
index 44710b09648..b6038f031f3 100644
--- a/src/tools/clippy/tests/ui-toml/toml_unknown_key/conf_unknown_key.stderr
+++ b/src/tools/clippy/tests/ui-toml/toml_unknown_key/conf_unknown_key.stderr
@@ -1,4 +1,4 @@
-error: error reading Clippy's configuration file `$DIR/clippy.toml`: unknown field `foobar`, expected one of
+error: error reading Clippy's configuration file: unknown field `foobar`, expected one of
            allow-dbg-in-tests
            allow-expect-in-tests
            allow-mixed-uninlined-format-args
@@ -54,7 +54,71 @@ error: error reading Clippy's configuration file `$DIR/clippy.toml`: unknown fie
            vec-box-size-threshold
            verbose-bit-mask-threshold
            warn-on-all-wildcard-imports
-       at line 5 column 1
+  --> $DIR/clippy.toml:2:1
+   |
+LL | foobar = 42
+   | ^^^^^^
 
-error: aborting due to previous error
+error: error reading Clippy's configuration file: unknown field `barfoo`, expected one of
+           allow-dbg-in-tests
+           allow-expect-in-tests
+           allow-mixed-uninlined-format-args
+           allow-print-in-tests
+           allow-unwrap-in-tests
+           allowed-scripts
+           arithmetic-side-effects-allowed
+           arithmetic-side-effects-allowed-binary
+           arithmetic-side-effects-allowed-unary
+           array-size-threshold
+           avoid-breaking-exported-api
+           await-holding-invalid-types
+           blacklisted-names
+           cargo-ignore-publish
+           cognitive-complexity-threshold
+           cyclomatic-complexity-threshold
+           disallowed-macros
+           disallowed-methods
+           disallowed-names
+           disallowed-types
+           doc-valid-idents
+           enable-raw-pointer-heuristic-for-send
+           enforced-import-renames
+           enum-variant-name-threshold
+           enum-variant-size-threshold
+           future-size-threshold
+           ignore-interior-mutability
+           large-error-threshold
+           literal-representation-threshold
+           matches-for-let-else
+           max-fn-params-bools
+           max-include-file-size
+           max-struct-bools
+           max-suggested-slice-pattern-length
+           max-trait-bounds
+           missing-docs-in-crate-items
+           msrv
+           pass-by-value-size-limit
+           semicolon-inside-block-ignore-singleline
+           semicolon-outside-block-ignore-multiline
+           single-char-binding-names-threshold
+           standard-macro-braces
+           suppress-restriction-lint-in-const
+           third-party
+           too-large-for-stack
+           too-many-arguments-threshold
+           too-many-lines-threshold
+           trivial-copy-size-limit
+           type-complexity-threshold
+           unnecessary-box-size
+           unreadable-literal-lint-fractions
+           upper-case-acronyms-aggressive
+           vec-box-size-threshold
+           verbose-bit-mask-threshold
+           warn-on-all-wildcard-imports
+  --> $DIR/clippy.toml:4:1
+   |
+LL | barfoo = 53
+   | ^^^^^^
+
+error: aborting due to 2 previous errors
 
diff --git a/src/tools/clippy/tests/ui/auxiliary/wildcard_imports_helper.rs b/src/tools/clippy/tests/ui/auxiliary/wildcard_imports_helper.rs
index d75cdd625f9..44f49c080cd 100644
--- a/src/tools/clippy/tests/ui/auxiliary/wildcard_imports_helper.rs
+++ b/src/tools/clippy/tests/ui/auxiliary/wildcard_imports_helper.rs
@@ -25,3 +25,9 @@ pub mod prelude {
         pub struct PreludeModAnywhere;
     }
 }
+
+pub mod extern_prelude {
+    pub mod v1 {
+        pub struct ExternPreludeModAnywhere;
+    }
+}
diff --git a/src/tools/clippy/tests/ui/branches_sharing_code/valid_if_blocks.rs b/src/tools/clippy/tests/ui/branches_sharing_code/valid_if_blocks.rs
index 2d6055eb6c4..5780ea08937 100644
--- a/src/tools/clippy/tests/ui/branches_sharing_code/valid_if_blocks.rs
+++ b/src/tools/clippy/tests/ui/branches_sharing_code/valid_if_blocks.rs
@@ -1,6 +1,10 @@
 #![deny(clippy::branches_sharing_code, clippy::if_same_then_else)]
 #![allow(dead_code)]
-#![allow(clippy::mixed_read_write_in_expression, clippy::uninlined_format_args)]
+#![allow(
+    clippy::mixed_read_write_in_expression,
+    clippy::uninlined_format_args,
+    clippy::needless_else
+)]
 
 // This tests valid if blocks that shouldn't trigger the lint
 
diff --git a/src/tools/clippy/tests/ui/branches_sharing_code/valid_if_blocks.stderr b/src/tools/clippy/tests/ui/branches_sharing_code/valid_if_blocks.stderr
index ce7fff0122f..a7e72b780af 100644
--- a/src/tools/clippy/tests/ui/branches_sharing_code/valid_if_blocks.stderr
+++ b/src/tools/clippy/tests/ui/branches_sharing_code/valid_if_blocks.stderr
@@ -1,5 +1,5 @@
 error: this `if` has identical blocks
-  --> $DIR/valid_if_blocks.rs:105:14
+  --> $DIR/valid_if_blocks.rs:109:14
    |
 LL |       if false {
    |  ______________^
@@ -7,7 +7,7 @@ LL | |     } else {
    | |_____^
    |
 note: same as this
-  --> $DIR/valid_if_blocks.rs:106:12
+  --> $DIR/valid_if_blocks.rs:110:12
    |
 LL |       } else {
    |  ____________^
@@ -20,7 +20,7 @@ LL | #![deny(clippy::branches_sharing_code, clippy::if_same_then_else)]
    |                                        ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: this `if` has identical blocks
-  --> $DIR/valid_if_blocks.rs:116:15
+  --> $DIR/valid_if_blocks.rs:120:15
    |
 LL |       if x == 0 {
    |  _______________^
@@ -31,7 +31,7 @@ LL | |     } else {
    | |_____^
    |
 note: same as this
-  --> $DIR/valid_if_blocks.rs:120:12
+  --> $DIR/valid_if_blocks.rs:124:12
    |
 LL |       } else {
    |  ____________^
@@ -42,19 +42,19 @@ LL | |     }
    | |_____^
 
 error: this `if` has identical blocks
-  --> $DIR/valid_if_blocks.rs:127:23
+  --> $DIR/valid_if_blocks.rs:131:23
    |
 LL |     let _ = if x == 6 { 7 } else { 7 };
    |                       ^^^^^
    |
 note: same as this
-  --> $DIR/valid_if_blocks.rs:127:34
+  --> $DIR/valid_if_blocks.rs:131:34
    |
 LL |     let _ = if x == 6 { 7 } else { 7 };
    |                                  ^^^^^
 
 error: this `if` has identical blocks
-  --> $DIR/valid_if_blocks.rs:133:23
+  --> $DIR/valid_if_blocks.rs:137:23
    |
 LL |       } else if x == 68 {
    |  _______________________^
@@ -66,7 +66,7 @@ LL | |     } else {
    | |_____^
    |
 note: same as this
-  --> $DIR/valid_if_blocks.rs:138:12
+  --> $DIR/valid_if_blocks.rs:142:12
    |
 LL |       } else {
    |  ____________^
@@ -78,7 +78,7 @@ LL | |     };
    | |_____^
 
 error: this `if` has identical blocks
-  --> $DIR/valid_if_blocks.rs:147:23
+  --> $DIR/valid_if_blocks.rs:151:23
    |
 LL |       } else if x == 68 {
    |  _______________________^
@@ -88,7 +88,7 @@ LL | |     } else {
    | |_____^
    |
 note: same as this
-  --> $DIR/valid_if_blocks.rs:150:12
+  --> $DIR/valid_if_blocks.rs:154:12
    |
 LL |       } else {
    |  ____________^
diff --git a/src/tools/clippy/tests/ui/crashes/ice-7410.rs b/src/tools/clippy/tests/ui/crashes/ice-7410.rs
index ffe20ab1c31..a5373cdcae1 100644
--- a/src/tools/clippy/tests/ui/crashes/ice-7410.rs
+++ b/src/tools/clippy/tests/ui/crashes/ice-7410.rs
@@ -6,6 +6,7 @@
 #![no_std]
 #![allow(clippy::if_same_then_else)]
 #![allow(clippy::redundant_pattern_matching)]
+#![allow(clippy::needless_else)]
 
 use core::panic::PanicInfo;
 
diff --git a/src/tools/clippy/tests/ui/default_constructed_unit_structs.fixed b/src/tools/clippy/tests/ui/default_constructed_unit_structs.fixed
index e1012f38bba..ac5fe38ff44 100644
--- a/src/tools/clippy/tests/ui/default_constructed_unit_structs.fixed
+++ b/src/tools/clippy/tests/ui/default_constructed_unit_structs.fixed
@@ -101,6 +101,28 @@ struct EmptyStruct {}
 #[non_exhaustive]
 struct NonExhaustiveStruct;
 
+mod issue_10755 {
+    struct Sqlite {}
+
+    trait HasArguments<'q> {
+        type Arguments;
+    }
+
+    impl<'q> HasArguments<'q> for Sqlite {
+        type Arguments = std::marker::PhantomData<&'q ()>;
+    }
+
+    type SqliteArguments<'q> = <Sqlite as HasArguments<'q>>::Arguments;
+
+    fn foo() {
+        // should not lint
+        // type alias cannot be used as a constructor
+        let _ = <Sqlite as HasArguments>::Arguments::default();
+
+        let _ = SqliteArguments::default();
+    }
+}
+
 fn main() {
     // should lint
     let _ = PhantomData::<usize>;
diff --git a/src/tools/clippy/tests/ui/default_constructed_unit_structs.rs b/src/tools/clippy/tests/ui/default_constructed_unit_structs.rs
index c7b4313dbf0..de7f14ffbd9 100644
--- a/src/tools/clippy/tests/ui/default_constructed_unit_structs.rs
+++ b/src/tools/clippy/tests/ui/default_constructed_unit_structs.rs
@@ -101,6 +101,28 @@ struct EmptyStruct {}
 #[non_exhaustive]
 struct NonExhaustiveStruct;
 
+mod issue_10755 {
+    struct Sqlite {}
+
+    trait HasArguments<'q> {
+        type Arguments;
+    }
+
+    impl<'q> HasArguments<'q> for Sqlite {
+        type Arguments = std::marker::PhantomData<&'q ()>;
+    }
+
+    type SqliteArguments<'q> = <Sqlite as HasArguments<'q>>::Arguments;
+
+    fn foo() {
+        // should not lint
+        // type alias cannot be used as a constructor
+        let _ = <Sqlite as HasArguments>::Arguments::default();
+
+        let _ = SqliteArguments::default();
+    }
+}
+
 fn main() {
     // should lint
     let _ = PhantomData::<usize>::default();
diff --git a/src/tools/clippy/tests/ui/default_constructed_unit_structs.stderr b/src/tools/clippy/tests/ui/default_constructed_unit_structs.stderr
index 61a32fb10e5..13abb9149da 100644
--- a/src/tools/clippy/tests/ui/default_constructed_unit_structs.stderr
+++ b/src/tools/clippy/tests/ui/default_constructed_unit_structs.stderr
@@ -13,25 +13,25 @@ LL |             inner: PhantomData::default(),
    |                               ^^^^^^^^^^^ help: remove this call to `default`
 
 error: use of `default` to create a unit struct
-  --> $DIR/default_constructed_unit_structs.rs:106:33
+  --> $DIR/default_constructed_unit_structs.rs:128:33
    |
 LL |     let _ = PhantomData::<usize>::default();
    |                                 ^^^^^^^^^^^ help: remove this call to `default`
 
 error: use of `default` to create a unit struct
-  --> $DIR/default_constructed_unit_structs.rs:107:42
+  --> $DIR/default_constructed_unit_structs.rs:129:42
    |
 LL |     let _: PhantomData<i32> = PhantomData::default();
    |                                          ^^^^^^^^^^^ help: remove this call to `default`
 
 error: use of `default` to create a unit struct
-  --> $DIR/default_constructed_unit_structs.rs:108:55
+  --> $DIR/default_constructed_unit_structs.rs:130:55
    |
 LL |     let _: PhantomData<i32> = std::marker::PhantomData::default();
    |                                                       ^^^^^^^^^^^ help: remove this call to `default`
 
 error: use of `default` to create a unit struct
-  --> $DIR/default_constructed_unit_structs.rs:109:23
+  --> $DIR/default_constructed_unit_structs.rs:131:23
    |
 LL |     let _ = UnitStruct::default();
    |                       ^^^^^^^^^^^ help: remove this call to `default`
diff --git a/src/tools/clippy/tests/ui/ifs_same_cond.rs b/src/tools/clippy/tests/ui/ifs_same_cond.rs
index 9ce9a87626a..f62da157d1b 100644
--- a/src/tools/clippy/tests/ui/ifs_same_cond.rs
+++ b/src/tools/clippy/tests/ui/ifs_same_cond.rs
@@ -1,5 +1,5 @@
 #![warn(clippy::ifs_same_cond)]
-#![allow(clippy::if_same_then_else, clippy::comparison_chain)] // all empty blocks
+#![allow(clippy::if_same_then_else, clippy::comparison_chain, clippy::needless_else)] // all empty blocks
 
 fn ifs_same_cond() {
     let a = 0;
diff --git a/src/tools/clippy/tests/ui/large_stack_arrays.rs b/src/tools/clippy/tests/ui/large_stack_arrays.rs
index 99787ffd3d3..3e9d5e6a4ca 100644
--- a/src/tools/clippy/tests/ui/large_stack_arrays.rs
+++ b/src/tools/clippy/tests/ui/large_stack_arrays.rs
@@ -18,6 +18,19 @@ pub static DOESNOTLINT2: [u8; 512_001] = {
     [x; 512_001]
 };
 
+fn issue_10741() {
+    #[derive(Copy, Clone)]
+    struct Large([u32; 100_000]);
+
+    fn build() -> Large {
+        Large([0; 100_000])
+    }
+
+    let _x = [build(); 3];
+
+    let _y = [build(), build(), build()];
+}
+
 fn main() {
     let bad = (
         [0u32; 20_000_000],
diff --git a/src/tools/clippy/tests/ui/large_stack_arrays.stderr b/src/tools/clippy/tests/ui/large_stack_arrays.stderr
index 24e90094982..118d39566ab 100644
--- a/src/tools/clippy/tests/ui/large_stack_arrays.stderr
+++ b/src/tools/clippy/tests/ui/large_stack_arrays.stderr
@@ -1,14 +1,30 @@
 error: allocating a local array larger than 512000 bytes
-  --> $DIR/large_stack_arrays.rs:23:9
+  --> $DIR/large_stack_arrays.rs:29:14
+   |
+LL |     let _x = [build(); 3];
+   |              ^^^^^^^^^^^^
+   |
+   = help: consider allocating on the heap with `vec![build(); 3].into_boxed_slice()`
+   = note: `-D clippy::large-stack-arrays` implied by `-D warnings`
+
+error: allocating a local array larger than 512000 bytes
+  --> $DIR/large_stack_arrays.rs:31:14
+   |
+LL |     let _y = [build(), build(), build()];
+   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = help: consider allocating on the heap with `vec![build(), build(), build()].into_boxed_slice()`
+
+error: allocating a local array larger than 512000 bytes
+  --> $DIR/large_stack_arrays.rs:36:9
    |
 LL |         [0u32; 20_000_000],
    |         ^^^^^^^^^^^^^^^^^^
    |
    = help: consider allocating on the heap with `vec![0u32; 20_000_000].into_boxed_slice()`
-   = note: `-D clippy::large-stack-arrays` implied by `-D warnings`
 
 error: allocating a local array larger than 512000 bytes
-  --> $DIR/large_stack_arrays.rs:24:9
+  --> $DIR/large_stack_arrays.rs:37:9
    |
 LL |         [S { data: [0; 32] }; 5000],
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -16,7 +32,7 @@ LL |         [S { data: [0; 32] }; 5000],
    = help: consider allocating on the heap with `vec![S { data: [0; 32] }; 5000].into_boxed_slice()`
 
 error: allocating a local array larger than 512000 bytes
-  --> $DIR/large_stack_arrays.rs:25:9
+  --> $DIR/large_stack_arrays.rs:38:9
    |
 LL |         [Some(""); 20_000_000],
    |         ^^^^^^^^^^^^^^^^^^^^^^
@@ -24,7 +40,7 @@ LL |         [Some(""); 20_000_000],
    = help: consider allocating on the heap with `vec![Some(""); 20_000_000].into_boxed_slice()`
 
 error: allocating a local array larger than 512000 bytes
-  --> $DIR/large_stack_arrays.rs:26:9
+  --> $DIR/large_stack_arrays.rs:39:9
    |
 LL |         [E::T(0); 5000],
    |         ^^^^^^^^^^^^^^^
@@ -32,12 +48,12 @@ LL |         [E::T(0); 5000],
    = help: consider allocating on the heap with `vec![E::T(0); 5000].into_boxed_slice()`
 
 error: allocating a local array larger than 512000 bytes
-  --> $DIR/large_stack_arrays.rs:27:9
+  --> $DIR/large_stack_arrays.rs:40:9
    |
 LL |         [0u8; usize::MAX],
    |         ^^^^^^^^^^^^^^^^^
    |
    = help: consider allocating on the heap with `vec![0u8; usize::MAX].into_boxed_slice()`
 
-error: aborting due to 5 previous errors
+error: aborting due to 7 previous errors
 
diff --git a/src/tools/clippy/tests/ui/manual_let_else.rs b/src/tools/clippy/tests/ui/manual_let_else.rs
index 3996d775f55..351ea0e4f50 100644
--- a/src/tools/clippy/tests/ui/manual_let_else.rs
+++ b/src/tools/clippy/tests/ui/manual_let_else.rs
@@ -146,10 +146,20 @@ fn fire() {
         Variant::A(0, 0)
     }
 
-    // Should not be renamed
     let v = if let Variant::A(a, 0) = e() { a } else { return };
-    // Should be renamed
-    let v = if let Variant::B(b) = e() { b } else { return };
+
+    // `mut v` is inserted into the pattern
+    let mut v = if let Variant::B(b) = e() { b } else { return };
+
+    // Nesting works
+    let nested = Ok(Some(e()));
+    let v = if let Ok(Some(Variant::B(b))) | Err(Some(Variant::A(b, _))) = nested {
+        b
+    } else {
+        return;
+    };
+    // dot dot works
+    let v = if let Variant::A(.., a) = e() { a } else { return };
 }
 
 fn not_fire() {
diff --git a/src/tools/clippy/tests/ui/manual_let_else.stderr b/src/tools/clippy/tests/ui/manual_let_else.stderr
index f6f56f7b00e..0e876797134 100644
--- a/src/tools/clippy/tests/ui/manual_let_else.stderr
+++ b/src/tools/clippy/tests/ui/manual_let_else.stderr
@@ -260,19 +260,42 @@ LL |     create_binding_if_some!(w, g());
    = note: this error originates in the macro `create_binding_if_some` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error: this could be rewritten as `let...else`
-  --> $DIR/manual_let_else.rs:150:5
+  --> $DIR/manual_let_else.rs:149:5
    |
 LL |     let v = if let Variant::A(a, 0) = e() { a } else { return };
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider writing: `let Variant::A(a, 0) = e() else { return };`
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider writing: `let Variant::A(v, 0) = e() else { return };`
 
 error: this could be rewritten as `let...else`
   --> $DIR/manual_let_else.rs:152:5
    |
-LL |     let v = if let Variant::B(b) = e() { b } else { return };
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider writing: `let Variant::B(v) = e() else { return };`
+LL |     let mut v = if let Variant::B(b) = e() { b } else { return };
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider writing: `let Variant::B(mut v) = e() else { return };`
 
 error: this could be rewritten as `let...else`
-  --> $DIR/manual_let_else.rs:262:5
+  --> $DIR/manual_let_else.rs:156:5
+   |
+LL | /     let v = if let Ok(Some(Variant::B(b))) | Err(Some(Variant::A(b, _))) = nested {
+LL | |         b
+LL | |     } else {
+LL | |         return;
+LL | |     };
+   | |______^
+   |
+help: consider writing
+   |
+LL ~     let (Ok(Some(Variant::B(v))) | Err(Some(Variant::A(v, _)))) = nested else {
+LL +         return;
+LL +     };
+   |
+
+error: this could be rewritten as `let...else`
+  --> $DIR/manual_let_else.rs:162:5
+   |
+LL |     let v = if let Variant::A(.., a) = e() { a } else { return };
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider writing: `let Variant::A(.., v) = e() else { return };`
+
+error: this could be rewritten as `let...else`
+  --> $DIR/manual_let_else.rs:272:5
    |
 LL | /     let _ = match ff {
 LL | |         Some(value) => value,
@@ -280,5 +303,5 @@ LL | |         _ => macro_call!(),
 LL | |     };
    | |______^ help: consider writing: `let Some(_) = ff else { macro_call!() };`
 
-error: aborting due to 20 previous errors
+error: aborting due to 22 previous errors
 
diff --git a/src/tools/clippy/tests/ui/manual_let_else_match.rs b/src/tools/clippy/tests/ui/manual_let_else_match.rs
index 73b74679125..dfca3b023cd 100644
--- a/src/tools/clippy/tests/ui/manual_let_else_match.rs
+++ b/src/tools/clippy/tests/ui/manual_let_else_match.rs
@@ -68,7 +68,7 @@ fn fire() {
     let f = Variant::Bar(1);
 
     let _value = match f {
-        Variant::Bar(_) | Variant::Baz(_) => (),
+        Variant::Bar(v) | Variant::Baz(v) => v,
         _ => return,
     };
 
diff --git a/src/tools/clippy/tests/ui/manual_let_else_match.stderr b/src/tools/clippy/tests/ui/manual_let_else_match.stderr
index bacc14dc967..13ed35bc1d5 100644
--- a/src/tools/clippy/tests/ui/manual_let_else_match.stderr
+++ b/src/tools/clippy/tests/ui/manual_let_else_match.stderr
@@ -58,10 +58,10 @@ error: this could be rewritten as `let...else`
   --> $DIR/manual_let_else_match.rs:70:5
    |
 LL | /     let _value = match f {
-LL | |         Variant::Bar(_) | Variant::Baz(_) => (),
+LL | |         Variant::Bar(v) | Variant::Baz(v) => v,
 LL | |         _ => return,
 LL | |     };
-   | |______^ help: consider writing: `let (Variant::Bar(_) | Variant::Baz(_)) = f else { return };`
+   | |______^ help: consider writing: `let (Variant::Bar(_value) | Variant::Baz(_value)) = f else { return };`
 
 error: this could be rewritten as `let...else`
   --> $DIR/manual_let_else_match.rs:76:5
diff --git a/src/tools/clippy/tests/ui/match_wild_err_arm.rs b/src/tools/clippy/tests/ui/match_wild_err_arm.rs
index 823be65efe0..5a552e4ae51 100644
--- a/src/tools/clippy/tests/ui/match_wild_err_arm.rs
+++ b/src/tools/clippy/tests/ui/match_wild_err_arm.rs
@@ -1,7 +1,20 @@
 #![feature(exclusive_range_pattern)]
-#![allow(clippy::match_same_arms)]
+#![allow(clippy::match_same_arms, dead_code)]
 #![warn(clippy::match_wild_err_arm)]
 
+fn issue_10635() {
+    enum Error {
+        A,
+        B,
+    }
+
+    // Don't trigger in const contexts. Const unwrap is not yet stable
+    const X: () = match Ok::<_, Error>(()) {
+        Ok(x) => x,
+        Err(_) => panic!(),
+    };
+}
+
 fn match_wild_err_arm() {
     let x: Result<i32, &str> = Ok(3);
 
diff --git a/src/tools/clippy/tests/ui/match_wild_err_arm.stderr b/src/tools/clippy/tests/ui/match_wild_err_arm.stderr
index b016d682698..a9f54feacdb 100644
--- a/src/tools/clippy/tests/ui/match_wild_err_arm.stderr
+++ b/src/tools/clippy/tests/ui/match_wild_err_arm.stderr
@@ -1,5 +1,5 @@
 error: `Err(_)` matches all errors
-  --> $DIR/match_wild_err_arm.rs:11:9
+  --> $DIR/match_wild_err_arm.rs:24:9
    |
 LL |         Err(_) => panic!("err"),
    |         ^^^^^^
@@ -8,7 +8,7 @@ LL |         Err(_) => panic!("err"),
    = note: `-D clippy::match-wild-err-arm` implied by `-D warnings`
 
 error: `Err(_)` matches all errors
-  --> $DIR/match_wild_err_arm.rs:17:9
+  --> $DIR/match_wild_err_arm.rs:30:9
    |
 LL |         Err(_) => panic!(),
    |         ^^^^^^
@@ -16,7 +16,7 @@ LL |         Err(_) => panic!(),
    = note: match each error separately or use the error output, or use `.expect(msg)` if the error case is unreachable
 
 error: `Err(_)` matches all errors
-  --> $DIR/match_wild_err_arm.rs:23:9
+  --> $DIR/match_wild_err_arm.rs:36:9
    |
 LL |         Err(_) => {
    |         ^^^^^^
@@ -24,7 +24,7 @@ LL |         Err(_) => {
    = note: match each error separately or use the error output, or use `.expect(msg)` if the error case is unreachable
 
 error: `Err(_e)` matches all errors
-  --> $DIR/match_wild_err_arm.rs:31:9
+  --> $DIR/match_wild_err_arm.rs:44:9
    |
 LL |         Err(_e) => panic!(),
    |         ^^^^^^^
diff --git a/src/tools/clippy/tests/ui/missing_fields_in_debug.rs b/src/tools/clippy/tests/ui/missing_fields_in_debug.rs
new file mode 100644
index 00000000000..c156d394ece
--- /dev/null
+++ b/src/tools/clippy/tests/ui/missing_fields_in_debug.rs
@@ -0,0 +1,191 @@
+#![allow(unused)]
+#![warn(clippy::missing_fields_in_debug)]
+
+use std::fmt;
+use std::marker::PhantomData;
+use std::ops::Deref;
+
+struct NamedStruct1Ignored {
+    data: u8,
+    hidden: u32,
+}
+
+impl fmt::Debug for NamedStruct1Ignored {
+    // unused field: hidden
+    fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
+        formatter
+            .debug_struct("NamedStruct1Ignored")
+            .field("data", &self.data)
+            .finish()
+    }
+}
+
+struct NamedStructMultipleIgnored {
+    data: u8,
+    hidden: u32,
+    hidden2: String,
+    hidden3: Vec<Vec<i32>>,
+    hidden4: ((((u8), u16), u32), u64),
+}
+
+impl fmt::Debug for NamedStructMultipleIgnored {
+    // unused fields: hidden, hidden2, hidden4
+    fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
+        formatter
+            .debug_struct("NamedStructMultipleIgnored")
+            .field("data", &self.data)
+            .field("hidden3", &self.hidden3)
+            .finish()
+    }
+}
+
+struct Unit;
+
+// ok
+impl fmt::Debug for Unit {
+    fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
+        formatter.debug_struct("Unit").finish()
+    }
+}
+
+struct UnnamedStruct1Ignored(String);
+
+impl fmt::Debug for UnnamedStruct1Ignored {
+    fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
+        formatter.debug_tuple("UnnamedStruct1Ignored").finish()
+    }
+}
+
+struct UnnamedStructMultipleIgnored(String, Vec<u8>, i32);
+
+// tuple structs are not linted
+impl fmt::Debug for UnnamedStructMultipleIgnored {
+    fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
+        formatter
+            .debug_tuple("UnnamedStructMultipleIgnored")
+            .field(&self.1)
+            .finish()
+    }
+}
+
+struct NamedStructNonExhaustive {
+    a: u8,
+    b: String,
+}
+
+// ok
+impl fmt::Debug for NamedStructNonExhaustive {
+    fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
+        formatter
+            .debug_struct("NamedStructNonExhaustive")
+            .field("a", &self.a)
+            .finish_non_exhaustive() // should not warn here
+    }
+}
+
+struct MultiExprDebugImpl {
+    a: u8,
+    b: String,
+}
+
+// ok
+impl fmt::Debug for MultiExprDebugImpl {
+    fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
+        let mut f = formatter.debug_struct("MultiExprDebugImpl");
+        f.field("a", &self.a);
+        f.finish()
+    }
+}
+
+#[derive(Debug)]
+struct DerivedStruct {
+    a: u8,
+    b: i32,
+}
+
+// https://github.com/rust-lang/rust-clippy/pull/10616#discussion_r1166846953
+
+struct Inner {
+    a: usize,
+    b: usize,
+}
+
+struct HasInner {
+    inner: Inner,
+}
+
+impl HasInner {
+    fn get(&self) -> &Inner {
+        &self.inner
+    }
+}
+
+impl fmt::Debug for HasInner {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        let inner = self.get();
+
+        f.debug_struct("HasInner")
+            .field("a", &inner.a)
+            .field("b", &inner.b)
+            .finish()
+    }
+}
+
+// https://github.com/rust-lang/rust-clippy/pull/10616#discussion_r1170306053
+struct Foo {
+    a: u8,
+    b: u8,
+}
+
+impl fmt::Debug for Foo {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        f.debug_struct("Foo").field("a", &self.a).field("b", &()).finish()
+    }
+}
+
+// https://github.com/rust-lang/rust-clippy/pull/10616#discussion_r1175473620
+mod comment1175473620 {
+    use super::*;
+
+    struct Inner {
+        a: usize,
+        b: usize,
+    }
+    struct Wrapper(Inner);
+
+    impl Deref for Wrapper {
+        type Target = Inner;
+
+        fn deref(&self) -> &Self::Target {
+            &self.0
+        }
+    }
+
+    impl fmt::Debug for Wrapper {
+        fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+            f.debug_struct("Wrapper")
+                .field("a", &self.a)
+                .field("b", &self.b)
+                .finish()
+        }
+    }
+}
+
+// https://github.com/rust-lang/rust-clippy/pull/10616#discussion_r1175488757
+// PhantomData is an exception and does not need to be included
+struct WithPD {
+    a: u8,
+    b: u8,
+    c: PhantomData<String>,
+}
+
+impl fmt::Debug for WithPD {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        f.debug_struct("WithPD")
+            .field("a", &self.a)
+            .field("b", &self.b)
+            .finish()
+    }
+}
+
+fn main() {}
diff --git a/src/tools/clippy/tests/ui/missing_fields_in_debug.stderr b/src/tools/clippy/tests/ui/missing_fields_in_debug.stderr
new file mode 100644
index 00000000000..ef9d02abab7
--- /dev/null
+++ b/src/tools/clippy/tests/ui/missing_fields_in_debug.stderr
@@ -0,0 +1,73 @@
+error: manual `Debug` impl does not include all fields
+  --> $DIR/missing_fields_in_debug.rs:13:1
+   |
+LL | / impl fmt::Debug for NamedStruct1Ignored {
+LL | |     // unused field: hidden
+LL | |     fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
+LL | |         formatter
+...  |
+LL | |     }
+LL | | }
+   | |_^
+   |
+note: this field is unused
+  --> $DIR/missing_fields_in_debug.rs:10:5
+   |
+LL |     hidden: u32,
+   |     ^^^^^^^^^^^
+   = help: consider including all fields in this `Debug` impl
+   = help: consider calling `.finish_non_exhaustive()` if you intend to ignore fields
+   = note: `-D clippy::missing-fields-in-debug` implied by `-D warnings`
+
+error: manual `Debug` impl does not include all fields
+  --> $DIR/missing_fields_in_debug.rs:31:1
+   |
+LL | / impl fmt::Debug for NamedStructMultipleIgnored {
+LL | |     // unused fields: hidden, hidden2, hidden4
+LL | |     fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
+LL | |         formatter
+...  |
+LL | |     }
+LL | | }
+   | |_^
+   |
+note: this field is unused
+  --> $DIR/missing_fields_in_debug.rs:25:5
+   |
+LL |     hidden: u32,
+   |     ^^^^^^^^^^^
+note: this field is unused
+  --> $DIR/missing_fields_in_debug.rs:26:5
+   |
+LL |     hidden2: String,
+   |     ^^^^^^^^^^^^^^^
+note: this field is unused
+  --> $DIR/missing_fields_in_debug.rs:28:5
+   |
+LL |     hidden4: ((((u8), u16), u32), u64),
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   = help: consider including all fields in this `Debug` impl
+   = help: consider calling `.finish_non_exhaustive()` if you intend to ignore fields
+
+error: manual `Debug` impl does not include all fields
+  --> $DIR/missing_fields_in_debug.rs:92:1
+   |
+LL | / impl fmt::Debug for MultiExprDebugImpl {
+LL | |     fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
+LL | |         let mut f = formatter.debug_struct("MultiExprDebugImpl");
+LL | |         f.field("a", &self.a);
+LL | |         f.finish()
+LL | |     }
+LL | | }
+   | |_^
+   |
+note: this field is unused
+  --> $DIR/missing_fields_in_debug.rs:88:5
+   |
+LL |     b: String,
+   |     ^^^^^^^^^
+   = help: consider including all fields in this `Debug` impl
+   = help: consider calling `.finish_non_exhaustive()` if you intend to ignore fields
+
+error: aborting due to 3 previous errors
+
diff --git a/src/tools/clippy/tests/ui/needless_else.fixed b/src/tools/clippy/tests/ui/needless_else.fixed
new file mode 100644
index 00000000000..06a16162790
--- /dev/null
+++ b/src/tools/clippy/tests/ui/needless_else.fixed
@@ -0,0 +1,57 @@
+//@run-rustfix
+#![allow(unused)]
+#![warn(clippy::needless_else)]
+#![allow(clippy::suspicious_else_formatting)]
+
+macro_rules! mac {
+    ($test:expr) => {
+        if $test {
+            println!("Test successful!");
+        } else {
+        }
+    };
+}
+
+macro_rules! empty_expansion {
+    () => {};
+}
+
+fn main() {
+    let b = std::hint::black_box(true);
+
+    if b {
+        println!("Foobar");
+    } 
+
+    if b {
+        println!("Foobar");
+    } else {
+        // Do not lint because this comment might be important
+    }
+
+    if b {
+        println!("Foobar");
+    } else
+    /* Do not lint because this comment might be important */
+    {
+    }
+
+    // Do not lint because of the expression
+    let _ = if b { 1 } else { 2 };
+
+    // Do not lint because inside a macro
+    mac!(b);
+
+    if b {
+        println!("Foobar");
+    } else {
+        #[cfg(foo)]
+        "Do not lint cfg'd out code"
+    }
+
+    if b {
+        println!("Foobar");
+    } else {
+        empty_expansion!();
+    }
+}
diff --git a/src/tools/clippy/tests/ui/needless_else.rs b/src/tools/clippy/tests/ui/needless_else.rs
new file mode 100644
index 00000000000..728032c47a6
--- /dev/null
+++ b/src/tools/clippy/tests/ui/needless_else.rs
@@ -0,0 +1,58 @@
+//@run-rustfix
+#![allow(unused)]
+#![warn(clippy::needless_else)]
+#![allow(clippy::suspicious_else_formatting)]
+
+macro_rules! mac {
+    ($test:expr) => {
+        if $test {
+            println!("Test successful!");
+        } else {
+        }
+    };
+}
+
+macro_rules! empty_expansion {
+    () => {};
+}
+
+fn main() {
+    let b = std::hint::black_box(true);
+
+    if b {
+        println!("Foobar");
+    } else {
+    }
+
+    if b {
+        println!("Foobar");
+    } else {
+        // Do not lint because this comment might be important
+    }
+
+    if b {
+        println!("Foobar");
+    } else
+    /* Do not lint because this comment might be important */
+    {
+    }
+
+    // Do not lint because of the expression
+    let _ = if b { 1 } else { 2 };
+
+    // Do not lint because inside a macro
+    mac!(b);
+
+    if b {
+        println!("Foobar");
+    } else {
+        #[cfg(foo)]
+        "Do not lint cfg'd out code"
+    }
+
+    if b {
+        println!("Foobar");
+    } else {
+        empty_expansion!();
+    }
+}
diff --git a/src/tools/clippy/tests/ui/needless_else.stderr b/src/tools/clippy/tests/ui/needless_else.stderr
new file mode 100644
index 00000000000..ea693085164
--- /dev/null
+++ b/src/tools/clippy/tests/ui/needless_else.stderr
@@ -0,0 +1,12 @@
+error: this else branch is empty
+  --> $DIR/needless_else.rs:24:7
+   |
+LL |       } else {
+   |  _______^
+LL | |     }
+   | |_____^ help: you can remove it
+   |
+   = note: `-D clippy::needless-else` implied by `-D warnings`
+
+error: aborting due to previous error
+
diff --git a/src/tools/clippy/tests/ui/needless_return.fixed b/src/tools/clippy/tests/ui/needless_return.fixed
index d49ae5d8636..4dabf313963 100644
--- a/src/tools/clippy/tests/ui/needless_return.fixed
+++ b/src/tools/clippy/tests/ui/needless_return.fixed
@@ -7,7 +7,8 @@
     clippy::if_same_then_else,
     clippy::single_match,
     clippy::needless_bool,
-    clippy::equatable_if_let
+    clippy::equatable_if_let,
+    clippy::needless_else
 )]
 #![warn(clippy::needless_return)]
 
diff --git a/src/tools/clippy/tests/ui/needless_return.rs b/src/tools/clippy/tests/ui/needless_return.rs
index 36763826174..542f562b314 100644
--- a/src/tools/clippy/tests/ui/needless_return.rs
+++ b/src/tools/clippy/tests/ui/needless_return.rs
@@ -7,7 +7,8 @@
     clippy::if_same_then_else,
     clippy::single_match,
     clippy::needless_bool,
-    clippy::equatable_if_let
+    clippy::equatable_if_let,
+    clippy::needless_else
 )]
 #![warn(clippy::needless_return)]
 
diff --git a/src/tools/clippy/tests/ui/needless_return.stderr b/src/tools/clippy/tests/ui/needless_return.stderr
index 05f6038cd25..1d9d23d3008 100644
--- a/src/tools/clippy/tests/ui/needless_return.stderr
+++ b/src/tools/clippy/tests/ui/needless_return.stderr
@@ -1,390 +1,582 @@
 error: unneeded `return` statement
-  --> $DIR/needless_return.rs:27:5
+  --> $DIR/needless_return.rs:28:5
    |
 LL |     return true;
    |     ^^^^^^^^^^^
    |
    = note: `-D clippy::needless-return` implied by `-D warnings`
-   = help: remove `return`
+help: remove `return`
+   |
+LL -     return true;
+LL +     true
+   |
 
 error: unneeded `return` statement
-  --> $DIR/needless_return.rs:31:5
+  --> $DIR/needless_return.rs:32:5
    |
 LL |     return true;
    |     ^^^^^^^^^^^
    |
-   = help: remove `return`
+help: remove `return`
+   |
+LL -     return true;
+LL +     true
+   |
 
 error: unneeded `return` statement
-  --> $DIR/needless_return.rs:36:5
+  --> $DIR/needless_return.rs:37:5
    |
 LL |     return true;;;
    |     ^^^^^^^^^^^
    |
-   = help: remove `return`
+help: remove `return`
+   |
+LL -     return true;;;
+LL +     true
+   |
 
 error: unneeded `return` statement
-  --> $DIR/needless_return.rs:41:5
+  --> $DIR/needless_return.rs:42:5
    |
 LL |     return true;; ; ;
    |     ^^^^^^^^^^^
    |
-   = help: remove `return`
+help: remove `return`
+   |
+LL -     return true;; ; ;
+LL +     true
+   |
 
 error: unneeded `return` statement
-  --> $DIR/needless_return.rs:46:9
+  --> $DIR/needless_return.rs:47:9
    |
 LL |         return true;
    |         ^^^^^^^^^^^
    |
-   = help: remove `return`
+help: remove `return`
+   |
+LL -         return true;
+LL +         true
+   |
 
 error: unneeded `return` statement
-  --> $DIR/needless_return.rs:48:9
+  --> $DIR/needless_return.rs:49:9
    |
 LL |         return false;
    |         ^^^^^^^^^^^^
    |
-   = help: remove `return`
+help: remove `return`
+   |
+LL -         return false;
+LL +         false
+   |
 
 error: unneeded `return` statement
-  --> $DIR/needless_return.rs:54:17
+  --> $DIR/needless_return.rs:55:17
    |
 LL |         true => return false,
    |                 ^^^^^^^^^^^^
    |
-   = help: remove `return`
+help: remove `return`
+   |
+LL |         true => false,
+   |                 ~~~~~
 
 error: unneeded `return` statement
-  --> $DIR/needless_return.rs:56:13
+  --> $DIR/needless_return.rs:57:13
    |
 LL |             return true;
    |             ^^^^^^^^^^^
    |
-   = help: remove `return`
+help: remove `return`
+   |
+LL -             return true;
+LL +             true
+   |
 
 error: unneeded `return` statement
-  --> $DIR/needless_return.rs:63:9
+  --> $DIR/needless_return.rs:64:9
    |
 LL |         return true;
    |         ^^^^^^^^^^^
    |
-   = help: remove `return`
+help: remove `return`
+   |
+LL -         return true;
+LL +         true
+   |
 
 error: unneeded `return` statement
-  --> $DIR/needless_return.rs:65:16
+  --> $DIR/needless_return.rs:66:16
    |
 LL |     let _ = || return true;
    |                ^^^^^^^^^^^
    |
-   = help: remove `return`
+help: remove `return`
+   |
+LL |     let _ = || true;
+   |                ~~~~
 
 error: unneeded `return` statement
-  --> $DIR/needless_return.rs:69:5
+  --> $DIR/needless_return.rs:70:5
    |
 LL |     return the_answer!();
    |     ^^^^^^^^^^^^^^^^^^^^
    |
-   = help: remove `return`
+help: remove `return`
+   |
+LL -     return the_answer!();
+LL +     the_answer!()
+   |
 
 error: unneeded `return` statement
-  --> $DIR/needless_return.rs:72:21
+  --> $DIR/needless_return.rs:73:21
    |
 LL |   fn test_void_fun() {
    |  _____________________^
 LL | |     return;
    | |__________^
    |
-   = help: remove `return`
+help: remove `return`
+   |
+LL - fn test_void_fun() {
+LL -     return;
+LL + fn test_void_fun() {
+   |
 
 error: unneeded `return` statement
-  --> $DIR/needless_return.rs:77:11
+  --> $DIR/needless_return.rs:78:11
    |
 LL |       if b {
    |  ___________^
 LL | |         return;
    | |______________^
    |
-   = help: remove `return`
+help: remove `return`
+   |
+LL -     if b {
+LL -         return;
+LL +     if b {
+   |
 
 error: unneeded `return` statement
-  --> $DIR/needless_return.rs:79:13
+  --> $DIR/needless_return.rs:80:13
    |
 LL |       } else {
    |  _____________^
 LL | |         return;
    | |______________^
    |
-   = help: remove `return`
+help: remove `return`
+   |
+LL -     } else {
+LL -         return;
+LL +     } else {
+   |
 
 error: unneeded `return` statement
-  --> $DIR/needless_return.rs:87:14
+  --> $DIR/needless_return.rs:88:14
    |
 LL |         _ => return,
    |              ^^^^^^
    |
-   = help: replace `return` with a unit value
+help: replace `return` with a unit value
+   |
+LL |         _ => (),
+   |              ~~
 
 error: unneeded `return` statement
-  --> $DIR/needless_return.rs:95:24
+  --> $DIR/needless_return.rs:96:24
    |
 LL |               let _ = 42;
    |  ________________________^
 LL | |             return;
    | |__________________^
    |
-   = help: remove `return`
+help: remove `return`
+   |
+LL -             let _ = 42;
+LL -             return;
+LL +             let _ = 42;
+   |
 
 error: unneeded `return` statement
-  --> $DIR/needless_return.rs:98:14
+  --> $DIR/needless_return.rs:99:14
    |
 LL |         _ => return,
    |              ^^^^^^
    |
-   = help: replace `return` with a unit value
+help: replace `return` with a unit value
+   |
+LL |         _ => (),
+   |              ~~
 
 error: unneeded `return` statement
-  --> $DIR/needless_return.rs:111:9
+  --> $DIR/needless_return.rs:112:9
    |
 LL |         return String::from("test");
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
-   = help: remove `return`
+help: remove `return`
+   |
+LL -         return String::from("test");
+LL +         String::from("test")
+   |
 
 error: unneeded `return` statement
-  --> $DIR/needless_return.rs:113:9
+  --> $DIR/needless_return.rs:114:9
    |
 LL |         return String::new();
    |         ^^^^^^^^^^^^^^^^^^^^
    |
-   = help: remove `return`
+help: remove `return`
+   |
+LL -         return String::new();
+LL +         String::new()
+   |
 
 error: unneeded `return` statement
-  --> $DIR/needless_return.rs:135:32
+  --> $DIR/needless_return.rs:136:32
    |
 LL |         bar.unwrap_or_else(|_| return)
    |                                ^^^^^^
    |
-   = help: replace `return` with an empty block
+help: replace `return` with an empty block
+   |
+LL |         bar.unwrap_or_else(|_| {})
+   |                                ~~
 
 error: unneeded `return` statement
-  --> $DIR/needless_return.rs:139:21
+  --> $DIR/needless_return.rs:140:21
    |
 LL |           let _ = || {
    |  _____________________^
 LL | |             return;
    | |__________________^
    |
-   = help: remove `return`
+help: remove `return`
+   |
+LL -         let _ = || {
+LL -             return;
+LL +         let _ = || {
+   |
 
 error: unneeded `return` statement
-  --> $DIR/needless_return.rs:142:20
+  --> $DIR/needless_return.rs:143:20
    |
 LL |         let _ = || return;
    |                    ^^^^^^
    |
-   = help: replace `return` with an empty block
+help: replace `return` with an empty block
+   |
+LL |         let _ = || {};
+   |                    ~~
 
 error: unneeded `return` statement
-  --> $DIR/needless_return.rs:148:32
+  --> $DIR/needless_return.rs:149:32
    |
 LL |         res.unwrap_or_else(|_| return Foo)
    |                                ^^^^^^^^^^
    |
-   = help: remove `return`
+help: remove `return`
+   |
+LL |         res.unwrap_or_else(|_| Foo)
+   |                                ~~~
 
 error: unneeded `return` statement
-  --> $DIR/needless_return.rs:157:5
+  --> $DIR/needless_return.rs:158:5
    |
 LL |     return true;
    |     ^^^^^^^^^^^
    |
-   = help: remove `return`
+help: remove `return`
+   |
+LL -     return true;
+LL +     true
+   |
 
 error: unneeded `return` statement
-  --> $DIR/needless_return.rs:161:5
+  --> $DIR/needless_return.rs:162:5
    |
 LL |     return true;
    |     ^^^^^^^^^^^
    |
-   = help: remove `return`
+help: remove `return`
+   |
+LL -     return true;
+LL +     true
+   |
 
 error: unneeded `return` statement
-  --> $DIR/needless_return.rs:166:9
+  --> $DIR/needless_return.rs:167:9
    |
 LL |         return true;
    |         ^^^^^^^^^^^
    |
-   = help: remove `return`
+help: remove `return`
+   |
+LL -         return true;
+LL +         true
+   |
 
 error: unneeded `return` statement
-  --> $DIR/needless_return.rs:168:9
+  --> $DIR/needless_return.rs:169:9
    |
 LL |         return false;
    |         ^^^^^^^^^^^^
    |
-   = help: remove `return`
+help: remove `return`
+   |
+LL -         return false;
+LL +         false
+   |
 
 error: unneeded `return` statement
-  --> $DIR/needless_return.rs:174:17
+  --> $DIR/needless_return.rs:175:17
    |
 LL |         true => return false,
    |                 ^^^^^^^^^^^^
    |
-   = help: remove `return`
+help: remove `return`
+   |
+LL |         true => false,
+   |                 ~~~~~
 
 error: unneeded `return` statement
-  --> $DIR/needless_return.rs:176:13
+  --> $DIR/needless_return.rs:177:13
    |
 LL |             return true;
    |             ^^^^^^^^^^^
    |
-   = help: remove `return`
+help: remove `return`
+   |
+LL -             return true;
+LL +             true
+   |
 
 error: unneeded `return` statement
-  --> $DIR/needless_return.rs:183:9
+  --> $DIR/needless_return.rs:184:9
    |
 LL |         return true;
    |         ^^^^^^^^^^^
    |
-   = help: remove `return`
+help: remove `return`
+   |
+LL -         return true;
+LL +         true
+   |
 
 error: unneeded `return` statement
-  --> $DIR/needless_return.rs:185:16
+  --> $DIR/needless_return.rs:186:16
    |
 LL |     let _ = || return true;
    |                ^^^^^^^^^^^
    |
-   = help: remove `return`
+help: remove `return`
+   |
+LL |     let _ = || true;
+   |                ~~~~
 
 error: unneeded `return` statement
-  --> $DIR/needless_return.rs:189:5
+  --> $DIR/needless_return.rs:190:5
    |
 LL |     return the_answer!();
    |     ^^^^^^^^^^^^^^^^^^^^
    |
-   = help: remove `return`
+help: remove `return`
+   |
+LL -     return the_answer!();
+LL +     the_answer!()
+   |
 
 error: unneeded `return` statement
-  --> $DIR/needless_return.rs:192:33
+  --> $DIR/needless_return.rs:193:33
    |
 LL |   async fn async_test_void_fun() {
    |  _________________________________^
 LL | |     return;
    | |__________^
    |
-   = help: remove `return`
+help: remove `return`
+   |
+LL - async fn async_test_void_fun() {
+LL -     return;
+LL + async fn async_test_void_fun() {
+   |
 
 error: unneeded `return` statement
-  --> $DIR/needless_return.rs:197:11
+  --> $DIR/needless_return.rs:198:11
    |
 LL |       if b {
    |  ___________^
 LL | |         return;
    | |______________^
    |
-   = help: remove `return`
+help: remove `return`
+   |
+LL -     if b {
+LL -         return;
+LL +     if b {
+   |
 
 error: unneeded `return` statement
-  --> $DIR/needless_return.rs:199:13
+  --> $DIR/needless_return.rs:200:13
    |
 LL |       } else {
    |  _____________^
 LL | |         return;
    | |______________^
    |
-   = help: remove `return`
+help: remove `return`
+   |
+LL -     } else {
+LL -         return;
+LL +     } else {
+   |
 
 error: unneeded `return` statement
-  --> $DIR/needless_return.rs:207:14
+  --> $DIR/needless_return.rs:208:14
    |
 LL |         _ => return,
    |              ^^^^^^
    |
-   = help: replace `return` with a unit value
+help: replace `return` with a unit value
+   |
+LL |         _ => (),
+   |              ~~
 
 error: unneeded `return` statement
-  --> $DIR/needless_return.rs:220:9
+  --> $DIR/needless_return.rs:221:9
    |
 LL |         return String::from("test");
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
-   = help: remove `return`
+help: remove `return`
+   |
+LL -         return String::from("test");
+LL +         String::from("test")
+   |
 
 error: unneeded `return` statement
-  --> $DIR/needless_return.rs:222:9
+  --> $DIR/needless_return.rs:223:9
    |
 LL |         return String::new();
    |         ^^^^^^^^^^^^^^^^^^^^
    |
-   = help: remove `return`
+help: remove `return`
+   |
+LL -         return String::new();
+LL +         String::new()
+   |
 
 error: unneeded `return` statement
-  --> $DIR/needless_return.rs:238:5
+  --> $DIR/needless_return.rs:239:5
    |
 LL |     return format!("Hello {}", "world!");
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
-   = help: remove `return`
+help: remove `return`
+   |
+LL -     return format!("Hello {}", "world!");
+LL +     format!("Hello {}", "world!")
+   |
 
 error: unneeded `return` statement
-  --> $DIR/needless_return.rs:250:9
+  --> $DIR/needless_return.rs:251:9
    |
 LL |         return true;
    |         ^^^^^^^^^^^
    |
-   = help: remove `return`
+help: remove `return`
+   |
+LL ~         true
+LL |     } else {
+LL |         return false;
+LL ~     }
+   |
 
 error: unneeded `return` statement
-  --> $DIR/needless_return.rs:252:9
+  --> $DIR/needless_return.rs:253:9
    |
 LL |         return false;
    |         ^^^^^^^^^^^^
    |
-   = help: remove `return`
+help: remove `return`
+   |
+LL ~         false
+LL ~     }
+   |
 
 error: unneeded `return` statement
-  --> $DIR/needless_return.rs:259:13
+  --> $DIR/needless_return.rs:260:13
    |
 LL |             return 10;
    |             ^^^^^^^^^
    |
-   = help: remove `return`
+help: remove `return`
+   |
+LL ~             10
+LL |         },
+ ...
+LL |         },
+LL ~     }
+   |
 
 error: unneeded `return` statement
-  --> $DIR/needless_return.rs:262:13
+  --> $DIR/needless_return.rs:263:13
    |
 LL |             return 100;
    |             ^^^^^^^^^^
    |
-   = help: remove `return`
+help: remove `return`
+   |
+LL ~             100
+LL |         },
+LL ~     }
+   |
 
 error: unneeded `return` statement
-  --> $DIR/needless_return.rs:270:9
+  --> $DIR/needless_return.rs:271:9
    |
 LL |         return 0;
    |         ^^^^^^^^
    |
-   = help: remove `return`
+help: remove `return`
+   |
+LL ~         0
+LL ~     }
+   |
 
 error: unneeded `return` statement
-  --> $DIR/needless_return.rs:277:13
+  --> $DIR/needless_return.rs:278:13
    |
 LL |             return *(x as *const isize);
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
-   = help: remove `return`
+help: remove `return`
+   |
+LL ~             *(x as *const isize)
+LL |         } else {
+LL |             return !*(x as *const isize);
+LL ~         }
+LL ~     }
+   |
 
 error: unneeded `return` statement
-  --> $DIR/needless_return.rs:279:13
+  --> $DIR/needless_return.rs:280:13
    |
 LL |             return !*(x as *const isize);
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
-   = help: remove `return`
+help: remove `return`
+   |
+LL ~             !*(x as *const isize)
+LL ~         }
+LL ~     }
+   |
 
 error: unneeded `return` statement
-  --> $DIR/needless_return.rs:286:20
+  --> $DIR/needless_return.rs:287:20
    |
 LL |           let _ = 42;
    |  ____________________^
@@ -392,47 +584,73 @@ LL | |
 LL | |         return;
    | |______________^
    |
-   = help: remove `return`
+help: remove `return`
+   |
+LL -         let _ = 42;
+LL - 
+LL -         return;
+LL +         let _ = 42;
+   |
 
 error: unneeded `return` statement
-  --> $DIR/needless_return.rs:293:20
+  --> $DIR/needless_return.rs:294:20
    |
 LL |         let _ = 42; return;
    |                    ^^^^^^^
    |
-   = help: remove `return`
+help: remove `return`
+   |
+LL -         let _ = 42; return;
+LL +         let _ = 42;
+   |
 
 error: unneeded `return` statement
-  --> $DIR/needless_return.rs:305:9
+  --> $DIR/needless_return.rs:306:9
    |
 LL |         return Ok(format!("ok!"));
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^
    |
-   = help: remove `return`
+help: remove `return`
+   |
+LL -         return Ok(format!("ok!"));
+LL +         Ok(format!("ok!"))
+   |
 
 error: unneeded `return` statement
-  --> $DIR/needless_return.rs:307:9
+  --> $DIR/needless_return.rs:308:9
    |
 LL |         return Err(format!("err!"));
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
-   = help: remove `return`
+help: remove `return`
+   |
+LL -         return Err(format!("err!"));
+LL +         Err(format!("err!"))
+   |
 
 error: unneeded `return` statement
-  --> $DIR/needless_return.rs:313:9
+  --> $DIR/needless_return.rs:314:9
    |
 LL |         return if true { 1 } else { 2 };
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
-   = help: remove `return`
+help: remove `return`
+   |
+LL -         return if true { 1 } else { 2 };
+LL +         if true { 1 } else { 2 }
+   |
 
 error: unneeded `return` statement
-  --> $DIR/needless_return.rs:317:9
+  --> $DIR/needless_return.rs:318:9
    |
 LL |         return if b1 { 0 } else { 1 } | if b2 { 2 } else { 3 } | if b3 { 4 } else { 5 };
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
-   = help: remove `return` and wrap the sequence with parentheses
+help: remove `return` and wrap the sequence with parentheses
+   |
+LL -         return if b1 { 0 } else { 1 } | if b2 { 2 } else { 3 } | if b3 { 4 } else { 5 };
+LL +         (if b1 { 0 } else { 1 } | if b2 { 2 } else { 3 } | if b3 { 4 } else { 5 })
+   |
 
 error: aborting due to 52 previous errors
 
diff --git a/src/tools/clippy/tests/ui/nonminimal_bool.rs b/src/tools/clippy/tests/ui/nonminimal_bool.rs
index 80cc7c60f56..fec6b7713ee 100644
--- a/src/tools/clippy/tests/ui/nonminimal_bool.rs
+++ b/src/tools/clippy/tests/ui/nonminimal_bool.rs
@@ -110,3 +110,17 @@ fn issue_10435() {
         println!("{}", line!());
     }
 }
+
+fn issue10836() {
+    struct Foo(bool);
+    impl std::ops::Not for Foo {
+        type Output = bool;
+
+        fn not(self) -> Self::Output {
+            !self.0
+        }
+    }
+
+    // Should not lint
+    let _: bool = !!Foo(true);
+}
diff --git a/src/tools/clippy/tests/ui/ptr_cast_constness.fixed b/src/tools/clippy/tests/ui/ptr_cast_constness.fixed
new file mode 100644
index 00000000000..24de573d083
--- /dev/null
+++ b/src/tools/clippy/tests/ui/ptr_cast_constness.fixed
@@ -0,0 +1,55 @@
+//@run-rustfix
+//@aux-build:proc_macros.rs
+
+#![warn(clippy::ptr_cast_constness)]
+
+extern crate proc_macros;
+use proc_macros::{external, inline_macros};
+
+#[inline_macros]
+fn main() {
+    let ptr: *const u32 = &42_u32;
+    let mut_ptr: *mut u32 = &mut 42_u32;
+
+    let _ = ptr as *const i32;
+    let _ = mut_ptr as *mut i32;
+
+    // Make sure the lint can handle the difference in their operator precedences.
+    unsafe {
+        let ptr_ptr: *const *const u32 = &ptr;
+        let _ = (*ptr_ptr).cast_mut();
+    }
+
+    let _ = ptr.cast_mut();
+    let _ = mut_ptr.cast_const();
+
+    // Lint this, since pointer::cast_mut and pointer::cast_const have ?Sized
+    let ptr_of_array: *const [u32; 4] = &[1, 2, 3, 4];
+    let _ = ptr_of_array as *const [u32];
+    let _ = ptr_of_array as *const dyn std::fmt::Debug;
+
+    // Make sure the lint is triggered inside a macro
+    let _ = inline!($ptr as *const i32);
+
+    // Do not lint inside macros from external crates
+    let _ = external!($ptr as *const i32);
+}
+
+#[clippy::msrv = "1.64"]
+fn _msrv_1_64() {
+    let ptr: *const u32 = &42_u32;
+    let mut_ptr: *mut u32 = &mut 42_u32;
+
+    // `pointer::cast_const` and `pointer::cast_mut` were stabilized in 1.65. Do not lint this
+    let _ = ptr as *mut i32;
+    let _ = mut_ptr as *const i32;
+}
+
+#[clippy::msrv = "1.65"]
+fn _msrv_1_65() {
+    let ptr: *const u32 = &42_u32;
+    let mut_ptr: *mut u32 = &mut 42_u32;
+
+    let _ = ptr.cast_mut();
+    let _ = mut_ptr.cast_const();
+}
diff --git a/src/tools/clippy/tests/ui/ptr_cast_constness.rs b/src/tools/clippy/tests/ui/ptr_cast_constness.rs
new file mode 100644
index 00000000000..63d973a9fca
--- /dev/null
+++ b/src/tools/clippy/tests/ui/ptr_cast_constness.rs
@@ -0,0 +1,55 @@
+//@run-rustfix
+//@aux-build:proc_macros.rs
+
+#![warn(clippy::ptr_cast_constness)]
+
+extern crate proc_macros;
+use proc_macros::{external, inline_macros};
+
+#[inline_macros]
+fn main() {
+    let ptr: *const u32 = &42_u32;
+    let mut_ptr: *mut u32 = &mut 42_u32;
+
+    let _ = ptr as *const i32;
+    let _ = mut_ptr as *mut i32;
+
+    // Make sure the lint can handle the difference in their operator precedences.
+    unsafe {
+        let ptr_ptr: *const *const u32 = &ptr;
+        let _ = *ptr_ptr as *mut i32;
+    }
+
+    let _ = ptr as *mut i32;
+    let _ = mut_ptr as *const i32;
+
+    // Lint this, since pointer::cast_mut and pointer::cast_const have ?Sized
+    let ptr_of_array: *const [u32; 4] = &[1, 2, 3, 4];
+    let _ = ptr_of_array as *const [u32];
+    let _ = ptr_of_array as *const dyn std::fmt::Debug;
+
+    // Make sure the lint is triggered inside a macro
+    let _ = inline!($ptr as *const i32);
+
+    // Do not lint inside macros from external crates
+    let _ = external!($ptr as *const i32);
+}
+
+#[clippy::msrv = "1.64"]
+fn _msrv_1_64() {
+    let ptr: *const u32 = &42_u32;
+    let mut_ptr: *mut u32 = &mut 42_u32;
+
+    // `pointer::cast_const` and `pointer::cast_mut` were stabilized in 1.65. Do not lint this
+    let _ = ptr as *mut i32;
+    let _ = mut_ptr as *const i32;
+}
+
+#[clippy::msrv = "1.65"]
+fn _msrv_1_65() {
+    let ptr: *const u32 = &42_u32;
+    let mut_ptr: *mut u32 = &mut 42_u32;
+
+    let _ = ptr as *mut i32;
+    let _ = mut_ptr as *const i32;
+}
diff --git a/src/tools/clippy/tests/ui/ptr_cast_constness.stderr b/src/tools/clippy/tests/ui/ptr_cast_constness.stderr
new file mode 100644
index 00000000000..43816c87c19
--- /dev/null
+++ b/src/tools/clippy/tests/ui/ptr_cast_constness.stderr
@@ -0,0 +1,34 @@
+error: `as` casting between raw pointers while changing its constness
+  --> $DIR/ptr_cast_constness.rs:20:17
+   |
+LL |         let _ = *ptr_ptr as *mut i32;
+   |                 ^^^^^^^^^^^^^^^^^^^^ help: try `pointer::cast_mut`, a safer alternative: `(*ptr_ptr).cast_mut()`
+   |
+   = note: `-D clippy::ptr-cast-constness` implied by `-D warnings`
+
+error: `as` casting between raw pointers while changing its constness
+  --> $DIR/ptr_cast_constness.rs:23:13
+   |
+LL |     let _ = ptr as *mut i32;
+   |             ^^^^^^^^^^^^^^^ help: try `pointer::cast_mut`, a safer alternative: `ptr.cast_mut()`
+
+error: `as` casting between raw pointers while changing its constness
+  --> $DIR/ptr_cast_constness.rs:24:13
+   |
+LL |     let _ = mut_ptr as *const i32;
+   |             ^^^^^^^^^^^^^^^^^^^^^ help: try `pointer::cast_const`, a safer alternative: `mut_ptr.cast_const()`
+
+error: `as` casting between raw pointers while changing its constness
+  --> $DIR/ptr_cast_constness.rs:53:13
+   |
+LL |     let _ = ptr as *mut i32;
+   |             ^^^^^^^^^^^^^^^ help: try `pointer::cast_mut`, a safer alternative: `ptr.cast_mut()`
+
+error: `as` casting between raw pointers while changing its constness
+  --> $DIR/ptr_cast_constness.rs:54:13
+   |
+LL |     let _ = mut_ptr as *const i32;
+   |             ^^^^^^^^^^^^^^^^^^^^^ help: try `pointer::cast_const`, a safer alternative: `mut_ptr.cast_const()`
+
+error: aborting due to 5 previous errors
+
diff --git a/src/tools/clippy/tests/ui/redundant_pattern_matching_drop_order.fixed b/src/tools/clippy/tests/ui/redundant_pattern_matching_drop_order.fixed
index bebdf89716f..481c9b263fb 100644
--- a/src/tools/clippy/tests/ui/redundant_pattern_matching_drop_order.fixed
+++ b/src/tools/clippy/tests/ui/redundant_pattern_matching_drop_order.fixed
@@ -2,7 +2,7 @@
 
 // Issue #5746
 #![warn(clippy::redundant_pattern_matching)]
-#![allow(clippy::if_same_then_else, clippy::equatable_if_let)]
+#![allow(clippy::if_same_then_else, clippy::equatable_if_let, clippy::needless_else)]
 use std::task::Poll::{Pending, Ready};
 
 fn main() {
diff --git a/src/tools/clippy/tests/ui/redundant_pattern_matching_drop_order.rs b/src/tools/clippy/tests/ui/redundant_pattern_matching_drop_order.rs
index 8fb6ed5f7ec..86e46d41e65 100644
--- a/src/tools/clippy/tests/ui/redundant_pattern_matching_drop_order.rs
+++ b/src/tools/clippy/tests/ui/redundant_pattern_matching_drop_order.rs
@@ -2,7 +2,7 @@
 
 // Issue #5746
 #![warn(clippy::redundant_pattern_matching)]
-#![allow(clippy::if_same_then_else, clippy::equatable_if_let)]
+#![allow(clippy::if_same_then_else, clippy::equatable_if_let, clippy::needless_else)]
 use std::task::Poll::{Pending, Ready};
 
 fn main() {
diff --git a/src/tools/clippy/tests/ui/redundant_pattern_matching_option.fixed b/src/tools/clippy/tests/ui/redundant_pattern_matching_option.fixed
index accdf1da9dd..dae931541d4 100644
--- a/src/tools/clippy/tests/ui/redundant_pattern_matching_option.fixed
+++ b/src/tools/clippy/tests/ui/redundant_pattern_matching_option.fixed
@@ -47,6 +47,7 @@ fn main() {
 
     issue6067();
     issue10726();
+    issue10803();
 
     let _ = if gen_opt().is_some() {
         1
@@ -107,3 +108,14 @@ fn issue10726() {
         _ => false,
     };
 }
+
+fn issue10803() {
+    let x = Some(42);
+
+    let _ = x.is_some();
+
+    let _ = x.is_none();
+
+    // Don't lint
+    let _ = matches!(x, Some(16));
+}
diff --git a/src/tools/clippy/tests/ui/redundant_pattern_matching_option.rs b/src/tools/clippy/tests/ui/redundant_pattern_matching_option.rs
index ec684bdf71c..3f2fa3f53ce 100644
--- a/src/tools/clippy/tests/ui/redundant_pattern_matching_option.rs
+++ b/src/tools/clippy/tests/ui/redundant_pattern_matching_option.rs
@@ -56,6 +56,7 @@ fn main() {
 
     issue6067();
     issue10726();
+    issue10803();
 
     let _ = if let Some(_) = gen_opt() {
         1
@@ -134,3 +135,14 @@ fn issue10726() {
         _ => false,
     };
 }
+
+fn issue10803() {
+    let x = Some(42);
+
+    let _ = matches!(x, Some(_));
+
+    let _ = matches!(x, None);
+
+    // Don't lint
+    let _ = matches!(x, Some(16));
+}
diff --git a/src/tools/clippy/tests/ui/redundant_pattern_matching_option.stderr b/src/tools/clippy/tests/ui/redundant_pattern_matching_option.stderr
index a69eb390520..93760ce97a8 100644
--- a/src/tools/clippy/tests/ui/redundant_pattern_matching_option.stderr
+++ b/src/tools/clippy/tests/ui/redundant_pattern_matching_option.stderr
@@ -77,49 +77,49 @@ LL |     let _ = if let Some(_) = opt { true } else { false };
    |             -------^^^^^^^------ help: try this: `if opt.is_some()`
 
 error: redundant pattern matching, consider using `is_some()`
-  --> $DIR/redundant_pattern_matching_option.rs:60:20
+  --> $DIR/redundant_pattern_matching_option.rs:61:20
    |
 LL |     let _ = if let Some(_) = gen_opt() {
    |             -------^^^^^^^------------ help: try this: `if gen_opt().is_some()`
 
 error: redundant pattern matching, consider using `is_none()`
-  --> $DIR/redundant_pattern_matching_option.rs:62:19
+  --> $DIR/redundant_pattern_matching_option.rs:63:19
    |
 LL |     } else if let None = gen_opt() {
    |            -------^^^^------------ help: try this: `if gen_opt().is_none()`
 
 error: redundant pattern matching, consider using `is_some()`
-  --> $DIR/redundant_pattern_matching_option.rs:68:12
+  --> $DIR/redundant_pattern_matching_option.rs:69:12
    |
 LL |     if let Some(..) = gen_opt() {}
    |     -------^^^^^^^^------------ help: try this: `if gen_opt().is_some()`
 
 error: redundant pattern matching, consider using `is_some()`
-  --> $DIR/redundant_pattern_matching_option.rs:83:12
+  --> $DIR/redundant_pattern_matching_option.rs:84:12
    |
 LL |     if let Some(_) = Some(42) {}
    |     -------^^^^^^^----------- help: try this: `if Some(42).is_some()`
 
 error: redundant pattern matching, consider using `is_none()`
-  --> $DIR/redundant_pattern_matching_option.rs:85:12
+  --> $DIR/redundant_pattern_matching_option.rs:86:12
    |
 LL |     if let None = None::<()> {}
    |     -------^^^^------------- help: try this: `if None::<()>.is_none()`
 
 error: redundant pattern matching, consider using `is_some()`
-  --> $DIR/redundant_pattern_matching_option.rs:87:15
+  --> $DIR/redundant_pattern_matching_option.rs:88:15
    |
 LL |     while let Some(_) = Some(42) {}
    |     ----------^^^^^^^----------- help: try this: `while Some(42).is_some()`
 
 error: redundant pattern matching, consider using `is_none()`
-  --> $DIR/redundant_pattern_matching_option.rs:89:15
+  --> $DIR/redundant_pattern_matching_option.rs:90:15
    |
 LL |     while let None = None::<()> {}
    |     ----------^^^^------------- help: try this: `while None::<()>.is_none()`
 
 error: redundant pattern matching, consider using `is_some()`
-  --> $DIR/redundant_pattern_matching_option.rs:91:5
+  --> $DIR/redundant_pattern_matching_option.rs:92:5
    |
 LL | /     match Some(42) {
 LL | |         Some(_) => true,
@@ -128,7 +128,7 @@ LL | |     };
    | |_____^ help: try this: `Some(42).is_some()`
 
 error: redundant pattern matching, consider using `is_none()`
-  --> $DIR/redundant_pattern_matching_option.rs:96:5
+  --> $DIR/redundant_pattern_matching_option.rs:97:5
    |
 LL | /     match None::<()> {
 LL | |         Some(_) => false,
@@ -137,19 +137,19 @@ LL | |     };
    | |_____^ help: try this: `None::<()>.is_none()`
 
 error: redundant pattern matching, consider using `is_none()`
-  --> $DIR/redundant_pattern_matching_option.rs:104:12
+  --> $DIR/redundant_pattern_matching_option.rs:105:12
    |
 LL |     if let None = *(&None::<()>) {}
    |     -------^^^^----------------- help: try this: `if (&None::<()>).is_none()`
 
 error: redundant pattern matching, consider using `is_none()`
-  --> $DIR/redundant_pattern_matching_option.rs:105:12
+  --> $DIR/redundant_pattern_matching_option.rs:106:12
    |
 LL |     if let None = *&None::<()> {}
    |     -------^^^^--------------- help: try this: `if (&None::<()>).is_none()`
 
 error: redundant pattern matching, consider using `is_some()`
-  --> $DIR/redundant_pattern_matching_option.rs:111:5
+  --> $DIR/redundant_pattern_matching_option.rs:112:5
    |
 LL | /     match x {
 LL | |         Some(_) => true,
@@ -158,7 +158,7 @@ LL | |     };
    | |_____^ help: try this: `x.is_some()`
 
 error: redundant pattern matching, consider using `is_none()`
-  --> $DIR/redundant_pattern_matching_option.rs:116:5
+  --> $DIR/redundant_pattern_matching_option.rs:117:5
    |
 LL | /     match x {
 LL | |         None => true,
@@ -167,7 +167,7 @@ LL | |     };
    | |_____^ help: try this: `x.is_none()`
 
 error: redundant pattern matching, consider using `is_none()`
-  --> $DIR/redundant_pattern_matching_option.rs:121:5
+  --> $DIR/redundant_pattern_matching_option.rs:122:5
    |
 LL | /     match x {
 LL | |         Some(_) => false,
@@ -176,7 +176,7 @@ LL | |     };
    | |_____^ help: try this: `x.is_none()`
 
 error: redundant pattern matching, consider using `is_some()`
-  --> $DIR/redundant_pattern_matching_option.rs:126:5
+  --> $DIR/redundant_pattern_matching_option.rs:127:5
    |
 LL | /     match x {
 LL | |         None => false,
@@ -184,5 +184,17 @@ LL | |         _ => true,
 LL | |     };
    | |_____^ help: try this: `x.is_some()`
 
-error: aborting due to 26 previous errors
+error: redundant pattern matching, consider using `is_some()`
+  --> $DIR/redundant_pattern_matching_option.rs:142:13
+   |
+LL |     let _ = matches!(x, Some(_));
+   |             ^^^^^^^^^^^^^^^^^^^^ help: try this: `x.is_some()`
+
+error: redundant pattern matching, consider using `is_none()`
+  --> $DIR/redundant_pattern_matching_option.rs:144:13
+   |
+LL |     let _ = matches!(x, None);
+   |             ^^^^^^^^^^^^^^^^^ help: try this: `x.is_none()`
+
+error: aborting due to 28 previous errors
 
diff --git a/src/tools/clippy/tests/ui/redundant_pattern_matching_result.fixed b/src/tools/clippy/tests/ui/redundant_pattern_matching_result.fixed
index e4032ae44b7..d77a2af7616 100644
--- a/src/tools/clippy/tests/ui/redundant_pattern_matching_result.fixed
+++ b/src/tools/clippy/tests/ui/redundant_pattern_matching_result.fixed
@@ -44,6 +44,7 @@ fn main() {
     issue6067();
     issue6065();
     issue10726();
+    issue10803();
 
     let _ = if gen_res().is_ok() {
         1
@@ -133,3 +134,17 @@ fn issue10726() {
         _ => true,
     };
 }
+
+fn issue10803() {
+    let x: Result<i32, i32> = Ok(42);
+
+    let _ = x.is_ok();
+
+    let _ = x.is_err();
+
+    // Don't lint
+    let _ = matches!(x, Ok(16));
+
+    // Don't lint
+    let _ = matches!(x, Err(16));
+}
diff --git a/src/tools/clippy/tests/ui/redundant_pattern_matching_result.rs b/src/tools/clippy/tests/ui/redundant_pattern_matching_result.rs
index 39eb10df878..aa884ac6bb1 100644
--- a/src/tools/clippy/tests/ui/redundant_pattern_matching_result.rs
+++ b/src/tools/clippy/tests/ui/redundant_pattern_matching_result.rs
@@ -56,6 +56,7 @@ fn main() {
     issue6067();
     issue6065();
     issue10726();
+    issue10803();
 
     let _ = if let Ok(_) = gen_res() {
         1
@@ -163,3 +164,17 @@ fn issue10726() {
         _ => true,
     };
 }
+
+fn issue10803() {
+    let x: Result<i32, i32> = Ok(42);
+
+    let _ = matches!(x, Ok(_));
+
+    let _ = matches!(x, Err(_));
+
+    // Don't lint
+    let _ = matches!(x, Ok(16));
+
+    // Don't lint
+    let _ = matches!(x, Err(16));
+}
diff --git a/src/tools/clippy/tests/ui/redundant_pattern_matching_result.stderr b/src/tools/clippy/tests/ui/redundant_pattern_matching_result.stderr
index 5893ae4dcc4..b462f7f41b9 100644
--- a/src/tools/clippy/tests/ui/redundant_pattern_matching_result.stderr
+++ b/src/tools/clippy/tests/ui/redundant_pattern_matching_result.stderr
@@ -73,67 +73,67 @@ LL |     let _ = if let Ok(_) = Ok::<usize, ()>(4) { true } else { false };
    |             -------^^^^^--------------------- help: try this: `if Ok::<usize, ()>(4).is_ok()`
 
 error: redundant pattern matching, consider using `is_ok()`
-  --> $DIR/redundant_pattern_matching_result.rs:60:20
+  --> $DIR/redundant_pattern_matching_result.rs:61:20
    |
 LL |     let _ = if let Ok(_) = gen_res() {
    |             -------^^^^^------------ help: try this: `if gen_res().is_ok()`
 
 error: redundant pattern matching, consider using `is_err()`
-  --> $DIR/redundant_pattern_matching_result.rs:62:19
+  --> $DIR/redundant_pattern_matching_result.rs:63:19
    |
 LL |     } else if let Err(_) = gen_res() {
    |            -------^^^^^^------------ help: try this: `if gen_res().is_err()`
 
 error: redundant pattern matching, consider using `is_some()`
-  --> $DIR/redundant_pattern_matching_result.rs:85:19
+  --> $DIR/redundant_pattern_matching_result.rs:86:19
    |
 LL |         while let Some(_) = r#try!(result_opt()) {}
    |         ----------^^^^^^^----------------------- help: try this: `while r#try!(result_opt()).is_some()`
 
 error: redundant pattern matching, consider using `is_some()`
-  --> $DIR/redundant_pattern_matching_result.rs:86:16
+  --> $DIR/redundant_pattern_matching_result.rs:87:16
    |
 LL |         if let Some(_) = r#try!(result_opt()) {}
    |         -------^^^^^^^----------------------- help: try this: `if r#try!(result_opt()).is_some()`
 
 error: redundant pattern matching, consider using `is_some()`
-  --> $DIR/redundant_pattern_matching_result.rs:92:12
+  --> $DIR/redundant_pattern_matching_result.rs:93:12
    |
 LL |     if let Some(_) = m!() {}
    |     -------^^^^^^^------- help: try this: `if m!().is_some()`
 
 error: redundant pattern matching, consider using `is_some()`
-  --> $DIR/redundant_pattern_matching_result.rs:93:15
+  --> $DIR/redundant_pattern_matching_result.rs:94:15
    |
 LL |     while let Some(_) = m!() {}
    |     ----------^^^^^^^------- help: try this: `while m!().is_some()`
 
 error: redundant pattern matching, consider using `is_ok()`
-  --> $DIR/redundant_pattern_matching_result.rs:111:12
+  --> $DIR/redundant_pattern_matching_result.rs:112:12
    |
 LL |     if let Ok(_) = Ok::<i32, i32>(42) {}
    |     -------^^^^^--------------------- help: try this: `if Ok::<i32, i32>(42).is_ok()`
 
 error: redundant pattern matching, consider using `is_err()`
-  --> $DIR/redundant_pattern_matching_result.rs:113:12
+  --> $DIR/redundant_pattern_matching_result.rs:114:12
    |
 LL |     if let Err(_) = Err::<i32, i32>(42) {}
    |     -------^^^^^^---------------------- help: try this: `if Err::<i32, i32>(42).is_err()`
 
 error: redundant pattern matching, consider using `is_ok()`
-  --> $DIR/redundant_pattern_matching_result.rs:115:15
+  --> $DIR/redundant_pattern_matching_result.rs:116:15
    |
 LL |     while let Ok(_) = Ok::<i32, i32>(10) {}
    |     ----------^^^^^--------------------- help: try this: `while Ok::<i32, i32>(10).is_ok()`
 
 error: redundant pattern matching, consider using `is_err()`
-  --> $DIR/redundant_pattern_matching_result.rs:117:15
+  --> $DIR/redundant_pattern_matching_result.rs:118:15
    |
 LL |     while let Err(_) = Ok::<i32, i32>(10) {}
    |     ----------^^^^^^--------------------- help: try this: `while Ok::<i32, i32>(10).is_err()`
 
 error: redundant pattern matching, consider using `is_ok()`
-  --> $DIR/redundant_pattern_matching_result.rs:119:5
+  --> $DIR/redundant_pattern_matching_result.rs:120:5
    |
 LL | /     match Ok::<i32, i32>(42) {
 LL | |         Ok(_) => true,
@@ -142,7 +142,7 @@ LL | |     };
    | |_____^ help: try this: `Ok::<i32, i32>(42).is_ok()`
 
 error: redundant pattern matching, consider using `is_err()`
-  --> $DIR/redundant_pattern_matching_result.rs:124:5
+  --> $DIR/redundant_pattern_matching_result.rs:125:5
    |
 LL | /     match Err::<i32, i32>(42) {
 LL | |         Ok(_) => false,
@@ -151,7 +151,7 @@ LL | |     };
    | |_____^ help: try this: `Err::<i32, i32>(42).is_err()`
 
 error: redundant pattern matching, consider using `is_ok()`
-  --> $DIR/redundant_pattern_matching_result.rs:134:5
+  --> $DIR/redundant_pattern_matching_result.rs:135:5
    |
 LL | /     match x {
 LL | |         Ok(_) => true,
@@ -160,7 +160,7 @@ LL | |     };
    | |_____^ help: try this: `x.is_ok()`
 
 error: redundant pattern matching, consider using `is_err()`
-  --> $DIR/redundant_pattern_matching_result.rs:139:5
+  --> $DIR/redundant_pattern_matching_result.rs:140:5
    |
 LL | /     match x {
 LL | |         Ok(_) => false,
@@ -169,7 +169,7 @@ LL | |     };
    | |_____^ help: try this: `x.is_err()`
 
 error: redundant pattern matching, consider using `is_err()`
-  --> $DIR/redundant_pattern_matching_result.rs:144:5
+  --> $DIR/redundant_pattern_matching_result.rs:145:5
    |
 LL | /     match x {
 LL | |         Err(_) => true,
@@ -178,7 +178,7 @@ LL | |     };
    | |_____^ help: try this: `x.is_err()`
 
 error: redundant pattern matching, consider using `is_ok()`
-  --> $DIR/redundant_pattern_matching_result.rs:149:5
+  --> $DIR/redundant_pattern_matching_result.rs:150:5
    |
 LL | /     match x {
 LL | |         Err(_) => false,
@@ -186,5 +186,17 @@ LL | |         _ => true,
 LL | |     };
    | |_____^ help: try this: `x.is_ok()`
 
-error: aborting due to 26 previous errors
+error: redundant pattern matching, consider using `is_ok()`
+  --> $DIR/redundant_pattern_matching_result.rs:171:13
+   |
+LL |     let _ = matches!(x, Ok(_));
+   |             ^^^^^^^^^^^^^^^^^^ help: try this: `x.is_ok()`
+
+error: redundant pattern matching, consider using `is_err()`
+  --> $DIR/redundant_pattern_matching_result.rs:173:13
+   |
+LL |     let _ = matches!(x, Err(_));
+   |             ^^^^^^^^^^^^^^^^^^^ help: try this: `x.is_err()`
+
+error: aborting due to 28 previous errors
 
diff --git a/src/tools/clippy/tests/ui/regex.rs b/src/tools/clippy/tests/ui/regex.rs
index a5f79b139bc..1c8e47ab594 100644
--- a/src/tools/clippy/tests/ui/regex.rs
+++ b/src/tools/clippy/tests/ui/regex.rs
@@ -42,6 +42,11 @@ fn syntax_error() {
     let escaped_string_span = Regex::new("\\b\\c");
 
     let aux_span = Regex::new("(?ixi)");
+
+    let should_not_lint = Regex::new("(?u).");
+    let should_not_lint = BRegex::new("(?u).");
+    let invalid_utf8_should_not_lint = BRegex::new("(?-u).");
+    let invalid_utf8_should_lint = Regex::new("(?-u).");
 }
 
 fn trivial_regex() {
@@ -71,6 +76,8 @@ fn trivial_regex() {
     // non-trivial regexes
     let non_trivial_dot = Regex::new("a.b");
     let non_trivial_dot_builder = RegexBuilder::new("a.b");
+    let non_trivial_dot = Regex::new(".");
+    let non_trivial_dot = BRegex::new(".");
     let non_trivial_eq = Regex::new("^foo|bar$");
     let non_trivial_starts_with = Regex::new("^foo|bar");
     let non_trivial_ends_with = Regex::new("^foo|bar");
diff --git a/src/tools/clippy/tests/ui/regex.stderr b/src/tools/clippy/tests/ui/regex.stderr
index 6b8a772e7f0..1e8a21283cd 100644
--- a/src/tools/clippy/tests/ui/regex.stderr
+++ b/src/tools/clippy/tests/ui/regex.stderr
@@ -99,8 +99,14 @@ error: regex syntax error: duplicate flag
 LL |     let aux_span = Regex::new("(?ixi)");
    |                                  ^ ^
 
+error: regex syntax error: pattern can match invalid UTF-8
+  --> $DIR/regex.rs:49:53
+   |
+LL |     let invalid_utf8_should_lint = Regex::new("(?-u).");
+   |                                                     ^
+
 error: trivial regex
-  --> $DIR/regex.rs:48:33
+  --> $DIR/regex.rs:53:33
    |
 LL |     let trivial_eq = Regex::new("^foobar$");
    |                                 ^^^^^^^^^^
@@ -108,7 +114,7 @@ LL |     let trivial_eq = Regex::new("^foobar$");
    = help: consider using `==` on `str`s
 
 error: trivial regex
-  --> $DIR/regex.rs:50:48
+  --> $DIR/regex.rs:55:48
    |
 LL |     let trivial_eq_builder = RegexBuilder::new("^foobar$");
    |                                                ^^^^^^^^^^
@@ -116,7 +122,7 @@ LL |     let trivial_eq_builder = RegexBuilder::new("^foobar$");
    = help: consider using `==` on `str`s
 
 error: trivial regex
-  --> $DIR/regex.rs:52:42
+  --> $DIR/regex.rs:57:42
    |
 LL |     let trivial_starts_with = Regex::new("^foobar");
    |                                          ^^^^^^^^^
@@ -124,7 +130,7 @@ LL |     let trivial_starts_with = Regex::new("^foobar");
    = help: consider using `str::starts_with`
 
 error: trivial regex
-  --> $DIR/regex.rs:54:40
+  --> $DIR/regex.rs:59:40
    |
 LL |     let trivial_ends_with = Regex::new("foobar$");
    |                                        ^^^^^^^^^
@@ -132,7 +138,7 @@ LL |     let trivial_ends_with = Regex::new("foobar$");
    = help: consider using `str::ends_with`
 
 error: trivial regex
-  --> $DIR/regex.rs:56:39
+  --> $DIR/regex.rs:61:39
    |
 LL |     let trivial_contains = Regex::new("foobar");
    |                                       ^^^^^^^^
@@ -140,7 +146,7 @@ LL |     let trivial_contains = Regex::new("foobar");
    = help: consider using `str::contains`
 
 error: trivial regex
-  --> $DIR/regex.rs:58:39
+  --> $DIR/regex.rs:63:39
    |
 LL |     let trivial_contains = Regex::new(NOT_A_REAL_REGEX);
    |                                       ^^^^^^^^^^^^^^^^
@@ -148,7 +154,7 @@ LL |     let trivial_contains = Regex::new(NOT_A_REAL_REGEX);
    = help: consider using `str::contains`
 
 error: trivial regex
-  --> $DIR/regex.rs:60:40
+  --> $DIR/regex.rs:65:40
    |
 LL |     let trivial_backslash = Regex::new("a/.b");
    |                                        ^^^^^^^
@@ -156,7 +162,7 @@ LL |     let trivial_backslash = Regex::new("a/.b");
    = help: consider using `str::contains`
 
 error: trivial regex
-  --> $DIR/regex.rs:63:36
+  --> $DIR/regex.rs:68:36
    |
 LL |     let trivial_empty = Regex::new("");
    |                                    ^^
@@ -164,7 +170,7 @@ LL |     let trivial_empty = Regex::new("");
    = help: the regex is unlikely to be useful as it is
 
 error: trivial regex
-  --> $DIR/regex.rs:65:36
+  --> $DIR/regex.rs:70:36
    |
 LL |     let trivial_empty = Regex::new("^");
    |                                    ^^^
@@ -172,7 +178,7 @@ LL |     let trivial_empty = Regex::new("^");
    = help: the regex is unlikely to be useful as it is
 
 error: trivial regex
-  --> $DIR/regex.rs:67:36
+  --> $DIR/regex.rs:72:36
    |
 LL |     let trivial_empty = Regex::new("^$");
    |                                    ^^^^
@@ -180,12 +186,12 @@ LL |     let trivial_empty = Regex::new("^$");
    = help: consider using `str::is_empty`
 
 error: trivial regex
-  --> $DIR/regex.rs:69:44
+  --> $DIR/regex.rs:74:44
    |
 LL |     let binary_trivial_empty = BRegex::new("^$");
    |                                            ^^^^
    |
    = help: consider using `str::is_empty`
 
-error: aborting due to 23 previous errors
+error: aborting due to 24 previous errors
 
diff --git a/src/tools/clippy/tests/ui/rename.fixed b/src/tools/clippy/tests/ui/rename.fixed
index f7854b89ee4..30f2bfc8c1a 100644
--- a/src/tools/clippy/tests/ui/rename.fixed
+++ b/src/tools/clippy/tests/ui/rename.fixed
@@ -28,6 +28,7 @@
 #![allow(clippy::module_name_repetitions)]
 #![allow(clippy::recursive_format_impl)]
 #![allow(clippy::invisible_characters)]
+#![allow(cast_ref_to_mut)]
 #![allow(suspicious_double_ref_op)]
 #![allow(cast_ref_to_mut)]
 #![allow(drop_bounds)]
diff --git a/src/tools/clippy/tests/ui/rename.rs b/src/tools/clippy/tests/ui/rename.rs
index fa347d395ef..3939914d422 100644
--- a/src/tools/clippy/tests/ui/rename.rs
+++ b/src/tools/clippy/tests/ui/rename.rs
@@ -28,6 +28,7 @@
 #![allow(clippy::module_name_repetitions)]
 #![allow(clippy::recursive_format_impl)]
 #![allow(clippy::invisible_characters)]
+#![allow(cast_ref_to_mut)]
 #![allow(suspicious_double_ref_op)]
 #![allow(cast_ref_to_mut)]
 #![allow(drop_bounds)]
diff --git a/src/tools/clippy/tests/ui/rename.stderr b/src/tools/clippy/tests/ui/rename.stderr
index 9dffe51e5d7..7290cf32e5b 100644
--- a/src/tools/clippy/tests/ui/rename.stderr
+++ b/src/tools/clippy/tests/ui/rename.stderr
@@ -1,5 +1,5 @@
 error: lint `clippy::almost_complete_letter_range` has been renamed to `clippy::almost_complete_range`
-  --> $DIR/rename.rs:51:9
+  --> $DIR/rename.rs:52:9
    |
 LL | #![warn(clippy::almost_complete_letter_range)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::almost_complete_range`
@@ -7,295 +7,295 @@ 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:52:9
+  --> $DIR/rename.rs:53: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:53:9
+  --> $DIR/rename.rs:54: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:54:9
+  --> $DIR/rename.rs:55: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:55:9
+  --> $DIR/rename.rs:56: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:56:9
+  --> $DIR/rename.rs:57: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:57:9
+  --> $DIR/rename.rs:58: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:58:9
+  --> $DIR/rename.rs:59: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:59:9
+  --> $DIR/rename.rs:60: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:60:9
+  --> $DIR/rename.rs:61: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:61:9
+  --> $DIR/rename.rs:62: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:62:9
+  --> $DIR/rename.rs:63: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:63:9
+  --> $DIR/rename.rs:64: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:64:9
+  --> $DIR/rename.rs:65: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:65:9
+  --> $DIR/rename.rs:66: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:66:9
+  --> $DIR/rename.rs:67: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:67:9
+  --> $DIR/rename.rs:68: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:68:9
+  --> $DIR/rename.rs:69: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:69:9
+  --> $DIR/rename.rs:70: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:70:9
+  --> $DIR/rename.rs:71: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:71:9
+  --> $DIR/rename.rs:72: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:72:9
+  --> $DIR/rename.rs:73: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:73:9
+  --> $DIR/rename.rs:74: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:74:9
+  --> $DIR/rename.rs:75: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:75:9
+  --> $DIR/rename.rs:76: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:76:9
+  --> $DIR/rename.rs:77: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:77:9
+  --> $DIR/rename.rs:78: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:78:9
+  --> $DIR/rename.rs:79:9
    |
 LL | #![warn(clippy::to_string_in_display)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::recursive_format_impl`
 
 error: lint `clippy::zero_width_space` has been renamed to `clippy::invisible_characters`
-  --> $DIR/rename.rs:79:9
+  --> $DIR/rename.rs:80: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:80:9
+  --> $DIR/rename.rs:81: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:81:9
+  --> $DIR/rename.rs:82:9
    |
 LL | #![warn(clippy::clone_double_ref)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `suspicious_double_ref_op`
 
 error: lint `clippy::drop_bounds` has been renamed to `drop_bounds`
-  --> $DIR/rename.rs:82:9
+  --> $DIR/rename.rs:83: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:83:9
+  --> $DIR/rename.rs:84: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:84:9
+  --> $DIR/rename.rs:85: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:85:9
+  --> $DIR/rename.rs:86: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:86:9
+  --> $DIR/rename.rs:87: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:87:9
+  --> $DIR/rename.rs:88: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:88:9
+  --> $DIR/rename.rs:89: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:89:9
+  --> $DIR/rename.rs:90:9
    |
 LL | #![warn(clippy::forget_ref)]
    |         ^^^^^^^^^^^^^^^^^^ help: use the new name: `forgetting_references`
 
 error: lint `clippy::into_iter_on_array` has been renamed to `array_into_iter`
-  --> $DIR/rename.rs:90:9
+  --> $DIR/rename.rs:91: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:91:9
+  --> $DIR/rename.rs:92: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:92:9
+  --> $DIR/rename.rs:93: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:93:9
+  --> $DIR/rename.rs:94: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:94:9
+  --> $DIR/rename.rs:95: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:95:9
+  --> $DIR/rename.rs:96: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:96:9
+  --> $DIR/rename.rs:97: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:97:9
+  --> $DIR/rename.rs:98: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:98:9
+  --> $DIR/rename.rs:99:9
    |
 LL | #![warn(clippy::temporary_cstring_as_ptr)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `temporary_cstring_as_ptr`
 
 error: lint `clippy::unknown_clippy_lints` has been renamed to `unknown_lints`
-  --> $DIR/rename.rs:99:9
+  --> $DIR/rename.rs:100: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:100:9
+  --> $DIR/rename.rs:101:9
    |
 LL | #![warn(clippy::unused_label)]
    |         ^^^^^^^^^^^^^^^^^^^^ help: use the new name: `unused_labels`
diff --git a/src/tools/clippy/tests/ui/single_match.fixed b/src/tools/clippy/tests/ui/single_match.fixed
new file mode 100644
index 00000000000..77a2cf3b991
--- /dev/null
+++ b/src/tools/clippy/tests/ui/single_match.fixed
@@ -0,0 +1,209 @@
+//@run-rustfix
+#![warn(clippy::single_match)]
+#![allow(unused, clippy::uninlined_format_args, clippy::redundant_pattern_matching)]
+fn dummy() {}
+
+fn single_match() {
+    let x = Some(1u8);
+
+    if let Some(y) = x {
+        println!("{:?}", y);
+    };
+
+    let x = Some(1u8);
+    if let Some(y) = x { println!("{:?}", y) }
+
+    let z = (1u8, 1u8);
+    if let (2..=3, 7..=9) = z { dummy() };
+
+    // Not linted (pattern guards used)
+    match x {
+        Some(y) if y == 0 => println!("{:?}", y),
+        _ => (),
+    }
+
+    // Not linted (no block with statements in the single arm)
+    match z {
+        (2..=3, 7..=9) => println!("{:?}", z),
+        _ => println!("nope"),
+    }
+}
+
+enum Foo {
+    Bar,
+    Baz(u8),
+}
+use std::borrow::Cow;
+use Foo::*;
+
+fn single_match_know_enum() {
+    let x = Some(1u8);
+    let y: Result<_, i8> = Ok(1i8);
+
+    if let Some(y) = x { dummy() };
+
+    if let Ok(y) = y { dummy() };
+
+    let c = Cow::Borrowed("");
+
+    if let Cow::Borrowed(..) = c { dummy() };
+
+    let z = Foo::Bar;
+    // no warning
+    match z {
+        Bar => println!("42"),
+        Baz(_) => (),
+    }
+
+    match z {
+        Baz(_) => println!("42"),
+        Bar => (),
+    }
+}
+
+// issue #173
+fn if_suggestion() {
+    let x = "test";
+    if x == "test" { println!() }
+
+    #[derive(PartialEq, Eq)]
+    enum Foo {
+        A,
+        B,
+        C(u32),
+    }
+
+    let x = Foo::A;
+    if x == Foo::A { println!() }
+
+    const FOO_C: Foo = Foo::C(0);
+    if x == FOO_C { println!() }
+
+    if x == Foo::A { println!() }
+
+    let x = &x;
+    if x == &Foo::A { println!() }
+
+    enum Bar {
+        A,
+        B,
+    }
+    impl PartialEq for Bar {
+        fn eq(&self, rhs: &Self) -> bool {
+            matches!((self, rhs), (Self::A, Self::A) | (Self::B, Self::B))
+        }
+    }
+    impl Eq for Bar {}
+
+    let x = Bar::A;
+    if let Bar::A = x { println!() }
+
+    // issue #7038
+    struct X;
+    let x = Some(X);
+    if let None = x { println!() };
+}
+
+// See: issue #8282
+fn ranges() {
+    enum E {
+        V,
+    }
+    let x = (Some(E::V), Some(42));
+
+    // Don't lint, because the `E` enum can be extended with additional fields later. Thus, the
+    // proposed replacement to `if let Some(E::V)` may hide non-exhaustive warnings that appeared
+    // because of `match` construction.
+    match x {
+        (Some(E::V), _) => {},
+        (None, _) => {},
+    }
+
+    // lint
+    if let (Some(_), _) = x {}
+
+    // lint
+    if let (Some(E::V), _) = x { todo!() }
+
+    // lint
+    if let (.., Some(E::V), _) = (Some(42), Some(E::V), Some(42)) {}
+
+    // Don't lint, see above.
+    match (Some(E::V), Some(E::V), Some(E::V)) {
+        (.., Some(E::V), _) => {},
+        (.., None, _) => {},
+    }
+
+    // Don't lint, see above.
+    match (Some(E::V), Some(E::V), Some(E::V)) {
+        (Some(E::V), ..) => {},
+        (None, ..) => {},
+    }
+
+    // Don't lint, see above.
+    match (Some(E::V), Some(E::V), Some(E::V)) {
+        (_, Some(E::V), ..) => {},
+        (_, None, ..) => {},
+    }
+}
+
+fn skip_type_aliases() {
+    enum OptionEx {
+        Some(i32),
+        None,
+    }
+    enum ResultEx {
+        Err(i32),
+        Ok(i32),
+    }
+
+    use OptionEx::{None, Some};
+    use ResultEx::{Err, Ok};
+
+    // don't lint
+    match Err(42) {
+        Ok(_) => dummy(),
+        Err(_) => (),
+    };
+
+    // don't lint
+    match Some(1i32) {
+        Some(_) => dummy(),
+        None => (),
+    };
+}
+
+macro_rules! single_match {
+    ($num:literal) => {
+        match $num {
+            15 => println!("15"),
+            _ => (),
+        }
+    };
+}
+
+fn main() {
+    single_match!(5);
+
+    // Don't lint
+    let _ = match Some(0) {
+        #[cfg(feature = "foo")]
+        Some(10) => 11,
+        Some(x) => x,
+        _ => 0,
+    };
+}
+
+fn issue_10808(bar: Option<i32>) {
+    if let Some(v) = bar { unsafe {
+        let r = &v as *const i32;
+        println!("{}", *r);
+    } }
+
+    if let Some(v) = bar {
+        unsafe {
+            let r = &v as *const i32;
+            println!("{}", *r);
+        }
+    }
+}
diff --git a/src/tools/clippy/tests/ui/single_match.rs b/src/tools/clippy/tests/ui/single_match.rs
index d0c9b7b5663..8d0ab5b99ad 100644
--- a/src/tools/clippy/tests/ui/single_match.rs
+++ b/src/tools/clippy/tests/ui/single_match.rs
@@ -1,6 +1,6 @@
+//@run-rustfix
 #![warn(clippy::single_match)]
-#![allow(clippy::uninlined_format_args)]
-
+#![allow(unused, clippy::uninlined_format_args, clippy::redundant_pattern_matching)]
 fn dummy() {}
 
 fn single_match() {
@@ -244,3 +244,24 @@ fn main() {
         _ => 0,
     };
 }
+
+fn issue_10808(bar: Option<i32>) {
+    match bar {
+        Some(v) => unsafe {
+            let r = &v as *const i32;
+            println!("{}", *r);
+        },
+        _ => {},
+    }
+
+    match bar {
+        #[rustfmt::skip]
+        Some(v) => {
+            unsafe {
+                let r = &v as *const i32;
+                println!("{}", *r);
+            }
+        },
+        _ => {},
+    }
+}
diff --git a/src/tools/clippy/tests/ui/single_match.stderr b/src/tools/clippy/tests/ui/single_match.stderr
index 7cecc1b7395..dad66e2ab2e 100644
--- a/src/tools/clippy/tests/ui/single_match.stderr
+++ b/src/tools/clippy/tests/ui/single_match.stderr
@@ -155,5 +155,47 @@ LL | |         (..) => {},
 LL | |     }
    | |_____^ help: try this: `if let (.., Some(E::V), _) = (Some(42), Some(E::V), Some(42)) {}`
 
-error: aborting due to 16 previous errors
+error: you seem to be trying to use `match` for destructuring a single pattern. Consider using `if let`
+  --> $DIR/single_match.rs:249:5
+   |
+LL | /     match bar {
+LL | |         Some(v) => unsafe {
+LL | |             let r = &v as *const i32;
+LL | |             println!("{}", *r);
+LL | |         },
+LL | |         _ => {},
+LL | |     }
+   | |_____^
+   |
+help: try this
+   |
+LL ~     if let Some(v) = bar { unsafe {
+LL +         let r = &v as *const i32;
+LL +         println!("{}", *r);
+LL +     } }
+   |
+
+error: you seem to be trying to use `match` for destructuring a single pattern. Consider using `if let`
+  --> $DIR/single_match.rs:257:5
+   |
+LL | /     match bar {
+LL | |         #[rustfmt::skip]
+LL | |         Some(v) => {
+LL | |             unsafe {
+...  |
+LL | |         _ => {},
+LL | |     }
+   | |_____^
+   |
+help: try this
+   |
+LL ~     if let Some(v) = bar {
+LL +         unsafe {
+LL +             let r = &v as *const i32;
+LL +             println!("{}", *r);
+LL +         }
+LL +     }
+   |
+
+error: aborting due to 18 previous errors
 
diff --git a/src/tools/clippy/tests/ui/single_match_else.fixed b/src/tools/clippy/tests/ui/single_match_else.fixed
new file mode 100644
index 00000000000..f88498655a4
--- /dev/null
+++ b/src/tools/clippy/tests/ui/single_match_else.fixed
@@ -0,0 +1,173 @@
+//@run-rustfix
+//@aux-build: proc_macros.rs
+#![warn(clippy::single_match_else)]
+#![allow(unused, clippy::needless_return, clippy::no_effect, clippy::uninlined_format_args)]
+extern crate proc_macros;
+use proc_macros::with_span;
+
+enum ExprNode {
+    ExprAddrOf,
+    Butterflies,
+    Unicorns,
+}
+
+static NODE: ExprNode = ExprNode::Unicorns;
+
+fn unwrap_addr() -> Option<&'static ExprNode> {
+    let _ = if let ExprNode::ExprAddrOf = ExprNode::Butterflies { Some(&NODE) } else {
+        let x = 5;
+        None
+    };
+
+    // Don't lint
+    with_span!(span match ExprNode::Butterflies {
+        ExprNode::ExprAddrOf => Some(&NODE),
+        _ => {
+            let x = 5;
+            None
+        },
+    })
+}
+
+macro_rules! unwrap_addr {
+    ($expression:expr) => {
+        match $expression {
+            ExprNode::ExprAddrOf => Some(&NODE),
+            _ => {
+                let x = 5;
+                None
+            },
+        }
+    };
+}
+
+#[rustfmt::skip]
+fn main() {
+    unwrap_addr!(ExprNode::Unicorns);
+
+    //
+    // don't lint single exprs/statements
+    //
+
+    // don't lint here
+    match Some(1) {
+        Some(a) => println!("${:?}", a),
+        None => return,
+    }
+
+    // don't lint here
+    match Some(1) {
+        Some(a) => println!("${:?}", a),
+        None => {
+            return
+        },
+    }
+
+    // don't lint here
+    match Some(1) {
+        Some(a) => println!("${:?}", a),
+        None => {
+            return;
+        },
+    }
+
+    //
+    // lint multiple exprs/statements "else" blocks
+    //
+
+    // lint here
+    if let Some(a) = Some(1) { println!("${:?}", a) } else {
+        println!("else block");
+        return
+    }
+
+    // lint here
+    if let Some(a) = Some(1) { println!("${:?}", a) } else {
+        println!("else block");
+        return;
+    }
+
+    // lint here
+    use std::convert::Infallible;
+    if let Ok(a) = Result::<i32, Infallible>::Ok(1) { println!("${:?}", a) } else {
+        println!("else block");
+        return;
+    }
+
+    use std::borrow::Cow;
+    if let Cow::Owned(a) = Cow::from("moo") { println!("${:?}", a) } else {
+        println!("else block");
+        return;
+    }
+}
+
+fn issue_10808(bar: Option<i32>) {
+    if let Some(v) = bar { unsafe {
+        let r = &v as *const i32;
+        println!("{}", *r);
+    } } else {
+        println!("None1");
+        println!("None2");
+    }
+
+    if let Some(v) = bar {
+        println!("Some");
+        println!("{v}");
+    } else { unsafe {
+        let v = 0;
+        let r = &v as *const i32;
+        println!("{}", *r);
+    } }
+
+    if let Some(v) = bar { unsafe {
+        let r = &v as *const i32;
+        println!("{}", *r);
+    } } else { unsafe {
+        let v = 0;
+        let r = &v as *const i32;
+        println!("{}", *r);
+    } }
+
+    if let Some(v) = bar {
+        unsafe {
+            let r = &v as *const i32;
+            println!("{}", *r);
+        }
+    } else {
+        println!("None");
+        println!("None");
+    }
+
+    match bar {
+        Some(v) => {
+            println!("Some");
+            println!("{v}");
+        },
+        #[rustfmt::skip]
+        None => {
+            unsafe {
+                let v = 0;
+                let r = &v as *const i32;
+                println!("{}", *r);
+            }
+        },
+    }
+
+    match bar {
+        #[rustfmt::skip]
+        Some(v) => {
+            unsafe {
+                let r = &v as *const i32;
+                println!("{}", *r);
+            }
+        },
+        #[rustfmt::skip]
+        None => {
+            unsafe {
+                let v = 0;
+                let r = &v as *const i32;
+                println!("{}", *r);
+            }
+        },
+    }
+}
diff --git a/src/tools/clippy/tests/ui/single_match_else.rs b/src/tools/clippy/tests/ui/single_match_else.rs
index c8ac768b60f..b34b9553919 100644
--- a/src/tools/clippy/tests/ui/single_match_else.rs
+++ b/src/tools/clippy/tests/ui/single_match_else.rs
@@ -1,7 +1,7 @@
+//@run-rustfix
 //@aux-build: proc_macros.rs
 #![warn(clippy::single_match_else)]
-#![allow(clippy::needless_return, clippy::no_effect, clippy::uninlined_format_args)]
-
+#![allow(unused, clippy::needless_return, clippy::no_effect, clippy::uninlined_format_args)]
 extern crate proc_macros;
 use proc_macros::with_span;
 
@@ -115,3 +115,87 @@ fn main() {
         }
     }
 }
+
+fn issue_10808(bar: Option<i32>) {
+    match bar {
+        Some(v) => unsafe {
+            let r = &v as *const i32;
+            println!("{}", *r);
+        },
+        None => {
+            println!("None1");
+            println!("None2");
+        },
+    }
+
+    match bar {
+        Some(v) => {
+            println!("Some");
+            println!("{v}");
+        },
+        None => unsafe {
+            let v = 0;
+            let r = &v as *const i32;
+            println!("{}", *r);
+        },
+    }
+
+    match bar {
+        Some(v) => unsafe {
+            let r = &v as *const i32;
+            println!("{}", *r);
+        },
+        None => unsafe {
+            let v = 0;
+            let r = &v as *const i32;
+            println!("{}", *r);
+        },
+    }
+
+    match bar {
+        #[rustfmt::skip]
+        Some(v) => {
+            unsafe {
+                let r = &v as *const i32;
+                println!("{}", *r);
+            }
+        },
+        None => {
+            println!("None");
+            println!("None");
+        },
+    }
+
+    match bar {
+        Some(v) => {
+            println!("Some");
+            println!("{v}");
+        },
+        #[rustfmt::skip]
+        None => {
+            unsafe {
+                let v = 0;
+                let r = &v as *const i32;
+                println!("{}", *r);
+            }
+        },
+    }
+
+    match bar {
+        #[rustfmt::skip]
+        Some(v) => {
+            unsafe {
+                let r = &v as *const i32;
+                println!("{}", *r);
+            }
+        },
+        #[rustfmt::skip]
+        None => {
+            unsafe {
+                let v = 0;
+                let r = &v as *const i32;
+                println!("{}", *r);
+            }
+        },
+    }
+}
diff --git a/src/tools/clippy/tests/ui/single_match_else.stderr b/src/tools/clippy/tests/ui/single_match_else.stderr
index 62876a55dc6..228236f3bb8 100644
--- a/src/tools/clippy/tests/ui/single_match_else.stderr
+++ b/src/tools/clippy/tests/ui/single_match_else.stderr
@@ -100,5 +100,101 @@ LL +         return;
 LL +     }
    |
 
-error: aborting due to 5 previous errors
+error: you seem to be trying to use `match` for destructuring a single pattern. Consider using `if let`
+  --> $DIR/single_match_else.rs:120:5
+   |
+LL | /     match bar {
+LL | |         Some(v) => unsafe {
+LL | |             let r = &v as *const i32;
+LL | |             println!("{}", *r);
+...  |
+LL | |         },
+LL | |     }
+   | |_____^
+   |
+help: try this
+   |
+LL ~     if let Some(v) = bar { unsafe {
+LL +         let r = &v as *const i32;
+LL +         println!("{}", *r);
+LL +     } } else {
+LL +         println!("None1");
+LL +         println!("None2");
+LL +     }
+   |
+
+error: you seem to be trying to use `match` for destructuring a single pattern. Consider using `if let`
+  --> $DIR/single_match_else.rs:131:5
+   |
+LL | /     match bar {
+LL | |         Some(v) => {
+LL | |             println!("Some");
+LL | |             println!("{v}");
+...  |
+LL | |         },
+LL | |     }
+   | |_____^
+   |
+help: try this
+   |
+LL ~     if let Some(v) = bar {
+LL +         println!("Some");
+LL +         println!("{v}");
+LL +     } else { unsafe {
+LL +         let v = 0;
+LL +         let r = &v as *const i32;
+LL +         println!("{}", *r);
+LL +     } }
+   |
+
+error: you seem to be trying to use `match` for destructuring a single pattern. Consider using `if let`
+  --> $DIR/single_match_else.rs:143:5
+   |
+LL | /     match bar {
+LL | |         Some(v) => unsafe {
+LL | |             let r = &v as *const i32;
+LL | |             println!("{}", *r);
+...  |
+LL | |         },
+LL | |     }
+   | |_____^
+   |
+help: try this
+   |
+LL ~     if let Some(v) = bar { unsafe {
+LL +         let r = &v as *const i32;
+LL +         println!("{}", *r);
+LL +     } } else { unsafe {
+LL +         let v = 0;
+LL +         let r = &v as *const i32;
+LL +         println!("{}", *r);
+LL +     } }
+   |
+
+error: you seem to be trying to use `match` for destructuring a single pattern. Consider using `if let`
+  --> $DIR/single_match_else.rs:155:5
+   |
+LL | /     match bar {
+LL | |         #[rustfmt::skip]
+LL | |         Some(v) => {
+LL | |             unsafe {
+...  |
+LL | |         },
+LL | |     }
+   | |_____^
+   |
+help: try this
+   |
+LL ~     if let Some(v) = bar {
+LL +         unsafe {
+LL +             let r = &v as *const i32;
+LL +             println!("{}", *r);
+LL +         }
+LL +     } else {
+LL +         println!("None");
+LL +         println!("None");
+LL +     }
+   |
+
+error: aborting due to 9 previous errors
 
diff --git a/src/tools/clippy/tests/ui/suspicious_else_formatting.rs b/src/tools/clippy/tests/ui/suspicious_else_formatting.rs
index e0153cdd8cd..4823d909208 100644
--- a/src/tools/clippy/tests/ui/suspicious_else_formatting.rs
+++ b/src/tools/clippy/tests/ui/suspicious_else_formatting.rs
@@ -1,7 +1,7 @@
 //@aux-build:proc_macro_suspicious_else_formatting.rs
 
 #![warn(clippy::suspicious_else_formatting)]
-#![allow(clippy::if_same_then_else, clippy::let_unit_value)]
+#![allow(clippy::if_same_then_else, clippy::let_unit_value, clippy::needless_else)]
 
 extern crate proc_macro_suspicious_else_formatting;
 use proc_macro_suspicious_else_formatting::DeriveBadSpan;
diff --git a/src/tools/clippy/tests/ui/unused_async.rs b/src/tools/clippy/tests/ui/unused_async.rs
index 4ca7f29b34c..bfaa5dadfa5 100644
--- a/src/tools/clippy/tests/ui/unused_async.rs
+++ b/src/tools/clippy/tests/ui/unused_async.rs
@@ -3,6 +3,26 @@
 use std::future::Future;
 use std::pin::Pin;
 
+mod issue10800 {
+    #![allow(dead_code, unused_must_use, clippy::no_effect)]
+
+    use std::future::ready;
+
+    async fn async_block_await() {
+        async {
+            ready(()).await;
+        };
+    }
+
+    async fn normal_block_await() {
+        {
+            {
+                ready(()).await;
+            }
+        }
+    }
+}
+
 async fn foo() -> i32 {
     4
 }
diff --git a/src/tools/clippy/tests/ui/unused_async.stderr b/src/tools/clippy/tests/ui/unused_async.stderr
index cff3eccbd32..8ac2066a6b2 100644
--- a/src/tools/clippy/tests/ui/unused_async.stderr
+++ b/src/tools/clippy/tests/ui/unused_async.stderr
@@ -1,5 +1,23 @@
 error: unused `async` for function with no await statements
-  --> $DIR/unused_async.rs:6:1
+  --> $DIR/unused_async.rs:11:5
+   |
+LL | /     async fn async_block_await() {
+LL | |         async {
+LL | |             ready(()).await;
+LL | |         };
+LL | |     }
+   | |_____^
+   |
+   = help: consider removing the `async` from this function
+note: `await` used in an async block, which does not require the enclosing function to be `async`
+  --> $DIR/unused_async.rs:13:23
+   |
+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:26:1
    |
 LL | / async fn foo() -> i32 {
 LL | |     4
@@ -7,10 +25,9 @@ LL | | }
    | |_^
    |
    = help: consider removing the `async` from this function
-   = note: `-D clippy::unused-async` implied by `-D warnings`
 
 error: unused `async` for function with no await statements
-  --> $DIR/unused_async.rs:17:5
+  --> $DIR/unused_async.rs:37:5
    |
 LL | /     async fn unused(&self) -> i32 {
 LL | |         1
@@ -19,5 +36,5 @@ LL | |     }
    |
    = help: consider removing the `async` from this function
 
-error: aborting due to 2 previous errors
+error: aborting due to 3 previous errors
 
diff --git a/src/tools/clippy/tests/ui/wildcard_imports.fixed b/src/tools/clippy/tests/ui/wildcard_imports.fixed
index bd845361fa8..733bbcfbcef 100644
--- a/src/tools/clippy/tests/ui/wildcard_imports.fixed
+++ b/src/tools/clippy/tests/ui/wildcard_imports.fixed
@@ -24,6 +24,7 @@ use wildcard_imports_helper::inner::inner_for_self_import::inner_extern_bar;
 use wildcard_imports_helper::{ExternA, extern_foo};
 
 use std::io::prelude::*;
+use wildcard_imports_helper::extern_prelude::v1::*;
 use wildcard_imports_helper::prelude::v1::*;
 
 struct ReadFoo;
@@ -81,6 +82,7 @@ fn main() {
     let _ = inner_struct_mod::C;
     let _ = ExternA;
     let _ = PreludeModAnywhere;
+    let _ = ExternPreludeModAnywhere;
 
     double_struct_import_test!();
     double_struct_import_test!();
diff --git a/src/tools/clippy/tests/ui/wildcard_imports.rs b/src/tools/clippy/tests/ui/wildcard_imports.rs
index fb51f7bdfcc..4acdd374bde 100644
--- a/src/tools/clippy/tests/ui/wildcard_imports.rs
+++ b/src/tools/clippy/tests/ui/wildcard_imports.rs
@@ -24,6 +24,7 @@ use wildcard_imports_helper::inner::inner_for_self_import::*;
 use wildcard_imports_helper::*;
 
 use std::io::prelude::*;
+use wildcard_imports_helper::extern_prelude::v1::*;
 use wildcard_imports_helper::prelude::v1::*;
 
 struct ReadFoo;
@@ -81,6 +82,7 @@ fn main() {
     let _ = inner_struct_mod::C;
     let _ = ExternA;
     let _ = PreludeModAnywhere;
+    let _ = ExternPreludeModAnywhere;
 
     double_struct_import_test!();
     double_struct_import_test!();
diff --git a/src/tools/clippy/tests/ui/wildcard_imports.stderr b/src/tools/clippy/tests/ui/wildcard_imports.stderr
index 6b469cdfc44..235be2d5708 100644
--- a/src/tools/clippy/tests/ui/wildcard_imports.stderr
+++ b/src/tools/clippy/tests/ui/wildcard_imports.stderr
@@ -37,55 +37,55 @@ LL | use wildcard_imports_helper::*;
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `wildcard_imports_helper::{ExternA, extern_foo}`
 
 error: usage of wildcard import
-  --> $DIR/wildcard_imports.rs:95:13
+  --> $DIR/wildcard_imports.rs:97:13
    |
 LL |         use crate::fn_mod::*;
    |             ^^^^^^^^^^^^^^^^ help: try: `crate::fn_mod::foo`
 
 error: usage of wildcard import
-  --> $DIR/wildcard_imports.rs:101:75
+  --> $DIR/wildcard_imports.rs:103:75
    |
 LL |         use wildcard_imports_helper::inner::inner_for_self_import::{self, *};
    |                                                                           ^ help: try: `inner_extern_foo`
 
 error: usage of wildcard import
-  --> $DIR/wildcard_imports.rs:102:13
+  --> $DIR/wildcard_imports.rs:104:13
    |
 LL |         use wildcard_imports_helper::*;
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `wildcard_imports_helper::{ExternA, extern_foo}`
 
 error: usage of wildcard import
-  --> $DIR/wildcard_imports.rs:113:20
+  --> $DIR/wildcard_imports.rs:115:20
    |
 LL |         use self::{inner::*, inner2::*};
    |                    ^^^^^^^^ help: try: `inner::inner_foo`
 
 error: usage of wildcard import
-  --> $DIR/wildcard_imports.rs:113:30
+  --> $DIR/wildcard_imports.rs:115:30
    |
 LL |         use self::{inner::*, inner2::*};
    |                              ^^^^^^^^^ help: try: `inner2::inner_bar`
 
 error: usage of wildcard import
-  --> $DIR/wildcard_imports.rs:120:13
+  --> $DIR/wildcard_imports.rs:122:13
    |
 LL |         use wildcard_imports_helper::*;
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `wildcard_imports_helper::{ExternExportedEnum, ExternExportedStruct, extern_exported}`
 
 error: usage of wildcard import
-  --> $DIR/wildcard_imports.rs:149:9
+  --> $DIR/wildcard_imports.rs:151:9
    |
 LL |     use crate::in_fn_test::*;
    |         ^^^^^^^^^^^^^^^^^^^^ help: try: `crate::in_fn_test::{ExportedEnum, ExportedStruct, exported}`
 
 error: usage of wildcard import
-  --> $DIR/wildcard_imports.rs:158:9
+  --> $DIR/wildcard_imports.rs:160:9
    |
 LL |     use crate:: in_fn_test::  * ;
    |         ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `crate:: in_fn_test::exported`
 
 error: usage of wildcard import
-  --> $DIR/wildcard_imports.rs:159:9
+  --> $DIR/wildcard_imports.rs:161:9
    |
 LL |       use crate:: fn_mod::
    |  _________^
@@ -93,37 +93,37 @@ LL | |         *;
    | |_________^ help: try: `crate:: fn_mod::foo`
 
 error: usage of wildcard import
-  --> $DIR/wildcard_imports.rs:170:13
+  --> $DIR/wildcard_imports.rs:172:13
    |
 LL |         use super::*;
    |             ^^^^^^^^ help: try: `super::foofoo`
 
 error: usage of wildcard import
-  --> $DIR/wildcard_imports.rs:205:17
+  --> $DIR/wildcard_imports.rs:207:17
    |
 LL |             use super::*;
    |                 ^^^^^^^^ help: try: `super::insidefoo`
 
 error: usage of wildcard import
-  --> $DIR/wildcard_imports.rs:213:13
+  --> $DIR/wildcard_imports.rs:215:13
    |
 LL |         use super_imports::*;
    |             ^^^^^^^^^^^^^^^^ help: try: `super_imports::foofoo`
 
 error: usage of wildcard import
-  --> $DIR/wildcard_imports.rs:222:17
+  --> $DIR/wildcard_imports.rs:224:17
    |
 LL |             use super::super::*;
    |                 ^^^^^^^^^^^^^^^ help: try: `super::super::foofoo`
 
 error: usage of wildcard import
-  --> $DIR/wildcard_imports.rs:231:13
+  --> $DIR/wildcard_imports.rs:233:13
    |
 LL |         use super::super::super_imports::*;
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `super::super::super_imports::foofoo`
 
 error: usage of wildcard import
-  --> $DIR/wildcard_imports.rs:239:13
+  --> $DIR/wildcard_imports.rs:241:13
    |
 LL |         use super::*;
    |             ^^^^^^^^ help: try: `super::foofoo`