about summary refs log tree commit diff
path: root/compiler
diff options
context:
space:
mode:
authorAman Arora <me@aman-arora.com>2020-12-15 23:00:19 -0500
committerAman Arora <me@aman-arora.com>2021-01-29 15:37:42 -0500
commit604cbdcfddb959cd1d7de2f9afa14a199561a428 (patch)
treef711c27d880cc8c09ccfd6b7f7a5546b9c289539 /compiler
parent0897db56098dd8e8355017f4364bc88f1e4f26c0 (diff)
downloadrust-604cbdcfddb959cd1d7de2f9afa14a199561a428.tar.gz
rust-604cbdcfddb959cd1d7de2f9afa14a199561a428.zip
Fix unused 'mut' warning for capture's root variable
Diffstat (limited to 'compiler')
-rw-r--r--compiler/rustc_mir/src/borrow_check/mod.rs33
1 files changed, 29 insertions, 4 deletions
diff --git a/compiler/rustc_mir/src/borrow_check/mod.rs b/compiler/rustc_mir/src/borrow_check/mod.rs
index 1a771157e28..6e1e5c65aea 100644
--- a/compiler/rustc_mir/src/borrow_check/mod.rs
+++ b/compiler/rustc_mir/src/borrow_check/mod.rs
@@ -1369,13 +1369,38 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
 
     fn propagate_closure_used_mut_upvar(&mut self, operand: &Operand<'tcx>) {
         let propagate_closure_used_mut_place = |this: &mut Self, place: Place<'tcx>| {
-            if !place.projection.is_empty() {
-                if let Some(field) = this.is_upvar_field_projection(place.as_ref()) {
+            // We have three possiblities here:
+            // a. We are modifying something through a mut-ref
+            // b. We are modifying something that is local to our parent
+            // c. Current body is a nested clsoure, and we are modifying path starting from
+            //    a Place captured by our parent closure.
+
+            // Handle (c), the path being modified is exactly the path captured by our parent
+            if let Some(field) = this.is_upvar_field_projection(place.as_ref()) {
+                this.used_mut_upvars.push(field);
+                return;
+            }
+
+            for (place_ref, proj) in place.iter_projections().rev() {
+                // Handle (a)
+                if proj == ProjectionElem::Deref {
+                    match place_ref.ty(this.body(), this.infcx.tcx).ty.kind() {
+                        // We aren't modifying a variable directly
+                        ty::Ref(_, _, hir::Mutability::Mut) => return,
+
+                        _ => {}
+                    }
+                }
+
+                // Handle (c)
+                if let Some(field) = this.is_upvar_field_projection(place_ref) {
                     this.used_mut_upvars.push(field);
+                    return;
                 }
-            } else {
-                this.used_mut.insert(place.local);
             }
+
+            // Handle(b)
+            this.used_mut.insert(place.local);
         };
 
         // This relies on the current way that by-value