about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--src/librustc/mir/mod.rs10
-rw-r--r--src/librustc_mir/borrow_check/mod.rs23
2 files changed, 25 insertions, 8 deletions
diff --git a/src/librustc/mir/mod.rs b/src/librustc/mir/mod.rs
index 7b6389072b7..c26b3014e53 100644
--- a/src/librustc/mir/mod.rs
+++ b/src/librustc/mir/mod.rs
@@ -248,13 +248,15 @@ impl<'tcx> Mir<'tcx> {
         })
     }
 
-    /// Returns an iterator over all user-declared mutable locals.
+    /// Returns an iterator over all user-declared mutable arguments and locals.
     #[inline]
-    pub fn mut_vars_iter<'a>(&'a self) -> impl Iterator<Item=Local> + 'a {
-        (self.arg_count+1..self.local_decls.len()).filter_map(move |index| {
+    pub fn mut_vars_and_args_iter<'a>(&'a self) -> impl Iterator<Item=Local> + 'a {
+        (1..self.local_decls.len()).filter_map(move |index| {
             let local = Local::new(index);
             let decl = &self.local_decls[local];
-            if decl.is_user_variable && decl.mutability == Mutability::Mut {
+            if (decl.is_user_variable || index < self.arg_count + 1)
+               && decl.mutability == Mutability::Mut
+            {
                 Some(local)
             } else {
                 None
diff --git a/src/librustc_mir/borrow_check/mod.rs b/src/librustc_mir/borrow_check/mod.rs
index ea628cefd3e..60691d1179a 100644
--- a/src/librustc_mir/borrow_check/mod.rs
+++ b/src/librustc_mir/borrow_check/mod.rs
@@ -261,9 +261,17 @@ fn do_mir_borrowck<'a, 'gcx, 'tcx>(
 
     debug!("mbcx.used_mut: {:?}", mbcx.used_mut);
 
-    for local in mbcx.mir.mut_vars_iter().filter(|local| !mbcx.used_mut.contains(local)) {
+    for local in mbcx.mir.mut_vars_and_args_iter().filter(|local| !mbcx.used_mut.contains(local)) {
         if let ClearCrossCrate::Set(ref vsi) = mbcx.mir.visibility_scope_info {
-            let source_info = mbcx.mir.local_decls[local].source_info;
+            let local_decl = &mbcx.mir.local_decls[local];
+
+            // Skip over locals that begin with an underscore
+            match local_decl.name {
+                Some(name) if name.as_str().starts_with("_") => continue,
+                _ => {},
+            }
+
+            let source_info = local_decl.source_info;
             let mut_span = tcx.sess.codemap().span_until_non_whitespace(source_info.span);
 
             tcx.struct_span_lint_node(
@@ -864,7 +872,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
         }
 
         let mutability_error =
-            self.check_access_permissions(place_span, rw, is_local_mutation_allowed);
+            self.check_access_permissions(place_span, rw, is_local_mutation_allowed, flow_state);
         let conflict_error =
             self.check_access_for_conflict(context, place_span, sd, rw, flow_state);
 
@@ -1656,6 +1664,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
         (place, span): (&Place<'tcx>, Span),
         kind: ReadOrWrite,
         is_local_mutation_allowed: LocalMutationIsAllowed,
+        flow_state: &Flows<'cx, 'gcx, 'tcx>,
     ) -> bool {
         debug!(
             "check_access_permissions({:?}, {:?}, {:?})",
@@ -1691,7 +1700,13 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
             Reservation(WriteKind::Mutate) | Write(WriteKind::Mutate) => {
                 match place {
                     Place::Local(local) => {
-                        self.used_mut.insert(*local);
+                        // If the local may be initialized, and it is now currently being
+                        // mutated, then it is justified to be annotated with the `mut` keyword,
+                        // since the mutation may be a possible reassignment.
+                        let mpi = self.move_data.rev_lookup.find_local(*local);
+                        if flow_state.inits.contains(&mpi) {
+                            self.used_mut.insert(*local);
+                        }
                     }
                     Place::Projection(ref proj) => {
                         if let Some(field) = self.is_upvar_field_projection(&proj.base) {