about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2021-11-21 21:20:20 +0000
committerbors <bors@rust-lang.org>2021-11-21 21:20:20 +0000
commitcebd2dda1d9071f2209079370c412f4ef9ef2b82 (patch)
treeff90842dc821a514ae5a8fd9bf429f353eef64cb /src
parent65f3f8b220f020e562c5dd848ff7319257a7ba45 (diff)
parent66da8faf176cf5fbdd198371f80ff58b3ed50cf9 (diff)
Auto merge of #90352 - camsteffen:for-loop-desugar, r=oli-obk
Simplify `for` loop desugar

Basically two intermediate bindings are inlined. I could have left one intermediate binding in place as this would simplify some diagnostic logic, but I think the difference in that regard would be negligible, so it is better to have a minimal HIR.

For checking that the pattern is irrefutable, I added a special case when the `match` is found to be non-exhaustive.

The reordering of the arms is purely stylistic. I don't *think* there are any perf implications.

```diff
  match IntoIterator::into_iter($head) {
      mut iter => {
          $label: loop {
-             let mut __next;
              match Iterator::next(&mut iter) {
-                 Some(val) => __next = val,
                  None => break,
+                 Some($pat) => $block,
              }
-             let $pat = __next;
-             $block
          }
      }
  }
```
Diffstat (limited to 'src')
-rw-r--r--src/test/incremental/hashes/for_loops.rs2
-rw-r--r--src/test/mir-opt/remove_storage_markers.main.RemoveStorageMarkers.diff115
-rw-r--r--src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.continue.txt5
-rw-r--r--src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.inline.txt3
-rw-r--r--src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.loops_branches.txt6
-rw-r--r--src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.simple_match.txt2
-rw-r--r--src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.try_error_result.txt4
-rw-r--r--src/test/ui/borrowck/return-local-binding-from-desugaring.rs2
-rw-r--r--src/test/ui/borrowck/return-local-binding-from-desugaring.stderr4
-rw-r--r--src/test/ui/for/for-loop-unconstrained-element-type.stderr6
-rw-r--r--src/test/ui/issues/issue-20261.stderr4
-rw-r--r--src/test/ui/issues/issue-33941.rs1
-rw-r--r--src/test/ui/issues/issue-33941.stderr12
-rw-r--r--src/test/ui/nll/dont-print-desugared.stderr2
-rw-r--r--src/test/ui/nll/issue-53773.stderr4
-rw-r--r--src/test/ui/reachable/unreachable-loop-patterns.rs1
-rw-r--r--src/test/ui/reachable/unreachable-loop-patterns.stderr8
-rw-r--r--src/tools/clippy/clippy_lints/src/loops/explicit_counter_loop.rs8
-rw-r--r--src/tools/clippy/clippy_lints/src/loops/manual_memcpy.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/loops/mod.rs19
-rw-r--r--src/tools/clippy/clippy_lints/src/loops/never_loop.rs58
-rw-r--r--src/tools/clippy/clippy_lints/src/loops/single_element_loop.rs5
-rw-r--r--src/tools/clippy/clippy_lints/src/loops/utils.rs12
-rw-r--r--src/tools/clippy/clippy_lints/src/misc.rs5
-rw-r--r--src/tools/clippy/clippy_lints/src/pattern_type_mismatch.rs207
-rw-r--r--src/tools/clippy/clippy_lints/src/unit_types/let_unit_value.rs4
-rw-r--r--src/tools/clippy/clippy_utils/src/higher.rs62
-rw-r--r--src/tools/clippy/tests/ui/author/for_loop.stdout53
28 files changed, 202 insertions, 416 deletions
diff --git a/src/test/incremental/hashes/for_loops.rs b/src/test/incremental/hashes/for_loops.rs
index 1b96cd54c3e..d3687d5b908 100644
--- a/src/test/incremental/hashes/for_loops.rs
+++ b/src/test/incremental/hashes/for_loops.rs
@@ -183,7 +183,7 @@ pub fn add_loop_label_to_break() {
 #[cfg(not(any(cfail1,cfail4)))]
 #[rustc_clean(cfg="cfail2", except="hir_owner_nodes")]
 #[rustc_clean(cfg="cfail3")]
-#[rustc_clean(cfg="cfail5", except="hir_owner_nodes")]
+#[rustc_clean(cfg="cfail5", except="hir_owner_nodes, optimized_mir")]
 #[rustc_clean(cfg="cfail6")]
 pub fn add_loop_label_to_break() {
     let mut _x = 0;
diff --git a/src/test/mir-opt/remove_storage_markers.main.RemoveStorageMarkers.diff b/src/test/mir-opt/remove_storage_markers.main.RemoveStorageMarkers.diff
index 02f6e55a9a8..2dfc94f2186 100644
--- a/src/test/mir-opt/remove_storage_markers.main.RemoveStorageMarkers.diff
+++ b/src/test/mir-opt/remove_storage_markers.main.RemoveStorageMarkers.diff
@@ -7,39 +7,29 @@
       let mut _2: std::ops::Range<i32>;    // in scope 0 at $DIR/remove_storage_markers.rs:8:14: 8:19
       let mut _3: std::ops::Range<i32>;    // in scope 0 at $DIR/remove_storage_markers.rs:8:14: 8:19
       let mut _5: ();                      // in scope 0 at $DIR/remove_storage_markers.rs:6:1: 11:2
-      let _7: ();                          // in scope 0 at $DIR/remove_storage_markers.rs:8:14: 8:19
-      let mut _8: std::option::Option<i32>; // in scope 0 at $DIR/remove_storage_markers.rs:8:14: 8:19
+      let _6: ();                          // in scope 0 at $DIR/remove_storage_markers.rs:8:14: 8:19
+      let mut _7: std::option::Option<i32>; // in scope 0 at $DIR/remove_storage_markers.rs:8:14: 8:19
+      let mut _8: &mut std::ops::Range<i32>; // in scope 0 at $DIR/remove_storage_markers.rs:8:14: 8:19
       let mut _9: &mut std::ops::Range<i32>; // in scope 0 at $DIR/remove_storage_markers.rs:8:14: 8:19
-      let mut _10: &mut std::ops::Range<i32>; // in scope 0 at $DIR/remove_storage_markers.rs:8:14: 8:19
-      let mut _11: isize;                  // in scope 0 at $DIR/remove_storage_markers.rs:8:9: 8:10
-      let mut _13: i32;                    // in scope 0 at $DIR/remove_storage_markers.rs:8:9: 8:10
-      let mut _14: !;                      // in scope 0 at $DIR/remove_storage_markers.rs:8:5: 10:6
-      let _16: ();                         // in scope 0 at $DIR/remove_storage_markers.rs:8:20: 10:6
-      let mut _17: i32;                    // in scope 0 at $DIR/remove_storage_markers.rs:9:16: 9:17
+      let mut _10: isize;                  // in scope 0 at $DIR/remove_storage_markers.rs:8:5: 10:6
+      let mut _11: !;                      // in scope 0 at $DIR/remove_storage_markers.rs:8:5: 10:6
+      let mut _13: i32;                    // in scope 0 at $DIR/remove_storage_markers.rs:9:16: 9:17
       scope 1 {
           debug sum => _1;                 // in scope 1 at $DIR/remove_storage_markers.rs:7:9: 7:16
           let mut _4: std::ops::Range<i32>; // in scope 1 at $DIR/remove_storage_markers.rs:8:14: 8:19
           scope 2 {
               debug iter => _4;            // in scope 2 at $DIR/remove_storage_markers.rs:8:14: 8:19
-              let mut _6: i32;             // in scope 2 at $DIR/remove_storage_markers.rs:8:14: 8:19
+              let _12: i32;                // in scope 2 at $DIR/remove_storage_markers.rs:8:9: 8:10
               scope 3 {
-                  debug __next => _6;      // in scope 3 at $DIR/remove_storage_markers.rs:8:14: 8:19
-                  let _12: i32;            // in scope 3 at $DIR/remove_storage_markers.rs:8:9: 8:10
-                  let _15: i32;            // in scope 3 at $DIR/remove_storage_markers.rs:8:9: 8:10
-                  scope 4 {
-                      debug val => _12;    // in scope 4 at $DIR/remove_storage_markers.rs:8:9: 8:10
-                  }
-                  scope 5 {
-                      debug i => _15;      // in scope 5 at $DIR/remove_storage_markers.rs:8:9: 8:10
-                  }
-                  scope 7 (inlined iter::range::<impl Iterator for std::ops::Range<i32>>::next) { // at $DIR/remove_storage_markers.rs:8:14: 8:19
-                      debug self => _9;    // in scope 7 at $DIR/remove_storage_markers.rs:8:14: 8:19
-                      let mut _18: &mut std::ops::Range<i32>; // in scope 7 at $DIR/remove_storage_markers.rs:8:14: 8:19
-                  }
+                  debug i => _12;          // in scope 3 at $DIR/remove_storage_markers.rs:8:9: 8:10
+              }
+              scope 5 (inlined iter::range::<impl Iterator for std::ops::Range<i32>>::next) { // at $DIR/remove_storage_markers.rs:8:14: 8:19
+                  debug self => _8;        // in scope 5 at $DIR/remove_storage_markers.rs:8:14: 8:19
+                  let mut _14: &mut std::ops::Range<i32>; // in scope 5 at $DIR/remove_storage_markers.rs:8:14: 8:19
               }
           }
-          scope 6 (inlined <std::ops::Range<i32> as IntoIterator>::into_iter) { // at $DIR/remove_storage_markers.rs:8:14: 8:19
-              debug self => _3;            // in scope 6 at $DIR/remove_storage_markers.rs:8:14: 8:19
+          scope 4 (inlined <std::ops::Range<i32> as IntoIterator>::into_iter) { // at $DIR/remove_storage_markers.rs:8:14: 8:19
+              debug self => _3;            // in scope 4 at $DIR/remove_storage_markers.rs:8:14: 8:19
           }
       }
   
@@ -50,7 +40,7 @@
 -         StorageLive(_3);                 // scope 1 at $DIR/remove_storage_markers.rs:8:14: 8:19
           (_3.0: i32) = const 0_i32;       // scope 1 at $DIR/remove_storage_markers.rs:8:14: 8:19
           (_3.1: i32) = const 10_i32;      // scope 1 at $DIR/remove_storage_markers.rs:8:14: 8:19
-          _2 = move _3;                    // scope 6 at $DIR/remove_storage_markers.rs:8:14: 8:19
+          _2 = move _3;                    // scope 4 at $DIR/remove_storage_markers.rs:8:14: 8:19
 -         StorageDead(_3);                 // scope 1 at $DIR/remove_storage_markers.rs:8:18: 8:19
 -         StorageLive(_4);                 // scope 1 at $DIR/remove_storage_markers.rs:8:14: 8:19
           _4 = move _2;                    // scope 1 at $DIR/remove_storage_markers.rs:8:14: 8:19
@@ -59,64 +49,51 @@
   
       bb1: {
 -         StorageLive(_6);                 // scope 2 at $DIR/remove_storage_markers.rs:8:14: 8:19
--         StorageLive(_7);                 // scope 3 at $DIR/remove_storage_markers.rs:8:14: 8:19
--         StorageLive(_8);                 // scope 3 at $DIR/remove_storage_markers.rs:8:14: 8:19
--         StorageLive(_9);                 // scope 3 at $DIR/remove_storage_markers.rs:8:14: 8:19
--         StorageLive(_10);                // scope 3 at $DIR/remove_storage_markers.rs:8:14: 8:19
-          _10 = &mut _4;                   // scope 3 at $DIR/remove_storage_markers.rs:8:14: 8:19
-          _9 = &mut (*_10);                // scope 3 at $DIR/remove_storage_markers.rs:8:14: 8:19
--         StorageLive(_18);                // scope 7 at $DIR/remove_storage_markers.rs:8:14: 8:19
-          _18 = &mut (*_9);                // scope 7 at $DIR/remove_storage_markers.rs:8:14: 8:19
-          _8 = <std::ops::Range<i32> as iter::range::RangeIteratorImpl>::spec_next(move _18) -> bb4; // scope 7 at $DIR/remove_storage_markers.rs:8:14: 8:19
+-         StorageLive(_7);                 // scope 2 at $DIR/remove_storage_markers.rs:8:14: 8:19
+-         StorageLive(_8);                 // scope 2 at $DIR/remove_storage_markers.rs:8:14: 8:19
+-         StorageLive(_9);                 // scope 2 at $DIR/remove_storage_markers.rs:8:14: 8:19
+          _9 = &mut _4;                    // scope 2 at $DIR/remove_storage_markers.rs:8:14: 8:19
+          _8 = &mut (*_9);                 // scope 2 at $DIR/remove_storage_markers.rs:8:14: 8:19
+-         StorageLive(_14);                // scope 5 at $DIR/remove_storage_markers.rs:8:14: 8:19
+          _14 = &mut (*_8);                // scope 5 at $DIR/remove_storage_markers.rs:8:14: 8:19
+          _7 = <std::ops::Range<i32> as iter::range::RangeIteratorImpl>::spec_next(move _14) -> bb4; // scope 5 at $DIR/remove_storage_markers.rs:8:14: 8:19
                                            // mir::Constant
                                            // + span: $DIR/remove_storage_markers.rs:8:14: 8:19
                                            // + literal: Const { ty: for<'r> fn(&'r mut std::ops::Range<i32>) -> std::option::Option<<std::ops::Range<i32> as std::iter::range::RangeIteratorImpl>::Item> {<std::ops::Range<i32> as std::iter::range::RangeIteratorImpl>::spec_next}, val: Value(Scalar(<ZST>)) }
       }
   
       bb2: {
-          _0 = const ();                   // scope 3 at $DIR/remove_storage_markers.rs:8:5: 10:6
--         StorageDead(_10);                // scope 3 at $DIR/remove_storage_markers.rs:8:18: 8:19
--         StorageDead(_8);                 // scope 3 at $DIR/remove_storage_markers.rs:8:18: 8:19
--         StorageDead(_7);                 // scope 3 at $DIR/remove_storage_markers.rs:8:18: 8:19
+-         StorageLive(_12);                // scope 2 at $DIR/remove_storage_markers.rs:8:9: 8:10
+          _12 = ((_7 as Some).0: i32);     // scope 2 at $DIR/remove_storage_markers.rs:8:9: 8:10
+-         StorageLive(_13);                // scope 3 at $DIR/remove_storage_markers.rs:9:16: 9:17
+          _13 = _12;                       // scope 3 at $DIR/remove_storage_markers.rs:9:16: 9:17
+          _1 = Add(_1, move _13);          // scope 3 at $DIR/remove_storage_markers.rs:9:9: 9:17
+-         StorageDead(_13);                // scope 3 at $DIR/remove_storage_markers.rs:9:16: 9:17
+          _6 = const ();                   // scope 3 at $DIR/remove_storage_markers.rs:8:20: 10:6
+-         StorageDead(_12);                // scope 2 at $DIR/remove_storage_markers.rs:10:5: 10:6
+-         StorageDead(_9);                 // scope 2 at $DIR/remove_storage_markers.rs:10:5: 10:6
+-         StorageDead(_7);                 // scope 2 at $DIR/remove_storage_markers.rs:10:5: 10:6
 -         StorageDead(_6);                 // scope 2 at $DIR/remove_storage_markers.rs:10:5: 10:6
--         StorageDead(_4);                 // scope 1 at $DIR/remove_storage_markers.rs:10:5: 10:6
--         StorageDead(_2);                 // scope 1 at $DIR/remove_storage_markers.rs:10:5: 10:6
--         StorageDead(_1);                 // scope 0 at $DIR/remove_storage_markers.rs:11:1: 11:2
-          return;                          // scope 0 at $DIR/remove_storage_markers.rs:11:2: 11:2
+          _5 = const ();                   // scope 2 at $DIR/remove_storage_markers.rs:8:5: 10:6
+          goto -> bb1;                     // scope 2 at $DIR/remove_storage_markers.rs:8:5: 10:6
       }
   
       bb3: {
--         StorageLive(_12);                // scope 3 at $DIR/remove_storage_markers.rs:8:9: 8:10
-          _12 = ((_8 as Some).0: i32);     // scope 3 at $DIR/remove_storage_markers.rs:8:9: 8:10
--         StorageLive(_13);                // scope 4 at $DIR/remove_storage_markers.rs:8:9: 8:10
-          _13 = _12;                       // scope 4 at $DIR/remove_storage_markers.rs:8:9: 8:10
-          _6 = move _13;                   // scope 4 at $DIR/remove_storage_markers.rs:8:9: 8:10
-          _7 = const ();                   // scope 4 at $DIR/remove_storage_markers.rs:8:9: 8:10
--         StorageDead(_13);                // scope 4 at $DIR/remove_storage_markers.rs:8:9: 8:10
--         StorageDead(_12);                // scope 3 at $DIR/remove_storage_markers.rs:8:9: 8:10
--         StorageDead(_10);                // scope 3 at $DIR/remove_storage_markers.rs:8:18: 8:19
--         StorageDead(_8);                 // scope 3 at $DIR/remove_storage_markers.rs:8:18: 8:19
--         StorageDead(_7);                 // scope 3 at $DIR/remove_storage_markers.rs:8:18: 8:19
--         StorageLive(_15);                // scope 3 at $DIR/remove_storage_markers.rs:8:9: 8:10
-          _15 = _6;                        // scope 3 at $DIR/remove_storage_markers.rs:8:14: 8:19
--         StorageLive(_16);                // scope 5 at $DIR/remove_storage_markers.rs:8:20: 10:6
--         StorageLive(_17);                // scope 5 at $DIR/remove_storage_markers.rs:9:16: 9:17
-          _17 = _15;                       // scope 5 at $DIR/remove_storage_markers.rs:9:16: 9:17
-          _1 = Add(_1, move _17);          // scope 5 at $DIR/remove_storage_markers.rs:9:9: 9:17
--         StorageDead(_17);                // scope 5 at $DIR/remove_storage_markers.rs:9:16: 9:17
-          _16 = const ();                  // scope 5 at $DIR/remove_storage_markers.rs:8:20: 10:6
--         StorageDead(_16);                // scope 5 at $DIR/remove_storage_markers.rs:10:5: 10:6
-          _5 = const ();                   // scope 2 at $DIR/remove_storage_markers.rs:8:5: 10:6
--         StorageDead(_15);                // scope 3 at $DIR/remove_storage_markers.rs:10:5: 10:6
+          _0 = const ();                   // scope 2 at $DIR/remove_storage_markers.rs:8:5: 10:6
+-         StorageDead(_9);                 // scope 2 at $DIR/remove_storage_markers.rs:10:5: 10:6
+-         StorageDead(_7);                 // scope 2 at $DIR/remove_storage_markers.rs:10:5: 10:6
 -         StorageDead(_6);                 // scope 2 at $DIR/remove_storage_markers.rs:10:5: 10:6
-          goto -> bb1;                     // scope 2 at $DIR/remove_storage_markers.rs:8:5: 10:6
+-         StorageDead(_4);                 // scope 1 at $DIR/remove_storage_markers.rs:10:5: 10:6
+-         StorageDead(_2);                 // scope 1 at $DIR/remove_storage_markers.rs:10:5: 10:6
+-         StorageDead(_1);                 // scope 0 at $DIR/remove_storage_markers.rs:11:1: 11:2
+          return;                          // scope 0 at $DIR/remove_storage_markers.rs:11:2: 11:2
       }
   
       bb4: {
--         StorageDead(_18);                // scope 7 at $DIR/remove_storage_markers.rs:8:14: 8:19
--         StorageDead(_9);                 // scope 3 at $DIR/remove_storage_markers.rs:8:18: 8:19
-          _11 = discriminant(_8);          // scope 3 at $DIR/remove_storage_markers.rs:8:14: 8:19
-          switchInt(move _11) -> [0_isize: bb2, otherwise: bb3]; // scope 3 at $DIR/remove_storage_markers.rs:8:14: 8:19
+-         StorageDead(_14);                // scope 5 at $DIR/remove_storage_markers.rs:8:14: 8:19
+-         StorageDead(_8);                 // scope 2 at $DIR/remove_storage_markers.rs:8:18: 8:19
+          _10 = discriminant(_7);          // scope 2 at $DIR/remove_storage_markers.rs:8:14: 8:19
+          switchInt(move _10) -> [0_isize: bb3, otherwise: bb2]; // scope 2 at $DIR/remove_storage_markers.rs:8:14: 8:19
       }
   }
   
diff --git a/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.continue.txt b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.continue.txt
index 28e0f1953e0..1c64ead9f26 100644
--- a/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.continue.txt
+++ b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.continue.txt
@@ -5,7 +5,6 @@
     5|      1|
     6|      1|    let mut x = 0;
     7|     11|    for _ in 0..10 {
-                      ^10
     8|     10|        match is_true {
     9|       |            true => {
    10|     10|                continue;
@@ -17,7 +16,6 @@
    16|      0|        x = 3;
    17|       |    }
    18|     11|    for _ in 0..10 {
-                      ^10
    19|     10|        match is_true {
    20|      0|            false => {
    21|      0|                x = 1;
@@ -29,7 +27,6 @@
    27|      0|        x = 3;
    28|       |    }
    29|     11|    for _ in 0..10 {
-                      ^10
    30|     10|        match is_true {
    31|     10|            true => {
    32|     10|                x = 1;
@@ -41,14 +38,12 @@
    38|     10|        x = 3;
    39|       |    }
    40|     11|    for _ in 0..10 {
-                      ^10
    41|     10|        if is_true {
    42|     10|            continue;
    43|      0|        }
    44|      0|        x = 3;
    45|       |    }
    46|     11|    for _ in 0..10 {
-                      ^10
    47|     10|        match is_true {
    48|      0|            false => {
    49|      0|                x = 1;
diff --git a/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.inline.txt b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.inline.txt
index 31d3ddea8d9..6f5d1544fa0 100644
--- a/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.inline.txt
+++ b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.inline.txt
@@ -40,7 +40,8 @@
    39|     30|}
    40|       |
    41|      6|fn display<T: Display>(xs: &[T]) {
-   42|     18|    for x in xs {
+   42|     24|    for x in xs {
+                      ^18
    43|     18|        print!("{}", x);
    44|     18|    }
    45|      6|    println!();
diff --git a/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.loops_branches.txt b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.loops_branches.txt
index 5d572db7cc6..b7ad79a2484 100644
--- a/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.loops_branches.txt
+++ b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.loops_branches.txt
@@ -17,7 +17,8 @@
    16|      0|        } else {
    17|      0|        }
    18|       |
-   19|     10|        for i in 0..10 {
+   19|     11|        for i in 0..10 {
+                          ^10
    20|     10|            if true {
    21|     10|                if false {
    22|      0|                    while true {}
@@ -43,7 +44,8 @@
    41|      1|            write!(f, "cool")?;
                                            ^0
    42|       |        }
-   43|     10|        for i in 0..10 {
+   43|     11|        for i in 0..10 {
+                          ^10
    44|     10|            if false {
    45|      0|            } else {
    46|     10|                if false {
diff --git a/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.simple_match.txt b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.simple_match.txt
index 81b4c090a46..b9298213111 100644
--- a/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.simple_match.txt
+++ b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.simple_match.txt
@@ -13,7 +13,7 @@
                    ^0
    13|       |
    14|       |    for
-   15|      2|        _
+   15|       |        _
    16|       |    in
    17|      3|        0..2
    18|       |    {
diff --git a/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.try_error_result.txt b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.try_error_result.txt
index 9fca52451ed..0ad0180b761 100644
--- a/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.try_error_result.txt
+++ b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.try_error_result.txt
@@ -14,7 +14,7 @@
    14|      1|        countdown = 10
    15|       |    ;
    16|       |    for
-   17|      6|        _
+   17|       |        _
    18|       |    in
    19|      6|        0..10
    20|       |    {
@@ -64,7 +64,7 @@
    63|      1|        countdown = 10
    64|       |    ;
    65|       |    for
-   66|      6|        _
+   66|       |        _
    67|       |    in
    68|      6|        0..10
    69|       |    {
diff --git a/src/test/ui/borrowck/return-local-binding-from-desugaring.rs b/src/test/ui/borrowck/return-local-binding-from-desugaring.rs
index b2dcd54ec2e..c6643edf5a9 100644
--- a/src/test/ui/borrowck/return-local-binding-from-desugaring.rs
+++ b/src/test/ui/borrowck/return-local-binding-from-desugaring.rs
@@ -27,7 +27,7 @@ where
         let key = f(x);
         result.entry(key).or_insert(Vec::new()).push(x);
     }
-    result //~ ERROR cannot return value referencing local binding
+    result //~ ERROR cannot return value referencing temporary value
 }
 
 fn main() {}
diff --git a/src/test/ui/borrowck/return-local-binding-from-desugaring.stderr b/src/test/ui/borrowck/return-local-binding-from-desugaring.stderr
index 293dbe62813..9f952542e18 100644
--- a/src/test/ui/borrowck/return-local-binding-from-desugaring.stderr
+++ b/src/test/ui/borrowck/return-local-binding-from-desugaring.stderr
@@ -1,8 +1,8 @@
-error[E0515]: cannot return value referencing local binding
+error[E0515]: cannot return value referencing temporary value
   --> $DIR/return-local-binding-from-desugaring.rs:30:5
    |
 LL |     for ref x in xs {
-   |                  -- local binding introduced here
+   |                  -- temporary value created here
 ...
 LL |     result
    |     ^^^^^^ returns a value referencing data owned by the current function
diff --git a/src/test/ui/for/for-loop-unconstrained-element-type.stderr b/src/test/ui/for/for-loop-unconstrained-element-type.stderr
index 0672014a929..580b135ac2d 100644
--- a/src/test/ui/for/for-loop-unconstrained-element-type.stderr
+++ b/src/test/ui/for/for-loop-unconstrained-element-type.stderr
@@ -1,8 +1,10 @@
 error[E0282]: type annotations needed
-  --> $DIR/for-loop-unconstrained-element-type.rs:8:14
+  --> $DIR/for-loop-unconstrained-element-type.rs:8:9
    |
 LL |     for i in Vec::new() { }
-   |              ^^^^^^^^^^ the element type for this iterator is not specified
+   |         ^    ---------- the element type for this iterator is not specified
+   |         |
+   |         cannot infer type
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/issues/issue-20261.stderr b/src/test/ui/issues/issue-20261.stderr
index c6c3f32dfe7..6330364c92b 100644
--- a/src/test/ui/issues/issue-20261.stderr
+++ b/src/test/ui/issues/issue-20261.stderr
@@ -1,8 +1,8 @@
-error[E0282]: type annotations needed for `&(_,)`
+error[E0282]: type annotations needed for `(_,)`
   --> $DIR/issue-20261.rs:4:11
    |
 LL |     for (ref i,) in [].iter() {
-   |                     --------- the element type for this iterator is not specified
+   |                     --------- this method call resolves to `std::slice::Iter<'_, T>`
 LL |         i.clone();
    |           ^^^^^ cannot infer type
    |
diff --git a/src/test/ui/issues/issue-33941.rs b/src/test/ui/issues/issue-33941.rs
index 4fb805b37e0..ccaa6334856 100644
--- a/src/test/ui/issues/issue-33941.rs
+++ b/src/test/ui/issues/issue-33941.rs
@@ -3,5 +3,4 @@ use std::collections::HashMap;
 fn main() {
     for _ in HashMap::new().iter().cloned() {} //~ ERROR type mismatch
     //~^ ERROR type mismatch
-    //~| ERROR type mismatch
 }
diff --git a/src/test/ui/issues/issue-33941.stderr b/src/test/ui/issues/issue-33941.stderr
index e7263148205..eb98a3a29a6 100644
--- a/src/test/ui/issues/issue-33941.stderr
+++ b/src/test/ui/issues/issue-33941.stderr
@@ -23,16 +23,6 @@ LL |     for _ in HashMap::new().iter().cloned() {}
    = note: required because of the requirements on the impl of `Iterator` for `Cloned<std::collections::hash_map::Iter<'_, _, _>>`
    = note: required because of the requirements on the impl of `IntoIterator` for `Cloned<std::collections::hash_map::Iter<'_, _, _>>`
 
-error[E0271]: type mismatch resolving `<std::collections::hash_map::Iter<'_, _, _> as Iterator>::Item == &_`
-  --> $DIR/issue-33941.rs:4:14
-   |
-LL |     for _ in HashMap::new().iter().cloned() {}
-   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected reference, found tuple
-   |
-   = note: expected reference `&_`
-                  found tuple `(&_, &_)`
-   = note: required because of the requirements on the impl of `Iterator` for `Cloned<std::collections::hash_map::Iter<'_, _, _>>`
-
-error: aborting due to 3 previous errors
+error: aborting due to 2 previous errors
 
 For more information about this error, try `rustc --explain E0271`.
diff --git a/src/test/ui/nll/dont-print-desugared.stderr b/src/test/ui/nll/dont-print-desugared.stderr
index 88773def8b7..fad6121cbca 100644
--- a/src/test/ui/nll/dont-print-desugared.stderr
+++ b/src/test/ui/nll/dont-print-desugared.stderr
@@ -2,7 +2,7 @@ error[E0596]: cannot borrow data in a `&` reference as mutable
   --> $DIR/dont-print-desugared.rs:4:10
    |
 LL |     for &ref mut x in s {}
-   |          ^^^^^^^^^ cannot borrow as mutable through `&` reference
+   |          ^^^^^^^^^ cannot borrow as mutable
 
 error[E0597]: `y` does not live long enough
   --> $DIR/dont-print-desugared.rs:17:16
diff --git a/src/test/ui/nll/issue-53773.stderr b/src/test/ui/nll/issue-53773.stderr
index 11cd423295a..90cba2a145f 100644
--- a/src/test/ui/nll/issue-53773.stderr
+++ b/src/test/ui/nll/issue-53773.stderr
@@ -2,12 +2,10 @@ error[E0713]: borrow may still be in use when destructor runs
   --> $DIR/issue-53773.rs:41:22
    |
 LL |         members.push(child.raw);
-   |                      ^^^^^^^^^
+   |         -------------^^^^^^^^^- borrow later used here
 LL |
 LL |     }
    |     - here, drop of `child` needs exclusive access to `*child.raw`, because the type `C<'_>` implements the `Drop` trait
-LL |     members.len();
-   |     ------------- borrow later used here
    |
    = note: consider using a `let` binding to create a longer lived value
 
diff --git a/src/test/ui/reachable/unreachable-loop-patterns.rs b/src/test/ui/reachable/unreachable-loop-patterns.rs
index 4de29c3c3d7..e9cef5f47d4 100644
--- a/src/test/ui/reachable/unreachable-loop-patterns.rs
+++ b/src/test/ui/reachable/unreachable-loop-patterns.rs
@@ -17,5 +17,4 @@ impl Iterator for Void {
 fn main() {
     for _ in unimplemented!() as Void {}
     //~^ ERROR unreachable pattern
-    //~^^ ERROR unreachable pattern
 }
diff --git a/src/test/ui/reachable/unreachable-loop-patterns.stderr b/src/test/ui/reachable/unreachable-loop-patterns.stderr
index 680d22862d7..80ffa5d73f0 100644
--- a/src/test/ui/reachable/unreachable-loop-patterns.stderr
+++ b/src/test/ui/reachable/unreachable-loop-patterns.stderr
@@ -10,11 +10,5 @@ note: the lint level is defined here
 LL | #![deny(unreachable_patterns)]
    |         ^^^^^^^^^^^^^^^^^^^^
 
-error: unreachable pattern
-  --> $DIR/unreachable-loop-patterns.rs:18:14
-   |
-LL |     for _ in unimplemented!() as Void {}
-   |              ^^^^^^^^^^^^^^^^^^^^^^^^
-
-error: aborting due to 2 previous errors
+error: aborting due to previous error
 
diff --git a/src/tools/clippy/clippy_lints/src/loops/explicit_counter_loop.rs b/src/tools/clippy/clippy_lints/src/loops/explicit_counter_loop.rs
index 98e60f7ed85..6f213d7a699 100644
--- a/src/tools/clippy/clippy_lints/src/loops/explicit_counter_loop.rs
+++ b/src/tools/clippy/clippy_lints/src/loops/explicit_counter_loop.rs
@@ -1,6 +1,4 @@
-use super::{
-    get_span_of_entire_for_loop, make_iterator_snippet, IncrementVisitor, InitializeVisitor, EXPLICIT_COUNTER_LOOP,
-};
+use super::{make_iterator_snippet, IncrementVisitor, InitializeVisitor, EXPLICIT_COUNTER_LOOP};
 use clippy_utils::diagnostics::span_lint_and_sugg;
 use clippy_utils::source::snippet_with_applicability;
 use clippy_utils::{get_enclosing_block, is_integer_const};
@@ -37,12 +35,10 @@ pub(super) fn check<'tcx>(
                 then {
                     let mut applicability = Applicability::MachineApplicable;
 
-                    let for_span = get_span_of_entire_for_loop(expr);
-
                     span_lint_and_sugg(
                         cx,
                         EXPLICIT_COUNTER_LOOP,
-                        for_span.with_hi(arg.span.hi()),
+                        expr.span.with_hi(arg.span.hi()),
                         &format!("the variable `{}` is used as a loop counter", name),
                         "consider using",
                         format!(
diff --git a/src/tools/clippy/clippy_lints/src/loops/manual_memcpy.rs b/src/tools/clippy/clippy_lints/src/loops/manual_memcpy.rs
index 72027a163af..2362b4b2067 100644
--- a/src/tools/clippy/clippy_lints/src/loops/manual_memcpy.rs
+++ b/src/tools/clippy/clippy_lints/src/loops/manual_memcpy.rs
@@ -1,4 +1,4 @@
-use super::{get_span_of_entire_for_loop, IncrementVisitor, InitializeVisitor, MANUAL_MEMCPY};
+use super::{IncrementVisitor, InitializeVisitor, MANUAL_MEMCPY};
 use clippy_utils::diagnostics::span_lint_and_sugg;
 use clippy_utils::source::snippet;
 use clippy_utils::sugg::Sugg;
@@ -86,7 +86,7 @@ pub(super) fn check<'tcx>(
                 span_lint_and_sugg(
                     cx,
                     MANUAL_MEMCPY,
-                    get_span_of_entire_for_loop(expr),
+                    expr.span,
                     "it looks like you're manually copying between slices",
                     "try replacing the loop by",
                     big_sugg,
diff --git a/src/tools/clippy/clippy_lints/src/loops/mod.rs b/src/tools/clippy/clippy_lints/src/loops/mod.rs
index 5df1b796401..fd4881b2947 100644
--- a/src/tools/clippy/clippy_lints/src/loops/mod.rs
+++ b/src/tools/clippy/clippy_lints/src/loops/mod.rs
@@ -23,7 +23,7 @@ use rustc_hir::{Expr, ExprKind, LoopSource, Pat};
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_session::{declare_lint_pass, declare_tool_lint};
 use rustc_span::source_map::Span;
-use utils::{get_span_of_entire_for_loop, make_iterator_snippet, IncrementVisitor, InitializeVisitor};
+use utils::{make_iterator_snippet, IncrementVisitor, InitializeVisitor};
 
 declare_clippy_lint! {
     /// ### What it does
@@ -566,7 +566,15 @@ declare_lint_pass!(Loops => [
 impl<'tcx> LateLintPass<'tcx> for Loops {
     #[allow(clippy::too_many_lines)]
     fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
-        if let Some(higher::ForLoop { pat, arg, body, span }) = higher::ForLoop::hir(expr) {
+        let for_loop = higher::ForLoop::hir(expr);
+        if let Some(higher::ForLoop {
+            pat,
+            arg,
+            body,
+            loop_id,
+            span,
+        }) = for_loop
+        {
             // we don't want to check expanded macros
             // this check is not at the top of the function
             // since higher::for_loop expressions are marked as expansions
@@ -574,6 +582,9 @@ impl<'tcx> LateLintPass<'tcx> for Loops {
                 return;
             }
             check_for_loop(cx, pat, arg, body, expr, span);
+            if let ExprKind::Block(block, _) = body.kind {
+                never_loop::check(cx, block, loop_id, span, for_loop.as_ref());
+            }
         }
 
         // we don't want to check expanded macros
@@ -582,7 +593,9 @@ impl<'tcx> LateLintPass<'tcx> for Loops {
         }
 
         // check for never_loop
-        never_loop::check(cx, expr);
+        if let ExprKind::Loop(block, ..) = expr.kind {
+            never_loop::check(cx, block, expr.hir_id, expr.span, None);
+        }
 
         // check for `loop { if let {} else break }` that could be `while let`
         // (also matches an explicit "match" instead of "if let")
diff --git a/src/tools/clippy/clippy_lints/src/loops/never_loop.rs b/src/tools/clippy/clippy_lints/src/loops/never_loop.rs
index c0fde5e5166..86b7d6d989a 100644
--- a/src/tools/clippy/clippy_lints/src/loops/never_loop.rs
+++ b/src/tools/clippy/clippy_lints/src/loops/never_loop.rs
@@ -4,35 +4,41 @@ use clippy_utils::diagnostics::span_lint_and_then;
 use clippy_utils::higher::ForLoop;
 use clippy_utils::source::snippet;
 use rustc_errors::Applicability;
-use rustc_hir::{Block, Expr, ExprKind, HirId, InlineAsmOperand, LoopSource, Node, Pat, Stmt, StmtKind};
+use rustc_hir::{Block, Expr, ExprKind, HirId, InlineAsmOperand, Pat, Stmt, StmtKind};
 use rustc_lint::LateContext;
+use rustc_span::Span;
 use std::iter::{once, Iterator};
 
-pub(super) fn check(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
-    if let ExprKind::Loop(block, _, source, _) = expr.kind {
-        match never_loop_block(block, expr.hir_id) {
-            NeverLoopResult::AlwaysBreak => {
-                span_lint_and_then(cx, NEVER_LOOP, expr.span, "this loop never actually loops", |diag| {
-                    if_chain! {
-                        if source == LoopSource::ForLoop;
-                        if let Some((_, Node::Expr(parent_match))) = cx.tcx.hir().parent_iter(expr.hir_id).nth(1);
-                        if let Some(ForLoop { arg: iterator, pat, span: for_span, .. }) = ForLoop::hir(parent_match);
-                        then {
-                            // Suggests using an `if let` instead. This is `Unspecified` because the
-                            // loop may (probably) contain `break` statements which would be invalid
-                            // in an `if let`.
-                            diag.span_suggestion_verbose(
-                                for_span.with_hi(iterator.span.hi()),
-                                "if you need the first element of the iterator, try writing",
-                                for_to_if_let_sugg(cx, iterator, pat),
-                                Applicability::Unspecified,
-                            );
-                        }
-                    };
-                });
-            },
-            NeverLoopResult::MayContinueMainLoop | NeverLoopResult::Otherwise => (),
-        }
+pub(super) fn check(
+    cx: &LateContext<'tcx>,
+    block: &'tcx Block<'_>,
+    loop_id: HirId,
+    span: Span,
+    for_loop: Option<&ForLoop<'_>>,
+) {
+    match never_loop_block(block, loop_id) {
+        NeverLoopResult::AlwaysBreak => {
+            span_lint_and_then(cx, NEVER_LOOP, span, "this loop never actually loops", |diag| {
+                if let Some(ForLoop {
+                    arg: iterator,
+                    pat,
+                    span: for_span,
+                    ..
+                }) = for_loop
+                {
+                    // Suggests using an `if let` instead. This is `Unspecified` because the
+                    // loop may (probably) contain `break` statements which would be invalid
+                    // in an `if let`.
+                    diag.span_suggestion_verbose(
+                        for_span.with_hi(iterator.span.hi()),
+                        "if you need the first element of the iterator, try writing",
+                        for_to_if_let_sugg(cx, iterator, pat),
+                        Applicability::Unspecified,
+                    );
+                }
+            });
+        },
+        NeverLoopResult::MayContinueMainLoop | NeverLoopResult::Otherwise => (),
     }
 }
 
diff --git a/src/tools/clippy/clippy_lints/src/loops/single_element_loop.rs b/src/tools/clippy/clippy_lints/src/loops/single_element_loop.rs
index 0fd09ff7197..e39605f3e7d 100644
--- a/src/tools/clippy/clippy_lints/src/loops/single_element_loop.rs
+++ b/src/tools/clippy/clippy_lints/src/loops/single_element_loop.rs
@@ -1,4 +1,4 @@
-use super::{get_span_of_entire_for_loop, SINGLE_ELEMENT_LOOP};
+use super::SINGLE_ELEMENT_LOOP;
 use clippy_utils::diagnostics::span_lint_and_sugg;
 use clippy_utils::single_segment_path;
 use clippy_utils::source::{indent_of, snippet};
@@ -30,7 +30,6 @@ pub(super) fn check<'tcx>(
         if !block.stmts.is_empty();
 
         then {
-            let for_span = get_span_of_entire_for_loop(expr);
             let mut block_str = snippet(cx, block.span, "..").into_owned();
             block_str.remove(0);
             block_str.pop();
@@ -39,7 +38,7 @@ pub(super) fn check<'tcx>(
             span_lint_and_sugg(
                 cx,
                 SINGLE_ELEMENT_LOOP,
-                for_span,
+                expr.span,
                 "for loop over a single element",
                 "try",
                 format!("{{\n{}let {} = &{};{}}}", " ".repeat(indent_of(cx, block.stmts[0].span).unwrap_or(0)), target.name, list_item_name, block_str),
diff --git a/src/tools/clippy/clippy_lints/src/loops/utils.rs b/src/tools/clippy/clippy_lints/src/loops/utils.rs
index f9f515cc40a..c3939a66c6a 100644
--- a/src/tools/clippy/clippy_lints/src/loops/utils.rs
+++ b/src/tools/clippy/clippy_lints/src/loops/utils.rs
@@ -7,7 +7,6 @@ use rustc_hir::HirIdMap;
 use rustc_hir::{BinOpKind, BorrowKind, Expr, ExprKind, HirId, Mutability, Pat, PatKind, Stmt, StmtKind};
 use rustc_lint::LateContext;
 use rustc_middle::hir::map::Map;
-use rustc_span::source_map::Span;
 use rustc_span::symbol::{sym, Symbol};
 use std::iter::Iterator;
 
@@ -300,17 +299,6 @@ impl<'tcx> Visitor<'tcx> for LoopNestVisitor {
     }
 }
 
-// this function assumes the given expression is a `for` loop.
-pub(super) fn get_span_of_entire_for_loop(expr: &Expr<'_>) -> Span {
-    // for some reason this is the only way to get the `Span`
-    // of the entire `for` loop
-    if let ExprKind::Match(_, arms, _) = &expr.kind {
-        arms[0].body.span
-    } else {
-        unreachable!()
-    }
-}
-
 /// If `arg` was the argument to a `for` loop, return the "cleanest" way of writing the
 /// actual `Iterator` that the loop uses.
 pub(super) fn make_iterator_snippet(cx: &LateContext<'_>, arg: &Expr<'_>, applic_ref: &mut Applicability) -> String {
diff --git a/src/tools/clippy/clippy_lints/src/misc.rs b/src/tools/clippy/clippy_lints/src/misc.rs
index 0f32cd9164e..78183add9cc 100644
--- a/src/tools/clippy/clippy_lints/src/misc.rs
+++ b/src/tools/clippy/clippy_lints/src/misc.rs
@@ -20,8 +20,8 @@ use rustc_span::symbol::sym;
 use clippy_utils::consts::{constant, Constant};
 use clippy_utils::sugg::Sugg;
 use clippy_utils::{
-    expr_path_res, get_item_name, get_parent_expr, higher, in_constant, is_diag_trait_item, is_integer_const,
-    iter_input_pats, last_path_segment, match_any_def_paths, paths, unsext, SpanlessEq,
+    expr_path_res, get_item_name, get_parent_expr, in_constant, is_diag_trait_item, is_integer_const, iter_input_pats,
+    last_path_segment, match_any_def_paths, paths, unsext, SpanlessEq,
 };
 
 declare_clippy_lint! {
@@ -312,7 +312,6 @@ impl<'tcx> LateLintPass<'tcx> for MiscLints {
             if let StmtKind::Local(local) = stmt.kind;
             if let PatKind::Binding(an, .., name, None) = local.pat.kind;
             if let Some(init) = local.init;
-            if !higher::is_from_for_desugar(local);
             if an == BindingAnnotation::Ref || an == BindingAnnotation::RefMut;
             then {
                 // use the macro callsite when the init span (but not the whole local span)
diff --git a/src/tools/clippy/clippy_lints/src/pattern_type_mismatch.rs b/src/tools/clippy/clippy_lints/src/pattern_type_mismatch.rs
index e7bc2446590..018e6d611db 100644
--- a/src/tools/clippy/clippy_lints/src/pattern_type_mismatch.rs
+++ b/src/tools/clippy/clippy_lints/src/pattern_type_mismatch.rs
@@ -1,16 +1,12 @@
 use clippy_utils::diagnostics::span_lint_and_help;
-use clippy_utils::last_path_segment;
 use rustc_hir::{
-    intravisit, Body, Expr, ExprKind, FnDecl, HirId, LocalSource, MatchSource, Mutability, Pat, PatField, PatKind,
-    QPath, Stmt, StmtKind,
+    intravisit, Body, Expr, ExprKind, FnDecl, HirId, LocalSource, Mutability, Pat, PatKind, Stmt, StmtKind,
 };
 use rustc_lint::{LateContext, LateLintPass, LintContext};
 use rustc_middle::lint::in_external_macro;
-use rustc_middle::ty::subst::SubstsRef;
-use rustc_middle::ty::{AdtDef, FieldDef, Ty, TyKind, VariantDef};
+use rustc_middle::ty;
 use rustc_session::{declare_lint_pass, declare_tool_lint};
 use rustc_span::source_map::Span;
-use std::iter;
 
 declare_clippy_lint! {
     /// ### What it does
@@ -87,43 +83,28 @@ declare_lint_pass!(PatternTypeMismatch => [PATTERN_TYPE_MISMATCH]);
 impl<'tcx> LateLintPass<'tcx> for PatternTypeMismatch {
     fn check_stmt(&mut self, cx: &LateContext<'tcx>, stmt: &'tcx Stmt<'_>) {
         if let StmtKind::Local(local) = stmt.kind {
-            if let Some(init) = &local.init {
-                if let Some(init_ty) = cx.typeck_results().node_type_opt(init.hir_id) {
-                    let pat = &local.pat;
-                    if in_external_macro(cx.sess(), pat.span) {
-                        return;
-                    }
-                    let deref_possible = match local.source {
-                        LocalSource::Normal => DerefPossible::Possible,
-                        _ => DerefPossible::Impossible,
-                    };
-                    apply_lint(cx, pat, init_ty, deref_possible);
-                }
+            if in_external_macro(cx.sess(), local.pat.span) {
+                return;
             }
+            let deref_possible = match local.source {
+                LocalSource::Normal => DerefPossible::Possible,
+                _ => DerefPossible::Impossible,
+            };
+            apply_lint(cx, local.pat, deref_possible);
         }
     }
 
     fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
-        if let ExprKind::Match(scrutinee, arms, MatchSource::Normal) = expr.kind {
-            if let Some(expr_ty) = cx.typeck_results().node_type_opt(scrutinee.hir_id) {
-                'pattern_checks: for arm in arms {
-                    let pat = &arm.pat;
-                    if in_external_macro(cx.sess(), pat.span) {
-                        continue 'pattern_checks;
-                    }
-                    if apply_lint(cx, pat, expr_ty, DerefPossible::Possible) {
-                        break 'pattern_checks;
-                    }
+        if let ExprKind::Match(_, arms, _) = expr.kind {
+            for arm in arms {
+                let pat = &arm.pat;
+                if apply_lint(cx, pat, DerefPossible::Possible) {
+                    break;
                 }
             }
         }
-        if let ExprKind::Let(let_pat, let_expr, _) = expr.kind {
-            if let Some(expr_ty) = cx.typeck_results().node_type_opt(let_expr.hir_id) {
-                if in_external_macro(cx.sess(), let_pat.span) {
-                    return;
-                }
-                apply_lint(cx, let_pat, expr_ty, DerefPossible::Possible);
-            }
+        if let ExprKind::Let(let_pat, ..) = expr.kind {
+            apply_lint(cx, let_pat, DerefPossible::Possible);
         }
     }
 
@@ -134,12 +115,10 @@ impl<'tcx> LateLintPass<'tcx> for PatternTypeMismatch {
         _: &'tcx FnDecl<'_>,
         body: &'tcx Body<'_>,
         _: Span,
-        hir_id: HirId,
+        _: HirId,
     ) {
-        if let Some(fn_sig) = cx.typeck_results().liberated_fn_sigs().get(hir_id) {
-            for (param, ty) in iter::zip(body.params, fn_sig.inputs()) {
-                apply_lint(cx, param.pat, ty, DerefPossible::Impossible);
-            }
+        for param in body.params {
+            apply_lint(cx, param.pat, DerefPossible::Impossible);
         }
     }
 }
@@ -150,8 +129,8 @@ enum DerefPossible {
     Impossible,
 }
 
-fn apply_lint<'tcx>(cx: &LateContext<'tcx>, pat: &Pat<'_>, expr_ty: Ty<'tcx>, deref_possible: DerefPossible) -> bool {
-    let maybe_mismatch = find_first_mismatch(cx, pat, expr_ty, Level::Top);
+fn apply_lint<'tcx>(cx: &LateContext<'tcx>, pat: &Pat<'_>, deref_possible: DerefPossible) -> bool {
+    let maybe_mismatch = find_first_mismatch(cx, pat);
     if let Some((span, mutability, level)) = maybe_mismatch {
         span_lint_and_help(
             cx,
@@ -184,132 +163,32 @@ enum Level {
 }
 
 #[allow(rustc::usage_of_ty_tykind)]
-fn find_first_mismatch<'tcx>(
-    cx: &LateContext<'tcx>,
-    pat: &Pat<'_>,
-    ty: Ty<'tcx>,
-    level: Level,
-) -> Option<(Span, Mutability, Level)> {
-    if let PatKind::Ref(sub_pat, _) = pat.kind {
-        if let TyKind::Ref(_, sub_ty, _) = ty.kind() {
-            return find_first_mismatch(cx, sub_pat, sub_ty, Level::Lower);
-        }
-    }
-
-    if let TyKind::Ref(_, _, mutability) = *ty.kind() {
-        if is_non_ref_pattern(&pat.kind) {
-            return Some((pat.span, mutability, level));
-        }
-    }
-
-    if let PatKind::Struct(ref qpath, field_pats, _) = pat.kind {
-        if let TyKind::Adt(adt_def, substs_ref) = ty.kind() {
-            if let Some(variant) = get_variant(adt_def, qpath) {
-                let field_defs = &variant.fields;
-                return find_first_mismatch_in_struct(cx, field_pats, field_defs, substs_ref);
-            }
+fn find_first_mismatch<'tcx>(cx: &LateContext<'tcx>, pat: &Pat<'_>) -> Option<(Span, Mutability, Level)> {
+    let mut result = None;
+    pat.walk(|p| {
+        if result.is_some() {
+            return false;
         }
-    }
-
-    if let PatKind::TupleStruct(ref qpath, pats, _) = pat.kind {
-        if let TyKind::Adt(adt_def, substs_ref) = ty.kind() {
-            if let Some(variant) = get_variant(adt_def, qpath) {
-                let field_defs = &variant.fields;
-                let ty_iter = field_defs.iter().map(|field_def| field_def.ty(cx.tcx, substs_ref));
-                return find_first_mismatch_in_tuple(cx, pats, ty_iter);
-            }
-        }
-    }
-
-    if let PatKind::Tuple(pats, _) = pat.kind {
-        if let TyKind::Tuple(..) = ty.kind() {
-            return find_first_mismatch_in_tuple(cx, pats, ty.tuple_fields());
+        if in_external_macro(cx.sess(), p.span) {
+            return true;
         }
-    }
-
-    if let PatKind::Or(sub_pats) = pat.kind {
-        for pat in sub_pats {
-            let maybe_mismatch = find_first_mismatch(cx, pat, ty, level);
-            if let Some(mismatch) = maybe_mismatch {
-                return Some(mismatch);
-            }
-        }
-    }
-
-    None
-}
-
-fn get_variant<'a>(adt_def: &'a AdtDef, qpath: &QPath<'_>) -> Option<&'a VariantDef> {
-    if adt_def.is_struct() {
-        if let Some(variant) = adt_def.variants.iter().next() {
-            return Some(variant);
-        }
-    }
-
-    if adt_def.is_enum() {
-        let pat_ident = last_path_segment(qpath).ident;
-        for variant in &adt_def.variants {
-            if variant.ident == pat_ident {
-                return Some(variant);
-            }
-        }
-    }
-
-    None
-}
-
-fn find_first_mismatch_in_tuple<'tcx, I>(
-    cx: &LateContext<'tcx>,
-    pats: &[Pat<'_>],
-    ty_iter_src: I,
-) -> Option<(Span, Mutability, Level)>
-where
-    I: IntoIterator<Item = Ty<'tcx>>,
-{
-    let mut field_tys = ty_iter_src.into_iter();
-    'fields: for pat in pats {
-        let field_ty = if let Some(ty) = field_tys.next() {
-            ty
-        } else {
-            break 'fields;
+        let adjust_pat = match p.kind {
+            PatKind::Or([p, ..]) => p,
+            _ => p,
         };
-
-        let maybe_mismatch = find_first_mismatch(cx, pat, field_ty, Level::Lower);
-        if let Some(mismatch) = maybe_mismatch {
-            return Some(mismatch);
-        }
-    }
-
-    None
-}
-
-fn find_first_mismatch_in_struct<'tcx>(
-    cx: &LateContext<'tcx>,
-    field_pats: &[PatField<'_>],
-    field_defs: &[FieldDef],
-    substs_ref: SubstsRef<'tcx>,
-) -> Option<(Span, Mutability, Level)> {
-    for field_pat in field_pats {
-        'definitions: for field_def in field_defs {
-            if field_pat.ident == field_def.ident {
-                let field_ty = field_def.ty(cx.tcx, substs_ref);
-                let pat = &field_pat.pat;
-                let maybe_mismatch = find_first_mismatch(cx, pat, field_ty, Level::Lower);
-                if let Some(mismatch) = maybe_mismatch {
-                    return Some(mismatch);
+        if let Some(adjustments) = cx.typeck_results().pat_adjustments().get(adjust_pat.hir_id) {
+            if let [first, ..] = **adjustments {
+                if let ty::Ref(.., mutability) = *first.kind() {
+                    let level = if p.hir_id == pat.hir_id {
+                        Level::Top
+                    } else {
+                        Level::Lower
+                    };
+                    result = Some((p.span, mutability, level));
                 }
-                break 'definitions;
             }
         }
-    }
-
-    None
-}
-
-fn is_non_ref_pattern(pat_kind: &PatKind<'_>) -> bool {
-    match pat_kind {
-        PatKind::Struct(..) | PatKind::Tuple(..) | PatKind::TupleStruct(..) | PatKind::Path(..) => true,
-        PatKind::Or(sub_pats) => sub_pats.iter().any(|pat| is_non_ref_pattern(&pat.kind)),
-        _ => false,
-    }
+        result.is_none()
+    });
+    result
 }
diff --git a/src/tools/clippy/clippy_lints/src/unit_types/let_unit_value.rs b/src/tools/clippy/clippy_lints/src/unit_types/let_unit_value.rs
index fad647dfb26..b25a6e3375b 100644
--- a/src/tools/clippy/clippy_lints/src/unit_types/let_unit_value.rs
+++ b/src/tools/clippy/clippy_lints/src/unit_types/let_unit_value.rs
@@ -1,5 +1,4 @@
 use clippy_utils::diagnostics::span_lint_and_then;
-use clippy_utils::higher;
 use clippy_utils::source::snippet_with_macro_callsite;
 use rustc_errors::Applicability;
 use rustc_hir::{Stmt, StmtKind};
@@ -14,9 +13,6 @@ pub(super) fn check(cx: &LateContext<'_>, stmt: &Stmt<'_>) {
             if in_external_macro(cx.sess(), stmt.span) || local.pat.span.from_expansion() {
                 return;
             }
-            if higher::is_from_for_desugar(local) {
-                return;
-            }
             span_lint_and_then(
                 cx,
                 LET_UNIT_VALUE,
diff --git a/src/tools/clippy/clippy_utils/src/higher.rs b/src/tools/clippy/clippy_utils/src/higher.rs
index 733cc97c845..7297265d08c 100644
--- a/src/tools/clippy/clippy_utils/src/higher.rs
+++ b/src/tools/clippy/clippy_utils/src/higher.rs
@@ -22,31 +22,31 @@ pub struct ForLoop<'tcx> {
     pub arg: &'tcx hir::Expr<'tcx>,
     /// `for` loop body
     pub body: &'tcx hir::Expr<'tcx>,
+    /// Compare this against `hir::Destination.target`
+    pub loop_id: HirId,
     /// entire `for` loop span
     pub span: Span,
 }
 
 impl<'tcx> ForLoop<'tcx> {
-    #[inline]
     /// Parses a desugared `for` loop
     pub fn hir(expr: &Expr<'tcx>) -> Option<Self> {
         if_chain! {
-            if let hir::ExprKind::Match(iterexpr, arms, hir::MatchSource::ForLoopDesugar) = expr.kind;
-            if let Some(first_arm) = arms.get(0);
-            if let hir::ExprKind::Call(_, iterargs) = iterexpr.kind;
-            if let Some(first_arg) = iterargs.get(0);
-            if iterargs.len() == 1 && arms.len() == 1 && first_arm.guard.is_none();
-            if let hir::ExprKind::Loop(block, ..) = first_arm.body.kind;
-            if block.expr.is_none();
-            if let [ _, _, ref let_stmt, ref body ] = *block.stmts;
-            if let hir::StmtKind::Local(local) = let_stmt.kind;
-            if let hir::StmtKind::Expr(body_expr) = body.kind;
+            if let hir::ExprKind::DropTemps(e) = expr.kind;
+            if let hir::ExprKind::Match(iterexpr, [arm], hir::MatchSource::ForLoopDesugar) = e.kind;
+            if let hir::ExprKind::Call(_, [arg]) = iterexpr.kind;
+            if let hir::ExprKind::Loop(block, ..) = arm.body.kind;
+            if let [stmt] = &*block.stmts;
+            if let hir::StmtKind::Expr(e) = stmt.kind;
+            if let hir::ExprKind::Match(_, [_, some_arm], _) = e.kind;
+            if let hir::PatKind::Struct(_, [field], _) = some_arm.pat.kind;
             then {
                 return Some(Self {
-                    pat: &*local.pat,
-                    arg: first_arg,
-                    body: body_expr,
-                    span: first_arm.span
+                    pat: field.pat,
+                    arg,
+                    body: some_arm.body,
+                    loop_id: arm.body.hir_id,
+                    span: expr.span.ctxt().outer_expn_data().call_site,
                 });
             }
         }
@@ -678,38 +678,6 @@ impl<'tcx> FormatArgsArg<'tcx> {
     }
 }
 
-/// Checks if a `let` statement is from a `for` loop desugaring.
-pub fn is_from_for_desugar(local: &hir::Local<'_>) -> bool {
-    // This will detect plain for-loops without an actual variable binding:
-    //
-    // ```
-    // for x in some_vec {
-    //     // do stuff
-    // }
-    // ```
-    if_chain! {
-        if let Some(expr) = local.init;
-        if let hir::ExprKind::Match(_, _, hir::MatchSource::ForLoopDesugar) = expr.kind;
-        then {
-            return true;
-        }
-    }
-
-    // This detects a variable binding in for loop to avoid `let_unit_value`
-    // lint (see issue #1964).
-    //
-    // ```
-    // for _ in vec![()] {
-    //     // anything
-    // }
-    // ```
-    if let hir::LocalSource::ForLoopDesugar = local.source {
-        return true;
-    }
-
-    false
-}
-
 /// A parsed `panic!` expansion
 pub struct PanicExpn<'tcx> {
     /// Span of `panic!(..)`
diff --git a/src/tools/clippy/tests/ui/author/for_loop.stdout b/src/tools/clippy/tests/ui/author/for_loop.stdout
index f1b4d4e096e..4d0e13c833f 100644
--- a/src/tools/clippy/tests/ui/author/for_loop.stdout
+++ b/src/tools/clippy/tests/ui/author/for_loop.stdout
@@ -11,11 +11,8 @@ if_chain! {
     // unimplemented: field checks
     if arms.len() == 1;
     if let ExprKind::Loop(ref body, ref label, LoopSource::ForLoop) = arms[0].body.kind;
-    if body.stmts.len() == 4;
-    if let StmtKind::Local(ref local) = body.stmts[0].kind;
-    if let PatKind::Binding(BindingAnnotation::Mutable, _, name, None) = local.pat.kind;
-    if name.as_str() == "__next";
-    if let StmtKind::Expr(ref e, _) = body.stmts[1].kind
+    if body.stmts.len() == 1;
+    if let StmtKind::Expr(ref e, _) = body.stmts[0].kind
     if let ExprKind::Match(ref expr2, ref arms1, MatchSource::ForLoopDesugar) = e.kind;
     if let ExprKind::Call(ref func1, ref args1) = expr2.kind;
     if let ExprKind::Path(ref path2) = func1.kind;
@@ -25,39 +22,27 @@ if_chain! {
     if let ExprKind::Path(ref path3) = inner.kind;
     if match_qpath(path3, &["iter"]);
     if arms1.len() == 2;
-    if let ExprKind::Assign(ref target, ref value, ref _span) = arms1[0].body.kind;
-    if let ExprKind::Path(ref path4) = target.kind;
-    if match_qpath(path4, &["__next"]);
-    if let ExprKind::Path(ref path5) = value.kind;
-    if match_qpath(path5, &["val"]);
-    if let PatKind::Struct(ref path6, ref fields1, false) = arms1[0].pat.kind;
-    if matches!(path6, QPath::LangItem(LangItem::OptionSome, _));
-    if fields1.len() == 1;
-    // unimplemented: field checks
-    if let ExprKind::Break(ref destination, None) = arms1[1].body.kind;
-    if let PatKind::Struct(ref path7, ref fields2, false) = arms1[1].pat.kind;
-    if matches!(path7, QPath::LangItem(LangItem::OptionNone, _));
-    if fields2.len() == 0;
+    if let ExprKind::Break(ref destination, None) = arms1[0].body.kind;
+    if let PatKind::Struct(ref path4, ref fields1, false) = arms1[0].pat.kind;
+    if matches!(path4, QPath::LangItem(LangItem::OptionNone, _));
+    if fields1.len() == 0;
     // unimplemented: field checks
-    if let StmtKind::Local(ref local1) = body.stmts[2].kind;
-    if let Some(ref init) = local1.init;
-    if let ExprKind::Path(ref path8) = init.kind;
-    if match_qpath(path8, &["__next"]);
-    if let PatKind::Binding(BindingAnnotation::Unannotated, _, name1, None) = local1.pat.kind;
-    if name1.as_str() == "y";
-    if let StmtKind::Expr(ref e1, _) = body.stmts[3].kind
-    if let ExprKind::Block(ref block) = e1.kind;
+    if let ExprKind::Block(ref block) = arms1[1].body.kind;
     if block.stmts.len() == 1;
-    if let StmtKind::Local(ref local2) = block.stmts[0].kind;
-    if let Some(ref init1) = local2.init;
-    if let ExprKind::Path(ref path9) = init1.kind;
-    if match_qpath(path9, &["y"]);
-    if let PatKind::Binding(BindingAnnotation::Unannotated, _, name2, None) = local2.pat.kind;
-    if name2.as_str() == "z";
+    if let StmtKind::Local(ref local) = block.stmts[0].kind;
+    if let Some(ref init) = local.init;
+    if let ExprKind::Path(ref path5) = init.kind;
+    if match_qpath(path5, &["y"]);
+    if let PatKind::Binding(BindingAnnotation::Unannotated, _, name, None) = local.pat.kind;
+    if name.as_str() == "z";
     if block.expr.is_none();
+    if let PatKind::Struct(ref path6, ref fields2, false) = arms1[1].pat.kind;
+    if matches!(path6, QPath::LangItem(LangItem::OptionSome, _));
+    if fields2.len() == 1;
+    // unimplemented: field checks
     if body.expr.is_none();
-    if let PatKind::Binding(BindingAnnotation::Mutable, _, name3, None) = arms[0].pat.kind;
-    if name3.as_str() == "iter";
+    if let PatKind::Binding(BindingAnnotation::Mutable, _, name1, None) = arms[0].pat.kind;
+    if name1.as_str() == "iter";
     then {
         // report your lint here
     }