Skip to content

Commit

Permalink
Rollup merge of rust-lang#82442 - Aaron1011:fix/closure-mut-crash, r=…
Browse files Browse the repository at this point in the history
…matthewjasper

Skip emitting closure diagnostic when closure_kind_origins has no entry

Fixes rust-lang#82438

This map is not guarnateed to have an entry for a closure.
  • Loading branch information
Dylan-DPC authored Feb 27, 2021
2 parents d80033f + 46db4ba commit 5c7b383
Show file tree
Hide file tree
Showing 3 changed files with 66 additions and 25 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
28 changes: 28 additions & 0 deletions src/test/ui/closures/issue-82438-mut-without-upvar.rs
Original file line number Diff line number Diff line change
@@ -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
}
12 changes: 12 additions & 0 deletions src/test/ui/closures/issue-82438-mut-without-upvar.stderr
Original file line number Diff line number Diff line change
@@ -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`.

0 comments on commit 5c7b383

Please sign in to comment.