Skip to content

Commit 03591e8

Browse files
authored
Rollup merge of #70421 - Centril:recover-const-async-fn-ptr, r=estebank
parse: recover on `const fn()` / `async fn()` Recover on `const fn()` and `async fn()` function pointers, suggesting to remove the qualifier. For example: ``` error: an `fn` pointer type cannot be `async` --> $DIR/recover-const-async-fn-ptr.rs:6:11 | LL | type T3 = async fn(); | -----^^^^^ | | | `async` because of this | help: remove the `async` qualifier ``` r? @estebank
2 parents cb81b41 + af1146b commit 03591e8

7 files changed

+215
-23
lines changed

src/librustc_parse/parser/item.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -1496,7 +1496,7 @@ impl<'a> Parser<'a> {
14961496
}
14971497

14981498
/// Is the current token the start of an `FnHeader` / not a valid parse?
1499-
fn check_fn_front_matter(&mut self) -> bool {
1499+
pub(super) fn check_fn_front_matter(&mut self) -> bool {
15001500
// We use an over-approximation here.
15011501
// `const const`, `fn const` won't parse, but we're not stepping over other syntax either.
15021502
const QUALS: [Symbol; 4] = [kw::Const, kw::Async, kw::Unsafe, kw::Extern];
@@ -1523,7 +1523,7 @@ impl<'a> Parser<'a> {
15231523
/// FnQual = "const"? "async"? "unsafe"? Extern? ;
15241524
/// FnFrontMatter = FnQual? "fn" ;
15251525
/// ```
1526-
fn parse_fn_front_matter(&mut self) -> PResult<'a, FnHeader> {
1526+
pub(super) fn parse_fn_front_matter(&mut self) -> PResult<'a, FnHeader> {
15271527
let constness = self.parse_constness();
15281528
let asyncness = self.parse_asyncness();
15291529
let unsafety = self.parse_unsafety();

src/librustc_parse/parser/ty.rs

+28-16
Original file line numberDiff line numberDiff line change
@@ -127,16 +127,16 @@ impl<'a> Parser<'a> {
127127
} else if self.eat_keyword(kw::Underscore) {
128128
// A type to be inferred `_`
129129
TyKind::Infer
130-
} else if self.token_is_bare_fn_keyword() {
130+
} else if self.check_fn_front_matter() {
131131
// Function pointer type
132-
self.parse_ty_bare_fn(Vec::new())?
132+
self.parse_ty_bare_fn(lo, Vec::new())?
133133
} else if self.check_keyword(kw::For) {
134134
// Function pointer type or bound list (trait object type) starting with a poly-trait.
135135
// `for<'lt> [unsafe] [extern "ABI"] fn (&'lt S) -> T`
136136
// `for<'lt> Trait1<'lt> + Trait2 + 'a`
137137
let lifetime_defs = self.parse_late_bound_lifetime_defs()?;
138-
if self.token_is_bare_fn_keyword() {
139-
self.parse_ty_bare_fn(lifetime_defs)?
138+
if self.check_fn_front_matter() {
139+
self.parse_ty_bare_fn(lo, lifetime_defs)?
140140
} else {
141141
let path = self.parse_path(PathStyle::Type)?;
142142
let parse_plus = allow_plus == AllowPlus::Yes && self.check_plus();
@@ -291,13 +291,6 @@ impl<'a> Parser<'a> {
291291
Ok(TyKind::Typeof(expr))
292292
}
293293

294-
/// Is the current token one of the keywords that signals a bare function type?
295-
fn token_is_bare_fn_keyword(&mut self) -> bool {
296-
self.check_keyword(kw::Fn)
297-
|| self.check_keyword(kw::Unsafe)
298-
|| self.check_keyword(kw::Extern)
299-
}
300-
301294
/// Parses a function pointer type (`TyKind::BareFn`).
302295
/// ```
303296
/// [unsafe] [extern "ABI"] fn (S) -> T
@@ -306,12 +299,31 @@ impl<'a> Parser<'a> {
306299
/// | | | Return type
307300
/// Function Style ABI Parameter types
308301
/// ```
309-
fn parse_ty_bare_fn(&mut self, generic_params: Vec<GenericParam>) -> PResult<'a, TyKind> {
310-
let unsafety = self.parse_unsafety();
311-
let ext = self.parse_extern()?;
312-
self.expect_keyword(kw::Fn)?;
302+
/// We actually parse `FnHeader FnDecl`, but we error on `const` and `async` qualifiers.
303+
fn parse_ty_bare_fn(&mut self, lo: Span, params: Vec<GenericParam>) -> PResult<'a, TyKind> {
304+
let ast::FnHeader { ext, unsafety, constness, asyncness } = self.parse_fn_front_matter()?;
313305
let decl = self.parse_fn_decl(|_| false, AllowPlus::No)?;
314-
Ok(TyKind::BareFn(P(BareFnTy { ext, unsafety, generic_params, decl })))
306+
let whole_span = lo.to(self.prev_token.span);
307+
if let ast::Const::Yes(span) = constness {
308+
self.error_fn_ptr_bad_qualifier(whole_span, span, "const");
309+
}
310+
if let ast::Async::Yes { span, .. } = asyncness {
311+
self.error_fn_ptr_bad_qualifier(whole_span, span, "async");
312+
}
313+
Ok(TyKind::BareFn(P(BareFnTy { ext, unsafety, generic_params: params, decl })))
314+
}
315+
316+
/// Emit an error for the given bad function pointer qualifier.
317+
fn error_fn_ptr_bad_qualifier(&self, span: Span, qual_span: Span, qual: &str) {
318+
self.struct_span_err(span, &format!("an `fn` pointer type cannot be `{}`", qual))
319+
.span_label(qual_span, format!("`{}` because of this", qual))
320+
.span_suggestion_short(
321+
qual_span,
322+
&format!("remove the `{}` qualifier", qual),
323+
String::new(),
324+
Applicability::MaybeIncorrect,
325+
)
326+
.emit();
315327
}
316328

317329
/// Parses an `impl B0 + ... + Bn` type.
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
1-
type A = extern::foo::bar; //~ ERROR expected `fn`, found `::`
1+
type A = extern::foo::bar; //~ ERROR expected type, found keyword `extern`
22

33
fn main() {}
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
1-
error: expected `fn`, found `::`
2-
--> $DIR/keyword-extern-as-identifier-type.rs:1:16
1+
error: expected type, found keyword `extern`
2+
--> $DIR/keyword-extern-as-identifier-type.rs:1:10
33
|
44
LL | type A = extern::foo::bar;
5-
| ^^ expected `fn`
5+
| ^^^^^^ expected type
66

77
error: aborting due to previous error
88

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

+1-1
Original file line numberDiff line numberDiff line change
@@ -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 `!`, `&&`, `&`, `(`, `)`, `*`, `+`, `,`, `->`, `...`, `::`, `<`, `>`, `?`, `[`, `_`, `dyn`, `extern`, `fn`, `for`, `impl`, `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(;]
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
// edition:2018
2+
3+
type T0 = const fn(); //~ ERROR an `fn` pointer type cannot be `const`
4+
type T1 = const extern "C" fn(); //~ ERROR an `fn` pointer type cannot be `const`
5+
type T2 = const unsafe extern fn(); //~ ERROR an `fn` pointer type cannot be `const`
6+
type T3 = async fn(); //~ ERROR an `fn` pointer type cannot be `async`
7+
type T4 = async extern fn(); //~ ERROR an `fn` pointer type cannot be `async`
8+
type T5 = async unsafe extern "C" fn(); //~ ERROR an `fn` pointer type cannot be `async`
9+
type T6 = const async unsafe extern "C" fn();
10+
//~^ ERROR an `fn` pointer type cannot be `const`
11+
//~| ERROR an `fn` pointer type cannot be `async`
12+
13+
type FT0 = for<'a> const fn(); //~ ERROR an `fn` pointer type cannot be `const`
14+
type FT1 = for<'a> const extern "C" fn(); //~ ERROR an `fn` pointer type cannot be `const`
15+
type FT2 = for<'a> const unsafe extern fn(); //~ ERROR an `fn` pointer type cannot be `const`
16+
type FT3 = for<'a> async fn(); //~ ERROR an `fn` pointer type cannot be `async`
17+
type FT4 = for<'a> async extern fn(); //~ ERROR an `fn` pointer type cannot be `async`
18+
type FT5 = for<'a> async unsafe extern "C" fn(); //~ ERROR an `fn` pointer type cannot be `async`
19+
type FT6 = for<'a> const async unsafe extern "C" fn();
20+
//~^ ERROR an `fn` pointer type cannot be `const`
21+
//~| ERROR an `fn` pointer type cannot be `async`
22+
23+
fn main() {
24+
let _recovery_witness: () = 0; //~ ERROR mismatched types
25+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,155 @@
1+
error: an `fn` pointer type cannot be `const`
2+
--> $DIR/recover-const-async-fn-ptr.rs:3:11
3+
|
4+
LL | type T0 = const fn();
5+
| -----^^^^^
6+
| |
7+
| `const` because of this
8+
| help: remove the `const` qualifier
9+
10+
error: an `fn` pointer type cannot be `const`
11+
--> $DIR/recover-const-async-fn-ptr.rs:4:11
12+
|
13+
LL | type T1 = const extern "C" fn();
14+
| -----^^^^^^^^^^^^^^^^
15+
| |
16+
| `const` because of this
17+
| help: remove the `const` qualifier
18+
19+
error: an `fn` pointer type cannot be `const`
20+
--> $DIR/recover-const-async-fn-ptr.rs:5:11
21+
|
22+
LL | type T2 = const unsafe extern fn();
23+
| -----^^^^^^^^^^^^^^^^^^^
24+
| |
25+
| `const` because of this
26+
| help: remove the `const` qualifier
27+
28+
error: an `fn` pointer type cannot be `async`
29+
--> $DIR/recover-const-async-fn-ptr.rs:6:11
30+
|
31+
LL | type T3 = async fn();
32+
| -----^^^^^
33+
| |
34+
| `async` because of this
35+
| help: remove the `async` qualifier
36+
37+
error: an `fn` pointer type cannot be `async`
38+
--> $DIR/recover-const-async-fn-ptr.rs:7:11
39+
|
40+
LL | type T4 = async extern fn();
41+
| -----^^^^^^^^^^^^
42+
| |
43+
| `async` because of this
44+
| help: remove the `async` qualifier
45+
46+
error: an `fn` pointer type cannot be `async`
47+
--> $DIR/recover-const-async-fn-ptr.rs:8:11
48+
|
49+
LL | type T5 = async unsafe extern "C" fn();
50+
| -----^^^^^^^^^^^^^^^^^^^^^^^
51+
| |
52+
| `async` because of this
53+
| help: remove the `async` qualifier
54+
55+
error: an `fn` pointer type cannot be `const`
56+
--> $DIR/recover-const-async-fn-ptr.rs:9:11
57+
|
58+
LL | type T6 = const async unsafe extern "C" fn();
59+
| -----^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
60+
| |
61+
| `const` because of this
62+
| help: remove the `const` qualifier
63+
64+
error: an `fn` pointer type cannot be `async`
65+
--> $DIR/recover-const-async-fn-ptr.rs:9:11
66+
|
67+
LL | type T6 = const async unsafe extern "C" fn();
68+
| ^^^^^^-----^^^^^^^^^^^^^^^^^^^^^^^
69+
| |
70+
| `async` because of this
71+
| help: remove the `async` qualifier
72+
73+
error: an `fn` pointer type cannot be `const`
74+
--> $DIR/recover-const-async-fn-ptr.rs:13:12
75+
|
76+
LL | type FT0 = for<'a> const fn();
77+
| ^^^^^^^^-----^^^^^
78+
| |
79+
| `const` because of this
80+
| help: remove the `const` qualifier
81+
82+
error: an `fn` pointer type cannot be `const`
83+
--> $DIR/recover-const-async-fn-ptr.rs:14:12
84+
|
85+
LL | type FT1 = for<'a> const extern "C" fn();
86+
| ^^^^^^^^-----^^^^^^^^^^^^^^^^
87+
| |
88+
| `const` because of this
89+
| help: remove the `const` qualifier
90+
91+
error: an `fn` pointer type cannot be `const`
92+
--> $DIR/recover-const-async-fn-ptr.rs:15:12
93+
|
94+
LL | type FT2 = for<'a> const unsafe extern fn();
95+
| ^^^^^^^^-----^^^^^^^^^^^^^^^^^^^
96+
| |
97+
| `const` because of this
98+
| help: remove the `const` qualifier
99+
100+
error: an `fn` pointer type cannot be `async`
101+
--> $DIR/recover-const-async-fn-ptr.rs:16:12
102+
|
103+
LL | type FT3 = for<'a> async fn();
104+
| ^^^^^^^^-----^^^^^
105+
| |
106+
| `async` because of this
107+
| help: remove the `async` qualifier
108+
109+
error: an `fn` pointer type cannot be `async`
110+
--> $DIR/recover-const-async-fn-ptr.rs:17:12
111+
|
112+
LL | type FT4 = for<'a> async extern fn();
113+
| ^^^^^^^^-----^^^^^^^^^^^^
114+
| |
115+
| `async` because of this
116+
| help: remove the `async` qualifier
117+
118+
error: an `fn` pointer type cannot be `async`
119+
--> $DIR/recover-const-async-fn-ptr.rs:18:12
120+
|
121+
LL | type FT5 = for<'a> async unsafe extern "C" fn();
122+
| ^^^^^^^^-----^^^^^^^^^^^^^^^^^^^^^^^
123+
| |
124+
| `async` because of this
125+
| help: remove the `async` qualifier
126+
127+
error: an `fn` pointer type cannot be `const`
128+
--> $DIR/recover-const-async-fn-ptr.rs:19:12
129+
|
130+
LL | type FT6 = for<'a> const async unsafe extern "C" fn();
131+
| ^^^^^^^^-----^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
132+
| |
133+
| `const` because of this
134+
| help: remove the `const` qualifier
135+
136+
error: an `fn` pointer type cannot be `async`
137+
--> $DIR/recover-const-async-fn-ptr.rs:19:12
138+
|
139+
LL | type FT6 = for<'a> const async unsafe extern "C" fn();
140+
| ^^^^^^^^^^^^^^-----^^^^^^^^^^^^^^^^^^^^^^^
141+
| |
142+
| `async` because of this
143+
| help: remove the `async` qualifier
144+
145+
error[E0308]: mismatched types
146+
--> $DIR/recover-const-async-fn-ptr.rs:24:33
147+
|
148+
LL | let _recovery_witness: () = 0;
149+
| -- ^ expected `()`, found integer
150+
| |
151+
| expected due to this
152+
153+
error: aborting due to 17 previous errors
154+
155+
For more information about this error, try `rustc --explain E0308`.

0 commit comments

Comments
 (0)