Skip to content

Commit c0935bf

Browse files
committed
Use closure parse code
1 parent 9fd5694 commit c0935bf

File tree

20 files changed

+133
-64
lines changed

20 files changed

+133
-64
lines changed

compiler/rustc_ast/src/ast.rs

+5
Original file line numberDiff line numberDiff line change
@@ -1702,6 +1702,11 @@ pub enum CaptureBy {
17021702
},
17031703
/// `move` keyword was not specified.
17041704
Ref,
1705+
/// `use |x| y + x`.
1706+
Use {
1707+
/// The span of the `use` keyword.
1708+
use_kw: Span,
1709+
},
17051710
}
17061711

17071712
/// Closure lifetime binder, `for<'a, 'b>` in `for<'a, 'b> |_: &'a (), _: &'b ()|`.

compiler/rustc_ast/src/mut_visit.rs

+3
Original file line numberDiff line numberDiff line change
@@ -1867,6 +1867,9 @@ fn walk_capture_by<T: MutVisitor>(vis: &mut T, capture_by: &mut CaptureBy) {
18671867
CaptureBy::Value { move_kw } => {
18681868
vis.visit_span(move_kw);
18691869
}
1870+
CaptureBy::Use { use_kw } => {
1871+
vis.visit_span(use_kw);
1872+
}
18701873
}
18711874
}
18721875

compiler/rustc_ast_pretty/src/pprust/state/expr.rs

+1
Original file line numberDiff line numberDiff line change
@@ -886,6 +886,7 @@ impl<'a> State<'a> {
886886
fn print_capture_clause(&mut self, capture_clause: ast::CaptureBy) {
887887
match capture_clause {
888888
ast::CaptureBy::Value { .. } => self.word_space("move"),
889+
ast::CaptureBy::Use { .. } => self.word_space("use"),
889890
ast::CaptureBy::Ref => {}
890891
}
891892
}

compiler/rustc_borrowck/src/borrowck_errors.rs

+1
Original file line numberDiff line numberDiff line change
@@ -403,6 +403,7 @@ impl<'infcx, 'tcx> crate::MirBorrowckCtxt<'_, 'infcx, 'tcx> {
403403
.expect_closure();
404404
let span = match capture_clause {
405405
rustc_hir::CaptureBy::Value { move_kw } => move_kw.shrink_to_lo(),
406+
rustc_hir::CaptureBy::Use { use_kw } => use_kw.shrink_to_lo(),
406407
rustc_hir::CaptureBy::Ref => fn_decl_span.shrink_to_lo(),
407408
};
408409
diag.span_suggestion_verbose(

compiler/rustc_hir_pretty/src/lib.rs

+1
Original file line numberDiff line numberDiff line change
@@ -2159,6 +2159,7 @@ impl<'a> State<'a> {
21592159
fn print_capture_clause(&mut self, capture_clause: hir::CaptureBy) {
21602160
match capture_clause {
21612161
hir::CaptureBy::Value { .. } => self.word_space("move"),
2162+
hir::CaptureBy::Use { .. } => self.word_space("use"),
21622163
hir::CaptureBy::Ref => {}
21632164
}
21642165
}

compiler/rustc_hir_typeck/src/upvar.rs

+9-5
Original file line numberDiff line numberDiff line change
@@ -666,7 +666,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
666666
origin = updated.1;
667667

668668
let (place, capture_kind) = match capture_clause {
669-
hir::CaptureBy::Value { .. } => adjust_for_move_closure(place, capture_kind),
669+
hir::CaptureBy::Value { .. } | hir::CaptureBy::Use { .. } => {
670+
adjust_for_move_closure(place, capture_kind)
671+
}
670672
hir::CaptureBy::Ref => adjust_for_non_move_closure(place, capture_kind),
671673
};
672674

@@ -1161,7 +1163,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
11611163

11621164
let ty = match closure_clause {
11631165
hir::CaptureBy::Value { .. } => ty, // For move closure the capture kind should be by value
1164-
hir::CaptureBy::Ref => {
1166+
hir::CaptureBy::Ref | hir::CaptureBy::Use { .. } => {
11651167
// For non move closure the capture kind is the max capture kind of all captures
11661168
// according to the ordering ImmBorrow < UniqueImmBorrow < MutBorrow < ByValue
11671169
let mut max_capture_info = root_var_min_capture_list.first().unwrap().info;
@@ -1288,7 +1290,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
12881290
.insert(UpvarMigrationInfo::CapturingNothing { use_span: upvar.span });
12891291
return Some(diagnostics_info);
12901292
}
1291-
hir::CaptureBy::Ref => {}
1293+
hir::CaptureBy::Ref | hir::CaptureBy::Use { .. } => {}
12921294
}
12931295

12941296
return None;
@@ -1685,10 +1687,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
16851687
//
16861688
// If the data will be moved out of this place, then the place will be truncated
16871689
// at the first Deref in `adjust_for_move_closure` and then moved into the closure.
1688-
hir::CaptureBy::Value { .. } if !place.deref_tys().any(Ty::is_ref) => {
1690+
hir::CaptureBy::Value { .. } | hir::CaptureBy::Use { .. }
1691+
if !place.deref_tys().any(Ty::is_ref) =>
1692+
{
16891693
ty::UpvarCapture::ByValue
16901694
}
1691-
hir::CaptureBy::Value { .. } | hir::CaptureBy::Ref => {
1695+
hir::CaptureBy::Value { .. } | hir::CaptureBy::Use { .. } | hir::CaptureBy::Ref => {
16921696
ty::UpvarCapture::ByRef(BorrowKind::Immutable)
16931697
}
16941698
}

compiler/rustc_parse/messages.ftl

+3
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,9 @@ parse_async_move_block_in_2015 = `async move` blocks are only allowed in Rust 20
2626
parse_async_move_order_incorrect = the order of `move` and `async` is incorrect
2727
.suggestion = try switching the order
2828
29+
parse_async_use_order_incorrect = the order of `use` and `async` is incorrect
30+
.suggestion = try switching the order
31+
2932
parse_at_dot_dot_in_struct_pattern = `@ ..` is not supported in struct patterns
3033
.suggestion = bind to each field separately or, if you don't need them, just remove `{$ident} @`
3134

compiler/rustc_parse/src/errors.rs

+8
Original file line numberDiff line numberDiff line change
@@ -1523,6 +1523,14 @@ pub(crate) struct AsyncMoveOrderIncorrect {
15231523
pub span: Span,
15241524
}
15251525

1526+
#[derive(Diagnostic)]
1527+
#[diag(parse_async_use_order_incorrect)]
1528+
pub(crate) struct AsyncUseOrderIncorrect {
1529+
#[primary_span]
1530+
#[suggestion(style = "verbose", code = "async use", applicability = "maybe-incorrect")]
1531+
pub span: Span,
1532+
}
1533+
15261534
#[derive(Diagnostic)]
15271535
#[diag(parse_double_colon_in_bound)]
15281536
pub(crate) struct DoubleColonInBound {

compiler/rustc_parse/src/parser/expr.rs

+13-2
Original file line numberDiff line numberDiff line change
@@ -1439,6 +1439,7 @@ impl<'a> Parser<'a> {
14391439
} else if this.check_path() {
14401440
this.parse_expr_path_start()
14411441
} else if this.check_keyword(exp!(Move))
1442+
|| this.check_keyword(exp!(Use))
14421443
|| this.check_keyword(exp!(Static))
14431444
|| this.check_const_closure()
14441445
{
@@ -2432,7 +2433,7 @@ impl<'a> Parser<'a> {
24322433
Ok(closure)
24332434
}
24342435

2435-
/// Parses an optional `move` prefix to a closure-like construct.
2436+
/// Parses an optional `move` or `use` prefix to a closure-like construct.
24362437
fn parse_capture_clause(&mut self) -> PResult<'a, CaptureBy> {
24372438
if self.eat_keyword(exp!(Move)) {
24382439
let move_kw_span = self.prev_token.span;
@@ -2445,6 +2446,16 @@ impl<'a> Parser<'a> {
24452446
} else {
24462447
Ok(CaptureBy::Value { move_kw: move_kw_span })
24472448
}
2449+
} else if self.eat_keyword(exp!(Use)) {
2450+
let use_kw_span = self.prev_token.span;
2451+
self.psess.gated_spans.gate(sym::ergonomic_clones, use_kw_span);
2452+
// Check for `use async` and recover
2453+
if self.check_keyword(exp!(Async)) {
2454+
let use_async_span = self.token.span.with_lo(self.prev_token.span.data().lo);
2455+
Err(self.dcx().create_err(errors::AsyncUseOrderIncorrect { span: use_async_span }))
2456+
} else {
2457+
Ok(CaptureBy::Use { use_kw: use_kw_span })
2458+
}
24482459
} else {
24492460
Ok(CaptureBy::Ref)
24502461
}
@@ -3462,7 +3473,7 @@ impl<'a> Parser<'a> {
34623473
self.is_keyword_ahead(lookahead, &[kw])
34633474
&& ((
34643475
// `async move {`
3465-
self.is_keyword_ahead(lookahead + 1, &[kw::Move])
3476+
self.is_keyword_ahead(lookahead + 1, &[kw::Move, kw::Use])
34663477
&& self.look_ahead(lookahead + 2, |t| {
34673478
*t == token::OpenDelim(Delimiter::Brace) || t.is_whole_block()
34683479
})

compiler/rustc_parse/src/parser/item.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -1287,7 +1287,7 @@ impl<'a> Parser<'a> {
12871287
if self.check_keyword(exp!(Static)) {
12881288
// Check if this could be a closure.
12891289
!self.look_ahead(1, |token| {
1290-
if token.is_keyword(kw::Move) {
1290+
if token.is_keyword(kw::Move) || token.is_keyword(kw::Use) {
12911291
return true;
12921292
}
12931293
matches!(token.kind, token::BinOp(token::Or) | token::OrOr)

tests/ui/editions/edition-keywords-2018-2015-parsing.stderr

+4-4
Original file line numberDiff line numberDiff line change
@@ -44,22 +44,22 @@ note: while trying to match `r#async`
4444
LL | (r#async) => (1)
4545
| ^^^^^^^
4646

47-
error: macro expansion ends with an incomplete expression: expected one of `move`, `|`, or `||`
47+
error: macro expansion ends with an incomplete expression: expected one of `move`, `use`, `|`, or `||`
4848
--> $DIR/auxiliary/edition-kw-macro-2015.rs:27:23
4949
|
5050
LL | ($i: ident) => ($i)
51-
| ^ expected one of `move`, `|`, or `||`
51+
| ^ expected one of `move`, `use`, `|`, or `||`
5252
|
5353
::: $DIR/edition-keywords-2018-2015-parsing.rs:22:8
5454
|
5555
LL | if passes_ident!(async) == 1 {} // FIXME: Edition hygiene bug, async here is 2018 and reserved
5656
| -------------------- in this macro invocation
5757

58-
error: macro expansion ends with an incomplete expression: expected one of `move`, `|`, or `||`
58+
error: macro expansion ends with an incomplete expression: expected one of `move`, `use`, `|`, or `||`
5959
--> $DIR/edition-keywords-2018-2015-parsing.rs:24:24
6060
|
6161
LL | if passes_tt!(async) == 1 {}
62-
| ^ expected one of `move`, `|`, or `||`
62+
| ^ expected one of `move`, `use`, `|`, or `||`
6363

6464
error[E0308]: mismatched types
6565
--> $DIR/edition-keywords-2018-2015-parsing.rs:29:33

tests/ui/editions/edition-keywords-2018-2018-parsing.stderr

+8-8
Original file line numberDiff line numberDiff line change
@@ -44,34 +44,34 @@ note: while trying to match `r#async`
4444
LL | (r#async) => (1)
4545
| ^^^^^^^
4646

47-
error: macro expansion ends with an incomplete expression: expected one of `move`, `|`, or `||`
47+
error: macro expansion ends with an incomplete expression: expected one of `move`, `use`, `|`, or `||`
4848
--> $DIR/auxiliary/edition-kw-macro-2018.rs:27:23
4949
|
5050
LL | ($i: ident) => ($i)
51-
| ^ expected one of `move`, `|`, or `||`
51+
| ^ expected one of `move`, `use`, `|`, or `||`
5252
|
5353
::: $DIR/edition-keywords-2018-2018-parsing.rs:29:8
5454
|
5555
LL | if passes_ident!(async) == 1 {} // FIXME: Edition hygiene bug, async here is 2018 and reserved
5656
| -------------------- in this macro invocation
5757

58-
error: macro expansion ends with an incomplete expression: expected one of `move`, `|`, or `||`
58+
error: macro expansion ends with an incomplete expression: expected one of `move`, `use`, `|`, or `||`
5959
--> $DIR/edition-keywords-2018-2018-parsing.rs:31:24
6060
|
6161
LL | if passes_tt!(async) == 1 {}
62-
| ^ expected one of `move`, `|`, or `||`
62+
| ^ expected one of `move`, `use`, `|`, or `||`
6363

64-
error: macro expansion ends with an incomplete expression: expected one of `move`, `|`, or `||`
64+
error: macro expansion ends with an incomplete expression: expected one of `move`, `use`, `|`, or `||`
6565
--> $DIR/edition-keywords-2018-2018-parsing.rs:14:23
6666
|
6767
LL | ($i: ident) => ($i)
68-
| ^ expected one of `move`, `|`, or `||`
68+
| ^ expected one of `move`, `use`, `|`, or `||`
6969

70-
error: macro expansion ends with an incomplete expression: expected one of `move`, `|`, or `||`
70+
error: macro expansion ends with an incomplete expression: expected one of `move`, `use`, `|`, or `||`
7171
--> $DIR/edition-keywords-2018-2018-parsing.rs:35:30
7272
|
7373
LL | if local_passes_tt!(async) == 1 {}
74-
| ^ expected one of `move`, `|`, or `||`
74+
| ^ expected one of `move`, `use`, `|`, or `||`
7575

7676
error[E0308]: mismatched types
7777
--> $DIR/edition-keywords-2018-2018-parsing.rs:40:33

tests/ui/ergonomic-clones/closure.rs

+23
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
//@ check-pass
2+
//@ edition:2018
3+
4+
#![feature(ergonomic_clones)]
5+
6+
fn ergonomic_clone_closure() -> i32 {
7+
let cl = use || {
8+
1
9+
};
10+
cl()
11+
}
12+
13+
fn ergonomic_clone_async_closures() -> String {
14+
let s = String::from("hi");
15+
16+
async use {
17+
22
18+
};
19+
20+
s
21+
}
22+
23+
fn main() {}

tests/ui/feature-gates/feature-gate-ergonomic-clones.rs

+3-2
Original file line numberDiff line numberDiff line change
@@ -7,12 +7,13 @@ fn ergonomic_closure_clone() {
77
let s1 = String::from("hi!");
88

99
let s2 = use || {
10-
//~^ ERROR incorrect use of `use`
10+
//~^ ERROR `.use` calls are experimental [E0658]
1111
s1
1212
};
1313

1414
let s3 = use || {
15-
//~^ ERROR incorrect use of `use`
15+
//~^ ERROR `.use` calls are experimental [E0658]
16+
//~| ERROR use of moved value: `s1` [E0382]
1617
s1
1718
};
1819
}
Original file line numberDiff line numberDiff line change
@@ -1,49 +1,57 @@
1-
error: incorrect use of `use`
2-
--> $DIR/feature-gate-ergonomic-clones.rs:9:14
1+
error[E0658]: `.use` calls are experimental
2+
--> $DIR/feature-gate-ergonomic-clones.rs:2:7
33
|
4-
LL | let s2 = use || {
5-
| ______________^
6-
LL | |
7-
LL | | s1
8-
LL | | };
9-
| |_____^
4+
LL | x.use
5+
| ^^^
106
|
11-
help: `use` is a postfix operation
7+
= note: see issue #132290 <https://github.com/rust-lang/rust/issues/132290> for more information
8+
= help: add `#![feature(ergonomic_clones)]` to the crate attributes to enable
9+
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
10+
11+
error[E0658]: `.use` calls are experimental
12+
--> $DIR/feature-gate-ergonomic-clones.rs:9:14
1213
|
13-
LL ~ let s2 = || {
14-
LL |
15-
LL | s1
16-
LL ~ }.use;
14+
LL | let s2 = use || {
15+
| ^^^
1716
|
17+
= note: see issue #132290 <https://github.com/rust-lang/rust/issues/132290> for more information
18+
= help: add `#![feature(ergonomic_clones)]` to the crate attributes to enable
19+
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
1820

19-
error: incorrect use of `use`
21+
error[E0658]: `.use` calls are experimental
2022
--> $DIR/feature-gate-ergonomic-clones.rs:14:14
2123
|
22-
LL | let s3 = use || {
23-
| ______________^
24-
LL | |
25-
LL | | s1
26-
LL | | };
27-
| |_____^
24+
LL | let s3 = use || {
25+
| ^^^
2826
|
29-
help: `use` is a postfix operation
27+
= note: see issue #132290 <https://github.com/rust-lang/rust/issues/132290> for more information
28+
= help: add `#![feature(ergonomic_clones)]` to the crate attributes to enable
29+
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
30+
31+
error[E0382]: use of moved value: `s1`
32+
--> $DIR/feature-gate-ergonomic-clones.rs:14:14
3033
|
31-
LL ~ let s3 = || {
34+
LL | let s1 = String::from("hi!");
35+
| -- move occurs because `s1` has type `String`, which does not implement the `Copy` trait
36+
LL |
37+
LL | let s2 = use || {
38+
| ------ value moved into closure here
3239
LL |
3340
LL | s1
34-
LL ~ }.use;
35-
|
36-
37-
error[E0658]: `.use` calls are experimental
38-
--> $DIR/feature-gate-ergonomic-clones.rs:2:7
41+
| -- variable moved due to use in closure
42+
...
43+
LL | let s3 = use || {
44+
| ^^^^^^ value used here after move
45+
...
46+
LL | s1
47+
| -- use occurs due to use in closure
3948
|
40-
LL | x.use
41-
| ^^^
49+
help: consider cloning the value if the performance cost is acceptable
4250
|
43-
= note: see issue #132290 <https://github.com/rust-lang/rust/issues/132290> for more information
44-
= help: add `#![feature(ergonomic_clones)]` to the crate attributes to enable
45-
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
51+
LL | s1.clone()
52+
| ++++++++
4653

47-
error: aborting due to 3 previous errors
54+
error: aborting due to 4 previous errors
4855

49-
For more information about this error, try `rustc --explain E0658`.
56+
Some errors have detailed explanations: E0382, E0658.
57+
For more information about an error, try `rustc --explain E0382`.

tests/ui/parser/block-no-opening-brace.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ fn in_try() {
3030
// FIXME(#80931)
3131
fn in_async() {
3232
async
33-
let x = 0; //~ ERROR expected one of `move`, `|`, or `||`, found keyword `let`
33+
let x = 0; //~ ERROR expected one of `move`, `use`, `|`, or `||`, found keyword `let`
3434
}
3535

3636
// FIXME(#78168)

tests/ui/parser/block-no-opening-brace.stderr

+2-2
Original file line numberDiff line numberDiff line change
@@ -43,11 +43,11 @@ error: expected expression, found reserved keyword `try`
4343
LL | try
4444
| ^^^ expected expression
4545

46-
error: expected one of `move`, `|`, or `||`, found keyword `let`
46+
error: expected one of `move`, `use`, `|`, or `||`, found keyword `let`
4747
--> $DIR/block-no-opening-brace.rs:33:9
4848
|
4949
LL | async
50-
| - expected one of `move`, `|`, or `||`
50+
| - expected one of `move`, `use`, `|`, or `||`
5151
LL | let x = 0;
5252
| ^^^ unexpected token
5353

0 commit comments

Comments
 (0)