about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--src/librustc_borrowck/borrowck/mod.rs129
-rw-r--r--src/test/ui/span/borrowck-borrow-overloaded-auto-deref-mut.rs (renamed from src/test/compile-fail/borrowck/borrowck-borrow-overloaded-auto-deref-mut.rs)0
-rw-r--r--src/test/ui/span/borrowck-borrow-overloaded-auto-deref-mut.stderr86
-rw-r--r--src/test/ui/span/borrowck-borrow-overloaded-deref-mut.rs (renamed from src/test/compile-fail/borrowck/borrowck-borrow-overloaded-deref-mut.rs)0
-rw-r--r--src/test/ui/span/borrowck-borrow-overloaded-deref-mut.stderr34
-rw-r--r--src/test/ui/span/borrowck-call-is-borrow-issue-12224.rs (renamed from src/test/compile-fail/borrowck/borrowck-call-is-borrow-issue-12224.rs)0
-rw-r--r--src/test/ui/span/borrowck-call-is-borrow-issue-12224.stderr43
-rw-r--r--src/test/ui/span/borrowck-call-method-from-mut-aliasable.rs (renamed from src/test/compile-fail/borrowck/borrowck-call-method-from-mut-aliasable.rs)0
-rw-r--r--src/test/ui/span/borrowck-call-method-from-mut-aliasable.stderr11
-rw-r--r--src/test/ui/span/borrowck-fn-in-const-b.rs (renamed from src/test/compile-fail/borrowck/borrowck-fn-in-const-b.rs)0
-rw-r--r--src/test/ui/span/borrowck-fn-in-const-b.stderr10
-rw-r--r--src/test/ui/span/borrowck-object-mutability.rs (renamed from src/test/compile-fail/borrowck/borrowck-object-mutability.rs)0
-rw-r--r--src/test/ui/span/borrowck-object-mutability.stderr17
-rw-r--r--src/test/ui/span/mut-arg-hint.rs32
-rw-r--r--src/test/ui/span/mut-arg-hint.stderr26
15 files changed, 342 insertions, 46 deletions
diff --git a/src/librustc_borrowck/borrowck/mod.rs b/src/librustc_borrowck/borrowck/mod.rs
index 5e54e333bb9..0c52aacdbdb 100644
--- a/src/librustc_borrowck/borrowck/mod.rs
+++ b/src/librustc_borrowck/borrowck/mod.rs
@@ -24,7 +24,7 @@ use self::InteriorKind::*;
 
 use rustc::dep_graph::DepNode;
 use rustc::hir::map as hir_map;
-use rustc::hir::map::blocks::FnParts;
+use rustc::hir::map::blocks::{FnParts, FnLikeNode};
 use rustc::cfg;
 use rustc::middle::dataflow::DataFlowContext;
 use rustc::middle::dataflow::BitwiseOperator;
@@ -970,51 +970,8 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> {
 
     pub fn note_and_explain_bckerr(&self, db: &mut DiagnosticBuilder, err: BckError<'tcx>,
         error_span: Span) {
-        let code = err.code;
-        match code {
-            err_mutbl => {
-                match err.cmt.note {
-                    mc::NoteClosureEnv(upvar_id) | mc::NoteUpvarRef(upvar_id) => {
-                        // If this is an `Fn` closure, it simply can't mutate upvars.
-                        // If it's an `FnMut` closure, the original variable was declared immutable.
-                        // We need to determine which is the case here.
-                        let kind = match err.cmt.upvar().unwrap().cat {
-                            Categorization::Upvar(mc::Upvar { kind, .. }) => kind,
-                            _ => bug!()
-                        };
-                        if kind == ty::ClosureKind::Fn {
-                            db.span_help(
-                                self.tcx.map.span(upvar_id.closure_expr_id),
-                                "consider changing this closure to take \
-                                 self by mutable reference");
-                        }
-                    }
-                    _ => {
-                        if let Categorization::Local(local_id) = err.cmt.cat {
-                            let span = self.tcx.map.span(local_id);
-                            if let Ok(snippet) = self.tcx.sess.codemap().span_to_snippet(span) {
-                                if snippet.starts_with("ref mut ") || snippet.starts_with("&mut ") {
-                                    db.span_label(error_span, &format!("cannot reborrow mutably"));
-                                    db.span_label(error_span, &format!("try removing `&mut` here"));
-                                } else {
-                                    if snippet.starts_with("ref ") {
-                                        db.span_label(span,
-                                            &format!("use `{}` here to make mutable",
-                                                snippet.replace("ref ", "ref mut ")));
-                                    } else if snippet != "self" {
-                                        db.span_label(span,
-                                            &format!("use `mut {}` here to make mutable", snippet));
-                                    }
-                                    db.span_label(error_span, &format!("cannot borrow mutably"));
-                                }
-                            } else {
-                                db.span_label(error_span, &format!("cannot borrow mutably"));
-                            }
-                        }
-                    }
-                }
-            }
-
+        match err.code {
+            err_mutbl => self.note_and_explain_mutbl_error(db, &err, &error_span),
             err_out_of_scope(super_scope, sub_scope, cause) => {
                 let (value_kind, value_msg) = match err.cmt.cat {
                     mc::Categorization::Rvalue(_) =>
@@ -1135,6 +1092,86 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> {
         }
     }
 
+    fn note_and_explain_mutbl_error(&self, db: &mut DiagnosticBuilder, err: &BckError<'tcx>,
+                                    error_span: &Span) {
+        match err.cmt.note {
+            mc::NoteClosureEnv(upvar_id) | mc::NoteUpvarRef(upvar_id) => {
+                // If this is an `Fn` closure, it simply can't mutate upvars.
+                // If it's an `FnMut` closure, the original variable was declared immutable.
+                // We need to determine which is the case here.
+                let kind = match err.cmt.upvar().unwrap().cat {
+                    Categorization::Upvar(mc::Upvar { kind, .. }) => kind,
+                    _ => bug!()
+                };
+                if kind == ty::ClosureKind::Fn {
+                    db.span_help(self.tcx.map.span(upvar_id.closure_expr_id),
+                                 "consider changing this closure to take \
+                                 self by mutable reference");
+                }
+            }
+            _ => {
+                if let Categorization::Deref(ref inner_cmt, ..) = err.cmt.cat {
+                    if let Categorization::Local(local_id) = inner_cmt.cat {
+                        let parent = self.tcx.map.get_parent_node(local_id);
+                        let opt_fn_decl = FnLikeNode::from_node(self.tcx.map.get(parent))
+                            .map(|fn_like| fn_like.decl());
+
+                        if let Some(fn_decl) = opt_fn_decl {
+                            if let Some(ref arg) = fn_decl.inputs.iter()
+                                .find(|ref arg| arg.pat.id == local_id) {
+                                if let hir::TyRptr(
+                                    opt_lifetime,
+                                    hir::MutTy{mutbl: hir::Mutability::MutImmutable, ref ty}) =
+                                    arg.ty.node {
+                                    if let Some(lifetime) = opt_lifetime {
+                                        if let Ok(snippet) = self.tcx.sess.codemap()
+                                            .span_to_snippet(ty.span) {
+                                            if let Ok(lifetime_snippet) = self.tcx.sess.codemap()
+                                                .span_to_snippet(lifetime.span) {
+                                                    db.span_label(arg.ty.span,
+                                                                  &format!("use `&{} mut {}` \
+                                                                            here to make mutable",
+                                                                            lifetime_snippet,
+                                                                            snippet));
+                                            }
+                                        }
+                                    }
+                                    else if let Ok(snippet) = self.tcx.sess.codemap()
+                                        .span_to_snippet(arg.ty.span) {
+                                        if snippet.starts_with("&") {
+                                            db.span_label(arg.ty.span,
+                                                          &format!("use `{}` here to make mutable",
+                                                                   snippet.replace("&", "&mut ")));
+                                        }
+                                    }
+                                }
+                            }
+                        }
+                    }
+                } else if let Categorization::Local(local_id) = err.cmt.cat {
+                    let span = self.tcx.map.span(local_id);
+                    if let Ok(snippet) = self.tcx.sess.codemap().span_to_snippet(span) {
+                        if snippet.starts_with("ref mut ") || snippet.starts_with("&mut ") {
+                            db.span_label(*error_span, &format!("cannot reborrow mutably"));
+                            db.span_label(*error_span, &format!("try removing `&mut` here"));
+                        } else {
+                            if snippet.starts_with("ref ") {
+                                db.span_label(span, &format!("use `{}` here to make mutable",
+                                                             snippet.replace("ref ", "ref mut ")));
+                            } else if snippet != "self" {
+                                db.span_label(span,
+                                              &format!("use `mut {}` here to make mutable",
+                                                       snippet));
+                            }
+                            db.span_label(*error_span, &format!("cannot borrow mutably"));
+                        }
+                    } else {
+                        db.span_label(*error_span, &format!("cannot borrow mutably"));
+                    }
+                }
+            }
+        }
+    }
     pub fn append_loan_path_to_string(&self,
                                       loan_path: &LoanPath<'tcx>,
                                       out: &mut String) {
diff --git a/src/test/compile-fail/borrowck/borrowck-borrow-overloaded-auto-deref-mut.rs b/src/test/ui/span/borrowck-borrow-overloaded-auto-deref-mut.rs
index 764d05be879..764d05be879 100644
--- a/src/test/compile-fail/borrowck/borrowck-borrow-overloaded-auto-deref-mut.rs
+++ b/src/test/ui/span/borrowck-borrow-overloaded-auto-deref-mut.rs
diff --git a/src/test/ui/span/borrowck-borrow-overloaded-auto-deref-mut.stderr b/src/test/ui/span/borrowck-borrow-overloaded-auto-deref-mut.stderr
new file mode 100644
index 00000000000..1109351bff8
--- /dev/null
+++ b/src/test/ui/span/borrowck-borrow-overloaded-auto-deref-mut.stderr
@@ -0,0 +1,86 @@
+error: cannot borrow immutable argument `x` as mutable
+  --> $DIR/borrowck-borrow-overloaded-auto-deref-mut.rs:63:24
+   |
+62 | fn deref_mut_field1(x: Own<Point>) {
+   |                     - use `mut x` here to make mutable
+63 |     let __isize = &mut x.y; //~ ERROR cannot borrow
+   |                        ^ cannot borrow mutably
+
+error: cannot borrow immutable borrowed content `*x` as mutable
+  --> $DIR/borrowck-borrow-overloaded-auto-deref-mut.rs:75:10
+   |
+74 | fn deref_extend_mut_field1(x: &Own<Point>) -> &mut isize {
+   |                               ----------- use `&mut Own<Point>` here to make mutable
+75 |     &mut x.y //~ ERROR cannot borrow
+   |          ^
+
+error[E0499]: cannot borrow `*x` as mutable more than once at a time
+  --> $DIR/borrowck-borrow-overloaded-auto-deref-mut.rs:88:19
+   |
+87 |     let _x = &mut x.x;
+   |                   - first mutable borrow occurs here
+88 |     let _y = &mut x.y; //~ ERROR cannot borrow
+   |                   ^ second mutable borrow occurs here
+89 | }
+   | - first borrow ends here
+
+error: cannot borrow immutable argument `x` as mutable
+  --> $DIR/borrowck-borrow-overloaded-auto-deref-mut.rs:98:5
+   |
+97 | fn assign_field1<'a>(x: Own<Point>) {
+   |                      - use `mut x` here to make mutable
+98 |     x.y = 3; //~ ERROR cannot borrow
+   |     ^ cannot borrow mutably
+
+error: cannot borrow immutable borrowed content `*x` as mutable
+   --> $DIR/borrowck-borrow-overloaded-auto-deref-mut.rs:102:5
+    |
+101 | fn assign_field2<'a>(x: &'a Own<Point>) {
+    |                         -------------- use `&'a mut Own<Point>` here to make mutable
+102 |     x.y = 3; //~ ERROR cannot borrow
+    |     ^
+
+error[E0499]: cannot borrow `*x` as mutable more than once at a time
+   --> $DIR/borrowck-borrow-overloaded-auto-deref-mut.rs:111:5
+    |
+110 |     let _p: &mut Point = &mut **x;
+    |                                -- first mutable borrow occurs here
+111 |     x.y = 3; //~ ERROR cannot borrow
+    |     ^ second mutable borrow occurs here
+112 | }
+    | - first borrow ends here
+
+error: cannot borrow immutable argument `x` as mutable
+   --> $DIR/borrowck-borrow-overloaded-auto-deref-mut.rs:119:5
+    |
+118 | fn deref_mut_method1(x: Own<Point>) {
+    |                      - use `mut x` here to make mutable
+119 |     x.set(0, 0); //~ ERROR cannot borrow
+    |     ^ cannot borrow mutably
+
+error: cannot borrow immutable borrowed content `*x` as mutable
+   --> $DIR/borrowck-borrow-overloaded-auto-deref-mut.rs:131:5
+    |
+130 | fn deref_extend_mut_method1(x: &Own<Point>) -> &mut isize {
+    |                                ----------- use `&mut Own<Point>` here to make mutable
+131 |     x.y_mut() //~ ERROR cannot borrow
+    |     ^
+
+error: cannot borrow immutable argument `x` as mutable
+   --> $DIR/borrowck-borrow-overloaded-auto-deref-mut.rs:139:6
+    |
+138 | fn assign_method1<'a>(x: Own<Point>) {
+    |                       - use `mut x` here to make mutable
+139 |     *x.y_mut() = 3; //~ ERROR cannot borrow
+    |      ^ cannot borrow mutably
+
+error: cannot borrow immutable borrowed content `*x` as mutable
+   --> $DIR/borrowck-borrow-overloaded-auto-deref-mut.rs:143:6
+    |
+142 | fn assign_method2<'a>(x: &'a Own<Point>) {
+    |                          -------------- use `&'a mut Own<Point>` here to make mutable
+143 |     *x.y_mut() = 3; //~ ERROR cannot borrow
+    |      ^
+
+error: aborting due to 10 previous errors
+
diff --git a/src/test/compile-fail/borrowck/borrowck-borrow-overloaded-deref-mut.rs b/src/test/ui/span/borrowck-borrow-overloaded-deref-mut.rs
index 34b926aab1f..34b926aab1f 100644
--- a/src/test/compile-fail/borrowck/borrowck-borrow-overloaded-deref-mut.rs
+++ b/src/test/ui/span/borrowck-borrow-overloaded-deref-mut.rs
diff --git a/src/test/ui/span/borrowck-borrow-overloaded-deref-mut.stderr b/src/test/ui/span/borrowck-borrow-overloaded-deref-mut.stderr
new file mode 100644
index 00000000000..a5b70459161
--- /dev/null
+++ b/src/test/ui/span/borrowck-borrow-overloaded-deref-mut.stderr
@@ -0,0 +1,34 @@
+error: cannot borrow immutable argument `x` as mutable
+  --> $DIR/borrowck-borrow-overloaded-deref-mut.rs:39:25
+   |
+38 | fn deref_mut1(x: Own<isize>) {
+   |               - use `mut x` here to make mutable
+39 |     let __isize = &mut *x; //~ ERROR cannot borrow
+   |                         ^ cannot borrow mutably
+
+error: cannot borrow immutable borrowed content `*x` as mutable
+  --> $DIR/borrowck-borrow-overloaded-deref-mut.rs:51:11
+   |
+50 | fn deref_extend_mut1<'a>(x: &'a Own<isize>) -> &'a mut isize {
+   |                             -------------- use `&'a mut Own<isize>` here to make mutable
+51 |     &mut **x //~ ERROR cannot borrow
+   |           ^^
+
+error: cannot borrow immutable argument `x` as mutable
+  --> $DIR/borrowck-borrow-overloaded-deref-mut.rs:59:6
+   |
+58 | fn assign1<'a>(x: Own<isize>) {
+   |                - use `mut x` here to make mutable
+59 |     *x = 3; //~ ERROR cannot borrow
+   |      ^ cannot borrow mutably
+
+error: cannot borrow immutable borrowed content `*x` as mutable
+  --> $DIR/borrowck-borrow-overloaded-deref-mut.rs:63:6
+   |
+62 | fn assign2<'a>(x: &'a Own<isize>) {
+   |                   -------------- use `&'a mut Own<isize>` here to make mutable
+63 |     **x = 3; //~ ERROR cannot borrow
+   |      ^^
+
+error: aborting due to 4 previous errors
+
diff --git a/src/test/compile-fail/borrowck/borrowck-call-is-borrow-issue-12224.rs b/src/test/ui/span/borrowck-call-is-borrow-issue-12224.rs
index ba1ae64ec33..ba1ae64ec33 100644
--- a/src/test/compile-fail/borrowck/borrowck-call-is-borrow-issue-12224.rs
+++ b/src/test/ui/span/borrowck-call-is-borrow-issue-12224.rs
diff --git a/src/test/ui/span/borrowck-call-is-borrow-issue-12224.stderr b/src/test/ui/span/borrowck-call-is-borrow-issue-12224.stderr
new file mode 100644
index 00000000000..16bb6001367
--- /dev/null
+++ b/src/test/ui/span/borrowck-call-is-borrow-issue-12224.stderr
@@ -0,0 +1,43 @@
+error[E0499]: cannot borrow `f` as mutable more than once at a time
+  --> $DIR/borrowck-call-is-borrow-issue-12224.rs:23:16
+   |
+23 |     f(Box::new(|| {
+   |     -          ^^ second mutable borrow occurs here
+   |     |
+   |     first mutable borrow occurs here
+24 |     //~^ ERROR: cannot borrow `f` as mutable more than once
+25 |         f((Box::new(|| {})))
+   |         - borrow occurs due to use of `f` in closure
+26 |     }));
+   |       - first borrow ends here
+
+error: cannot borrow immutable borrowed content `*f` as mutable
+  --> $DIR/borrowck-call-is-borrow-issue-12224.rs:36:5
+   |
+35 | fn test2<F>(f: &F) where F: FnMut() {
+   |                -- use `&mut F` here to make mutable
+36 |     (*f)(); //~ ERROR: cannot borrow immutable borrowed content `*f` as mutable
+   |     ^^^^
+
+error: cannot borrow immutable `Box` content `*f.f` as mutable
+  --> $DIR/borrowck-call-is-borrow-issue-12224.rs:44:5
+   |
+44 |     f.f.call_mut(()) //~ ERROR: cannot borrow immutable `Box` content `*f.f` as mutable
+   |     ^^^
+
+error[E0504]: cannot move `f` into closure because it is borrowed
+  --> $DIR/borrowck-call-is-borrow-issue-12224.rs:63:13
+   |
+62 |     f(Box::new(|a| {
+   |     - borrow of `f` occurs here
+63 |         foo(f);
+   |             ^ move into closure occurs here
+
+error[E0507]: cannot move out of captured outer variable in an `FnMut` closure
+  --> $DIR/borrowck-call-is-borrow-issue-12224.rs:63:13
+   |
+63 |         foo(f);
+   |             ^ cannot move out of captured outer variable in an `FnMut` closure
+
+error: aborting due to 5 previous errors
+
diff --git a/src/test/compile-fail/borrowck/borrowck-call-method-from-mut-aliasable.rs b/src/test/ui/span/borrowck-call-method-from-mut-aliasable.rs
index bc0b667e895..bc0b667e895 100644
--- a/src/test/compile-fail/borrowck/borrowck-call-method-from-mut-aliasable.rs
+++ b/src/test/ui/span/borrowck-call-method-from-mut-aliasable.rs
diff --git a/src/test/ui/span/borrowck-call-method-from-mut-aliasable.stderr b/src/test/ui/span/borrowck-call-method-from-mut-aliasable.stderr
new file mode 100644
index 00000000000..a1af1ca7408
--- /dev/null
+++ b/src/test/ui/span/borrowck-call-method-from-mut-aliasable.stderr
@@ -0,0 +1,11 @@
+error: cannot borrow immutable borrowed content `*x` as mutable
+  --> $DIR/borrowck-call-method-from-mut-aliasable.rs:27:5
+   |
+25 | fn b(x: &Foo) {
+   |         ---- use `&mut Foo` here to make mutable
+26 |     x.f();
+27 |     x.h(); //~ ERROR cannot borrow
+   |     ^
+
+error: aborting due to previous error
+
diff --git a/src/test/compile-fail/borrowck/borrowck-fn-in-const-b.rs b/src/test/ui/span/borrowck-fn-in-const-b.rs
index 7e29b2ee0fd..7e29b2ee0fd 100644
--- a/src/test/compile-fail/borrowck/borrowck-fn-in-const-b.rs
+++ b/src/test/ui/span/borrowck-fn-in-const-b.rs
diff --git a/src/test/ui/span/borrowck-fn-in-const-b.stderr b/src/test/ui/span/borrowck-fn-in-const-b.stderr
new file mode 100644
index 00000000000..41f549c708a
--- /dev/null
+++ b/src/test/ui/span/borrowck-fn-in-const-b.stderr
@@ -0,0 +1,10 @@
+error: cannot borrow immutable borrowed content `*x` as mutable
+  --> $DIR/borrowck-fn-in-const-b.rs:17:9
+   |
+16 |     fn broken(x: &Vec<String>) {
+   |                  ------------ use `&mut Vec<String>` here to make mutable
+17 |         x.push(format!("this is broken"));
+   |         ^
+
+error: aborting due to previous error
+
diff --git a/src/test/compile-fail/borrowck/borrowck-object-mutability.rs b/src/test/ui/span/borrowck-object-mutability.rs
index 1bdc32b0975..1bdc32b0975 100644
--- a/src/test/compile-fail/borrowck/borrowck-object-mutability.rs
+++ b/src/test/ui/span/borrowck-object-mutability.rs
diff --git a/src/test/ui/span/borrowck-object-mutability.stderr b/src/test/ui/span/borrowck-object-mutability.stderr
new file mode 100644
index 00000000000..32e4da18056
--- /dev/null
+++ b/src/test/ui/span/borrowck-object-mutability.stderr
@@ -0,0 +1,17 @@
+error: cannot borrow immutable borrowed content `*x` as mutable
+  --> $DIR/borrowck-object-mutability.rs:19:5
+   |
+17 | fn borrowed_receiver(x: &Foo) {
+   |                         ---- use `&mut Foo` here to make mutable
+18 |     x.borrowed();
+19 |     x.borrowed_mut(); //~ ERROR cannot borrow
+   |     ^
+
+error: cannot borrow immutable `Box` content `*x` as mutable
+  --> $DIR/borrowck-object-mutability.rs:29:5
+   |
+29 |     x.borrowed_mut(); //~ ERROR cannot borrow
+   |     ^
+
+error: aborting due to 2 previous errors
+
diff --git a/src/test/ui/span/mut-arg-hint.rs b/src/test/ui/span/mut-arg-hint.rs
new file mode 100644
index 00000000000..296ee6ca10e
--- /dev/null
+++ b/src/test/ui/span/mut-arg-hint.rs
@@ -0,0 +1,32 @@
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+trait B {
+    fn foo(mut a: &String) {
+        a.push_str("bar");
+    }
+}
+
+pub fn foo<'a>(mut a: &'a String) {
+    a.push_str("foo");
+}
+
+struct A {}
+
+impl A {
+    pub fn foo(mut a: &String) {
+        a.push_str("foo");
+    }
+}
+
+fn main() {
+    foo(&"a".to_string());
+    A::foo(&"a".to_string());
+}
diff --git a/src/test/ui/span/mut-arg-hint.stderr b/src/test/ui/span/mut-arg-hint.stderr
new file mode 100644
index 00000000000..5e9a0b91503
--- /dev/null
+++ b/src/test/ui/span/mut-arg-hint.stderr
@@ -0,0 +1,26 @@
+error: cannot borrow immutable borrowed content `*a` as mutable
+  --> $DIR/mut-arg-hint.rs:13:9
+   |
+12 |     fn foo(mut a: &String) {
+   |                   ------- use `&mut String` here to make mutable
+13 |         a.push_str("bar");
+   |         ^
+
+error: cannot borrow immutable borrowed content `*a` as mutable
+  --> $DIR/mut-arg-hint.rs:18:5
+   |
+17 | pub fn foo<'a>(mut a: &'a String) {
+   |                       ---------- use `&'a mut String` here to make mutable
+18 |     a.push_str("foo");
+   |     ^
+
+error: cannot borrow immutable borrowed content `*a` as mutable
+  --> $DIR/mut-arg-hint.rs:25:9
+   |
+24 |     pub fn foo(mut a: &String) {
+   |                       ------- use `&mut String` here to make mutable
+25 |         a.push_str("foo");
+   |         ^
+
+error: aborting due to 3 previous errors
+