Skip to content

Commit 4691471

Browse files
committed
Auto merge of #59195 - estebank:for-loop-move, r=petrochenkov
When moving out of a for loop head, suggest borrowing it When encountering code like the following, suggest borrowing the for loop head to avoid moving it into the for loop pattern: ``` fn main() { let a = vec![1, 2, 3]; for i in &a { for j in a { println!("{} * {} = {}", i, j, i * j); } } } ``` Fix #25534.
2 parents 3752b3d + 66202c1 commit 4691471

File tree

5 files changed

+74
-1
lines changed

5 files changed

+74
-1
lines changed

src/librustc/hir/lowering.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -4326,13 +4326,14 @@ impl<'a> LoweringContext<'a> {
43264326
// }
43274327

43284328
// expand <head>
4329-
let head = self.lower_expr(head);
4329+
let mut head = self.lower_expr(head);
43304330
let head_sp = head.span;
43314331
let desugared_span = self.mark_span_with_reason(
43324332
CompilerDesugaringKind::ForLoop,
43334333
head_sp,
43344334
None,
43354335
);
4336+
head.span = desugared_span;
43364337

43374338
let iter = self.str_to_ident("iter");
43384339

src/librustc_borrowck/borrowck/mod.rs

+14
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ use std::fmt;
3434
use std::rc::Rc;
3535
use rustc_data_structures::sync::Lrc;
3636
use std::hash::{Hash, Hasher};
37+
use syntax::source_map::CompilerDesugaringKind;
3738
use syntax_pos::{MultiSpan, Span};
3839
use errors::{Applicability, DiagnosticBuilder, DiagnosticId};
3940
use log::debug;
@@ -743,6 +744,19 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> {
743744
},
744745
moved_lp.ty));
745746
}
747+
if let (Some(CompilerDesugaringKind::ForLoop), Ok(snippet)) = (
748+
move_span.compiler_desugaring_kind(),
749+
self.tcx.sess.source_map().span_to_snippet(move_span),
750+
) {
751+
if !snippet.starts_with("&") {
752+
err.span_suggestion(
753+
move_span,
754+
"consider borrowing this to avoid moving it into the for loop",
755+
format!("&{}", snippet),
756+
Applicability::MaybeIncorrect,
757+
);
758+
}
759+
}
746760

747761
// Note: we used to suggest adding a `ref binding` or calling
748762
// `clone` but those suggestions have been removed because
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
error[E0505]: cannot move out of `a` because it is borrowed
2+
--> $DIR/borrow-for-loop-head.rs:4:18
3+
|
4+
LL | for i in &a {
5+
| --
6+
| |
7+
| borrow of `a` occurs here
8+
| borrow later used here
9+
LL | for j in a {
10+
| ^ move out of `a` occurs here
11+
12+
error[E0382]: use of moved value: `a`
13+
--> $DIR/borrow-for-loop-head.rs:4:18
14+
|
15+
LL | let a = vec![1, 2, 3];
16+
| - move occurs because `a` has type `std::vec::Vec<i32>`, which does not implement the `Copy` trait
17+
LL | for i in &a {
18+
LL | for j in a {
19+
| ^ value moved here, in previous iteration of loop
20+
21+
error: aborting due to 2 previous errors
22+
23+
Some errors occurred: E0382, E0505.
24+
For more information about an error, try `rustc --explain E0382`.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
fn main() {
2+
let a = vec![1, 2, 3];
3+
for i in &a {
4+
for j in a {
5+
//~^ ERROR cannot move out of `a` because it is borrowed
6+
//~| ERROR use of moved value: `a`
7+
println!("{} * {} = {}", i, j, i * j);
8+
}
9+
}
10+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
error[E0505]: cannot move out of `a` because it is borrowed
2+
--> $DIR/borrow-for-loop-head.rs:4:18
3+
|
4+
LL | for i in &a {
5+
| - borrow of `a` occurs here
6+
LL | for j in a {
7+
| ^ move out of `a` occurs here
8+
9+
error[E0382]: use of moved value: `a`
10+
--> $DIR/borrow-for-loop-head.rs:4:18
11+
|
12+
LL | for j in a {
13+
| ^ value moved here in previous iteration of loop
14+
|
15+
= note: move occurs because `a` has type `std::vec::Vec<i32>`, which does not implement the `Copy` trait
16+
help: consider borrowing this to avoid moving it into the for loop
17+
|
18+
LL | for j in &a {
19+
| ^^
20+
21+
error: aborting due to 2 previous errors
22+
23+
Some errors occurred: E0382, E0505.
24+
For more information about an error, try `rustc --explain E0382`.

0 commit comments

Comments
 (0)