diff --git a/src/librustc_borrowck/borrowck/unused.rs b/src/librustc_borrowck/borrowck/unused.rs
index 7bcd8a185453b..57f6084446126 100644
--- a/src/librustc_borrowck/borrowck/unused.rs
+++ b/src/librustc_borrowck/borrowck/unused.rs
@@ -62,7 +62,8 @@ impl<'a, 'tcx> UnusedMutCx<'a, 'tcx> {
                     None => span_bug!(span, "missing binding mode"),
                 };
                 match bm {
-                    ty::BindByValue(hir::MutMutable) => {}
+                    // allow `fn(mut self: &mut self)` so we can desugar `fn(&mut self)` to that
+                    ty::BindByValue(hir::MutMutable) if name.as_str() != "self" => {}
                     _ => return,
                 }
 
diff --git a/src/librustc_passes/ast_validation.rs b/src/librustc_passes/ast_validation.rs
index 1866122454c70..6438e932babad 100644
--- a/src/librustc_passes/ast_validation.rs
+++ b/src/librustc_passes/ast_validation.rs
@@ -82,6 +82,9 @@ impl<'a> AstValidator<'a> {
             match arg.pat.node {
                 PatKind::Ident(BindingMode::ByValue(Mutability::Immutable), _, None) |
                 PatKind::Wild => {}
+                // allow `fn(mut self: &mut self)` so we can desugar `fn(&mut self)` to that
+                PatKind::Ident(BindingMode::ByValue(Mutability::Mutable), ref ident, None)
+                    if ident.name.as_str() == "self" => {}
                 PatKind::Ident(BindingMode::ByValue(Mutability::Mutable), _, None) =>
                     report_err(arg.pat.span, true),
                 _ => report_err(arg.pat.span, false),
diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs
index 91c9a1524e144..8f2678890331e 100644
--- a/src/libsyntax/ast.rs
+++ b/src/libsyntax/ast.rs
@@ -1597,7 +1597,7 @@ pub enum TyKind {
     Infer,
     /// Inferred type of a `self` or `&self` argument in a method.
     ImplicitSelf,
-    // A macro in the type position.
+    /// A macro in the type position.
     Mac(Mac),
     /// Placeholder for a kind that has failed to be defined.
     Err,
@@ -1677,7 +1677,9 @@ impl Arg {
             if ident.name == keywords::SelfValue.name() {
                 return match self.ty.node {
                     TyKind::ImplicitSelf => Some(respan(self.pat.span, SelfKind::Value(mutbl))),
-                    TyKind::Rptr(lt, MutTy{ref ty, mutbl}) if ty.node == TyKind::ImplicitSelf => {
+                    TyKind::Rptr(lt, MutTy { ref ty, mutbl })
+                        if ty.node == TyKind::ImplicitSelf =>
+                    {
                         Some(respan(self.pat.span, SelfKind::Region(lt, mutbl)))
                     }
                     _ => Some(respan(self.pat.span.to(self.ty.span),
@@ -1715,7 +1717,7 @@ impl Arg {
         match eself.node {
             SelfKind::Explicit(ty, mutbl) => arg(mutbl, ty),
             SelfKind::Value(mutbl) => arg(mutbl, infer_ty),
-            SelfKind::Region(lt, mutbl) => arg(Mutability::Immutable, P(Ty {
+            SelfKind::Region(lt, mutbl) => arg(mutbl, P(Ty {
                 id: DUMMY_NODE_ID,
                 node: TyKind::Rptr(lt, MutTy { ty: infer_ty, mutbl: mutbl }),
                 span,
diff --git a/src/test/ui/did_you_mean/issue-31424.rs b/src/test/ui/did_you_mean/issue-31424.rs
index 1b31e064337e2..7ef5fbf8c2b4e 100644
--- a/src/test/ui/did_you_mean/issue-31424.rs
+++ b/src/test/ui/did_you_mean/issue-31424.rs
@@ -14,7 +14,7 @@ struct Struct;
 
 impl Struct {
     fn foo(&mut self) {
-        (&mut self).bar(); //~ ERROR cannot borrow
+        (&mut self).bar();
     }
 
     // In this case we could keep the suggestion, but to distinguish the
diff --git a/src/test/ui/did_you_mean/issue-31424.stderr b/src/test/ui/did_you_mean/issue-31424.stderr
index a80593e05f105..32571ec418f58 100644
--- a/src/test/ui/did_you_mean/issue-31424.stderr
+++ b/src/test/ui/did_you_mean/issue-31424.stderr
@@ -1,12 +1,3 @@
-error[E0596]: cannot borrow immutable argument `self` as mutable
-  --> $DIR/issue-31424.rs:17:15
-   |
-LL |         (&mut self).bar(); //~ ERROR cannot borrow
-   |               ^^^^
-   |               |
-   |               cannot reborrow mutably
-   |               try removing `&mut` here
-
 error[E0596]: cannot borrow immutable argument `self` as mutable
   --> $DIR/issue-31424.rs:23:15
    |
@@ -15,6 +6,6 @@ LL |     fn bar(self: &mut Self) {
 LL |         (&mut self).bar(); //~ ERROR cannot borrow
    |               ^^^^ cannot borrow mutably
 
-error: aborting due to 2 previous errors
+error: aborting due to previous error
 
 For more information about this error, try `rustc --explain E0596`.
diff --git a/src/test/ui/did_you_mean/issue-34126.rs b/src/test/ui/did_you_mean/issue-34126.rs
index 9dfb38abd049f..67d296b98641e 100644
--- a/src/test/ui/did_you_mean/issue-34126.rs
+++ b/src/test/ui/did_you_mean/issue-34126.rs
@@ -11,7 +11,7 @@
 struct Z { }
 
 impl Z {
-    fn run(&self, z: &mut Z) { }
+    fn run(&self, _z: &mut Z) { }
     fn start(&mut self) {
         self.run(&mut self); //~ ERROR cannot borrow
     }
diff --git a/src/test/ui/did_you_mean/issue-34126.stderr b/src/test/ui/did_you_mean/issue-34126.stderr
index 08ece78b78885..3f8dd369a9cd6 100644
--- a/src/test/ui/did_you_mean/issue-34126.stderr
+++ b/src/test/ui/did_you_mean/issue-34126.stderr
@@ -1,12 +1,12 @@
-error[E0596]: cannot borrow immutable argument `self` as mutable
+error[E0502]: cannot borrow `self` as mutable because `*self` is also borrowed as immutable
   --> $DIR/issue-34126.rs:16:23
    |
 LL |         self.run(&mut self); //~ ERROR cannot borrow
-   |                       ^^^^
-   |                       |
-   |                       cannot reborrow mutably
-   |                       try removing `&mut` here
+   |         ----          ^^^^- immutable borrow ends here
+   |         |             |
+   |         |             mutable borrow occurs here
+   |         immutable borrow occurs here
 
 error: aborting due to previous error
 
-For more information about this error, try `rustc --explain E0596`.
+For more information about this error, try `rustc --explain E0502`.