about summary refs log tree commit diff
path: root/src/librustc_parse
diff options
context:
space:
mode:
authorMazdak Farrokhzad <twingoow@gmail.com>2020-01-30 00:18:54 +0100
committerMazdak Farrokhzad <twingoow@gmail.com>2020-02-05 01:27:09 +0100
commitb2c6eeb713d4cf9b35b7dda6ff2b0274e7f24684 (patch)
treedb169a7cc1f065c0b2975a1178d3afdef5a172b4 /src/librustc_parse
parentc0b7b41cff2b40d430befefc8688fb8ad847bcd4 (diff)
downloadrust-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.rs41
-rw-r--r--src/librustc_parse/parser/item.rs115
-rw-r--r--src/librustc_parse/parser/stmt.rs2
-rw-r--r--src/librustc_parse/parser/ty.rs16
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;
             }
         }