about summary refs log tree commit diff
path: root/compiler
diff options
context:
space:
mode:
authorCameron Steffen <cam.steffen94@gmail.com>2021-10-25 23:33:12 -0500
committerCameron Steffen <cam.steffen94@gmail.com>2021-11-21 08:15:21 -0600
commit9c83f8c4d1e562cd73a29a00828d68e2b520a086 (patch)
treea7b824c188a775e1de44c0e9c44dffe2d039c78f /compiler
parent3bfde2f1f4fc9409ecb63dfe1370df66171cf861 (diff)
downloadrust-9c83f8c4d1e562cd73a29a00828d68e2b520a086.tar.gz
rust-9c83f8c4d1e562cd73a29a00828d68e2b520a086.zip
Simplify for loop desugar
Diffstat (limited to 'compiler')
-rw-r--r--compiler/rustc_ast_lowering/src/expr.rs137
-rw-r--r--compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs13
-rw-r--r--compiler/rustc_borrowck/src/diagnostics/mod.rs12
-rw-r--r--compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs24
-rw-r--r--compiler/rustc_hir/src/hir.rs2
-rw-r--r--compiler/rustc_hir/src/pat_util.rs11
-rw-r--r--compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs24
-rw-r--r--compiler/rustc_middle/src/lint.rs2
-rw-r--r--compiler/rustc_mir_build/src/thir/pattern/check_match.rs21
-rw-r--r--compiler/rustc_span/src/hygiene.rs11
-rw-r--r--compiler/rustc_span/src/lib.rs2
-rw-r--r--compiler/rustc_span/src/symbol.rs1
-rw-r--r--compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs7
13 files changed, 118 insertions, 149 deletions
diff --git a/compiler/rustc_ast_lowering/src/expr.rs b/compiler/rustc_ast_lowering/src/expr.rs
index 405e9035c4c..a0a63620c08 100644
--- a/compiler/rustc_ast_lowering/src/expr.rs
+++ b/compiler/rustc_ast_lowering/src/expr.rs
@@ -13,7 +13,7 @@ use rustc_session::parse::feature_err;
 use rustc_span::hygiene::ExpnId;
 use rustc_span::source_map::{respan, DesugaringKind, Span, Spanned};
 use rustc_span::symbol::{sym, Ident, Symbol};
-use rustc_span::{hygiene::ForLoopLoc, DUMMY_SP};
+use rustc_span::DUMMY_SP;
 
 impl<'hir> LoweringContext<'_, 'hir> {
     fn lower_exprs(&mut self, exprs: &[AstP<Expr>]) -> &'hir [hir::Expr<'hir>] {
@@ -1308,16 +1308,13 @@ impl<'hir> LoweringContext<'_, 'hir> {
     /// Desugar `ExprForLoop` from: `[opt_ident]: for <pat> in <head> <body>` into:
     /// ```rust
     /// {
-    ///     let result = match ::std::iter::IntoIterator::into_iter(<head>) {
+    ///     let result = match IntoIterator::into_iter(<head>) {
     ///         mut iter => {
     ///             [opt_ident]: loop {
-    ///                 let mut __next;
-    ///                 match ::std::iter::Iterator::next(&mut iter) {
-    ///                     ::std::option::Option::Some(val) => __next = val,
-    ///                     ::std::option::Option::None => break
+    ///                 match Iterator::next(&mut iter) {
+    ///                     None => break,
+    ///                     Some(<pat>) => <body>,
     ///                 };
-    ///                 let <pat> = __next;
-    ///                 StmtKind::Expr(<body>);
     ///             }
     ///         }
     ///     };
@@ -1332,133 +1329,75 @@ impl<'hir> LoweringContext<'_, 'hir> {
         body: &Block,
         opt_label: Option<Label>,
     ) -> hir::Expr<'hir> {
-        // expand <head>
         let head = self.lower_expr_mut(head);
-        let desugared_span =
-            self.mark_span_with_reason(DesugaringKind::ForLoop(ForLoopLoc::Head), head.span, None);
-        let e_span = self.lower_span(e.span);
-
-        let iter = Ident::with_dummy_span(sym::iter);
-
-        let next_ident = Ident::with_dummy_span(sym::__next);
-        let (next_pat, next_pat_hid) = self.pat_ident_binding_mode(
-            desugared_span,
-            next_ident,
-            hir::BindingAnnotation::Mutable,
-        );
-
-        // `::std::option::Option::Some(val) => __next = val`
-        let pat_arm = {
-            let val_ident = Ident::with_dummy_span(sym::val);
-            let pat_span = self.lower_span(pat.span);
-            let (val_pat, val_pat_hid) = self.pat_ident(pat_span, val_ident);
-            let val_expr = self.expr_ident(pat_span, val_ident, val_pat_hid);
-            let next_expr = self.expr_ident(pat_span, next_ident, next_pat_hid);
-            let assign = self.arena.alloc(self.expr(
-                pat_span,
-                hir::ExprKind::Assign(next_expr, val_expr, self.lower_span(pat_span)),
-                ThinVec::new(),
-            ));
-            let some_pat = self.pat_some(pat_span, val_pat);
-            self.arm(some_pat, assign)
-        };
+        let pat = self.lower_pat(pat);
+        let for_span =
+            self.mark_span_with_reason(DesugaringKind::ForLoop, self.lower_span(e.span), None);
+        let head_span = self.mark_span_with_reason(DesugaringKind::ForLoop, head.span, None);
+        let pat_span = self.mark_span_with_reason(DesugaringKind::ForLoop, pat.span, None);
 
-        // `::std::option::Option::None => break`
-        let break_arm = {
+        // `None => break`
+        let none_arm = {
             let break_expr =
-                self.with_loop_scope(e.id, |this| this.expr_break_alloc(e_span, ThinVec::new()));
-            let pat = self.pat_none(e_span);
+                self.with_loop_scope(e.id, |this| this.expr_break_alloc(for_span, ThinVec::new()));
+            let pat = self.pat_none(for_span);
             self.arm(pat, break_expr)
         };
 
+        // Some(<pat>) => <body>,
+        let some_arm = {
+            let some_pat = self.pat_some(pat_span, pat);
+            let body_block = self.with_loop_scope(e.id, |this| this.lower_block(body, false));
+            let body_expr = self.arena.alloc(self.expr_block(body_block, ThinVec::new()));
+            self.arm(some_pat, body_expr)
+        };
+
         // `mut iter`
+        let iter = Ident::with_dummy_span(sym::iter);
         let (iter_pat, iter_pat_nid) =
-            self.pat_ident_binding_mode(desugared_span, iter, hir::BindingAnnotation::Mutable);
+            self.pat_ident_binding_mode(head_span, iter, hir::BindingAnnotation::Mutable);
 
-        // `match ::std::iter::Iterator::next(&mut iter) { ... }`
+        // `match Iterator::next(&mut iter) { ... }`
         let match_expr = {
-            let iter = self.expr_ident(desugared_span, iter, iter_pat_nid);
-            let ref_mut_iter = self.expr_mut_addr_of(desugared_span, iter);
+            let iter = self.expr_ident(head_span, iter, iter_pat_nid);
+            let ref_mut_iter = self.expr_mut_addr_of(head_span, iter);
             let next_expr = self.expr_call_lang_item_fn(
-                desugared_span,
+                head_span,
                 hir::LangItem::IteratorNext,
                 arena_vec![self; ref_mut_iter],
             );
-            let arms = arena_vec![self; pat_arm, break_arm];
+            let arms = arena_vec![self; none_arm, some_arm];
 
-            self.expr_match(desugared_span, next_expr, arms, hir::MatchSource::ForLoopDesugar)
+            self.expr_match(head_span, next_expr, arms, hir::MatchSource::ForLoopDesugar)
         };
-        let match_stmt = self.stmt_expr(desugared_span, match_expr);
-
-        let next_expr = self.expr_ident(desugared_span, next_ident, next_pat_hid);
-
-        // `let mut __next`
-        let next_let = self.stmt_let_pat(
-            None,
-            desugared_span,
-            None,
-            next_pat,
-            hir::LocalSource::ForLoopDesugar,
-        );
+        let match_stmt = self.stmt_expr(for_span, match_expr);
 
-        // `let <pat> = __next`
-        let pat = self.lower_pat(pat);
-        let pat_let = self.stmt_let_pat(
-            None,
-            desugared_span,
-            Some(next_expr),
-            pat,
-            hir::LocalSource::ForLoopDesugar,
-        );
-
-        let body_block = self.with_loop_scope(e.id, |this| this.lower_block(body, false));
-        let body_expr = self.expr_block(body_block, ThinVec::new());
-        let body_stmt = self.stmt_expr(body_block.span, body_expr);
-
-        let loop_block = self.block_all(
-            e_span,
-            arena_vec![self; next_let, match_stmt, pat_let, body_stmt],
-            None,
-        );
+        let loop_block = self.block_all(for_span, arena_vec![self; match_stmt], None);
 
         // `[opt_ident]: loop { ... }`
         let kind = hir::ExprKind::Loop(
             loop_block,
             self.lower_label(opt_label),
             hir::LoopSource::ForLoop,
-            self.lower_span(e_span.with_hi(head.span.hi())),
+            self.lower_span(for_span.with_hi(head.span.hi())),
         );
-        let loop_expr = self.arena.alloc(hir::Expr {
-            hir_id: self.lower_node_id(e.id),
-            kind,
-            span: self.lower_span(e.span),
-        });
+        let loop_expr =
+            self.arena.alloc(hir::Expr { hir_id: self.lower_node_id(e.id), kind, span: for_span });
 
         // `mut iter => { ... }`
         let iter_arm = self.arm(iter_pat, loop_expr);
 
-        let into_iter_span = self.mark_span_with_reason(
-            DesugaringKind::ForLoop(ForLoopLoc::IntoIter),
-            head.span,
-            None,
-        );
-
         // `match ::std::iter::IntoIterator::into_iter(<head>) { ... }`
         let into_iter_expr = {
             self.expr_call_lang_item_fn(
-                into_iter_span,
+                head_span,
                 hir::LangItem::IntoIterIntoIter,
                 arena_vec![self; head],
             )
         };
 
-        // #82462: to correctly diagnose borrow errors, the block that contains
-        // the iter expr needs to have a span that covers the loop body.
-        let desugared_full_span =
-            self.mark_span_with_reason(DesugaringKind::ForLoop(ForLoopLoc::Head), e_span, None);
-
         let match_expr = self.arena.alloc(self.expr_match(
-            desugared_full_span,
+            for_span,
             into_iter_expr,
             arena_vec![self; iter_arm],
             hir::MatchSource::ForLoopDesugar,
@@ -1472,7 +1411,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
         // surrounding scope of the `match` since the `match` is not a terminating scope.
         //
         // Also, add the attributes to the outer returned expr node.
-        self.expr_drop_temps_mut(desugared_full_span, match_expr, attrs.into())
+        self.expr_drop_temps_mut(for_span, match_expr, attrs.into())
     }
 
     /// Desugar `ExprKind::Try` from: `<expr>?` into:
diff --git a/compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs b/compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs
index 79973ab170c..db8268c8e2e 100644
--- a/compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs
@@ -13,7 +13,7 @@ use rustc_middle::mir::{
 use rustc_middle::ty::adjustment::PointerCast;
 use rustc_middle::ty::{self, RegionVid, TyCtxt};
 use rustc_span::symbol::Symbol;
-use rustc_span::Span;
+use rustc_span::{sym, DesugaringKind, Span};
 
 use crate::region_infer::BlameConstraint;
 use crate::{
@@ -135,7 +135,16 @@ impl BorrowExplanation {
                 should_note_order,
             } => {
                 let local_decl = &body.local_decls[dropped_local];
-                let (dtor_desc, type_desc) = match local_decl.ty.kind() {
+                let mut ty = local_decl.ty;
+                if local_decl.source_info.span.desugaring_kind() == Some(DesugaringKind::ForLoop) {
+                    if let ty::Adt(adt, substs) = local_decl.ty.kind() {
+                        if tcx.is_diagnostic_item(sym::Option, adt.did) {
+                            // in for loop desugaring, only look at the `Some(..)` inner type
+                            ty = substs.type_at(0);
+                        }
+                    }
+                }
+                let (dtor_desc, type_desc) = match ty.kind() {
                     // If type is an ADT that implements Drop, then
                     // simplify output by reporting just the ADT name.
                     ty::Adt(adt, _substs) if adt.has_dtor(tcx) && !adt.is_box() => {
diff --git a/compiler/rustc_borrowck/src/diagnostics/mod.rs b/compiler/rustc_borrowck/src/diagnostics/mod.rs
index a4df277a7b0..79623e26eb7 100644
--- a/compiler/rustc_borrowck/src/diagnostics/mod.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/mod.rs
@@ -13,11 +13,7 @@ use rustc_middle::mir::{
 use rustc_middle::ty::print::Print;
 use rustc_middle::ty::{self, DefIdTree, Instance, Ty, TyCtxt};
 use rustc_mir_dataflow::move_paths::{InitLocation, LookupResult};
-use rustc_span::{
-    hygiene::{DesugaringKind, ForLoopLoc},
-    symbol::sym,
-    Span,
-};
+use rustc_span::{hygiene::DesugaringKind, symbol::sym, Span};
 use rustc_target::abi::VariantIdx;
 
 use super::borrow_set::BorrowData;
@@ -955,10 +951,8 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
             let kind = kind.unwrap_or_else(|| {
                 // This isn't a 'special' use of `self`
                 debug!("move_spans: method_did={:?}, fn_call_span={:?}", method_did, fn_call_span);
-                let implicit_into_iter = matches!(
-                    fn_call_span.desugaring_kind(),
-                    Some(DesugaringKind::ForLoop(ForLoopLoc::IntoIter))
-                );
+                let implicit_into_iter = Some(method_did) == tcx.lang_items().into_iter_fn()
+                    && fn_call_span.desugaring_kind() == Some(DesugaringKind::ForLoop);
                 let parent_self_ty = parent
                     .filter(|did| tcx.def_kind(*did) == rustc_hir::def::DefKind::Impl)
                     .and_then(|did| match tcx.type_of(did).kind() {
diff --git a/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs b/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs
index d5ff4c6766f..46e2a99a0d0 100644
--- a/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs
@@ -445,15 +445,23 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
                                 },
                             ))) => {
                                 // check if the RHS is from desugaring
-                                let locations = self.body.find_assignments(local);
-                                let opt_assignment_rhs_span = locations
-                                    .first()
-                                    .map(|&location| self.body.source_info(location).span);
-                                let opt_desugaring_kind =
-                                    opt_assignment_rhs_span.and_then(|span| span.desugaring_kind());
-                                match opt_desugaring_kind {
+                                let opt_assignment_rhs_span =
+                                    self.body.find_assignments(local).first().map(|&location| {
+                                        let stmt = &self.body[location.block].statements
+                                            [location.statement_index];
+                                        match stmt.kind {
+                                            mir::StatementKind::Assign(box (
+                                                _,
+                                                mir::Rvalue::Use(mir::Operand::Copy(place)),
+                                            )) => {
+                                                self.body.local_decls[place.local].source_info.span
+                                            }
+                                            _ => self.body.source_info(location).span,
+                                        }
+                                    });
+                                match opt_assignment_rhs_span.and_then(|s| s.desugaring_kind()) {
                                     // on for loops, RHS points to the iterator part
-                                    Some(DesugaringKind::ForLoop(_)) => {
+                                    Some(DesugaringKind::ForLoop) => {
                                         self.suggest_similar_mut_method_for_for_loop(&mut err);
                                         Some((
                                             false,
diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs
index a4db57bfc11..c67d3df3ded 100644
--- a/compiler/rustc_hir/src/hir.rs
+++ b/compiler/rustc_hir/src/hir.rs
@@ -1821,8 +1821,6 @@ impl<'hir> QPath<'hir> {
 pub enum LocalSource {
     /// A `match _ { .. }`.
     Normal,
-    /// A desugared `for _ in _ { .. }` loop.
-    ForLoopDesugar,
     /// When lowering async functions, we create locals within the `async move` so that
     /// all parameters are dropped after the future is polled.
     ///
diff --git a/compiler/rustc_hir/src/pat_util.rs b/compiler/rustc_hir/src/pat_util.rs
index b1f78a83e74..b30076100bb 100644
--- a/compiler/rustc_hir/src/pat_util.rs
+++ b/compiler/rustc_hir/src/pat_util.rs
@@ -2,6 +2,7 @@ use crate::def::{CtorOf, DefKind, Res};
 use crate::def_id::DefId;
 use crate::hir::{self, HirId, PatKind};
 use rustc_data_structures::stable_set::FxHashSet;
+use rustc_span::hygiene::DesugaringKind;
 use rustc_span::symbol::Ident;
 use rustc_span::Span;
 
@@ -143,4 +144,14 @@ impl hir::Pat<'_> {
         });
         result
     }
+
+    /// If the pattern is `Some(<pat>)` from a desugared for loop, returns the inner pattern
+    pub fn for_loop_some(&self) -> Option<&Self> {
+        if self.span.desugaring_kind() == Some(DesugaringKind::ForLoop) {
+            if let hir::PatKind::Struct(_, [pat_field], _) = self.kind {
+                return Some(pat_field.pat);
+            }
+        }
+        None
+    }
 }
diff --git a/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs b/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs
index e00003face9..a7e019a53ee 100644
--- a/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs
+++ b/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs
@@ -5,13 +5,12 @@ use rustc_hir as hir;
 use rustc_hir::def::{DefKind, Namespace};
 use rustc_hir::def_id::DefId;
 use rustc_hir::intravisit::{self, NestedVisitorMap, Visitor};
-use rustc_hir::{Body, Expr, ExprKind, FnRetTy, HirId, Local, Pat};
+use rustc_hir::{Body, Expr, ExprKind, FnRetTy, HirId, Local, MatchSource, Pat};
 use rustc_middle::hir::map::Map;
 use rustc_middle::infer::unify_key::ConstVariableOriginKind;
 use rustc_middle::ty::print::Print;
 use rustc_middle::ty::subst::{GenericArg, GenericArgKind};
 use rustc_middle::ty::{self, DefIdTree, InferConst, Ty, TyCtxt};
-use rustc_span::source_map::DesugaringKind;
 use rustc_span::symbol::kw;
 use rustc_span::Span;
 use std::borrow::Cow;
@@ -26,6 +25,7 @@ struct FindHirNodeVisitor<'a, 'tcx> {
     found_closure: Option<&'tcx Expr<'tcx>>,
     found_method_call: Option<&'tcx Expr<'tcx>>,
     found_exact_method_call: Option<&'tcx Expr<'tcx>>,
+    found_for_loop_iter: Option<&'tcx Expr<'tcx>>,
     found_use_diagnostic: Option<UseDiagnostic<'tcx>>,
 }
 
@@ -41,6 +41,7 @@ impl<'a, 'tcx> FindHirNodeVisitor<'a, 'tcx> {
             found_closure: None,
             found_method_call: None,
             found_exact_method_call: None,
+            found_for_loop_iter: None,
             found_use_diagnostic: None,
         }
     }
@@ -111,6 +112,15 @@ impl<'a, 'tcx> Visitor<'tcx> for FindHirNodeVisitor<'a, 'tcx> {
     }
 
     fn visit_expr(&mut self, expr: &'tcx Expr<'tcx>) {
+        if let ExprKind::Match(scrutinee, [_, arm], MatchSource::ForLoopDesugar) = expr.kind {
+            if let Some(pat) = arm.pat.for_loop_some() {
+                if let Some(ty) = self.node_ty_contains_target(pat.hir_id) {
+                    self.found_for_loop_iter = Some(scrutinee);
+                    self.found_node_ty = Some(ty);
+                    return;
+                }
+            }
+        }
         if let ExprKind::MethodCall(_, call_span, exprs, _) = expr.kind {
             if call_span == self.target_span
                 && Some(self.target)
@@ -643,10 +653,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
             let msg = if let Some(simple_ident) = pattern.simple_ident() {
                 match pattern.span.desugaring_kind() {
                     None => format!("consider giving `{}` {}", simple_ident, suffix),
-                    Some(DesugaringKind::ForLoop(_)) => {
-                        "the element type for this iterator is not specified".to_string()
-                    }
-                    _ => format!("this needs {}", suffix),
+                    Some(_) => format!("this needs {}", suffix),
                 }
             } else {
                 format!("consider giving this pattern {}", suffix)
@@ -719,6 +726,11 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
                 //    = note: type must be known at this point
                 self.annotate_method_call(segment, e, &mut err);
             }
+        } else if let Some(scrutinee) = local_visitor.found_for_loop_iter {
+            err.span_label(
+                scrutinee.span,
+                "the element type for this iterator is not specified".to_string(),
+            );
         }
         // Instead of the following:
         // error[E0282]: type annotations needed
diff --git a/compiler/rustc_middle/src/lint.rs b/compiler/rustc_middle/src/lint.rs
index 0e70d49ef49..881b14278e9 100644
--- a/compiler/rustc_middle/src/lint.rs
+++ b/compiler/rustc_middle/src/lint.rs
@@ -395,7 +395,7 @@ pub fn in_external_macro(sess: &Session, span: Span) -> bool {
     match expn_data.kind {
         ExpnKind::Inlined
         | ExpnKind::Root
-        | ExpnKind::Desugaring(DesugaringKind::ForLoop(_) | DesugaringKind::WhileLoop) => false,
+        | ExpnKind::Desugaring(DesugaringKind::ForLoop | DesugaringKind::WhileLoop) => false,
         ExpnKind::AstPass(_) | ExpnKind::Desugaring(_) => true, // well, it's "external"
         ExpnKind::Macro(MacroKind::Bang, _) => {
             // Dummy span for the `def_site` means it's an external macro.
diff --git a/compiler/rustc_mir_build/src/thir/pattern/check_match.rs b/compiler/rustc_mir_build/src/thir/pattern/check_match.rs
index e28fd2c5081..d74c53fae53 100644
--- a/compiler/rustc_mir_build/src/thir/pattern/check_match.rs
+++ b/compiler/rustc_mir_build/src/thir/pattern/check_match.rs
@@ -74,19 +74,16 @@ impl<'tcx> Visitor<'tcx> for MatchVisitor<'_, '_, 'tcx> {
 
         let (msg, sp) = match loc.source {
             hir::LocalSource::Normal => ("local binding", Some(loc.span)),
-            hir::LocalSource::ForLoopDesugar => ("`for` loop binding", None),
             hir::LocalSource::AsyncFn => ("async fn binding", None),
             hir::LocalSource::AwaitDesugar => ("`await` future binding", None),
             hir::LocalSource::AssignDesugar(_) => ("destructuring assignment binding", None),
         };
         self.check_irrefutable(&loc.pat, msg, sp);
-        self.check_patterns(&loc.pat, Irrefutable);
     }
 
     fn visit_param(&mut self, param: &'tcx hir::Param<'tcx>) {
         intravisit::walk_param(self, param);
         self.check_irrefutable(&param.pat, "function argument", None);
-        self.check_patterns(&param.pat, Irrefutable);
     }
 }
 
@@ -161,12 +158,12 @@ impl<'p, 'tcx> MatchVisitor<'_, 'p, 'tcx> {
     fn check_match(
         &mut self,
         scrut: &hir::Expr<'_>,
-        arms: &'tcx [hir::Arm<'tcx>],
+        hir_arms: &'tcx [hir::Arm<'tcx>],
         source: hir::MatchSource,
     ) {
         let mut cx = self.new_cx(scrut.hir_id);
 
-        for arm in arms {
+        for arm in hir_arms {
             // Check the arm for some things unrelated to exhaustiveness.
             self.check_patterns(&arm.pat, Refutable);
             if let Some(hir::Guard::IfLet(ref pat, _)) = arm.guard {
@@ -178,7 +175,7 @@ impl<'p, 'tcx> MatchVisitor<'_, 'p, 'tcx> {
 
         let mut have_errors = false;
 
-        let arms: Vec<_> = arms
+        let arms: Vec<_> = hir_arms
             .iter()
             .map(|hir::Arm { pat, guard, .. }| MatchArm {
                 pat: self.lower_pattern(&mut cx, pat, &mut have_errors),
@@ -196,6 +193,9 @@ impl<'p, 'tcx> MatchVisitor<'_, 'p, 'tcx> {
         let report = compute_match_usefulness(&cx, &arms, scrut.hir_id, scrut_ty);
 
         match source {
+            // Don't report arm reachability of desugared `match $iter.into_iter() { iter => .. }`
+            // when the iterator is an uninhabited type. unreachable_code will trigger instead.
+            hir::MatchSource::ForLoopDesugar if arms.len() == 1 => {}
             hir::MatchSource::ForLoopDesugar | hir::MatchSource::Normal => {
                 report_arm_reachability(&cx, &report)
             }
@@ -208,7 +208,13 @@ impl<'p, 'tcx> MatchVisitor<'_, 'p, 'tcx> {
         let is_empty_match = arms.is_empty();
         let witnesses = report.non_exhaustiveness_witnesses;
         if !witnesses.is_empty() {
-            non_exhaustive_match(&cx, scrut_ty, scrut.span, witnesses, is_empty_match);
+            if source == hir::MatchSource::ForLoopDesugar && hir_arms.len() == 2 {
+                // the for loop pattern is not irrefutable
+                let pat = hir_arms[1].pat.for_loop_some().unwrap();
+                self.check_irrefutable(pat, "`for` loop binding", None);
+            } else {
+                non_exhaustive_match(&cx, scrut_ty, scrut.span, witnesses, is_empty_match);
+            }
         }
     }
 
@@ -225,6 +231,7 @@ impl<'p, 'tcx> MatchVisitor<'_, 'p, 'tcx> {
         let witnesses = report.non_exhaustiveness_witnesses;
         if witnesses.is_empty() {
             // The pattern is irrefutable.
+            self.check_patterns(pat, Irrefutable);
             return;
         }
 
diff --git a/compiler/rustc_span/src/hygiene.rs b/compiler/rustc_span/src/hygiene.rs
index 724d1904dc3..d590776676b 100644
--- a/compiler/rustc_span/src/hygiene.rs
+++ b/compiler/rustc_span/src/hygiene.rs
@@ -1099,18 +1099,11 @@ pub enum DesugaringKind {
     OpaqueTy,
     Async,
     Await,
-    ForLoop(ForLoopLoc),
+    ForLoop,
     LetElse,
     WhileLoop,
 }
 
-/// A location in the desugaring of a `for` loop
-#[derive(Clone, Copy, PartialEq, Debug, Encodable, Decodable, HashStable_Generic)]
-pub enum ForLoopLoc {
-    Head,
-    IntoIter,
-}
-
 impl DesugaringKind {
     /// The description wording should combine well with "desugaring of {}".
     pub fn descr(self) -> &'static str {
@@ -1121,7 +1114,7 @@ impl DesugaringKind {
             DesugaringKind::QuestionMark => "operator `?`",
             DesugaringKind::TryBlock => "`try` block",
             DesugaringKind::OpaqueTy => "`impl Trait`",
-            DesugaringKind::ForLoop(_) => "`for` loop",
+            DesugaringKind::ForLoop => "`for` loop",
             DesugaringKind::LetElse => "`let...else`",
             DesugaringKind::WhileLoop => "`while` loop",
         }
diff --git a/compiler/rustc_span/src/lib.rs b/compiler/rustc_span/src/lib.rs
index 1445c59710c..66c01140abc 100644
--- a/compiler/rustc_span/src/lib.rs
+++ b/compiler/rustc_span/src/lib.rs
@@ -41,7 +41,7 @@ pub mod edition;
 use edition::Edition;
 pub mod hygiene;
 use hygiene::Transparency;
-pub use hygiene::{DesugaringKind, ExpnKind, ForLoopLoc, MacroKind};
+pub use hygiene::{DesugaringKind, ExpnKind, MacroKind};
 pub use hygiene::{ExpnData, ExpnHash, ExpnId, LocalExpnId, SyntaxContext};
 pub mod def_id;
 use def_id::{CrateNum, DefId, DefPathHash, LocalDefId, LOCAL_CRATE};
diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs
index 9992b1f31fe..0d556b5eda6 100644
--- a/compiler/rustc_span/src/symbol.rs
+++ b/compiler/rustc_span/src/symbol.rs
@@ -269,7 +269,6 @@ symbols! {
         __D,
         __H,
         __S,
-        __next,
         __try_var,
         _args,
         _d,
diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs
index d5c7cf71116..a90140a9b50 100644
--- a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs
+++ b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs
@@ -27,7 +27,7 @@ use rustc_middle::ty::{TypeAndMut, TypeckResults};
 use rustc_session::Limit;
 use rustc_span::def_id::LOCAL_CRATE;
 use rustc_span::symbol::{kw, sym, Ident, Symbol};
-use rustc_span::{BytePos, DesugaringKind, ExpnKind, ForLoopLoc, MultiSpan, Span, DUMMY_SP};
+use rustc_span::{BytePos, DesugaringKind, ExpnKind, MultiSpan, Span, DUMMY_SP};
 use rustc_target::spec::abi;
 use std::fmt;
 
@@ -685,7 +685,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
             &obligation.cause.code
         {
             parent_code.clone()
-        } else if let ExpnKind::Desugaring(DesugaringKind::ForLoop(ForLoopLoc::IntoIter)) =
+        } else if let ExpnKind::Desugaring(DesugaringKind::ForLoop) =
             span.ctxt().outer_expn_data().kind
         {
             Lrc::new(obligation.cause.code.clone())
@@ -765,8 +765,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
                     // This if is to prevent a special edge-case
                     if matches!(
                         span.ctxt().outer_expn_data().kind,
-                        ExpnKind::Root
-                            | ExpnKind::Desugaring(DesugaringKind::ForLoop(ForLoopLoc::IntoIter))
+                        ExpnKind::Root | ExpnKind::Desugaring(DesugaringKind::ForLoop)
                     ) {
                         // We don't want a borrowing suggestion on the fields in structs,
                         // ```