Skip to content

Commit 21c1574

Browse files
committed
Add pub as optional check_front_matter
async-pub check created a regression for default
1 parent c44a5fe commit 21c1574

File tree

5 files changed

+39
-25
lines changed

5 files changed

+39
-25
lines changed

compiler/rustc_parse/src/parser/item.rs

+15-6
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)))
@@ -1636,19 +1637,27 @@ impl<'a> Parser<'a> {
16361637
}
16371638

16381639
/// Is the current token the start of an `FnHeader` / not a valid parse?
1639-
pub(super) fn check_fn_front_matter(&mut self) -> bool {
1640+
///
1641+
/// `check_pub` adds additional `pub` to the checks in case users place it
1642+
/// wrongly, can be used to ensure `pub` never comes after `default`.
1643+
pub(super) fn check_fn_front_matter(&mut self, check_pub: bool) -> bool {
16401644
// We use an over-approximation here.
16411645
// `const const`, `fn const` won't parse, but we're not stepping over other syntax either.
1642-
// `pub` is added in case users got confused with the ordering like `async pub fn`.
1643-
const QUALS: [Symbol; 5] = [kw::Pub, kw::Const, kw::Async, kw::Unsafe, kw::Extern];
1646+
// `pub` is added in case users got confused with the ordering like `async pub fn`,
1647+
// only if it wasn't preceeded by `default` as `default pub` is invalid.
1648+
let quals: &[Symbol] = if check_pub {
1649+
&[kw::Pub, kw::Const, kw::Async, kw::Unsafe, kw::Extern]
1650+
} else {
1651+
&[kw::Const, kw::Async, kw::Unsafe, kw::Extern]
1652+
};
16441653
self.check_keyword(kw::Fn) // Definitely an `fn`.
16451654
// `$qual fn` or `$qual $qual`:
1646-
|| QUALS.iter().any(|&kw| self.check_keyword(kw))
1655+
|| quals.iter().any(|&kw| self.check_keyword(kw))
16471656
&& self.look_ahead(1, |t| {
16481657
// `$qual fn`, e.g. `const fn` or `async fn`.
16491658
t.is_keyword(kw::Fn)
16501659
// Two qualifiers `$qual $qual` is enough, e.g. `async unsafe`.
1651-
|| t.is_non_raw_ident_where(|i| QUALS.contains(&i.name)
1660+
|| t.is_non_raw_ident_where(|i| quals.contains(&i.name)
16521661
// Rule out 2015 `const async: T = val`.
16531662
&& i.is_reserved()
16541663
// Rule out unsafe extern block.

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)?;

src/test/ui/parser/default.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
// ignore-tidy-linelength
21
// Test successful and unsuccessful parsing of the `default` contextual keyword
32

43
#![feature(specialization)]
@@ -22,7 +21,8 @@ impl Foo for u16 {
2221

2322
impl Foo for u32 { //~ ERROR not all trait items implemented, missing: `foo`
2423
default pub fn foo<T: Default>() -> T { T::default() }
25-
//~^ ERROR expected one of `async`, `const`, `extern`, `fn`, `pub`, `unsafe`, or `use`, found keyword `pub`
24+
//~^ ERROR `default` is not followed by an item
25+
//~| ERROR non-item in item list
2626
}
2727

2828
fn main() {}

src/test/ui/parser/default.stderr

+18-13
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,30 @@
1-
error: expected one of `async`, `const`, `extern`, `fn`, `pub`, `unsafe`, or `use`, found keyword `pub`
2-
--> $DIR/default.rs:24:13
1+
error: `default` is not followed by an item
2+
--> $DIR/default.rs:23:5
3+
|
4+
LL | default pub fn foo<T: Default>() -> T { T::default() }
5+
| ^^^^^^^ the `default` qualifier
6+
|
7+
= note: only `fn`, `const`, `type`, or `impl` items may be prefixed by `default`
8+
9+
error: non-item in item list
10+
--> $DIR/default.rs:23:13
311
|
412
LL | impl Foo for u32 {
5-
| - while parsing this item list starting here
13+
| - item list starts here
614
LL | default pub fn foo<T: Default>() -> T { T::default() }
7-
| ^^^
8-
| |
9-
| expected one of 7 possible tokens
10-
| help: visibility `pub` must come before `default pub`: `pub default pub`
11-
LL |
15+
| ^^^ non-item starts here
16+
...
1217
LL | }
13-
| - the item list ends here
18+
| - item list ends here
1419

1520
error[E0449]: unnecessary visibility qualifier
16-
--> $DIR/default.rs:18:5
21+
--> $DIR/default.rs:17:5
1722
|
1823
LL | pub default fn foo<T: Default>() -> T {
1924
| ^^^ `pub` not permitted here because it's implied
2025

2126
warning: the feature `specialization` is incomplete and may not be safe to use and/or cause compiler crashes
22-
--> $DIR/default.rs:4:12
27+
--> $DIR/default.rs:3:12
2328
|
2429
LL | #![feature(specialization)]
2530
| ^^^^^^^^^^^^^^
@@ -29,15 +34,15 @@ LL | #![feature(specialization)]
2934
= help: consider using `min_specialization` instead, which is more stable and complete
3035

3136
error[E0046]: not all trait items implemented, missing: `foo`
32-
--> $DIR/default.rs:23:1
37+
--> $DIR/default.rs:22:1
3338
|
3439
LL | fn foo<T: Default>() -> T;
3540
| -------------------------- `foo` from trait
3641
...
3742
LL | impl Foo for u32 {
3843
| ^^^^^^^^^^^^^^^^ missing `foo` in implementation
3944

40-
error: aborting due to 3 previous errors; 1 warning emitted
45+
error: aborting due to 4 previous errors; 1 warning emitted
4146

4247
Some errors have detailed explanations: E0046, E0449.
4348
For more information about an error, try `rustc --explain E0046`.

src/test/ui/parser/issue-63116.stderr

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
=rror: this file contains an unclosed delimiter
1+
error: this file contains an unclosed delimiter
22
--> $DIR/issue-63116.rs:3:18
33
|
44
LL | impl W <s(f;Y(;]
@@ -12,7 +12,7 @@ error: expected one of `!`, `(`, `)`, `+`, `,`, `::`, or `<`, found `;`
1212
LL | impl W <s(f;Y(;]
1313
| ^ expected one of 7 possible tokens
1414

15-
error: expected one of `!`, `&&`, `&`, `(`, `)`, `*`, `+`, `,`, `->`, `...`, `::`, `<`, `>`, `?`, `[`, `_`, `async`, `const`, `dyn`, `extern`, `fn`, `for`, `impl`, `pub`, `unsafe`, lifetime, or path, found `;`
15+
error: expected one of `!`, `&&`, `&`, `(`, `)`, `*`, `+`, `,`, `->`, `...`, `::`, `:`, `<`, `=`, `>`, `?`, `[`, `_`, `async`, `const`, `dyn`, `extern`, `fn`, `for`, `impl`, `unsafe`, lifetime, or path, found `;`
1616
--> $DIR/issue-63116.rs:3:15
1717
|
1818
LL | impl W <s(f;Y(;]

0 commit comments

Comments
 (0)