Skip to content

Commit aaebbe1

Browse files
committed
Suggest move for closures and async blocks in more cases.
1 parent 42abbd8 commit aaebbe1

9 files changed

+80
-64
lines changed

src/librustc_mir/borrow_check/diagnostics/conflict_errors.rs

+20-38
Original file line numberDiff line numberDiff line change
@@ -760,47 +760,26 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
760760
(
761761
Some(ref name),
762762
BorrowExplanation::MustBeValidFor {
763-
category: category @ ConstraintCategory::Return,
763+
category:
764+
category
765+
@
766+
(ConstraintCategory::Return
767+
| ConstraintCategory::CallArgument
768+
| ConstraintCategory::OpaqueType),
764769
from_closure: false,
765770
ref region_name,
766771
span,
767772
..
768773
},
769-
)
770-
| (
771-
Some(ref name),
772-
BorrowExplanation::MustBeValidFor {
773-
category: category @ ConstraintCategory::CallArgument,
774-
from_closure: false,
775-
ref region_name,
776-
span,
777-
..
778-
},
779-
) if borrow_spans.for_closure() => self.report_escaping_closure_capture(
780-
borrow_spans,
781-
borrow_span,
782-
region_name,
783-
category,
784-
span,
785-
&format!("`{}`", name),
786-
),
787-
(
788-
Some(ref name),
789-
BorrowExplanation::MustBeValidFor {
790-
category: category @ ConstraintCategory::OpaqueType,
791-
from_closure: false,
792-
ref region_name,
774+
) if borrow_spans.for_generator() | borrow_spans.for_closure() => self
775+
.report_escaping_closure_capture(
776+
borrow_spans,
777+
borrow_span,
778+
region_name,
779+
category,
793780
span,
794-
..
795-
},
796-
) if borrow_spans.for_generator() => self.report_escaping_closure_capture(
797-
borrow_spans,
798-
borrow_span,
799-
region_name,
800-
category,
801-
span,
802-
&format!("`{}`", name),
803-
),
781+
&format!("`{}`", name),
782+
),
804783
(
805784
ref name,
806785
BorrowExplanation::MustBeValidFor {
@@ -1187,7 +1166,6 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
11871166
) -> DiagnosticBuilder<'cx> {
11881167
let tcx = self.infcx.tcx;
11891168
let args_span = use_span.args_or_use();
1190-
let mut err = self.cannot_capture_in_long_lived_closure(args_span, captured_var, var_span);
11911169

11921170
let suggestion = match tcx.sess.source_map().span_to_snippet(args_span) {
11931171
Ok(mut string) => {
@@ -1213,6 +1191,9 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
12131191
},
12141192
None => "closure",
12151193
};
1194+
1195+
let mut err =
1196+
self.cannot_capture_in_long_lived_closure(args_span, kind, captured_var, var_span);
12161197
err.span_suggestion(
12171198
args_span,
12181199
&format!(
@@ -1225,8 +1206,9 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
12251206
);
12261207

12271208
let msg = match category {
1228-
ConstraintCategory::Return => "closure is returned here".to_string(),
1229-
ConstraintCategory::OpaqueType => "generator is returned here".to_string(),
1209+
ConstraintCategory::Return | ConstraintCategory::OpaqueType => {
1210+
format!("{} is returned here", kind)
1211+
}
12301212
ConstraintCategory::CallArgument => {
12311213
fr_name.highlight_region_name(&mut err);
12321214
format!("function requires argument type to outlive `{}`", fr_name)

src/librustc_mir/lib.rs

+1
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ Rust MIR: a lowered representation of Rust.
2525
#![feature(stmt_expr_attributes)]
2626
#![feature(trait_alias)]
2727
#![feature(option_expect_none)]
28+
#![feature(or_patterns)]
2829
#![recursion_limit = "256"]
2930

3031
#[macro_use]

src/librustc_mir/util/borrowck_errors.rs

+3-1
Original file line numberDiff line numberDiff line change
@@ -431,16 +431,18 @@ impl<'cx, 'tcx> crate::borrow_check::MirBorrowckCtxt<'cx, 'tcx> {
431431
crate fn cannot_capture_in_long_lived_closure(
432432
&self,
433433
closure_span: Span,
434+
closure_kind: &str,
434435
borrowed_path: &str,
435436
capture_span: Span,
436437
) -> DiagnosticBuilder<'cx> {
437438
let mut err = struct_span_err!(
438439
self,
439440
closure_span,
440441
E0373,
441-
"closure may outlive the current function, \
442+
"{} may outlive the current function, \
442443
but it borrows {}, \
443444
which is owned by the current function",
445+
closure_kind,
444446
borrowed_path,
445447
);
446448
err.span_label(capture_span, format!("{} is borrowed here", borrowed_path))
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,18 @@
11
// edition:2018
22
// run-rustfix
33

4-
fn foo() -> Box<impl std::future::Future<Output = u32>> {
4+
fn test_boxed() -> Box<impl std::future::Future<Output = u32>> {
55
let x = 0u32;
66
Box::new(async move { x } )
77
//~^ ERROR E0373
88
}
99

10+
fn test_ref(x: &u32) -> impl std::future::Future<Output = u32> + '_ {
11+
async move { *x }
12+
//~^ ERROR E0373
13+
}
14+
1015
fn main() {
11-
let _foo = foo();
16+
let _ = test_boxed();
17+
let _ = test_ref(&0u32);
1218
}
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,18 @@
11
// edition:2018
22
// run-rustfix
33

4-
fn foo() -> Box<impl std::future::Future<Output = u32>> {
4+
fn test_boxed() -> Box<impl std::future::Future<Output = u32>> {
55
let x = 0u32;
66
Box::new(async { x } )
77
//~^ ERROR E0373
88
}
99

10+
fn test_ref(x: &u32) -> impl std::future::Future<Output = u32> + '_ {
11+
async { *x }
12+
//~^ ERROR E0373
13+
}
14+
1015
fn main() {
11-
let _foo = foo();
16+
let _ = test_boxed();
17+
let _ = test_ref(&0u32);
1218
}
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
error[E0373]: closure may outlive the current function, but it borrows `x`, which is owned by the current function
1+
error[E0373]: async block may outlive the current function, but it borrows `x`, which is owned by the current function
22
--> $DIR/async-borrowck-escaping-block-error.rs:6:20
33
|
44
LL | Box::new(async { x } )
@@ -7,16 +7,35 @@ LL | Box::new(async { x } )
77
| | `x` is borrowed here
88
| may outlive borrowed value `x`
99
|
10-
note: generator is returned here
11-
--> $DIR/async-borrowck-escaping-block-error.rs:4:13
10+
note: async block is returned here
11+
--> $DIR/async-borrowck-escaping-block-error.rs:4:20
1212
|
13-
LL | fn foo() -> Box<impl std::future::Future<Output = u32>> {
14-
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
13+
LL | fn test_boxed() -> Box<impl std::future::Future<Output = u32>> {
14+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
1515
help: to force the async block to take ownership of `x` (and any other referenced variables), use the `move` keyword
1616
|
1717
LL | Box::new(async move { x } )
1818
| ^^^^^^^^^^
1919

20-
error: aborting due to previous error
20+
error[E0373]: async block may outlive the current function, but it borrows `x`, which is owned by the current function
21+
--> $DIR/async-borrowck-escaping-block-error.rs:11:11
22+
|
23+
LL | async { *x }
24+
| ^^^-^^
25+
| | |
26+
| | `x` is borrowed here
27+
| may outlive borrowed value `x`
28+
|
29+
note: async block is returned here
30+
--> $DIR/async-borrowck-escaping-block-error.rs:11:5
31+
|
32+
LL | async { *x }
33+
| ^^^^^^^^^^^^
34+
help: to force the async block to take ownership of `x` (and any other referenced variables), use the `move` keyword
35+
|
36+
LL | async move { *x }
37+
| ^^^^^^^^^^^
38+
39+
error: aborting due to 2 previous errors
2140

2241
For more information about this error, try `rustc --explain E0373`.

src/test/ui/async-await/async-borrowck-escaping-closure-error.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
// edition:2018
2-
#![feature(async_closure,async_await)]
2+
#![feature(async_closure)]
33
fn foo() -> Box<dyn std::future::Future<Output = u32>> {
44
let x = 0u32;
55
Box::new((async || x)())

src/test/ui/impl-trait/does-not-live-long-enough.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ struct List {
44
impl List {
55
fn started_with<'a>(&'a self, prefix: &'a str) -> impl Iterator<Item=&'a str> {
66
self.data.iter().filter(|s| s.starts_with(prefix)).map(|s| s.as_ref())
7-
//~^ ERROR does not live long enough
7+
//~^ ERROR E0373
88
}
99
}
1010

Original file line numberDiff line numberDiff line change
@@ -1,21 +1,21 @@
1-
error[E0597]: `prefix` does not live long enough
2-
--> $DIR/does-not-live-long-enough.rs:6:51
1+
error[E0373]: closure may outlive the current function, but it borrows `prefix`, which is owned by the current function
2+
--> $DIR/does-not-live-long-enough.rs:6:33
33
|
4-
LL | fn started_with<'a>(&'a self, prefix: &'a str) -> impl Iterator<Item=&'a str> {
5-
| -- lifetime `'a` defined here --------------------------- opaque type requires that `prefix` is borrowed for `'a`
64
LL | self.data.iter().filter(|s| s.starts_with(prefix)).map(|s| s.as_ref())
7-
| --- ^^^^^^ borrowed value does not live long enough
5+
| ^^^ ------ `prefix` is borrowed here
86
| |
9-
| value captured here
10-
LL |
11-
LL | }
12-
| - `prefix` dropped here while still borrowed
7+
| may outlive borrowed value `prefix`
8+
|
9+
note: closure is returned here
10+
--> $DIR/does-not-live-long-enough.rs:5:55
1311
|
14-
help: you can add a bound to the opaque type to make it last less than `'static` and match `'a`
12+
LL | fn started_with<'a>(&'a self, prefix: &'a str) -> impl Iterator<Item=&'a str> {
13+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
14+
help: to force the closure to take ownership of `prefix` (and any other referenced variables), use the `move` keyword
1515
|
16-
LL | fn started_with<'a>(&'a self, prefix: &'a str) -> impl Iterator<Item=&'a str> + 'a {
17-
| ^^^^
16+
LL | self.data.iter().filter(move |s| s.starts_with(prefix)).map(|s| s.as_ref())
17+
| ^^^^^^^^
1818

1919
error: aborting due to previous error
2020

21-
For more information about this error, try `rustc --explain E0597`.
21+
For more information about this error, try `rustc --explain E0373`.

0 commit comments

Comments
 (0)