diff options
| author | bors <bors@rust-lang.org> | 2019-03-25 00:38:15 +0000 |
|---|---|---|
| committer | bors <bors@rust-lang.org> | 2019-03-25 00:38:15 +0000 |
| commit | 46914715e2427e376ee9593b62ff8661caadee93 (patch) | |
| tree | 24a88b34e85ecd82a50d972c423d57449871c12f /src | |
| parent | 3752b3d3a56bf3eabb588b7d595cd1f8accc0286 (diff) | |
| parent | 66202c113a5397198757d1eb09b78eb0b9b368b1 (diff) | |
| download | rust-46914715e2427e376ee9593b62ff8661caadee93.tar.gz rust-46914715e2427e376ee9593b62ff8661caadee93.zip | |
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.
Diffstat (limited to 'src')
| -rw-r--r-- | src/librustc/hir/lowering.rs | 3 | ||||
| -rw-r--r-- | src/librustc_borrowck/borrowck/mod.rs | 14 | ||||
| -rw-r--r-- | src/test/ui/suggestions/borrow-for-loop-head.nll.stderr | 24 | ||||
| -rw-r--r-- | src/test/ui/suggestions/borrow-for-loop-head.rs | 10 | ||||
| -rw-r--r-- | src/test/ui/suggestions/borrow-for-loop-head.stderr | 24 |
5 files changed, 74 insertions, 1 deletions
diff --git a/src/librustc/hir/lowering.rs b/src/librustc/hir/lowering.rs index 8db90035c8e..891210511ca 100644 --- a/src/librustc/hir/lowering.rs +++ b/src/librustc/hir/lowering.rs @@ -4326,13 +4326,14 @@ impl<'a> LoweringContext<'a> { // } // expand <head> - let head = self.lower_expr(head); + let mut head = self.lower_expr(head); let head_sp = head.span; let desugared_span = self.mark_span_with_reason( CompilerDesugaringKind::ForLoop, head_sp, None, ); + head.span = desugared_span; let iter = self.str_to_ident("iter"); diff --git a/src/librustc_borrowck/borrowck/mod.rs b/src/librustc_borrowck/borrowck/mod.rs index 09de907b751..fe39e3ae0c6 100644 --- a/src/librustc_borrowck/borrowck/mod.rs +++ b/src/librustc_borrowck/borrowck/mod.rs @@ -34,6 +34,7 @@ use std::fmt; use std::rc::Rc; use rustc_data_structures::sync::Lrc; use std::hash::{Hash, Hasher}; +use syntax::source_map::CompilerDesugaringKind; use syntax_pos::{MultiSpan, Span}; use errors::{Applicability, DiagnosticBuilder, DiagnosticId}; use log::debug; @@ -743,6 +744,19 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> { }, moved_lp.ty)); } + if let (Some(CompilerDesugaringKind::ForLoop), Ok(snippet)) = ( + move_span.compiler_desugaring_kind(), + self.tcx.sess.source_map().span_to_snippet(move_span), + ) { + if !snippet.starts_with("&") { + err.span_suggestion( + move_span, + "consider borrowing this to avoid moving it into the for loop", + format!("&{}", snippet), + Applicability::MaybeIncorrect, + ); + } + } // Note: we used to suggest adding a `ref binding` or calling // `clone` but those suggestions have been removed because diff --git a/src/test/ui/suggestions/borrow-for-loop-head.nll.stderr b/src/test/ui/suggestions/borrow-for-loop-head.nll.stderr new file mode 100644 index 00000000000..6450f7f52a4 --- /dev/null +++ b/src/test/ui/suggestions/borrow-for-loop-head.nll.stderr @@ -0,0 +1,24 @@ +error[E0505]: cannot move out of `a` because it is borrowed + --> $DIR/borrow-for-loop-head.rs:4:18 + | +LL | for i in &a { + | -- + | | + | borrow of `a` occurs here + | borrow later used here +LL | for j in a { + | ^ move out of `a` occurs here + +error[E0382]: use of moved value: `a` + --> $DIR/borrow-for-loop-head.rs:4:18 + | +LL | let a = vec![1, 2, 3]; + | - move occurs because `a` has type `std::vec::Vec<i32>`, which does not implement the `Copy` trait +LL | for i in &a { +LL | for j in a { + | ^ value moved here, in previous iteration of loop + +error: aborting due to 2 previous errors + +Some errors occurred: E0382, E0505. +For more information about an error, try `rustc --explain E0382`. diff --git a/src/test/ui/suggestions/borrow-for-loop-head.rs b/src/test/ui/suggestions/borrow-for-loop-head.rs new file mode 100644 index 00000000000..c2bda55e589 --- /dev/null +++ b/src/test/ui/suggestions/borrow-for-loop-head.rs @@ -0,0 +1,10 @@ +fn main() { + let a = vec![1, 2, 3]; + for i in &a { + for j in a { + //~^ ERROR cannot move out of `a` because it is borrowed + //~| ERROR use of moved value: `a` + println!("{} * {} = {}", i, j, i * j); + } + } +} diff --git a/src/test/ui/suggestions/borrow-for-loop-head.stderr b/src/test/ui/suggestions/borrow-for-loop-head.stderr new file mode 100644 index 00000000000..17ac3fe86d0 --- /dev/null +++ b/src/test/ui/suggestions/borrow-for-loop-head.stderr @@ -0,0 +1,24 @@ +error[E0505]: cannot move out of `a` because it is borrowed + --> $DIR/borrow-for-loop-head.rs:4:18 + | +LL | for i in &a { + | - borrow of `a` occurs here +LL | for j in a { + | ^ move out of `a` occurs here + +error[E0382]: use of moved value: `a` + --> $DIR/borrow-for-loop-head.rs:4:18 + | +LL | for j in a { + | ^ value moved here in previous iteration of loop + | + = note: move occurs because `a` has type `std::vec::Vec<i32>`, which does not implement the `Copy` trait +help: consider borrowing this to avoid moving it into the for loop + | +LL | for j in &a { + | ^^ + +error: aborting due to 2 previous errors + +Some errors occurred: E0382, E0505. +For more information about an error, try `rustc --explain E0382`. |
