From 5b475a46181cc4e8bfe2ac64f3724a5c485d6c5c Mon Sep 17 00:00:00 2001 From: Andy Weiss Date: Wed, 9 Sep 2020 15:16:34 -0700 Subject: [PATCH] Suggest async {} for async || {} Fixes #76011 This adds support for adding help diagnostics to the feature gating checks and then uses it for the async_closure gate to add the extra bit of help information as described in the issue. --- compiler/rustc_ast_passes/src/feature_gate.rs | 27 ++++++++++++++++++- compiler/rustc_parse/src/parser/expr.rs | 9 ++++--- .../async-await/feature-async-closure.stderr | 1 + src/test/ui/parser/block-no-opening-brace.rs | 2 +- .../ui/parser/block-no-opening-brace.stderr | 12 +-------- 5 files changed, 34 insertions(+), 17 deletions(-) diff --git a/compiler/rustc_ast_passes/src/feature_gate.rs b/compiler/rustc_ast_passes/src/feature_gate.rs index 97e6b363eff60..f52bc206ee4b1 100644 --- a/compiler/rustc_ast_passes/src/feature_gate.rs +++ b/compiler/rustc_ast_passes/src/feature_gate.rs @@ -14,6 +14,17 @@ use rustc_span::Span; use tracing::debug; macro_rules! gate_feature_fn { + ($visitor: expr, $has_feature: expr, $span: expr, $name: expr, $explain: expr, $help: expr) => {{ + let (visitor, has_feature, span, name, explain, help) = + (&*$visitor, $has_feature, $span, $name, $explain, $help); + let has_feature: bool = has_feature(visitor.features); + debug!("gate_feature(feature = {:?}, span = {:?}); has? {}", name, span, has_feature); + if !has_feature && !span.allows_unstable($name) { + feature_err_issue(&visitor.sess.parse_sess, name, span, GateIssue::Language, explain) + .help(help) + .emit(); + } + }}; ($visitor: expr, $has_feature: expr, $span: expr, $name: expr, $explain: expr) => {{ let (visitor, has_feature, span, name, explain) = (&*$visitor, $has_feature, $span, $name, $explain); @@ -27,6 +38,9 @@ macro_rules! gate_feature_fn { } macro_rules! gate_feature_post { + ($visitor: expr, $feature: ident, $span: expr, $explain: expr, $help: expr) => { + gate_feature_fn!($visitor, |x: &Features| x.$feature, $span, sym::$feature, $explain, $help) + }; ($visitor: expr, $feature: ident, $span: expr, $explain: expr) => { gate_feature_fn!($visitor, |x: &Features| x.$feature, $span, sym::$feature, $explain) }; @@ -613,6 +627,13 @@ pub fn check_crate(krate: &ast::Crate, sess: &Session) { let spans = sess.parse_sess.gated_spans.spans.borrow(); macro_rules! gate_all { + ($gate:ident, $msg:literal, $help:literal) => { + if let Some(spans) = spans.get(&sym::$gate) { + for span in spans { + gate_feature_post!(&visitor, $gate, *span, $msg, $help); + } + } + }; ($gate:ident, $msg:literal) => { if let Some(spans) = spans.get(&sym::$gate) { for span in spans { @@ -623,7 +644,11 @@ pub fn check_crate(krate: &ast::Crate, sess: &Session) { } gate_all!(if_let_guard, "`if let` guard is not implemented"); gate_all!(let_chains, "`let` expressions in this position are experimental"); - gate_all!(async_closure, "async closures are unstable"); + gate_all!( + async_closure, + "async closures are unstable", + "to use an async block, remove the `||`: `async {`" + ); gate_all!(generators, "yield syntax is experimental"); gate_all!(or_patterns, "or-patterns syntax is experimental"); gate_all!(raw_ref_op, "raw address of syntax is experimental"); diff --git a/compiler/rustc_parse/src/parser/expr.rs b/compiler/rustc_parse/src/parser/expr.rs index 69d13b5cf53a2..368c0d4c9bcf1 100644 --- a/compiler/rustc_parse/src/parser/expr.rs +++ b/compiler/rustc_parse/src/parser/expr.rs @@ -1554,10 +1554,6 @@ impl<'a> Parser<'a> { } else { Async::No }; - if let Async::Yes { span, .. } = asyncness { - // Feature-gate `async ||` closures. - self.sess.gated_spans.gate(sym::async_closure, span); - } let capture_clause = self.parse_capture_clause(); let decl = self.parse_fn_block_decl()?; @@ -1574,6 +1570,11 @@ impl<'a> Parser<'a> { } }; + if let Async::Yes { span, .. } = asyncness { + // Feature-gate `async ||` closures. + self.sess.gated_spans.gate(sym::async_closure, span); + } + Ok(self.mk_expr( lo.to(body.span), ExprKind::Closure(capture_clause, asyncness, movability, decl, body, lo.to(decl_hi)), diff --git a/src/test/ui/async-await/feature-async-closure.stderr b/src/test/ui/async-await/feature-async-closure.stderr index ba851ba7d2984..485a838b67ff2 100644 --- a/src/test/ui/async-await/feature-async-closure.stderr +++ b/src/test/ui/async-await/feature-async-closure.stderr @@ -6,6 +6,7 @@ LL | let _ = async || {}; | = note: see issue #62290 for more information = help: add `#![feature(async_closure)]` to the crate attributes to enable + = help: to use an async block, remove the `||`: `async {` error: aborting due to previous error diff --git a/src/test/ui/parser/block-no-opening-brace.rs b/src/test/ui/parser/block-no-opening-brace.rs index e4bb39f6836b4..8a6599488b1e7 100644 --- a/src/test/ui/parser/block-no-opening-brace.rs +++ b/src/test/ui/parser/block-no-opening-brace.rs @@ -26,6 +26,6 @@ fn f4() { } fn f5() { - async //~ ERROR async closures are unstable + async let x = 0; //~ ERROR expected one of `move`, `|`, or `||`, found keyword `let` } diff --git a/src/test/ui/parser/block-no-opening-brace.stderr b/src/test/ui/parser/block-no-opening-brace.stderr index a88e4ac44cfda..e32c8bdc73acc 100644 --- a/src/test/ui/parser/block-no-opening-brace.stderr +++ b/src/test/ui/parser/block-no-opening-brace.stderr @@ -39,15 +39,5 @@ LL | async LL | let x = 0; | ^^^ unexpected token -error[E0658]: async closures are unstable - --> $DIR/block-no-opening-brace.rs:29:5 - | -LL | async - | ^^^^^ - | - = note: see issue #62290 for more information - = help: add `#![feature(async_closure)]` to the crate attributes to enable - -error: aborting due to 6 previous errors +error: aborting due to 5 previous errors -For more information about this error, try `rustc --explain E0658`.