about summary refs log tree commit diff
path: root/src/libsyntax/parse/parser.rs
diff options
context:
space:
mode:
authorAlex Crichton <alex@alexcrichton.com>2018-04-05 10:49:14 -0500
committerGitHub <noreply@github.com>2018-04-05 10:49:14 -0500
commit46492ffabd7194bb134035cadcd66d47f1b97db8 (patch)
treef361c33cc5f7794ae707b5ed1d60fff877000575 /src/libsyntax/parse/parser.rs
parentb0bd9a771e81740da7e4a7a2f5a6dfecce10c699 (diff)
parent5d74990cebb82b9573ea6a9d509bb8e05fd6681e (diff)
downloadrust-46492ffabd7194bb134035cadcd66d47f1b97db8.tar.gz
rust-46492ffabd7194bb134035cadcd66d47f1b97db8.zip
Rollup merge of #49350 - abonander:macros-in-extern, r=petrochenkov
Expand macros in `extern {}` blocks

This permits macro and proc-macro and attribute invocations (the latter only with the `proc_macro` feature of course) in `extern {}` blocks, gated behind a new `macros_in_extern` feature.

A tracking issue is now open at #49476

closes #48747
Diffstat (limited to 'src/libsyntax/parse/parser.rs')
-rw-r--r--src/libsyntax/parse/parser.rs124
1 files changed, 69 insertions, 55 deletions
diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs
index f5ab023b30e..9936eea9356 100644
--- a/src/libsyntax/parse/parser.rs
+++ b/src/libsyntax/parse/parser.rs
@@ -26,7 +26,7 @@ use ast::{Ident, ImplItem, IsAuto, Item, ItemKind};
 use ast::{Label, Lifetime, LifetimeDef, Lit, LitKind, UintTy};
 use ast::Local;
 use ast::MacStmtStyle;
-use ast::Mac_;
+use ast::{Mac, Mac_};
 use ast::{MutTy, Mutability};
 use ast::{Pat, PatKind, PathSegment};
 use ast::{PolyTraitRef, QSelf};
@@ -1417,28 +1417,8 @@ impl<'a> Parser<'a> {
                 None
             };
             (ident, TraitItemKind::Const(ty, default), ast::Generics::default())
-        } else if self.token.is_path_start() && !self.is_extern_non_path() {
+        } else if let Some(mac) = self.parse_assoc_macro_invoc("trait", None, &mut false)? {
             // trait item macro.
-            // code copied from parse_macro_use_or_failure... abstraction!
-            let prev_span = self.prev_span;
-            let lo = self.span;
-            let pth = self.parse_path(PathStyle::Mod)?;
-
-            if pth.segments.len() == 1 {
-                if !self.eat(&token::Not) {
-                    return Err(self.missing_assoc_item_kind_err("trait", prev_span));
-                }
-            } else {
-                self.expect(&token::Not)?;
-            }
-
-            // eat a matched-delimiter token tree:
-            let (delim, tts) = self.expect_delimited_token_tree()?;
-            if delim != token::Brace {
-                self.expect(&token::Semi)?
-            }
-
-            let mac = respan(lo.to(self.prev_span), Mac_ { path: pth, tts: tts });
             (keywords::Invalid.ident(), ast::TraitItemKind::Macro(mac), ast::Generics::default())
         } else {
             let (constness, unsafety, abi) = self.parse_fn_front_matter()?;
@@ -5393,6 +5373,12 @@ impl<'a> Parser<'a> {
     fn missing_assoc_item_kind_err(&mut self, item_type: &str, prev_span: Span)
                                    -> DiagnosticBuilder<'a>
     {
+        let expected_kinds = if item_type == "extern" {
+            "missing `fn`, `type`, or `static`"
+        } else {
+            "missing `fn`, `type`, or `const`"
+        };
+
         // Given this code `path(`, it seems like this is not
         // setting the visibility of a macro invocation, but rather
         // a mistyped method declaration.
@@ -5405,9 +5391,9 @@ impl<'a> Parser<'a> {
         let sp = prev_span.between(self.prev_span);
         let mut err = self.diagnostic().struct_span_err(
             sp,
-            &format!("missing `fn`, `type`, or `const` for {}-item declaration",
-                     item_type));
-        err.span_label(sp, "missing `fn`, `type`, or `const`");
+            &format!("{} for {}-item declaration",
+                     expected_kinds, item_type));
+        err.span_label(sp, expected_kinds);
         err
     }
 
@@ -5416,31 +5402,8 @@ impl<'a> Parser<'a> {
                          -> PResult<'a, (Ident, Vec<Attribute>, ast::Generics,
                              ast::ImplItemKind)> {
         // code copied from parse_macro_use_or_failure... abstraction!
-        if self.token.is_path_start() && !self.is_extern_non_path() {
+        if let Some(mac) = self.parse_assoc_macro_invoc("impl", Some(vis), at_end)? {
             // Method macro.
-
-            let prev_span = self.prev_span;
-
-            let lo = self.span;
-            let pth = self.parse_path(PathStyle::Mod)?;
-            if pth.segments.len() == 1 {
-                if !self.eat(&token::Not) {
-                    return Err(self.missing_assoc_item_kind_err("impl", prev_span));
-                }
-            } else {
-                self.expect(&token::Not)?;
-            }
-
-            self.complain_if_pub_macro(&vis.node, prev_span);
-
-            // eat a matched-delimiter token tree:
-            *at_end = true;
-            let (delim, tts) = self.expect_delimited_token_tree()?;
-            if delim != token::Brace {
-                self.expect(&token::Semi)?
-            }
-
-            let mac = respan(lo.to(self.prev_span), Mac_ { path: pth, tts: tts });
             Ok((keywords::Invalid.ident(), vec![], ast::Generics::default(),
                 ast::ImplItemKind::Macro(mac)))
         } else {
@@ -6786,7 +6749,9 @@ impl<'a> Parser<'a> {
     }
 
     /// Parse a foreign item.
-    fn parse_foreign_item(&mut self) -> PResult<'a, Option<ForeignItem>> {
+    pub fn parse_foreign_item(&mut self) -> PResult<'a, Option<ForeignItem>> {
+        maybe_whole!(self, NtForeignItem, |ni| Some(ni));
+
         let attrs = self.parse_outer_attributes()?;
         let lo = self.span;
         let visibility = self.parse_visibility(false)?;
@@ -6812,12 +6777,26 @@ impl<'a> Parser<'a> {
             return Ok(Some(self.parse_item_foreign_type(visibility, lo, attrs)?));
         }
 
-        // FIXME #5668: this will occur for a macro invocation:
-        match self.parse_macro_use_or_failure(attrs, true, false, lo, visibility)? {
-            Some(item) => {
-                return Err(self.span_fatal(item.span, "macros cannot expand to foreign items"));
+        match self.parse_assoc_macro_invoc("extern", Some(&visibility), &mut false)? {
+            Some(mac) => {
+                Ok(Some(
+                    ForeignItem {
+                        ident: keywords::Invalid.ident(),
+                        span: lo.to(self.prev_span),
+                        id: ast::DUMMY_NODE_ID,
+                        attrs,
+                        vis: visibility,
+                        node: ForeignItemKind::Macro(mac),
+                    }
+                ))
+            }
+            None => {
+                if !attrs.is_empty() {
+                    self.expected_item_err(&attrs);
+                }
+
+                Ok(None)
             }
-            None => Ok(None)
         }
     }
 
@@ -6881,6 +6860,41 @@ impl<'a> Parser<'a> {
         Ok(None)
     }
 
+    /// Parse a macro invocation inside a `trait`, `impl` or `extern` block
+    fn parse_assoc_macro_invoc(&mut self, item_kind: &str, vis: Option<&Visibility>,
+                               at_end: &mut bool) -> PResult<'a, Option<Mac>>
+    {
+        if self.token.is_path_start() && !self.is_extern_non_path() {
+            let prev_span = self.prev_span;
+            let lo = self.span;
+            let pth = self.parse_path(PathStyle::Mod)?;
+
+            if pth.segments.len() == 1 {
+                if !self.eat(&token::Not) {
+                    return Err(self.missing_assoc_item_kind_err(item_kind, prev_span));
+                }
+            } else {
+                self.expect(&token::Not)?;
+            }
+
+            if let Some(vis) = vis {
+                self.complain_if_pub_macro(&vis.node, prev_span);
+            }
+
+            *at_end = true;
+
+            // eat a matched-delimiter token tree:
+            let (delim, tts) = self.expect_delimited_token_tree()?;
+            if delim != token::Brace {
+                self.expect(&token::Semi)?
+            }
+
+            Ok(Some(respan(lo.to(self.prev_span), Mac_ { path: pth, tts: tts })))
+        } else {
+            Ok(None)
+        }
+    }
+
     fn collect_tokens<F, R>(&mut self, f: F) -> PResult<'a, (R, TokenStream)>
         where F: FnOnce(&mut Self) -> PResult<'a, R>
     {