]> git.lizzy.rs Git - rust.git/blobdiff - src/libsyntax/ext/expand.rs
Provide specific label for patern parsing error
[rust.git] / src / libsyntax / ext / expand.rs
index 52322e98d46f9cd0e7e3e57b3b0e98a7fe14967a..84e40a7e4033de5dc305436460d8fc29e4d23544 100644 (file)
@@ -220,14 +220,6 @@ pub struct Invocation {
     pub expansion_data: ExpansionData,
 }
 
-// Needed for feature-gating attributes used after derives or together with test/bench
-#[derive(Clone, Copy, PartialEq)]
-pub enum TogetherWith {
-    None,
-    Derive,
-    TestBench,
-}
-
 pub enum InvocationKind {
     Bang {
         mac: ast::Mac,
@@ -238,7 +230,8 @@ pub enum InvocationKind {
         attr: Option<ast::Attribute>,
         traits: Vec<Path>,
         item: Annotatable,
-        together_with: TogetherWith,
+        // We temporarily report errors for attribute macros placed after derives
+        after_derive: bool,
     },
     Derive {
         path: Path,
@@ -645,8 +638,8 @@ fn gate_proc_macro_attr_item(&self, span: Span, item: &Annotatable) {
         let (kind, gate) = match *item {
             Annotatable::Item(ref item) => {
                 match item.node {
-                    ItemKind::Mod(_) if self.cx.ecfg.proc_macro_mod() => return,
-                    ItemKind::Mod(_) => ("modules", "proc_macro_mod"),
+                    ItemKind::Mod(_) if self.cx.ecfg.proc_macro_hygiene() => return,
+                    ItemKind::Mod(_) => ("modules", "proc_macro_hygiene"),
                     _ => return,
                 }
             }
@@ -654,9 +647,9 @@ fn gate_proc_macro_attr_item(&self, span: Span, item: &Annotatable) {
             Annotatable::ImplItem(_) => return,
             Annotatable::ForeignItem(_) => return,
             Annotatable::Stmt(_) |
-            Annotatable::Expr(_) if self.cx.ecfg.proc_macro_expr() => return,
-            Annotatable::Stmt(_) => ("statements", "proc_macro_expr"),
-            Annotatable::Expr(_) => ("expressions", "proc_macro_expr"),
+            Annotatable::Expr(_) if self.cx.ecfg.proc_macro_hygiene() => return,
+            Annotatable::Stmt(_) => ("statements", "proc_macro_hygiene"),
+            Annotatable::Expr(_) => ("expressions", "proc_macro_hygiene"),
         };
         emit_feature_err(
             self.cx.parse_sess,
@@ -668,7 +661,7 @@ fn gate_proc_macro_attr_item(&self, span: Span, item: &Annotatable) {
     }
 
     fn gate_proc_macro_expansion(&self, span: Span, fragment: &Option<AstFragment>) {
-        if self.cx.ecfg.proc_macro_gen() {
+        if self.cx.ecfg.proc_macro_hygiene() {
             return
         }
         let fragment = match fragment {
@@ -691,7 +684,7 @@ fn visit_item(&mut self, i: &'ast ast::Item) {
                 if let ast::ItemKind::MacroDef(_) = i.node {
                     emit_feature_err(
                         self.parse_sess,
-                        "proc_macro_gen",
+                        "proc_macro_hygiene",
                         self.span,
                         GateIssue::Language,
                         &format!("procedural macros cannot expand to macro definitions"),
@@ -771,7 +764,7 @@ fn expand_bang_invoc(&mut self,
                                                                     edition) {
                     dummy_span
                 } else {
-                    kind.make_from(expander.expand(self.cx, span, mac.node.stream()))
+                    kind.make_from(expander.expand(self.cx, span, mac.node.stream(), None))
                 }
             }
 
@@ -792,7 +785,12 @@ fn expand_bang_invoc(&mut self,
                                                                     edition) {
                     dummy_span
                 } else {
-                    kind.make_from(expander.expand(self.cx, span, mac.node.stream()))
+                    kind.make_from(expander.expand(
+                        self.cx,
+                        span,
+                        mac.node.stream(),
+                        def_info.map(|(_, s)| s),
+                    ))
                 }
             }
 
@@ -885,12 +883,12 @@ fn gate_proc_macro_expansion_kind(&self, span: Span, kind: AstFragmentKind) {
             AstFragmentKind::ImplItems => return,
             AstFragmentKind::ForeignItems => return,
         };
-        if self.cx.ecfg.proc_macro_non_items() {
+        if self.cx.ecfg.proc_macro_hygiene() {
             return
         }
         emit_feature_err(
             self.cx.parse_sess,
-            "proc_macro_non_items",
+            "proc_macro_hygiene",
             span,
             GateIssue::Language,
             &format!("procedural macros cannot be expanded to {}", kind),
@@ -1008,9 +1006,7 @@ pub fn parse_ast_fragment(&mut self, kind: AstFragmentKind, macro_legacy_warning
             AstFragmentKind::ForeignItems => {
                 let mut items = SmallVec::new();
                 while self.token != token::Eof {
-                    if let Some(item) = self.parse_foreign_item()? {
-                        items.push(item);
-                    }
+                    items.push(self.parse_foreign_item()?);
                 }
                 AstFragment::ForeignItems(items)
             }
@@ -1034,7 +1030,7 @@ pub fn parse_ast_fragment(&mut self, kind: AstFragmentKind, macro_legacy_warning
                 }
             },
             AstFragmentKind::Ty => AstFragment::Ty(self.parse_ty()?),
-            AstFragmentKind::Pat => AstFragment::Pat(self.parse_pat()?),
+            AstFragmentKind::Pat => AstFragment::Pat(self.parse_pat(None)?),
         })
     }
 
@@ -1045,10 +1041,28 @@ pub fn ensure_complete_parse(&mut self, macro_path: &Path, kind_name: &str, span
             // Avoid emitting backtrace info twice.
             let def_site_span = self.span.with_ctxt(SyntaxContext::empty());
             let mut err = self.diagnostic().struct_span_err(def_site_span, &msg);
-            let msg = format!("caused by the macro expansion here; the usage \
-                               of `{}!` is likely invalid in {} context",
-                               macro_path, kind_name);
-            err.span_note(span, &msg).emit();
+            err.span_label(span, "caused by the macro expansion here");
+            let msg = format!(
+                "the usage of `{}!` is likely invalid in {} context",
+                macro_path,
+                kind_name,
+            );
+            err.note(&msg);
+            let semi_span = self.sess.source_map().next_point(span);
+
+            let semi_full_span = semi_span.to(self.sess.source_map().next_point(semi_span));
+            match self.sess.source_map().span_to_snippet(semi_full_span) {
+                Ok(ref snippet) if &snippet[..] != ";" && kind_name == "expression" => {
+                    err.span_suggestion_with_applicability(
+                        semi_span,
+                        "you might be missing a semicolon here",
+                        ";".to_owned(),
+                        Applicability::MaybeIncorrect,
+                    );
+                }
+                _ => {}
+            }
+            err.emit();
         }
     }
 }
@@ -1084,19 +1098,17 @@ fn collect_attr(&mut self,
                     traits: Vec<Path>,
                     item: Annotatable,
                     kind: AstFragmentKind,
-                    together_with: TogetherWith)
+                    after_derive: bool)
                     -> AstFragment {
-        self.collect(kind, InvocationKind::Attr { attr, traits, item, together_with })
+        self.collect(kind, InvocationKind::Attr { attr, traits, item, after_derive })
     }
 
-    fn find_attr_invoc(&self, attrs: &mut Vec<ast::Attribute>, together_with: &mut TogetherWith)
+    fn find_attr_invoc(&self, attrs: &mut Vec<ast::Attribute>, after_derive: &mut bool)
                        -> Option<ast::Attribute> {
         let attr = attrs.iter()
                         .position(|a| {
                             if a.path == "derive" {
-                                *together_with = TogetherWith::Derive
-                            } else if a.path == "rustc_test_marker2" {
-                                *together_with = TogetherWith::TestBench
+                                *after_derive = true;
                             }
                             !attr::is_known(a) && !is_builtin_attr(a)
                         })
@@ -1109,19 +1121,15 @@ fn find_attr_invoc(&self, attrs: &mut Vec<ast::Attribute>, together_with: &mut T
                                  "non-builtin inner attributes are unstable");
             }
         }
-        if together_with == &TogetherWith::None &&
-           attrs.iter().any(|a| a.path == "rustc_test_marker2") {
-            *together_with = TogetherWith::TestBench;
-        }
         attr
     }
 
     /// If `item` is an attr invocation, remove and return the macro attribute and derive traits.
     fn classify_item<T>(&mut self, mut item: T)
-                        -> (Option<ast::Attribute>, Vec<Path>, T, TogetherWith)
+                        -> (Option<ast::Attribute>, Vec<Path>, T, /* after_derive */ bool)
         where T: HasAttrs,
     {
-        let (mut attr, mut traits, mut together_with) = (None, Vec::new(), TogetherWith::None);
+        let (mut attr, mut traits, mut after_derive) = (None, Vec::new(), false);
 
         item = item.map_attrs(|mut attrs| {
             if let Some(legacy_attr_invoc) = self.cx.resolver.find_legacy_attr_invoc(&mut attrs,
@@ -1130,20 +1138,20 @@ fn classify_item<T>(&mut self, mut item: T)
                 return attrs;
             }
 
-            attr = self.find_attr_invoc(&mut attrs, &mut together_with);
+            attr = self.find_attr_invoc(&mut attrs, &mut after_derive);
             traits = collect_derives(&mut self.cx, &mut attrs);
             attrs
         });
 
-        (attr, traits, item, together_with)
+        (attr, traits, item, after_derive)
     }
 
     /// Alternative of `classify_item()` that ignores `#[derive]` so invocations fallthrough
     /// to the unused-attributes lint (making it an error on statements and expressions
     /// is a breaking change)
     fn classify_nonitem<T: HasAttrs>(&mut self, mut item: T)
-                                     -> (Option<ast::Attribute>, T, TogetherWith) {
-        let (mut attr, mut together_with) = (None, TogetherWith::None);
+                                     -> (Option<ast::Attribute>, T, /* after_derive */ bool) {
+        let (mut attr, mut after_derive) = (None, false);
 
         item = item.map_attrs(|mut attrs| {
             if let Some(legacy_attr_invoc) = self.cx.resolver.find_legacy_attr_invoc(&mut attrs,
@@ -1152,11 +1160,11 @@ fn classify_nonitem<T: HasAttrs>(&mut self, mut item: T)
                 return attrs;
             }
 
-            attr = self.find_attr_invoc(&mut attrs, &mut together_with);
+            attr = self.find_attr_invoc(&mut attrs, &mut after_derive);
             attrs
         });
 
-        (attr, item, together_with)
+        (attr, item, after_derive)
     }
 
     fn configure<T: HasAttrs>(&mut self, node: T) -> Option<T> {
@@ -1195,7 +1203,7 @@ fn fold_expr(&mut self, expr: P<ast::Expr>) -> P<ast::Expr> {
         expr.node = self.cfg.configure_expr_kind(expr.node);
 
         // ignore derives so they remain unused
-        let (attr, expr, together_with) = self.classify_nonitem(expr);
+        let (attr, expr, after_derive) = self.classify_nonitem(expr);
 
         if attr.is_some() {
             // collect the invoc regardless of whether or not attributes are permitted here
@@ -1204,7 +1212,7 @@ fn fold_expr(&mut self, expr: P<ast::Expr>) -> P<ast::Expr> {
 
             // AstFragmentKind::Expr requires the macro to emit an expression
             return self.collect_attr(attr, vec![], Annotatable::Expr(P(expr)),
-                                     AstFragmentKind::Expr, together_with).make_expr();
+                                     AstFragmentKind::Expr, after_derive).make_expr();
         }
 
         if let ast::ExprKind::Mac(mac) = expr.node {
@@ -1220,13 +1228,13 @@ fn fold_opt_expr(&mut self, expr: P<ast::Expr>) -> Option<P<ast::Expr>> {
         expr.node = self.cfg.configure_expr_kind(expr.node);
 
         // ignore derives so they remain unused
-        let (attr, expr, together_with) = self.classify_nonitem(expr);
+        let (attr, expr, after_derive) = self.classify_nonitem(expr);
 
         if attr.is_some() {
             attr.as_ref().map(|a| self.cfg.maybe_emit_expr_attr_err(a));
 
             return self.collect_attr(attr, vec![], Annotatable::Expr(P(expr)),
-                                     AstFragmentKind::OptExpr, together_with).make_opt_expr();
+                                     AstFragmentKind::OptExpr, after_derive).make_opt_expr();
         }
 
         if let ast::ExprKind::Mac(mac) = expr.node {
@@ -1258,18 +1266,18 @@ fn fold_pat(&mut self, pat: P<ast::Pat>) -> P<ast::Pat> {
 
         // we'll expand attributes on expressions separately
         if !stmt.is_expr() {
-            let (attr, derives, stmt_, together_with) = if stmt.is_item() {
+            let (attr, derives, stmt_, after_derive) = if stmt.is_item() {
                 self.classify_item(stmt)
             } else {
                 // ignore derives on non-item statements so it falls through
                 // to the unused-attributes lint
-                let (attr, stmt, together_with) = self.classify_nonitem(stmt);
-                (attr, vec![], stmt, together_with)
+                let (attr, stmt, after_derive) = self.classify_nonitem(stmt);
+                (attr, vec![], stmt, after_derive)
             };
 
             if attr.is_some() || !derives.is_empty() {
                 return self.collect_attr(attr, derives, Annotatable::Stmt(P(stmt_)),
-                                         AstFragmentKind::Stmts, together_with).make_stmts();
+                                         AstFragmentKind::Stmts, after_derive).make_stmts();
             }
 
             stmt = stmt_;
@@ -1311,10 +1319,10 @@ fn fold_block(&mut self, block: P<Block>) -> P<Block> {
     fn fold_item(&mut self, item: P<ast::Item>) -> SmallVec<[P<ast::Item>; 1]> {
         let item = configure!(self, item);
 
-        let (attr, traits, item, together_with) = self.classify_item(item);
+        let (attr, traits, item, after_derive) = self.classify_item(item);
         if attr.is_some() || !traits.is_empty() {
             return self.collect_attr(attr, traits, Annotatable::Item(item),
-                                     AstFragmentKind::Items, together_with).make_items();
+                                     AstFragmentKind::Items, after_derive).make_items();
         }
 
         match item.node {
@@ -1386,10 +1394,10 @@ fn fold_block(&mut self, block: P<Block>) -> P<Block> {
     fn fold_trait_item(&mut self, item: ast::TraitItem) -> SmallVec<[ast::TraitItem; 1]> {
         let item = configure!(self, item);
 
-        let (attr, traits, item, together_with) = self.classify_item(item);
+        let (attr, traits, item, after_derive) = self.classify_item(item);
         if attr.is_some() || !traits.is_empty() {
             return self.collect_attr(attr, traits, Annotatable::TraitItem(P(item)),
-                                     AstFragmentKind::TraitItems, together_with).make_trait_items()
+                                     AstFragmentKind::TraitItems, after_derive).make_trait_items()
         }
 
         match item.node {
@@ -1405,10 +1413,10 @@ fn fold_block(&mut self, block: P<Block>) -> P<Block> {
     fn fold_impl_item(&mut self, item: ast::ImplItem) -> SmallVec<[ast::ImplItem; 1]> {
         let item = configure!(self, item);
 
-        let (attr, traits, item, together_with) = self.classify_item(item);
+        let (attr, traits, item, after_derive) = self.classify_item(item);
         if attr.is_some() || !traits.is_empty() {
             return self.collect_attr(attr, traits, Annotatable::ImplItem(P(item)),
-                                     AstFragmentKind::ImplItems, together_with).make_impl_items();
+                                     AstFragmentKind::ImplItems, after_derive).make_impl_items();
         }
 
         match item.node {
@@ -1440,11 +1448,11 @@ fn fold_foreign_mod(&mut self, foreign_mod: ast::ForeignMod) -> ast::ForeignMod
     fn fold_foreign_item(&mut self, foreign_item: ast::ForeignItem)
         -> SmallVec<[ast::ForeignItem; 1]>
     {
-        let (attr, traits, foreign_item, together_with) = self.classify_item(foreign_item);
+        let (attr, traits, foreign_item, after_derive) = self.classify_item(foreign_item);
 
         if attr.is_some() || !traits.is_empty() {
             return self.collect_attr(attr, traits, Annotatable::ForeignItem(P(foreign_item)),
-                                     AstFragmentKind::ForeignItems, together_with)
+                                     AstFragmentKind::ForeignItems, after_derive)
                                      .make_foreign_items();
         }
 
@@ -1612,10 +1620,7 @@ fn enable_allow_internal_unstable = allow_internal_unstable,
         fn enable_custom_derive = custom_derive,
         fn enable_format_args_nl = format_args_nl,
         fn macros_in_extern_enabled = macros_in_extern,
-        fn proc_macro_mod = proc_macro_mod,
-        fn proc_macro_gen = proc_macro_gen,
-        fn proc_macro_expr = proc_macro_expr,
-        fn proc_macro_non_items = proc_macro_non_items,
+        fn proc_macro_hygiene = proc_macro_hygiene,
     }
 
     fn enable_custom_inner_attributes(&self) -> bool {