diff options
| author | Mazdak Farrokhzad <twingoow@gmail.com> | 2020-04-02 14:27:54 +0200 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2020-04-02 14:27:54 +0200 |
| commit | 03591e8a7842896975985614221a152b28238bb8 (patch) | |
| tree | f6fa505cc4918e1fa231700309287ef1a66ef07e /src/librustc_parse/parser | |
| parent | cb81b41c9a474d403bd35fd2898ad226bc02657c (diff) | |
| parent | af1146bd23634d34d953255114b1235e131f2c80 (diff) | |
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
Diffstat (limited to 'src/librustc_parse/parser')
| -rw-r--r-- | src/librustc_parse/parser/item.rs | 4 | ||||
| -rw-r--r-- | src/librustc_parse/parser/ty.rs | 44 |
2 files changed, 30 insertions, 18 deletions
diff --git a/src/librustc_parse/parser/item.rs b/src/librustc_parse/parser/item.rs index 6b7a9ec658d..798eb85f36f 100644 --- a/src/librustc_parse/parser/item.rs +++ b/src/librustc_parse/parser/item.rs @@ -1496,7 +1496,7 @@ impl<'a> Parser<'a> { } /// Is the current token the start of an `FnHeader` / not a valid parse? - fn check_fn_front_matter(&mut self) -> bool { + pub(super) fn check_fn_front_matter(&mut self) -> bool { // We use an over-approximation here. // `const const`, `fn const` won't parse, but we're not stepping over other syntax either. const QUALS: [Symbol; 4] = [kw::Const, kw::Async, kw::Unsafe, kw::Extern]; @@ -1523,7 +1523,7 @@ impl<'a> Parser<'a> { /// FnQual = "const"? "async"? "unsafe"? Extern? ; /// FnFrontMatter = FnQual? "fn" ; /// ``` - fn parse_fn_front_matter(&mut self) -> PResult<'a, FnHeader> { + pub(super) fn parse_fn_front_matter(&mut self) -> PResult<'a, FnHeader> { let constness = self.parse_constness(); let asyncness = self.parse_asyncness(); let unsafety = self.parse_unsafety(); diff --git a/src/librustc_parse/parser/ty.rs b/src/librustc_parse/parser/ty.rs index c21ac8d04f1..a6015504a32 100644 --- a/src/librustc_parse/parser/ty.rs +++ b/src/librustc_parse/parser/ty.rs @@ -127,16 +127,16 @@ impl<'a> Parser<'a> { } else if self.eat_keyword(kw::Underscore) { // A type to be inferred `_` TyKind::Infer - } else if self.token_is_bare_fn_keyword() { + } else if self.check_fn_front_matter() { // Function pointer type - self.parse_ty_bare_fn(Vec::new())? + self.parse_ty_bare_fn(lo, Vec::new())? } else if self.check_keyword(kw::For) { // Function pointer type or bound list (trait object type) starting with a poly-trait. // `for<'lt> [unsafe] [extern "ABI"] fn (&'lt S) -> T` // `for<'lt> Trait1<'lt> + Trait2 + 'a` let lifetime_defs = self.parse_late_bound_lifetime_defs()?; - if self.token_is_bare_fn_keyword() { - self.parse_ty_bare_fn(lifetime_defs)? + if self.check_fn_front_matter() { + self.parse_ty_bare_fn(lo, lifetime_defs)? } else { let path = self.parse_path(PathStyle::Type)?; let parse_plus = allow_plus == AllowPlus::Yes && self.check_plus(); @@ -291,13 +291,6 @@ impl<'a> Parser<'a> { Ok(TyKind::Typeof(expr)) } - /// Is the current token one of the keywords that signals a bare function type? - fn token_is_bare_fn_keyword(&mut self) -> bool { - self.check_keyword(kw::Fn) - || self.check_keyword(kw::Unsafe) - || self.check_keyword(kw::Extern) - } - /// Parses a function pointer type (`TyKind::BareFn`). /// ``` /// [unsafe] [extern "ABI"] fn (S) -> T @@ -306,12 +299,31 @@ impl<'a> Parser<'a> { /// | | | Return type /// Function Style ABI Parameter types /// ``` - fn parse_ty_bare_fn(&mut self, generic_params: Vec<GenericParam>) -> PResult<'a, TyKind> { - let unsafety = self.parse_unsafety(); - let ext = self.parse_extern()?; - self.expect_keyword(kw::Fn)?; + /// We actually parse `FnHeader FnDecl`, but we error on `const` and `async` qualifiers. + fn parse_ty_bare_fn(&mut self, lo: Span, params: Vec<GenericParam>) -> PResult<'a, TyKind> { + let ast::FnHeader { ext, unsafety, constness, asyncness } = self.parse_fn_front_matter()?; let decl = self.parse_fn_decl(|_| false, AllowPlus::No)?; - Ok(TyKind::BareFn(P(BareFnTy { ext, unsafety, generic_params, decl }))) + let whole_span = lo.to(self.prev_token.span); + if let ast::Const::Yes(span) = constness { + self.error_fn_ptr_bad_qualifier(whole_span, span, "const"); + } + if let ast::Async::Yes { span, .. } = asyncness { + self.error_fn_ptr_bad_qualifier(whole_span, span, "async"); + } + Ok(TyKind::BareFn(P(BareFnTy { ext, unsafety, generic_params: params, decl }))) + } + + /// Emit an error for the given bad function pointer qualifier. + fn error_fn_ptr_bad_qualifier(&self, span: Span, qual_span: Span, qual: &str) { + self.struct_span_err(span, &format!("an `fn` pointer type cannot be `{}`", qual)) + .span_label(qual_span, format!("`{}` because of this", qual)) + .span_suggestion_short( + qual_span, + &format!("remove the `{}` qualifier", qual), + String::new(), + Applicability::MaybeIncorrect, + ) + .emit(); } /// Parses an `impl B0 + ... + Bn` type. |
