about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
authorNiko Matsakis <niko@alum.mit.edu>2018-04-06 12:35:50 -0400
committerKeith Yeung <kungfukeith11@gmail.com>2018-04-28 22:25:57 -0700
commitded06976790299c87ca3501aca23d3c74b5b0039 (patch)
tree51888e9f86f80c975a8c0331139a81f0acafce53 /src
parent8c607eaf949a0ba9c365dd00e18d948418cfe957 (diff)
downloadrust-ded06976790299c87ca3501aca23d3c74b5b0039.tar.gz
rust-ded06976790299c87ca3501aca23d3c74b5b0039.zip
Return RootPlace in is_mutable
Diffstat (limited to 'src')
-rw-r--r--src/librustc_mir/borrow_check/mod.rs42
1 files changed, 35 insertions, 7 deletions
diff --git a/src/librustc_mir/borrow_check/mod.rs b/src/librustc_mir/borrow_check/mod.rs
index a70c601bd1a..f2b0ec58e78 100644
--- a/src/librustc_mir/borrow_check/mod.rs
+++ b/src/librustc_mir/borrow_check/mod.rs
@@ -1150,13 +1150,14 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
                 // in order to populate our used_mut set.
                 if let AggregateKind::Closure(def_id, _) = &**aggregate_kind {
                     let BorrowCheckResult { used_mut_upvars, .. } = self.tcx.mir_borrowck(*def_id);
+                    debug!("{:?} used_mut_upvars={:?}", def_id, used_mut_upvars);
                     for field in used_mut_upvars {
                         match operands[field.index()] {
                             Operand::Move(Place::Local(local)) => {
                                 self.used_mut.insert(local);
                             }
-                            Operand::Move(Place::Projection(ref proj)) => {
-                                if let Some(field) = self.is_upvar_field_projection(&proj.base) {
+                            Operand::Move(ref place @ Place::Projection(_)) => {
+                                if let Some(field) = self.is_upvar_field_projection(place) {
                                     self.used_mut_upvars.push(field);
                                 }
                             }
@@ -1697,8 +1698,8 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
                             }
                         }
                     }
-                    Ok((Place::Projection(ref proj), _mut_allowed)) => {
-                        if let Some(field) = self.is_upvar_field_projection(&proj.base) {
+                    Ok((Place::Projection(_), _mut_allowed)) => {
+                        if let Some(field) = self.is_upvar_field_projection(&place) {
                             self.used_mut_upvars.push(field);
                         }
                     }
@@ -1734,8 +1735,8 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
                             }
                         }
                     }
-                    Ok((Place::Projection(ref proj), _mut_allowed)) => {
-                        if let Some(field) = self.is_upvar_field_projection(&proj.base) {
+                    Ok((Place::Projection(_), _mut_allowed)) => {
+                        if let Some(field) = self.is_upvar_field_projection(&place) {
                             self.used_mut_upvars.push(field);
                         }
                     }
@@ -1930,7 +1931,34 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
                                 }
                                 (Mutability::Not, LocalMutationIsAllowed::Yes)
                                 | (Mutability::Mut, _) => {
-                                    self.is_mutable(&proj.base, is_local_mutation_allowed)
+                                    // Subtle: this is an upvar
+                                    // reference, so it looks like
+                                    // `self.foo` -- we want to double
+                                    // check that the context `*self`
+                                    // is mutable (i.e., this is not a
+                                    // `Fn` closure).  But if that
+                                    // check succeeds, we want to
+                                    // *blame* the mutability on
+                                    // `place` (that is,
+                                    // `self.foo`). This is used to
+                                    // propagate the info about
+                                    // whether mutability declarations
+                                    // are used outwards, so that we register
+                                    // the outer variable as mutable. Otherwise a
+                                    // test like this fails to record the `mut`
+                                    // as needed:
+                                    //
+                                    // ```
+                                    // fn foo<F: FnOnce()>(_f: F) { }
+                                    // fn main() {
+                                    //     let var = Vec::new();
+                                    //     foo(move || {
+                                    //         var.push(1);
+                                    //     });
+                                    // }
+                                    // ```
+                                    let _ = self.is_mutable(&proj.base, is_local_mutation_allowed)?;
+                                    Ok((place, is_local_mutation_allowed))
                                 }
                             }
                         } else {