diff options
| author | Mazdak Farrokhzad <twingoow@gmail.com> | 2020-01-30 00:18:54 +0100 |
|---|---|---|
| committer | Mazdak Farrokhzad <twingoow@gmail.com> | 2020-02-05 01:27:09 +0100 |
| commit | b2c6eeb713d4cf9b35b7dda6ff2b0274e7f24684 (patch) | |
| tree | db169a7cc1f065c0b2975a1178d3afdef5a172b4 /src/librustc_parse | |
| parent | c0b7b41cff2b40d430befefc8688fb8ad847bcd4 (diff) | |
| download | rust-b2c6eeb713d4cf9b35b7dda6ff2b0274e7f24684.tar.gz rust-b2c6eeb713d4cf9b35b7dda6ff2b0274e7f24684.zip | |
parser: merge `fn` grammars wrt. bodies & headers
also refactor `FnKind` and `visit_assoc_item` visitors
Diffstat (limited to 'src/librustc_parse')
| -rw-r--r-- | src/librustc_parse/parser/diagnostics.rs | 41 | ||||
| -rw-r--r-- | src/librustc_parse/parser/item.rs | 115 | ||||
| -rw-r--r-- | src/librustc_parse/parser/stmt.rs | 2 | ||||
| -rw-r--r-- | src/librustc_parse/parser/ty.rs | 16 |
4 files changed, 59 insertions, 115 deletions
diff --git a/src/librustc_parse/parser/diagnostics.rs b/src/librustc_parse/parser/diagnostics.rs index 5f148fa6ba2..7c015c7a1d7 100644 --- a/src/librustc_parse/parser/diagnostics.rs +++ b/src/librustc_parse/parser/diagnostics.rs @@ -938,47 +938,6 @@ impl<'a> Parser<'a> { self.expect(&token::Semi).map(drop) // Error unconditionally } - pub(super) fn parse_semi_or_incorrect_foreign_fn_body( - &mut self, - ident: &Ident, - extern_sp: Span, - ) -> PResult<'a, ()> { - if self.token != token::Semi { - // This might be an incorrect fn definition (#62109). - let parser_snapshot = self.clone(); - match self.parse_inner_attrs_and_block() { - Ok((_, body)) => { - self.struct_span_err(ident.span, "incorrect `fn` inside `extern` block") - .span_label(ident.span, "can't have a body") - .span_label(body.span, "this body is invalid here") - .span_label( - extern_sp, - "`extern` blocks define existing foreign functions and `fn`s \ - inside of them cannot have a body", - ) - .help( - "you might have meant to write a function accessible through ffi, \ - which can be done by writing `extern fn` outside of the \ - `extern` block", - ) - .note( - "for more information, visit \ - https://doc.rust-lang.org/std/keyword.extern.html", - ) - .emit(); - } - Err(mut err) => { - err.cancel(); - mem::replace(self, parser_snapshot); - self.expect_semi()?; - } - } - } else { - self.bump(); - } - Ok(()) - } - /// Consumes alternative await syntaxes like `await!(<expr>)`, `await <expr>`, /// `await? <expr>`, `await(<expr>)`, and `await { <expr> }`. pub(super) fn recover_incorrect_await_syntax( diff --git a/src/librustc_parse/parser/item.rs b/src/librustc_parse/parser/item.rs index 87a6aa76f57..07d8bae4725 100644 --- a/src/librustc_parse/parser/item.rs +++ b/src/librustc_parse/parser/item.rs @@ -97,7 +97,6 @@ impl<'a> Parser<'a> { } if self.eat_keyword(kw::Extern) { - let extern_sp = self.prev_span; if self.eat_keyword(kw::Crate) { return Ok(Some(self.parse_item_extern_crate(lo, vis, attrs)?)); } @@ -115,7 +114,7 @@ impl<'a> Parser<'a> { }; 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, extern_sp)?)); + return Ok(Some(self.parse_item_foreign_mod(lo, abi, vis, attrs)?)); } self.unexpected()?; @@ -1046,7 +1045,6 @@ impl<'a> Parser<'a> { abi: Option<StrLit>, visibility: Visibility, mut attrs: Vec<Attribute>, - extern_sp: Span, ) -> PResult<'a, P<Item>> { self.expect(&token::OpenDelim(token::Brace))?; @@ -1054,7 +1052,7 @@ impl<'a> Parser<'a> { let mut foreign_items = vec![]; while !self.eat(&token::CloseDelim(token::Brace)) { - foreign_items.push(self.parse_foreign_item(extern_sp)?); + foreign_items.push(self.parse_foreign_item()?); } let prev_span = self.prev_span; @@ -1064,51 +1062,42 @@ impl<'a> Parser<'a> { } /// Parses a foreign item. - pub fn parse_foreign_item(&mut self, extern_sp: Span) -> PResult<'a, P<ForeignItem>> { + pub fn parse_foreign_item(&mut self) -> PResult<'a, P<ForeignItem>> { maybe_whole!(self, NtForeignItem, |ni| ni); let attrs = self.parse_outer_attributes()?; let lo = self.token.span; let visibility = self.parse_visibility(FollowedByType::No)?; + // FOREIGN TYPE ITEM + if self.check_keyword(kw::Type) { + return self.parse_item_foreign_type(visibility, lo, attrs); + } + // FOREIGN STATIC ITEM - // Treat `const` as `static` for error recovery, but don't add it to expected tokens. - if self.check_keyword(kw::Static) || self.token.is_keyword(kw::Const) { - if self.token.is_keyword(kw::Const) { - let mut err = - self.struct_span_err(self.token.span, "extern items cannot be `const`"); + if self.is_static_global() { + self.bump(); // `static` + return self.parse_item_foreign_static(visibility, lo, attrs); + } - // The user wrote 'const fn' - if self.is_keyword_ahead(1, &[kw::Fn, kw::Unsafe]) { - err.emit(); - // Consume `const` - self.bump(); - // Consume `unsafe` if present, since `extern` blocks - // don't allow it. This will leave behind a plain 'fn' - self.eat_keyword(kw::Unsafe); - // Treat 'const fn` as a plain `fn` for error recovery purposes. - // We've already emitted an error, so compilation is guaranteed - // to fail - return Ok(self.parse_item_foreign_fn(visibility, lo, attrs, extern_sp)?); - } - err.span_suggestion( - self.token.span, + // Treat `const` as `static` for error recovery, but don't add it to expected tokens. + if self.is_kw_followed_by_ident(kw::Const) { + self.bump(); // `const` + self.struct_span_err(self.prev_span, "extern items cannot be `const`") + .span_suggestion( + self.prev_span, "try using a static value", "static".to_owned(), Applicability::MachineApplicable, - ); - err.emit(); - } - self.bump(); // `static` or `const` - return Ok(self.parse_item_foreign_static(visibility, lo, attrs)?); + ) + .emit(); + return self.parse_item_foreign_static(visibility, lo, attrs); } + // FOREIGN FUNCTION ITEM - if self.check_keyword(kw::Fn) { - return Ok(self.parse_item_foreign_fn(visibility, lo, attrs, extern_sp)?); - } - // FOREIGN TYPE ITEM - if self.check_keyword(kw::Type) { - return Ok(self.parse_item_foreign_type(visibility, lo, attrs)?); + const MAY_INTRODUCE_FN: &[Symbol] = &[kw::Const, kw::Async, kw::Unsafe, kw::Extern, kw::Fn]; + if MAY_INTRODUCE_FN.iter().any(|&kw| self.check_keyword(kw)) { + return self.parse_item_foreign_fn(visibility, lo, attrs); } match self.parse_assoc_macro_invoc("extern", Some(&visibility), &mut false)? { @@ -1727,14 +1716,14 @@ impl<'a> Parser<'a> { &mut self, lo: Span, vis: Visibility, - attrs: Vec<Attribute>, + mut attrs: Vec<Attribute>, header: FnHeader, ) -> PResult<'a, Option<P<Item>>> { let cfg = ParamCfg { is_name_required: |_| true }; let (ident, decl, generics) = self.parse_fn_sig(&cfg)?; - let (inner_attrs, body) = self.parse_inner_attrs_and_block()?; + let body = self.parse_fn_body(&mut false, &mut attrs)?; let kind = ItemKind::Fn(FnSig { decl, header }, generics, body); - self.mk_item_with_info(attrs, lo, vis, (ident, kind, Some(inner_attrs))) + self.mk_item_with_info(attrs, lo, vis, (ident, kind, None)) } /// Parses a function declaration from a foreign module. @@ -1742,15 +1731,14 @@ impl<'a> Parser<'a> { &mut self, vis: ast::Visibility, lo: Span, - attrs: Vec<Attribute>, - extern_sp: Span, + mut attrs: Vec<Attribute>, ) -> PResult<'a, P<ForeignItem>> { let cfg = ParamCfg { is_name_required: |_| true }; - self.expect_keyword(kw::Fn)?; + let header = self.parse_fn_front_matter()?; let (ident, decl, generics) = self.parse_fn_sig(&cfg)?; - let span = lo.to(self.token.span); - self.parse_semi_or_incorrect_foreign_fn_body(&ident, extern_sp)?; - let kind = ForeignItemKind::Fn(decl, generics); + let body = self.parse_fn_body(&mut false, &mut attrs)?; + let kind = ForeignItemKind::Fn(FnSig { header, decl }, generics, body); + let span = lo.to(self.prev_span); Ok(P(ast::ForeignItem { ident, attrs, kind, id: DUMMY_NODE_ID, span, vis, tokens: None })) } @@ -1761,45 +1749,40 @@ impl<'a> Parser<'a> { is_name_required: fn(&token::Token) -> bool, ) -> PResult<'a, (Ident, AssocItemKind, Generics)> { let header = self.parse_fn_front_matter()?; - let (ident, decl, generics) = self.parse_fn_sig(&ParamCfg { is_name_required })?; - let sig = FnSig { header, decl }; - let body = self.parse_assoc_fn_body(at_end, attrs)?; - Ok((ident, AssocItemKind::Fn(sig, body), generics)) + let (ident, decl, generics) = self.parse_fn_sig(&&ParamCfg { is_name_required })?; + let body = self.parse_fn_body(at_end, attrs)?; + Ok((ident, AssocItemKind::Fn(FnSig { header, decl }, body), generics)) } - /// Parse the "body" of a method in an associated item definition. + /// Parse the "body" of a function. /// This can either be `;` when there's no body, - /// or e.g. a block when the method is a provided one. - fn parse_assoc_fn_body( + /// or e.g. a block when the function is a provided one. + fn parse_fn_body( &mut self, at_end: &mut bool, attrs: &mut Vec<Attribute>, ) -> PResult<'a, Option<P<Block>>> { - Ok(match self.token.kind { + let (inner_attrs, body) = match self.token.kind { token::Semi => { - debug!("parse_assoc_fn_body(): parsing required method"); self.bump(); - *at_end = true; - None + (Vec::new(), None) } token::OpenDelim(token::Brace) => { - debug!("parse_assoc_fn_body(): parsing provided method"); - *at_end = true; - let (inner_attrs, body) = self.parse_inner_attrs_and_block()?; - attrs.extend(inner_attrs.iter().cloned()); - Some(body) + let (attrs, body) = self.parse_inner_attrs_and_block()?; + (attrs, Some(body)) } token::Interpolated(ref nt) => match **nt { token::NtBlock(..) => { - *at_end = true; - let (inner_attrs, body) = self.parse_inner_attrs_and_block()?; - attrs.extend(inner_attrs.iter().cloned()); - Some(body) + let (attrs, body) = self.parse_inner_attrs_and_block()?; + (attrs, Some(body)) } _ => return self.expected_semi_or_open_brace(), }, _ => return self.expected_semi_or_open_brace(), - }) + }; + attrs.extend(inner_attrs); + *at_end = true; + Ok(body) } /// Parses all the "front matter" for a `fn` declaration, up to diff --git a/src/librustc_parse/parser/stmt.rs b/src/librustc_parse/parser/stmt.rs index ae8f1e4db1b..f3a69729399 100644 --- a/src/librustc_parse/parser/stmt.rs +++ b/src/librustc_parse/parser/stmt.rs @@ -199,7 +199,7 @@ impl<'a> Parser<'a> { } } - fn is_kw_followed_by_ident(&self, kw: Symbol) -> bool { + pub(super) fn is_kw_followed_by_ident(&self, kw: Symbol) -> bool { self.token.is_keyword(kw) && self.look_ahead(1, |t| t.is_ident() && !t.is_reserved_ident()) } diff --git a/src/librustc_parse/parser/ty.rs b/src/librustc_parse/parser/ty.rs index 1ed80ed7350..990661bf6b5 100644 --- a/src/librustc_parse/parser/ty.rs +++ b/src/librustc_parse/parser/ty.rs @@ -36,18 +36,20 @@ impl BoundModifiers { } } -#[derive(Copy, Clone)] +#[derive(Copy, Clone, PartialEq)] pub(super) enum AllowPlus { Yes, No, } +#[derive(PartialEq)] pub(super) enum RecoverQPath { Yes, No, } // Is `...` (`CVarArgs`) legal at this level of type parsing? +#[derive(PartialEq)] enum AllowCVariadic { Yes, No, @@ -106,7 +108,7 @@ impl<'a> Parser<'a> { recover_qpath: RecoverQPath, allow_c_variadic: AllowCVariadic, ) -> PResult<'a, P<Ty>> { - let allow_qpath_recovery = matches!(recover_qpath, RecoverQPath::Yes); + let allow_qpath_recovery = recover_qpath == RecoverQPath::Yes; maybe_recover_from_interpolated_ty_qpath!(self, allow_qpath_recovery); maybe_whole!(self, NtTy, |x| x); @@ -142,7 +144,7 @@ impl<'a> Parser<'a> { self.parse_ty_bare_fn(lifetime_defs)? } else { let path = self.parse_path(PathStyle::Type)?; - let parse_plus = matches!(allow_plus, AllowPlus::Yes) && self.check_plus(); + let parse_plus = allow_plus == AllowPlus::Yes && self.check_plus(); self.parse_remaining_bounds(lifetime_defs, path, lo, parse_plus)? } } else if self.eat_keyword(kw::Impl) { @@ -162,7 +164,7 @@ impl<'a> Parser<'a> { } else if self.token.is_path_start() { self.parse_path_start_ty(lo, allow_plus)? } else if self.eat(&token::DotDotDot) { - if let AllowCVariadic::Yes = allow_c_variadic { + if allow_c_variadic == AllowCVariadic::Yes { TyKind::CVarArgs } else { // FIXME(Centril): Should we just allow `...` syntactically @@ -200,7 +202,7 @@ impl<'a> Parser<'a> { if ts.len() == 1 && !trailing { let ty = ts.into_iter().nth(0).unwrap().into_inner(); - let maybe_bounds = matches!(allow_plus, AllowPlus::Yes) && self.token.is_like_plus(); + let maybe_bounds = allow_plus == AllowPlus::Yes && self.token.is_like_plus(); match ty.kind { // `(TY_BOUND_NOPAREN) + BOUND + ...`. TyKind::Path(None, path) if maybe_bounds => { @@ -355,7 +357,7 @@ impl<'a> Parser<'a> { args: self.parse_mac_args()?, prior_type_ascription: self.last_type_ascription, })) - } else if matches!(allow_plus, AllowPlus::Yes) && self.check_plus() { + } else if allow_plus == AllowPlus::Yes && self.check_plus() { // `Trait1 + Trait2 + 'a` self.parse_remaining_bounds(Vec::new(), path, lo, true) } else { @@ -396,7 +398,7 @@ impl<'a> Parser<'a> { Ok(bound) => bounds.push(bound), Err(neg_sp) => negative_bounds.push(neg_sp), } - if matches!(allow_plus, AllowPlus::No) || !self.eat_plus() { + if allow_plus == AllowPlus::No || !self.eat_plus() { break; } } |
