Skip to content

Commit be0b42f

Browse files
committed
Recover from incorrectly ordered/duplicated function keywords
1 parent 54e57e6 commit be0b42f

14 files changed

+136
-11
lines changed

compiler/rustc_parse/src/parser/item.rs

+37-3
Original file line numberDiff line numberDiff line change
@@ -2382,22 +2382,39 @@ impl<'a> Parser<'a> {
23822382
Misplaced(Span),
23832383
}
23842384

2385+
// We may be able to recover
2386+
let mut recover_constness = constness;
2387+
let mut recover_asyncness = asyncness;
2388+
let mut recover_unsafety = unsafety;
23852389
// This will allow the machine fix to directly place the keyword in the correct place or to indicate
23862390
// that the keyword is already present and the second instance should be removed.
23872391
let wrong_kw = if self.check_keyword(kw::Const) {
23882392
match constness {
23892393
Const::Yes(sp) => Some(WrongKw::Duplicated(sp)),
2390-
Const::No => Some(WrongKw::Misplaced(async_start_sp)),
2394+
Const::No => {
2395+
recover_constness = Const::Yes(self.token.span);
2396+
Some(WrongKw::Misplaced(async_start_sp))
2397+
}
23912398
}
23922399
} else if self.check_keyword(kw::Async) {
23932400
match asyncness {
23942401
Async::Yes { span, .. } => Some(WrongKw::Duplicated(span)),
2395-
Async::No => Some(WrongKw::Misplaced(unsafe_start_sp)),
2402+
Async::No => {
2403+
recover_asyncness = Async::Yes {
2404+
span: self.token.span,
2405+
closure_id: DUMMY_NODE_ID,
2406+
return_impl_trait_id: DUMMY_NODE_ID,
2407+
};
2408+
Some(WrongKw::Misplaced(unsafe_start_sp))
2409+
}
23962410
}
23972411
} else if self.check_keyword(kw::Unsafe) {
23982412
match unsafety {
23992413
Unsafe::Yes(sp) => Some(WrongKw::Duplicated(sp)),
2400-
Unsafe::No => Some(WrongKw::Misplaced(ext_start_sp)),
2414+
Unsafe::No => {
2415+
recover_unsafety = Unsafe::Yes(self.token.span);
2416+
Some(WrongKw::Misplaced(ext_start_sp))
2417+
}
24012418
}
24022419
} else {
24032420
None
@@ -2467,6 +2484,23 @@ impl<'a> Parser<'a> {
24672484
}
24682485
}
24692486
}
2487+
2488+
if wrong_kw.is_some()
2489+
&& self.may_recover()
2490+
&& self.look_ahead(1, |tok| tok.is_keyword_case(kw::Fn, case))
2491+
{
2492+
// Advance past the misplaced keyword and `fn`
2493+
self.bump();
2494+
self.bump();
2495+
err.emit();
2496+
return Ok(FnHeader {
2497+
constness: recover_constness,
2498+
unsafety: recover_unsafety,
2499+
asyncness: recover_asyncness,
2500+
ext,
2501+
});
2502+
}
2503+
24702504
return Err(err);
24712505
}
24722506
}

tests/ui/async-await/no-async-const.rs

+1
Original file line numberDiff line numberDiff line change
@@ -3,3 +3,4 @@
33

44
pub async const fn x() {}
55
//~^ ERROR expected one of `extern`, `fn`, or `unsafe`, found keyword `const`
6+
//~| ERROR functions cannot be both `const` and `async`

tests/ui/async-await/no-async-const.stderr

+10-1
Original file line numberDiff line numberDiff line change
@@ -9,5 +9,14 @@ LL | pub async const fn x() {}
99
|
1010
= note: keyword order for functions declaration is `pub`, `default`, `const`, `async`, `unsafe`, `extern`
1111

12-
error: aborting due to previous error
12+
error: functions cannot be both `const` and `async`
13+
--> $DIR/no-async-const.rs:4:5
14+
|
15+
LL | pub async const fn x() {}
16+
| ----^^^^^-^^^^^----------
17+
| | |
18+
| | `const` because of this
19+
| `async` because of this
20+
21+
error: aborting due to 2 previous errors
1322

tests/ui/async-await/no-unsafe-async.rs

+2
Original file line numberDiff line numberDiff line change
@@ -9,3 +9,5 @@ impl S {
99

1010
#[cfg(FALSE)]
1111
unsafe async fn f() {} //~ ERROR expected one of `extern` or `fn`, found keyword `async`
12+
13+
fn main() {}

tests/ui/async-await/no-unsafe-async.stderr

-5
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,11 @@
11
error: expected one of `extern` or `fn`, found keyword `async`
22
--> $DIR/no-unsafe-async.rs:7:12
33
|
4-
LL | impl S {
5-
| - while parsing this item list starting here
6-
LL | #[cfg(FALSE)]
74
LL | unsafe async fn g() {}
85
| -------^^^^^
96
| | |
107
| | expected one of `extern` or `fn`
118
| help: `async` must come before `unsafe`: `async unsafe`
12-
LL | }
13-
| - the item list ends here
149
|
1510
= note: keyword order for functions declaration is `pub`, `default`, `const`, `async`, `unsafe`, `extern`
1611

tests/ui/parser/issues/issue-87217-keyword-order/const-async-const.rs

+5
Original file line numberDiff line numberDiff line change
@@ -7,3 +7,8 @@ const async const fn test() {}
77
//~| NOTE expected one of `extern`, `fn`, or `unsafe`
88
//~| HELP `const` already used earlier, remove this one
99
//~| NOTE `const` first seen here
10+
//~| ERROR functions cannot be both `const` and `async`
11+
//~| NOTE `const` because of this
12+
//~| NOTE `async` because of this
13+
14+
fn main() {}

tests/ui/parser/issues/issue-87217-keyword-order/const-async-const.stderr

+10-1
Original file line numberDiff line numberDiff line change
@@ -13,5 +13,14 @@ note: `const` first seen here
1313
LL | const async const fn test() {}
1414
| ^^^^^
1515

16-
error: aborting due to previous error
16+
error: functions cannot be both `const` and `async`
17+
--> $DIR/const-async-const.rs:5:1
18+
|
19+
LL | const async const fn test() {}
20+
| ^^^^^-^^^^^-------------------
21+
| | |
22+
| | `async` because of this
23+
| `const` because of this
24+
25+
error: aborting due to 2 previous errors
1726

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
// test for #115714
2+
3+
struct Misplaced;
4+
5+
impl Misplaced {
6+
unsafe const fn from_u32(val: u32) {}
7+
//~^ ERROR expected one of `extern` or `fn`
8+
fn oof(self){}
9+
}
10+
11+
struct Duplicated;
12+
13+
impl Duplicated {
14+
unsafe unsafe fn from_u32(val: u32) {}
15+
//~^ ERROR expected one of `extern` or `fn`
16+
fn oof(self){}
17+
}
18+
19+
fn main() {
20+
Misplaced.oof();
21+
Duplicated.oof();
22+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
error: expected one of `extern` or `fn`, found keyword `const`
2+
--> $DIR/recovery.rs:6:12
3+
|
4+
LL | unsafe const fn from_u32(val: u32) {}
5+
| -------^^^^^
6+
| | |
7+
| | expected one of `extern` or `fn`
8+
| help: `const` must come before `unsafe`: `const unsafe`
9+
|
10+
= note: keyword order for functions declaration is `pub`, `default`, `const`, `async`, `unsafe`, `extern`
11+
12+
error: expected one of `extern` or `fn`, found keyword `unsafe`
13+
--> $DIR/recovery.rs:14:12
14+
|
15+
LL | unsafe unsafe fn from_u32(val: u32) {}
16+
| ^^^^^^
17+
| |
18+
| expected one of `extern` or `fn`
19+
| help: `unsafe` already used earlier, remove this one
20+
|
21+
note: `unsafe` first seen here
22+
--> $DIR/recovery.rs:14:5
23+
|
24+
LL | unsafe unsafe fn from_u32(val: u32) {}
25+
| ^^^^^^
26+
27+
error: aborting due to 2 previous errors
28+

tests/ui/parser/issues/issue-87217-keyword-order/several-kw-jump.rs

+5
Original file line numberDiff line numberDiff line change
@@ -12,3 +12,8 @@ async unsafe const fn test() {}
1212
//~| HELP `const` must come before `async unsafe`
1313
//~| SUGGESTION const async unsafe
1414
//~| NOTE keyword order for functions declaration is `pub`, `default`, `const`, `async`, `unsafe`, `extern`
15+
//~| ERROR functions cannot be both `const` and `async`
16+
//~| NOTE `const` because of this
17+
//~| NOTE `async` because of this
18+
19+
fn main() {}

tests/ui/parser/issues/issue-87217-keyword-order/several-kw-jump.stderr

+10-1
Original file line numberDiff line numberDiff line change
@@ -9,5 +9,14 @@ LL | async unsafe const fn test() {}
99
|
1010
= note: keyword order for functions declaration is `pub`, `default`, `const`, `async`, `unsafe`, `extern`
1111

12-
error: aborting due to previous error
12+
error: functions cannot be both `const` and `async`
13+
--> $DIR/several-kw-jump.rs:9:1
14+
|
15+
LL | async unsafe const fn test() {}
16+
| ^^^^^--------^^^^^-------------
17+
| | |
18+
| | `const` because of this
19+
| `async` because of this
20+
21+
error: aborting due to 2 previous errors
1322

tests/ui/parser/issues/issue-87217-keyword-order/wrong-async.rs

+2
Original file line numberDiff line numberDiff line change
@@ -12,3 +12,5 @@ unsafe async fn test() {}
1212
//~| HELP `async` must come before `unsafe`
1313
//~| SUGGESTION async unsafe
1414
//~| NOTE keyword order for functions declaration is `pub`, `default`, `const`, `async`, `unsafe`, `extern`
15+
16+
fn main() {}

tests/ui/parser/issues/issue-87217-keyword-order/wrong-const.rs

+2
Original file line numberDiff line numberDiff line change
@@ -12,3 +12,5 @@ unsafe const fn test() {}
1212
//~| HELP `const` must come before `unsafe`
1313
//~| SUGGESTION const unsafe
1414
//~| NOTE keyword order for functions declaration is `pub`, `default`, `const`, `async`, `unsafe`, `extern`
15+
16+
fn main() {}

tests/ui/parser/issues/issue-87217-keyword-order/wrong-unsafe.rs

+2
Original file line numberDiff line numberDiff line change
@@ -12,3 +12,5 @@ extern unsafe fn test() {}
1212
//~| HELP `unsafe` must come before `extern`
1313
//~| SUGGESTION unsafe extern
1414
//~| NOTE keyword order for functions declaration is `pub`, `default`, `const`, `async`, `unsafe`, `extern`
15+
16+
fn main() {}

0 commit comments

Comments
 (0)