about summary refs log tree commit diff
diff options
context:
space:
mode:
authorDylan DPC <dylan.dpc@gmail.com>2021-04-07 13:07:17 +0200
committerGitHub <noreply@github.com>2021-04-07 13:07:17 +0200
commitd7d42ccfd254dca9923bca63b008423dc4e0f83d (patch)
treefc12b3db17212c201f0303b2fd65a6e355f2320a
parent9c688cd2a2935ae4645c0b878f1f40ea51e98816 (diff)
parenta77598434838376141c8cb25fe29693b3a26b173 (diff)
downloadrust-d7d42ccfd254dca9923bca63b008423dc4e0f83d.tar.gz
rust-d7d42ccfd254dca9923bca63b008423dc4e0f83d.zip
Rollup merge of #83945 - SkiFire13:fix-83924, r=estebank
Add suggestion to reborrow mutable references when they're moved in a for loop

Address #83924
-rw-r--r--compiler/rustc_mir/src/borrow_check/diagnostics/conflict_errors.rs19
-rw-r--r--src/test/ui/issues/issue-83924.fixed20
-rw-r--r--src/test/ui/issues/issue-83924.rs20
-rw-r--r--src/test/ui/issues/issue-83924.stderr25
4 files changed, 83 insertions, 1 deletions
diff --git a/compiler/rustc_mir/src/borrow_check/diagnostics/conflict_errors.rs b/compiler/rustc_mir/src/borrow_check/diagnostics/conflict_errors.rs
index d5deec82088..5fdf8a8d1ee 100644
--- a/compiler/rustc_mir/src/borrow_check/diagnostics/conflict_errors.rs
+++ b/compiler/rustc_mir/src/borrow_check/diagnostics/conflict_errors.rs
@@ -264,7 +264,24 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
 
                 if let Some(DesugaringKind::ForLoop(_)) = move_span.desugaring_kind() {
                     let sess = self.infcx.tcx.sess;
-                    if let Ok(snippet) = sess.source_map().span_to_snippet(move_span) {
+                    let ty = used_place.ty(self.body, self.infcx.tcx).ty;
+                    // If we have a `&mut` ref, we need to reborrow.
+                    if let ty::Ref(_, _, hir::Mutability::Mut) = ty.kind() {
+                        // If we are in a loop this will be suggested later.
+                        if !is_loop_move {
+                            err.span_suggestion_verbose(
+                                move_span.shrink_to_lo(),
+                                &format!(
+                                    "consider creating a fresh reborrow of {} here",
+                                    self.describe_place(moved_place.as_ref())
+                                        .map(|n| format!("`{}`", n))
+                                        .unwrap_or_else(|| "the mutable reference".to_string()),
+                                ),
+                                format!("&mut *"),
+                                Applicability::MachineApplicable,
+                            );
+                        }
+                    } else if let Ok(snippet) = sess.source_map().span_to_snippet(move_span) {
                         err.span_suggestion(
                             move_span,
                             "consider borrowing to avoid moving into the for loop",
diff --git a/src/test/ui/issues/issue-83924.fixed b/src/test/ui/issues/issue-83924.fixed
new file mode 100644
index 00000000000..aa40da12b87
--- /dev/null
+++ b/src/test/ui/issues/issue-83924.fixed
@@ -0,0 +1,20 @@
+// run-rustfix
+
+fn main() {
+    let mut values = vec![10, 11, 12];
+    let v = &mut values;
+
+    let mut max = 0;
+
+    for n in &mut *v {
+        max = std::cmp::max(max, *n);
+    }
+
+    println!("max is {}", max);
+    println!("Converting to percentages of maximum value...");
+    for n in v {
+        //~^ ERROR: use of moved value: `v` [E0382]
+        *n = 100 * (*n) / max;
+    }
+    println!("values: {:#?}", values);
+}
diff --git a/src/test/ui/issues/issue-83924.rs b/src/test/ui/issues/issue-83924.rs
new file mode 100644
index 00000000000..22b80fe2f38
--- /dev/null
+++ b/src/test/ui/issues/issue-83924.rs
@@ -0,0 +1,20 @@
+// run-rustfix
+
+fn main() {
+    let mut values = vec![10, 11, 12];
+    let v = &mut values;
+
+    let mut max = 0;
+
+    for n in v {
+        max = std::cmp::max(max, *n);
+    }
+
+    println!("max is {}", max);
+    println!("Converting to percentages of maximum value...");
+    for n in v {
+        //~^ ERROR: use of moved value: `v` [E0382]
+        *n = 100 * (*n) / max;
+    }
+    println!("values: {:#?}", values);
+}
diff --git a/src/test/ui/issues/issue-83924.stderr b/src/test/ui/issues/issue-83924.stderr
new file mode 100644
index 00000000000..682bc323cb0
--- /dev/null
+++ b/src/test/ui/issues/issue-83924.stderr
@@ -0,0 +1,25 @@
+error[E0382]: use of moved value: `v`
+  --> $DIR/issue-83924.rs:15:14
+   |
+LL |     let v = &mut values;
+   |         - move occurs because `v` has type `&mut Vec<i32>`, which does not implement the `Copy` trait
+...
+LL |     for n in v {
+   |              - `v` moved due to this implicit call to `.into_iter()`
+...
+LL |     for n in v {
+   |              ^ value used here after move
+   |
+note: this function takes ownership of the receiver `self`, which moves `v`
+  --> $SRC_DIR/core/src/iter/traits/collect.rs:LL:COL
+   |
+LL |     fn into_iter(self) -> Self::IntoIter;
+   |                  ^^^^
+help: consider creating a fresh reborrow of `v` here
+   |
+LL |     for n in &mut *v {
+   |              ^^^^^^
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0382`.