Skip to content

Commit 604cbdc

Browse files
committed
Fix unused 'mut' warning for capture's root variable
1 parent 0897db5 commit 604cbdc

File tree

4 files changed

+75
-21
lines changed

4 files changed

+75
-21
lines changed

compiler/rustc_mir/src/borrow_check/mod.rs

Lines changed: 29 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1369,13 +1369,38 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
13691369

13701370
fn propagate_closure_used_mut_upvar(&mut self, operand: &Operand<'tcx>) {
13711371
let propagate_closure_used_mut_place = |this: &mut Self, place: Place<'tcx>| {
1372-
if !place.projection.is_empty() {
1373-
if let Some(field) = this.is_upvar_field_projection(place.as_ref()) {
1372+
// We have three possiblities here:
1373+
// a. We are modifying something through a mut-ref
1374+
// b. We are modifying something that is local to our parent
1375+
// c. Current body is a nested clsoure, and we are modifying path starting from
1376+
// a Place captured by our parent closure.
1377+
1378+
// Handle (c), the path being modified is exactly the path captured by our parent
1379+
if let Some(field) = this.is_upvar_field_projection(place.as_ref()) {
1380+
this.used_mut_upvars.push(field);
1381+
return;
1382+
}
1383+
1384+
for (place_ref, proj) in place.iter_projections().rev() {
1385+
// Handle (a)
1386+
if proj == ProjectionElem::Deref {
1387+
match place_ref.ty(this.body(), this.infcx.tcx).ty.kind() {
1388+
// We aren't modifying a variable directly
1389+
ty::Ref(_, _, hir::Mutability::Mut) => return,
1390+
1391+
_ => {}
1392+
}
1393+
}
1394+
1395+
// Handle (c)
1396+
if let Some(field) = this.is_upvar_field_projection(place_ref) {
13741397
this.used_mut_upvars.push(field);
1398+
return;
13751399
}
1376-
} else {
1377-
this.used_mut.insert(place.local);
13781400
}
1401+
1402+
// Handle(b)
1403+
this.used_mut.insert(place.local);
13791404
};
13801405

13811406
// This relies on the current way that by-value

src/test/ui/closures/2229_closure_analysis/run_pass/move_closure.rs

Lines changed: 21 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -29,19 +29,36 @@ fn struct_contains_ref_to_another_struct() {
2929
c();
3030
}
3131

32-
fn no_ref() {
33-
struct S(String);
34-
struct T(S);
32+
#[derive(Debug)]
33+
struct S(String);
3534

36-
let t = T(S("s".into()));
35+
#[derive(Debug)]
36+
struct T(S);
37+
38+
fn no_ref() {
39+
let mut t = T(S("s".into()));
3740
let mut c = move || {
3841
t.0.0 = "new S".into();
3942
};
4043
c();
4144
}
4245

46+
fn no_ref_nested() {
47+
let mut t = T(S("s".into()));
48+
let c = || {
49+
println!("{:?}", t.0);
50+
let mut c = move || {
51+
t.0.0 = "new S".into();
52+
println!("{:?}", t.0.0);
53+
};
54+
c();
55+
};
56+
c();
57+
}
58+
4359
fn main() {
4460
simple_ref();
4561
struct_contains_ref_to_another_struct();
4662
no_ref();
63+
no_ref_nested();
4764
}

src/test/ui/closures/2229_closure_analysis/run_pass/move_closure.stderr

Lines changed: 1 addition & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -7,15 +7,5 @@ LL | #![feature(capture_disjoint_fields)]
77
= note: `#[warn(incomplete_features)]` on by default
88
= note: see issue #53488 <https://github.com/rust-lang/rust/issues/53488> for more information
99

10-
warning: variable does not need to be mutable
11-
--> $DIR/move_closure.rs:36:9
12-
|
13-
LL | let mut t = T(S("s".into()));
14-
| ----^
15-
| |
16-
| help: remove this `mut`
17-
|
18-
= note: `#[warn(unused_mut)]` on by default
19-
20-
warning: 2 warnings emitted
10+
warning: 1 warning emitted
2111

src/test/ui/closures/2229_closure_analysis/run_pass/mut_ref_struct_mem.rs

Lines changed: 24 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,14 +2,14 @@
22

33
// Test that we can mutate a place through a mut-borrow
44
// that is captured by the closure
5-
//
5+
66
// More specifically we test that the if the mutable reference isn't root variable of a capture
77
// but rather accessed while acessing the precise capture.
88

99
#![feature(capture_disjoint_fields)]
1010
//~^ WARNING: the feature `capture_disjoint_fields` is incomplete
1111

12-
fn main() {
12+
fn mut_tuple() {
1313
let mut t = (10, 10);
1414

1515
let t1 = (&mut t, 10);
@@ -21,3 +21,25 @@ fn main() {
2121

2222
c();
2323
}
24+
25+
fn mut_tuple_nested() {
26+
let mut t = (10, 10);
27+
28+
let t1 = (&mut t, 10);
29+
30+
let mut c = || {
31+
let mut c = || {
32+
// Mutable because (*t.0) is mutable
33+
t1.0.0 += 10;
34+
};
35+
36+
c();
37+
};
38+
39+
c();
40+
}
41+
42+
fn main() {
43+
mut_tuple();
44+
mut_tuple_nested();
45+
}

0 commit comments

Comments
 (0)