Rollup merge of #80324 - Aaron1011:loop-move-fn-self, r=oli-obk
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.
This commit is contained in:
commit
8e6472fe32
@ -151,95 +151,88 @@ pub(in crate::borrow_check) fn report_use_of_moved_or_uninitialized(
|
||||
|
||||
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 {
|
||||
}
|
||||
|
||||
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 implicit call to `.into_iter()`{}",
|
||||
place_name, partially_str, loop_message
|
||||
),
|
||||
);
|
||||
} else {
|
||||
err.span_label(
|
||||
fn_call_span,
|
||||
&format!(
|
||||
"{} {}moved due to this method call{}",
|
||||
place_name, partially_str, loop_message
|
||||
),
|
||||
);
|
||||
}
|
||||
// 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, in previous iteration of loop",
|
||||
partially_str, move_msg
|
||||
),
|
||||
format!("value {}moved{} here{}", partially_str, move_msg, loop_message),
|
||||
);
|
||||
} 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 => {
|
||||
err.span_label(
|
||||
fn_call_span,
|
||||
&format!(
|
||||
"{} {}moved due to this call",
|
||||
place_name, partially_str
|
||||
),
|
||||
);
|
||||
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
|
||||
),
|
||||
);
|
||||
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)
|
||||
);
|
||||
}
|
||||
}
|
||||
// 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),
|
||||
);
|
||||
// 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 @@ pub(in crate::borrow_check) fn report_use_of_moved_or_uninitialized(
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
if let UseSpans::PatUse(span) = move_spans {
|
||||
err.span_suggestion_verbose(
|
||||
span.shrink_to_lo(),
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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() {}
|
||||
|
@ -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<Self>) {}
|
||||
@ -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<Box<Self>>) {}
|
||||
@ -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<Self>) {}
|
||||
@ -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<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`.
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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) {}
|
||||
|
@ -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) {}
|
||||
|
@ -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{
|
||||
|
Loading…
Reference in New Issue
Block a user