Skip to content

Commit 81c1d7a

Browse files
committed
Auto merge of #76447 - pickfire:async-pub, r=estebank
Detect async visibility wrong order, `async pub` Partially address #76437.
2 parents 146f574 + 21c1574 commit 81c1d7a

16 files changed

+160
-26
lines changed

compiler/rustc_parse/src/parser/item.rs

+37-7
Original file line numberDiff line numberDiff line change
@@ -204,6 +204,7 @@ impl<'a> Parser<'a> {
204204
def: &mut Defaultness,
205205
req_name: ReqName,
206206
) -> PResult<'a, Option<ItemInfo>> {
207+
let def_final = def == &Defaultness::Final;
207208
let mut def = || mem::replace(def, Defaultness::Final);
208209

209210
let info = if self.eat_keyword(kw::Use) {
@@ -226,7 +227,7 @@ impl<'a> Parser<'a> {
226227
}
227228

228229
(Ident::invalid(), ItemKind::Use(tree))
229-
} else if self.check_fn_front_matter() {
230+
} else if self.check_fn_front_matter(def_final) {
230231
// FUNCTION ITEM
231232
let (ident, sig, generics, body) = self.parse_fn(attrs, req_name, lo)?;
232233
(ident, ItemKind::Fn(box FnKind(def(), sig, generics, body)))
@@ -1634,18 +1635,27 @@ impl<'a> Parser<'a> {
16341635
}
16351636

16361637
/// Is the current token the start of an `FnHeader` / not a valid parse?
1637-
pub(super) fn check_fn_front_matter(&mut self) -> bool {
1638+
///
1639+
/// `check_pub` adds additional `pub` to the checks in case users place it
1640+
/// wrongly, can be used to ensure `pub` never comes after `default`.
1641+
pub(super) fn check_fn_front_matter(&mut self, check_pub: bool) -> bool {
16381642
// We use an over-approximation here.
16391643
// `const const`, `fn const` won't parse, but we're not stepping over other syntax either.
1640-
const QUALS: [Symbol; 4] = [kw::Const, kw::Async, kw::Unsafe, kw::Extern];
1644+
// `pub` is added in case users got confused with the ordering like `async pub fn`,
1645+
// only if it wasn't preceeded by `default` as `default pub` is invalid.
1646+
let quals: &[Symbol] = if check_pub {
1647+
&[kw::Pub, kw::Const, kw::Async, kw::Unsafe, kw::Extern]
1648+
} else {
1649+
&[kw::Const, kw::Async, kw::Unsafe, kw::Extern]
1650+
};
16411651
self.check_keyword(kw::Fn) // Definitely an `fn`.
16421652
// `$qual fn` or `$qual $qual`:
1643-
|| QUALS.iter().any(|&kw| self.check_keyword(kw))
1653+
|| quals.iter().any(|&kw| self.check_keyword(kw))
16441654
&& self.look_ahead(1, |t| {
16451655
// `$qual fn`, e.g. `const fn` or `async fn`.
16461656
t.is_keyword(kw::Fn)
16471657
// Two qualifiers `$qual $qual` is enough, e.g. `async unsafe`.
1648-
|| t.is_non_raw_ident_where(|i| QUALS.contains(&i.name)
1658+
|| t.is_non_raw_ident_where(|i| quals.contains(&i.name)
16491659
// Rule out 2015 `const async: T = val`.
16501660
&& i.is_reserved()
16511661
// Rule out unsafe extern block.
@@ -1666,6 +1676,7 @@ impl<'a> Parser<'a> {
16661676
/// FnFrontMatter = FnQual "fn" ;
16671677
/// ```
16681678
pub(super) fn parse_fn_front_matter(&mut self) -> PResult<'a, FnHeader> {
1679+
let sp_start = self.token.span;
16691680
let constness = self.parse_constness();
16701681
let asyncness = self.parse_asyncness();
16711682
let unsafety = self.parse_unsafety();
@@ -1679,8 +1690,27 @@ impl<'a> Parser<'a> {
16791690
// It is possible for `expect_one_of` to recover given the contents of
16801691
// `self.expected_tokens`, therefore, do not use `self.unexpected()` which doesn't
16811692
// account for this.
1682-
if !self.expect_one_of(&[], &[])? {
1683-
unreachable!()
1693+
match self.expect_one_of(&[], &[]) {
1694+
Ok(true) => {}
1695+
Ok(false) => unreachable!(),
1696+
Err(mut err) => {
1697+
// Recover incorrect visibility order such as `async pub`.
1698+
if self.check_keyword(kw::Pub) {
1699+
let sp = sp_start.to(self.prev_token.span);
1700+
if let Ok(snippet) = self.span_to_snippet(sp) {
1701+
let vis = self.parse_visibility(FollowedByType::No)?;
1702+
let vs = pprust::vis_to_string(&vis);
1703+
let vs = vs.trim_end();
1704+
err.span_suggestion(
1705+
sp_start.to(self.prev_token.span),
1706+
&format!("visibility `{}` must come before `{}`", vs, snippet),
1707+
format!("{} {}", vs, snippet),
1708+
Applicability::MachineApplicable,
1709+
);
1710+
}
1711+
}
1712+
return Err(err);
1713+
}
16841714
}
16851715
}
16861716

compiler/rustc_parse/src/parser/ty.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -209,15 +209,15 @@ impl<'a> Parser<'a> {
209209
} else if self.eat_keyword(kw::Underscore) {
210210
// A type to be inferred `_`
211211
TyKind::Infer
212-
} else if self.check_fn_front_matter() {
212+
} else if self.check_fn_front_matter(false) {
213213
// Function pointer type
214214
self.parse_ty_bare_fn(lo, Vec::new(), recover_return_sign)?
215215
} else if self.check_keyword(kw::For) {
216216
// Function pointer type or bound list (trait object type) starting with a poly-trait.
217217
// `for<'lt> [unsafe] [extern "ABI"] fn (&'lt S) -> T`
218218
// `for<'lt> Trait1<'lt> + Trait2 + 'a`
219219
let lifetime_defs = self.parse_late_bound_lifetime_defs()?;
220-
if self.check_fn_front_matter() {
220+
if self.check_fn_front_matter(false) {
221221
self.parse_ty_bare_fn(lo, lifetime_defs, recover_return_sign)?
222222
} else {
223223
let path = self.parse_path(PathStyle::Type)?;
+3-2
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
1+
// ignore-tidy-linelength
2+
13
fn main() {}
24

35
extern "C" {
46
pub pub fn foo();
5-
//~^ ERROR visibility `pub` is not followed by an item
6-
//~| ERROR non-item in item list
7+
//~^ ERROR expected one of `(`, `async`, `const`, `default`, `extern`, `fn`, `pub`, `unsafe`, or `use`, found keyword `pub`
78
}
+10-15
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,16 @@
1-
error: visibility `pub` is not followed by an item
2-
--> $DIR/duplicate-visibility.rs:4:5
3-
|
4-
LL | pub pub fn foo();
5-
| ^^^ the visibility
6-
|
7-
= help: you likely meant to define an item, e.g., `pub fn foo() {}`
8-
9-
error: non-item in item list
10-
--> $DIR/duplicate-visibility.rs:4:9
1+
error: expected one of `(`, `async`, `const`, `default`, `extern`, `fn`, `pub`, `unsafe`, or `use`, found keyword `pub`
2+
--> $DIR/duplicate-visibility.rs:6:9
113
|
124
LL | extern "C" {
13-
| - item list starts here
5+
| - while parsing this item list starting here
146
LL | pub pub fn foo();
15-
| ^^^ non-item starts here
16-
...
7+
| ^^^
8+
| |
9+
| expected one of 9 possible tokens
10+
| help: visibility `pub` must come before `pub pub`: `pub pub pub`
11+
LL |
1712
LL | }
18-
| - item list ends here
13+
| - the item list ends here
1914

20-
error: aborting due to 2 previous errors
15+
error: aborting due to previous error
2116

+7
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
// edition:2018
2+
3+
mod t {
4+
async pub fn t() {}
5+
//~^ ERROR expected one of `extern`, `fn`, or `unsafe`, found keyword `pub`
6+
//~| HELP visibility `pub` must come before `async`
7+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
error: expected one of `extern`, `fn`, or `unsafe`, found keyword `pub`
2+
--> $DIR/issue-76437-async.rs:4:11
3+
|
4+
LL | async pub fn t() {}
5+
| ------^^^
6+
| | |
7+
| | expected one of `extern`, `fn`, or `unsafe`
8+
| help: visibility `pub` must come before `async`: `pub async`
9+
10+
error: aborting due to previous error
11+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
// edition:2018
2+
3+
mod t {
4+
const async unsafe pub fn t() {}
5+
//~^ ERROR expected one of `extern` or `fn`, found keyword `pub`
6+
//~| HELP visibility `pub` must come before `const async unsafe`
7+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
error: expected one of `extern` or `fn`, found keyword `pub`
2+
--> $DIR/issue-76437-const-async-unsafe.rs:4:24
3+
|
4+
LL | const async unsafe pub fn t() {}
5+
| -------------------^^^
6+
| | |
7+
| | expected one of `extern` or `fn`
8+
| help: visibility `pub` must come before `const async unsafe`: `pub const async unsafe`
9+
10+
error: aborting due to previous error
11+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
// edition:2018
2+
3+
mod t {
4+
const async pub fn t() {}
5+
//~^ ERROR expected one of `extern`, `fn`, or `unsafe`, found keyword `pub`
6+
//~| HELP visibility `pub` must come before `const async`
7+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
error: expected one of `extern`, `fn`, or `unsafe`, found keyword `pub`
2+
--> $DIR/issue-76437-const-async.rs:4:17
3+
|
4+
LL | const async pub fn t() {}
5+
| ------------^^^
6+
| | |
7+
| | expected one of `extern`, `fn`, or `unsafe`
8+
| help: visibility `pub` must come before `const async`: `pub const async`
9+
10+
error: aborting due to previous error
11+
+7
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
// edition:2018
2+
3+
mod t {
4+
const pub fn t() {}
5+
//~^ ERROR expected one of `async`, `extern`, `fn`, or `unsafe`, found keyword `pub`
6+
//~| HELP visibility `pub` must come before `const`
7+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
error: expected one of `async`, `extern`, `fn`, or `unsafe`, found keyword `pub`
2+
--> $DIR/issue-76437-const.rs:4:11
3+
|
4+
LL | const pub fn t() {}
5+
| ------^^^
6+
| | |
7+
| | expected one of `async`, `extern`, `fn`, or `unsafe`
8+
| help: visibility `pub` must come before `const`: `pub const`
9+
10+
error: aborting due to previous error
11+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
// edition:2018
2+
3+
mod t {
4+
unsafe pub(crate) fn t() {}
5+
//~^ ERROR expected one of `extern` or `fn`, found keyword `pub`
6+
//~| HELP visibility `pub(crate)` must come before `unsafe`
7+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
error: expected one of `extern` or `fn`, found keyword `pub`
2+
--> $DIR/issue-76437-pub-crate-unsafe.rs:4:12
3+
|
4+
LL | unsafe pub(crate) fn t() {}
5+
| -------^^^-------
6+
| | |
7+
| | expected one of `extern` or `fn`
8+
| help: visibility `pub(crate)` must come before `unsafe`: `pub(crate) unsafe`
9+
10+
error: aborting due to previous error
11+
+7
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
// edition:2018
2+
3+
mod t {
4+
unsafe pub fn t() {}
5+
//~^ ERROR expected one of `extern` or `fn`, found keyword `pub`
6+
//~| HELP visibility `pub` must come before `unsafe`
7+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
error: expected one of `extern` or `fn`, found keyword `pub`
2+
--> $DIR/issue-76437-unsafe.rs:4:12
3+
|
4+
LL | unsafe pub fn t() {}
5+
| -------^^^
6+
| | |
7+
| | expected one of `extern` or `fn`
8+
| help: visibility `pub` must come before `unsafe`: `pub unsafe`
9+
10+
error: aborting due to previous error
11+

0 commit comments

Comments
 (0)