Skip to content

Commit 8e6472f

Browse files
authored
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.
2 parents 56504a0 + 20979aa commit 8e6472f

15 files changed

+108
-94
lines changed

compiler/rustc_mir/src/borrow_check/diagnostics/conflict_errors.rs

+68-74
Original file line numberDiff line numberDiff line change
@@ -151,95 +151,88 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
151151

152152
let move_msg = if move_spans.for_closure() { " into closure" } else { "" };
153153

154+
let loop_message = if location == move_out.source || move_site.traversed_back_edge {
155+
", in previous iteration of loop"
156+
} else {
157+
""
158+
};
159+
154160
if location == move_out.source {
155-
err.span_label(
156-
span,
157-
format!(
158-
"value {}moved{} here, in previous iteration of loop",
159-
partially_str, move_msg
160-
),
161-
);
162161
is_loop_move = true;
163-
} else if move_site.traversed_back_edge {
164-
err.span_label(
165-
move_span,
166-
format!(
167-
"value {}moved{} here, in previous iteration of loop",
168-
partially_str, move_msg
169-
),
170-
);
171-
} else {
172-
if let UseSpans::FnSelfUse { var_span, fn_call_span, fn_span, kind } =
173-
move_spans
174-
{
175-
let place_name = self
176-
.describe_place(moved_place.as_ref())
177-
.map(|n| format!("`{}`", n))
178-
.unwrap_or_else(|| "value".to_owned());
179-
match kind {
180-
FnSelfUseKind::FnOnceCall => {
162+
}
163+
164+
if let UseSpans::FnSelfUse { var_span, fn_call_span, fn_span, kind } = move_spans {
165+
let place_name = self
166+
.describe_place(moved_place.as_ref())
167+
.map(|n| format!("`{}`", n))
168+
.unwrap_or_else(|| "value".to_owned());
169+
match kind {
170+
FnSelfUseKind::FnOnceCall => {
171+
err.span_label(
172+
fn_call_span,
173+
&format!(
174+
"{} {}moved due to this call{}",
175+
place_name, partially_str, loop_message
176+
),
177+
);
178+
err.span_note(
179+
var_span,
180+
"this value implements `FnOnce`, which causes it to be moved when called",
181+
);
182+
}
183+
FnSelfUseKind::Operator { self_arg } => {
184+
err.span_label(
185+
fn_call_span,
186+
&format!(
187+
"{} {}moved due to usage in operator{}",
188+
place_name, partially_str, loop_message
189+
),
190+
);
191+
if self.fn_self_span_reported.insert(fn_span) {
192+
err.span_note(
193+
self_arg.span,
194+
"calling this operator moves the left-hand side",
195+
);
196+
}
197+
}
198+
FnSelfUseKind::Normal { self_arg, implicit_into_iter } => {
199+
if implicit_into_iter {
181200
err.span_label(
182201
fn_call_span,
183202
&format!(
184-
"{} {}moved due to this call",
185-
place_name, partially_str
203+
"{} {}moved due to this implicit call to `.into_iter()`{}",
204+
place_name, partially_str, loop_message
186205
),
187206
);
188-
err.span_note(
189-
var_span,
190-
"this value implements `FnOnce`, which causes it to be moved when called",
191-
);
192-
}
193-
FnSelfUseKind::Operator { self_arg } => {
207+
} else {
194208
err.span_label(
195209
fn_call_span,
196210
&format!(
197-
"{} {}moved due to usage in operator",
198-
place_name, partially_str
211+
"{} {}moved due to this method call{}",
212+
place_name, partially_str, loop_message
199213
),
200214
);
201-
if self.fn_self_span_reported.insert(fn_span) {
202-
err.span_note(
203-
self_arg.span,
204-
"calling this operator moves the left-hand side",
205-
);
206-
}
207215
}
208-
FnSelfUseKind::Normal { self_arg, implicit_into_iter } => {
209-
if implicit_into_iter {
210-
err.span_label(
211-
fn_call_span,
212-
&format!(
213-
"{} {}moved due to this implicit call to `.into_iter()`",
214-
place_name, partially_str
215-
),
216-
);
217-
} else {
218-
err.span_label(
219-
fn_call_span,
220-
&format!(
221-
"{} {}moved due to this method call",
222-
place_name, partially_str
223-
),
224-
);
225-
}
226-
// Avoid pointing to the same function in multiple different
227-
// error messages
228-
if self.fn_self_span_reported.insert(self_arg.span) {
229-
err.span_note(
230-
self_arg.span,
231-
&format!("this function consumes the receiver `self` by taking ownership of it, which moves {}", place_name)
232-
);
233-
}
216+
// Avoid pointing to the same function in multiple different
217+
// error messages
218+
if self.fn_self_span_reported.insert(self_arg.span) {
219+
err.span_note(
220+
self_arg.span,
221+
&format!("this function takes ownership of the receiver `self`, which moves {}", place_name)
222+
);
234223
}
235-
// Deref::deref takes &self, which cannot cause a move
236-
FnSelfUseKind::DerefCoercion { .. } => unreachable!(),
237224
}
238-
} else {
239-
err.span_label(
240-
move_span,
241-
format!("value {}moved{} here", partially_str, move_msg),
242-
);
225+
// Deref::deref takes &self, which cannot cause a move
226+
FnSelfUseKind::DerefCoercion { .. } => unreachable!(),
227+
}
228+
} else {
229+
err.span_label(
230+
move_span,
231+
format!("value {}moved{} here{}", partially_str, move_msg, loop_message),
232+
);
233+
// If the move error occurs due to a loop, don't show
234+
// another message for the same span
235+
if loop_message.is_empty() {
243236
move_spans.var_span_label(
244237
&mut err,
245238
format!(
@@ -250,6 +243,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
250243
);
251244
}
252245
}
246+
253247
if let UseSpans::PatUse(span) = move_spans {
254248
err.span_suggestion_verbose(
255249
span.shrink_to_lo(),

src/test/ui/codemap_tests/tab_3.stderr

+1-1
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ LL | {
99
LL | println!("{:?}", some_vec);
1010
| ^^^^^^^^ value borrowed here after move
1111
|
12-
note: this function consumes the receiver `self` by taking ownership of it, which moves `some_vec`
12+
note: this function takes ownership of the receiver `self`, which moves `some_vec`
1313
--> $SRC_DIR/core/src/iter/traits/collect.rs:LL:COL
1414
|
1515
LL | fn into_iter(self) -> Self::IntoIter;

src/test/ui/issues/issue-34721.stderr

+1-1
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ LL | };
1313
LL | x.zero()
1414
| ^ value used here after move
1515
|
16-
note: this function consumes the receiver `self` by taking ownership of it, which moves `x`
16+
note: this function takes ownership of the receiver `self`, which moves `x`
1717
--> $DIR/issue-34721.rs:4:13
1818
|
1919
LL | fn zero(self) -> Self;

src/test/ui/issues/issue-61108.stderr

+1-1
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ LL | for l in bad_letters {
1212
LL | bad_letters.push('s');
1313
| ^^^^^^^^^^^ value borrowed here after move
1414
|
15-
note: this function consumes the receiver `self` by taking ownership of it, which moves `bad_letters`
15+
note: this function takes ownership of the receiver `self`, which moves `bad_letters`
1616
--> $SRC_DIR/core/src/iter/traits/collect.rs:LL:COL
1717
|
1818
LL | fn into_iter(self) -> Self::IntoIter;

src/test/ui/issues/issue-64559.stderr

+1-1
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ LL | let _closure = || orig;
1313
| |
1414
| value used here after move
1515
|
16-
note: this function consumes the receiver `self` by taking ownership of it, which moves `orig`
16+
note: this function takes ownership of the receiver `self`, which moves `orig`
1717
--> $SRC_DIR/core/src/iter/traits/collect.rs:LL:COL
1818
|
1919
LL | fn into_iter(self) -> Self::IntoIter;

src/test/ui/moves/move-fn-self-receiver.rs

+5
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,11 @@ fn move_out(val: Container) {
6969
let container = Container(vec![]);
7070
for _val in container.custom_into_iter() {}
7171
container; //~ ERROR use of moved
72+
73+
let foo2 = Foo;
74+
loop {
75+
foo2.use_self(); //~ ERROR use of moved
76+
}
7277
}
7378

7479
fn main() {}

src/test/ui/moves/move-fn-self-receiver.stderr

+16-7
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ LL | val.0.into_iter().next();
66
LL | val.0;
77
| ^^^^^ value used here after move
88
|
9-
note: this function consumes the receiver `self` by taking ownership of it, which moves `val.0`
9+
note: this function takes ownership of the receiver `self`, which moves `val.0`
1010
--> $SRC_DIR/core/src/iter/traits/collect.rs:LL:COL
1111
|
1212
LL | fn into_iter(self) -> Self::IntoIter;
@@ -23,7 +23,7 @@ LL | foo.use_self();
2323
LL | foo;
2424
| ^^^ value used here after move
2525
|
26-
note: this function consumes the receiver `self` by taking ownership of it, which moves `foo`
26+
note: this function takes ownership of the receiver `self`, which moves `foo`
2727
--> $DIR/move-fn-self-receiver.rs:13:17
2828
|
2929
LL | fn use_self(self) {}
@@ -49,7 +49,7 @@ LL | boxed_foo.use_box_self();
4949
LL | boxed_foo;
5050
| ^^^^^^^^^ value used here after move
5151
|
52-
note: this function consumes the receiver `self` by taking ownership of it, which moves `boxed_foo`
52+
note: this function takes ownership of the receiver `self`, which moves `boxed_foo`
5353
--> $DIR/move-fn-self-receiver.rs:14:21
5454
|
5555
LL | fn use_box_self(self: Box<Self>) {}
@@ -65,7 +65,7 @@ LL | pin_box_foo.use_pin_box_self();
6565
LL | pin_box_foo;
6666
| ^^^^^^^^^^^ value used here after move
6767
|
68-
note: this function consumes the receiver `self` by taking ownership of it, which moves `pin_box_foo`
68+
note: this function takes ownership of the receiver `self`, which moves `pin_box_foo`
6969
--> $DIR/move-fn-self-receiver.rs:15:25
7070
|
7171
LL | fn use_pin_box_self(self: Pin<Box<Self>>) {}
@@ -91,7 +91,7 @@ LL | rc_foo.use_rc_self();
9191
LL | rc_foo;
9292
| ^^^^^^ value used here after move
9393
|
94-
note: this function consumes the receiver `self` by taking ownership of it, which moves `rc_foo`
94+
note: this function takes ownership of the receiver `self`, which moves `rc_foo`
9595
--> $DIR/move-fn-self-receiver.rs:16:20
9696
|
9797
LL | fn use_rc_self(self: Rc<Self>) {}
@@ -146,13 +146,22 @@ LL | for _val in container.custom_into_iter() {}
146146
LL | container;
147147
| ^^^^^^^^^ value used here after move
148148
|
149-
note: this function consumes the receiver `self` by taking ownership of it, which moves `container`
149+
note: this function takes ownership of the receiver `self`, which moves `container`
150150
--> $DIR/move-fn-self-receiver.rs:23:25
151151
|
152152
LL | fn custom_into_iter(self) -> impl Iterator<Item = bool> {
153153
| ^^^^
154154

155-
error: aborting due to 11 previous errors
155+
error[E0382]: use of moved value: `foo2`
156+
--> $DIR/move-fn-self-receiver.rs:75:9
157+
|
158+
LL | let foo2 = Foo;
159+
| ---- move occurs because `foo2` has type `Foo`, which does not implement the `Copy` trait
160+
LL | loop {
161+
LL | foo2.use_self();
162+
| ^^^^ ---------- `foo2` moved due to this method call, in previous iteration of loop
163+
164+
error: aborting due to 12 previous errors
156165

157166
Some errors have detailed explanations: E0382, E0505.
158167
For more information about an error, try `rustc --explain E0382`.

src/test/ui/moves/moves-based-on-type-access-to-field.stderr

+1-1
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ LL | consume(x.into_iter().next().unwrap());
88
LL | touch(&x[0]);
99
| ^ value borrowed here after move
1010
|
11-
note: this function consumes the receiver `self` by taking ownership of it, which moves `x`
11+
note: this function takes ownership of the receiver `self`, which moves `x`
1212
--> $SRC_DIR/core/src/iter/traits/collect.rs:LL:COL
1313
|
1414
LL | fn into_iter(self) -> Self::IntoIter;

src/test/ui/moves/moves-based-on-type-exprs.stderr

+2-2
Original file line numberDiff line numberDiff line change
@@ -108,7 +108,7 @@ LL | let _y = x.into_iter().next().unwrap();
108108
LL | touch(&x);
109109
| ^^ value borrowed here after move
110110
|
111-
note: this function consumes the receiver `self` by taking ownership of it, which moves `x`
111+
note: this function takes ownership of the receiver `self`, which moves `x`
112112
--> $SRC_DIR/core/src/iter/traits/collect.rs:LL:COL
113113
|
114114
LL | fn into_iter(self) -> Self::IntoIter;
@@ -124,7 +124,7 @@ LL | let _y = [x.into_iter().next().unwrap(); 1];
124124
LL | touch(&x);
125125
| ^^ value borrowed here after move
126126
|
127-
note: this function consumes the receiver `self` by taking ownership of it, which moves `x`
127+
note: this function takes ownership of the receiver `self`, which moves `x`
128128
--> $SRC_DIR/core/src/iter/traits/collect.rs:LL:COL
129129
|
130130
LL | fn into_iter(self) -> Self::IntoIter;

src/test/ui/suggestions/borrow-for-loop-head.stderr

+7-1
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,14 @@ LL | for i in &a {
1515
LL | for j in a {
1616
| ^
1717
| |
18-
| value moved here, in previous iteration of loop
18+
| `a` moved due to this implicit call to `.into_iter()`, in previous iteration of loop
1919
| help: consider borrowing to avoid moving into the for loop: `&a`
20+
|
21+
note: this function takes ownership of the receiver `self`, which moves `a`
22+
--> $SRC_DIR/core/src/iter/traits/collect.rs:LL:COL
23+
|
24+
LL | fn into_iter(self) -> Self::IntoIter;
25+
| ^^^^
2026

2127
error: aborting due to 2 previous errors
2228

src/test/ui/unsized-locals/borrow-after-move.stderr

+1-1
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ LL | y.foo();
5151
LL | println!("{}", &y);
5252
| ^^ value borrowed here after move
5353
|
54-
note: this function consumes the receiver `self` by taking ownership of it, which moves `y`
54+
note: this function takes ownership of the receiver `self`, which moves `y`
5555
--> $DIR/borrow-after-move.rs:5:12
5656
|
5757
LL | fn foo(self) -> String;

src/test/ui/unsized-locals/double-move.stderr

+1-1
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ LL | y.foo();
4747
LL | y.foo();
4848
| ^ value used here after move
4949
|
50-
note: this function consumes the receiver `self` by taking ownership of it, which moves `y`
50+
note: this function takes ownership of the receiver `self`, which moves `y`
5151
--> $DIR/double-move.rs:5:12
5252
|
5353
LL | fn foo(self) -> String;

src/test/ui/use/use-after-move-self-based-on-type.stderr

+1-1
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ LL | self.bar();
88
LL | return self.x;
99
| ^^^^^^ value used here after move
1010
|
11-
note: this function consumes the receiver `self` by taking ownership of it, which moves `self`
11+
note: this function takes ownership of the receiver `self`, which moves `self`
1212
--> $DIR/use-after-move-self-based-on-type.rs:15:16
1313
|
1414
LL | pub fn bar(self) {}

src/test/ui/use/use-after-move-self.stderr

+1-1
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ LL | self.bar();
88
LL | return *self.x;
99
| ^^^^^^^ value used here after move
1010
|
11-
note: this function consumes the receiver `self` by taking ownership of it, which moves `self`
11+
note: this function takes ownership of the receiver `self`, which moves `self`
1212
--> $DIR/use-after-move-self.rs:13:16
1313
|
1414
LL | pub fn bar(self) {}

src/test/ui/walk-struct-literal-with.stderr

+1-1
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ LL | let end = Mine{other_val:1, ..start.make_string_bar()};
88
LL | println!("{}", start.test);
99
| ^^^^^^^^^^ value borrowed here after move
1010
|
11-
note: this function consumes the receiver `self` by taking ownership of it, which moves `start`
11+
note: this function takes ownership of the receiver `self`, which moves `start`
1212
--> $DIR/walk-struct-literal-with.rs:7:28
1313
|
1414
LL | fn make_string_bar(mut self) -> Mine{

0 commit comments

Comments
 (0)