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.
This commit is contained in:
bors 2017-08-10 08:53:22 +00:00
commit d21ec9b4ef
42 changed files with 110 additions and 70 deletions

View File

@ -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))
}
}

View File

@ -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()
}
}

View File

@ -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))
}

View File

@ -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)
}
}

View File

@ -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()
}
}

View File

@ -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()
}
}

View File

@ -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][..]));

View File

@ -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,

View File

@ -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

View File

@ -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));

View File

@ -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
},

View File

@ -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 {

View File

@ -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,

View File

@ -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);

View File

@ -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);

View File

@ -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;

View File

@ -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()
}
}

View File

@ -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;
}

View File

@ -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();

View File

@ -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 {

View File

@ -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);
}

View File

@ -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();

View File

@ -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);

View File

@ -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() {

View File

@ -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) {

View File

@ -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 {

View File

@ -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);
}

View File

@ -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);

View File

@ -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,

View File

@ -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;

View File

@ -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()
}
}

View File

@ -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 {

View File

@ -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));

View File

@ -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];

View File

@ -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 {

View File

@ -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) }

View File

@ -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

View File

@ -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);

View File

@ -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);
}

View File

@ -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();

View File

@ -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;

@ -1 +1 @@
Subproject commit 305bc25d5e105e84ffe261655b46cf74570f6e5b
Subproject commit 7704f7b1fd52607104cc7fdc435d636c9de1fe90