]> git.lizzy.rs Git - rust.git/blobdiff - src/librustc_parse/parser/item.rs
parse extern consts
[rust.git] / src / librustc_parse / parser / item.rs
index 500aaaf43b92a3ddc669bb75c005f145bf9cc14e..5fcd72090ec87f88a37459aeff2414b0dcda160d 100644 (file)
@@ -546,6 +546,7 @@ fn parse_defaultness(&mut self) -> Defaultness {
                 1,
                 &[
                     kw::Impl,
+                    kw::Static,
                     kw::Const,
                     kw::Async,
                     kw::Fn,
@@ -665,19 +666,25 @@ fn parse_assoc_item_(
         let vis = self.parse_visibility(FollowedByType::No)?;
         let defaultness = self.parse_defaultness();
 
-        let (ident, kind, generics) = if self.eat_keyword(kw::Type) {
+        let (ident, kind) = if self.eat_keyword(kw::Type) {
             self.parse_assoc_ty()?
         } else if self.check_fn_front_matter() {
             let (ident, sig, generics, body) = self.parse_fn(at_end, &mut attrs, req_name)?;
-            (ident, AssocItemKind::Fn(sig, body), generics)
-        } else if self.check_keyword(kw::Const) {
-            self.parse_assoc_const()?
+            (ident, AssocItemKind::Fn(sig, generics, body))
+        } else if self.is_static_global() {
+            self.bump(); // `static`
+            let mutbl = self.parse_mutability();
+            let (ident, ty, expr) = self.parse_item_const_common(Some(mutbl))?;
+            (ident, AssocItemKind::Static(ty, mutbl, expr))
+        } else if self.eat_keyword(kw::Const) {
+            let (ident, ty, expr) = self.parse_item_const_common(None)?;
+            (ident, AssocItemKind::Const(ty, expr))
         } else if self.isnt_macro_invocation() {
             return Err(self.missing_assoc_item_kind_err("associated", self.prev_span));
         } else if self.token.is_path_start() {
             let mac = self.parse_item_macro(&vis)?;
             *at_end = true;
-            (Ident::invalid(), AssocItemKind::Macro(mac), Generics::default())
+            (Ident::invalid(), AssocItemKind::Macro(mac))
         } else {
             self.recover_attrs_no_item(&attrs)?;
             self.unexpected()?
@@ -685,26 +692,13 @@ fn parse_assoc_item_(
 
         let span = lo.to(self.prev_span);
         let id = DUMMY_NODE_ID;
-        Ok(AssocItem { id, span, ident, attrs, vis, defaultness, generics, kind, tokens: None })
-    }
-
-    /// This parses the grammar:
-    ///
-    ///     AssocConst = "const" Ident ":" Ty "=" Expr ";"
-    fn parse_assoc_const(&mut self) -> PResult<'a, (Ident, AssocItemKind, Generics)> {
-        self.expect_keyword(kw::Const)?;
-        let ident = self.parse_ident()?;
-        self.expect(&token::Colon)?;
-        let ty = self.parse_ty()?;
-        let expr = if self.eat(&token::Eq) { Some(self.parse_expr()?) } else { None };
-        self.expect_semi()?;
-        Ok((ident, AssocItemKind::Const(ty, expr), Generics::default()))
+        Ok(AssocItem { id, span, ident, attrs, vis, defaultness, kind, tokens: None })
     }
 
     /// Parses the following grammar:
     ///
     ///     AssocTy = Ident ["<"...">"] [":" [GenericBounds]] ["where" ...] ["=" Ty]
-    fn parse_assoc_ty(&mut self) -> PResult<'a, (Ident, AssocItemKind, Generics)> {
+    fn parse_assoc_ty(&mut self) -> PResult<'a, (Ident, AssocItemKind)> {
         let ident = self.parse_ident()?;
         let mut generics = self.parse_generics()?;
 
@@ -716,7 +710,7 @@ fn parse_assoc_ty(&mut self) -> PResult<'a, (Ident, AssocItemKind, Generics)> {
         let default = if self.eat(&token::Eq) { Some(self.parse_ty()?) } else { None };
         self.expect_semi()?;
 
-        Ok((ident, AssocItemKind::TyAlias(bounds, default), generics))
+        Ok((ident, AssocItemKind::TyAlias(generics, bounds, default)))
     }
 
     /// Parses a `UseTree`.
@@ -876,7 +870,7 @@ pub fn parse_foreign_item(&mut self, at_end: &mut bool) -> PResult<'a, P<Foreign
         let lo = self.token.span;
         let vis = self.parse_visibility(FollowedByType::No)?;
 
-        let (ident, kind) = if self.check_keyword(kw::Type) {
+        let (ident, kind) = if self.eat_keyword(kw::Type) {
             // FOREIGN TYPE ITEM
             self.parse_item_foreign_type()?
         } else if self.check_fn_front_matter() {
@@ -886,19 +880,12 @@ pub fn parse_foreign_item(&mut self, at_end: &mut bool) -> PResult<'a, P<Foreign
         } else if self.is_static_global() {
             // FOREIGN STATIC ITEM
             self.bump(); // `static`
-            self.parse_item_foreign_static()?
-        } else if self.token.is_keyword(kw::Const) {
-            // Treat `const` as `static` for error recovery, but don't add it to expected tokens.
-            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,
-                )
-                .emit();
-            self.parse_item_foreign_static()?
+            let mutbl = self.parse_mutability();
+            let (ident, ty, expr) = self.parse_item_const_common(Some(mutbl))?;
+            (ident, ForeignItemKind::Static(ty, mutbl, expr))
+        } else if self.eat_keyword(kw::Const) {
+            let (ident, ty, expr) = self.parse_item_const_common(None)?;
+            (ident, ForeignItemKind::Const(ty, expr))
         } else if self.isnt_macro_invocation() {
             return Err(self.missing_assoc_item_kind_err("extern", self.prev_span));
         } else if self.token.is_path_start() {
@@ -912,23 +899,14 @@ pub fn parse_foreign_item(&mut self, at_end: &mut bool) -> PResult<'a, P<Foreign
         Ok(P(self.mk_item(lo, ident, kind, vis, attrs)))
     }
 
-    /// Parses a static item from a foreign module.
-    /// Assumes that the `static` keyword is already parsed.
-    fn parse_item_foreign_static(&mut self) -> PResult<'a, (Ident, ForeignItemKind)> {
-        let mutbl = self.parse_mutability();
-        let ident = self.parse_ident()?;
-        self.expect(&token::Colon)?;
-        let ty = self.parse_ty()?;
-        self.expect_semi()?;
-        Ok((ident, ForeignItemKind::Static(ty, mutbl)))
-    }
-
     /// Parses a type from a foreign module.
     fn parse_item_foreign_type(&mut self) -> PResult<'a, (Ident, ForeignItemKind)> {
-        self.expect_keyword(kw::Type)?;
-        let ident = self.parse_ident()?;
-        self.expect_semi()?;
-        Ok((ident, ForeignItemKind::Ty))
+        let (ident, kind) = self.parse_assoc_ty()?;
+        let kind = match kind {
+            AssocItemKind::TyAlias(g, b, d) => ForeignItemKind::TyAlias(g, b, d),
+            _ => unreachable!(),
+        };
+        Ok((ident, kind))
     }
 
     fn is_static_global(&mut self) -> bool {
@@ -964,34 +942,43 @@ fn recover_const_mut(&mut self, const_span: Span) {
         }
     }
 
-    /// Parse `["const" | ("static" "mut"?)] $ident ":" $ty = $expr` with
+    /// Parse `["const" | ("static" "mut"?)] $ident ":" $ty (= $expr)?` with
     /// `["const" | ("static" "mut"?)]` already parsed and stored in `m`.
     ///
     /// When `m` is `"const"`, `$ident` may also be `"_"`.
     fn parse_item_const(&mut self, m: Option<Mutability>) -> PResult<'a, ItemInfo> {
+        let (id, ty, expr) = self.parse_item_const_common(m)?;
+        let item = match m {
+            Some(m) => ItemKind::Static(ty, m, expr),
+            None => ItemKind::Const(ty, expr),
+        };
+        Ok((id, item))
+    }
+
+    /// Parse `["const" | ("static" "mut"?)] $ident ":" $ty (= $expr)?` with
+    /// `["const" | ("static" "mut"?)]` already parsed and stored in `m`.
+    ///
+    /// When `m` is `"const"`, `$ident` may also be `"_"`.
+    fn parse_item_const_common(
+        &mut self,
+        m: Option<Mutability>,
+    ) -> PResult<'a, (Ident, P<Ty>, Option<P<ast::Expr>>)> {
         let id = if m.is_none() { self.parse_ident_or_underscore() } else { self.parse_ident() }?;
 
         // Parse the type of a `const` or `static mut?` item.
         // That is, the `":" $ty` fragment.
-        let ty = if self.token == token::Eq {
-            self.recover_missing_const_type(id, m)
-        } else {
-            // Not `=` so expect `":"" $ty` as usual.
-            self.expect(&token::Colon)?;
+        let ty = if self.eat(&token::Colon) {
             self.parse_ty()?
+        } else {
+            self.recover_missing_const_type(id, m)
         };
 
-        self.expect(&token::Eq)?;
-        let e = self.parse_expr()?;
+        let expr = if self.eat(&token::Eq) { Some(self.parse_expr()?) } else { None };
         self.expect_semi()?;
-        let item = match m {
-            Some(m) => ItemKind::Static(ty, m, e),
-            None => ItemKind::Const(ty, e),
-        };
-        Ok((id, item))
+        Ok((id, ty, expr))
     }
 
-    /// We were supposed to parse `:` but instead, we're already at `=`.
+    /// We were supposed to parse `:` but the `:` was missing.
     /// This means that the type is missing.
     fn recover_missing_const_type(&mut self, id: Ident, m: Option<Mutability>) -> P<Ty> {
         // Construct the error and stash it away with the hope