about summary refs log tree commit diff
diff options
context:
space:
mode:
authorAaron Hill <aa1ronham@gmail.com>2020-12-22 22:15:40 -0500
committerAaron Hill <aa1ronham@gmail.com>2021-01-08 14:37:07 -0500
commitde90afc72e2393efad0fb9cdfd765703a044fe02 (patch)
tree66c1d947d40638e700f2abf17dd20af674ab7dbc
parentddf2cc7f8eb34f1a63b491d6a52e3e8208393c09 (diff)
downloadrust-de90afc72e2393efad0fb9cdfd765703a044fe02.tar.gz
rust-de90afc72e2393efad0fb9cdfd765703a044fe02.zip
Explain method-call move errors in loops
PR #73708 added a more detailed explanation of move errors that occur
due to a call to a method that takes `self`. This PR extends that logic
to work when a move error occurs due to a method call in the previous
iteration of a loop.
-rw-r--r--compiler/rustc_mir/src/borrow_check/diagnostics/conflict_errors.rs142
-rw-r--r--src/test/ui/moves/move-fn-self-receiver.rs5
-rw-r--r--src/test/ui/moves/move-fn-self-receiver.stderr11
-rw-r--r--src/test/ui/suggestions/borrow-for-loop-head.stderr8
4 files changed, 90 insertions, 76 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 0bb09e26f03..c2a14840fb8 100644
--- a/compiler/rustc_mir/src/borrow_check/diagnostics/conflict_errors.rs
+++ b/compiler/rustc_mir/src/borrow_check/diagnostics/conflict_errors.rs
@@ -151,95 +151,88 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
 
                 let move_msg = if move_spans.for_closure() { " into closure" } else { "" };
 
+                let loop_message = if location == move_out.source || move_site.traversed_back_edge {
+                    ", in previous iteration of loop"
+                } else {
+                    ""
+                };
+
                 if location == move_out.source {
-                    err.span_label(
-                        span,
-                        format!(
-                            "value {}moved{} here, in previous iteration of loop",
-                            partially_str, move_msg
-                        ),
-                    );
                     is_loop_move = true;
-                } else if move_site.traversed_back_edge {
-                    err.span_label(
-                        move_span,
-                        format!(
-                            "value {}moved{} here, in previous iteration of loop",
-                            partially_str, move_msg
-                        ),
-                    );
-                } else {
-                    if let UseSpans::FnSelfUse { var_span, fn_call_span, fn_span, kind } =
-                        move_spans
-                    {
-                        let place_name = self
-                            .describe_place(moved_place.as_ref())
-                            .map(|n| format!("`{}`", n))
-                            .unwrap_or_else(|| "value".to_owned());
-                        match kind {
-                            FnSelfUseKind::FnOnceCall => {
+                }
+
+                if let UseSpans::FnSelfUse { var_span, fn_call_span, fn_span, kind } = move_spans {
+                    let place_name = self
+                        .describe_place(moved_place.as_ref())
+                        .map(|n| format!("`{}`", n))
+                        .unwrap_or_else(|| "value".to_owned());
+                    match kind {
+                        FnSelfUseKind::FnOnceCall => {
+                            err.span_label(
+                                fn_call_span,
+                                &format!(
+                                    "{} {}moved due to this call{}",
+                                    place_name, partially_str, loop_message
+                                ),
+                            );
+                            err.span_note(
+                                var_span,
+                                "this value implements `FnOnce`, which causes it to be moved when called",
+                            );
+                        }
+                        FnSelfUseKind::Operator { self_arg } => {
+                            err.span_label(
+                                fn_call_span,
+                                &format!(
+                                    "{} {}moved due to usage in operator{}",
+                                    place_name, partially_str, loop_message
+                                ),
+                            );
+                            if self.fn_self_span_reported.insert(fn_span) {
+                                err.span_note(
+                                    self_arg.span,
+                                    "calling this operator moves the left-hand side",
+                                );
+                            }
+                        }
+                        FnSelfUseKind::Normal { self_arg, implicit_into_iter } => {
+                            if implicit_into_iter {
                                 err.span_label(
                                     fn_call_span,
                                     &format!(
-                                        "{} {}moved due to this call",
-                                        place_name, partially_str
+                                        "{} {}moved due to this implicit call to `.into_iter()`{}",
+                                        place_name, partially_str, loop_message
                                     ),
                                 );
-                                err.span_note(
-                                    var_span,
-                                    "this value implements `FnOnce`, which causes it to be moved when called",
-                                );
-                            }
-                            FnSelfUseKind::Operator { self_arg } => {
+                            } else {
                                 err.span_label(
                                     fn_call_span,
                                     &format!(
-                                        "{} {}moved due to usage in operator",
-                                        place_name, partially_str
+                                        "{} {}moved due to this method call{}",
+                                        place_name, partially_str, loop_message
                                     ),
                                 );
-                                if self.fn_self_span_reported.insert(fn_span) {
-                                    err.span_note(
-                                        self_arg.span,
-                                        "calling this operator moves the left-hand side",
-                                    );
-                                }
                             }
-                            FnSelfUseKind::Normal { self_arg, implicit_into_iter } => {
-                                if implicit_into_iter {
-                                    err.span_label(
-                                        fn_call_span,
-                                        &format!(
-                                            "{} {}moved due to this implicit call to `.into_iter()`",
-                                            place_name, partially_str
-                                        ),
-                                    );
-                                } else {
-                                    err.span_label(
-                                        fn_call_span,
-                                        &format!(
-                                            "{} {}moved due to this method call",
-                                            place_name, partially_str
-                                        ),
-                                    );
-                                }
-                                // Avoid pointing to the same function in multiple different
-                                // error messages
-                                if self.fn_self_span_reported.insert(self_arg.span) {
-                                    err.span_note(
-                                        self_arg.span,
-                                        &format!("this function consumes the receiver `self` by taking ownership of it, which moves {}", place_name)
-                                    );
-                                }
+                            // Avoid pointing to the same function in multiple different
+                            // error messages
+                            if self.fn_self_span_reported.insert(self_arg.span) {
+                                err.span_note(
+                                    self_arg.span,
+                                    &format!("this function consumes the receiver `self` by taking ownership of it, which moves {}", place_name)
+                                );
                             }
-                            // Deref::deref takes &self, which cannot cause a move
-                            FnSelfUseKind::DerefCoercion { .. } => unreachable!(),
                         }
-                    } else {
-                        err.span_label(
-                            move_span,
-                            format!("value {}moved{} here", partially_str, move_msg),
-                        );
+                        // Deref::deref takes &self, which cannot cause a move
+                        FnSelfUseKind::DerefCoercion { .. } => unreachable!(),
+                    }
+                } else {
+                    err.span_label(
+                        move_span,
+                        format!("value {}moved{} here{}", partially_str, move_msg, loop_message),
+                    );
+                    // If the move error occurs due to a loop, don't show
+                    // another message for the same span
+                    if loop_message.is_empty() {
                         move_spans.var_span_label(
                             &mut err,
                             format!(
@@ -250,6 +243,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
                         );
                     }
                 }
+
                 if let UseSpans::PatUse(span) = move_spans {
                     err.span_suggestion_verbose(
                         span.shrink_to_lo(),
diff --git a/src/test/ui/moves/move-fn-self-receiver.rs b/src/test/ui/moves/move-fn-self-receiver.rs
index 6107f53fa19..946642ef6f3 100644
--- a/src/test/ui/moves/move-fn-self-receiver.rs
+++ b/src/test/ui/moves/move-fn-self-receiver.rs
@@ -69,6 +69,11 @@ fn move_out(val: Container) {
     let container = Container(vec![]);
     for _val in container.custom_into_iter() {}
     container; //~ ERROR use of moved
+
+    let foo2 = Foo;
+    loop {
+        foo2.use_self(); //~ ERROR use of moved
+    }
 }
 
 fn main() {}
diff --git a/src/test/ui/moves/move-fn-self-receiver.stderr b/src/test/ui/moves/move-fn-self-receiver.stderr
index dd263c1e906..8c509363d02 100644
--- a/src/test/ui/moves/move-fn-self-receiver.stderr
+++ b/src/test/ui/moves/move-fn-self-receiver.stderr
@@ -152,7 +152,16 @@ note: this function consumes the receiver `self` by taking ownership of it, whic
 LL |     fn custom_into_iter(self) -> impl Iterator<Item = bool> {
    |                         ^^^^
 
-error: aborting due to 11 previous errors
+error[E0382]: use of moved value: `foo2`
+  --> $DIR/move-fn-self-receiver.rs:75:9
+   |
+LL |     let foo2 = Foo;
+   |         ---- move occurs because `foo2` has type `Foo`, which does not implement the `Copy` trait
+LL |     loop {
+LL |         foo2.use_self();
+   |         ^^^^ ---------- `foo2` moved due to this method call, in previous iteration of loop
+
+error: aborting due to 12 previous errors
 
 Some errors have detailed explanations: E0382, E0505.
 For more information about an error, try `rustc --explain E0382`.
diff --git a/src/test/ui/suggestions/borrow-for-loop-head.stderr b/src/test/ui/suggestions/borrow-for-loop-head.stderr
index de342a969f4..64ce6c1e16d 100644
--- a/src/test/ui/suggestions/borrow-for-loop-head.stderr
+++ b/src/test/ui/suggestions/borrow-for-loop-head.stderr
@@ -15,8 +15,14 @@ LL |     for i in &a {
 LL |         for j in a {
    |                  ^
    |                  |
-   |                  value moved here, in previous iteration of loop
+   |                  `a` moved due to this implicit call to `.into_iter()`, in previous iteration of loop
    |                  help: consider borrowing to avoid moving into the for loop: `&a`
+   |
+note: this function consumes the receiver `self` by taking ownership of it, which moves `a`
+  --> $SRC_DIR/core/src/iter/traits/collect.rs:LL:COL
+   |
+LL |     fn into_iter(self) -> Self::IntoIter;
+   |                  ^^^^
 
 error: aborting due to 2 previous errors