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 0bb09e26f03e8..db02ee67910b2 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 takes ownership of the receiver `self`, 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/codemap_tests/tab_3.stderr b/src/test/ui/codemap_tests/tab_3.stderr index 958d54bbb151f..e067dbbf85bdd 100644 --- a/src/test/ui/codemap_tests/tab_3.stderr +++ b/src/test/ui/codemap_tests/tab_3.stderr @@ -9,7 +9,7 @@ LL | { LL | println!("{:?}", some_vec); | ^^^^^^^^ value borrowed here after move | -note: this function consumes the receiver `self` by taking ownership of it, which moves `some_vec` +note: this function takes ownership of the receiver `self`, which moves `some_vec` --> $SRC_DIR/core/src/iter/traits/collect.rs:LL:COL | LL | fn into_iter(self) -> Self::IntoIter; diff --git a/src/test/ui/issues/issue-34721.stderr b/src/test/ui/issues/issue-34721.stderr index b4cc1a0aa7eb2..b14faff8f7b8d 100644 --- a/src/test/ui/issues/issue-34721.stderr +++ b/src/test/ui/issues/issue-34721.stderr @@ -13,7 +13,7 @@ LL | }; LL | x.zero() | ^ value used here after move | -note: this function consumes the receiver `self` by taking ownership of it, which moves `x` +note: this function takes ownership of the receiver `self`, which moves `x` --> $DIR/issue-34721.rs:4:13 | LL | fn zero(self) -> Self; diff --git a/src/test/ui/issues/issue-61108.stderr b/src/test/ui/issues/issue-61108.stderr index d6c289cbd668d..fb242f738c87e 100644 --- a/src/test/ui/issues/issue-61108.stderr +++ b/src/test/ui/issues/issue-61108.stderr @@ -12,7 +12,7 @@ LL | for l in bad_letters { LL | bad_letters.push('s'); | ^^^^^^^^^^^ value borrowed here after move | -note: this function consumes the receiver `self` by taking ownership of it, which moves `bad_letters` +note: this function takes ownership of the receiver `self`, which moves `bad_letters` --> $SRC_DIR/core/src/iter/traits/collect.rs:LL:COL | LL | fn into_iter(self) -> Self::IntoIter; diff --git a/src/test/ui/issues/issue-64559.stderr b/src/test/ui/issues/issue-64559.stderr index 5b97e21b88835..e0da3fd5195cb 100644 --- a/src/test/ui/issues/issue-64559.stderr +++ b/src/test/ui/issues/issue-64559.stderr @@ -13,7 +13,7 @@ LL | let _closure = || orig; | | | value used here after move | -note: this function consumes the receiver `self` by taking ownership of it, which moves `orig` +note: this function takes ownership of the receiver `self`, which moves `orig` --> $SRC_DIR/core/src/iter/traits/collect.rs:LL:COL | LL | fn into_iter(self) -> Self::IntoIter; diff --git a/src/test/ui/moves/move-fn-self-receiver.rs b/src/test/ui/moves/move-fn-self-receiver.rs index 6107f53fa1960..946642ef6f3ad 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 dd263c1e90677..eca6bb9296ddc 100644 --- a/src/test/ui/moves/move-fn-self-receiver.stderr +++ b/src/test/ui/moves/move-fn-self-receiver.stderr @@ -6,7 +6,7 @@ LL | val.0.into_iter().next(); LL | val.0; | ^^^^^ value used here after move | -note: this function consumes the receiver `self` by taking ownership of it, which moves `val.0` +note: this function takes ownership of the receiver `self`, which moves `val.0` --> $SRC_DIR/core/src/iter/traits/collect.rs:LL:COL | LL | fn into_iter(self) -> Self::IntoIter; @@ -23,7 +23,7 @@ LL | foo.use_self(); LL | foo; | ^^^ value used here after move | -note: this function consumes the receiver `self` by taking ownership of it, which moves `foo` +note: this function takes ownership of the receiver `self`, which moves `foo` --> $DIR/move-fn-self-receiver.rs:13:17 | LL | fn use_self(self) {} @@ -49,7 +49,7 @@ LL | boxed_foo.use_box_self(); LL | boxed_foo; | ^^^^^^^^^ value used here after move | -note: this function consumes the receiver `self` by taking ownership of it, which moves `boxed_foo` +note: this function takes ownership of the receiver `self`, which moves `boxed_foo` --> $DIR/move-fn-self-receiver.rs:14:21 | LL | fn use_box_self(self: Box) {} @@ -65,7 +65,7 @@ LL | pin_box_foo.use_pin_box_self(); LL | pin_box_foo; | ^^^^^^^^^^^ value used here after move | -note: this function consumes the receiver `self` by taking ownership of it, which moves `pin_box_foo` +note: this function takes ownership of the receiver `self`, which moves `pin_box_foo` --> $DIR/move-fn-self-receiver.rs:15:25 | LL | fn use_pin_box_self(self: Pin>) {} @@ -91,7 +91,7 @@ LL | rc_foo.use_rc_self(); LL | rc_foo; | ^^^^^^ value used here after move | -note: this function consumes the receiver `self` by taking ownership of it, which moves `rc_foo` +note: this function takes ownership of the receiver `self`, which moves `rc_foo` --> $DIR/move-fn-self-receiver.rs:16:20 | LL | fn use_rc_self(self: Rc) {} @@ -146,13 +146,22 @@ LL | for _val in container.custom_into_iter() {} LL | container; | ^^^^^^^^^ value used here after move | -note: this function consumes the receiver `self` by taking ownership of it, which moves `container` +note: this function takes ownership of the receiver `self`, which moves `container` --> $DIR/move-fn-self-receiver.rs:23:25 | LL | fn custom_into_iter(self) -> impl Iterator { | ^^^^ -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/moves/moves-based-on-type-access-to-field.stderr b/src/test/ui/moves/moves-based-on-type-access-to-field.stderr index 11e9456958084..3cc8ca29144ca 100644 --- a/src/test/ui/moves/moves-based-on-type-access-to-field.stderr +++ b/src/test/ui/moves/moves-based-on-type-access-to-field.stderr @@ -8,7 +8,7 @@ LL | consume(x.into_iter().next().unwrap()); LL | touch(&x[0]); | ^ value borrowed here after move | -note: this function consumes the receiver `self` by taking ownership of it, which moves `x` +note: this function takes ownership of the receiver `self`, which moves `x` --> $SRC_DIR/core/src/iter/traits/collect.rs:LL:COL | LL | fn into_iter(self) -> Self::IntoIter; diff --git a/src/test/ui/moves/moves-based-on-type-exprs.stderr b/src/test/ui/moves/moves-based-on-type-exprs.stderr index 46940cf493659..9bcec36740d62 100644 --- a/src/test/ui/moves/moves-based-on-type-exprs.stderr +++ b/src/test/ui/moves/moves-based-on-type-exprs.stderr @@ -108,7 +108,7 @@ LL | let _y = x.into_iter().next().unwrap(); LL | touch(&x); | ^^ value borrowed here after move | -note: this function consumes the receiver `self` by taking ownership of it, which moves `x` +note: this function takes ownership of the receiver `self`, which moves `x` --> $SRC_DIR/core/src/iter/traits/collect.rs:LL:COL | LL | fn into_iter(self) -> Self::IntoIter; @@ -124,7 +124,7 @@ LL | let _y = [x.into_iter().next().unwrap(); 1]; LL | touch(&x); | ^^ value borrowed here after move | -note: this function consumes the receiver `self` by taking ownership of it, which moves `x` +note: this function takes ownership of the receiver `self`, which moves `x` --> $SRC_DIR/core/src/iter/traits/collect.rs:LL:COL | LL | fn into_iter(self) -> Self::IntoIter; diff --git a/src/test/ui/suggestions/borrow-for-loop-head.stderr b/src/test/ui/suggestions/borrow-for-loop-head.stderr index de342a969f4eb..28c319b659765 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 takes ownership of the receiver `self`, 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 diff --git a/src/test/ui/unsized-locals/borrow-after-move.stderr b/src/test/ui/unsized-locals/borrow-after-move.stderr index 5934276cc1dda..4f2bc06d4ab8e 100644 --- a/src/test/ui/unsized-locals/borrow-after-move.stderr +++ b/src/test/ui/unsized-locals/borrow-after-move.stderr @@ -51,7 +51,7 @@ LL | y.foo(); LL | println!("{}", &y); | ^^ value borrowed here after move | -note: this function consumes the receiver `self` by taking ownership of it, which moves `y` +note: this function takes ownership of the receiver `self`, which moves `y` --> $DIR/borrow-after-move.rs:5:12 | LL | fn foo(self) -> String; diff --git a/src/test/ui/unsized-locals/double-move.stderr b/src/test/ui/unsized-locals/double-move.stderr index b897dbbc9a3aa..4bb2ad88faf3b 100644 --- a/src/test/ui/unsized-locals/double-move.stderr +++ b/src/test/ui/unsized-locals/double-move.stderr @@ -47,7 +47,7 @@ LL | y.foo(); LL | y.foo(); | ^ value used here after move | -note: this function consumes the receiver `self` by taking ownership of it, which moves `y` +note: this function takes ownership of the receiver `self`, which moves `y` --> $DIR/double-move.rs:5:12 | LL | fn foo(self) -> String; diff --git a/src/test/ui/use/use-after-move-self-based-on-type.stderr b/src/test/ui/use/use-after-move-self-based-on-type.stderr index b9440f4de07a9..7fdc4ab251fe8 100644 --- a/src/test/ui/use/use-after-move-self-based-on-type.stderr +++ b/src/test/ui/use/use-after-move-self-based-on-type.stderr @@ -8,7 +8,7 @@ LL | self.bar(); LL | return self.x; | ^^^^^^ value used here after move | -note: this function consumes the receiver `self` by taking ownership of it, which moves `self` +note: this function takes ownership of the receiver `self`, which moves `self` --> $DIR/use-after-move-self-based-on-type.rs:15:16 | LL | pub fn bar(self) {} diff --git a/src/test/ui/use/use-after-move-self.stderr b/src/test/ui/use/use-after-move-self.stderr index 3da53b024db44..073deee63b98c 100644 --- a/src/test/ui/use/use-after-move-self.stderr +++ b/src/test/ui/use/use-after-move-self.stderr @@ -8,7 +8,7 @@ LL | self.bar(); LL | return *self.x; | ^^^^^^^ value used here after move | -note: this function consumes the receiver `self` by taking ownership of it, which moves `self` +note: this function takes ownership of the receiver `self`, which moves `self` --> $DIR/use-after-move-self.rs:13:16 | LL | pub fn bar(self) {} diff --git a/src/test/ui/walk-struct-literal-with.stderr b/src/test/ui/walk-struct-literal-with.stderr index ece63a2b81947..cda08b0f4e09c 100644 --- a/src/test/ui/walk-struct-literal-with.stderr +++ b/src/test/ui/walk-struct-literal-with.stderr @@ -8,7 +8,7 @@ LL | let end = Mine{other_val:1, ..start.make_string_bar()}; LL | println!("{}", start.test); | ^^^^^^^^^^ value borrowed here after move | -note: this function consumes the receiver `self` by taking ownership of it, which moves `start` +note: this function takes ownership of the receiver `self`, which moves `start` --> $DIR/walk-struct-literal-with.rs:7:28 | LL | fn make_string_bar(mut self) -> Mine{