Detect errors caused by async
block in 2015 edition
This commit is contained in:
parent
6318d24ad8
commit
3cf556939e
7 changed files with 121 additions and 41 deletions
|
@ -13,7 +13,7 @@ use rustc_ast::util::classify;
|
||||||
use rustc_ast::util::literal::LitError;
|
use rustc_ast::util::literal::LitError;
|
||||||
use rustc_ast::util::parser::{prec_let_scrutinee_needs_par, AssocOp, Fixity};
|
use rustc_ast::util::parser::{prec_let_scrutinee_needs_par, AssocOp, Fixity};
|
||||||
use rustc_ast_pretty::pprust;
|
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::source_map::{self, Span, Spanned};
|
||||||
use rustc_span::symbol::{kw, sym, Symbol};
|
use rustc_span::symbol::{kw, sym, Symbol};
|
||||||
use std::mem;
|
use std::mem;
|
||||||
|
@ -1068,8 +1068,8 @@ impl<'a> Parser<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_path_start_expr(&mut self, attrs: AttrVec) -> PResult<'a, P<Expr>> {
|
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 path = self.parse_path(PathStyle::Expr)?;
|
||||||
|
let lo = path.span;
|
||||||
|
|
||||||
// `!`, as an operator, is prefix, so we know this isn't that.
|
// `!`, as an operator, is prefix, so we know this isn't that.
|
||||||
let (hi, kind) = if self.eat(&token::Not) {
|
let (hi, kind) = if self.eat(&token::Not) {
|
||||||
|
@ -1081,7 +1081,7 @@ impl<'a> Parser<'a> {
|
||||||
};
|
};
|
||||||
(self.prev_token.span, ExprKind::MacCall(mac))
|
(self.prev_token.span, ExprKind::MacCall(mac))
|
||||||
} else if self.check(&token::OpenDelim(token::Brace)) {
|
} 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;
|
return expr;
|
||||||
} else {
|
} else {
|
||||||
(path.span, ExprKind::Path(None, path))
|
(path.span, ExprKind::Path(None, path))
|
||||||
|
@ -1895,16 +1895,15 @@ impl<'a> Parser<'a> {
|
||||||
|
|
||||||
fn maybe_parse_struct_expr(
|
fn maybe_parse_struct_expr(
|
||||||
&mut self,
|
&mut self,
|
||||||
lo: Span,
|
|
||||||
path: &ast::Path,
|
path: &ast::Path,
|
||||||
attrs: &AttrVec,
|
attrs: &AttrVec,
|
||||||
) -> Option<PResult<'a, P<Expr>>> {
|
) -> Option<PResult<'a, P<Expr>>> {
|
||||||
let struct_allowed = !self.restrictions.contains(Restrictions::NO_STRUCT_LITERAL);
|
let struct_allowed = !self.restrictions.contains(Restrictions::NO_STRUCT_LITERAL);
|
||||||
if struct_allowed || self.is_certainly_not_a_block() {
|
if struct_allowed || self.is_certainly_not_a_block() {
|
||||||
// This is a struct literal, but we don't can't accept them here.
|
// 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) {
|
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);
|
return Some(expr);
|
||||||
}
|
}
|
||||||
|
@ -1923,17 +1922,23 @@ impl<'a> Parser<'a> {
|
||||||
|
|
||||||
pub(super) fn parse_struct_expr(
|
pub(super) fn parse_struct_expr(
|
||||||
&mut self,
|
&mut self,
|
||||||
lo: Span,
|
|
||||||
pth: ast::Path,
|
pth: ast::Path,
|
||||||
mut attrs: AttrVec,
|
mut attrs: AttrVec,
|
||||||
) -> PResult<'a, P<Expr>> {
|
) -> PResult<'a, P<Expr>> {
|
||||||
let struct_sp = lo.to(self.prev_token.span);
|
|
||||||
self.bump();
|
self.bump();
|
||||||
let mut fields = Vec::new();
|
let mut fields = Vec::new();
|
||||||
let mut base = None;
|
let mut base = None;
|
||||||
|
let mut recover_async = false;
|
||||||
|
|
||||||
attrs.extend(self.parse_inner_attributes()?);
|
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) {
|
while self.token != token::CloseDelim(token::Brace) {
|
||||||
if self.eat(&token::DotDot) {
|
if self.eat(&token::DotDot) {
|
||||||
let exp_span = self.prev_token.span;
|
let exp_span = self.prev_token.span;
|
||||||
|
@ -1952,7 +1957,11 @@ impl<'a> Parser<'a> {
|
||||||
let parsed_field = match self.parse_field() {
|
let parsed_field = match self.parse_field() {
|
||||||
Ok(f) => Some(f),
|
Ok(f) => Some(f),
|
||||||
Err(mut e) => {
|
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();
|
e.emit();
|
||||||
|
|
||||||
// If the next token is a comma, then try to parse
|
// If the next token is a comma, then try to parse
|
||||||
|
@ -1976,15 +1985,19 @@ impl<'a> Parser<'a> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Err(mut e) => {
|
Err(mut e) => {
|
||||||
e.span_label(struct_sp, "while parsing this struct");
|
if pth == kw::Async {
|
||||||
if let Some(f) = recovery_field {
|
async_block_err(&mut e, pth.span);
|
||||||
fields.push(f);
|
} else {
|
||||||
e.span_suggestion(
|
e.span_label(pth.span, "while parsing this struct");
|
||||||
self.prev_token.span.shrink_to_hi(),
|
if let Some(f) = recovery_field {
|
||||||
"try adding a comma",
|
fields.push(f);
|
||||||
",".into(),
|
e.span_suggestion(
|
||||||
Applicability::MachineApplicable,
|
self.prev_token.span.shrink_to_hi(),
|
||||||
);
|
"try adding a comma",
|
||||||
|
",".into(),
|
||||||
|
Applicability::MachineApplicable,
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
e.emit();
|
e.emit();
|
||||||
self.recover_stmt_(SemiColonMode::Comma, BlockMode::Ignore);
|
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))?;
|
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 }`.
|
/// Use in case of error after field-looking code: `S { foo: () with a }`.
|
||||||
|
|
|
@ -1550,7 +1550,7 @@ impl<'a> Parser<'a> {
|
||||||
if span.rust_2015() {
|
if span.rust_2015() {
|
||||||
let diag = self.diagnostic();
|
let diag = self.diagnostic();
|
||||||
struct_span_err!(diag, span, E0670, "`async fn` is not permitted in the 2015 edition")
|
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`")
|
.help("set `edition = \"2018\"` in `Cargo.toml`")
|
||||||
.note("for more on editions, read https://doc.rust-lang.org/edition-guide")
|
.note("for more on editions, read https://doc.rust-lang.org/edition-guide")
|
||||||
.emit();
|
.emit();
|
||||||
|
|
|
@ -79,7 +79,7 @@ impl<'a> Parser<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
let expr = if self.check(&token::OpenDelim(token::Brace)) {
|
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 {
|
} else {
|
||||||
let hi = self.prev_token.span;
|
let hi = self.prev_token.span;
|
||||||
self.mk_expr(lo.to(hi), ExprKind::Path(None, path), AttrVec::new())
|
self.mk_expr(lo.to(hi), ExprKind::Path(None, path), AttrVec::new())
|
||||||
|
|
|
@ -151,7 +151,11 @@ impl<'a> LateResolutionVisitor<'a, '_, '_> {
|
||||||
};
|
};
|
||||||
(
|
(
|
||||||
format!("cannot find {} `{}` in {}{}", expected, item_str, mod_prefix, mod_str),
|
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,
|
item_span,
|
||||||
false,
|
false,
|
||||||
)
|
)
|
||||||
|
|
|
@ -2,9 +2,8 @@ error[E0670]: `async fn` is not permitted in the 2015 edition
|
||||||
--> $DIR/edition-deny-async-fns-2015.rs:3:1
|
--> $DIR/edition-deny-async-fns-2015.rs:3:1
|
||||||
|
|
|
|
||||||
LL | async fn foo() {}
|
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`
|
= help: set `edition = "2018"` in `Cargo.toml`
|
||||||
= note: for more on editions, read https://doc.rust-lang.org/edition-guide
|
= 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
|
--> $DIR/edition-deny-async-fns-2015.rs:5:12
|
||||||
|
|
|
|
||||||
LL | fn baz() { async fn foo() {} }
|
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`
|
= help: set `edition = "2018"` in `Cargo.toml`
|
||||||
= note: for more on editions, read https://doc.rust-lang.org/edition-guide
|
= 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
|
--> $DIR/edition-deny-async-fns-2015.rs:7:1
|
||||||
|
|
|
|
||||||
LL | async fn async_baz() {
|
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`
|
= help: set `edition = "2018"` in `Cargo.toml`
|
||||||
= note: for more on editions, read https://doc.rust-lang.org/edition-guide
|
= 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
|
--> $DIR/edition-deny-async-fns-2015.rs:8:5
|
||||||
|
|
|
|
||||||
LL | async fn bar() {}
|
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`
|
= help: set `edition = "2018"` in `Cargo.toml`
|
||||||
= note: for more on editions, read https://doc.rust-lang.org/edition-guide
|
= 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
|
--> $DIR/edition-deny-async-fns-2015.rs:14:5
|
||||||
|
|
|
|
||||||
LL | async fn foo() {}
|
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`
|
= help: set `edition = "2018"` in `Cargo.toml`
|
||||||
= note: for more on editions, read https://doc.rust-lang.org/edition-guide
|
= 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
|
--> $DIR/edition-deny-async-fns-2015.rs:18:5
|
||||||
|
|
|
|
||||||
LL | async fn foo() {}
|
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`
|
= help: set `edition = "2018"` in `Cargo.toml`
|
||||||
= note: for more on editions, read https://doc.rust-lang.org/edition-guide
|
= 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
|
--> $DIR/edition-deny-async-fns-2015.rs:36:9
|
||||||
|
|
|
|
||||||
LL | async fn bar() {}
|
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`
|
= help: set `edition = "2018"` in `Cargo.toml`
|
||||||
= note: for more on editions, read https://doc.rust-lang.org/edition-guide
|
= 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
|
--> $DIR/edition-deny-async-fns-2015.rs:26:9
|
||||||
|
|
|
|
||||||
LL | async fn foo() {}
|
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`
|
= help: set `edition = "2018"` in `Cargo.toml`
|
||||||
= note: for more on editions, read https://doc.rust-lang.org/edition-guide
|
= 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
|
--> $DIR/edition-deny-async-fns-2015.rs:31:13
|
||||||
|
|
|
|
||||||
LL | async fn bar() {}
|
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`
|
= help: set `edition = "2018"` in `Cargo.toml`
|
||||||
= note: for more on editions, read https://doc.rust-lang.org/edition-guide
|
= note: for more on editions, read https://doc.rust-lang.org/edition-guide
|
||||||
|
|
||||||
|
|
30
src/test/ui/editions/async-block-2015.rs
Normal file
30
src/test/ui/editions/async-block-2015.rs
Normal file
|
@ -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() {}
|
41
src/test/ui/editions/async-block-2015.stderr
Normal file
41
src/test/ui/editions/async-block-2015.stderr
Normal file
|
@ -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`.
|
Loading…
Add table
Add a link
Reference in a new issue