Skip to content

Commit 26b4baf

Browse files
Point to span of upvar making closure FnMut
Add expected error Add comment Tweak comment wording Fix after rebase to updated master Fix after rebase to updated master Distinguish mutation in normal and move closures Tweak error message Fix error message for nested closures Refactor code showing mutated upvar in closure Remove debug assert B
1 parent 66eb982 commit 26b4baf

13 files changed

+152
-4
lines changed

compiler/rustc_mir/src/borrow_check/diagnostics/mutability_errors.rs

+55-1
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,12 @@
11
use rustc_hir as hir;
22
use rustc_hir::Node;
33
use rustc_index::vec::Idx;
4-
use rustc_middle::mir::{self, ClearCrossCrate, Local, LocalDecl, LocalInfo, Location};
54
use rustc_middle::mir::{Mutability, Place, PlaceRef, ProjectionElem};
65
use rustc_middle::ty::{self, Ty, TyCtxt};
6+
use rustc_middle::{
7+
hir::place::PlaceBase,
8+
mir::{self, ClearCrossCrate, Local, LocalDecl, LocalInfo, Location},
9+
};
710
use rustc_span::source_map::DesugaringKind;
811
use rustc_span::symbol::{kw, Symbol};
912
use rustc_span::Span;
@@ -241,6 +244,10 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
241244
format!("mut {}", self.local_names[local].unwrap()),
242245
Applicability::MachineApplicable,
243246
);
247+
let tcx = self.infcx.tcx;
248+
if let ty::Closure(id, _) = the_place_err.ty(self.body, tcx).ty.kind() {
249+
self.show_mutating_upvar(tcx, id, the_place_err, &mut err);
250+
}
244251
}
245252

246253
// Also suggest adding mut for upvars
@@ -271,6 +278,14 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
271278
);
272279
}
273280
}
281+
282+
let tcx = self.infcx.tcx;
283+
if let ty::Ref(_, ty, Mutability::Mut) = the_place_err.ty(self.body, tcx).ty.kind()
284+
{
285+
if let ty::Closure(id, _) = ty.kind() {
286+
self.show_mutating_upvar(tcx, id, the_place_err, &mut err);
287+
}
288+
}
274289
}
275290

276291
// complete hack to approximate old AST-borrowck
@@ -463,6 +478,45 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
463478
err.buffer(&mut self.errors_buffer);
464479
}
465480

481+
// point to span of upvar making closure call require mutable borrow
482+
fn show_mutating_upvar(
483+
&self,
484+
tcx: TyCtxt<'_>,
485+
id: &hir::def_id::DefId,
486+
the_place_err: PlaceRef<'tcx>,
487+
err: &mut DiagnosticBuilder<'_>,
488+
) {
489+
let id = id.expect_local();
490+
let tables = tcx.typeck(id);
491+
let hir_id = tcx.hir().local_def_id_to_hir_id(id);
492+
let (span, place) = &tables.closure_kind_origins()[hir_id];
493+
let reason = if let PlaceBase::Upvar(upvar_id) = place.base {
494+
let upvar = ty::place_to_string_for_capture(tcx, place);
495+
match tables.upvar_capture(upvar_id) {
496+
ty::UpvarCapture::ByRef(ty::UpvarBorrow {
497+
kind: ty::BorrowKind::MutBorrow,
498+
..
499+
}) => {
500+
format!("mutable borrow of `{}`", upvar)
501+
}
502+
ty::UpvarCapture::ByValue(_) => {
503+
format!("possible mutation of `{}`", upvar)
504+
}
505+
_ => bug!("upvar `{}` borrowed, but not mutably", upvar),
506+
}
507+
} else {
508+
bug!("not an upvar")
509+
};
510+
err.span_label(
511+
*span,
512+
format!(
513+
"calling `{}` requires mutable binding due to {}",
514+
self.describe_place(the_place_err).unwrap(),
515+
reason
516+
),
517+
);
518+
}
519+
466520
/// Targeted error when encountering an `FnMut` closure where an `Fn` closure was expected.
467521
fn expected_fn_found_fn_mut_call(&self, err: &mut DiagnosticBuilder<'_>, sp: Span, act: &str) {
468522
err.span_label(sp, format!("cannot {}", act));

src/test/ui/borrowck/borrow-raw-address-of-mutability.stderr

+3-1
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,9 @@ error[E0596]: cannot borrow `f` as mutable, as it is not declared as mutable
2020
|
2121
LL | let f = || {
2222
| - help: consider changing this to be mutable: `mut f`
23-
...
23+
LL | let y = &raw mut x;
24+
| - calling `f` requires mutable binding due to mutable borrow of `x`
25+
LL | };
2426
LL | f();
2527
| ^ cannot borrow as mutable
2628

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
fn main() {
2+
let mut my_var = false;
3+
let callback = || {
4+
&mut my_var;
5+
};
6+
callback(); //~ ERROR E0596
7+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
error[E0596]: cannot borrow `callback` as mutable, as it is not declared as mutable
2+
--> $DIR/issue-80313-mutable-borrow-in-closure.rs:6:5
3+
|
4+
LL | let callback = || {
5+
| -------- help: consider changing this to be mutable: `mut callback`
6+
LL | &mut my_var;
7+
| ------ calling `callback` requires mutable binding due to mutable borrow of `my_var`
8+
LL | };
9+
LL | callback();
10+
| ^^^^^^^^ cannot borrow as mutable
11+
12+
error: aborting due to previous error
13+
14+
For more information about this error, try `rustc --explain E0596`.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
fn main() {
2+
let mut my_var = false;
3+
let callback = move || {
4+
&mut my_var;
5+
};
6+
callback(); //~ ERROR E0596
7+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
error[E0596]: cannot borrow `callback` as mutable, as it is not declared as mutable
2+
--> $DIR/issue-80313-mutable-borrow-in-move-closure.rs:6:5
3+
|
4+
LL | let callback = move || {
5+
| -------- help: consider changing this to be mutable: `mut callback`
6+
LL | &mut my_var;
7+
| ------ calling `callback` requires mutable binding due to possible mutation of `my_var`
8+
LL | };
9+
LL | callback();
10+
| ^^^^^^^^ cannot borrow as mutable
11+
12+
error: aborting due to previous error
13+
14+
For more information about this error, try `rustc --explain E0596`.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
fn main() {
2+
let mut my_var = false;
3+
let callback = || {
4+
my_var = true;
5+
};
6+
callback(); //~ ERROR E0596
7+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
error[E0596]: cannot borrow `callback` as mutable, as it is not declared as mutable
2+
--> $DIR/issue-80313-mutation-in-closure.rs:6:5
3+
|
4+
LL | let callback = || {
5+
| -------- help: consider changing this to be mutable: `mut callback`
6+
LL | my_var = true;
7+
| ------ calling `callback` requires mutable binding due to mutable borrow of `my_var`
8+
LL | };
9+
LL | callback();
10+
| ^^^^^^^^ cannot borrow as mutable
11+
12+
error: aborting due to previous error
13+
14+
For more information about this error, try `rustc --explain E0596`.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
fn main() {
2+
let mut my_var = false;
3+
let callback = move || {
4+
my_var = true;
5+
};
6+
callback(); //~ ERROR E0596
7+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
error[E0596]: cannot borrow `callback` as mutable, as it is not declared as mutable
2+
--> $DIR/issue-80313-mutation-in-move-closure.rs:6:5
3+
|
4+
LL | let callback = move || {
5+
| -------- help: consider changing this to be mutable: `mut callback`
6+
LL | my_var = true;
7+
| ------ calling `callback` requires mutable binding due to possible mutation of `my_var`
8+
LL | };
9+
LL | callback();
10+
| ^^^^^^^^ cannot borrow as mutable
11+
12+
error: aborting due to previous error
13+
14+
For more information about this error, try `rustc --explain E0596`.

src/test/ui/unboxed-closures/unboxed-closures-infer-fnmut-calling-fnmut-no-mut.stderr

+4
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@ error[E0596]: cannot borrow `tick1` as mutable, as it is not declared as mutable
33
|
44
LL | let tick1 = || {
55
| ----- help: consider changing this to be mutable: `mut tick1`
6+
LL | counter += 1;
7+
| ------- calling `tick1` requires mutable binding due to mutable borrow of `counter`
68
...
79
LL | tick1();
810
| ^^^^^ cannot borrow as mutable
@@ -12,6 +14,8 @@ error[E0596]: cannot borrow `tick2` as mutable, as it is not declared as mutable
1214
|
1315
LL | let tick2 = || {
1416
| ----- help: consider changing this to be mutable: `mut tick2`
17+
LL | tick1();
18+
| ----- calling `tick2` requires mutable binding due to mutable borrow of `tick1`
1519
...
1620
LL | tick2();
1721
| ^^^^^ cannot borrow as mutable

src/test/ui/unboxed-closures/unboxed-closures-infer-fnmut-missing-mut.stderr

+3-1
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,9 @@ error[E0596]: cannot borrow `tick` as mutable, as it is not declared as mutable
22
--> $DIR/unboxed-closures-infer-fnmut-missing-mut.rs:7:5
33
|
44
LL | let tick = || counter += 1;
5-
| ---- help: consider changing this to be mutable: `mut tick`
5+
| ---- ------- calling `tick` requires mutable binding due to mutable borrow of `counter`
6+
| |
7+
| help: consider changing this to be mutable: `mut tick`
68
LL | tick();
79
| ^^^^ cannot borrow as mutable
810

src/test/ui/unboxed-closures/unboxed-closures-infer-fnmut-move-missing-mut.stderr

+3-1
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,9 @@ error[E0596]: cannot borrow `tick` as mutable, as it is not declared as mutable
22
--> $DIR/unboxed-closures-infer-fnmut-move-missing-mut.rs:7:5
33
|
44
LL | let tick = move || counter += 1;
5-
| ---- help: consider changing this to be mutable: `mut tick`
5+
| ---- ------- calling `tick` requires mutable binding due to possible mutation of `counter`
6+
| |
7+
| help: consider changing this to be mutable: `mut tick`
68
LL | tick();
79
| ^^^^ cannot borrow as mutable
810

0 commit comments

Comments
 (0)