diff options
| author | Yan Chen <ychen2@futurewei.com> | 2022-07-22 09:53:39 -0700 |
|---|---|---|
| committer | Yan Chen <ychen2@futurewei.com> | 2022-08-15 11:20:32 -0700 |
| commit | 15713e1717219be78c46234d2255fb105f87c02c (patch) | |
| tree | 5e21707d82618fbc7800c3c03a285348a7877fc0 | |
| parent | 4916e2b9e6ef8cee6f9c6abb75bd01ba9dc07e5c (diff) | |
| download | rust-15713e1717219be78c46234d2255fb105f87c02c.tar.gz rust-15713e1717219be78c46234d2255fb105f87c02c.zip | |
Fix #95079 by adding help and suggestion for missing move in nested closure
7 files changed, 104 insertions, 0 deletions
diff --git a/compiler/rustc_borrowck/src/diagnostics/region_errors.rs b/compiler/rustc_borrowck/src/diagnostics/region_errors.rs index bd3a2a3d694..0dce5be953e 100644 --- a/compiler/rustc_borrowck/src/diagnostics/region_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/region_errors.rs @@ -546,6 +546,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { executing...", ); diag.note("...therefore, they cannot allow references to captured variables to escape"); + self.suggest_move_on_borrowing_closure(&mut diag); diag } @@ -716,6 +717,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { self.add_static_impl_trait_suggestion(&mut diag, *fr, fr_name, *outlived_fr); self.suggest_adding_lifetime_params(&mut diag, *fr, *outlived_fr); + self.suggest_move_on_borrowing_closure(&mut diag); diag } @@ -901,4 +903,39 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { suggest_adding_lifetime_params(self.infcx.tcx, sub, ty_sup, ty_sub, diag); } + + fn suggest_move_on_borrowing_closure(&self, diag: &mut Diagnostic) { + let map = self.infcx.tcx.hir(); + let body_id = map.body_owned_by(self.mir_def_id()); + let expr = &map.body(body_id).value; + let mut closure_span = None::<rustc_span::Span>; + match expr.kind { + hir::ExprKind::MethodCall(.., args, _) => { + // only the first closre parameter of the method. args[0] is MethodCall PathSegment + for i in 1..args.len() { + if let hir::ExprKind::Closure(..) = args[i].kind { + closure_span = Some(args[i].span.shrink_to_lo()); + break; + } + } + } + hir::ExprKind::Block(blk, _) => { + if let Some(ref expr) = blk.expr { + // only when the block is a closure + if let hir::ExprKind::Closure(..) = expr.kind { + closure_span = Some(expr.span.shrink_to_lo()); + } + } + } + _ => {} + } + if let Some(closure_span) = closure_span { + diag.span_suggestion_verbose( + closure_span, + format!("consider adding 'move' keyword before the nested closure"), + "move ", + Applicability::MaybeIncorrect, + ); + } + } } diff --git a/src/test/ui/borrowck/borrowck-describe-lvalue.stderr b/src/test/ui/borrowck/borrowck-describe-lvalue.stderr index f909dbc4082..cfcc62de438 100644 --- a/src/test/ui/borrowck/borrowck-describe-lvalue.stderr +++ b/src/test/ui/borrowck/borrowck-describe-lvalue.stderr @@ -36,6 +36,10 @@ LL | | } | = note: `FnMut` closures only have access to their captured variables while they are executing... = note: ...therefore, they cannot allow references to captured variables to escape +help: consider adding 'move' keyword before the nested closure + | +LL | move || { + | ++++ error[E0503]: cannot use `f.x` because it was mutably borrowed --> $DIR/borrowck-describe-lvalue.rs:37:9 diff --git a/src/test/ui/borrowck/issue-53432-nested-closure-outlives-borrowed-value.stderr b/src/test/ui/borrowck/issue-53432-nested-closure-outlives-borrowed-value.stderr index d98b3bae4e0..f0b57484632 100644 --- a/src/test/ui/borrowck/issue-53432-nested-closure-outlives-borrowed-value.stderr +++ b/src/test/ui/borrowck/issue-53432-nested-closure-outlives-borrowed-value.stderr @@ -10,6 +10,10 @@ LL | || f() // The `nested` closure | ^^^^^^ returning this value requires that `'1` must outlive `'2` | = note: closure implements `Fn`, so references to captured variables can't escape the closure +help: consider adding 'move' keyword before the nested closure + | +LL | move || f() // The `nested` closure + | ++++ error: aborting due to previous error diff --git a/src/test/ui/borrowck/issue-95079-missing-move-in-nested-closure.rs b/src/test/ui/borrowck/issue-95079-missing-move-in-nested-closure.rs new file mode 100644 index 00000000000..95847d8d301 --- /dev/null +++ b/src/test/ui/borrowck/issue-95079-missing-move-in-nested-closure.rs @@ -0,0 +1,14 @@ +fn foo1(s: &str) -> impl Iterator<Item = String> + '_ { + None.into_iter() + .flat_map(move |()| s.chars().map(|c| format!("{}{}", c, s))) + //~^ ERROR captured variable cannot escape `FnMut` closure body + //~| HELP consider adding 'move' keyword before the nested closure +} + +fn foo2(s: &str) -> impl Sized + '_ { + move |()| s.chars().map(|c| format!("{}{}", c, s)) + //~^ ERROR lifetime may not live long enough + //~| HELP consider adding 'move' keyword before the nested closure +} + +fn main() {} diff --git a/src/test/ui/borrowck/issue-95079-missing-move-in-nested-closure.stderr b/src/test/ui/borrowck/issue-95079-missing-move-in-nested-closure.stderr new file mode 100644 index 00000000000..2eae614a2f5 --- /dev/null +++ b/src/test/ui/borrowck/issue-95079-missing-move-in-nested-closure.stderr @@ -0,0 +1,37 @@ +error: captured variable cannot escape `FnMut` closure body + --> $DIR/issue-95079-missing-move-in-nested-closure.rs:3:29 + | +LL | fn foo1(s: &str) -> impl Iterator<Item = String> + '_ { + | - variable defined here +LL | None.into_iter() +LL | .flat_map(move |()| s.chars().map(|c| format!("{}{}", c, s))) + | - -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | | | + | | returns a reference to a captured variable which escapes the closure body + | | variable captured here + | inferred to be a `FnMut` closure + | + = note: `FnMut` closures only have access to their captured variables while they are executing... + = note: ...therefore, they cannot allow references to captured variables to escape +help: consider adding 'move' keyword before the nested closure + | +LL | .flat_map(move |()| s.chars().map(move |c| format!("{}{}", c, s))) + | ++++ + +error: lifetime may not live long enough + --> $DIR/issue-95079-missing-move-in-nested-closure.rs:9:15 + | +LL | move |()| s.chars().map(|c| format!("{}{}", c, s)) + | --------- ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ returning this value requires that `'1` must outlive `'2` + | | | + | | return type of closure `Map<Chars<'_>, [closure@$DIR/issue-95079-missing-move-in-nested-closure.rs:9:29: 9:32]>` contains a lifetime `'2` + | lifetime `'1` represents this closure's body + | + = note: closure implements `Fn`, so references to captured variables can't escape the closure +help: consider adding 'move' keyword before the nested closure + | +LL | move |()| s.chars().map(move |c| format!("{}{}", c, s)) + | ++++ + +error: aborting due to 2 previous errors + diff --git a/src/test/ui/issues/issue-40510-3.stderr b/src/test/ui/issues/issue-40510-3.stderr index 22186ba9a67..eb077415e6c 100644 --- a/src/test/ui/issues/issue-40510-3.stderr +++ b/src/test/ui/issues/issue-40510-3.stderr @@ -14,6 +14,10 @@ LL | | } | = note: `FnMut` closures only have access to their captured variables while they are executing... = note: ...therefore, they cannot allow references to captured variables to escape +help: consider adding 'move' keyword before the nested closure + | +LL | move || { + | ++++ error: aborting due to previous error diff --git a/src/test/ui/issues/issue-49824.stderr b/src/test/ui/issues/issue-49824.stderr index 2fec482543d..14beadececb 100644 --- a/src/test/ui/issues/issue-49824.stderr +++ b/src/test/ui/issues/issue-49824.stderr @@ -14,6 +14,10 @@ LL | | } | = note: `FnMut` closures only have access to their captured variables while they are executing... = note: ...therefore, they cannot allow references to captured variables to escape +help: consider adding 'move' keyword before the nested closure + | +LL | move || { + | ++++ error: aborting due to previous error |
