Skip to content

Commit 566909b

Browse files
authored
Rollup merge of rust-lang#62292 - Centril:split-async-closures, r=cramertj
Move `async || ...` closures into `#![feature(async_closure)]` The `async || expr` syntax is moved out from `#![feature(async_await)]` into its own gate `#![feature(async_closure)]`. New tracking issue: rust-lang#62290 Closes rust-lang#62214. cc rust-lang#62149 r? @varkor
2 parents f045805 + 43315bc commit 566909b

25 files changed

+260
-115
lines changed

src/libsyntax/feature_gate.rs

+28-24
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ use crate::tokenstream::TokenTree;
3131

3232
use errors::{Applicability, DiagnosticBuilder, Handler};
3333
use rustc_data_structures::fx::FxHashMap;
34+
use rustc_data_structures::sync::Lock;
3435
use rustc_target::spec::abi::Abi;
3536
use syntax_pos::{Span, DUMMY_SP, MultiSpan};
3637
use log::debug;
@@ -573,6 +574,9 @@ declare_features! (
573574
// Allows `impl Trait` with multiple unrelated lifetimes.
574575
(active, member_constraints, "1.37.0", Some(61977), None),
575576

577+
// Allows `async || body` closures.
578+
(active, async_closure, "1.37.0", Some(62290), None),
579+
576580
// -------------------------------------------------------------------------
577581
// feature-group-end: actual feature gates
578582
// -------------------------------------------------------------------------
@@ -2225,9 +2229,6 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> {
22252229
"labels on blocks are unstable");
22262230
}
22272231
}
2228-
ast::ExprKind::Closure(_, ast::IsAsync::Async { .. }, ..) => {
2229-
gate_feature_post!(&self, async_await, e.span, "async closures are unstable");
2230-
}
22312232
ast::ExprKind::Async(..) => {
22322233
gate_feature_post!(&self, async_await, e.span, "async blocks are unstable");
22332234
}
@@ -2561,6 +2562,10 @@ pub fn get_features(span_handler: &Handler, krate_attrs: &[ast::Attribute],
25612562
features
25622563
}
25632564

2565+
fn for_each_in_lock<T>(vec: &Lock<Vec<T>>, f: impl Fn(&T)) {
2566+
vec.borrow().iter().for_each(f);
2567+
}
2568+
25642569
pub fn check_crate(krate: &ast::Crate,
25652570
sess: &ParseSess,
25662571
features: &Features,
@@ -2573,27 +2578,26 @@ pub fn check_crate(krate: &ast::Crate,
25732578
plugin_attributes,
25742579
};
25752580

2576-
sess
2577-
.param_attr_spans
2578-
.borrow()
2579-
.iter()
2580-
.for_each(|span| gate_feature!(
2581-
&ctx,
2582-
param_attrs,
2583-
*span,
2584-
"attributes on function parameters are unstable"
2585-
));
2586-
2587-
sess
2588-
.let_chains_spans
2589-
.borrow()
2590-
.iter()
2591-
.for_each(|span| gate_feature!(
2592-
&ctx,
2593-
let_chains,
2594-
*span,
2595-
"`let` expressions in this position are experimental"
2596-
));
2581+
for_each_in_lock(&sess.param_attr_spans, |span| gate_feature!(
2582+
&ctx,
2583+
param_attrs,
2584+
*span,
2585+
"attributes on function parameters are unstable"
2586+
));
2587+
2588+
for_each_in_lock(&sess.let_chains_spans, |span| gate_feature!(
2589+
&ctx,
2590+
let_chains,
2591+
*span,
2592+
"`let` expressions in this position are experimental"
2593+
));
2594+
2595+
for_each_in_lock(&sess.async_closure_spans, |span| gate_feature!(
2596+
&ctx,
2597+
async_closure,
2598+
*span,
2599+
"async closures are unstable"
2600+
));
25972601

25982602
let visitor = &mut PostExpansionVisitor {
25992603
context: &ctx,

src/libsyntax/parse/lexer/mod.rs

+1
Original file line numberDiff line numberDiff line change
@@ -1452,6 +1452,7 @@ mod tests {
14521452
ambiguous_block_expr_parse: Lock::new(FxHashMap::default()),
14531453
param_attr_spans: Lock::new(Vec::new()),
14541454
let_chains_spans: Lock::new(Vec::new()),
1455+
async_closure_spans: Lock::new(Vec::new()),
14551456
}
14561457
}
14571458

src/libsyntax/parse/mod.rs

+3
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,8 @@ pub struct ParseSess {
5757
pub param_attr_spans: Lock<Vec<Span>>,
5858
// Places where `let` exprs were used and should be feature gated according to `let_chains`.
5959
pub let_chains_spans: Lock<Vec<Span>>,
60+
// Places where `async || ..` exprs were used and should be feature gated.
61+
pub async_closure_spans: Lock<Vec<Span>>,
6062
}
6163

6264
impl ParseSess {
@@ -84,6 +86,7 @@ impl ParseSess {
8486
ambiguous_block_expr_parse: Lock::new(FxHashMap::default()),
8587
param_attr_spans: Lock::new(Vec::new()),
8688
let_chains_spans: Lock::new(Vec::new()),
89+
async_closure_spans: Lock::new(Vec::new()),
8790
}
8891
}
8992

src/libsyntax/parse/parser.rs

+21-15
Original file line numberDiff line numberDiff line change
@@ -3221,21 +3221,24 @@ impl<'a> Parser<'a> {
32213221
-> PResult<'a, P<Expr>>
32223222
{
32233223
let lo = self.token.span;
3224+
32243225
let movability = if self.eat_keyword(kw::Static) {
32253226
Movability::Static
32263227
} else {
32273228
Movability::Movable
32283229
};
3230+
32293231
let asyncness = if self.token.span.rust_2018() {
32303232
self.parse_asyncness()
32313233
} else {
32323234
IsAsync::NotAsync
32333235
};
3234-
let capture_clause = if self.eat_keyword(kw::Move) {
3235-
CaptureBy::Value
3236-
} else {
3237-
CaptureBy::Ref
3238-
};
3236+
if asyncness.is_async() {
3237+
// Feature gate `async ||` closures.
3238+
self.sess.async_closure_spans.borrow_mut().push(self.prev_span);
3239+
}
3240+
3241+
let capture_clause = self.parse_capture_clause();
32393242
let decl = self.parse_fn_block_decl()?;
32403243
let decl_hi = self.prev_span;
32413244
let body = match decl.output {
@@ -3257,7 +3260,7 @@ impl<'a> Parser<'a> {
32573260
attrs))
32583261
}
32593262

3260-
// `else` token already eaten
3263+
/// `else` token already eaten
32613264
fn parse_else_expr(&mut self) -> PResult<'a, P<Expr>> {
32623265
if self.eat_keyword(kw::If) {
32633266
return self.parse_if_expr(ThinVec::new());
@@ -3306,7 +3309,7 @@ impl<'a> Parser<'a> {
33063309
Ok(self.mk_expr(span, ExprKind::While(cond, body, opt_label), attrs))
33073310
}
33083311

3309-
// parse `loop {...}`, `loop` token already eaten
3312+
/// Parse `loop {...}`, `loop` token already eaten.
33103313
fn parse_loop_expr(&mut self, opt_label: Option<Label>,
33113314
span_lo: Span,
33123315
mut attrs: ThinVec<Attribute>) -> PResult<'a, P<Expr>> {
@@ -3316,17 +3319,20 @@ impl<'a> Parser<'a> {
33163319
Ok(self.mk_expr(span, ExprKind::Loop(body, opt_label), attrs))
33173320
}
33183321

3319-
/// Parses an `async move {...}` expression.
3320-
pub fn parse_async_block(&mut self, mut attrs: ThinVec<Attribute>)
3321-
-> PResult<'a, P<Expr>>
3322-
{
3323-
let span_lo = self.token.span;
3324-
self.expect_keyword(kw::Async)?;
3325-
let capture_clause = if self.eat_keyword(kw::Move) {
3322+
/// Parse an optional `move` prefix to a closure lke construct.
3323+
fn parse_capture_clause(&mut self) -> CaptureBy {
3324+
if self.eat_keyword(kw::Move) {
33263325
CaptureBy::Value
33273326
} else {
33283327
CaptureBy::Ref
3329-
};
3328+
}
3329+
}
3330+
3331+
/// Parses an `async move? {...}` expression.
3332+
pub fn parse_async_block(&mut self, mut attrs: ThinVec<Attribute>) -> PResult<'a, P<Expr>> {
3333+
let span_lo = self.token.span;
3334+
self.expect_keyword(kw::Async)?;
3335+
let capture_clause = self.parse_capture_clause();
33303336
let (iattrs, body) = self.parse_inner_attrs_and_block()?;
33313337
attrs.extend(iattrs);
33323338
Ok(self.mk_expr(

src/libsyntax_pos/symbol.rs

+1
Original file line numberDiff line numberDiff line change
@@ -146,6 +146,7 @@ symbols! {
146146
associated_type_defaults,
147147
associated_types,
148148
async_await,
149+
async_closure,
149150
attr,
150151
attributes,
151152
attr_literals,

src/test/ui/async-await/async-await.rs

-8
Original file line numberDiff line numberDiff line change
@@ -70,13 +70,6 @@ fn async_nonmove_block(x: u8) -> impl Future<Output = u8> {
7070
}
7171
}
7272

73-
fn async_closure(x: u8) -> impl Future<Output = u8> {
74-
(async move |x: u8| -> u8 {
75-
wake_and_yield_once().await;
76-
x
77-
})(x)
78-
}
79-
8073
async fn async_fn(x: u8) -> u8 {
8174
wake_and_yield_once().await;
8275
x
@@ -180,7 +173,6 @@ fn main() {
180173
test! {
181174
async_block,
182175
async_nonmove_block,
183-
async_closure,
184176
async_fn,
185177
generic_async_fn,
186178
async_fn_with_internal_borrow,
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
// compile-pass
2+
// edition:2018
3+
4+
#![feature(async_await, async_closure)]
5+
6+
macro_rules! match_expr {
7+
($x:expr) => {}
8+
}
9+
10+
fn main() {
11+
match_expr!(async || {});
12+
}
+81
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
// run-pass
2+
3+
// edition:2018
4+
// aux-build:arc_wake.rs
5+
6+
#![feature(async_await, async_closure)]
7+
8+
extern crate arc_wake;
9+
10+
use std::pin::Pin;
11+
use std::future::Future;
12+
use std::sync::{
13+
Arc,
14+
atomic::{self, AtomicUsize},
15+
};
16+
use std::task::{Context, Poll};
17+
use arc_wake::ArcWake;
18+
19+
struct Counter {
20+
wakes: AtomicUsize,
21+
}
22+
23+
impl ArcWake for Counter {
24+
fn wake(self: Arc<Self>) {
25+
Self::wake_by_ref(&self)
26+
}
27+
fn wake_by_ref(arc_self: &Arc<Self>) {
28+
arc_self.wakes.fetch_add(1, atomic::Ordering::SeqCst);
29+
}
30+
}
31+
32+
struct WakeOnceThenComplete(bool);
33+
34+
fn wake_and_yield_once() -> WakeOnceThenComplete { WakeOnceThenComplete(false) }
35+
36+
impl Future for WakeOnceThenComplete {
37+
type Output = ();
38+
fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<()> {
39+
if self.0 {
40+
Poll::Ready(())
41+
} else {
42+
cx.waker().wake_by_ref();
43+
self.0 = true;
44+
Poll::Pending
45+
}
46+
}
47+
}
48+
49+
fn async_closure(x: u8) -> impl Future<Output = u8> {
50+
(async move |x: u8| -> u8 {
51+
wake_and_yield_once().await;
52+
x
53+
})(x)
54+
}
55+
56+
fn test_future_yields_once_then_returns<F, Fut>(f: F)
57+
where
58+
F: FnOnce(u8) -> Fut,
59+
Fut: Future<Output = u8>,
60+
{
61+
let mut fut = Box::pin(f(9));
62+
let counter = Arc::new(Counter { wakes: AtomicUsize::new(0) });
63+
let waker = ArcWake::into_waker(counter.clone());
64+
let mut cx = Context::from_waker(&waker);
65+
assert_eq!(0, counter.wakes.load(atomic::Ordering::SeqCst));
66+
assert_eq!(Poll::Pending, fut.as_mut().poll(&mut cx));
67+
assert_eq!(1, counter.wakes.load(atomic::Ordering::SeqCst));
68+
assert_eq!(Poll::Ready(9), fut.as_mut().poll(&mut cx));
69+
}
70+
71+
fn main() {
72+
macro_rules! test {
73+
($($fn_name:expr,)*) => { $(
74+
test_future_yields_once_then_returns($fn_name);
75+
)* }
76+
}
77+
78+
test! {
79+
async_closure,
80+
}
81+
}
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,12 @@
11
// build-pass (FIXME(62277): could be check-pass?)
22
// edition:2018
33

4-
#![feature(async_await, await_macro)]
4+
#![feature(async_await)]
55

66
macro_rules! match_expr {
77
($x:expr) => {}
88
}
99

1010
fn main() {
1111
match_expr!(async {});
12-
match_expr!(async || {});
1312
}

src/test/ui/async-await/await-macro.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
// edition:2018
44
// aux-build:arc_wake.rs
55

6-
#![feature(async_await, await_macro)]
6+
#![feature(async_await, async_closure, await_macro)]
77

88
extern crate arc_wake;
99

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
// edition:2018
2+
// gate-test-async_closure
3+
4+
fn f() {
5+
let _ = async || {}; //~ ERROR async closures are unstable
6+
}
7+
8+
fn main() {}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
error[E0658]: async closures are unstable
2+
--> $DIR/feature-async-closure.rs:5:13
3+
|
4+
LL | let _ = async || {};
5+
| ^^^^^
6+
|
7+
= note: for more information, see https://github.com/rust-lang/rust/issues/62290
8+
= help: add #![feature(async_closure)] to the crate attributes to enable
9+
10+
error: aborting due to previous error
11+
12+
For more information about this error, try `rustc --explain E0658`.

src/test/ui/async-await/issues/issue-62009.rs src/test/ui/async-await/issues/issue-62009-1.rs

-2
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,6 @@ fn main() {
1111
//~^ ERROR `await` is only allowed inside `async` functions and blocks
1212
let task1 = print_dur().await;
1313
}.await;
14-
(async || 2333)().await;
15-
//~^ ERROR `await` is only allowed inside `async` functions and blocks
1614
(|_| 2333).await;
1715
//~^ ERROR `await` is only allowed inside `async` functions and blocks
1816
//~^^ ERROR

0 commit comments

Comments
 (0)