about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2017-08-10 08:53:22 +0000
committerbors <bors@rust-lang.org>2017-08-10 08:53:22 +0000
commitd21ec9b4efd1da012979b050bc0a0426fe45fcdf (patch)
treeb33492318dcad1da9a032327304bd1b972d2a947 /src
parent2ac5f7d249e29ee48737359e0e6dd9e59701a568 (diff)
parent8f78d453ded152e95d66f113d24287f12c680a15 (diff)
downloadrust-d21ec9b4efd1da012979b050bc0a0426fe45fcdf.tar.gz
rust-d21ec9b4efd1da012979b050bc0a0426fe45fcdf.zip
Auto merge of #43582 - ivanbakel:unused_mut_ref, r=arielb1
Fixed mutable vars being marked used when they weren't

#### NB : bootstrapping is slow on my machine, even with `keep-stage` - fixes for occurances in the current codebase are <s>in the pipeline</s> done. This PR is being put up for review of the fix of the issue.

Fixes #43526, Fixes #30280, Fixes #25049

### Issue
Whenever the compiler detected a mutable deref being used mutably, it marked an associated value as being used mutably as well. In the case of derefencing local variables which were mutable references, this incorrectly marked the reference itself being used mutably, instead of its contents - with the consequence of making the following code emit no warnings
```
fn do_thing<T>(mut arg : &mut T) {
    ... // don't touch arg - just deref it to access the T
}
```

### Fix
Make dereferences not be counted as a mutable use, but only when they're on borrows on local variables.
#### Why not on things other than local variables?
  * Whenever you capture a variable in a closure, it gets turned into a hidden reference - when you use it in the closure, it gets dereferenced. If the closure uses the variable mutably, that is actually a mutable use of the thing being dereffed to, so it has to be counted.
  * If you deref a mutable `Box` to access the contents mutably, you are using the `Box` mutably - so it has to be counted.
Diffstat (limited to 'src')
-rw-r--r--src/liballoc/btree/node.rs4
-rw-r--r--src/liballoc/vec.rs2
-rw-r--r--src/liballoc/vec_deque.rs6
-rw-r--r--src/libcore/ops/function.rs2
-rw-r--r--src/libcore/option.rs2
-rw-r--r--src/libcore/result.rs2
-rw-r--r--src/libcore/tests/slice.rs12
-rw-r--r--src/librustc/infer/error_reporting/mod.rs4
-rw-r--r--src/librustc/traits/mod.rs2
-rw-r--r--src/librustc/traits/select.rs2
-rw-r--r--src/librustc/ty/inhabitedness/mod.rs4
-rw-r--r--src/librustc_allocator/expand.rs4
-rw-r--r--src/librustc_borrowck/borrowck/gather_loans/mod.rs44
-rw-r--r--src/librustc_borrowck/borrowck/mod.rs2
-rw-r--r--src/librustc_data_structures/array_vec.rs2
-rw-r--r--src/librustc_data_structures/bitvec.rs2
-rw-r--r--src/librustc_data_structures/indexed_vec.rs2
-rw-r--r--src/librustc_driver/lib.rs2
-rw-r--r--src/librustc_metadata/cstore_impl.rs2
-rw-r--r--src/librustc_mir/build/matches/mod.rs2
-rw-r--r--src/librustc_mir/transform/type_check.rs2
-rw-r--r--src/librustc_privacy/lib.rs4
-rw-r--r--src/librustc_resolve/resolve_imports.rs2
-rw-r--r--src/librustc_trans/base.rs2
-rw-r--r--src/librustc_trans/partitioning.rs2
-rw-r--r--src/librustc_trans/time_graph.rs4
-rw-r--r--src/librustc_typeck/check/coercion.rs2
-rw-r--r--src/librustc_typeck/check/method/probe.rs4
-rw-r--r--src/librustc_typeck/check/mod.rs4
-rw-r--r--src/librustc_typeck/check/op.rs2
-rw-r--r--src/libstd/collections/hash/map.rs2
-rw-r--r--src/libstd/collections/hash/table.rs2
-rw-r--r--src/libstd/error.rs2
-rw-r--r--src/libstd/io/cursor.rs2
-rw-r--r--src/libstd/sync/once.rs2
-rw-r--r--src/libstd/sys/unix/rand.rs4
-rw-r--r--src/libstd/sys/windows/fs.rs4
-rw-r--r--src/libsyntax/ext/tt/macro_parser.rs4
-rw-r--r--src/libsyntax/ext/tt/macro_rules.rs2
-rw-r--r--src/libsyntax_ext/format.rs2
-rw-r--r--src/test/compile-fail/lint-unused-mut-variables.rs20
m---------src/tools/cargo0
42 files changed, 109 insertions, 69 deletions
diff --git a/src/liballoc/btree/node.rs b/src/liballoc/btree/node.rs
index 06d3a113b94..8cea6c482c3 100644
--- a/src/liballoc/btree/node.rs
+++ b/src/liballoc/btree/node.rs
@@ -1037,7 +1037,7 @@ impl<'a, K: 'a, V: 'a, NodeType>
         Handle<NodeRef<marker::Mut<'a>, K, V, NodeType>, marker::KV> {
 
     pub fn into_kv_mut(self) -> (&'a mut K, &'a mut V) {
-        let (mut keys, mut vals) = self.node.into_slices_mut();
+        let (keys, vals) = self.node.into_slices_mut();
         unsafe {
             (keys.get_unchecked_mut(self.idx), vals.get_unchecked_mut(self.idx))
         }
@@ -1047,7 +1047,7 @@ impl<'a, K: 'a, V: 'a, NodeType>
 impl<'a, K, V, NodeType> Handle<NodeRef<marker::Mut<'a>, K, V, NodeType>, marker::KV> {
     pub fn kv_mut(&mut self) -> (&mut K, &mut V) {
         unsafe {
-            let (mut keys, mut vals) = self.node.reborrow_mut().into_slices_mut();
+            let (keys, vals) = self.node.reborrow_mut().into_slices_mut();
             (keys.get_unchecked_mut(self.idx), vals.get_unchecked_mut(self.idx))
         }
     }
diff --git a/src/liballoc/vec.rs b/src/liballoc/vec.rs
index da47ca50983..160c0ba2ab0 100644
--- a/src/liballoc/vec.rs
+++ b/src/liballoc/vec.rs
@@ -1751,7 +1751,7 @@ impl<'a, T> IntoIterator for &'a mut Vec<T> {
     type Item = &'a mut T;
     type IntoIter = slice::IterMut<'a, T>;
 
-    fn into_iter(mut self) -> slice::IterMut<'a, T> {
+    fn into_iter(self) -> slice::IterMut<'a, T> {
         self.iter_mut()
     }
 }
diff --git a/src/liballoc/vec_deque.rs b/src/liballoc/vec_deque.rs
index fdd6c79ef2e..2068c2c9c5f 100644
--- a/src/liballoc/vec_deque.rs
+++ b/src/liballoc/vec_deque.rs
@@ -2394,7 +2394,7 @@ impl<'a, T> IntoIterator for &'a mut VecDeque<T> {
     type Item = &'a mut T;
     type IntoIter = IterMut<'a, T>;
 
-    fn into_iter(mut self) -> IterMut<'a, T> {
+    fn into_iter(self) -> IterMut<'a, T> {
         self.iter_mut()
     }
 }
@@ -2558,7 +2558,7 @@ impl<'a, T> Place<T> for PlaceBack<'a, T> {
 impl<'a, T> InPlace<T> for PlaceBack<'a, T> {
     type Owner = &'a mut T;
 
-    unsafe fn finalize(mut self) -> &'a mut T {
+    unsafe fn finalize(self) -> &'a mut T {
         let head = self.vec_deque.head;
         self.vec_deque.head = self.vec_deque.wrap_add(head, 1);
         &mut *(self.vec_deque.ptr().offset(head as isize))
@@ -2605,7 +2605,7 @@ impl<'a, T> Place<T> for PlaceFront<'a, T> {
 impl<'a, T> InPlace<T> for PlaceFront<'a, T> {
     type Owner = &'a mut T;
 
-    unsafe fn finalize(mut self) -> &'a mut T {
+    unsafe fn finalize(self) -> &'a mut T {
         self.vec_deque.tail = self.vec_deque.wrap_sub(self.vec_deque.tail, 1);
         &mut *(self.vec_deque.ptr().offset(self.vec_deque.tail as isize))
     }
diff --git a/src/libcore/ops/function.rs b/src/libcore/ops/function.rs
index 62bf69336a3..c5b3fbca1a6 100644
--- a/src/libcore/ops/function.rs
+++ b/src/libcore/ops/function.rs
@@ -187,7 +187,7 @@ mod impls {
         where F : FnMut<A>
     {
         type Output = F::Output;
-        extern "rust-call" fn call_once(mut self, args: A) -> F::Output {
+        extern "rust-call" fn call_once(self, args: A) -> F::Output {
             (*self).call_mut(args)
         }
     }
diff --git a/src/libcore/option.rs b/src/libcore/option.rs
index ef41b679410..aecf2ee9325 100644
--- a/src/libcore/option.rs
+++ b/src/libcore/option.rs
@@ -872,7 +872,7 @@ impl<'a, T> IntoIterator for &'a mut Option<T> {
     type Item = &'a mut T;
     type IntoIter = IterMut<'a, T>;
 
-    fn into_iter(mut self) -> IterMut<'a, T> {
+    fn into_iter(self) -> IterMut<'a, T> {
         self.iter_mut()
     }
 }
diff --git a/src/libcore/result.rs b/src/libcore/result.rs
index 88a93492de9..20cfb02afcc 100644
--- a/src/libcore/result.rs
+++ b/src/libcore/result.rs
@@ -909,7 +909,7 @@ impl<'a, T, E> IntoIterator for &'a mut Result<T, E> {
     type Item = &'a mut T;
     type IntoIter = IterMut<'a, T>;
 
-    fn into_iter(mut self) -> IterMut<'a, T> {
+    fn into_iter(self) -> IterMut<'a, T> {
         self.iter_mut()
     }
 }
diff --git a/src/libcore/tests/slice.rs b/src/libcore/tests/slice.rs
index e5d6b53b570..8c31d2e83d3 100644
--- a/src/libcore/tests/slice.rs
+++ b/src/libcore/tests/slice.rs
@@ -105,27 +105,27 @@ fn test_chunks_last() {
 
 #[test]
 fn test_chunks_mut_count() {
-    let mut v: &mut [i32] = &mut [0, 1, 2, 3, 4, 5];
+    let v: &mut [i32] = &mut [0, 1, 2, 3, 4, 5];
     let c = v.chunks_mut(3);
     assert_eq!(c.count(), 2);
 
-    let mut v2: &mut [i32] = &mut [0, 1, 2, 3, 4];
+    let v2: &mut [i32] = &mut [0, 1, 2, 3, 4];
     let c2 = v2.chunks_mut(2);
     assert_eq!(c2.count(), 3);
 
-    let mut v3: &mut [i32] = &mut [];
+    let v3: &mut [i32] = &mut [];
     let c3 = v3.chunks_mut(2);
     assert_eq!(c3.count(), 0);
 }
 
 #[test]
 fn test_chunks_mut_nth() {
-    let mut v: &mut [i32] = &mut [0, 1, 2, 3, 4, 5];
+    let v: &mut [i32] = &mut [0, 1, 2, 3, 4, 5];
     let mut c = v.chunks_mut(2);
     assert_eq!(c.nth(1).unwrap()[1], 3);
     assert_eq!(c.next().unwrap()[0], 4);
 
-    let mut v2: &mut [i32] = &mut [0, 1, 2, 3, 4];
+    let v2: &mut [i32] = &mut [0, 1, 2, 3, 4];
     let mut c2 = v2.chunks_mut(3);
     assert_eq!(c2.nth(1).unwrap()[1], 4);
     assert_eq!(c2.next(), None);
@@ -194,7 +194,7 @@ fn get_range() {
 
 #[test]
 fn get_mut_range() {
-    let mut v: &mut [i32] = &mut [0, 1, 2, 3, 4, 5];
+    let v: &mut [i32] = &mut [0, 1, 2, 3, 4, 5];
     assert_eq!(v.get_mut(..), Some(&mut [0, 1, 2, 3, 4, 5][..]));
     assert_eq!(v.get_mut(..2), Some(&mut [0, 1][..]));
     assert_eq!(v.get_mut(2..), Some(&mut [2, 3, 4, 5][..]));
diff --git a/src/librustc/infer/error_reporting/mod.rs b/src/librustc/infer/error_reporting/mod.rs
index 8e8576b83e4..9f70b4834dd 100644
--- a/src/librustc/infer/error_reporting/mod.rs
+++ b/src/librustc/infer/error_reporting/mod.rs
@@ -415,8 +415,8 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
     /// -------- this type is the same as a type argument in the other type, not highlighted
     /// ```
     fn highlight_outer(&self,
-                       mut value: &mut DiagnosticStyledString,
-                       mut other_value: &mut DiagnosticStyledString,
+                       value: &mut DiagnosticStyledString,
+                       other_value: &mut DiagnosticStyledString,
                        name: String,
                        sub: &ty::subst::Substs<'tcx>,
                        pos: usize,
diff --git a/src/librustc/traits/mod.rs b/src/librustc/traits/mod.rs
index e14203b34a1..d1938197e65 100644
--- a/src/librustc/traits/mod.rs
+++ b/src/librustc/traits/mod.rs
@@ -560,7 +560,7 @@ pub fn fully_normalize<'a, 'gcx, 'tcx, T>(infcx: &InferCtxt<'a, 'gcx, 'tcx>,
 {
     debug!("fully_normalize(value={:?})", value);
 
-    let mut selcx = &mut SelectionContext::new(infcx);
+    let selcx = &mut SelectionContext::new(infcx);
     // FIXME (@jroesch) ISSUE 26721
     // I'm not sure if this is a bug or not, needs further investigation.
     // It appears that by reusing the fulfillment_cx here we incur more
diff --git a/src/librustc/traits/select.rs b/src/librustc/traits/select.rs
index c2feb54c4db..b365096b23f 100644
--- a/src/librustc/traits/select.rs
+++ b/src/librustc/traits/select.rs
@@ -494,7 +494,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
             never_obligation.predicate = never_obligation.predicate.map_bound(|mut trait_pred| {
                 // Swap out () with ! so we can check if the trait is impld for !
                 {
-                    let mut trait_ref = &mut trait_pred.trait_ref;
+                    let trait_ref = &mut trait_pred.trait_ref;
                     let unit_substs = trait_ref.substs;
                     let mut never_substs = Vec::with_capacity(unit_substs.len());
                     never_substs.push(From::from(tcx.types.never));
diff --git a/src/librustc/ty/inhabitedness/mod.rs b/src/librustc/ty/inhabitedness/mod.rs
index 77c863a0123..900197f3dbd 100644
--- a/src/librustc/ty/inhabitedness/mod.rs
+++ b/src/librustc/ty/inhabitedness/mod.rs
@@ -171,7 +171,7 @@ impl<'a, 'gcx, 'tcx> TyS<'tcx> {
         match self.sty {
             TyAdt(def, substs) => {
                 {
-                    let mut substs_set = visited.entry(def.did).or_insert(FxHashSet::default());
+                    let substs_set = visited.entry(def.did).or_insert(FxHashSet::default());
                     if !substs_set.insert(substs) {
                         // We are already calculating the inhabitedness of this type.
                         // The type must contain a reference to itself. Break the
@@ -193,7 +193,7 @@ impl<'a, 'gcx, 'tcx> TyS<'tcx> {
                     }
                 }
                 let ret = def.uninhabited_from(visited, tcx, substs);
-                let mut substs_set = visited.get_mut(&def.did).unwrap();
+                let substs_set = visited.get_mut(&def.did).unwrap();
                 substs_set.remove(substs);
                 ret
             },
diff --git a/src/librustc_allocator/expand.rs b/src/librustc_allocator/expand.rs
index e942b7264c5..676c3c51ea2 100644
--- a/src/librustc_allocator/expand.rs
+++ b/src/librustc_allocator/expand.rs
@@ -188,7 +188,7 @@ impl<'a> AllocFnFactory<'a> {
     fn arg_ty(&self,
               ty: &AllocatorTy,
               args: &mut Vec<Arg>,
-              mut ident: &mut FnMut() -> Ident) -> P<Expr> {
+              ident: &mut FnMut() -> Ident) -> P<Expr> {
         match *ty {
             AllocatorTy::Layout => {
                 let usize = self.cx.path_ident(self.span, Ident::from_str("usize"));
@@ -263,7 +263,7 @@ impl<'a> AllocFnFactory<'a> {
     fn ret_ty(&self,
               ty: &AllocatorTy,
               args: &mut Vec<Arg>,
-              mut ident: &mut FnMut() -> Ident,
+              ident: &mut FnMut() -> Ident,
               expr: P<Expr>) -> (P<Ty>, P<Expr>)
     {
         match *ty {
diff --git a/src/librustc_borrowck/borrowck/gather_loans/mod.rs b/src/librustc_borrowck/borrowck/gather_loans/mod.rs
index 7dcb6ce76a4..3d669aa81df 100644
--- a/src/librustc_borrowck/borrowck/gather_loans/mod.rs
+++ b/src/librustc_borrowck/borrowck/gather_loans/mod.rs
@@ -436,20 +436,40 @@ impl<'a, 'tcx> GatherLoanCtxt<'a, 'tcx> {
         //! For mutable loans of content whose mutability derives
         //! from a local variable, mark the mutability decl as necessary.
 
-        match loan_path.kind {
-            LpVar(local_id) |
-            LpUpvar(ty::UpvarId{ var_id: local_id, closure_expr_id: _ }) => {
-                self.tcx().used_mut_nodes.borrow_mut().insert(local_id);
-            }
-            LpDowncast(ref base, _) |
-            LpExtend(ref base, mc::McInherited, _) |
-            LpExtend(ref base, mc::McDeclared, _) => {
-                self.mark_loan_path_as_mutated(&base);
-            }
-            LpExtend(_, mc::McImmutable, _) => {
-                // Nothing to do.
+        let mut wrapped_path = Some(loan_path);
+        let mut through_borrow = false;
+
+        while let Some(current_path) = wrapped_path {
+            wrapped_path = match current_path.kind {
+                LpVar(local_id) => {
+                    if !through_borrow {
+                        self.tcx().used_mut_nodes.borrow_mut().insert(local_id);
+                    }
+                    None
+                }
+                LpUpvar(ty::UpvarId{ var_id: local_id, closure_expr_id: _ }) => {
+                    self.tcx().used_mut_nodes.borrow_mut().insert(local_id);
+                    None
+                }
+                LpExtend(ref base, mc::McInherited, LpDeref(pointer_kind)) |
+                LpExtend(ref base, mc::McDeclared, LpDeref(pointer_kind)) => {
+                    if pointer_kind != mc::Unique {
+                        through_borrow = true;
+                    }
+                    Some(base)
+                }
+                LpDowncast(ref base, _) |
+                LpExtend(ref base, mc::McInherited, _) |
+                LpExtend(ref base, mc::McDeclared, _) => {
+                    Some(base)
+                }
+                LpExtend(_, mc::McImmutable, _) => {
+                    // Nothing to do.
+                    None
+                }
             }
         }
+
     }
 
     pub fn compute_gen_scope(&self,
diff --git a/src/librustc_borrowck/borrowck/mod.rs b/src/librustc_borrowck/borrowck/mod.rs
index 76c4ac57a14..6b31535c5a5 100644
--- a/src/librustc_borrowck/borrowck/mod.rs
+++ b/src/librustc_borrowck/borrowck/mod.rs
@@ -98,7 +98,7 @@ fn borrowck<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, owner_def_id: DefId) {
     let body_id = tcx.hir.body_owned_by(owner_id);
     let tables = tcx.typeck_tables_of(owner_def_id);
     let region_maps = tcx.region_maps(owner_def_id);
-    let mut bccx = &mut BorrowckCtxt { tcx, tables, region_maps, owner_def_id };
+    let bccx = &mut BorrowckCtxt { tcx, tables, region_maps, owner_def_id };
 
     let body = bccx.tcx.hir.body(body_id);
 
diff --git a/src/librustc_data_structures/array_vec.rs b/src/librustc_data_structures/array_vec.rs
index ced73e9e426..df660d08603 100644
--- a/src/librustc_data_structures/array_vec.rs
+++ b/src/librustc_data_structures/array_vec.rs
@@ -260,7 +260,7 @@ impl<'a, A: Array> Drop for Drain<'a, A> {
                 let start = source_array_vec.len();
                 let tail = self.tail_start;
                 {
-                    let mut arr = &mut source_array_vec.values as &mut [ManuallyDrop<_>];
+                    let arr = &mut source_array_vec.values as &mut [ManuallyDrop<_>];
                     let src = arr.as_ptr().offset(tail as isize);
                     let dst = arr.as_mut_ptr().offset(start as isize);
                     ptr::copy(src, dst, self.tail_len);
diff --git a/src/librustc_data_structures/bitvec.rs b/src/librustc_data_structures/bitvec.rs
index ffcd25a4cdd..7fc59be780f 100644
--- a/src/librustc_data_structures/bitvec.rs
+++ b/src/librustc_data_structures/bitvec.rs
@@ -166,7 +166,7 @@ impl BitMatrix {
     pub fn add(&mut self, source: usize, target: usize) -> bool {
         let (start, _) = self.range(source);
         let (word, mask) = word_mask(target);
-        let mut vector = &mut self.vector[..];
+        let vector = &mut self.vector[..];
         let v1 = vector[start + word];
         let v2 = v1 | mask;
         vector[start + word] = v2;
diff --git a/src/librustc_data_structures/indexed_vec.rs b/src/librustc_data_structures/indexed_vec.rs
index 29ac650aa70..1f44378c9e6 100644
--- a/src/librustc_data_structures/indexed_vec.rs
+++ b/src/librustc_data_structures/indexed_vec.rs
@@ -259,7 +259,7 @@ impl<'a, I: Idx, T> IntoIterator for &'a mut IndexVec<I, T> {
     type IntoIter = slice::IterMut<'a, T>;
 
     #[inline]
-    fn into_iter(mut self) -> slice::IterMut<'a, T> {
+    fn into_iter(self) -> slice::IterMut<'a, T> {
         self.raw.iter_mut()
     }
 }
diff --git a/src/librustc_driver/lib.rs b/src/librustc_driver/lib.rs
index a3c2957ff90..6f0a50180d7 100644
--- a/src/librustc_driver/lib.rs
+++ b/src/librustc_driver/lib.rs
@@ -422,7 +422,7 @@ fn show_content_with_pager(content: &String) {
 
     match Command::new(pager_name).stdin(Stdio::piped()).spawn() {
         Ok(mut pager) => {
-            if let Some(mut pipe) = pager.stdin.as_mut() {
+            if let Some(pipe) = pager.stdin.as_mut() {
                 if pipe.write_all(content.as_bytes()).is_err() {
                     fallback_to_println = true;
                 }
diff --git a/src/librustc_metadata/cstore_impl.rs b/src/librustc_metadata/cstore_impl.rs
index e8b0dea1e8a..d2ab9b2fbce 100644
--- a/src/librustc_metadata/cstore_impl.rs
+++ b/src/librustc_metadata/cstore_impl.rs
@@ -479,7 +479,7 @@ impl CrateStore for cstore::CStore {
                 _ => {},
             }
 
-            let mut bfs_queue = &mut VecDeque::new();
+            let bfs_queue = &mut VecDeque::new();
             let mut add_child = |bfs_queue: &mut VecDeque<_>, child: def::Export, parent: DefId| {
                 let child = child.def.def_id();
 
diff --git a/src/librustc_mir/build/matches/mod.rs b/src/librustc_mir/build/matches/mod.rs
index 54f285480ab..c0b54ce2a84 100644
--- a/src/librustc_mir/build/matches/mod.rs
+++ b/src/librustc_mir/build/matches/mod.rs
@@ -206,7 +206,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
         self.schedule_drop(span, extent, &Lvalue::Local(local_id), var_ty);
     }
 
-    pub fn visit_bindings<F>(&mut self, pattern: &Pattern<'tcx>, mut f: &mut F)
+    pub fn visit_bindings<F>(&mut self, pattern: &Pattern<'tcx>, f: &mut F)
         where F: FnMut(&mut Self, Mutability, Name, NodeId, Span, Ty<'tcx>)
     {
         match *pattern.kind {
diff --git a/src/librustc_mir/transform/type_check.rs b/src/librustc_mir/transform/type_check.rs
index 1c7899a46d1..f3a82b54063 100644
--- a/src/librustc_mir/transform/type_check.rs
+++ b/src/librustc_mir/transform/type_check.rs
@@ -721,7 +721,7 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
                value,
                obligations);
 
-        let mut fulfill_cx = &mut self.fulfillment_cx;
+        let fulfill_cx = &mut self.fulfillment_cx;
         for obligation in obligations {
             fulfill_cx.register_predicate_obligation(self.infcx, obligation);
         }
diff --git a/src/librustc_privacy/lib.rs b/src/librustc_privacy/lib.rs
index 64af24d92ee..3caa9ad34d3 100644
--- a/src/librustc_privacy/lib.rs
+++ b/src/librustc_privacy/lib.rs
@@ -781,7 +781,7 @@ impl<'a, 'tcx> Visitor<'tcx> for TypePrivacyVisitor<'a, 'tcx> {
             hir::ItemTrait(.., ref trait_item_refs) => {
                 self.check_item(item.id).generics().predicates();
                 for trait_item_ref in trait_item_refs {
-                    let mut check = self.check_item(trait_item_ref.id.node_id);
+                    let check = self.check_item(trait_item_ref.id.node_id);
                     check.generics().predicates();
                     if trait_item_ref.kind != hir::AssociatedItemKind::Type ||
                        trait_item_ref.defaultness.has_value() {
@@ -814,7 +814,7 @@ impl<'a, 'tcx> Visitor<'tcx> for TypePrivacyVisitor<'a, 'tcx> {
             }
             hir::ItemImpl(.., ref trait_ref, _, ref impl_item_refs) => {
                 {
-                    let mut check = self.check_item(item.id);
+                    let check = self.check_item(item.id);
                     check.ty().generics().predicates();
                     if trait_ref.is_some() {
                         check.impl_trait_ref();
diff --git a/src/librustc_resolve/resolve_imports.rs b/src/librustc_resolve/resolve_imports.rs
index 5e799b14f20..41f1f5877d8 100644
--- a/src/librustc_resolve/resolve_imports.rs
+++ b/src/librustc_resolve/resolve_imports.rs
@@ -379,7 +379,7 @@ impl<'a> Resolver<'a> {
         // Ensure that `resolution` isn't borrowed when defining in the module's glob importers,
         // during which the resolution might end up getting re-defined via a glob cycle.
         let (binding, t) = {
-            let mut resolution = &mut *self.resolution(module, ident, ns).borrow_mut();
+            let resolution = &mut *self.resolution(module, ident, ns).borrow_mut();
             let old_binding = resolution.binding();
 
             let t = f(self, resolution);
diff --git a/src/librustc_trans/base.rs b/src/librustc_trans/base.rs
index e8032529b1f..8cbc5155dde 100644
--- a/src/librustc_trans/base.rs
+++ b/src/librustc_trans/base.rs
@@ -1464,7 +1464,7 @@ fn collect_and_partition_translation_items<'a, 'tcx>(scx: &SharedCrateContext<'a
                 let mut output = i.to_string(scx.tcx());
                 output.push_str(" @@");
                 let mut empty = Vec::new();
-                let mut cgus = item_to_cgus.get_mut(i).unwrap_or(&mut empty);
+                let cgus = item_to_cgus.get_mut(i).unwrap_or(&mut empty);
                 cgus.as_mut_slice().sort_by_key(|&(ref name, _)| name.clone());
                 cgus.dedup();
                 for &(ref cgu_name, (linkage, _)) in cgus.iter() {
diff --git a/src/librustc_trans/partitioning.rs b/src/librustc_trans/partitioning.rs
index cff0eca02c6..63c7b18e8d2 100644
--- a/src/librustc_trans/partitioning.rs
+++ b/src/librustc_trans/partitioning.rs
@@ -335,7 +335,7 @@ fn place_root_translation_items<'a, 'tcx, I>(scx: &SharedCrateContext<'a, 'tcx>,
                 CodegenUnit::empty(codegen_unit_name.clone())
             };
 
-            let mut codegen_unit = codegen_units.entry(codegen_unit_name.clone())
+            let codegen_unit = codegen_units.entry(codegen_unit_name.clone())
                                                 .or_insert_with(make_codegen_unit);
 
             let (linkage, visibility) = match trans_item.explicit_linkage(tcx) {
diff --git a/src/librustc_trans/time_graph.rs b/src/librustc_trans/time_graph.rs
index e0ebe8a0933..ead6e432561 100644
--- a/src/librustc_trans/time_graph.rs
+++ b/src/librustc_trans/time_graph.rs
@@ -70,7 +70,7 @@ impl TimeGraph {
         {
             let mut table = self.data.lock().unwrap();
 
-            let mut data = table.entry(timeline).or_insert(PerThread {
+            let data = table.entry(timeline).or_insert(PerThread {
                 timings: Vec::new(),
                 open_work_package: None,
             });
@@ -90,7 +90,7 @@ impl TimeGraph {
         let end = Instant::now();
 
         let mut table = self.data.lock().unwrap();
-        let mut data = table.get_mut(&timeline).unwrap();
+        let data = table.get_mut(&timeline).unwrap();
 
         if let Some((start, work_package_kind)) = data.open_work_package {
             data.timings.push(Timing {
diff --git a/src/librustc_typeck/check/coercion.rs b/src/librustc_typeck/check/coercion.rs
index e494bc15222..934a4f9b296 100644
--- a/src/librustc_typeck/check/coercion.rs
+++ b/src/librustc_typeck/check/coercion.rs
@@ -1204,7 +1204,7 @@ impl<'gcx, 'tcx, 'exprs, E> CoerceMany<'gcx, 'tcx, 'exprs, E>
                     }
                 }
 
-                if let Some(mut augment_error) = augment_error {
+                if let Some(augment_error) = augment_error {
                     augment_error(&mut db);
                 }
 
diff --git a/src/librustc_typeck/check/method/probe.rs b/src/librustc_typeck/check/method/probe.rs
index 0934e2cdb0c..7bf671d5e9f 100644
--- a/src/librustc_typeck/check/method/probe.rs
+++ b/src/librustc_typeck/check/method/probe.rs
@@ -556,7 +556,7 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> {
             // We can't use normalize_associated_types_in as it will pollute the
             // fcx's fulfillment context after this probe is over.
             let cause = traits::ObligationCause::misc(self.span, self.body_id);
-            let mut selcx = &mut traits::SelectionContext::new(self.fcx);
+            let selcx = &mut traits::SelectionContext::new(self.fcx);
             let traits::Normalized { value: xform_self_ty, obligations } =
                 traits::normalize(selcx, self.param_env, cause, &xform_self_ty);
             debug!("assemble_inherent_impl_probe: xform_self_ty = {:?}",
@@ -765,7 +765,7 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> {
             // as it will pollute the fcx's fulfillment context after this probe
             // is over.
             let cause = traits::ObligationCause::misc(self.span, self.body_id);
-            let mut selcx = &mut traits::SelectionContext::new(self.fcx);
+            let selcx = &mut traits::SelectionContext::new(self.fcx);
             let traits::Normalized { value: xform_self_ty, obligations } =
                 traits::normalize(selcx, self.param_env, cause, &xform_self_ty);
 
diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs
index b9a9a954006..bd325474fe5 100644
--- a/src/librustc_typeck/check/mod.rs
+++ b/src/librustc_typeck/check/mod.rs
@@ -4183,8 +4183,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
             let tail_expr_ty = tail_expr.map(|t| self.check_expr_with_expectation(t, expected));
 
             let mut enclosing_breakables = self.enclosing_breakables.borrow_mut();
-            let mut ctxt = enclosing_breakables.find_breakable(blk.id);
-            let mut coerce = ctxt.coerce.as_mut().unwrap();
+            let ctxt = enclosing_breakables.find_breakable(blk.id);
+            let coerce = ctxt.coerce.as_mut().unwrap();
             if let Some(tail_expr_ty) = tail_expr_ty {
                 let tail_expr = tail_expr.unwrap();
                 let cause = self.cause(tail_expr.span,
diff --git a/src/librustc_typeck/check/op.rs b/src/librustc_typeck/check/op.rs
index 032e37a34a8..c1711491ee4 100644
--- a/src/librustc_typeck/check/op.rs
+++ b/src/librustc_typeck/check/op.rs
@@ -300,7 +300,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                           lhs_expr: &'gcx hir::Expr,
                           lhs_ty: Ty<'tcx>,
                           rhs_ty: Ty<'tcx>,
-                          mut err: &mut errors::DiagnosticBuilder) -> bool {
+                          err: &mut errors::DiagnosticBuilder) -> bool {
         // If this function returns true it means a note was printed, so we don't need
         // to print the normal "implementation of `std::ops::Add` might be missing" note
         let mut is_string_addition = false;
diff --git a/src/libstd/collections/hash/map.rs b/src/libstd/collections/hash/map.rs
index 12241b3f881..7e2229a8f84 100644
--- a/src/libstd/collections/hash/map.rs
+++ b/src/libstd/collections/hash/map.rs
@@ -1618,7 +1618,7 @@ impl<'a, K, V, S> IntoIterator for &'a mut HashMap<K, V, S>
     type Item = (&'a K, &'a mut V);
     type IntoIter = IterMut<'a, K, V>;
 
-    fn into_iter(mut self) -> IterMut<'a, K, V> {
+    fn into_iter(self) -> IterMut<'a, K, V> {
         self.iter_mut()
     }
 }
diff --git a/src/libstd/collections/hash/table.rs b/src/libstd/collections/hash/table.rs
index 3844690860b..6f7c5a5de42 100644
--- a/src/libstd/collections/hash/table.rs
+++ b/src/libstd/collections/hash/table.rs
@@ -563,7 +563,7 @@ impl<'t, K, V> FullBucket<K, V, &'t mut RawTable<K, V>> {
     ///
     /// This works similarly to `put`, building an `EmptyBucket` out of the
     /// taken bucket.
-    pub fn take(mut self) -> (EmptyBucket<K, V, &'t mut RawTable<K, V>>, K, V) {
+    pub fn take(self) -> (EmptyBucket<K, V, &'t mut RawTable<K, V>>, K, V) {
         self.table.size -= 1;
 
         unsafe {
diff --git a/src/libstd/error.rs b/src/libstd/error.rs
index d1c2bfb96b3..401552a6ec4 100644
--- a/src/libstd/error.rs
+++ b/src/libstd/error.rs
@@ -514,7 +514,7 @@ mod tests {
     #[test]
     fn downcasting() {
         let mut a = A;
-        let mut a = &mut a as &mut (Error + 'static);
+        let a = &mut a as &mut (Error + 'static);
         assert_eq!(a.downcast_ref::<A>(), Some(&A));
         assert_eq!(a.downcast_ref::<B>(), None);
         assert_eq!(a.downcast_mut::<A>(), Some(&mut A));
diff --git a/src/libstd/io/cursor.rs b/src/libstd/io/cursor.rs
index 616b4f47ed3..d986021a18b 100644
--- a/src/libstd/io/cursor.rs
+++ b/src/libstd/io/cursor.rs
@@ -456,7 +456,7 @@ mod tests {
     #[test]
     fn test_slice_reader() {
         let in_buf = vec![0, 1, 2, 3, 4, 5, 6, 7];
-        let mut reader = &mut &in_buf[..];
+        let reader = &mut &in_buf[..];
         let mut buf = [];
         assert_eq!(reader.read(&mut buf).unwrap(), 0);
         let mut buf = [0];
diff --git a/src/libstd/sync/once.rs b/src/libstd/sync/once.rs
index d9edf5d1254..bb18fe95a9d 100644
--- a/src/libstd/sync/once.rs
+++ b/src/libstd/sync/once.rs
@@ -267,7 +267,7 @@ impl Once {
     #[cold]
     fn call_inner(&'static self,
                   ignore_poisoning: bool,
-                  mut init: &mut FnMut(bool)) {
+                  init: &mut FnMut(bool)) {
         let mut state = self.state.load(Ordering::SeqCst);
 
         'outer: loop {
diff --git a/src/libstd/sys/unix/rand.rs b/src/libstd/sys/unix/rand.rs
index 77ebad4e344..1f56a299407 100644
--- a/src/libstd/sys/unix/rand.rs
+++ b/src/libstd/sys/unix/rand.rs
@@ -12,13 +12,13 @@ pub use self::imp::OsRng;
 
 use mem;
 
-fn next_u32(mut fill_buf: &mut FnMut(&mut [u8])) -> u32 {
+fn next_u32(fill_buf: &mut FnMut(&mut [u8])) -> u32 {
     let mut buf: [u8; 4] = [0; 4];
     fill_buf(&mut buf);
     unsafe { mem::transmute::<[u8; 4], u32>(buf) }
 }
 
-fn next_u64(mut fill_buf: &mut FnMut(&mut [u8])) -> u64 {
+fn next_u64(fill_buf: &mut FnMut(&mut [u8])) -> u64 {
     let mut buf: [u8; 8] = [0; 8];
     fill_buf(&mut buf);
     unsafe { mem::transmute::<[u8; 8], u64>(buf) }
diff --git a/src/libstd/sys/windows/fs.rs b/src/libstd/sys/windows/fs.rs
index 7f3291cf304..f2487c1b0bd 100644
--- a/src/libstd/sys/windows/fs.rs
+++ b/src/libstd/sys/windows/fs.rs
@@ -768,8 +768,8 @@ fn symlink_junction_inner(target: &Path, junction: &Path) -> io::Result<()> {
 
     unsafe {
         let mut data = [0u8; c::MAXIMUM_REPARSE_DATA_BUFFER_SIZE];
-        let mut db = data.as_mut_ptr()
-                        as *mut c::REPARSE_MOUNTPOINT_DATA_BUFFER;
+        let db = data.as_mut_ptr()
+                    as *mut c::REPARSE_MOUNTPOINT_DATA_BUFFER;
         let buf = &mut (*db).ReparseTarget as *mut _;
         let mut i = 0;
         // FIXME: this conversion is very hacky
diff --git a/src/libsyntax/ext/tt/macro_parser.rs b/src/libsyntax/ext/tt/macro_parser.rs
index 60833c75a15..146bd5d9856 100644
--- a/src/libsyntax/ext/tt/macro_parser.rs
+++ b/src/libsyntax/ext/tt/macro_parser.rs
@@ -211,7 +211,7 @@ pub enum NamedMatch {
 
 fn nameize<I: Iterator<Item=NamedMatch>>(sess: &ParseSess, ms: &[TokenTree], mut res: I)
                                              -> NamedParseResult {
-    fn n_rec<I: Iterator<Item=NamedMatch>>(sess: &ParseSess, m: &TokenTree, mut res: &mut I,
+    fn n_rec<I: Iterator<Item=NamedMatch>>(sess: &ParseSess, m: &TokenTree, res: &mut I,
              ret_val: &mut HashMap<Ident, Rc<NamedMatch>>)
              -> Result<(), (syntax_pos::Span, String)> {
         match *m {
@@ -445,7 +445,7 @@ pub fn parse(sess: &ParseSess,
         /* error messages here could be improved with links to orig. rules */
         if token_name_eq(&parser.token, &token::Eof) {
             if eof_items.len() == 1 {
-                let matches = eof_items[0].matches.iter_mut().map(|mut dv| {
+                let matches = eof_items[0].matches.iter_mut().map(|dv| {
                     Rc::make_mut(dv).pop().unwrap()
                 });
                 return nameize(sess, ms, matches);
diff --git a/src/libsyntax/ext/tt/macro_rules.rs b/src/libsyntax/ext/tt/macro_rules.rs
index 8e746676ecd..80b6794d1e3 100644
--- a/src/libsyntax/ext/tt/macro_rules.rs
+++ b/src/libsyntax/ext/tt/macro_rules.rs
@@ -86,7 +86,7 @@ impl TTMacroExpander for MacroRulesMacroExpander {
 
 fn trace_macros_note(cx: &mut ExtCtxt, sp: Span, message: String) {
     let sp = sp.macro_backtrace().last().map(|trace| trace.call_site).unwrap_or(sp);
-    let mut values: &mut Vec<String> = cx.expansions.entry(sp).or_insert_with(Vec::new);
+    let values: &mut Vec<String> = cx.expansions.entry(sp).or_insert_with(Vec::new);
     values.push(message);
 }
 
diff --git a/src/libsyntax_ext/format.rs b/src/libsyntax_ext/format.rs
index 9734bb867f1..16b06424c92 100644
--- a/src/libsyntax_ext/format.rs
+++ b/src/libsyntax_ext/format.rs
@@ -529,7 +529,7 @@ impl<'a, 'b> Context<'a, 'b> {
 
     /// Actually builds the expression which the format_args! block will be
     /// expanded to
-    fn into_expr(mut self) -> P<ast::Expr> {
+    fn into_expr(self) -> P<ast::Expr> {
         let mut locals = Vec::new();
         let mut counts = Vec::new();
         let mut pats = Vec::new();
diff --git a/src/test/compile-fail/lint-unused-mut-variables.rs b/src/test/compile-fail/lint-unused-mut-variables.rs
index 21cfadb9c79..26d00755da3 100644
--- a/src/test/compile-fail/lint-unused-mut-variables.rs
+++ b/src/test/compile-fail/lint-unused-mut-variables.rs
@@ -47,6 +47,26 @@ fn main() {
     let x = |mut y: isize| 10; //~ ERROR: variable does not need to be mutable
     fn what(mut foo: isize) {} //~ ERROR: variable does not need to be mutable
 
+    let mut a = &mut 5; //~ ERROR: variable does not need to be mutable
+    *a = 4;
+
+    let mut a = 5;
+    let mut b = (&mut a,);
+    *b.0 = 4; //~^ ERROR: variable does not need to be mutable
+
+    let mut x = &mut 1; //~ ERROR: variable does not need to be mutable
+    let mut f = || {
+      *x += 1;
+    };
+    f();
+
+    fn mut_ref_arg(mut arg : &mut [u8]) -> &mut [u8] {
+        &mut arg[..] //~^ ERROR: variable does not need to be mutable
+    }
+
+    let mut v : &mut Vec<()> = &mut vec![]; //~ ERROR: variable does not need to be mutable
+    v.push(());
+
     // positive cases
     let mut a = 2;
     a = 3;
diff --git a/src/tools/cargo b/src/tools/cargo
-Subproject 305bc25d5e105e84ffe261655b46cf74570f6e5
+Subproject 7704f7b1fd52607104cc7fdc435d636c9de1fe9