about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--src/librustc_parse/parser/expr.rs54
-rw-r--r--src/librustc_parse/parser/item.rs2
-rw-r--r--src/librustc_parse/parser/stmt.rs2
-rw-r--r--src/librustc_resolve/late/diagnostics.rs6
-rw-r--r--src/test/ui/async-await/edition-deny-async-fns-2015.stderr27
-rw-r--r--src/test/ui/editions/async-block-2015.rs30
-rw-r--r--src/test/ui/editions/async-block-2015.stderr41
7 files changed, 121 insertions, 41 deletions
diff --git a/src/librustc_parse/parser/expr.rs b/src/librustc_parse/parser/expr.rs
index 55c9f26999b..b3bb72554e9 100644
--- a/src/librustc_parse/parser/expr.rs
+++ b/src/librustc_parse/parser/expr.rs
@@ -13,7 +13,7 @@ use rustc_ast::util::classify;
 use rustc_ast::util::literal::LitError;
 use rustc_ast::util::parser::{prec_let_scrutinee_needs_par, AssocOp, Fixity};
 use rustc_ast_pretty::pprust;
-use rustc_errors::{Applicability, PResult};
+use rustc_errors::{Applicability, DiagnosticBuilder, PResult};
 use rustc_span::source_map::{self, Span, Spanned};
 use rustc_span::symbol::{kw, sym, Symbol};
 use std::mem;
@@ -1068,8 +1068,8 @@ impl<'a> Parser<'a> {
     }
 
     fn parse_path_start_expr(&mut self, attrs: AttrVec) -> PResult<'a, P<Expr>> {
-        let lo = self.token.span;
         let path = self.parse_path(PathStyle::Expr)?;
+        let lo = path.span;
 
         // `!`, as an operator, is prefix, so we know this isn't that.
         let (hi, kind) = if self.eat(&token::Not) {
@@ -1081,7 +1081,7 @@ impl<'a> Parser<'a> {
             };
             (self.prev_token.span, ExprKind::MacCall(mac))
         } else if self.check(&token::OpenDelim(token::Brace)) {
-            if let Some(expr) = self.maybe_parse_struct_expr(lo, &path, &attrs) {
+            if let Some(expr) = self.maybe_parse_struct_expr(&path, &attrs) {
                 return expr;
             } else {
                 (path.span, ExprKind::Path(None, path))
@@ -1895,16 +1895,15 @@ impl<'a> Parser<'a> {
 
     fn maybe_parse_struct_expr(
         &mut self,
-        lo: Span,
         path: &ast::Path,
         attrs: &AttrVec,
     ) -> Option<PResult<'a, P<Expr>>> {
         let struct_allowed = !self.restrictions.contains(Restrictions::NO_STRUCT_LITERAL);
         if struct_allowed || self.is_certainly_not_a_block() {
             // This is a struct literal, but we don't can't accept them here.
-            let expr = self.parse_struct_expr(lo, path.clone(), attrs.clone());
+            let expr = self.parse_struct_expr(path.clone(), attrs.clone());
             if let (Ok(expr), false) = (&expr, struct_allowed) {
-                self.error_struct_lit_not_allowed_here(lo, expr.span);
+                self.error_struct_lit_not_allowed_here(path.span, expr.span);
             }
             return Some(expr);
         }
@@ -1923,17 +1922,23 @@ impl<'a> Parser<'a> {
 
     pub(super) fn parse_struct_expr(
         &mut self,
-        lo: Span,
         pth: ast::Path,
         mut attrs: AttrVec,
     ) -> PResult<'a, P<Expr>> {
-        let struct_sp = lo.to(self.prev_token.span);
         self.bump();
         let mut fields = Vec::new();
         let mut base = None;
+        let mut recover_async = false;
 
         attrs.extend(self.parse_inner_attributes()?);
 
+        let mut async_block_err = |e: &mut DiagnosticBuilder<'_>, span: Span| {
+            recover_async = true;
+            e.span_label(span, "`async` blocks are only allowed in the 2018 edition");
+            e.help("set `edition = \"2018\"` in `Cargo.toml`");
+            e.note("for more on editions, read https://doc.rust-lang.org/edition-guide");
+        };
+
         while self.token != token::CloseDelim(token::Brace) {
             if self.eat(&token::DotDot) {
                 let exp_span = self.prev_token.span;
@@ -1952,7 +1957,11 @@ impl<'a> Parser<'a> {
             let parsed_field = match self.parse_field() {
                 Ok(f) => Some(f),
                 Err(mut e) => {
-                    e.span_label(struct_sp, "while parsing this struct");
+                    if pth == kw::Async {
+                        async_block_err(&mut e, pth.span);
+                    } else {
+                        e.span_label(pth.span, "while parsing this struct");
+                    }
                     e.emit();
 
                     // If the next token is a comma, then try to parse
@@ -1976,15 +1985,19 @@ impl<'a> Parser<'a> {
                     }
                 }
                 Err(mut e) => {
-                    e.span_label(struct_sp, "while parsing this struct");
-                    if let Some(f) = recovery_field {
-                        fields.push(f);
-                        e.span_suggestion(
-                            self.prev_token.span.shrink_to_hi(),
-                            "try adding a comma",
-                            ",".into(),
-                            Applicability::MachineApplicable,
-                        );
+                    if pth == kw::Async {
+                        async_block_err(&mut e, pth.span);
+                    } else {
+                        e.span_label(pth.span, "while parsing this struct");
+                        if let Some(f) = recovery_field {
+                            fields.push(f);
+                            e.span_suggestion(
+                                self.prev_token.span.shrink_to_hi(),
+                                "try adding a comma",
+                                ",".into(),
+                                Applicability::MachineApplicable,
+                            );
+                        }
                     }
                     e.emit();
                     self.recover_stmt_(SemiColonMode::Comma, BlockMode::Ignore);
@@ -1993,9 +2006,10 @@ impl<'a> Parser<'a> {
             }
         }
 
-        let span = lo.to(self.token.span);
+        let span = pth.span.to(self.token.span);
         self.expect(&token::CloseDelim(token::Brace))?;
-        Ok(self.mk_expr(span, ExprKind::Struct(pth, fields, base), attrs))
+        let expr = if recover_async { ExprKind::Err } else { ExprKind::Struct(pth, fields, base) };
+        Ok(self.mk_expr(span, expr, attrs))
     }
 
     /// Use in case of error after field-looking code: `S { foo: () with a }`.
diff --git a/src/librustc_parse/parser/item.rs b/src/librustc_parse/parser/item.rs
index e9f5f2c0dea..7fb814973e2 100644
--- a/src/librustc_parse/parser/item.rs
+++ b/src/librustc_parse/parser/item.rs
@@ -1550,7 +1550,7 @@ impl<'a> Parser<'a> {
         if span.rust_2015() {
             let diag = self.diagnostic();
             struct_span_err!(diag, span, E0670, "`async fn` is not permitted in the 2015 edition")
-                .note("to use `async fn`, switch to Rust 2018")
+                .span_label(span, "to use `async fn`, switch to Rust 2018")
                 .help("set `edition = \"2018\"` in `Cargo.toml`")
                 .note("for more on editions, read https://doc.rust-lang.org/edition-guide")
                 .emit();
diff --git a/src/librustc_parse/parser/stmt.rs b/src/librustc_parse/parser/stmt.rs
index e5d0ab247aa..849193151c3 100644
--- a/src/librustc_parse/parser/stmt.rs
+++ b/src/librustc_parse/parser/stmt.rs
@@ -79,7 +79,7 @@ impl<'a> Parser<'a> {
         }
 
         let expr = if self.check(&token::OpenDelim(token::Brace)) {
-            self.parse_struct_expr(lo, path, AttrVec::new())?
+            self.parse_struct_expr(path, AttrVec::new())?
         } else {
             let hi = self.prev_token.span;
             self.mk_expr(lo.to(hi), ExprKind::Path(None, path), AttrVec::new())
diff --git a/src/librustc_resolve/late/diagnostics.rs b/src/librustc_resolve/late/diagnostics.rs
index f6213189d94..c1a7cf855fa 100644
--- a/src/librustc_resolve/late/diagnostics.rs
+++ b/src/librustc_resolve/late/diagnostics.rs
@@ -151,7 +151,11 @@ impl<'a> LateResolutionVisitor<'a, '_, '_> {
             };
             (
                 format!("cannot find {} `{}` in {}{}", expected, item_str, mod_prefix, mod_str),
-                format!("not found in {}", mod_str),
+                if path_str == "async" && expected.starts_with("struct") {
+                    "`async` blocks are only allowed in the 2018 edition".to_string()
+                } else {
+                    format!("not found in {}", mod_str)
+                },
                 item_span,
                 false,
             )
diff --git a/src/test/ui/async-await/edition-deny-async-fns-2015.stderr b/src/test/ui/async-await/edition-deny-async-fns-2015.stderr
index f3d982801bb..8bffeb2131d 100644
--- a/src/test/ui/async-await/edition-deny-async-fns-2015.stderr
+++ b/src/test/ui/async-await/edition-deny-async-fns-2015.stderr
@@ -2,9 +2,8 @@ error[E0670]: `async fn` is not permitted in the 2015 edition
   --> $DIR/edition-deny-async-fns-2015.rs:3:1
    |
 LL | async fn foo() {}
-   | ^^^^^
+   | ^^^^^ to use `async fn`, switch to Rust 2018
    |
-   = note: to use `async fn`, switch to Rust 2018
    = help: set `edition = "2018"` in `Cargo.toml`
    = note: for more on editions, read https://doc.rust-lang.org/edition-guide
 
@@ -12,9 +11,8 @@ error[E0670]: `async fn` is not permitted in the 2015 edition
   --> $DIR/edition-deny-async-fns-2015.rs:5:12
    |
 LL | fn baz() { async fn foo() {} }
-   |            ^^^^^
+   |            ^^^^^ to use `async fn`, switch to Rust 2018
    |
-   = note: to use `async fn`, switch to Rust 2018
    = help: set `edition = "2018"` in `Cargo.toml`
    = note: for more on editions, read https://doc.rust-lang.org/edition-guide
 
@@ -22,9 +20,8 @@ error[E0670]: `async fn` is not permitted in the 2015 edition
   --> $DIR/edition-deny-async-fns-2015.rs:7:1
    |
 LL | async fn async_baz() {
-   | ^^^^^
+   | ^^^^^ to use `async fn`, switch to Rust 2018
    |
-   = note: to use `async fn`, switch to Rust 2018
    = help: set `edition = "2018"` in `Cargo.toml`
    = note: for more on editions, read https://doc.rust-lang.org/edition-guide
 
@@ -32,9 +29,8 @@ error[E0670]: `async fn` is not permitted in the 2015 edition
   --> $DIR/edition-deny-async-fns-2015.rs:8:5
    |
 LL |     async fn bar() {}
-   |     ^^^^^
+   |     ^^^^^ to use `async fn`, switch to Rust 2018
    |
-   = note: to use `async fn`, switch to Rust 2018
    = help: set `edition = "2018"` in `Cargo.toml`
    = note: for more on editions, read https://doc.rust-lang.org/edition-guide
 
@@ -42,9 +38,8 @@ error[E0670]: `async fn` is not permitted in the 2015 edition
   --> $DIR/edition-deny-async-fns-2015.rs:14:5
    |
 LL |     async fn foo() {}
-   |     ^^^^^
+   |     ^^^^^ to use `async fn`, switch to Rust 2018
    |
-   = note: to use `async fn`, switch to Rust 2018
    = help: set `edition = "2018"` in `Cargo.toml`
    = note: for more on editions, read https://doc.rust-lang.org/edition-guide
 
@@ -52,9 +47,8 @@ error[E0670]: `async fn` is not permitted in the 2015 edition
   --> $DIR/edition-deny-async-fns-2015.rs:18:5
    |
 LL |     async fn foo() {}
-   |     ^^^^^
+   |     ^^^^^ to use `async fn`, switch to Rust 2018
    |
-   = note: to use `async fn`, switch to Rust 2018
    = help: set `edition = "2018"` in `Cargo.toml`
    = note: for more on editions, read https://doc.rust-lang.org/edition-guide
 
@@ -62,9 +56,8 @@ error[E0670]: `async fn` is not permitted in the 2015 edition
   --> $DIR/edition-deny-async-fns-2015.rs:36:9
    |
 LL |         async fn bar() {}
-   |         ^^^^^
+   |         ^^^^^ to use `async fn`, switch to Rust 2018
    |
-   = note: to use `async fn`, switch to Rust 2018
    = help: set `edition = "2018"` in `Cargo.toml`
    = note: for more on editions, read https://doc.rust-lang.org/edition-guide
 
@@ -72,9 +65,8 @@ error[E0670]: `async fn` is not permitted in the 2015 edition
   --> $DIR/edition-deny-async-fns-2015.rs:26:9
    |
 LL |         async fn foo() {}
-   |         ^^^^^
+   |         ^^^^^ to use `async fn`, switch to Rust 2018
    |
-   = note: to use `async fn`, switch to Rust 2018
    = help: set `edition = "2018"` in `Cargo.toml`
    = note: for more on editions, read https://doc.rust-lang.org/edition-guide
 
@@ -82,9 +74,8 @@ error[E0670]: `async fn` is not permitted in the 2015 edition
   --> $DIR/edition-deny-async-fns-2015.rs:31:13
    |
 LL |             async fn bar() {}
-   |             ^^^^^
+   |             ^^^^^ to use `async fn`, switch to Rust 2018
    |
-   = note: to use `async fn`, switch to Rust 2018
    = help: set `edition = "2018"` in `Cargo.toml`
    = note: for more on editions, read https://doc.rust-lang.org/edition-guide
 
diff --git a/src/test/ui/editions/async-block-2015.rs b/src/test/ui/editions/async-block-2015.rs
new file mode 100644
index 00000000000..985606a6f25
--- /dev/null
+++ b/src/test/ui/editions/async-block-2015.rs
@@ -0,0 +1,30 @@
+async fn foo() {
+//~^ ERROR `async fn` is not permitted in the 2015 edition
+//~| NOTE to use `async fn`, switch to Rust 2018
+//~| HELP set `edition = "2018"` in `Cargo.toml`
+//~| NOTE for more on editions, read https://doc.rust-lang.org/edition-guide
+
+    let x = async {};
+    //~^ ERROR cannot find struct, variant or union type `async` in this scope
+    //~| NOTE `async` blocks are only allowed in the 2018 edition
+    let y = async { //~ NOTE `async` blocks are only allowed in the 2018 edition
+        let x = 42;
+        //~^ ERROR expected identifier, found keyword `let`
+        //~| NOTE expected identifier, found keyword
+        //~| HELP set `edition = "2018"` in `Cargo.toml`
+        //~| NOTE for more on editions, read https://doc.rust-lang.org/edition-guide
+        42
+    };
+    let z = async { //~ NOTE `async` blocks are only allowed in the 2018 edition
+        42
+        //~^ ERROR expected identifier, found `42`
+        //~| NOTE expected identifier
+        //~| HELP set `edition = "2018"` in `Cargo.toml`
+        //~| NOTE for more on editions, read https://doc.rust-lang.org/edition-guide
+    };
+    y.await;
+    z.await;
+    x
+}
+
+fn main() {}
diff --git a/src/test/ui/editions/async-block-2015.stderr b/src/test/ui/editions/async-block-2015.stderr
new file mode 100644
index 00000000000..8e5e5d8bfab
--- /dev/null
+++ b/src/test/ui/editions/async-block-2015.stderr
@@ -0,0 +1,41 @@
+error[E0670]: `async fn` is not permitted in the 2015 edition
+  --> $DIR/async-block-2015.rs:1:1
+   |
+LL | async fn foo() {
+   | ^^^^^ to use `async fn`, switch to Rust 2018
+   |
+   = help: set `edition = "2018"` in `Cargo.toml`
+   = note: for more on editions, read https://doc.rust-lang.org/edition-guide
+
+error: expected identifier, found keyword `let`
+  --> $DIR/async-block-2015.rs:11:9
+   |
+LL |     let y = async {
+   |             ----- `async` blocks are only allowed in the 2018 edition
+LL |         let x = 42;
+   |         ^^^ expected identifier, found keyword
+   |
+   = help: set `edition = "2018"` in `Cargo.toml`
+   = note: for more on editions, read https://doc.rust-lang.org/edition-guide
+
+error: expected identifier, found `42`
+  --> $DIR/async-block-2015.rs:19:9
+   |
+LL |     let z = async {
+   |             ----- `async` blocks are only allowed in the 2018 edition
+LL |         42
+   |         ^^ expected identifier
+   |
+   = help: set `edition = "2018"` in `Cargo.toml`
+   = note: for more on editions, read https://doc.rust-lang.org/edition-guide
+
+error[E0422]: cannot find struct, variant or union type `async` in this scope
+  --> $DIR/async-block-2015.rs:7:13
+   |
+LL |     let x = async {};
+   |             ^^^^^ `async` blocks are only allowed in the 2018 edition
+
+error: aborting due to 4 previous errors
+
+Some errors have detailed explanations: E0422, E0670.
+For more information about an error, try `rustc --explain E0422`.