about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
authorCorey Farwell <coreyf@rwell.org>2017-03-29 08:57:06 -0400
committerGitHub <noreply@github.com>2017-03-29 08:57:06 -0400
commita63b1dfa34cac58c8a19776dee7bfc54bd2e80f5 (patch)
tree782376996e2ff71f913524f13a6baad7b8eded61 /src
parent96dd9a9d27fdb59bad8ad545e96ecacad5dec8e6 (diff)
parent39011f8590b69d5ee9037c4ac9b863a516ae2e1e (diff)
downloadrust-a63b1dfa34cac58c8a19776dee7bfc54bd2e80f5.tar.gz
rust-a63b1dfa34cac58c8a19776dee7bfc54bd2e80f5.zip
Rollup merge of #40841 - arielb1:immutable-blame, r=pnkfelix
borrowck: consolidate `mut` suggestions

This converts all of borrowck's `mut` suggestions to a new
`mc::ImmutabilityBlame` API instead of the current mix of various hacks.

Fixes #35937.
Fixes #40823.
Fixes #40859.

cc @estebank
r? @pnkfelix
Diffstat (limited to 'src')
-rw-r--r--src/librustc/hir/lowering.rs7
-rw-r--r--src/librustc/hir/mod.rs3
-rw-r--r--src/librustc/middle/mem_categorization.rs140
-rw-r--r--src/librustc_borrowck/borrowck/gather_loans/mod.rs9
-rw-r--r--src/librustc_borrowck/borrowck/mod.rs248
-rw-r--r--src/librustc_borrowck/diagnostics.rs6
-rw-r--r--src/test/compile-fail/augmented-assignments.rs2
-rw-r--r--src/test/compile-fail/borrowck/borrowck-issue-14498.rs6
-rw-r--r--src/test/compile-fail/issue-33819.rs2
-rw-r--r--src/test/compile-fail/mut-suggestion.rs4
-rw-r--r--src/test/ui/codemap_tests/huge_multispan_highlight.stderr2
-rw-r--r--src/test/ui/did_you_mean/issue-31424.stderr2
-rw-r--r--src/test/ui/did_you_mean/issue-35937.rs31
-rw-r--r--src/test/ui/did_you_mean/issue-35937.stderr26
-rw-r--r--src/test/ui/did_you_mean/issue-38147-2.stderr2
-rw-r--r--src/test/ui/did_you_mean/issue-38147-3.stderr4
-rw-r--r--src/test/ui/did_you_mean/issue-39544.rs35
-rw-r--r--src/test/ui/did_you_mean/issue-39544.stderr86
-rw-r--r--src/test/ui/did_you_mean/issue-40823.rs14
-rw-r--r--src/test/ui/did_you_mean/issue-40823.stderr8
-rw-r--r--src/test/ui/span/borrowck-borrow-overloaded-auto-deref-mut.stderr8
-rw-r--r--src/test/ui/span/borrowck-borrow-overloaded-deref-mut.stderr4
-rw-r--r--src/test/ui/span/borrowck-object-mutability.stderr3
23 files changed, 427 insertions, 225 deletions
diff --git a/src/librustc/hir/lowering.rs b/src/librustc/hir/lowering.rs
index 6ca0c971ea4..f9b740235f4 100644
--- a/src/librustc/hir/lowering.rs
+++ b/src/librustc/hir/lowering.rs
@@ -907,6 +907,13 @@ impl<'a> LoweringContext<'a> {
                 FunctionRetTy::Default(span) => hir::DefaultReturn(span),
             },
             variadic: decl.variadic,
+            has_implicit_self: decl.inputs.get(0).map_or(false, |arg| {
+                match arg.ty.node {
+                    TyKind::ImplicitSelf => true,
+                    TyKind::Rptr(_, ref mt) => mt.ty.node == TyKind::ImplicitSelf,
+                    _ => false
+                }
+            })
         })
     }
 
diff --git a/src/librustc/hir/mod.rs b/src/librustc/hir/mod.rs
index f4f2f4cf921..27fa7487270 100644
--- a/src/librustc/hir/mod.rs
+++ b/src/librustc/hir/mod.rs
@@ -1383,6 +1383,9 @@ pub struct FnDecl {
     pub inputs: HirVec<P<Ty>>,
     pub output: FunctionRetTy,
     pub variadic: bool,
+    /// True if this function has an `self`, `&self` or `&mut self` receiver
+    /// (but not a `self: Xxx` one).
+    pub has_implicit_self: bool,
 }
 
 #[derive(Copy, Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)]
diff --git a/src/librustc/middle/mem_categorization.rs b/src/librustc/middle/mem_categorization.rs
index 0cf53826dd4..3b52e85e08e 100644
--- a/src/librustc/middle/mem_categorization.rs
+++ b/src/librustc/middle/mem_categorization.rs
@@ -194,76 +194,75 @@ pub struct cmt_<'tcx> {
 
 pub type cmt<'tcx> = Rc<cmt_<'tcx>>;
 
+pub enum ImmutabilityBlame<'tcx> {
+    ImmLocal(ast::NodeId),
+    ClosureEnv(ast::NodeId),
+    LocalDeref(ast::NodeId),
+    AdtFieldDeref(&'tcx ty::AdtDef, &'tcx ty::FieldDef)
+}
+
 impl<'tcx> cmt_<'tcx> {
-    pub fn get_def(&self) -> Option<ast::NodeId> {
-        match self.cat {
-            Categorization::Deref(ref cmt, ..) |
-            Categorization::Interior(ref cmt, _) |
-            Categorization::Downcast(ref cmt, _) => {
-                if let Categorization::Local(nid) = cmt.cat {
-                    Some(nid)
-                } else {
-                    None
-                }
+    fn resolve_field(&self, field_name: FieldName) -> (&'tcx ty::AdtDef, &'tcx ty::FieldDef)
+    {
+        let adt_def = self.ty.ty_adt_def().unwrap_or_else(|| {
+            bug!("interior cmt {:?} is not an ADT", self)
+        });
+        let variant_def = match self.cat {
+            Categorization::Downcast(_, variant_did) => {
+                adt_def.variant_with_id(variant_did)
             }
-            _ => None
-        }
+            _ => {
+                assert!(adt_def.is_univariant());
+                &adt_def.variants[0]
+            }
+        };
+        let field_def = match field_name {
+            NamedField(name) => variant_def.field_named(name),
+            PositionalField(idx) => &variant_def.fields[idx]
+        };
+        (adt_def, field_def)
     }
 
-    pub fn get_field(&self, name: ast::Name) -> Option<DefId> {
+    pub fn immutability_blame(&self) -> Option<ImmutabilityBlame<'tcx>> {
         match self.cat {
-            Categorization::Deref(ref cmt, ..) |
-            Categorization::Interior(ref cmt, _) |
-            Categorization::Downcast(ref cmt, _) => {
-                if let Categorization::Local(_) = cmt.cat {
-                    if let ty::TyAdt(def, _) = self.ty.sty {
-                        if def.is_struct() {
-                            return def.struct_variant().find_field_named(name).map(|x| x.did);
+            Categorization::Deref(ref base_cmt, _, BorrowedPtr(ty::ImmBorrow, _)) |
+            Categorization::Deref(ref base_cmt, _, Implicit(ty::ImmBorrow, _)) => {
+                // try to figure out where the immutable reference came from
+                match base_cmt.cat {
+                    Categorization::Local(node_id) =>
+                        Some(ImmutabilityBlame::LocalDeref(node_id)),
+                    Categorization::Interior(ref base_cmt, InteriorField(field_name)) => {
+                        let (adt_def, field_def) = base_cmt.resolve_field(field_name);
+                        Some(ImmutabilityBlame::AdtFieldDeref(adt_def, field_def))
+                    }
+                    Categorization::Upvar(Upvar { id, .. }) => {
+                        if let NoteClosureEnv(..) = self.note {
+                            Some(ImmutabilityBlame::ClosureEnv(id.closure_expr_id))
+                        } else {
+                            None
                         }
                     }
-                    None
-                } else {
-                    cmt.get_field(name)
+                    _ => None
                 }
             }
-            _ => None
-        }
-    }
-
-    pub fn get_field_name(&self) -> Option<ast::Name> {
-        match self.cat {
-            Categorization::Interior(_, ref ik) => {
-                if let InteriorKind::InteriorField(FieldName::NamedField(name)) = *ik {
-                    Some(name)
-                } else {
-                    None
-                }
+            Categorization::Local(node_id) => {
+                Some(ImmutabilityBlame::ImmLocal(node_id))
             }
-            Categorization::Deref(ref cmt, ..) |
-            Categorization::Downcast(ref cmt, _) => {
-                cmt.get_field_name()
+            Categorization::Rvalue(..) |
+            Categorization::Upvar(..) |
+            Categorization::Deref(.., UnsafePtr(..)) => {
+                // This should not be reachable up to inference limitations.
+                None
             }
-            _ => None,
-        }
-    }
-
-    pub fn get_arg_if_immutable(&self, map: &hir_map::Map) -> Option<ast::NodeId> {
-        match self.cat {
-            Categorization::Deref(ref cmt, ..) |
-            Categorization::Interior(ref cmt, _) |
-            Categorization::Downcast(ref cmt, _) => {
-                if let Categorization::Local(nid) = cmt.cat {
-                    if let ty::TyAdt(_, _) = self.ty.sty {
-                        if let ty::TyRef(_, ty::TypeAndMut{mutbl: MutImmutable, ..}) = cmt.ty.sty {
-                            return Some(nid);
-                        }
-                    }
-                    None
-                } else {
-                    cmt.get_arg_if_immutable(map)
-                }
+            Categorization::Interior(ref base_cmt, _) |
+            Categorization::Downcast(ref base_cmt, _) |
+            Categorization::Deref(ref base_cmt, _, _) => {
+                base_cmt.immutability_blame()
+            }
+            Categorization::StaticItem => {
+                // Do we want to do something here?
+                None
             }
-            _ => None
         }
     }
 }
@@ -1282,9 +1281,6 @@ pub enum Aliasability {
 #[derive(Copy, Clone, Debug)]
 pub enum AliasableReason {
     AliasableBorrowed,
-    AliasableClosure(ast::NodeId), // Aliasable due to capture Fn closure env
-    AliasableOther,
-    UnaliasableImmutable, // Created as needed upon seeing ImmutableUnique
     AliasableStatic,
     AliasableStaticMut,
 }
@@ -1324,23 +1320,13 @@ impl<'tcx> cmt_<'tcx> {
             Categorization::Deref(ref b, _, Implicit(ty::MutBorrow, _)) |
             Categorization::Deref(ref b, _, BorrowedPtr(ty::UniqueImmBorrow, _)) |
             Categorization::Deref(ref b, _, Implicit(ty::UniqueImmBorrow, _)) |
+            Categorization::Deref(ref b, _, Unique) |
             Categorization::Downcast(ref b, _) |
             Categorization::Interior(ref b, _) => {
                 // Aliasability depends on base cmt
                 b.freely_aliasable()
             }
 
-            Categorization::Deref(ref b, _, Unique) => {
-                let sub = b.freely_aliasable();
-                if b.mutbl.is_mutable() {
-                    // Aliasability depends on base cmt alone
-                    sub
-                } else {
-                    // Do not allow mutation through an immutable box.
-                    ImmutableUnique(Box::new(sub))
-                }
-            }
-
             Categorization::Rvalue(..) |
             Categorization::Local(..) |
             Categorization::Upvar(..) |
@@ -1356,13 +1342,9 @@ impl<'tcx> cmt_<'tcx> {
                 }
             }
 
-            Categorization::Deref(ref base, _, BorrowedPtr(ty::ImmBorrow, _)) |
-            Categorization::Deref(ref base, _, Implicit(ty::ImmBorrow, _)) => {
-                match base.cat {
-                    Categorization::Upvar(Upvar{ id, .. }) =>
-                        FreelyAliasable(AliasableClosure(id.closure_expr_id)),
-                    _ => FreelyAliasable(AliasableBorrowed)
-                }
+            Categorization::Deref(_, _, BorrowedPtr(ty::ImmBorrow, _)) |
+            Categorization::Deref(_, _, Implicit(ty::ImmBorrow, _)) => {
+                FreelyAliasable(AliasableBorrowed)
             }
         }
     }
diff --git a/src/librustc_borrowck/borrowck/gather_loans/mod.rs b/src/librustc_borrowck/borrowck/gather_loans/mod.rs
index 28b6c7a13f1..cedb9e1cd1c 100644
--- a/src/librustc_borrowck/borrowck/gather_loans/mod.rs
+++ b/src/librustc_borrowck/borrowck/gather_loans/mod.rs
@@ -188,14 +188,6 @@ fn check_aliasability<'a, 'tcx>(bccx: &BorrowckCtxt<'a, 'tcx>,
             // user knows what they're doing in these cases.
             Ok(())
         }
-        (mc::Aliasability::ImmutableUnique(_), ty::MutBorrow) => {
-            bccx.report_aliasability_violation(
-                        borrow_span,
-                        loan_cause,
-                        mc::AliasableReason::UnaliasableImmutable,
-                        cmt);
-            Err(())
-        }
         (mc::Aliasability::FreelyAliasable(alias_cause), ty::UniqueImmBorrow) |
         (mc::Aliasability::FreelyAliasable(alias_cause), ty::MutBorrow) => {
             bccx.report_aliasability_violation(
@@ -510,4 +502,3 @@ impl<'a, 'tcx> GatherLoanCtxt<'a, 'tcx> {
         self.move_error_collector.report_potential_errors(self.bccx);
     }
 }
-
diff --git a/src/librustc_borrowck/borrowck/mod.rs b/src/librustc_borrowck/borrowck/mod.rs
index 59c3e68aada..0915c57b588 100644
--- a/src/librustc_borrowck/borrowck/mod.rs
+++ b/src/librustc_borrowck/borrowck/mod.rs
@@ -34,6 +34,7 @@ use rustc::hir::def_id::DefId;
 use rustc::middle::expr_use_visitor as euv;
 use rustc::middle::mem_categorization as mc;
 use rustc::middle::mem_categorization::Categorization;
+use rustc::middle::mem_categorization::ImmutabilityBlame;
 use rustc::middle::region;
 use rustc::ty::{self, TyCtxt};
 
@@ -659,12 +660,10 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> {
         self.tcx.sess.span_err_with_code(s, msg, code);
     }
 
-    pub fn bckerr_to_diag(&self, err: &BckError<'tcx>) -> DiagnosticBuilder<'a> {
+    fn bckerr_to_diag(&self, err: &BckError<'tcx>) -> DiagnosticBuilder<'a> {
         let span = err.span.clone();
-        let mut immutable_field = None;
-        let mut local_def = None;
 
-        let msg = &match err.code {
+        let msg = match err.code {
             err_mutbl => {
                 let descr = match err.cmt.note {
                     mc::NoteClosureEnv(_) | mc::NoteUpvarRef(_) => {
@@ -700,27 +699,6 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> {
                     BorrowViolation(euv::AutoUnsafe) |
                     BorrowViolation(euv::ForLoop) |
                     BorrowViolation(euv::MatchDiscriminant) => {
-                        // Check for this field's definition to see if it is an immutable reference
-                        // and suggest making it mutable if that is the case.
-                        immutable_field = err.cmt.get_field_name()
-                            .and_then(|name| err.cmt.get_field(name))
-                            .and_then(|did| self.tcx.hir.as_local_node_id(did))
-                            .and_then(|nid| {
-                                if let hir_map::Node::NodeField(ref field) = self.tcx.hir.get(nid) {
-                                    return self.suggest_mut_for_immutable(&field.ty)
-                                        .map(|msg| (self.tcx.hir.span(nid), msg));
-                                }
-                                None
-                            });
-                        local_def = err.cmt.get_def()
-                            .and_then(|nid| {
-                                if !self.tcx.hir.is_argument(nid) {
-                                    Some(self.tcx.hir.span(nid))
-                                } else {
-                                    None
-                                }
-                            });
-
                         format!("cannot borrow {} as mutable", descr)
                     }
                     BorrowViolation(euv::ClosureInvocation) => {
@@ -746,16 +724,7 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> {
             }
         };
 
-        let mut db = self.struct_span_err(span, msg);
-        if let Some((span, msg)) = immutable_field {
-            db.span_label(span, &msg);
-        }
-        if let Some(let_span) = local_def {
-            if let Ok(snippet) = self.tcx.sess.codemap().span_to_snippet(let_span) {
-                db.span_label(let_span, &format!("consider changing this to `mut {}`", snippet));
-            }
-        }
-        db
+        self.struct_span_err(span, &msg)
     }
 
     pub fn report_aliasability_violation(&self,
@@ -788,55 +757,49 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> {
             }
         };
 
-        let mut err = match cause {
-            mc::AliasableOther => {
-                struct_span_err!(
-                    self.tcx.sess, span, E0385,
-                    "{} in an aliasable location", prefix)
-            }
-            mc::AliasableReason::UnaliasableImmutable => {
-                struct_span_err!(
-                    self.tcx.sess, span, E0386,
-                    "{} in an immutable container", prefix)
+        match cause {
+            mc::AliasableStatic |
+            mc::AliasableStaticMut => {
+                // This path cannot occur. It happens when we have an
+                // `&mut` or assignment to a static. But in the case
+                // of `static X`, we get a mutability violation first,
+                // and never get here. In the case of `static mut X`,
+                // that is unsafe and hence the aliasability error is
+                // ignored.
+                span_bug!(span, "aliasability violation for static `{}`", prefix)
             }
-            mc::AliasableClosure(id) => {
+            mc::AliasableBorrowed => {}
+        };
+        let blame = cmt.immutability_blame();
+        let mut err = match blame {
+            Some(ImmutabilityBlame::ClosureEnv(id)) => {
                 let mut err = struct_span_err!(
                     self.tcx.sess, span, E0387,
                     "{} in a captured outer variable in an `Fn` closure", prefix);
-                if let BorrowViolation(euv::ClosureCapture(_)) = kind {
+
+                // FIXME: the distinction between these 2 messages looks wrong.
+                let help = if let BorrowViolation(euv::ClosureCapture(_)) = kind {
                     // The aliasability violation with closure captures can
                     // happen for nested closures, so we know the enclosing
                     // closure incorrectly accepts an `Fn` while it needs to
                     // be `FnMut`.
-                    span_help!(&mut err, self.tcx.hir.span(id),
-                           "consider changing this to accept closures that implement `FnMut`");
+                    "consider changing this to accept closures that implement `FnMut`"
+
                 } else {
-                    span_help!(&mut err, self.tcx.hir.span(id),
-                           "consider changing this closure to take self by mutable reference");
-                }
+                    "consider changing this closure to take self by mutable reference"
+                };
+                err.span_help(self.tcx.hir.span(id), help);
                 err
             }
-            mc::AliasableStatic |
-            mc::AliasableStaticMut => {
-                // This path cannot occur. It happens when we have an
-                // `&mut` or assignment to a static. But in the case
-                // of `static X`, we get a mutability violation first,
-                // and never get here. In the case of `static mut X`,
-                // that is unsafe and hence the aliasability error is
-                // ignored.
-                span_bug!(span, "aliasability violation for static `{}`", prefix)
-            }
-            mc::AliasableBorrowed => {
-                let mut e = struct_span_err!(
+            _ =>  {
+                let mut err = struct_span_err!(
                     self.tcx.sess, span, E0389,
                     "{} in a `&` reference", prefix);
-                e.span_label(span, &"assignment into an immutable reference");
-                if let Some(nid) = cmt.get_arg_if_immutable(&self.tcx.hir) {
-                    self.immutable_argument_should_be_mut(nid, &mut e);
-                }
-                e
+                err.span_label(span, &"assignment into an immutable reference");
+                err
             }
         };
+        self.note_immutability_blame(&mut err, blame);
 
         if is_closure {
             err.help("closures behind references must be called via `&mut`");
@@ -845,49 +808,124 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> {
     }
 
     /// Given a type, if it is an immutable reference, return a suggestion to make it mutable
-    fn suggest_mut_for_immutable(&self, pty: &hir::Ty) -> Option<String> {
+    fn suggest_mut_for_immutable(&self, pty: &hir::Ty, is_implicit_self: bool) -> Option<String> {
         // Check wether the argument is an immutable reference
+        debug!("suggest_mut_for_immutable({:?}, {:?})", pty, is_implicit_self);
         if let hir::TyRptr(lifetime, hir::MutTy {
             mutbl: hir::Mutability::MutImmutable,
             ref ty
         }) = pty.node {
             // Account for existing lifetimes when generating the message
-            if !lifetime.is_elided() {
-                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) {
-                            return Some(format!("use `&{} mut {}` here to make mutable",
-                                                lifetime_snippet,
-                                                snippet));
-                    }
-                }
-            } else if let Ok(snippet) = self.tcx.sess.codemap().span_to_snippet(pty.span) {
-                if snippet.starts_with("&") {
-                    return Some(format!("use `{}` here to make mutable",
-                                        snippet.replace("&", "&mut ")));
-                }
+            let pointee_snippet = match self.tcx.sess.codemap().span_to_snippet(ty.span) {
+                Ok(snippet) => snippet,
+                _ => return None
+            };
+
+            let lifetime_snippet = if !lifetime.is_elided() {
+                format!("{} ", match self.tcx.sess.codemap().span_to_snippet(lifetime.span) {
+                    Ok(lifetime_snippet) => lifetime_snippet,
+                    _ => return None
+                })
             } else {
-                bug!("couldn't find a snippet for span: {:?}", pty.span);
-            }
+                String::new()
+            };
+            Some(format!("use `&{}mut {}` here to make mutable",
+                         lifetime_snippet,
+                         if is_implicit_self { "self" } else { &*pointee_snippet }))
+        } else {
+            None
         }
-        None
     }
 
-    fn immutable_argument_should_be_mut(&self, nid: ast::NodeId, db: &mut DiagnosticBuilder) {
-        let parent = self.tcx.hir.get_parent_node(nid);
+    fn local_binding_mode(&self, node_id: ast::NodeId) -> hir::BindingMode {
+        let pat = match self.tcx.hir.get(node_id) {
+            hir_map::Node::NodeLocal(pat) => pat,
+            node => bug!("bad node for local: {:?}", node)
+        };
+
+        match pat.node {
+            hir::PatKind::Binding(mode, ..) => mode,
+            _ => bug!("local is not a binding: {:?}", pat)
+        }
+    }
+
+    fn local_ty(&self, node_id: ast::NodeId) -> (Option<&hir::Ty>, bool) {
+        let parent = self.tcx.hir.get_parent_node(node_id);
         let parent_node = self.tcx.hir.get(parent);
 
         // The parent node is like a fn
         if let Some(fn_like) = FnLikeNode::from_node(parent_node) {
             // `nid`'s parent's `Body`
             let fn_body = self.tcx.hir.body(fn_like.body());
-            // Get the position of `nid` in the arguments list
-            let arg_pos = fn_body.arguments.iter().position(|arg| arg.pat.id == nid);
+            // Get the position of `node_id` in the arguments list
+            let arg_pos = fn_body.arguments.iter().position(|arg| arg.pat.id == node_id);
             if let Some(i) = arg_pos {
                 // The argument's `Ty`
-                let arg_ty = &fn_like.decl().inputs[i];
-                if let Some(msg) = self.suggest_mut_for_immutable(&arg_ty) {
-                    db.span_label(arg_ty.span, &msg);
+                (Some(&fn_like.decl().inputs[i]),
+                 i == 0 && fn_like.decl().has_implicit_self)
+            } else {
+                (None, false)
+            }
+        } else {
+            (None, false)
+        }
+    }
+
+    fn note_immutability_blame(&self,
+                               db: &mut DiagnosticBuilder,
+                               blame: Option<ImmutabilityBlame>) {
+        match blame {
+            None => {}
+            Some(ImmutabilityBlame::ClosureEnv(_)) => {}
+            Some(ImmutabilityBlame::ImmLocal(node_id)) => {
+                let let_span = self.tcx.hir.span(node_id);
+                if let hir::BindingMode::BindByValue(..) = self.local_binding_mode(node_id) {
+                    if let Ok(snippet) = self.tcx.sess.codemap().span_to_snippet(let_span) {
+                        let (_, is_implicit_self) = self.local_ty(node_id);
+                        if is_implicit_self && snippet != "self" {
+                            // avoid suggesting `mut &self`.
+                            return
+                        }
+                        db.span_label(
+                            let_span,
+                            &format!("consider changing this to `mut {}`", snippet)
+                        );
+                    }
+                }
+            }
+            Some(ImmutabilityBlame::LocalDeref(node_id)) => {
+                let let_span = self.tcx.hir.span(node_id);
+                match self.local_binding_mode(node_id) {
+                    hir::BindingMode::BindByRef(..) => {
+                        let snippet = self.tcx.sess.codemap().span_to_snippet(let_span);
+                        if let Ok(snippet) = snippet {
+                            db.span_label(
+                                let_span,
+                                &format!("consider changing this to `{}`",
+                                         snippet.replace("ref ", "ref mut "))
+                            );
+                        }
+                    }
+                    hir::BindingMode::BindByValue(..) => {
+                        if let (Some(local_ty), is_implicit_self) = self.local_ty(node_id) {
+                            if let Some(msg) =
+                                 self.suggest_mut_for_immutable(local_ty, is_implicit_self) {
+                                db.span_label(local_ty.span, &msg);
+                            }
+                        }
+                    }
+                }
+            }
+            Some(ImmutabilityBlame::AdtFieldDeref(_, field)) => {
+                let node_id = match self.tcx.hir.as_local_node_id(field.did) {
+                    Some(node_id) => node_id,
+                    None => return
+                };
+
+                if let hir_map::Node::NodeField(ref field) = self.tcx.hir.get(node_id) {
+                    if let Some(msg) = self.suggest_mut_for_immutable(&field.ty, false) {
+                        db.span_label(field.ty.span, &msg);
+                    }
                 }
             }
         }
@@ -941,10 +979,13 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> {
         }
     }
 
-    pub fn note_and_explain_bckerr(&self, db: &mut DiagnosticBuilder, err: BckError<'tcx>) {
+    fn note_and_explain_bckerr(&self, db: &mut DiagnosticBuilder, err: BckError<'tcx>) {
         let error_span = err.span.clone();
         match err.code {
-            err_mutbl => self.note_and_explain_mutbl_error(db, &err, &error_span),
+            err_mutbl => {
+                self.note_and_explain_mutbl_error(db, &err, &error_span);
+                self.note_immutability_blame(db, err.cmt.immutability_blame());
+            }
             err_out_of_scope(super_scope, sub_scope, cause) => {
                 let (value_kind, value_msg) = match err.cmt.cat {
                     mc::Categorization::Rvalue(..) =>
@@ -1096,13 +1137,6 @@ before rustc 1.16, this temporary lived longer - see issue #39283 \
             _ => {
                 if let Categorization::Deref(..) = err.cmt.cat {
                     db.span_label(*error_span, &"cannot borrow as mutable");
-                    if let Some(local_id) = err.cmt.get_arg_if_immutable(&self.tcx.hir) {
-                        self.immutable_argument_should_be_mut(local_id, db);
-                    } else if let Categorization::Deref(ref inner_cmt, ..) = err.cmt.cat {
-                        if let Categorization::Local(local_id) = inner_cmt.cat {
-                            self.immutable_argument_should_be_mut(local_id, db);
-                        }
-                    }
                 } else if let Categorization::Local(local_id) = err.cmt.cat {
                     let span = self.tcx.hir.span(local_id);
                     if let Ok(snippet) = self.tcx.sess.codemap().span_to_snippet(span) {
@@ -1110,14 +1144,6 @@ before rustc 1.16, this temporary lived longer - see issue #39283 \
                             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 {
diff --git a/src/librustc_borrowck/diagnostics.rs b/src/librustc_borrowck/diagnostics.rs
index db4a1701e97..bfd342a9f21 100644
--- a/src/librustc_borrowck/diagnostics.rs
+++ b/src/librustc_borrowck/diagnostics.rs
@@ -198,7 +198,7 @@ fn main() {
 ```
 "##,
 
-E0386: r##"
+/*E0386: r##"
 This error occurs when an attempt is made to mutate the target of a mutable
 reference stored inside an immutable container.
 
@@ -228,7 +228,7 @@ let x: i64 = 1;
 let y: Box<Cell<_>> = Box::new(Cell::new(x));
 y.set(2);
 ```
-"##,
+"##,*/
 
 E0387: r##"
 This error occurs when an attempt is made to mutate or mutably reference data
@@ -1117,6 +1117,6 @@ fn main() {
 }
 
 register_diagnostics! {
-    E0385, // {} in an aliasable location
+//    E0385, // {} in an aliasable location
     E0524, // two closures require unique access to `..` at the same time
 }
diff --git a/src/test/compile-fail/augmented-assignments.rs b/src/test/compile-fail/augmented-assignments.rs
index 92a8b10669c..736aa465aa7 100644
--- a/src/test/compile-fail/augmented-assignments.rs
+++ b/src/test/compile-fail/augmented-assignments.rs
@@ -27,7 +27,7 @@ fn main() {
     x;  //~ value moved here
 
     let y = Int(2);
-    //~^use `mut y` here to make mutable
+    //~^ consider changing this to `mut y`
     y   //~ error: cannot borrow immutable local variable `y` as mutable
         //~| cannot borrow
     +=
diff --git a/src/test/compile-fail/borrowck/borrowck-issue-14498.rs b/src/test/compile-fail/borrowck/borrowck-issue-14498.rs
index 64033623fe2..8b7ccedd697 100644
--- a/src/test/compile-fail/borrowck/borrowck-issue-14498.rs
+++ b/src/test/compile-fail/borrowck/borrowck-issue-14498.rs
@@ -23,7 +23,7 @@ fn indirect_write_to_imm_box() {
     let mut x: isize = 1;
     let y: Box<_> = box &mut x;
     let p = &y;
-    ***p = 2; //~ ERROR cannot assign to data in an immutable container
+    ***p = 2; //~ ERROR cannot assign to data in a `&` reference
     drop(p);
 }
 
@@ -43,7 +43,6 @@ fn borrow_in_var_from_var_via_imm_box() {
     let p = &y;
     let q = &***p;
     **y = 2; //~ ERROR cannot assign to `**y` because it is borrowed
-    //~^         ERROR cannot assign to data in an immutable container
     drop(p);
     drop(q);
 }
@@ -64,7 +63,6 @@ fn borrow_in_var_from_field_via_imm_box() {
     let p = &y;
     let q = &***p;
     **y = 2; //~ ERROR cannot assign to `**y` because it is borrowed
-    //~^         ERROR cannot assign to data in an immutable container
     drop(p);
     drop(q);
 }
@@ -85,7 +83,6 @@ fn borrow_in_field_from_var_via_imm_box() {
     let p = &y.a;
     let q = &***p;
     **y.a = 2; //~ ERROR cannot assign to `**y.a` because it is borrowed
-    //~^           ERROR cannot assign to data in an immutable container
     drop(p);
     drop(q);
 }
@@ -106,7 +103,6 @@ fn borrow_in_field_from_field_via_imm_box() {
     let p = &y.a;
     let q = &***p;
     **y.a = 2; //~ ERROR cannot assign to `**y.a` because it is borrowed
-    //~^           ERROR cannot assign to data in an immutable container
     drop(p);
     drop(q);
 }
diff --git a/src/test/compile-fail/issue-33819.rs b/src/test/compile-fail/issue-33819.rs
index 9c9677c1e98..499e7e54947 100644
--- a/src/test/compile-fail/issue-33819.rs
+++ b/src/test/compile-fail/issue-33819.rs
@@ -12,7 +12,7 @@ fn main() {
     match op {
         Some(ref v) => { let a = &mut v; },
         //~^ ERROR:cannot borrow immutable
-        //~| use `ref mut v` here to make mutable
+        //~| cannot borrow mutably
         None => {},
     }
 }
diff --git a/src/test/compile-fail/mut-suggestion.rs b/src/test/compile-fail/mut-suggestion.rs
index 242ad7aee8d..0015c8e5c00 100644
--- a/src/test/compile-fail/mut-suggestion.rs
+++ b/src/test/compile-fail/mut-suggestion.rs
@@ -17,7 +17,7 @@ impl S {
 }
 
 fn func(arg: S) {
-    //~^ here to make mutable
+    //~^ consider changing this to `mut arg`
     arg.mutate();
     //~^ ERROR cannot borrow immutable argument
     //~| cannot borrow mutably
@@ -25,7 +25,7 @@ fn func(arg: S) {
 
 fn main() {
     let local = S;
-    //~^ here to make mutable
+    //~^ consider changing this to `mut local`
     local.mutate();
     //~^ ERROR cannot borrow immutable local variable
     //~| cannot borrow mutably
diff --git a/src/test/ui/codemap_tests/huge_multispan_highlight.stderr b/src/test/ui/codemap_tests/huge_multispan_highlight.stderr
index edbfd72df61..7bb69caa102 100644
--- a/src/test/ui/codemap_tests/huge_multispan_highlight.stderr
+++ b/src/test/ui/codemap_tests/huge_multispan_highlight.stderr
@@ -2,7 +2,7 @@ error: cannot borrow immutable local variable `x` as mutable
    --> $DIR/huge_multispan_highlight.rs:100:18
     |
 12  |     let x = "foo";
-    |         - use `mut x` here to make mutable
+    |         - consider changing this to `mut x`
 ...
 100 |     let y = &mut x;
     |                  ^ cannot borrow mutably
diff --git a/src/test/ui/did_you_mean/issue-31424.stderr b/src/test/ui/did_you_mean/issue-31424.stderr
index 4873acf551e..60fa06d314f 100644
--- a/src/test/ui/did_you_mean/issue-31424.stderr
+++ b/src/test/ui/did_you_mean/issue-31424.stderr
@@ -10,6 +10,8 @@ error: cannot borrow immutable argument `self` as mutable
 error: cannot borrow immutable argument `self` as mutable
   --> $DIR/issue-31424.rs:23:15
    |
+22 |     fn bar(self: &mut Self) {
+   |            ---- consider changing this to `mut self`
 23 |         (&mut self).bar();
    |               ^^^^ cannot borrow mutably
 
diff --git a/src/test/ui/did_you_mean/issue-35937.rs b/src/test/ui/did_you_mean/issue-35937.rs
new file mode 100644
index 00000000000..9ec8728fd32
--- /dev/null
+++ b/src/test/ui/did_you_mean/issue-35937.rs
@@ -0,0 +1,31 @@
+// Copyright 2017 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.
+
+struct Foo {
+    pub v: Vec<String>
+}
+
+fn main() {
+    let f = Foo { v: Vec::new() };
+    f.v.push("cat".to_string());
+}
+
+
+struct S {
+    x: i32,
+}
+fn foo() {
+    let s = S { x: 42 };
+    s.x += 1;
+}
+
+fn bar(s: S) {
+    s.x += 1;
+}
diff --git a/src/test/ui/did_you_mean/issue-35937.stderr b/src/test/ui/did_you_mean/issue-35937.stderr
new file mode 100644
index 00000000000..bea3d129143
--- /dev/null
+++ b/src/test/ui/did_you_mean/issue-35937.stderr
@@ -0,0 +1,26 @@
+error: cannot borrow immutable field `f.v` as mutable
+  --> $DIR/issue-35937.rs:17:5
+   |
+16 |     let f = Foo { v: Vec::new() };
+   |         - consider changing this to `mut f`
+17 |     f.v.push("cat".to_string());
+   |     ^^^ cannot mutably borrow immutable field
+
+error: cannot assign to immutable field `s.x`
+  --> $DIR/issue-35937.rs:26:5
+   |
+25 |     let s = S { x: 42 };
+   |         - consider changing this to `mut s`
+26 |     s.x += 1;
+   |     ^^^^^^^^ cannot mutably borrow immutable field
+
+error: cannot assign to immutable field `s.x`
+  --> $DIR/issue-35937.rs:30:5
+   |
+29 | fn bar(s: S) {
+   |        - consider changing this to `mut s`
+30 |     s.x += 1;
+   |     ^^^^^^^^ cannot mutably borrow immutable field
+
+error: aborting due to 3 previous errors
+
diff --git a/src/test/ui/did_you_mean/issue-38147-2.stderr b/src/test/ui/did_you_mean/issue-38147-2.stderr
index fdaf0cd44d9..855feaf7d2d 100644
--- a/src/test/ui/did_you_mean/issue-38147-2.stderr
+++ b/src/test/ui/did_you_mean/issue-38147-2.stderr
@@ -2,7 +2,7 @@ error: cannot borrow immutable borrowed content `*self.s` as mutable
   --> $DIR/issue-38147-2.rs:17:9
    |
 12 |     s: &'a String
-   |     ------------- use `&'a mut String` here to make mutable
+   |        ---------- use `&'a mut String` here to make mutable
 ...
 17 |         self.s.push('x');
    |         ^^^^^^ cannot borrow as mutable
diff --git a/src/test/ui/did_you_mean/issue-38147-3.stderr b/src/test/ui/did_you_mean/issue-38147-3.stderr
index d2280fa561b..d970d078df8 100644
--- a/src/test/ui/did_you_mean/issue-38147-3.stderr
+++ b/src/test/ui/did_you_mean/issue-38147-3.stderr
@@ -2,10 +2,8 @@ error: cannot borrow immutable borrowed content `*self.s` as mutable
   --> $DIR/issue-38147-3.rs:17:9
    |
 12 |     s: &'a String
-   |     ------------- use `&'a mut String` here to make mutable
+   |        ---------- use `&'a mut String` here to make mutable
 ...
-16 |     fn f(&self) {
-   |          ----- use `&mut self` here to make mutable
 17 |         self.s.push('x');
    |         ^^^^^^ cannot borrow as mutable
 
diff --git a/src/test/ui/did_you_mean/issue-39544.rs b/src/test/ui/did_you_mean/issue-39544.rs
index bcdafefa247..6331fc5771f 100644
--- a/src/test/ui/did_you_mean/issue-39544.rs
+++ b/src/test/ui/did_you_mean/issue-39544.rs
@@ -8,11 +8,11 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-enum X {
+pub enum X {
     Y
 }
 
-struct Z {
+pub struct Z {
     x: X
 }
 
@@ -20,3 +20,34 @@ fn main() {
     let z = Z { x: X::Y };
     let _ = &mut z.x;
 }
+
+impl Z {
+    fn foo<'z>(&'z self) {
+        let _ = &mut self.x;
+    }
+
+    fn foo1(&self, other: &Z) {
+        let _ = &mut self.x;
+        let _ = &mut other.x;
+    }
+
+    fn foo2<'a>(&'a self, other: &Z) {
+        let _ = &mut self.x;
+        let _ = &mut other.x;
+    }
+
+    fn foo3<'a>(self: &'a Self, other: &Z) {
+        let _ = &mut self.x;
+        let _ = &mut other.x;
+    }
+
+    fn foo4(other: &Z) {
+        let _ = &mut other.x;
+    }
+
+}
+
+pub fn with_arg(z: Z, w: &Z) {
+    let _ = &mut z.x;
+    let _ = &mut w.x;
+}
diff --git a/src/test/ui/did_you_mean/issue-39544.stderr b/src/test/ui/did_you_mean/issue-39544.stderr
index 7f124e6d34d..e1e229a8b05 100644
--- a/src/test/ui/did_you_mean/issue-39544.stderr
+++ b/src/test/ui/did_you_mean/issue-39544.stderr
@@ -6,5 +6,89 @@ error: cannot borrow immutable field `z.x` as mutable
 21 |     let _ = &mut z.x;
    |                  ^^^ cannot mutably borrow immutable field
 
-error: aborting due to previous error
+error: cannot borrow immutable field `self.x` as mutable
+  --> $DIR/issue-39544.rs:26:22
+   |
+25 |     fn foo<'z>(&'z self) {
+   |                -------- use `&'z mut self` here to make mutable
+26 |         let _ = &mut self.x;
+   |                      ^^^^^^ cannot mutably borrow immutable field
+
+error: cannot borrow immutable field `self.x` as mutable
+  --> $DIR/issue-39544.rs:30:22
+   |
+29 |     fn foo1(&self, other: &Z) {
+   |             ----- use `&mut self` here to make mutable
+30 |         let _ = &mut self.x;
+   |                      ^^^^^^ cannot mutably borrow immutable field
+
+error: cannot borrow immutable field `other.x` as mutable
+  --> $DIR/issue-39544.rs:31:22
+   |
+29 |     fn foo1(&self, other: &Z) {
+   |                           -- use `&mut Z` here to make mutable
+30 |         let _ = &mut self.x;
+31 |         let _ = &mut other.x;
+   |                      ^^^^^^^ cannot mutably borrow immutable field
+
+error: cannot borrow immutable field `self.x` as mutable
+  --> $DIR/issue-39544.rs:35:22
+   |
+34 |     fn foo2<'a>(&'a self, other: &Z) {
+   |                 -------- use `&'a mut self` here to make mutable
+35 |         let _ = &mut self.x;
+   |                      ^^^^^^ cannot mutably borrow immutable field
+
+error: cannot borrow immutable field `other.x` as mutable
+  --> $DIR/issue-39544.rs:36:22
+   |
+34 |     fn foo2<'a>(&'a self, other: &Z) {
+   |                                  -- use `&mut Z` here to make mutable
+35 |         let _ = &mut self.x;
+36 |         let _ = &mut other.x;
+   |                      ^^^^^^^ cannot mutably borrow immutable field
+
+error: cannot borrow immutable field `self.x` as mutable
+  --> $DIR/issue-39544.rs:40:22
+   |
+39 |     fn foo3<'a>(self: &'a Self, other: &Z) {
+   |                       -------- use `&'a mut Self` here to make mutable
+40 |         let _ = &mut self.x;
+   |                      ^^^^^^ cannot mutably borrow immutable field
+
+error: cannot borrow immutable field `other.x` as mutable
+  --> $DIR/issue-39544.rs:41:22
+   |
+39 |     fn foo3<'a>(self: &'a Self, other: &Z) {
+   |                                        -- use `&mut Z` here to make mutable
+40 |         let _ = &mut self.x;
+41 |         let _ = &mut other.x;
+   |                      ^^^^^^^ cannot mutably borrow immutable field
+
+error: cannot borrow immutable field `other.x` as mutable
+  --> $DIR/issue-39544.rs:45:22
+   |
+44 |     fn foo4(other: &Z) {
+   |                    -- use `&mut Z` here to make mutable
+45 |         let _ = &mut other.x;
+   |                      ^^^^^^^ cannot mutably borrow immutable field
+
+error: cannot borrow immutable field `z.x` as mutable
+  --> $DIR/issue-39544.rs:51:18
+   |
+50 | pub fn with_arg(z: Z, w: &Z) {
+   |                 - consider changing this to `mut z`
+51 |     let _ = &mut z.x;
+   |                  ^^^ cannot mutably borrow immutable field
+
+error: cannot borrow immutable field `w.x` as mutable
+  --> $DIR/issue-39544.rs:52:18
+   |
+50 | pub fn with_arg(z: Z, w: &Z) {
+   |                          -- use `&mut Z` here to make mutable
+51 |     let _ = &mut z.x;
+52 |     let _ = &mut w.x;
+   |                  ^^^ cannot mutably borrow immutable field
+
+error: aborting due to 11 previous errors
 
diff --git a/src/test/ui/did_you_mean/issue-40823.rs b/src/test/ui/did_you_mean/issue-40823.rs
new file mode 100644
index 00000000000..f4ae3257279
--- /dev/null
+++ b/src/test/ui/did_you_mean/issue-40823.rs
@@ -0,0 +1,14 @@
+// Copyright 2017 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.
+
+fn main() {
+    let mut buf = &[1, 2, 3, 4];
+    buf.iter_mut();
+}
diff --git a/src/test/ui/did_you_mean/issue-40823.stderr b/src/test/ui/did_you_mean/issue-40823.stderr
new file mode 100644
index 00000000000..8e77ebd9b6d
--- /dev/null
+++ b/src/test/ui/did_you_mean/issue-40823.stderr
@@ -0,0 +1,8 @@
+error: cannot borrow immutable borrowed content `*buf` as mutable
+  --> $DIR/issue-40823.rs:13:5
+   |
+13 |     buf.iter_mut();
+   |     ^^^ cannot borrow as mutable
+
+error: aborting due to previous error
+
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
index b83a6aaebf3..edf1635a6b8 100644
--- a/src/test/ui/span/borrowck-borrow-overloaded-auto-deref-mut.stderr
+++ b/src/test/ui/span/borrowck-borrow-overloaded-auto-deref-mut.stderr
@@ -2,7 +2,7 @@ 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
+   |                     - consider changing this to `mut x`
 63 |     let __isize = &mut x.y; //~ ERROR cannot borrow
    |                        ^ cannot borrow mutably
 
@@ -28,7 +28,7 @@ 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
+   |                      - consider changing this to `mut x`
 98 |     x.y = 3; //~ ERROR cannot borrow
    |     ^ cannot borrow mutably
 
@@ -54,7 +54,7 @@ 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
+    |                      - consider changing this to `mut x`
 119 |     x.set(0, 0); //~ ERROR cannot borrow
     |     ^ cannot borrow mutably
 
@@ -70,7 +70,7 @@ 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
+    |                       - consider changing this to `mut x`
 139 |     *x.y_mut() = 3; //~ ERROR cannot borrow
     |      ^ cannot borrow mutably
 
diff --git a/src/test/ui/span/borrowck-borrow-overloaded-deref-mut.stderr b/src/test/ui/span/borrowck-borrow-overloaded-deref-mut.stderr
index af954a4d792..2ec01168721 100644
--- a/src/test/ui/span/borrowck-borrow-overloaded-deref-mut.stderr
+++ b/src/test/ui/span/borrowck-borrow-overloaded-deref-mut.stderr
@@ -2,7 +2,7 @@ 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
+   |               - consider changing this to `mut x`
 39 |     let __isize = &mut *x; //~ ERROR cannot borrow
    |                         ^ cannot borrow mutably
 
@@ -18,7 +18,7 @@ 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
+   |                - consider changing this to `mut x`
 59 |     *x = 3; //~ ERROR cannot borrow
    |      ^ cannot borrow mutably
 
diff --git a/src/test/ui/span/borrowck-object-mutability.stderr b/src/test/ui/span/borrowck-object-mutability.stderr
index 4ef1cb9c239..0abdbdc3a21 100644
--- a/src/test/ui/span/borrowck-object-mutability.stderr
+++ b/src/test/ui/span/borrowck-object-mutability.stderr
@@ -10,6 +10,9 @@ error: cannot borrow immutable borrowed content `*x` as mutable
 error: cannot borrow immutable `Box` content `*x` as mutable
   --> $DIR/borrowck-object-mutability.rs:29:5
    |
+27 | fn owned_receiver(x: Box<Foo>) {
+   |                   - consider changing this to `mut x`
+28 |     x.borrowed();
 29 |     x.borrowed_mut(); //~ ERROR cannot borrow
    |     ^ cannot borrow as mutable