Skip to content

Commit d189e6d

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 7486b9c commit d189e6d

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
@@ -35,6 +35,7 @@ use std::rc::Rc;
3535
use rustc_data_structures::sync::Lrc;
3636
use std::hash::{Hash, Hasher};
3737
use syntax::ast;
38+
use syntax::source_map::CompilerDesugaringKind;
3839
use syntax_pos::{MultiSpan, Span};
3940
use errors::{Applicability, DiagnosticBuilder, DiagnosticId};
4041
use log::debug;
@@ -746,6 +747,19 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> {
746747
},
747748
moved_lp.ty));
748749
}
750+
if let (Some(CompilerDesugaringKind::ForLoop), Ok(snippet)) = (
751+
move_span.compiler_desugaring_kind(),
752+
self.tcx.sess.source_map().span_to_snippet(move_span),
753+
) {
754+
if !snippet.starts_with("&") {
755+
err.span_suggestion(
756+
move_span,
757+
"consider borrowing this to avoid moving it into the for loop",
758+
format!("&{}", snippet),
759+
Applicability::MaybeIncorrect,
760+
);
761+
}
762+
}
749763

750764
// Note: we used to suggest adding a `ref binding` or calling
751765
// `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)