Skip to content

Commit 931f099

Browse files
authored
Rollup merge of rust-lang#71783 - estebank:async-block-2015, r=tmandry
Detect errors caused by `async` block in 2015 edition Fix rust-lang#67204.
2 parents 29457dd + 3cf5569 commit 931f099

File tree

7 files changed

+121
-41
lines changed

7 files changed

+121
-41
lines changed

src/librustc_parse/parser/expr.rs

+34-20
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ use rustc_ast::util::classify;
1313
use rustc_ast::util::literal::LitError;
1414
use rustc_ast::util::parser::{prec_let_scrutinee_needs_par, AssocOp, Fixity};
1515
use rustc_ast_pretty::pprust;
16-
use rustc_errors::{Applicability, PResult};
16+
use rustc_errors::{Applicability, DiagnosticBuilder, PResult};
1717
use rustc_span::source_map::{self, Span, Spanned};
1818
use rustc_span::symbol::{kw, sym, Symbol};
1919
use std::mem;
@@ -1068,8 +1068,8 @@ impl<'a> Parser<'a> {
10681068
}
10691069

10701070
fn parse_path_start_expr(&mut self, attrs: AttrVec) -> PResult<'a, P<Expr>> {
1071-
let lo = self.token.span;
10721071
let path = self.parse_path(PathStyle::Expr)?;
1072+
let lo = path.span;
10731073

10741074
// `!`, as an operator, is prefix, so we know this isn't that.
10751075
let (hi, kind) = if self.eat(&token::Not) {
@@ -1081,7 +1081,7 @@ impl<'a> Parser<'a> {
10811081
};
10821082
(self.prev_token.span, ExprKind::MacCall(mac))
10831083
} else if self.check(&token::OpenDelim(token::Brace)) {
1084-
if let Some(expr) = self.maybe_parse_struct_expr(lo, &path, &attrs) {
1084+
if let Some(expr) = self.maybe_parse_struct_expr(&path, &attrs) {
10851085
return expr;
10861086
} else {
10871087
(path.span, ExprKind::Path(None, path))
@@ -1895,16 +1895,15 @@ impl<'a> Parser<'a> {
18951895

18961896
fn maybe_parse_struct_expr(
18971897
&mut self,
1898-
lo: Span,
18991898
path: &ast::Path,
19001899
attrs: &AttrVec,
19011900
) -> Option<PResult<'a, P<Expr>>> {
19021901
let struct_allowed = !self.restrictions.contains(Restrictions::NO_STRUCT_LITERAL);
19031902
if struct_allowed || self.is_certainly_not_a_block() {
19041903
// This is a struct literal, but we don't can't accept them here.
1905-
let expr = self.parse_struct_expr(lo, path.clone(), attrs.clone());
1904+
let expr = self.parse_struct_expr(path.clone(), attrs.clone());
19061905
if let (Ok(expr), false) = (&expr, struct_allowed) {
1907-
self.error_struct_lit_not_allowed_here(lo, expr.span);
1906+
self.error_struct_lit_not_allowed_here(path.span, expr.span);
19081907
}
19091908
return Some(expr);
19101909
}
@@ -1923,17 +1922,23 @@ impl<'a> Parser<'a> {
19231922

19241923
pub(super) fn parse_struct_expr(
19251924
&mut self,
1926-
lo: Span,
19271925
pth: ast::Path,
19281926
mut attrs: AttrVec,
19291927
) -> PResult<'a, P<Expr>> {
1930-
let struct_sp = lo.to(self.prev_token.span);
19311928
self.bump();
19321929
let mut fields = Vec::new();
19331930
let mut base = None;
1931+
let mut recover_async = false;
19341932

19351933
attrs.extend(self.parse_inner_attributes()?);
19361934

1935+
let mut async_block_err = |e: &mut DiagnosticBuilder<'_>, span: Span| {
1936+
recover_async = true;
1937+
e.span_label(span, "`async` blocks are only allowed in the 2018 edition");
1938+
e.help("set `edition = \"2018\"` in `Cargo.toml`");
1939+
e.note("for more on editions, read https://doc.rust-lang.org/edition-guide");
1940+
};
1941+
19371942
while self.token != token::CloseDelim(token::Brace) {
19381943
if self.eat(&token::DotDot) {
19391944
let exp_span = self.prev_token.span;
@@ -1952,7 +1957,11 @@ impl<'a> Parser<'a> {
19521957
let parsed_field = match self.parse_field() {
19531958
Ok(f) => Some(f),
19541959
Err(mut e) => {
1955-
e.span_label(struct_sp, "while parsing this struct");
1960+
if pth == kw::Async {
1961+
async_block_err(&mut e, pth.span);
1962+
} else {
1963+
e.span_label(pth.span, "while parsing this struct");
1964+
}
19561965
e.emit();
19571966

19581967
// If the next token is a comma, then try to parse
@@ -1976,15 +1985,19 @@ impl<'a> Parser<'a> {
19761985
}
19771986
}
19781987
Err(mut e) => {
1979-
e.span_label(struct_sp, "while parsing this struct");
1980-
if let Some(f) = recovery_field {
1981-
fields.push(f);
1982-
e.span_suggestion(
1983-
self.prev_token.span.shrink_to_hi(),
1984-
"try adding a comma",
1985-
",".into(),
1986-
Applicability::MachineApplicable,
1987-
);
1988+
if pth == kw::Async {
1989+
async_block_err(&mut e, pth.span);
1990+
} else {
1991+
e.span_label(pth.span, "while parsing this struct");
1992+
if let Some(f) = recovery_field {
1993+
fields.push(f);
1994+
e.span_suggestion(
1995+
self.prev_token.span.shrink_to_hi(),
1996+
"try adding a comma",
1997+
",".into(),
1998+
Applicability::MachineApplicable,
1999+
);
2000+
}
19882001
}
19892002
e.emit();
19902003
self.recover_stmt_(SemiColonMode::Comma, BlockMode::Ignore);
@@ -1993,9 +2006,10 @@ impl<'a> Parser<'a> {
19932006
}
19942007
}
19952008

1996-
let span = lo.to(self.token.span);
2009+
let span = pth.span.to(self.token.span);
19972010
self.expect(&token::CloseDelim(token::Brace))?;
1998-
Ok(self.mk_expr(span, ExprKind::Struct(pth, fields, base), attrs))
2011+
let expr = if recover_async { ExprKind::Err } else { ExprKind::Struct(pth, fields, base) };
2012+
Ok(self.mk_expr(span, expr, attrs))
19992013
}
20002014

20012015
/// Use in case of error after field-looking code: `S { foo: () with a }`.

src/librustc_parse/parser/item.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -1550,7 +1550,7 @@ impl<'a> Parser<'a> {
15501550
if span.rust_2015() {
15511551
let diag = self.diagnostic();
15521552
struct_span_err!(diag, span, E0670, "`async fn` is not permitted in the 2015 edition")
1553-
.note("to use `async fn`, switch to Rust 2018")
1553+
.span_label(span, "to use `async fn`, switch to Rust 2018")
15541554
.help("set `edition = \"2018\"` in `Cargo.toml`")
15551555
.note("for more on editions, read https://doc.rust-lang.org/edition-guide")
15561556
.emit();

src/librustc_parse/parser/stmt.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,7 @@ impl<'a> Parser<'a> {
7979
}
8080

8181
let expr = if self.check(&token::OpenDelim(token::Brace)) {
82-
self.parse_struct_expr(lo, path, AttrVec::new())?
82+
self.parse_struct_expr(path, AttrVec::new())?
8383
} else {
8484
let hi = self.prev_token.span;
8585
self.mk_expr(lo.to(hi), ExprKind::Path(None, path), AttrVec::new())

src/librustc_resolve/late/diagnostics.rs

+5-1
Original file line numberDiff line numberDiff line change
@@ -151,7 +151,11 @@ impl<'a> LateResolutionVisitor<'a, '_, '_> {
151151
};
152152
(
153153
format!("cannot find {} `{}` in {}{}", expected, item_str, mod_prefix, mod_str),
154-
format!("not found in {}", mod_str),
154+
if path_str == "async" && expected.starts_with("struct") {
155+
"`async` blocks are only allowed in the 2018 edition".to_string()
156+
} else {
157+
format!("not found in {}", mod_str)
158+
},
155159
item_span,
156160
false,
157161
)

src/test/ui/async-await/edition-deny-async-fns-2015.stderr

+9-18
Original file line numberDiff line numberDiff line change
@@ -2,89 +2,80 @@ error[E0670]: `async fn` is not permitted in the 2015 edition
22
--> $DIR/edition-deny-async-fns-2015.rs:3:1
33
|
44
LL | async fn foo() {}
5-
| ^^^^^
5+
| ^^^^^ to use `async fn`, switch to Rust 2018
66
|
7-
= note: to use `async fn`, switch to Rust 2018
87
= help: set `edition = "2018"` in `Cargo.toml`
98
= note: for more on editions, read https://doc.rust-lang.org/edition-guide
109

1110
error[E0670]: `async fn` is not permitted in the 2015 edition
1211
--> $DIR/edition-deny-async-fns-2015.rs:5:12
1312
|
1413
LL | fn baz() { async fn foo() {} }
15-
| ^^^^^
14+
| ^^^^^ to use `async fn`, switch to Rust 2018
1615
|
17-
= note: to use `async fn`, switch to Rust 2018
1816
= help: set `edition = "2018"` in `Cargo.toml`
1917
= note: for more on editions, read https://doc.rust-lang.org/edition-guide
2018

2119
error[E0670]: `async fn` is not permitted in the 2015 edition
2220
--> $DIR/edition-deny-async-fns-2015.rs:7:1
2321
|
2422
LL | async fn async_baz() {
25-
| ^^^^^
23+
| ^^^^^ to use `async fn`, switch to Rust 2018
2624
|
27-
= note: to use `async fn`, switch to Rust 2018
2825
= help: set `edition = "2018"` in `Cargo.toml`
2926
= note: for more on editions, read https://doc.rust-lang.org/edition-guide
3027

3128
error[E0670]: `async fn` is not permitted in the 2015 edition
3229
--> $DIR/edition-deny-async-fns-2015.rs:8:5
3330
|
3431
LL | async fn bar() {}
35-
| ^^^^^
32+
| ^^^^^ to use `async fn`, switch to Rust 2018
3633
|
37-
= note: to use `async fn`, switch to Rust 2018
3834
= help: set `edition = "2018"` in `Cargo.toml`
3935
= note: for more on editions, read https://doc.rust-lang.org/edition-guide
4036

4137
error[E0670]: `async fn` is not permitted in the 2015 edition
4238
--> $DIR/edition-deny-async-fns-2015.rs:14:5
4339
|
4440
LL | async fn foo() {}
45-
| ^^^^^
41+
| ^^^^^ to use `async fn`, switch to Rust 2018
4642
|
47-
= note: to use `async fn`, switch to Rust 2018
4843
= help: set `edition = "2018"` in `Cargo.toml`
4944
= note: for more on editions, read https://doc.rust-lang.org/edition-guide
5045

5146
error[E0670]: `async fn` is not permitted in the 2015 edition
5247
--> $DIR/edition-deny-async-fns-2015.rs:18:5
5348
|
5449
LL | async fn foo() {}
55-
| ^^^^^
50+
| ^^^^^ to use `async fn`, switch to Rust 2018
5651
|
57-
= note: to use `async fn`, switch to Rust 2018
5852
= help: set `edition = "2018"` in `Cargo.toml`
5953
= note: for more on editions, read https://doc.rust-lang.org/edition-guide
6054

6155
error[E0670]: `async fn` is not permitted in the 2015 edition
6256
--> $DIR/edition-deny-async-fns-2015.rs:36:9
6357
|
6458
LL | async fn bar() {}
65-
| ^^^^^
59+
| ^^^^^ to use `async fn`, switch to Rust 2018
6660
|
67-
= note: to use `async fn`, switch to Rust 2018
6861
= help: set `edition = "2018"` in `Cargo.toml`
6962
= note: for more on editions, read https://doc.rust-lang.org/edition-guide
7063

7164
error[E0670]: `async fn` is not permitted in the 2015 edition
7265
--> $DIR/edition-deny-async-fns-2015.rs:26:9
7366
|
7467
LL | async fn foo() {}
75-
| ^^^^^
68+
| ^^^^^ to use `async fn`, switch to Rust 2018
7669
|
77-
= note: to use `async fn`, switch to Rust 2018
7870
= help: set `edition = "2018"` in `Cargo.toml`
7971
= note: for more on editions, read https://doc.rust-lang.org/edition-guide
8072

8173
error[E0670]: `async fn` is not permitted in the 2015 edition
8274
--> $DIR/edition-deny-async-fns-2015.rs:31:13
8375
|
8476
LL | async fn bar() {}
85-
| ^^^^^
77+
| ^^^^^ to use `async fn`, switch to Rust 2018
8678
|
87-
= note: to use `async fn`, switch to Rust 2018
8879
= help: set `edition = "2018"` in `Cargo.toml`
8980
= note: for more on editions, read https://doc.rust-lang.org/edition-guide
9081

+30
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
async fn foo() {
2+
//~^ ERROR `async fn` is not permitted in the 2015 edition
3+
//~| NOTE to use `async fn`, switch to Rust 2018
4+
//~| HELP set `edition = "2018"` in `Cargo.toml`
5+
//~| NOTE for more on editions, read https://doc.rust-lang.org/edition-guide
6+
7+
let x = async {};
8+
//~^ ERROR cannot find struct, variant or union type `async` in this scope
9+
//~| NOTE `async` blocks are only allowed in the 2018 edition
10+
let y = async { //~ NOTE `async` blocks are only allowed in the 2018 edition
11+
let x = 42;
12+
//~^ ERROR expected identifier, found keyword `let`
13+
//~| NOTE expected identifier, found keyword
14+
//~| HELP set `edition = "2018"` in `Cargo.toml`
15+
//~| NOTE for more on editions, read https://doc.rust-lang.org/edition-guide
16+
42
17+
};
18+
let z = async { //~ NOTE `async` blocks are only allowed in the 2018 edition
19+
42
20+
//~^ ERROR expected identifier, found `42`
21+
//~| NOTE expected identifier
22+
//~| HELP set `edition = "2018"` in `Cargo.toml`
23+
//~| NOTE for more on editions, read https://doc.rust-lang.org/edition-guide
24+
};
25+
y.await;
26+
z.await;
27+
x
28+
}
29+
30+
fn main() {}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
error[E0670]: `async fn` is not permitted in the 2015 edition
2+
--> $DIR/async-block-2015.rs:1:1
3+
|
4+
LL | async fn foo() {
5+
| ^^^^^ to use `async fn`, switch to Rust 2018
6+
|
7+
= help: set `edition = "2018"` in `Cargo.toml`
8+
= note: for more on editions, read https://doc.rust-lang.org/edition-guide
9+
10+
error: expected identifier, found keyword `let`
11+
--> $DIR/async-block-2015.rs:11:9
12+
|
13+
LL | let y = async {
14+
| ----- `async` blocks are only allowed in the 2018 edition
15+
LL | let x = 42;
16+
| ^^^ expected identifier, found keyword
17+
|
18+
= help: set `edition = "2018"` in `Cargo.toml`
19+
= note: for more on editions, read https://doc.rust-lang.org/edition-guide
20+
21+
error: expected identifier, found `42`
22+
--> $DIR/async-block-2015.rs:19:9
23+
|
24+
LL | let z = async {
25+
| ----- `async` blocks are only allowed in the 2018 edition
26+
LL | 42
27+
| ^^ expected identifier
28+
|
29+
= help: set `edition = "2018"` in `Cargo.toml`
30+
= note: for more on editions, read https://doc.rust-lang.org/edition-guide
31+
32+
error[E0422]: cannot find struct, variant or union type `async` in this scope
33+
--> $DIR/async-block-2015.rs:7:13
34+
|
35+
LL | let x = async {};
36+
| ^^^^^ `async` blocks are only allowed in the 2018 edition
37+
38+
error: aborting due to 4 previous errors
39+
40+
Some errors have detailed explanations: E0422, E0670.
41+
For more information about an error, try `rustc --explain E0422`.

0 commit comments

Comments
 (0)