]> git.lizzy.rs Git - rust.git/commitdiff
Implement built-in await syntax
authorTaylor Cramer <cramertj@google.com>
Thu, 18 Apr 2019 19:55:23 +0000 (12:55 -0700)
committerTaylor Cramer <cramertj@google.com>
Tue, 7 May 2019 21:45:53 +0000 (14:45 -0700)
Adds support for .await under the existing async_await feature gate.
Moves macro-like await! syntax to the await_macro feature gate.
Removes support for `await` as a non-keyword under the `async_await`
feature.

37 files changed:
src/librustc/error_codes.rs
src/librustc/hir/lowering.rs
src/librustc/hir/mod.rs
src/librustc/ich/impls_syntax.rs
src/librustc_lint/builtin.rs
src/librustc_mir/hair/pattern/check_match.rs
src/libsyntax/ast.rs
src/libsyntax/feature_gate.rs
src/libsyntax/mut_visit.rs
src/libsyntax/parse/parser.rs
src/libsyntax/parse/token.rs
src/libsyntax/print/pprust.rs
src/libsyntax/util/parser.rs
src/libsyntax/visit.rs
src/libsyntax_pos/hygiene.rs
src/libsyntax_pos/symbol.rs
src/test/run-pass/async-await.rs
src/test/run-pass/await-macro.rs [new file with mode: 0644]
src/test/run-pass/issue-55809.rs
src/test/ui/await-keyword/2015-edition-error-in-non-macro-position.rs [new file with mode: 0644]
src/test/ui/await-keyword/2015-edition-error-in-non-macro-position.stderr [new file with mode: 0644]
src/test/ui/await-keyword/2015-edition-no-warnings-with-feature-gate.rs [deleted file]
src/test/ui/await-keyword/2018-edition-error-in-non-macro-position.rs [new file with mode: 0644]
src/test/ui/await-keyword/2018-edition-error-in-non-macro-position.stderr [new file with mode: 0644]
src/test/ui/await-keyword/2018-edition-error.rs
src/test/ui/await-keyword/2018-edition-error.stderr
src/test/ui/await-keyword/2018-edition-no-error-with-feature-gate.rs [deleted file]
src/test/ui/await-keyword/post_expansion_error.rs
src/test/ui/await-keyword/post_expansion_error.stderr
src/test/ui/feature-gate/await-macro.rs [new file with mode: 0644]
src/test/ui/feature-gate/await-macro.stderr [new file with mode: 0644]
src/test/ui/generator/unresolved_type_param.rs
src/test/ui/generator/unresolved_type_param.stderr
src/test/ui/issues/issue-51719.rs [new file with mode: 0644]
src/test/ui/issues/issue-51719.stderr [new file with mode: 0644]
src/test/ui/issues/issue-51751.rs [new file with mode: 0644]
src/test/ui/issues/issue-51751.stderr [new file with mode: 0644]

index fd089fc688e32d5db01a66650e90a1dfe0a6bbce..a1bfd417566ad7473f93f8c2696af3674503aa6f 100644 (file)
@@ -2205,4 +2205,6 @@ trait Foo { }
     E0711, // a feature has been declared with conflicting stability attributes
 //  E0702, // replaced with a generic attribute input check
     E0726, // non-explicit (not `'_`) elided lifetime in unsupported position
+    E0727, // `async` generators are not yet supported
+    E0728, // `await` must be in an `async` function or block
 }
index 36e4195c989c0d0eb3a42c62e2ea95b110f4ad06..20e016b8b5b1ea59fe1bca158c679d84d0dcfe3e 100644 (file)
@@ -95,6 +95,7 @@ pub struct LoweringContext<'a> {
     modules: BTreeMap<NodeId, hir::ModuleItems>,
 
     is_generator: bool,
+    is_async_body: bool,
 
     catch_scopes: Vec<NodeId>,
     loop_scopes: Vec<NodeId>,
@@ -248,6 +249,7 @@ pub fn lower_crate(
         item_local_id_counters: Default::default(),
         node_id_to_hir_id: IndexVec::new(),
         is_generator: false,
+        is_async_body: false,
         is_in_trait_impl: false,
         lifetimes_to_define: Vec::new(),
         is_collecting_in_band_lifetimes: false,
@@ -801,8 +803,17 @@ fn lower_node_id_with_owner(&mut self, ast_node_id: NodeId, owner: NodeId) -> hi
     }
 
     fn record_body(&mut self, value: hir::Expr, arguments: HirVec<hir::Arg>) -> hir::BodyId {
+        if self.is_generator && self.is_async_body {
+            span_err!(
+                self.sess,
+                value.span,
+                E0727,
+                "`async` generators are not yet supported",
+            );
+            self.sess.abort_if_errors();
+        }
         let body = hir::Body {
-            is_generator: self.is_generator,
+            is_generator: self.is_generator || self.is_async_body,
             arguments,
             value,
         };
@@ -1124,7 +1135,8 @@ fn make_async_expr(
         span: Span,
         body: impl FnOnce(&mut LoweringContext<'_>) -> hir::Expr,
     ) -> hir::ExprKind {
-        let prev_is_generator = mem::replace(&mut self.is_generator, true);
+        let prev_is_generator = mem::replace(&mut self.is_generator, false);
+        let prev_is_async_body = mem::replace(&mut self.is_async_body, true);
         let output = match ret_ty {
             Some(ty) => FunctionRetTy::Ty(P(ty.clone())),
             None => FunctionRetTy::Default(span),
@@ -1140,6 +1152,7 @@ fn make_async_expr(
         let body_expr = body(self);
         let body_id = self.record_body(body_expr, arguments);
         self.is_generator = prev_is_generator;
+        self.is_async_body = prev_is_async_body;
 
         let capture_clause = self.lower_capture_clause(capture_clause);
         let decl = self.lower_fn_decl(&decl, None, /* impl trait allowed */ false, None);
@@ -1167,11 +1180,13 @@ fn lower_body<F>(&mut self, decl: Option<&FnDecl>, f: F) -> hir::BodyId
     where
         F: FnOnce(&mut LoweringContext<'_>) -> hir::Expr,
     {
-        let prev = mem::replace(&mut self.is_generator, false);
+        let prev_generator = mem::replace(&mut self.is_generator, false);
+        let prev_async = mem::replace(&mut self.is_async_body, false);
         let arguments = self.lower_args(decl);
         let result = f(self);
         let r = self.record_body(result, arguments);
-        self.is_generator = prev;
+        self.is_generator = prev_generator;
+        self.is_async_body = prev_async;
         return r;
     }
 
@@ -4205,6 +4220,7 @@ fn lower_expr(&mut self, e: &Expr) -> hir::Expr {
                     })
                 })
             }
+            ExprKind::Await(_origin, ref expr) => self.lower_await(e.span, expr),
             ExprKind::Closure(
                 capture_clause, ref asyncness, movability, ref decl, ref body, fn_decl_span
             ) => {
@@ -4326,12 +4342,13 @@ fn lower_expr(&mut self, e: &Expr) -> hir::Expr {
                 let id = self.next_id();
                 let e1 = self.lower_expr(e1);
                 let e2 = self.lower_expr(e2);
-                let ty_path = P(self.std_path(e.span, &["ops", "RangeInclusive"], None, false));
-                let ty = P(self.ty_path(id, e.span, hir::QPath::Resolved(None, ty_path)));
-                let new_seg = P(hir::PathSegment::from_ident(Ident::from_str("new")));
-                let new_path = hir::QPath::TypeRelative(ty, new_seg);
-                let new = P(self.expr(e.span, hir::ExprKind::Path(new_path), ThinVec::new()));
-                hir::ExprKind::Call(new, hir_vec![e1, e2])
+                self.expr_call_std_assoc_fn(
+                    id,
+                    e.span,
+                    &["ops", "RangeInclusive"],
+                    "new",
+                    hir_vec![e1, e2],
+                )
             }
             ExprKind::Range(ref e1, ref e2, lims) => {
                 use syntax::ast::RangeLimits::*;
@@ -4468,9 +4485,7 @@ fn lower_expr(&mut self, e: &Expr) -> hir::Expr {
                 let expr = opt_expr
                     .as_ref()
                     .map(|x| self.lower_expr(x))
-                    .unwrap_or_else(||
-                    self.expr(e.span, hir::ExprKind::Tup(hir_vec![]), ThinVec::new())
-                );
+                    .unwrap_or_else(|| self.expr_unit(e.span));
                 hir::ExprKind::Yield(P(expr))
             }
 
@@ -4503,7 +4518,7 @@ fn lower_expr(&mut self, e: &Expr) -> hir::Expr {
                     let body = if let Some(else_expr) = wildcard_arm {
                         P(self.lower_expr(else_expr))
                     } else {
-                        self.expr_tuple(e.span, hir_vec![])
+                        P(self.expr_tuple(e.span, hir_vec![]))
                     };
                     arms.push(self.arm(hir_vec![wildcard_pattern], body));
                 }
@@ -4651,8 +4666,11 @@ fn lower_expr(&mut self, e: &Expr) -> hir::Expr {
                     let iter = P(self.expr_ident(head_sp, iter, iter_pat_nid));
                     let ref_mut_iter = self.expr_mut_addr_of(head_sp, iter);
                     let next_path = &["iter", "Iterator", "next"];
-                    let next_path = P(self.expr_std_path(head_sp, next_path, None, ThinVec::new()));
-                    let next_expr = P(self.expr_call(head_sp, next_path, hir_vec![ref_mut_iter]));
+                    let next_expr = P(self.expr_call_std_path(
+                        head_sp,
+                        next_path,
+                        hir_vec![ref_mut_iter],
+                    ));
                     let arms = hir_vec![pat_arm, break_arm];
 
                     P(self.expr(
@@ -4723,9 +4741,11 @@ fn lower_expr(&mut self, e: &Expr) -> hir::Expr {
                 // `match ::std::iter::IntoIterator::into_iter(<head>) { ... }`
                 let into_iter_expr = {
                     let into_iter_path = &["iter", "IntoIterator", "into_iter"];
-                    let into_iter = P(self.expr_std_path(
-                            head_sp, into_iter_path, None, ThinVec::new()));
-                    P(self.expr_call(head_sp, into_iter, hir_vec![head]))
+                    P(self.expr_call_std_path(
+                        head_sp,
+                        into_iter_path,
+                        hir_vec![head],
+                    ))
                 };
 
                 let match_expr = P(self.expr_match(
@@ -4778,9 +4798,11 @@ fn lower_expr(&mut self, e: &Expr) -> hir::Expr {
                     let sub_expr = self.lower_expr(sub_expr);
 
                     let path = &["ops", "Try", "into_result"];
-                    let path = P(self.expr_std_path(
-                            unstable_span, path, None, ThinVec::new()));
-                    P(self.expr_call(e.span, path, hir_vec![sub_expr]))
+                    P(self.expr_call_std_path(
+                        unstable_span,
+                        path,
+                        hir_vec![sub_expr],
+                    ))
                 };
 
                 // `#[allow(unreachable_code)]`
@@ -4817,12 +4839,9 @@ fn lower_expr(&mut self, e: &Expr) -> hir::Expr {
                     let err_ident = self.str_to_ident("err");
                     let (err_local, err_local_nid) = self.pat_ident(try_span, err_ident);
                     let from_expr = {
-                        let path = &["convert", "From", "from"];
-                        let from = P(self.expr_std_path(
-                                try_span, path, None, ThinVec::new()));
+                        let from_path = &["convert", "From", "from"];
                         let err_expr = self.expr_ident(try_span, err_ident, err_local_nid);
-
-                        self.expr_call(try_span, from, hir_vec![err_expr])
+                        self.expr_call_std_path(try_span, from_path, hir_vec![err_expr])
                     };
                     let from_err_expr =
                         self.wrap_in_try_constructor("from_error", from_expr, unstable_span);
@@ -5056,6 +5075,42 @@ fn expr_call(
         self.expr(span, hir::ExprKind::Call(e, args), ThinVec::new())
     }
 
+    // Note: associated functions must use `expr_call_std_path`.
+    fn expr_call_std_path(
+        &mut self,
+        span: Span,
+        path_components: &[&str],
+        args: hir::HirVec<hir::Expr>,
+    ) -> hir::Expr {
+        let path = P(self.expr_std_path(span, path_components, None, ThinVec::new()));
+        self.expr_call(span, path, args)
+    }
+
+    // Create an expression calling an associated function of an std type.
+    //
+    // Associated functions cannot be resolved through the normal `std_path` function,
+    // as they are resolved differently and so cannot use `expr_call_std_path`.
+    //
+    // This function accepts the path component (`ty_path_components`) separately from
+    // the name of the associated function (`assoc_fn_name`) in order to facilitate
+    // separate resolution of the type and creation of a path referring to its associated
+    // function.
+    fn expr_call_std_assoc_fn(
+        &mut self,
+        ty_path_id: hir::HirId,
+        span: Span,
+        ty_path_components: &[&str],
+        assoc_fn_name: &str,
+        args: hir::HirVec<hir::Expr>,
+    ) -> hir::ExprKind {
+        let ty_path = P(self.std_path(span, ty_path_components, None, false));
+        let ty = P(self.ty_path(ty_path_id, span, hir::QPath::Resolved(None, ty_path)));
+        let fn_seg = P(hir::PathSegment::from_ident(Ident::from_str(assoc_fn_name)));
+        let fn_path = hir::QPath::TypeRelative(ty, fn_seg);
+        let fn_expr = P(self.expr(span, hir::ExprKind::Path(fn_path), ThinVec::new()));
+        hir::ExprKind::Call(fn_expr, args)
+    }
+
     fn expr_ident(&mut self, span: Span, ident: Ident, binding: hir::HirId) -> hir::Expr {
         self.expr_ident_with_attrs(span, ident, binding, ThinVec::new())
     }
@@ -5127,8 +5182,12 @@ fn expr_block(&mut self, b: P<hir::Block>, attrs: ThinVec<Attribute>) -> hir::Ex
         self.expr(b.span, hir::ExprKind::Block(b, None), attrs)
     }
 
-    fn expr_tuple(&mut self, sp: Span, exprs: hir::HirVec<hir::Expr>) -> P<hir::Expr> {
-        P(self.expr(sp, hir::ExprKind::Tup(exprs), ThinVec::new()))
+    fn expr_unit(&mut self, sp: Span) -> hir::Expr {
+        self.expr_tuple(sp, hir_vec![])
+    }
+
+    fn expr_tuple(&mut self, sp: Span, exprs: hir::HirVec<hir::Expr>) -> hir::Expr {
+        self.expr(sp, hir::ExprKind::Tup(exprs), ThinVec::new())
     }
 
     fn expr(&mut self, span: Span, node: hir::ExprKind, attrs: ThinVec<Attribute>) -> hir::Expr {
@@ -5184,6 +5243,23 @@ fn block_all(
         }
     }
 
+    fn expr_unsafe(&mut self, expr: P<hir::Expr>) -> hir::Expr {
+        let hir_id = self.next_id();
+        let span = expr.span;
+        self.expr(
+            span,
+            hir::ExprKind::Block(P(hir::Block {
+                stmts: hir_vec![],
+                expr: Some(expr),
+                hir_id,
+                rules: hir::UnsafeBlock(hir::CompilerGenerated),
+                span,
+                targeted_by_break: false,
+            }), None),
+            ThinVec::new(),
+        )
+    }
+
     fn pat_ok(&mut self, span: Span, pat: P<hir::Pat>) -> P<hir::Pat> {
         self.pat_std_enum(span, &["result", "Result", "Ok"], hir_vec![pat])
     }
@@ -5258,13 +5334,12 @@ fn std_path(
         span: Span,
         components: &[&str],
         params: Option<P<hir::GenericArgs>>,
-        is_value: bool
+        is_value: bool,
     ) -> hir::Path {
         let mut path = self.resolver
             .resolve_str_path(span, self.crate_root, components, is_value);
         path.segments.last_mut().unwrap().args = params;
 
-
         for seg in path.segments.iter_mut() {
             if seg.hir_id.is_some() {
                 seg.hir_id = Some(self.next_id());
@@ -5465,6 +5540,175 @@ fn wrap_in_try_constructor(
                                             ThinVec::new()));
         P(self.expr_call(e.span, from_err, hir_vec![e]))
     }
+
+    fn lower_await(
+        &mut self,
+        await_span: Span,
+        expr: &ast::Expr,
+    ) -> hir::ExprKind {
+        // to:
+        //
+        // {
+        //     let mut pinned = <expr>;
+        //     loop {
+        //         match ::std::future::poll_with_tls_context(unsafe {
+        //             ::std::pin::Pin::new_unchecked(&mut pinned)
+        //         }) {
+        //             ::std::task::Poll::Ready(x) => break x,
+        //             ::std::task::Poll::Pending => {},
+        //         }
+        //         yield ();
+        //     }
+        // }
+        if !self.is_async_body {
+            span_err!(
+                self.sess,
+                await_span,
+                E0728,
+                "`await` is only allowed inside `async` functions and blocks"
+            );
+            self.sess.abort_if_errors();
+        }
+        let span = self.mark_span_with_reason(
+            CompilerDesugaringKind::Await,
+            await_span,
+            None,
+        );
+        let gen_future_span = self.mark_span_with_reason(
+            CompilerDesugaringKind::Await,
+            await_span,
+            Some(vec![Symbol::intern("gen_future")].into()),
+        );
+
+        // let mut pinned = <expr>;
+        let expr = P(self.lower_expr(expr));
+        let pinned_ident = self.str_to_ident("pinned");
+        let (pinned_pat, pinned_pat_hid) = self.pat_ident_binding_mode(
+            span,
+            pinned_ident,
+            hir::BindingAnnotation::Mutable,
+        );
+        let pinned_let = self.stmt_let_pat(
+            span,
+            Some(expr),
+            pinned_pat,
+            hir::LocalSource::AwaitDesugar,
+        );
+
+        // ::std::future::poll_with_tls_context(unsafe {
+        //     ::std::pin::Pin::new_unchecked(&mut pinned)
+        // })`
+        let poll_expr = {
+            let pinned = P(self.expr_ident(span, pinned_ident, pinned_pat_hid));
+            let ref_mut_pinned = self.expr_mut_addr_of(span, pinned);
+            let pin_ty_id = self.next_id();
+            let new_unchecked_expr_kind = self.expr_call_std_assoc_fn(
+                pin_ty_id,
+                span,
+                &["pin", "Pin"],
+                "new_unchecked",
+                hir_vec![ref_mut_pinned],
+            );
+            let new_unchecked = P(self.expr(span, new_unchecked_expr_kind, ThinVec::new()));
+            let unsafe_expr = self.expr_unsafe(new_unchecked);
+            P(self.expr_call_std_path(
+                gen_future_span,
+                &["future", "poll_with_tls_context"],
+                hir_vec![unsafe_expr],
+            ))
+        };
+
+        // `::std::task::Poll::Ready(x) => break x`
+        let loop_node_id = self.sess.next_node_id();
+        let loop_hir_id = self.lower_node_id(loop_node_id);
+        let ready_arm = {
+            let x_ident = self.str_to_ident("x");
+            let (x_pat, x_pat_hid) = self.pat_ident(span, x_ident);
+            let x_expr = P(self.expr_ident(span, x_ident, x_pat_hid));
+            let ready_pat = self.pat_std_enum(
+                span,
+                &["task", "Poll", "Ready"],
+                hir_vec![x_pat],
+            );
+            let break_x = self.with_loop_scope(loop_node_id, |this| {
+                let expr_break = hir::ExprKind::Break(
+                    this.lower_loop_destination(None),
+                    Some(x_expr),
+                );
+                P(this.expr(await_span, expr_break, ThinVec::new()))
+            });
+            self.arm(hir_vec![ready_pat], break_x)
+        };
+
+        // `::std::task::Poll::Pending => {}`
+        let pending_arm = {
+            let pending_pat = self.pat_std_enum(
+                span,
+                &["task", "Poll", "Pending"],
+                hir_vec![],
+            );
+            let empty_block = P(hir::Block {
+                stmts: hir_vec![],
+                expr: None,
+                hir_id: self.next_id(),
+                rules: hir::DefaultBlock,
+                span,
+                targeted_by_break: false,
+            });
+            let empty_block = P(self.expr_block(empty_block, ThinVec::new()));
+            self.arm(hir_vec![pending_pat], empty_block)
+        };
+
+        let match_stmt = {
+            let match_expr = P(self.expr_match(
+                span,
+                poll_expr,
+                hir_vec![ready_arm, pending_arm],
+                hir::MatchSource::AwaitDesugar,
+            ));
+            hir::Stmt {
+                hir_id: self.next_id(),
+                node: hir::StmtKind::Expr(match_expr),
+                span,
+            }
+        };
+
+        let yield_stmt = {
+            let unit = self.expr_unit(span);
+            let yield_expr = P(self.expr(
+                span,
+                hir::ExprKind::Yield(P(unit)),
+                ThinVec::new(),
+            ));
+            hir::Stmt {
+                hir_id: self.next_id(),
+                node: hir::StmtKind::Expr(yield_expr),
+                span,
+            }
+        };
+
+        let loop_block = P(self.block_all(
+            span,
+            hir_vec![match_stmt, yield_stmt],
+            None,
+        ));
+
+        let loop_expr = P(hir::Expr {
+            hir_id: loop_hir_id,
+            node: hir::ExprKind::Loop(
+                loop_block,
+                None,
+                hir::LoopSource::Loop,
+            ),
+            span,
+            attrs: ThinVec::new(),
+        });
+
+        hir::ExprKind::Block(
+            P(self.block_all(span, hir_vec![pinned_let], Some(loop_expr))),
+            None,
+        )
+    }
 }
 
 fn body_ids(bodies: &BTreeMap<hir::BodyId, hir::Body>) -> Vec<hir::BodyId> {
index 1e357e1341710578392e22fab8e635db9cca9be9..01de7917e6e238224a7526acd53c46531be7f9bb 100644 (file)
@@ -1606,6 +1606,8 @@ pub enum LocalSource {
     /// }
     /// ```
     AsyncFn,
+    /// A desugared `<expr>.await`.
+    AwaitDesugar,
 }
 
 /// Hints at the original code for a `match _ { .. }`.
@@ -1624,6 +1626,8 @@ pub enum MatchSource {
     ForLoopDesugar,
     /// A desugared `?` operator.
     TryDesugar,
+    /// A desugared `<expr>.await`.
+    AwaitDesugar,
 }
 
 /// The loop type that yielded an `ExprKind::Loop`.
index 40cce8e77c0e049028d51d44bc9f8879ef43d226..90dd5099cbfd69d0f0faf21d11ffe19b2eca6d09 100644 (file)
@@ -396,6 +396,7 @@ fn hash_token<'a, 'gcx, W: StableHasherResult>(
 
 impl_stable_hash_for!(enum ::syntax_pos::hygiene::CompilerDesugaringKind {
     Async,
+    Await,
     QuestionMark,
     ExistentialReturnType,
     ForLoop,
index f70429c22b68c24607543d3440f1dc1634e8181e..f7a89271ec55f41659f8dbc197b8aafa25ff0d43 100644 (file)
@@ -46,7 +46,6 @@
 use syntax::errors::{Applicability, DiagnosticBuilder};
 use syntax::print::pprust::expr_to_string;
 use syntax::visit::FnKind;
-use syntax::struct_span_err;
 
 use rustc::hir::{self, GenericParamKind, PatKind};
 
@@ -1438,15 +1437,10 @@ fn check_ident_token(&mut self,
                          UnderMacro(under_macro): UnderMacro,
                          ident: ast::Ident)
     {
-        let ident_str = &ident.as_str()[..];
-        let cur_edition = cx.sess.edition();
-        let is_raw_ident = |ident: ast::Ident| {
-            cx.sess.parse_sess.raw_identifier_spans.borrow().contains(&ident.span)
-        };
-        let next_edition = match cur_edition {
+        let next_edition = match cx.sess.edition() {
             Edition::Edition2015 => {
-                match ident_str {
-                    "async" | "try" => Edition::Edition2018,
+                match &ident.as_str()[..] {
+                    "async" | "await" | "try" => Edition::Edition2018,
 
                     // rust-lang/rust#56327: Conservatively do not
                     // attempt to report occurrences of `dyn` within
@@ -1462,43 +1456,16 @@ fn check_ident_token(&mut self,
                     // an identifier.
                     "dyn" if !under_macro => Edition::Edition2018,
 
-                    // Only issue warnings for `await` if the `async_await`
-                    // feature isn't being used. Otherwise, users need
-                    // to keep using `await` for the macro exposed by std.
-                    "await" if !cx.sess.features_untracked().async_await => Edition::Edition2018,
                     _ => return,
                 }
             }
 
             // There are no new keywords yet for the 2018 edition and beyond.
-            // However, `await` is a "false" keyword in the 2018 edition,
-            // and can only be used if the `async_await` feature is enabled.
-            // Otherwise, we emit an error.
-            _ => {
-                if "await" == ident_str
-                    && !cx.sess.features_untracked().async_await
-                    && !is_raw_ident(ident)
-                {
-                    let mut err = struct_span_err!(
-                        cx.sess,
-                        ident.span,
-                        E0721,
-                        "`await` is a keyword in the {} edition", cur_edition,
-                    );
-                    err.span_suggestion(
-                        ident.span,
-                        "you can use a raw identifier to stay compatible",
-                        "r#await".to_string(),
-                        Applicability::MachineApplicable,
-                    );
-                    err.emit();
-                }
-                return
-            },
+            _ => return,
         };
 
         // don't lint `r#foo`
-        if is_raw_ident(ident) {
+        if cx.sess.parse_sess.raw_identifier_spans.borrow().contains(&ident.span) {
             return;
         }
 
index ed183acc93b74f75e9f5adafb28c90c8fef37406..1a7266859ad9f1a343a4ad1c1099cc4532e08068 100644 (file)
@@ -77,6 +77,7 @@ fn visit_local(&mut self, loc: &'tcx hir::Local) {
             hir::LocalSource::Normal => "local binding",
             hir::LocalSource::ForLoopDesugar => "`for` loop binding",
             hir::LocalSource::AsyncFn => "async fn binding",
+            hir::LocalSource::AwaitDesugar => "`await` future binding",
         });
 
         // Check legality of move bindings and `@` patterns.
@@ -412,8 +413,9 @@ fn check_arms<'a, 'tcx>(
                             err.emit();
                         }
 
-                        // Unreachable patterns in try expressions occur when one of the arms
-                        // are an uninhabited type. Which is OK.
+                        // Unreachable patterns in try and await expressions occur when one of
+                        // the arms are an uninhabited type. Which is OK.
+                        hir::MatchSource::AwaitDesugar |
                         hir::MatchSource::TryDesugar => {}
                     }
                 }
index 33b8c76bb531a2a6fc9219eb373bec20d0fad763..af2302d24f5214724715608ca6f26d59ca482112 100644 (file)
@@ -1065,6 +1065,7 @@ pub fn precedence(&self) -> ExprPrecedence {
             ExprKind::Block(..) => ExprPrecedence::Block,
             ExprKind::TryBlock(..) => ExprPrecedence::TryBlock,
             ExprKind::Async(..) => ExprPrecedence::Async,
+            ExprKind::Await(..) => ExprPrecedence::Await,
             ExprKind::Assign(..) => ExprPrecedence::Assign,
             ExprKind::AssignOp(..) => ExprPrecedence::AssignOp,
             ExprKind::Field(..) => ExprPrecedence::Field,
@@ -1186,6 +1187,9 @@ pub enum ExprKind {
     /// created during lowering cannot be made the parent of any other
     /// preexisting defs.
     Async(CaptureBy, NodeId, P<Block>),
+    /// An await expression (`my_future.await`).
+    Await(AwaitOrigin, P<Expr>),
+
     /// A try block (`try { ... }`).
     TryBlock(P<Block>),
 
@@ -1287,6 +1291,15 @@ pub enum Movability {
     Movable,
 }
 
+/// Whether an `await` comes from `await!` or `.await` syntax.
+/// FIXME: this should be removed when support for legacy `await!` is removed.
+/// https://github.com/rust-lang/rust/issues/60610
+#[derive(Clone, PartialEq, RustcEncodable, RustcDecodable, Debug, Copy)]
+pub enum AwaitOrigin {
+    FieldLike,
+    MacroLike,
+}
+
 pub type Mac = Spanned<Mac_>;
 
 /// Represents a macro invocation. The `Path` indicates which macro
index 2a1f3c48014069191ac6461a8277b230f2c978cd..dda5ac1f4e16e09b3d016ba1d9f801251a033035 100644 (file)
@@ -485,6 +485,10 @@ pub fn walk_feature_fields<F>(&self, mut f: F)
     // Allows async and await syntax.
     (active, async_await, "1.28.0", Some(50547), None),
 
+    // Allows await! macro-like syntax.
+    // This will likely be removed prior to stabilization of async/await.
+    (active, await_macro, "1.28.0", Some(50547), None),
+
     // Allows reinterpretation of the bits of a value of one type as another type during const eval.
     (active, const_transmute, "1.29.0", Some(53605), None),
 
@@ -2104,6 +2108,20 @@ fn visit_expr(&mut self, e: &'a ast::Expr) {
             ast::ExprKind::Async(..) => {
                 gate_feature_post!(&self, async_await, e.span, "async blocks are unstable");
             }
+            ast::ExprKind::Await(origin, _) => {
+                match origin {
+                    ast::AwaitOrigin::FieldLike =>
+                        gate_feature_post!(&self, async_await, e.span, "async/await is unstable"),
+                    ast::AwaitOrigin::MacroLike =>
+                        gate_feature_post!(
+                            &self,
+                            await_macro,
+                            e.span,
+                            "`await!(<expr>)` macro syntax is unstable, and will soon be removed \
+                            in favor of `<expr>.await` syntax."
+                        ),
+                }
+            }
             _ => {}
         }
         visit::walk_expr(self, e);
index 2e09235ca77b0a72bbcb1463778789e73e747164..6eb8b1b5004c96468958756878d0dbcf8a7b7b28 100644 (file)
@@ -1185,6 +1185,7 @@ pub fn noop_visit_expr<T: MutVisitor>(Expr { node, id, span, attrs }: &mut Expr,
             vis.visit_id(node_id);
             vis.visit_block(body);
         }
+        ExprKind::Await(_origin, expr) => vis.visit_expr(expr),
         ExprKind::Assign(el, er) => {
             vis.visit_expr(el);
             vis.visit_expr(er);
index d46feeab33599773fd3713303e45f53f2beba422..c5d761885657d0b956a608a2cef0131eb861acaf 100644 (file)
@@ -2751,6 +2751,14 @@ fn parse_bottom_expr(&mut self) -> PResult<'a, P<Expr>> {
                     db.span_label(self.span, "expected expression");
                     db.note("variable declaration using `let` is a statement");
                     return Err(db);
+                } else if self.span.rust_2018() && self.eat_keyword(keywords::Await) {
+                    // FIXME: remove this branch when `await!` is no longer supported
+                    // https://github.com/rust-lang/rust/issues/60610
+                    self.expect(&token::Not)?;
+                    self.expect(&token::OpenDelim(token::Paren))?;
+                    let expr = self.parse_expr()?;
+                    self.expect(&token::CloseDelim(token::Paren))?;
+                    ex = ExprKind::Await(ast::AwaitOrigin::MacroLike, expr);
                 } else if self.token.is_path_start() {
                     let path = self.parse_path(PathStyle::Expr)?;
 
@@ -3014,6 +3022,15 @@ fn parse_dot_or_call_expr_with(&mut self,
 
     // Assuming we have just parsed `.`, continue parsing into an expression.
     fn parse_dot_suffix(&mut self, self_arg: P<Expr>, lo: Span) -> PResult<'a, P<Expr>> {
+        if self.span.rust_2018() && self.eat_keyword(keywords::Await) {
+            let span = lo.to(self.prev_span);
+            let await_expr = self.mk_expr(
+                span,
+                ExprKind::Await(ast::AwaitOrigin::FieldLike, self_arg),
+                ThinVec::new(),
+            );
+            return Ok(await_expr);
+        }
         let segment = self.parse_path_segment(PathStyle::Expr)?;
         self.check_trailing_angle_brackets(&segment, token::OpenDelim(token::Paren));
 
index 2fa4f5263fbc581b951d2aeddf3b49e638846860..fd7a39c576daa79407a4650264f284bdd7490fa5 100644 (file)
@@ -99,6 +99,11 @@ pub(crate) fn ident_can_begin_expr(ident: ast::Ident, is_raw: bool) -> bool {
     ident_token.is_path_segment_keyword() ||
     [
         keywords::Async.name(),
+
+        // FIXME: remove when `await!(..)` syntax is removed
+        // https://github.com/rust-lang/rust/issues/60610
+        keywords::Await.name(),
+
         keywords::Do.name(),
         keywords::Box.name(),
         keywords::Break.name(),
index 6c0fdfaa776f956bc8f9ca590d9a53b2a40385ad..682621d40ab6583dfd2f2439c8d2d890b0eadc35 100644 (file)
@@ -2250,6 +2250,18 @@ fn print_expr_outer_attr_style(&mut self,
                 self.ibox(0)?;
                 self.print_block_with_attrs(blk, attrs)?;
             }
+            ast::ExprKind::Await(origin, ref expr) => {
+                match origin {
+                    ast::AwaitOrigin::MacroLike => {
+                        self.s.word("await!")?;
+                        self.print_expr_maybe_paren(expr, parser::PREC_FORCE_PAREN)?;
+                    }
+                    ast::AwaitOrigin::FieldLike => {
+                        self.print_expr_maybe_paren(expr, parser::PREC_POSTFIX)?;
+                        self.s.word(".await")?;
+                    }
+                }
+            }
             ast::ExprKind::Assign(ref lhs, ref rhs) => {
                 let prec = AssocOp::Assign.precedence() as i8;
                 self.print_expr_maybe_paren(lhs, prec + 1)?;
index 5f15ede7b0b6afac704a1097622415c061fda3ca..80dabffaba9f422414e76dcbdaf1544e121c8f89 100644 (file)
@@ -267,6 +267,7 @@ pub enum ExprPrecedence {
     TryBlock,
     Struct,
     Async,
+    Await,
     Err,
 }
 
@@ -301,6 +302,7 @@ pub fn order(self) -> i8 {
             ExprPrecedence::Unary => PREC_PREFIX,
 
             // Unary, postfix
+            ExprPrecedence::Await |
             ExprPrecedence::Call |
             ExprPrecedence::MethodCall |
             ExprPrecedence::Field |
@@ -346,6 +348,7 @@ pub fn contains_exterior_struct_lit(value: &ast::Expr) -> bool {
             // X { y: 1 } + X { y: 2 }
             contains_exterior_struct_lit(&lhs) || contains_exterior_struct_lit(&rhs)
         }
+        ast::ExprKind::Await(_, ref x) |
         ast::ExprKind::Unary(_, ref x) |
         ast::ExprKind::Cast(ref x, _) |
         ast::ExprKind::Type(ref x, _) |
index fc99d10b0b6c613cb76f4ec67b8f9522a2dc8ead..0503e5644dbc58112bd6547e974c1c2865b9f6df 100644 (file)
@@ -768,6 +768,7 @@ pub fn walk_expr<'a, V: Visitor<'a>>(visitor: &mut V, expression: &'a Expr) {
         ExprKind::Async(_, _, ref body) => {
             visitor.visit_block(body);
         }
+        ExprKind::Await(_, ref expr) => visitor.visit_expr(expr),
         ExprKind::Assign(ref left_hand_expression, ref right_hand_expression) => {
             visitor.visit_expr(left_hand_expression);
             visitor.visit_expr(right_hand_expression);
index c806020039d267cd4462cc9f5baa6be84d6caf2b..a901afdff43e63ff84e705a0870775907e1c21cf 100644 (file)
@@ -598,6 +598,7 @@ pub enum CompilerDesugaringKind {
     /// `impl Trait` with `Foo`.
     ExistentialReturnType,
     Async,
+    Await,
     ForLoop,
 }
 
@@ -605,6 +606,7 @@ impl CompilerDesugaringKind {
     pub fn name(self) -> Symbol {
         Symbol::intern(match self {
             CompilerDesugaringKind::Async => "async",
+            CompilerDesugaringKind::Await => "await",
             CompilerDesugaringKind::QuestionMark => "?",
             CompilerDesugaringKind::TryBlock => "try block",
             CompilerDesugaringKind::ExistentialReturnType => "existential type",
index cdbfabae7ce1f01cd2c7303da7635bd201bdf971..20759217b54a0962f72fdf16511f6b3a8dfa35f0 100644 (file)
@@ -84,6 +84,7 @@
 
         // Edition-specific keywords that are used in unstable Rust or reserved for future use.
         Async:              "async", // >= 2018 Edition only
+        Await:              "await", // >= 2018 Edition only
         Try:                "try", // >= 2018 Edition only
 
         // Special lifetime names
index e1b4328debd9a8918e7bea0c3e4aa16326bc31a9..49fd8b8b1ce27031f8111564473cb7b12bb13d92 100644 (file)
@@ -1,7 +1,7 @@
 // edition:2018
 // aux-build:arc_wake.rs
 
-#![feature(async_await, await_macro)]
+#![feature(async_await)]
 
 extern crate arc_wake;
 
@@ -46,14 +46,14 @@ fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<()> {
 
 fn async_block(x: u8) -> impl Future<Output = u8> {
     async move {
-        await!(wake_and_yield_once());
+        wake_and_yield_once().await;
         x
     }
 }
 
 fn async_block_with_borrow_named_lifetime<'a>(x: &'a u8) -> impl Future<Output = u8> + 'a {
     async move {
-        await!(wake_and_yield_once());
+        wake_and_yield_once().await;
         *x
     }
 }
@@ -61,43 +61,43 @@ fn async_block_with_borrow_named_lifetime<'a>(x: &'a u8) -> impl Future<Output =
 fn async_nonmove_block(x: u8) -> impl Future<Output = u8> {
     async move {
         let future = async {
-            await!(wake_and_yield_once());
+            wake_and_yield_once().await;
             x
         };
-        await!(future)
+        future.await
     }
 }
 
 fn async_closure(x: u8) -> impl Future<Output = u8> {
     (async move |x: u8| -> u8 {
-        await!(wake_and_yield_once());
+        wake_and_yield_once().await;
         x
     })(x)
 }
 
 async fn async_fn(x: u8) -> u8 {
-    await!(wake_and_yield_once());
+    wake_and_yield_once().await;
     x
 }
 
 async fn generic_async_fn<T>(x: T) -> T {
-    await!(wake_and_yield_once());
+    wake_and_yield_once().await;
     x
 }
 
 async fn async_fn_with_borrow(x: &u8) -> u8 {
-    await!(wake_and_yield_once());
+    wake_and_yield_once().await;
     *x
 }
 
 async fn async_fn_with_borrow_named_lifetime<'a>(x: &'a u8) -> u8 {
-    await!(wake_and_yield_once());
+    wake_and_yield_once().await;
     *x
 }
 
 fn async_fn_with_impl_future_named_lifetime<'a>(x: &'a u8) -> impl Future<Output = u8> + 'a {
     async move {
-        await!(wake_and_yield_once());
+        wake_and_yield_once().await;
         *x
     }
 }
@@ -110,18 +110,18 @@ async fn async_fn_multiple_args(x: &u8, _y: &u8) -> u8 {
 */
 
 async fn async_fn_multiple_args_named_lifetime<'a>(x: &'a u8, _y: &'a u8) -> u8 {
-    await!(wake_and_yield_once());
+    wake_and_yield_once().await;
     *x
 }
 
 fn async_fn_with_internal_borrow(y: u8) -> impl Future<Output = u8> {
     async move {
-        await!(async_fn_with_borrow_named_lifetime(&y))
+        async_fn_with_borrow_named_lifetime(&y).await
     }
 }
 
 unsafe async fn unsafe_async_fn(x: u8) -> u8 {
-    await!(wake_and_yield_once());
+    wake_and_yield_once().await;
     x
 }
 
@@ -134,7 +134,7 @@ fn foo() {}
 impl Foo {
     async fn async_method(x: u8) -> u8 {
         unsafe {
-            await!(unsafe_async_fn(x))
+            unsafe_async_fn(x).await
         }
     }
 }
@@ -165,7 +165,7 @@ macro_rules! test_with_borrow {
         ($($fn_name:expr,)*) => { $(
             test_future_yields_once_then_returns(|x| {
                 async move {
-                    await!($fn_name(&x))
+                    $fn_name(&x).await
                 }
             });
         )* }
@@ -181,7 +181,7 @@ macro_rules! test_with_borrow {
         Foo::async_method,
         |x| {
             async move {
-                unsafe { await!(unsafe_async_fn(x)) }
+                unsafe { unsafe_async_fn(x).await }
             }
         },
     }
@@ -192,7 +192,7 @@ macro_rules! test_with_borrow {
         async_fn_with_impl_future_named_lifetime,
         |x| {
             async move {
-                await!(async_fn_multiple_args_named_lifetime(x, x))
+                async_fn_multiple_args_named_lifetime(x, x).await
             }
         },
     }
diff --git a/src/test/run-pass/await-macro.rs b/src/test/run-pass/await-macro.rs
new file mode 100644 (file)
index 0000000..e1b4328
--- /dev/null
@@ -0,0 +1,199 @@
+// edition:2018
+// aux-build:arc_wake.rs
+
+#![feature(async_await, await_macro)]
+
+extern crate arc_wake;
+
+use std::pin::Pin;
+use std::future::Future;
+use std::sync::{
+    Arc,
+    atomic::{self, AtomicUsize},
+};
+use std::task::{Context, Poll};
+use arc_wake::ArcWake;
+
+struct Counter {
+    wakes: AtomicUsize,
+}
+
+impl ArcWake for Counter {
+    fn wake(self: Arc<Self>) {
+        Self::wake_by_ref(&self)
+    }
+    fn wake_by_ref(arc_self: &Arc<Self>) {
+        arc_self.wakes.fetch_add(1, atomic::Ordering::SeqCst);
+    }
+}
+
+struct WakeOnceThenComplete(bool);
+
+fn wake_and_yield_once() -> WakeOnceThenComplete { WakeOnceThenComplete(false) }
+
+impl Future for WakeOnceThenComplete {
+    type Output = ();
+    fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<()> {
+        if self.0 {
+            Poll::Ready(())
+        } else {
+            cx.waker().wake_by_ref();
+            self.0 = true;
+            Poll::Pending
+        }
+    }
+}
+
+fn async_block(x: u8) -> impl Future<Output = u8> {
+    async move {
+        await!(wake_and_yield_once());
+        x
+    }
+}
+
+fn async_block_with_borrow_named_lifetime<'a>(x: &'a u8) -> impl Future<Output = u8> + 'a {
+    async move {
+        await!(wake_and_yield_once());
+        *x
+    }
+}
+
+fn async_nonmove_block(x: u8) -> impl Future<Output = u8> {
+    async move {
+        let future = async {
+            await!(wake_and_yield_once());
+            x
+        };
+        await!(future)
+    }
+}
+
+fn async_closure(x: u8) -> impl Future<Output = u8> {
+    (async move |x: u8| -> u8 {
+        await!(wake_and_yield_once());
+        x
+    })(x)
+}
+
+async fn async_fn(x: u8) -> u8 {
+    await!(wake_and_yield_once());
+    x
+}
+
+async fn generic_async_fn<T>(x: T) -> T {
+    await!(wake_and_yield_once());
+    x
+}
+
+async fn async_fn_with_borrow(x: &u8) -> u8 {
+    await!(wake_and_yield_once());
+    *x
+}
+
+async fn async_fn_with_borrow_named_lifetime<'a>(x: &'a u8) -> u8 {
+    await!(wake_and_yield_once());
+    *x
+}
+
+fn async_fn_with_impl_future_named_lifetime<'a>(x: &'a u8) -> impl Future<Output = u8> + 'a {
+    async move {
+        await!(wake_and_yield_once());
+        *x
+    }
+}
+
+/* FIXME(cramertj) support when `existential type T<'a, 'b>:;` works
+async fn async_fn_multiple_args(x: &u8, _y: &u8) -> u8 {
+    await!(wake_and_yield_once());
+    *x
+}
+*/
+
+async fn async_fn_multiple_args_named_lifetime<'a>(x: &'a u8, _y: &'a u8) -> u8 {
+    await!(wake_and_yield_once());
+    *x
+}
+
+fn async_fn_with_internal_borrow(y: u8) -> impl Future<Output = u8> {
+    async move {
+        await!(async_fn_with_borrow_named_lifetime(&y))
+    }
+}
+
+unsafe async fn unsafe_async_fn(x: u8) -> u8 {
+    await!(wake_and_yield_once());
+    x
+}
+
+struct Foo;
+
+trait Bar {
+    fn foo() {}
+}
+
+impl Foo {
+    async fn async_method(x: u8) -> u8 {
+        unsafe {
+            await!(unsafe_async_fn(x))
+        }
+    }
+}
+
+fn test_future_yields_once_then_returns<F, Fut>(f: F)
+where
+    F: FnOnce(u8) -> Fut,
+    Fut: Future<Output = u8>,
+{
+    let mut fut = Box::pin(f(9));
+    let counter = Arc::new(Counter { wakes: AtomicUsize::new(0) });
+    let waker = ArcWake::into_waker(counter.clone());
+    let mut cx = Context::from_waker(&waker);
+    assert_eq!(0, counter.wakes.load(atomic::Ordering::SeqCst));
+    assert_eq!(Poll::Pending, fut.as_mut().poll(&mut cx));
+    assert_eq!(1, counter.wakes.load(atomic::Ordering::SeqCst));
+    assert_eq!(Poll::Ready(9), fut.as_mut().poll(&mut cx));
+}
+
+fn main() {
+    macro_rules! test {
+        ($($fn_name:expr,)*) => { $(
+            test_future_yields_once_then_returns($fn_name);
+        )* }
+    }
+
+    macro_rules! test_with_borrow {
+        ($($fn_name:expr,)*) => { $(
+            test_future_yields_once_then_returns(|x| {
+                async move {
+                    await!($fn_name(&x))
+                }
+            });
+        )* }
+    }
+
+    test! {
+        async_block,
+        async_nonmove_block,
+        async_closure,
+        async_fn,
+        generic_async_fn,
+        async_fn_with_internal_borrow,
+        Foo::async_method,
+        |x| {
+            async move {
+                unsafe { await!(unsafe_async_fn(x)) }
+            }
+        },
+    }
+    test_with_borrow! {
+        async_block_with_borrow_named_lifetime,
+        async_fn_with_borrow,
+        async_fn_with_borrow_named_lifetime,
+        async_fn_with_impl_future_named_lifetime,
+        |x| {
+            async move {
+                await!(async_fn_multiple_args_named_lifetime(x, x))
+            }
+        },
+    }
+}
index 12be6582a21e8e5df40d5dd24b7396ebcd3eae03..b7e60b773b416be29340e2330ab565894996a8c7 100644 (file)
@@ -1,7 +1,7 @@
 // edition:2018
 // run-pass
 
-#![feature(async_await, await_macro)]
+#![feature(async_await)]
 
 trait Foo { }
 
@@ -14,15 +14,15 @@ async fn foo_async<T>(_v: T) -> u8 where T: Foo {
 }
 
 async fn bad<T>(v: T) -> u8 where T: Foo {
-    await!(foo_async(v))
+    foo_async(v).await
 }
 
 async fn async_main() {
     let mut v = ();
 
-    let _ = await!(bad(&mut v));
-    let _ = await!(foo_async(&mut v));
-    let _ = await!(bad(v));
+    let _ = bad(&mut v).await;
+    let _ = foo_async(&mut v).await;
+    let _ = bad(v).await;
 }
 
 fn main() {
diff --git a/src/test/ui/await-keyword/2015-edition-error-in-non-macro-position.rs b/src/test/ui/await-keyword/2015-edition-error-in-non-macro-position.rs
new file mode 100644 (file)
index 0000000..c4f3f3e
--- /dev/null
@@ -0,0 +1,36 @@
+#![feature(async_await, await_macro)]
+#![allow(non_camel_case_types)]
+#![deny(keyword_idents)]
+
+mod outer_mod {
+    pub mod await { //~ ERROR `await` is a keyword in the 2018 edition
+    //~^ WARN this was previously accepted by the compiler
+        pub struct await; //~ ERROR `await` is a keyword in the 2018 edition
+        //~^ WARN this was previously accepted by the compiler
+    }
+}
+use outer_mod::await::await; //~ ERROR `await` is a keyword in the 2018 edition
+//~^ ERROR `await` is a keyword in the 2018 edition
+//~^^ WARN this was previously accepted by the compiler
+//~^^^ WARN this was previously accepted by the compiler
+
+struct Foo { await: () }
+//~^ ERROR `await` is a keyword in the 2018 edition
+//~^^ WARN this was previously accepted by the compiler
+
+impl Foo { fn await() {} }
+//~^ ERROR `await` is a keyword in the 2018 edition
+//~^^ WARN this was previously accepted by the compiler
+
+macro_rules! await {
+//~^ ERROR `await` is a keyword in the 2018 edition
+//~^^ WARN this was previously accepted by the compiler
+    () => {}
+}
+
+fn main() {
+    match await { await => {} } //~ ERROR `await` is a keyword in the 2018 edition
+    //~^ ERROR `await` is a keyword in the 2018 edition
+    //~^^ WARN this was previously accepted by the compiler
+    //~^^^ WARN this was previously accepted by the compiler
+}
diff --git a/src/test/ui/await-keyword/2015-edition-error-in-non-macro-position.stderr b/src/test/ui/await-keyword/2015-edition-error-in-non-macro-position.stderr
new file mode 100644 (file)
index 0000000..067ecd6
--- /dev/null
@@ -0,0 +1,88 @@
+error: `await` is a keyword in the 2018 edition
+  --> $DIR/2015-edition-error-in-non-macro-position.rs:6:13
+   |
+LL |     pub mod await {
+   |             ^^^^^ help: you can use a raw identifier to stay compatible: `r#await`
+   |
+note: lint level defined here
+  --> $DIR/2015-edition-error-in-non-macro-position.rs:3:9
+   |
+LL | #![deny(keyword_idents)]
+   |         ^^^^^^^^^^^^^^
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in the 2018 edition!
+   = note: for more information, see issue #49716 <https://github.com/rust-lang/rust/issues/49716>
+
+error: `await` is a keyword in the 2018 edition
+  --> $DIR/2015-edition-error-in-non-macro-position.rs:8:20
+   |
+LL |         pub struct await;
+   |                    ^^^^^ help: you can use a raw identifier to stay compatible: `r#await`
+   |
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in the 2018 edition!
+   = note: for more information, see issue #49716 <https://github.com/rust-lang/rust/issues/49716>
+
+error: `await` is a keyword in the 2018 edition
+  --> $DIR/2015-edition-error-in-non-macro-position.rs:12:16
+   |
+LL | use outer_mod::await::await;
+   |                ^^^^^ help: you can use a raw identifier to stay compatible: `r#await`
+   |
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in the 2018 edition!
+   = note: for more information, see issue #49716 <https://github.com/rust-lang/rust/issues/49716>
+
+error: `await` is a keyword in the 2018 edition
+  --> $DIR/2015-edition-error-in-non-macro-position.rs:12:23
+   |
+LL | use outer_mod::await::await;
+   |                       ^^^^^ help: you can use a raw identifier to stay compatible: `r#await`
+   |
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in the 2018 edition!
+   = note: for more information, see issue #49716 <https://github.com/rust-lang/rust/issues/49716>
+
+error: `await` is a keyword in the 2018 edition
+  --> $DIR/2015-edition-error-in-non-macro-position.rs:17:14
+   |
+LL | struct Foo { await: () }
+   |              ^^^^^ help: you can use a raw identifier to stay compatible: `r#await`
+   |
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in the 2018 edition!
+   = note: for more information, see issue #49716 <https://github.com/rust-lang/rust/issues/49716>
+
+error: `await` is a keyword in the 2018 edition
+  --> $DIR/2015-edition-error-in-non-macro-position.rs:21:15
+   |
+LL | impl Foo { fn await() {} }
+   |               ^^^^^ help: you can use a raw identifier to stay compatible: `r#await`
+   |
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in the 2018 edition!
+   = note: for more information, see issue #49716 <https://github.com/rust-lang/rust/issues/49716>
+
+error: `await` is a keyword in the 2018 edition
+  --> $DIR/2015-edition-error-in-non-macro-position.rs:25:14
+   |
+LL | macro_rules! await {
+   |              ^^^^^ help: you can use a raw identifier to stay compatible: `r#await`
+   |
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in the 2018 edition!
+   = note: for more information, see issue #49716 <https://github.com/rust-lang/rust/issues/49716>
+
+error: `await` is a keyword in the 2018 edition
+  --> $DIR/2015-edition-error-in-non-macro-position.rs:32:11
+   |
+LL |     match await { await => {} }
+   |           ^^^^^ help: you can use a raw identifier to stay compatible: `r#await`
+   |
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in the 2018 edition!
+   = note: for more information, see issue #49716 <https://github.com/rust-lang/rust/issues/49716>
+
+error: `await` is a keyword in the 2018 edition
+  --> $DIR/2015-edition-error-in-non-macro-position.rs:32:19
+   |
+LL |     match await { await => {} }
+   |                   ^^^^^ help: you can use a raw identifier to stay compatible: `r#await`
+   |
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in the 2018 edition!
+   = note: for more information, see issue #49716 <https://github.com/rust-lang/rust/issues/49716>
+
+error: aborting due to 9 previous errors
+
diff --git a/src/test/ui/await-keyword/2015-edition-no-warnings-with-feature-gate.rs b/src/test/ui/await-keyword/2015-edition-no-warnings-with-feature-gate.rs
deleted file mode 100644 (file)
index 92c60e7..0000000
+++ /dev/null
@@ -1,16 +0,0 @@
-// compile-pass
-
-#![feature(async_await)]
-#![allow(non_camel_case_types)]
-#![deny(keyword_idents)]
-
-mod outer_mod {
-    pub mod await {
-        pub struct await;
-    }
-}
-use outer_mod::await::await;
-
-fn main() {
-    match await { await => {} }
-}
diff --git a/src/test/ui/await-keyword/2018-edition-error-in-non-macro-position.rs b/src/test/ui/await-keyword/2018-edition-error-in-non-macro-position.rs
new file mode 100644 (file)
index 0000000..b2e8e4b
--- /dev/null
@@ -0,0 +1,27 @@
+// edition:2018
+
+#![allow(non_camel_case_types)]
+#![feature(async_await, await_macro)]
+
+mod outer_mod {
+    pub mod await { //~ ERROR expected identifier, found reserved keyword `await`
+        pub struct await; //~ ERROR expected identifier, found reserved keyword `await`
+    }
+}
+use self::outer_mod::await::await; //~ ERROR expected identifier, found reserved keyword `await`
+//~^ ERROR expected identifier, found reserved keyword `await`
+
+struct Foo { await: () }
+//~^ ERROR expected identifier, found reserved keyword `await`
+
+impl Foo { fn await() {} }
+//~^ ERROR expected identifier, found reserved keyword `await`
+
+macro_rules! await {
+//~^ ERROR expected identifier, found reserved keyword `await`
+    () => {}
+}
+
+fn main() {
+    match await { await => () } //~ ERROR expected `!`, found `{`
+}
diff --git a/src/test/ui/await-keyword/2018-edition-error-in-non-macro-position.stderr b/src/test/ui/await-keyword/2018-edition-error-in-non-macro-position.stderr
new file mode 100644 (file)
index 0000000..076a31b
--- /dev/null
@@ -0,0 +1,80 @@
+error: expected identifier, found reserved keyword `await`
+  --> $DIR/2018-edition-error-in-non-macro-position.rs:7:13
+   |
+LL |     pub mod await {
+   |             ^^^^^ expected identifier, found reserved keyword
+help: you can escape reserved keywords to use them as identifiers
+   |
+LL |     pub mod r#await {
+   |             ^^^^^^^
+
+error: expected identifier, found reserved keyword `await`
+  --> $DIR/2018-edition-error-in-non-macro-position.rs:8:20
+   |
+LL |         pub struct await;
+   |                    ^^^^^ expected identifier, found reserved keyword
+help: you can escape reserved keywords to use them as identifiers
+   |
+LL |         pub struct r#await;
+   |                    ^^^^^^^
+
+error: expected identifier, found reserved keyword `await`
+  --> $DIR/2018-edition-error-in-non-macro-position.rs:11:22
+   |
+LL | use self::outer_mod::await::await;
+   |                      ^^^^^ expected identifier, found reserved keyword
+help: you can escape reserved keywords to use them as identifiers
+   |
+LL | use self::outer_mod::r#await::await;
+   |                      ^^^^^^^
+
+error: expected identifier, found reserved keyword `await`
+  --> $DIR/2018-edition-error-in-non-macro-position.rs:11:29
+   |
+LL | use self::outer_mod::await::await;
+   |                             ^^^^^ expected identifier, found reserved keyword
+help: you can escape reserved keywords to use them as identifiers
+   |
+LL | use self::outer_mod::await::r#await;
+   |                             ^^^^^^^
+
+error: expected identifier, found reserved keyword `await`
+  --> $DIR/2018-edition-error-in-non-macro-position.rs:14:14
+   |
+LL | struct Foo { await: () }
+   |              ^^^^^ expected identifier, found reserved keyword
+help: you can escape reserved keywords to use them as identifiers
+   |
+LL | struct Foo { r#await: () }
+   |              ^^^^^^^
+
+error: expected identifier, found reserved keyword `await`
+  --> $DIR/2018-edition-error-in-non-macro-position.rs:17:15
+   |
+LL | impl Foo { fn await() {} }
+   |               ^^^^^ expected identifier, found reserved keyword
+help: you can escape reserved keywords to use them as identifiers
+   |
+LL | impl Foo { fn r#await() {} }
+   |               ^^^^^^^
+
+error: expected identifier, found reserved keyword `await`
+  --> $DIR/2018-edition-error-in-non-macro-position.rs:20:14
+   |
+LL | macro_rules! await {
+   |              ^^^^^ expected identifier, found reserved keyword
+help: you can escape reserved keywords to use them as identifiers
+   |
+LL | macro_rules! r#await {
+   |              ^^^^^^^
+
+error: expected `!`, found `{`
+  --> $DIR/2018-edition-error-in-non-macro-position.rs:26:17
+   |
+LL |     match await { await => () }
+   |     -----       ^ expected `!`
+   |     |
+   |     while parsing this match expression
+
+error: aborting due to 8 previous errors
+
index 7ba3382ddf1298229797b850a8840d180d8fe03b..e0b2962ce9791975acab3dc4bb0d8f7c6c0fd71d 100644 (file)
@@ -2,14 +2,13 @@
 #![allow(non_camel_case_types)]
 
 mod outer_mod {
-    pub mod await { //~ ERROR `await` is a keyword
-        pub struct await; //~ ERROR `await` is a keyword
+    pub mod await { //~ ERROR expected identifier
+        pub struct await; //~ ERROR expected identifier
     }
 }
-use self::outer_mod::await::await; //~ ERROR `await` is a keyword
-    //~^ ERROR `await` is a keyword
+use self::outer_mod::await::await; //~ ERROR expected identifier
+    //~^ ERROR expected identifier, found reserved keyword `await`
 
 fn main() {
-    match await { await => () } //~ ERROR `await` is a keyword
-    //~^ ERROR `await` is a keyword
+    match await { await => () } //~ ERROR expected `!`, found `{`
 }
index 67ff6c5675abfd7a0361fd57e852dff571e375ec..c8bf9b42ca5459f1b28e86c23135ef44d39659c9 100644 (file)
@@ -1,38 +1,50 @@
-error[E0721]: `await` is a keyword in the 2018 edition
+error: expected identifier, found reserved keyword `await`
   --> $DIR/2018-edition-error.rs:5:13
    |
 LL |     pub mod await {
-   |             ^^^^^ help: you can use a raw identifier to stay compatible: `r#await`
+   |             ^^^^^ expected identifier, found reserved keyword
+help: you can escape reserved keywords to use them as identifiers
+   |
+LL |     pub mod r#await {
+   |             ^^^^^^^
 
-error[E0721]: `await` is a keyword in the 2018 edition
+error: expected identifier, found reserved keyword `await`
   --> $DIR/2018-edition-error.rs:6:20
    |
 LL |         pub struct await;
-   |                    ^^^^^ help: you can use a raw identifier to stay compatible: `r#await`
+   |                    ^^^^^ expected identifier, found reserved keyword
+help: you can escape reserved keywords to use them as identifiers
+   |
+LL |         pub struct r#await;
+   |                    ^^^^^^^
 
-error[E0721]: `await` is a keyword in the 2018 edition
+error: expected identifier, found reserved keyword `await`
   --> $DIR/2018-edition-error.rs:9:22
    |
 LL | use self::outer_mod::await::await;
-   |                      ^^^^^ help: you can use a raw identifier to stay compatible: `r#await`
+   |                      ^^^^^ expected identifier, found reserved keyword
+help: you can escape reserved keywords to use them as identifiers
+   |
+LL | use self::outer_mod::r#await::await;
+   |                      ^^^^^^^
 
-error[E0721]: `await` is a keyword in the 2018 edition
+error: expected identifier, found reserved keyword `await`
   --> $DIR/2018-edition-error.rs:9:29
    |
 LL | use self::outer_mod::await::await;
-   |                             ^^^^^ help: you can use a raw identifier to stay compatible: `r#await`
-
-error[E0721]: `await` is a keyword in the 2018 edition
-  --> $DIR/2018-edition-error.rs:13:11
+   |                             ^^^^^ expected identifier, found reserved keyword
+help: you can escape reserved keywords to use them as identifiers
    |
-LL |     match await { await => () }
-   |           ^^^^^ help: you can use a raw identifier to stay compatible: `r#await`
+LL | use self::outer_mod::await::r#await;
+   |                             ^^^^^^^
 
-error[E0721]: `await` is a keyword in the 2018 edition
-  --> $DIR/2018-edition-error.rs:13:19
+error: expected `!`, found `{`
+  --> $DIR/2018-edition-error.rs:13:17
    |
 LL |     match await { await => () }
-   |                   ^^^^^ help: you can use a raw identifier to stay compatible: `r#await`
+   |     -----       ^ expected `!`
+   |     |
+   |     while parsing this match expression
 
-error: aborting due to 6 previous errors
+error: aborting due to 5 previous errors
 
diff --git a/src/test/ui/await-keyword/2018-edition-no-error-with-feature-gate.rs b/src/test/ui/await-keyword/2018-edition-no-error-with-feature-gate.rs
deleted file mode 100644 (file)
index 52d32c8..0000000
+++ /dev/null
@@ -1,16 +0,0 @@
-// compile-pass
-// edition:2018
-
-#![allow(non_camel_case_types)]
-#![feature(async_await)]
-
-mod outer_mod {
-    pub mod await {
-        pub struct await;
-    }
-}
-use self::outer_mod::await::await;
-
-fn main() {
-    match await { await => () }
-}
index 96dd48052def876cc7a3951334cf12bc8de07065..b4c899b0d0295b6b77b0fd45a5b0640dd51ad754 100644 (file)
@@ -6,5 +6,5 @@ macro_rules! r#await {
 
 fn main() {
     await!()
-    //~^ ERROR `await` is a keyword
+    //~^ ERROR expected expression, found `)`
 }
index 9483f77422759215a3287594fda81e3904e8c561..0996c38b3b6c61f18efcbefa970c498b3457bf8b 100644 (file)
@@ -1,8 +1,8 @@
-error[E0721]: `await` is a keyword in the 2018 edition
-  --> $DIR/post_expansion_error.rs:8:5
+error: expected expression, found `)`
+  --> $DIR/post_expansion_error.rs:8:12
    |
 LL |     await!()
-   |     ^^^^^ help: you can use a raw identifier to stay compatible: `r#await`
+   |            ^ expected expression
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/feature-gate/await-macro.rs b/src/test/ui/feature-gate/await-macro.rs
new file mode 100644 (file)
index 0000000..291db9b
--- /dev/null
@@ -0,0 +1,12 @@
+// gate-test-await_macro
+// edition:2018
+
+#![feature(async_await)]
+
+async fn bar() {}
+
+async fn foo() {
+    await!(bar()); //~ ERROR `await!(<expr>)` macro syntax is unstable, and will soon be removed
+}
+
+fn main() {}
diff --git a/src/test/ui/feature-gate/await-macro.stderr b/src/test/ui/feature-gate/await-macro.stderr
new file mode 100644 (file)
index 0000000..b683365
--- /dev/null
@@ -0,0 +1,12 @@
+error[E0658]: `await!(<expr>)` macro syntax is unstable, and will soon be removed in favor of `<expr>.await` syntax.
+  --> $DIR/await-macro.rs:9:5
+   |
+LL |     await!(bar());
+   |     ^^^^^
+   |
+   = note: for more information, see https://github.com/rust-lang/rust/issues/50547
+   = help: add #![feature(await_macro)] to the crate attributes to enable
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0658`.
index f49369b125f6fa5dcd72bea3f8a099c54b2ff465..77174b03217829661093ca8b391bd0f7210489be 100644 (file)
@@ -2,13 +2,14 @@
 // Error message should pinpoint the type parameter T as needing to be bound
 // (rather than give a general error message)
 // edition:2018
-#![feature(futures_api, async_await, await_macro)]
+#![feature(async_await)]
 async fn bar<T>() -> () {}
 
 async fn foo() {
-        await!(bar());
-        //~^ ERROR type inside generator must be known in this context
-        //~| NOTE cannot infer type for `T`
-        //~| NOTE the type is part of the generator because of this `yield`
+    bar().await;
+    //~^ ERROR type inside generator must be known in this context
+    //~| NOTE cannot infer type for `T`
+    //~| NOTE the type is part of the generator because of this `yield`
+    //~| NOTE in this expansion of desugaring of `await`
 }
 fn main() {}
index 57ccdda3f43a19b07718ea56c31ec07c3642d8df..afb9adf4c77cc019005117079f9577d23f90192e 100644 (file)
@@ -1,15 +1,14 @@
 error[E0698]: type inside generator must be known in this context
-  --> $DIR/unresolved_type_param.rs:9:16
+  --> $DIR/unresolved_type_param.rs:9:5
    |
-LL |         await!(bar());
-   |                ^^^ cannot infer type for `T`
+LL |     bar().await;
+   |     ^^^ cannot infer type for `T`
    |
 note: the type is part of the generator because of this `yield`
-  --> $DIR/unresolved_type_param.rs:9:9
+  --> $DIR/unresolved_type_param.rs:9:5
    |
-LL |         await!(bar());
-   |         ^^^^^^^^^^^^^^
-   = note: this error originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info)
+LL |     bar().await;
+   |     ^^^^^^^^^^^
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/issues/issue-51719.rs b/src/test/ui/issues/issue-51719.rs
new file mode 100644 (file)
index 0000000..2c02ac0
--- /dev/null
@@ -0,0 +1,11 @@
+// edition:2018
+//
+// Tests that the .await syntax can't be used to make a generator
+
+#![feature(async_await)]
+
+async fn foo() {}
+
+fn make_generator() {
+    let _gen = || foo.await; //~ ERROR `await` is only allowed inside `async` functions and blocks
+}
diff --git a/src/test/ui/issues/issue-51719.stderr b/src/test/ui/issues/issue-51719.stderr
new file mode 100644 (file)
index 0000000..768909b
--- /dev/null
@@ -0,0 +1,8 @@
+error[E0728]: `await` is only allowed inside `async` functions and blocks
+  --> $DIR/issue-51719.rs:10:19
+   |
+LL |     let _gen = || foo.await;
+   |                   ^^^^^^^^^
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/issues/issue-51751.rs b/src/test/ui/issues/issue-51751.rs
new file mode 100644 (file)
index 0000000..7afd7ec
--- /dev/null
@@ -0,0 +1,13 @@
+// edition:2018
+
+#![feature(async_await)]
+
+async fn inc(limit: i64) -> i64 {
+    limit + 1
+}
+
+fn main() {
+    let result = inc(10000);
+    let finished = result.await;
+    //~^ ERROR `await` is only allowed inside `async` functions and blocks
+}
diff --git a/src/test/ui/issues/issue-51751.stderr b/src/test/ui/issues/issue-51751.stderr
new file mode 100644 (file)
index 0000000..0c4cb03
--- /dev/null
@@ -0,0 +1,8 @@
+error[E0728]: `await` is only allowed inside `async` functions and blocks
+  --> $DIR/issue-51751.rs:11:20
+   |
+LL |     let finished = result.await;
+   |                    ^^^^^^^^^^^^
+
+error: aborting due to previous error
+