Add separate 'async_closure' feature gate.

This commit is contained in:
Mazdak Farrokhzad 2019-07-02 04:10:19 +02:00
parent 088b987307
commit bb7fbb99a2
5 changed files with 53 additions and 38 deletions

View File

@ -31,6 +31,7 @@ use crate::tokenstream::TokenTree;
use errors::{Applicability, DiagnosticBuilder, Handler}; use errors::{Applicability, DiagnosticBuilder, Handler};
use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::fx::FxHashMap;
use rustc_data_structures::sync::Lock;
use rustc_target::spec::abi::Abi; use rustc_target::spec::abi::Abi;
use syntax_pos::{Span, DUMMY_SP, MultiSpan}; use syntax_pos::{Span, DUMMY_SP, MultiSpan};
use log::debug; use log::debug;
@ -573,6 +574,9 @@ declare_features! (
// Allows `impl Trait` with multiple unrelated lifetimes. // Allows `impl Trait` with multiple unrelated lifetimes.
(active, member_constraints, "1.37.0", Some(61977), None), (active, member_constraints, "1.37.0", Some(61977), None),
// Allows `async || body` closures.
(active, async_closure, "1.37.0", Some(62290), None),
// ------------------------------------------------------------------------- // -------------------------------------------------------------------------
// feature-group-end: actual feature gates // feature-group-end: actual feature gates
// ------------------------------------------------------------------------- // -------------------------------------------------------------------------
@ -2191,9 +2195,6 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> {
"labels on blocks are unstable"); "labels on blocks are unstable");
} }
} }
ast::ExprKind::Closure(_, ast::IsAsync::Async { .. }, ..) => {
gate_feature_post!(&self, async_await, e.span, "async closures are unstable");
}
ast::ExprKind::Async(..) => { ast::ExprKind::Async(..) => {
gate_feature_post!(&self, async_await, e.span, "async blocks are unstable"); gate_feature_post!(&self, async_await, e.span, "async blocks are unstable");
} }
@ -2527,6 +2528,10 @@ pub fn get_features(span_handler: &Handler, krate_attrs: &[ast::Attribute],
features features
} }
fn for_each_in_lock<T>(vec: &Lock<Vec<T>>, f: impl Fn(&T)) {
vec.borrow().iter().for_each(f);
}
pub fn check_crate(krate: &ast::Crate, pub fn check_crate(krate: &ast::Crate,
sess: &ParseSess, sess: &ParseSess,
features: &Features, features: &Features,
@ -2539,28 +2544,27 @@ pub fn check_crate(krate: &ast::Crate,
plugin_attributes, plugin_attributes,
}; };
sess for_each_in_lock(&sess.param_attr_spans, |span| gate_feature!(
.param_attr_spans
.borrow()
.iter()
.for_each(|span| gate_feature!(
&ctx, &ctx,
param_attrs, param_attrs,
*span, *span,
"attributes on function parameters are unstable" "attributes on function parameters are unstable"
)); ));
sess for_each_in_lock(&sess.let_chains_spans, |span| gate_feature!(
.let_chains_spans
.borrow()
.iter()
.for_each(|span| gate_feature!(
&ctx, &ctx,
let_chains, let_chains,
*span, *span,
"`let` expressions in this position are experimental" "`let` expressions in this position are experimental"
)); ));
for_each_in_lock(&sess.async_closure_spans, |span| gate_feature!(
&ctx,
async_closure,
*span,
"async closures are unstable"
));
let visitor = &mut PostExpansionVisitor { let visitor = &mut PostExpansionVisitor {
context: &ctx, context: &ctx,
builtin_attributes: &*BUILTIN_ATTRIBUTE_MAP, builtin_attributes: &*BUILTIN_ATTRIBUTE_MAP,

View File

@ -1474,6 +1474,7 @@ mod tests {
ambiguous_block_expr_parse: Lock::new(FxHashMap::default()), ambiguous_block_expr_parse: Lock::new(FxHashMap::default()),
param_attr_spans: Lock::new(Vec::new()), param_attr_spans: Lock::new(Vec::new()),
let_chains_spans: Lock::new(Vec::new()), let_chains_spans: Lock::new(Vec::new()),
async_closure_spans: Lock::new(Vec::new()),
} }
} }

View File

@ -57,6 +57,8 @@ pub struct ParseSess {
pub param_attr_spans: Lock<Vec<Span>>, pub param_attr_spans: Lock<Vec<Span>>,
// Places where `let` exprs were used and should be feature gated according to `let_chains`. // Places where `let` exprs were used and should be feature gated according to `let_chains`.
pub let_chains_spans: Lock<Vec<Span>>, pub let_chains_spans: Lock<Vec<Span>>,
// Places where `async || ..` exprs were used and should be feature gated.
pub async_closure_spans: Lock<Vec<Span>>,
} }
impl ParseSess { impl ParseSess {
@ -84,6 +86,7 @@ impl ParseSess {
ambiguous_block_expr_parse: Lock::new(FxHashMap::default()), ambiguous_block_expr_parse: Lock::new(FxHashMap::default()),
param_attr_spans: Lock::new(Vec::new()), param_attr_spans: Lock::new(Vec::new()),
let_chains_spans: Lock::new(Vec::new()), let_chains_spans: Lock::new(Vec::new()),
async_closure_spans: Lock::new(Vec::new()),
} }
} }

View File

@ -3221,21 +3221,24 @@ impl<'a> Parser<'a> {
-> PResult<'a, P<Expr>> -> PResult<'a, P<Expr>>
{ {
let lo = self.token.span; let lo = self.token.span;
let movability = if self.eat_keyword(kw::Static) { let movability = if self.eat_keyword(kw::Static) {
Movability::Static Movability::Static
} else { } else {
Movability::Movable Movability::Movable
}; };
let asyncness = if self.token.span.rust_2018() { let asyncness = if self.token.span.rust_2018() {
self.parse_asyncness() self.parse_asyncness()
} else { } else {
IsAsync::NotAsync IsAsync::NotAsync
}; };
let capture_clause = if self.eat_keyword(kw::Move) { if asyncness.is_async() {
CaptureBy::Value // Feature gate `async ||` closures.
} else { self.sess.async_closure_spans.borrow_mut().push(self.prev_span);
CaptureBy::Ref }
};
let capture_clause = self.parse_capture_clause();
let decl = self.parse_fn_block_decl()?; let decl = self.parse_fn_block_decl()?;
let decl_hi = self.prev_span; let decl_hi = self.prev_span;
let body = match decl.output { let body = match decl.output {
@ -3257,7 +3260,7 @@ impl<'a> Parser<'a> {
attrs)) attrs))
} }
// `else` token already eaten /// `else` token already eaten
fn parse_else_expr(&mut self) -> PResult<'a, P<Expr>> { fn parse_else_expr(&mut self) -> PResult<'a, P<Expr>> {
if self.eat_keyword(kw::If) { if self.eat_keyword(kw::If) {
return self.parse_if_expr(ThinVec::new()); return self.parse_if_expr(ThinVec::new());
@ -3306,7 +3309,7 @@ impl<'a> Parser<'a> {
Ok(self.mk_expr(span, ExprKind::While(cond, body, opt_label), attrs)) Ok(self.mk_expr(span, ExprKind::While(cond, body, opt_label), attrs))
} }
// parse `loop {...}`, `loop` token already eaten /// Parse `loop {...}`, `loop` token already eaten.
fn parse_loop_expr(&mut self, opt_label: Option<Label>, fn parse_loop_expr(&mut self, opt_label: Option<Label>,
span_lo: Span, span_lo: Span,
mut attrs: ThinVec<Attribute>) -> PResult<'a, P<Expr>> { mut attrs: ThinVec<Attribute>) -> PResult<'a, P<Expr>> {
@ -3316,17 +3319,20 @@ impl<'a> Parser<'a> {
Ok(self.mk_expr(span, ExprKind::Loop(body, opt_label), attrs)) Ok(self.mk_expr(span, ExprKind::Loop(body, opt_label), attrs))
} }
/// Parses an `async move {...}` expression. /// Parse an optional `move` prefix to a closure lke construct.
pub fn parse_async_block(&mut self, mut attrs: ThinVec<Attribute>) fn parse_capture_clause(&mut self) -> CaptureBy {
-> PResult<'a, P<Expr>> if self.eat_keyword(kw::Move) {
{
let span_lo = self.token.span;
self.expect_keyword(kw::Async)?;
let capture_clause = if self.eat_keyword(kw::Move) {
CaptureBy::Value CaptureBy::Value
} else { } else {
CaptureBy::Ref CaptureBy::Ref
}; }
}
/// Parses an `async move? {...}` expression.
pub fn parse_async_block(&mut self, mut attrs: ThinVec<Attribute>) -> PResult<'a, P<Expr>> {
let span_lo = self.token.span;
self.expect_keyword(kw::Async)?;
let capture_clause = self.parse_capture_clause();
let (iattrs, body) = self.parse_inner_attrs_and_block()?; let (iattrs, body) = self.parse_inner_attrs_and_block()?;
attrs.extend(iattrs); attrs.extend(iattrs);
Ok(self.mk_expr( Ok(self.mk_expr(

View File

@ -146,6 +146,7 @@ symbols! {
associated_type_defaults, associated_type_defaults,
associated_types, associated_types,
async_await, async_await,
async_closure,
attr, attr,
attributes, attributes,
attr_literals, attr_literals,