about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--compiler/rustc_mir/src/borrow_check/diagnostics/mutability_errors.rs113
-rw-r--r--src/test/ui/suggestions/issue-68049-1.rs16
-rw-r--r--src/test/ui/suggestions/issue-68049-1.stderr9
-rw-r--r--src/test/ui/suggestions/issue-68049-2.rs21
-rw-r--r--src/test/ui/suggestions/issue-68049-2.stderr21
5 files changed, 170 insertions, 10 deletions
diff --git a/compiler/rustc_mir/src/borrow_check/diagnostics/mutability_errors.rs b/compiler/rustc_mir/src/borrow_check/diagnostics/mutability_errors.rs
index 88122777d2e..88ba112c8d5 100644
--- a/compiler/rustc_mir/src/borrow_check/diagnostics/mutability_errors.rs
+++ b/compiler/rustc_mir/src/borrow_check/diagnostics/mutability_errors.rs
@@ -6,7 +6,7 @@ use rustc_middle::mir::{Mutability, Place, PlaceRef, ProjectionElem};
 use rustc_middle::ty::{self, Ty, TyCtxt};
 use rustc_middle::{
     hir::place::PlaceBase,
-    mir::{self, ClearCrossCrate, Local, LocalDecl, LocalInfo, Location},
+    mir::{self, ClearCrossCrate, Local, LocalDecl, LocalInfo, LocalKind, Location},
 };
 use rustc_span::source_map::DesugaringKind;
 use rustc_span::symbol::{kw, Symbol};
@@ -424,15 +424,108 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
 
                         match label {
                             Some((true, err_help_span, suggested_code)) => {
-                                err.span_suggestion(
-                                    err_help_span,
-                                    &format!(
-                                        "consider changing this to be a mutable {}",
-                                        pointer_desc
-                                    ),
-                                    suggested_code,
-                                    Applicability::MachineApplicable,
-                                );
+                                /// User cannot make signature of a trait mutable
+                                /// without changing the trait. So we find if this
+                                /// error belongs to a trait and if so we move
+                                /// suggestion to the trait or disable it if it is
+                                /// out of scope of this crate
+                                let (is_trait_sig, local_trait) = {
+                                    if self.body.local_kind(local) != LocalKind::Arg {
+                                        (false, None)
+                                    } else {
+                                        let hir_map = self.infcx.tcx.hir();
+                                        let my_hir = hir_map.local_def_id_to_hir_id(
+                                            self.body.source.def_id().as_local().unwrap(),
+                                        );
+                                        match hir_map.find(hir_map.get_parent_node(my_hir)) {
+                                            Some(Node::Item(hir::Item {
+                                                kind:
+                                                    hir::ItemKind::Impl(hir::Impl {
+                                                        of_trait:
+                                                            Some(hir::TraitRef {
+                                                                path:
+                                                                    hir::Path {
+                                                                        res:
+                                                                            hir::def::Res::Def(_, td),
+                                                                        ..
+                                                                    },
+                                                                ..
+                                                            }),
+                                                        ..
+                                                    }),
+                                                ..
+                                            })) => {
+                                                (true, td.as_local().and_then(|tld| {
+                                                    let h = hir_map.local_def_id_to_hir_id(tld);
+                                                    match hir_map.find(h) {
+                                                        Some(Node::Item(hir::Item {
+                                                            kind: hir::ItemKind::Trait(
+                                                                _, _, _, _,
+                                                                items
+                                                            ),
+                                                            ..
+                                                        })) => {
+                                                            let mut f_in_trait_opt = None;
+                                                            for hir::TraitItemRef { id: fi, kind: k, .. } in *items {
+                                                                let hi = fi.hir_id();
+                                                                if !matches!(k, hir::AssocItemKind::Fn { .. }) {
+                                                                    continue;
+                                                                }
+                                                                if hir_map.name(hi) != hir_map.name(my_hir) {
+                                                                    continue;
+                                                                }
+                                                                f_in_trait_opt = Some(hi);
+                                                                break;
+                                                            }
+                                                            f_in_trait_opt.and_then(|f_in_trait| {
+                                                                match hir_map.find(f_in_trait) {
+                                                                    Some(Node::TraitItem(hir::TraitItem {
+                                                                        kind: hir::TraitItemKind::Fn(hir::FnSig {
+                                                                            decl: hir::FnDecl {
+                                                                                inputs,
+                                                                                ..
+                                                                            },
+                                                                            ..
+                                                                        }, _),
+                                                                        ..
+                                                                    })) => {
+                                                                        let hir::Ty { span, .. } = inputs[local.index() - 1];
+                                                                        Some(span)
+                                                                    },
+                                                                    _ => None,
+                                                                }
+                                                            })
+                                                            //Some(hir_map.span(h))
+                                                        }
+                                                        _ => None
+                                                    }
+                                                }))
+                                            }
+                                            _ => (false, None),
+                                        }
+                                    }
+                                };
+                                if !is_trait_sig {
+                                    err.span_suggestion(
+                                        err_help_span,
+                                        &format!(
+                                            "consider changing this to be a mutable {}",
+                                            pointer_desc
+                                        ),
+                                        suggested_code,
+                                        Applicability::MachineApplicable,
+                                    );
+                                } else if let Some(x) = local_trait {
+                                    err.span_suggestion(
+                                        x,
+                                        &format!(
+                                            "consider changing that to be a mutable {}",
+                                            pointer_desc
+                                        ),
+                                        suggested_code,
+                                        Applicability::MachineApplicable,
+                                    );
+                                }
                             }
                             Some((false, err_label_span, message)) => {
                                 err.span_label(err_label_span, &message);
diff --git a/src/test/ui/suggestions/issue-68049-1.rs b/src/test/ui/suggestions/issue-68049-1.rs
new file mode 100644
index 00000000000..9b9ae429aeb
--- /dev/null
+++ b/src/test/ui/suggestions/issue-68049-1.rs
@@ -0,0 +1,16 @@
+use std::alloc::{GlobalAlloc, Layout};
+
+struct Test(u32);
+
+unsafe impl GlobalAlloc for Test {
+    unsafe fn alloc(&self, _layout: Layout) -> *mut u8 {
+        self.0 += 1;
+        0 as *mut u8
+    }
+
+    unsafe fn dealloc(&self, _ptr: *mut u8, _layout: Layout) {
+        unimplemented!();
+    }
+}
+
+fn main() { }
diff --git a/src/test/ui/suggestions/issue-68049-1.stderr b/src/test/ui/suggestions/issue-68049-1.stderr
new file mode 100644
index 00000000000..32367d2d0cf
--- /dev/null
+++ b/src/test/ui/suggestions/issue-68049-1.stderr
@@ -0,0 +1,9 @@
+error[E0594]: cannot assign to `self.0` which is behind a `&` reference
+  --> $DIR/issue-68049-1.rs:7:9
+   |
+LL |         self.0 += 1;
+   |         ^^^^^^^^^^^ `self` is a `&` reference, so the data it refers to cannot be written
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0594`.
diff --git a/src/test/ui/suggestions/issue-68049-2.rs b/src/test/ui/suggestions/issue-68049-2.rs
new file mode 100644
index 00000000000..22bb6b85d6f
--- /dev/null
+++ b/src/test/ui/suggestions/issue-68049-2.rs
@@ -0,0 +1,21 @@
+trait Hello {
+  fn example(&self, input: &i32); // should suggest here
+}
+
+struct Test1(i32);
+
+impl Hello for Test1 {
+  fn example(&self, input: &i32) { // should not suggest here
+      *input = self.0;
+  }
+}
+
+struct Test2(i32);
+
+impl Hello for Test2 {
+  fn example(&self, input: &i32) { // should not suggest here
+    self.0 += *input;
+  }
+}
+
+fn main() { }
diff --git a/src/test/ui/suggestions/issue-68049-2.stderr b/src/test/ui/suggestions/issue-68049-2.stderr
new file mode 100644
index 00000000000..f10a83c68a8
--- /dev/null
+++ b/src/test/ui/suggestions/issue-68049-2.stderr
@@ -0,0 +1,21 @@
+error[E0594]: cannot assign to `*input` which is behind a `&` reference
+  --> $DIR/issue-68049-2.rs:9:7
+   |
+LL |   fn example(&self, input: &i32); // should suggest here
+   |                            ---- help: consider changing that to be a mutable reference: `&mut i32`
+...
+LL |       *input = self.0;
+   |       ^^^^^^^^^^^^^^^ `input` is a `&` reference, so the data it refers to cannot be written
+
+error[E0594]: cannot assign to `self.0` which is behind a `&` reference
+  --> $DIR/issue-68049-2.rs:17:5
+   |
+LL |   fn example(&self, input: &i32); // should suggest here
+   |              ----- help: consider changing that to be a mutable reference: `&mut self`
+...
+LL |     self.0 += *input;
+   |     ^^^^^^^^^^^^^^^^ `self` is a `&` reference, so the data it refers to cannot be written
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0594`.