Skip to content

Commit ae883dc

Browse files
committed
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); } } } ```
1 parent c7b5f4d commit ae883dc

File tree

4 files changed

+50
-1
lines changed

4 files changed

+50
-1
lines changed

src/librustc/hir/lowering.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -4334,13 +4334,14 @@ impl<'a> LoweringContext<'a> {
43344334
// }
43354335

43364336
// expand <head>
4337-
let head = self.lower_expr(head);
4337+
let mut head = self.lower_expr(head);
43384338
let head_sp = head.span;
43394339
let desugared_span = self.mark_span_with_reason(
43404340
CompilerDesugaringKind::ForLoop,
43414341
head_sp,
43424342
None,
43434343
);
4344+
head.span = desugared_span;
43444345

43454346
let iter = self.str_to_ident("iter");
43464347

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;
@@ -744,6 +745,19 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> {
744745
},
745746
moved_lp.ty));
746747
}
748+
if let (Some(CompilerDesugaringKind::ForLoop), Ok(snippet)) = (
749+
move_span.compiler_desugaring_kind(),
750+
self.tcx.sess.source_map().span_to_snippet(move_span),
751+
) {
752+
if !snippet.starts_with("&") {
753+
err.span_suggestion(
754+
move_span,
755+
"consider borrowing this to avoid moving it into the for loop",
756+
format!("&{}", snippet),
757+
Applicability::MaybeIncorrect,
758+
);
759+
}
760+
}
747761

748762
// Note: we used to suggest adding a `ref binding` or calling
749763
// `clone` but those suggestions have been removed because
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)