diff options
| author | Mazdak Farrokhzad <twingoow@gmail.com> | 2020-01-30 13:02:06 +0100 |
|---|---|---|
| committer | Mazdak Farrokhzad <twingoow@gmail.com> | 2020-02-13 10:39:24 +0100 |
| commit | a833be21626890de406e12f2561d2ffbda4aadb4 (patch) | |
| tree | bd75ba7b37902e0ba9d09e775bdd413f9c868201 /src/librustc_parse/parser | |
| parent | 36a17e4067d2e67223cd9a172476ee5503d6b44b (diff) | |
| download | rust-a833be21626890de406e12f2561d2ffbda4aadb4.tar.gz rust-a833be21626890de406e12f2561d2ffbda4aadb4.zip | |
parser: fuse free `fn` parsing together.
Diffstat (limited to 'src/librustc_parse/parser')
| -rw-r--r-- | src/librustc_parse/parser/item.rs | 111 |
1 files changed, 25 insertions, 86 deletions
diff --git a/src/librustc_parse/parser/item.rs b/src/librustc_parse/parser/item.rs index d2bcf31cb05..906b82f746b 100644 --- a/src/librustc_parse/parser/item.rs +++ b/src/librustc_parse/parser/item.rs @@ -11,7 +11,7 @@ use rustc_span::symbol::{kw, sym, Symbol}; use rustc_span::BytePos; use syntax::ast::{self, AttrKind, AttrStyle, AttrVec, Attribute, Ident, DUMMY_NODE_ID}; use syntax::ast::{AssocItem, AssocItemKind, Item, ItemKind, UseTree, UseTreeKind}; -use syntax::ast::{Async, Const, Defaultness, Extern, IsAuto, PathSegment, StrLit, Unsafe}; +use syntax::ast::{Async, Const, Defaultness, IsAuto, PathSegment, StrLit, Unsafe}; use syntax::ast::{BindingMode, Block, FnDecl, FnSig, Mac, MacArgs, MacDelimiter, Param, SelfKind}; use syntax::ast::{EnumDef, Generics, StructField, TraitRef, Ty, TyKind, Variant, VariantData}; use syntax::ast::{FnHeader, ForeignItem, ForeignItemKind, Mutability, Visibility, VisibilityKind}; @@ -96,53 +96,30 @@ impl<'a> Parser<'a> { return Ok(Some(item)); } + if self.is_fn_front_matter() { + // FUNCTION ITEM + return self.parse_item_fn(lo, vis, attrs); + } + if self.eat_keyword(kw::Extern) { if self.eat_keyword(kw::Crate) { + // EXTERN CRATE return Ok(Some(self.parse_item_extern_crate(lo, vis, attrs)?)); } - + // EXTERN BLOCK let abi = self.parse_abi(); - - if self.eat_keyword(kw::Fn) { - // EXTERN FUNCTION ITEM - let header = FnHeader { - unsafety: Unsafe::No, - asyncness: Async::No, - constness: Const::No, - ext: Extern::from_abi(abi), - }; - return self.parse_item_fn(lo, vis, attrs, header); - } else if self.check(&token::OpenDelim(token::Brace)) { - return Ok(Some(self.parse_item_foreign_mod(lo, abi, vis, attrs)?)); - } - - self.unexpected()?; + return Ok(Some(self.parse_item_foreign_mod(lo, abi, vis, attrs)?)); } if self.is_static_global() { - self.bump(); // STATIC ITEM + self.bump(); let m = self.parse_mutability(); let info = self.parse_item_const(Some(m))?; return self.mk_item_with_info(attrs, lo, vis, info); } - let constness = self.parse_constness(); - if let Const::Yes(const_span) = constness { - if [kw::Fn, kw::Unsafe, kw::Extern].iter().any(|k| self.check_keyword(*k)) { - // CONST FUNCTION ITEM - let unsafety = self.parse_unsafety(); - - if self.check_keyword(kw::Extern) { - self.sess.gated_spans.gate(sym::const_extern_fn, lo.to(self.token.span)); - } - let ext = self.parse_extern()?; - self.expect_keyword(kw::Fn)?; - - let header = FnHeader { unsafety, asyncness: Async::No, constness, ext }; - return self.parse_item_fn(lo, vis, attrs, header); - } - + if let Const::Yes(const_span) = self.parse_constness() { // CONST ITEM if self.eat_keyword(kw::Mut) { let prev_span = self.prev_span; @@ -161,21 +138,6 @@ impl<'a> Parser<'a> { return self.mk_item_with_info(attrs, lo, vis, info); } - // Parses `async unsafe? fn`. - if self.check_keyword(kw::Async) { - let async_span = self.token.span; - if self.is_keyword_ahead(1, &[kw::Fn]) || self.is_keyword_ahead(2, &[kw::Fn]) { - // ASYNC FUNCTION ITEM - let asyncness = self.parse_asyncness(); // `async` - let unsafety = self.parse_unsafety(); // `unsafe`? - self.expect_keyword(kw::Fn)?; // `fn` - self.ban_async_in_2015(async_span); - let header = - FnHeader { unsafety, asyncness, constness: Const::No, ext: Extern::None }; - return self.parse_item_fn(lo, vis, attrs, header); - } - } - if self.check_keyword(kw::Unsafe) && self.is_keyword_ahead(1, &[kw::Trait, kw::Auto]) { // UNSAFE TRAIT ITEM let unsafety = self.parse_unsafety(); @@ -195,26 +157,6 @@ impl<'a> Parser<'a> { return self.mk_item_with_info(attrs, lo, vis, info); } - if self.check_keyword(kw::Fn) { - // FUNCTION ITEM - self.bump(); - let header = FnHeader::default(); - return self.parse_item_fn(lo, vis, attrs, header); - } - - if self.check_keyword(kw::Unsafe) - && self.look_ahead(1, |t| *t != token::OpenDelim(token::Brace)) - { - // UNSAFE FUNCTION ITEM - let unsafety = self.parse_unsafety(); - // `{` is also expected after `unsafe`; in case of error, include it in the diagnostic. - self.check(&token::OpenDelim(token::Brace)); - let ext = self.parse_extern()?; - self.expect_keyword(kw::Fn)?; - let header = FnHeader { unsafety, asyncness: Async::No, constness: Const::No, ext }; - return self.parse_item_fn(lo, vis, attrs, header); - } - if self.eat_keyword(kw::Mod) { // MODULE ITEM let info = self.parse_item_mod(&attrs[..])?; @@ -1662,9 +1604,9 @@ impl<'a> Parser<'a> { lo: Span, vis: Visibility, mut attrs: Vec<Attribute>, - header: FnHeader, ) -> PResult<'a, Option<P<Item>>> { let cfg = ParamCfg { is_name_required: |_| true }; + let header = self.parse_fn_front_matter()?; let (ident, decl, generics) = self.parse_fn_sig(&cfg)?; let body = self.parse_fn_body(&mut false, &mut attrs)?; let kind = ItemKind::Fn(FnSig { decl, header }, generics, body); @@ -1730,27 +1672,24 @@ impl<'a> Parser<'a> { Ok(body) } - /// Is the current token unambiguously the start of an `FnHeader`? + /// Is the current token the start of an `FnHeader` / not a valid parse? fn is_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. - // This works for `async fn` and similar as `async async` is an invalid - // parse and `async fn` is never a valid parse on previous editions. - const QUALIFIER: [Symbol; 4] = [kw::Const, kw::Async, kw::Unsafe, kw::Extern]; - - let check_qual_follow = |this: &mut Self, dist| { - this.look_ahead(dist, |t| { - // ...qualified and then `fn`, e.g. `const fn`. - t.is_keyword(kw::Fn) - // Two qualifiers. This is enough. - || QUALIFIER.iter().any(|&kw| t.is_keyword(kw)) - }) - }; + const QUALS: [Symbol; 4] = [kw::Const, kw::Async, kw::Unsafe, kw::Extern]; self.check_keyword(kw::Fn) // Definitely an `fn`. // `$qual fn` or `$qual $qual`: - || QUALIFIER.iter().any(|&kw| self.check_keyword(kw)) && check_qual_follow(self, 1) - // `extern ABI fn` or `extern ABI $qual`; skip 1 for the ABI. - || self.check_keyword(kw::Extern) && check_qual_follow(self, 2) + || QUALS.iter().any(|&kw| self.check_keyword(kw)) + && self.look_ahead(1, |t| { + // ...qualified and then `fn`, e.g. `const fn`. + t.is_keyword(kw::Fn) + // Two qualifiers. This is enough. Due `async` we need to check that it's reserved. + || t.is_non_raw_ident_where(|i| QUALS.contains(&i.name) && i.is_reserved()) + }) + // `extern ABI fn` + || self.check_keyword(kw::Extern) + && self.look_ahead(1, |t| t.can_begin_literal_or_bool()) + && self.look_ahead(2, |t| t.is_keyword(kw::Fn)) } /// Parses all the "front matter" (or "qualifiers") for a `fn` declaration, |
