From 46db4bab0b44294a6e41eb756587904f8bed6049 Mon Sep 17 00:00:00 2001
From: Aaron Hill <aa1ronham@gmail.com>
Date: Tue, 23 Feb 2021 09:44:01 -0500
Subject: [PATCH] Skip emitting closure diagnostic when closure_kind_origins
 has no entry

Fixes #82438

This map is not guarnateed to have an entry for a closure.
---
 .../diagnostics/mutability_errors.rs          | 51 ++++++++++---------
 .../closures/issue-82438-mut-without-upvar.rs | 28 ++++++++++
 .../issue-82438-mut-without-upvar.stderr      | 12 +++++
 3 files changed, 66 insertions(+), 25 deletions(-)
 create mode 100644 src/test/ui/closures/issue-82438-mut-without-upvar.rs
 create mode 100644 src/test/ui/closures/issue-82438-mut-without-upvar.stderr

diff --git a/compiler/rustc_mir/src/borrow_check/diagnostics/mutability_errors.rs b/compiler/rustc_mir/src/borrow_check/diagnostics/mutability_errors.rs
index 0400431a542ee..2f40a90fb5516 100644
--- a/compiler/rustc_mir/src/borrow_check/diagnostics/mutability_errors.rs
+++ b/compiler/rustc_mir/src/borrow_check/diagnostics/mutability_errors.rs
@@ -513,32 +513,33 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
         let id = id.expect_local();
         let tables = tcx.typeck(id);
         let hir_id = tcx.hir().local_def_id_to_hir_id(id);
-        let (span, place) = &tables.closure_kind_origins()[hir_id];
-        let reason = if let PlaceBase::Upvar(upvar_id) = place.base {
-            let upvar = ty::place_to_string_for_capture(tcx, place);
-            match tables.upvar_capture(upvar_id) {
-                ty::UpvarCapture::ByRef(ty::UpvarBorrow {
-                    kind: ty::BorrowKind::MutBorrow | ty::BorrowKind::UniqueImmBorrow,
-                    ..
-                }) => {
-                    format!("mutable borrow of `{}`", upvar)
-                }
-                ty::UpvarCapture::ByValue(_) => {
-                    format!("possible mutation of `{}`", upvar)
+        if let Some((span, place)) = tables.closure_kind_origins().get(hir_id) {
+            let reason = if let PlaceBase::Upvar(upvar_id) = place.base {
+                let upvar = ty::place_to_string_for_capture(tcx, place);
+                match tables.upvar_capture(upvar_id) {
+                    ty::UpvarCapture::ByRef(ty::UpvarBorrow {
+                        kind: ty::BorrowKind::MutBorrow | ty::BorrowKind::UniqueImmBorrow,
+                        ..
+                    }) => {
+                        format!("mutable borrow of `{}`", upvar)
+                    }
+                    ty::UpvarCapture::ByValue(_) => {
+                        format!("possible mutation of `{}`", upvar)
+                    }
+                    val => bug!("upvar `{}` borrowed, but not mutably: {:?}", upvar, val),
                 }
-                val => bug!("upvar `{}` borrowed, but not mutably: {:?}", upvar, val),
-            }
-        } else {
-            bug!("not an upvar")
-        };
-        err.span_label(
-            *span,
-            format!(
-                "calling `{}` requires mutable binding due to {}",
-                self.describe_place(the_place_err).unwrap(),
-                reason
-            ),
-        );
+            } else {
+                bug!("not an upvar")
+            };
+            err.span_label(
+                *span,
+                format!(
+                    "calling `{}` requires mutable binding due to {}",
+                    self.describe_place(the_place_err).unwrap(),
+                    reason
+                ),
+            );
+        }
     }
 
     // Attempt to search similar mutable associated items for suggestion.
diff --git a/src/test/ui/closures/issue-82438-mut-without-upvar.rs b/src/test/ui/closures/issue-82438-mut-without-upvar.rs
new file mode 100644
index 0000000000000..5d88e1e77d450
--- /dev/null
+++ b/src/test/ui/closures/issue-82438-mut-without-upvar.rs
@@ -0,0 +1,28 @@
+use std::error::Error;
+struct A {
+}
+
+impl A {
+    pub fn new() -> A {
+        A {
+        }
+    }
+
+    pub fn f<'a>(
+        &'a self,
+        team_name: &'a str,
+        c: &'a mut dyn FnMut(String, String, u64, u64)
+    ) -> Result<(), Box<dyn Error>> {
+        Ok(())
+    }
+}
+
+
+fn main() {
+    let A = A::new();
+    let participant_name = "A";
+
+    let c = |a, b, c, d| {};
+
+    A.f(participant_name, &mut c); //~ ERROR cannot borrow
+}
diff --git a/src/test/ui/closures/issue-82438-mut-without-upvar.stderr b/src/test/ui/closures/issue-82438-mut-without-upvar.stderr
new file mode 100644
index 0000000000000..06e2b5d0c1bce
--- /dev/null
+++ b/src/test/ui/closures/issue-82438-mut-without-upvar.stderr
@@ -0,0 +1,12 @@
+error[E0596]: cannot borrow `c` as mutable, as it is not declared as mutable
+  --> $DIR/issue-82438-mut-without-upvar.rs:27:27
+   |
+LL |     let c = |a, b, c, d| {};
+   |         - help: consider changing this to be mutable: `mut c`
+LL | 
+LL |     A.f(participant_name, &mut c);
+   |                           ^^^^^^ cannot borrow as mutable
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0596`.