about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--compiler/rustc_hir_typeck/src/demand.rs38
-rw-r--r--compiler/rustc_passes/src/errors.rs2
-rw-r--r--compiler/rustc_passes/src/liveness.rs16
-rw-r--r--tests/ui/fn/mut-arg-of-borrowed-type-meant-to-be-arg-of-mut-borrow.fixed18
-rw-r--r--tests/ui/fn/mut-arg-of-borrowed-type-meant-to-be-arg-of-mut-borrow.rs20
-rw-r--r--tests/ui/fn/mut-arg-of-borrowed-type-meant-to-be-arg-of-mut-borrow.stderr77
6 files changed, 114 insertions, 57 deletions
diff --git a/compiler/rustc_hir_typeck/src/demand.rs b/compiler/rustc_hir_typeck/src/demand.rs
index 367e7c6de95..bc076670585 100644
--- a/compiler/rustc_hir_typeck/src/demand.rs
+++ b/compiler/rustc_hir_typeck/src/demand.rs
@@ -851,32 +851,32 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             && let hir::PatKind::Binding(hir::BindingMode::MUT, _hir_id, ident, _) = pat.kind
 
             // Look for the type corresponding to the argument pattern we have in the argument list.
-            && let Some(ty_sugg) = fn_decl
+            && let Some(ty_ref) = fn_decl
                 .inputs
                 .iter()
-                .filter_map(|ty| {
-                    if ty.span == *ty_span
-                        && let hir::TyKind::Ref(lt, x) = ty.kind
-                    {
-                        // `&'name Ty` -> `&'name mut Ty` or `&Ty` -> `&mut Ty`
-                        Some((
-                            x.ty.span.shrink_to_lo(),
-                            format!(
-                                "{}mut ",
-                                if lt.ident.span.lo() == lt.ident.span.hi() { "" } else { " " }
-                            ),
-                        ))
-                    } else {
-                        None
-                    }
+                .filter_map(|ty| match ty.kind {
+                    hir::TyKind::Ref(lt, mut_ty) if ty.span == *ty_span => Some((lt, mut_ty)),
+                    _ => None,
                 })
                 .next()
         {
-            let sugg = vec![
-                ty_sugg,
+            let mut sugg = if ty_ref.1.mutbl.is_mut() {
+                // Leave `&'name mut Ty` and `&mut Ty` as they are (#136028).
+                vec![]
+            } else {
+                // `&'name Ty` -> `&'name mut Ty` or `&Ty` -> `&mut Ty`
+                vec![(
+                    ty_ref.1.ty.span.shrink_to_lo(),
+                    format!(
+                        "{}mut ",
+                        if ty_ref.0.ident.span.lo() == ty_ref.0.ident.span.hi() { "" } else { " " },
+                    ),
+                )]
+            };
+            sugg.extend([
                 (pat.span.until(ident.span), String::new()),
                 (lhs.span.shrink_to_lo(), "*".to_string()),
-            ];
+            ]);
             // We suggest changing the argument from `mut ident: &Ty` to `ident: &'_ mut Ty` and the
             // assignment from `ident = val;` to `*ident = val;`.
             err.multipart_suggestion_verbose(
diff --git a/compiler/rustc_passes/src/errors.rs b/compiler/rustc_passes/src/errors.rs
index 196a0a46962..0aa50ad19ff 100644
--- a/compiler/rustc_passes/src/errors.rs
+++ b/compiler/rustc_passes/src/errors.rs
@@ -1791,7 +1791,7 @@ pub(crate) struct UnusedAssign {
 pub(crate) struct UnusedAssignSuggestion {
     pub pre: &'static str,
     #[suggestion_part(code = "{pre}mut ")]
-    pub ty_span: Span,
+    pub ty_span: Option<Span>,
     #[suggestion_part(code = "")]
     pub ty_ref_span: Span,
     #[suggestion_part(code = "*")]
diff --git a/compiler/rustc_passes/src/liveness.rs b/compiler/rustc_passes/src/liveness.rs
index 426899a4d5c..73da8855e10 100644
--- a/compiler/rustc_passes/src/liveness.rs
+++ b/compiler/rustc_passes/src/liveness.rs
@@ -1620,24 +1620,28 @@ impl<'tcx> Liveness<'_, 'tcx> {
             && let item = self.ir.tcx.hir_owner_node(item_id)
             && let Some(fn_decl) = item.fn_decl()
             && let hir::PatKind::Binding(hir::BindingMode::MUT, _hir_id, ident, _) = pat.kind
-            && let Some((ty_span, pre)) = fn_decl
+            && let Some((lt, mut_ty)) = fn_decl
                 .inputs
                 .iter()
                 .filter_map(|ty| {
                     if ty.span == *ty_span
                         && let hir::TyKind::Ref(lt, mut_ty) = ty.kind
                     {
-                        // `&'name Ty` -> `&'name mut Ty` or `&Ty` -> `&mut Ty`
-                        Some((
-                            mut_ty.ty.span.shrink_to_lo(),
-                            if lt.ident.span.lo() == lt.ident.span.hi() { "" } else { " " },
-                        ))
+                        Some((lt, mut_ty))
                     } else {
                         None
                     }
                 })
                 .next()
         {
+            let ty_span = if mut_ty.mutbl.is_mut() {
+                // Leave `&'name mut Ty` and `&mut Ty` as they are (#136028).
+                None
+            } else {
+                // `&'name Ty` -> `&'name mut Ty` or `&Ty` -> `&mut Ty`
+                Some(mut_ty.ty.span.shrink_to_lo())
+            };
+            let pre = if lt.ident.span.lo() == lt.ident.span.hi() { "" } else { " " };
             Some(errors::UnusedAssignSuggestion {
                 ty_span,
                 pre,
diff --git a/tests/ui/fn/mut-arg-of-borrowed-type-meant-to-be-arg-of-mut-borrow.fixed b/tests/ui/fn/mut-arg-of-borrowed-type-meant-to-be-arg-of-mut-borrow.fixed
index 914ca1f3a06..b58c3a6720d 100644
--- a/tests/ui/fn/mut-arg-of-borrowed-type-meant-to-be-arg-of-mut-borrow.fixed
+++ b/tests/ui/fn/mut-arg-of-borrowed-type-meant-to-be-arg-of-mut-borrow.fixed
@@ -1,17 +1,26 @@
 //@ run-rustfix
 #![deny(unused_assignments, unused_variables)]
+#![allow(unused_mut)]
 struct Object;
 
 fn change_object(object: &mut Object) { //~ HELP you might have meant to mutate
-    let object2 = Object;
-    *object = object2; //~ ERROR mismatched types
+   let object2 = Object;
+   *object = object2; //~ ERROR mismatched types
 }
 
 fn change_object2(object: &mut Object) { //~ ERROR variable `object` is assigned to, but never used
+   //~^ HELP you might have meant to mutate
+   let object2 = Object;
+   *object = object2;
+   //~^ ERROR `object2` does not live long enough
+   //~| ERROR value assigned to `object` is never read
+}
+
+fn change_object3(object: &mut Object) { //~ ERROR variable `object` is assigned to, but never used
     //~^ HELP you might have meant to mutate
-    let object2 = Object;
+    let mut object2 = Object; //~ HELP consider changing this to be mutable
     *object = object2;
-    //~^ ERROR `object2` does not live long enough
+    //~^ ERROR cannot borrow `object2` as mutable
     //~| ERROR value assigned to `object` is never read
 }
 
@@ -19,4 +28,5 @@ fn main() {
     let mut object = Object;
     change_object(&mut object);
     change_object2(&mut object);
+    change_object3(&mut object);
 }
diff --git a/tests/ui/fn/mut-arg-of-borrowed-type-meant-to-be-arg-of-mut-borrow.rs b/tests/ui/fn/mut-arg-of-borrowed-type-meant-to-be-arg-of-mut-borrow.rs
index 331359a98d1..1fd222e0db1 100644
--- a/tests/ui/fn/mut-arg-of-borrowed-type-meant-to-be-arg-of-mut-borrow.rs
+++ b/tests/ui/fn/mut-arg-of-borrowed-type-meant-to-be-arg-of-mut-borrow.rs
@@ -1,17 +1,26 @@
 //@ run-rustfix
 #![deny(unused_assignments, unused_variables)]
+#![allow(unused_mut)]
 struct Object;
 
 fn change_object(mut object: &Object) { //~ HELP you might have meant to mutate
-    let object2 = Object;
-    object = object2; //~ ERROR mismatched types
+   let object2 = Object;
+   object = object2; //~ ERROR mismatched types
 }
 
 fn change_object2(mut object: &Object) { //~ ERROR variable `object` is assigned to, but never used
+   //~^ HELP you might have meant to mutate
+   let object2 = Object;
+   object = &object2;
+   //~^ ERROR `object2` does not live long enough
+   //~| ERROR value assigned to `object` is never read
+}
+
+fn change_object3(mut object: &mut Object) { //~ ERROR variable `object` is assigned to, but never used
     //~^ HELP you might have meant to mutate
-    let object2 = Object;
-    object = &object2;
-    //~^ ERROR `object2` does not live long enough
+    let object2 = Object; //~ HELP consider changing this to be mutable
+    object = &mut object2;
+    //~^ ERROR cannot borrow `object2` as mutable
     //~| ERROR value assigned to `object` is never read
 }
 
@@ -19,4 +28,5 @@ fn main() {
     let mut object = Object;
     change_object(&mut object);
     change_object2(&mut object);
+    change_object3(&mut object);
 }
diff --git a/tests/ui/fn/mut-arg-of-borrowed-type-meant-to-be-arg-of-mut-borrow.stderr b/tests/ui/fn/mut-arg-of-borrowed-type-meant-to-be-arg-of-mut-borrow.stderr
index e7e4003936a..0330853d922 100644
--- a/tests/ui/fn/mut-arg-of-borrowed-type-meant-to-be-arg-of-mut-borrow.stderr
+++ b/tests/ui/fn/mut-arg-of-borrowed-type-meant-to-be-arg-of-mut-borrow.stderr
@@ -1,24 +1,24 @@
 error[E0308]: mismatched types
-  --> $DIR/mut-arg-of-borrowed-type-meant-to-be-arg-of-mut-borrow.rs:7:14
+  --> $DIR/mut-arg-of-borrowed-type-meant-to-be-arg-of-mut-borrow.rs:8:13
    |
 LL | fn change_object(mut object: &Object) {
    |                              ------- expected due to this parameter type
-LL |     let object2 = Object;
-LL |     object = object2;
-   |              ^^^^^^^ expected `&Object`, found `Object`
+LL |    let object2 = Object;
+LL |    object = object2;
+   |             ^^^^^^^ expected `&Object`, found `Object`
    |
 help: you might have meant to mutate the pointed at value being passed in, instead of changing the reference in the local binding
    |
 LL ~ fn change_object(object: &mut Object) {
-LL |     let object2 = Object;
-LL ~     *object = object2;
+LL |    let object2 = Object;
+LL ~    *object = object2;
    |
 
 error: value assigned to `object` is never read
-  --> $DIR/mut-arg-of-borrowed-type-meant-to-be-arg-of-mut-borrow.rs:13:5
+  --> $DIR/mut-arg-of-borrowed-type-meant-to-be-arg-of-mut-borrow.rs:14:4
    |
-LL |     object = &object2;
-   |     ^^^^^^
+LL |    object = &object2;
+   |    ^^^^^^
    |
 note: the lint level is defined here
   --> $DIR/mut-arg-of-borrowed-type-meant-to-be-arg-of-mut-borrow.rs:2:9
@@ -29,12 +29,12 @@ help: you might have meant to mutate the pointed at value being passed in, inste
    |
 LL ~ fn change_object2(object: &mut Object) {
 LL |
-LL |     let object2 = Object;
-LL ~     *object = object2;
+LL |    let object2 = Object;
+LL ~    *object = object2;
    |
 
 error: variable `object` is assigned to, but never used
-  --> $DIR/mut-arg-of-borrowed-type-meant-to-be-arg-of-mut-borrow.rs:10:23
+  --> $DIR/mut-arg-of-borrowed-type-meant-to-be-arg-of-mut-borrow.rs:11:23
    |
 LL | fn change_object2(mut object: &Object) {
    |                       ^^^^^^
@@ -47,23 +47,56 @@ LL | #![deny(unused_assignments, unused_variables)]
    |                             ^^^^^^^^^^^^^^^^
 
 error[E0597]: `object2` does not live long enough
-  --> $DIR/mut-arg-of-borrowed-type-meant-to-be-arg-of-mut-borrow.rs:13:14
+  --> $DIR/mut-arg-of-borrowed-type-meant-to-be-arg-of-mut-borrow.rs:14:13
    |
 LL | fn change_object2(mut object: &Object) {
    |                               - let's call the lifetime of this reference `'1`
 LL |
-LL |     let object2 = Object;
-   |         ------- binding `object2` declared here
-LL |     object = &object2;
-   |     ---------^^^^^^^^
-   |     |        |
-   |     |        borrowed value does not live long enough
-   |     assignment requires that `object2` is borrowed for `'1`
+LL |    let object2 = Object;
+   |        ------- binding `object2` declared here
+LL |    object = &object2;
+   |    ---------^^^^^^^^
+   |    |        |
+   |    |        borrowed value does not live long enough
+   |    assignment requires that `object2` is borrowed for `'1`
 ...
 LL | }
    | - `object2` dropped here while still borrowed
 
-error: aborting due to 4 previous errors
+error: value assigned to `object` is never read
+  --> $DIR/mut-arg-of-borrowed-type-meant-to-be-arg-of-mut-borrow.rs:22:5
+   |
+LL |     object = &mut object2;
+   |     ^^^^^^
+   |
+help: you might have meant to mutate the pointed at value being passed in, instead of changing the reference in the local binding
+   |
+LL ~ fn change_object3(object: &mut Object) {
+LL |
+LL |     let object2 = Object;
+LL ~     *object = object2;
+   |
+
+error: variable `object` is assigned to, but never used
+  --> $DIR/mut-arg-of-borrowed-type-meant-to-be-arg-of-mut-borrow.rs:19:23
+   |
+LL | fn change_object3(mut object: &mut Object) {
+   |                       ^^^^^^
+   |
+   = note: consider using `_object` instead
+
+error[E0596]: cannot borrow `object2` as mutable, as it is not declared as mutable
+  --> $DIR/mut-arg-of-borrowed-type-meant-to-be-arg-of-mut-borrow.rs:22:14
+   |
+LL |     object = &mut object2;
+   |              ^^^^^^^^^^^^ cannot borrow as mutable
+   |
+help: consider changing this to be mutable
+   |
+LL |     let mut object2 = Object;
+   |         +++
+
+error: aborting due to 7 previous errors
 
-Some errors have detailed explanations: E0308, E0597.
+Some errors have detailed explanations: E0308, E0596, E0597.
 For more information about an error, try `rustc --explain E0308`.