]> git.lizzy.rs Git - rust.git/commitdiff
rustc: Correctly pretty-print macro delimiters
authorAlex Crichton <alex@alexcrichton.com>
Tue, 22 May 2018 15:01:21 +0000 (08:01 -0700)
committerAlex Crichton <alex@alexcrichton.com>
Tue, 22 May 2018 18:56:41 +0000 (11:56 -0700)
This commit updates the `Mac_` AST structure to keep track of the delimiters
that it originally had for its invocation. This allows us to faithfully
pretty-print macro invocations not using parentheses (e.g. `vec![...]`). This in
turn helps procedural macros due to #43081.

Closes #50840

src/libsyntax/ast.rs
src/libsyntax/ext/placeholders.rs
src/libsyntax/fold.rs
src/libsyntax/parse/parser.rs
src/libsyntax/print/pprust.rs
src/libsyntax_ext/assert.rs
src/test/ui-fulldeps/proc-macro/auxiliary/macro-brackets.rs [new file with mode: 0644]
src/test/ui-fulldeps/proc-macro/macro-brackets.rs [new file with mode: 0644]
src/test/ui-fulldeps/proc-macro/macro-brackets.stderr [new file with mode: 0644]

index 0ce9763ded8bf4fd376af595ce3c172d04e30197..8991398ae44737fe4c1a952356f6b8c163bb42fb 100644 (file)
@@ -1239,9 +1239,17 @@ pub enum Movability {
 #[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)]
 pub struct Mac_ {
     pub path: Path,
+    pub delim: MacDelimiter,
     pub tts: ThinTokenStream,
 }
 
+#[derive(Copy, Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)]
+pub enum MacDelimiter {
+    Parenthesis,
+    Bracket,
+    Brace,
+}
+
 impl Mac_ {
     pub fn stream(&self) -> TokenStream {
         self.tts.clone().into()
index 9f60882ca29fc408224b388e1de08f181847cda3..5c1c661fffd378cebd212feca0276f309b1e3135 100644 (file)
@@ -27,6 +27,7 @@ fn mac_placeholder() -> ast::Mac {
         dummy_spanned(ast::Mac_ {
             path: ast::Path { span: DUMMY_SP, segments: Vec::new() },
             tts: TokenStream::empty().into(),
+            delim: ast::MacDelimiter::Brace,
         })
     }
 
index 28fb95f165fde509536b9acc669a5e1548a0ee1d..190fef2a9972f9a792e8e02de46cf3a6b5cd944d 100644 (file)
@@ -520,6 +520,7 @@ pub fn noop_fold_mac<T: Folder>(Spanned {node, span}: Mac, fld: &mut T) -> Mac {
         node: Mac_ {
             tts: fld.fold_tts(node.stream()).into(),
             path: fld.fold_path(node.path),
+            delim: node.delim,
         },
         span: fld.new_span(span)
     }
index 729ad491fd544baf737b5ac75b41b391876ec7e9..7cfb34fab84681b6f542bfcc2b3e35001f14e1ef 100644 (file)
@@ -26,7 +26,7 @@
 use ast::{Label, Lifetime, LifetimeDef, Lit, LitKind, UintTy};
 use ast::Local;
 use ast::MacStmtStyle;
-use ast::{Mac, Mac_};
+use ast::{Mac, Mac_, MacDelimiter};
 use ast::{MutTy, Mutability};
 use ast::{Pat, PatKind, PathSegment};
 use ast::{PolyTraitRef, QSelf};
@@ -1611,8 +1611,9 @@ fn parse_ty_common(&mut self, allow_plus: bool, allow_qpath_recovery: bool)
             let path = self.parse_path(PathStyle::Type)?;
             if self.eat(&token::Not) {
                 // Macro invocation in type position
-                let (_, tts) = self.expect_delimited_token_tree()?;
-                TyKind::Mac(respan(lo.to(self.prev_span), Mac_ { path: path, tts: tts }))
+                let (delim, tts) = self.expect_delimited_token_tree()?;
+                let node = Mac_ { path, tts, delim };
+                TyKind::Mac(respan(lo.to(self.prev_span), node))
             } else {
                 // Just a type path or bound list (trait object type) starting with a trait.
                 //   `Type`
@@ -2181,19 +2182,27 @@ pub fn mk_lit_u32(&mut self, i: u32, attrs: ThinVec<Attribute>) -> P<Expr> {
         })
     }
 
-    fn expect_delimited_token_tree(&mut self) -> PResult<'a, (token::DelimToken, ThinTokenStream)> {
-        match self.token {
-            token::OpenDelim(delim) => match self.parse_token_tree() {
-                TokenTree::Delimited(_, delimited) => Ok((delim, delimited.stream().into())),
-                _ => unreachable!(),
-            },
+    fn expect_delimited_token_tree(&mut self) -> PResult<'a, (MacDelimiter, ThinTokenStream)> {
+        let delim = match self.token {
+            token::OpenDelim(delim) => delim,
             _ => {
                 let msg = "expected open delimiter";
                 let mut err = self.fatal(msg);
                 err.span_label(self.span, msg);
-                Err(err)
+                return Err(err)
             }
-        }
+        };
+        let delimited = match self.parse_token_tree() {
+            TokenTree::Delimited(_, delimited) => delimited,
+            _ => unreachable!(),
+        };
+        let delim = match delim {
+            token::Paren => MacDelimiter::Parenthesis,
+            token::Bracket => MacDelimiter::Bracket,
+            token::Brace => MacDelimiter::Brace,
+            token::NoDelim => self.bug("unexpected no delimiter"),
+        };
+        Ok((delim, delimited.stream().into()))
     }
 
     /// At the bottom (top?) of the precedence hierarchy,
@@ -2406,9 +2415,10 @@ fn parse_bottom_expr(&mut self) -> PResult<'a, P<Expr>> {
                     // `!`, as an operator, is prefix, so we know this isn't that
                     if self.eat(&token::Not) {
                         // MACRO INVOCATION expression
-                        let (_, tts) = self.expect_delimited_token_tree()?;
+                        let (delim, tts) = self.expect_delimited_token_tree()?;
                         let hi = self.prev_span;
-                        return Ok(self.mk_mac_expr(lo.to(hi), Mac_ { path: pth, tts: tts }, attrs));
+                        let node = Mac_ { path: pth, tts, delim };
+                        return Ok(self.mk_mac_expr(lo.to(hi), node, attrs))
                     }
                     if self.check(&token::OpenDelim(token::Brace)) {
                         // This is a struct literal, unless we're prohibited
@@ -3881,8 +3891,8 @@ fn parse_pat_with_range_pat(&mut self, allow_range_pat: bool) -> PResult<'a, P<P
                     token::Not if qself.is_none() => {
                         // Parse macro invocation
                         self.bump();
-                        let (_, tts) = self.expect_delimited_token_tree()?;
-                        let mac = respan(lo.to(self.prev_span), Mac_ { path: path, tts: tts });
+                        let (delim, tts) = self.expect_delimited_token_tree()?;
+                        let mac = respan(lo.to(self.prev_span), Mac_ { path, tts, delim });
                         pat = PatKind::Mac(mac);
                     }
                     token::DotDotDot | token::DotDotEq | token::DotDot => {
@@ -4275,7 +4285,7 @@ fn eat_macro_def(&mut self, attrs: &[Attribute], vis: &Visibility, lo: Span)
 
                 let ident = self.parse_ident()?;
                 let (delim, tokens) = self.expect_delimited_token_tree()?;
-                if delim != token::Brace {
+                if delim != MacDelimiter::Brace {
                     if !self.eat(&token::Semi) {
                         let msg = "macros that expand to items must either \
                                    be surrounded with braces or followed by a semicolon";
@@ -4360,8 +4370,8 @@ fn parse_stmt_without_recovery(&mut self,
             // check that we're pointing at delimiters (need to check
             // again after the `if`, because of `parse_ident`
             // consuming more tokens).
-            let delim = match self.token {
-                token::OpenDelim(delim) => delim,
+            match self.token {
+                token::OpenDelim(_) => {}
                 _ => {
                     // we only expect an ident if we didn't parse one
                     // above.
@@ -4377,20 +4387,20 @@ fn parse_stmt_without_recovery(&mut self,
                     err.span_label(self.span, format!("expected {}`(` or `{{`", ident_str));
                     return Err(err)
                 },
-            };
+            }
 
-            let (_, tts) = self.expect_delimited_token_tree()?;
+            let (delim, tts) = self.expect_delimited_token_tree()?;
             let hi = self.prev_span;
 
-            let style = if delim == token::Brace {
+            let style = if delim == MacDelimiter::Brace {
                 MacStmtStyle::Braces
             } else {
                 MacStmtStyle::NoBraces
             };
 
             if id.name == keywords::Invalid.name() {
-                let mac = respan(lo.to(hi), Mac_ { path: pth, tts: tts });
-                let node = if delim == token::Brace ||
+                let mac = respan(lo.to(hi), Mac_ { path: pth, tts, delim });
+                let node = if delim == MacDelimiter::Brace ||
                               self.token == token::Semi || self.token == token::Eof {
                     StmtKind::Mac(P((mac, style, attrs.into())))
                 }
@@ -4438,7 +4448,7 @@ fn parse_stmt_without_recovery(&mut self,
                     node: StmtKind::Item({
                         self.mk_item(
                             span, id /*id is good here*/,
-                            ItemKind::Mac(respan(span, Mac_ { path: pth, tts: tts })),
+                            ItemKind::Mac(respan(span, Mac_ { path: pth, tts, delim })),
                             respan(lo, VisibilityKind::Inherited),
                             attrs)
                     }),
@@ -6871,7 +6881,7 @@ fn parse_macro_use_or_failure(
             };
             // eat a matched-delimiter token tree:
             let (delim, tts) = self.expect_delimited_token_tree()?;
-            if delim != token::Brace {
+            if delim != MacDelimiter::Brace {
                 if !self.eat(&token::Semi) {
                     self.span_err(self.prev_span,
                                   "macros that expand to items must either \
@@ -6881,7 +6891,7 @@ fn parse_macro_use_or_failure(
             }
 
             let hi = self.prev_span;
-            let mac = respan(mac_lo.to(hi), Mac_ { path: pth, tts: tts });
+            let mac = respan(mac_lo.to(hi), Mac_ { path: pth, tts, delim });
             let item = self.mk_item(lo.to(hi), id, ItemKind::Mac(mac), visibility, attrs);
             return Ok(Some(item));
         }
@@ -6925,11 +6935,11 @@ fn parse_assoc_macro_invoc(&mut self, item_kind: &str, vis: Option<&Visibility>,
 
             // eat a matched-delimiter token tree:
             let (delim, tts) = self.expect_delimited_token_tree()?;
-            if delim != token::Brace {
+            if delim != MacDelimiter::Brace {
                 self.expect(&token::Semi)?
             }
 
-            Ok(Some(respan(lo.to(self.prev_span), Mac_ { path: pth, tts: tts })))
+            Ok(Some(respan(lo.to(self.prev_span), Mac_ { path: pth, tts, delim })))
         } else {
             Ok(None)
         }
index be3408ce565992ef26abdf204ffd5bfdc7aab780..585d49d7076c48b297fba5c5afa4b4ed52ab606b 100644 (file)
@@ -13,7 +13,7 @@
 use rustc_target::spec::abi::{self, Abi};
 use ast::{self, BlockCheckMode, PatKind, RangeEnd, RangeSyntax};
 use ast::{SelfKind, RegionTyParamBound, TraitTyParamBound, TraitBoundModifier};
-use ast::Attribute;
+use ast::{Attribute, MacDelimiter};
 use util::parser::{self, AssocOp, Fixity};
 use attr;
 use codemap::{self, CodeMap};
@@ -422,7 +422,7 @@ pub fn arg_to_string(arg: &ast::Arg) -> String {
 }
 
 pub fn mac_to_string(arg: &ast::Mac) -> String {
-    to_string(|s| s.print_mac(arg, ::parse::token::Paren))
+    to_string(|s| s.print_mac(arg))
 }
 
 pub fn foreign_item_to_string(arg: &ast::ForeignItem) -> String {
@@ -1098,7 +1098,7 @@ pub fn print_type(&mut self, ty: &ast::Ty) -> io::Result<()> {
                 self.s.word("Self")?;
             }
             ast::TyKind::Mac(ref m) => {
-                self.print_mac(m, token::Paren)?;
+                self.print_mac(m)?;
             }
         }
         self.end()
@@ -1140,8 +1140,11 @@ pub fn print_foreign_item(&mut self,
                 self.end() // end the outer cbox
             }
             ast::ForeignItemKind::Macro(ref m) => {
-                self.print_mac(m, token::Paren)?;
-                self.s.word(";")
+                self.print_mac(m)?;
+                match m.node.delim {
+                    MacDelimiter::Brace => Ok(()),
+                    _ => self.s.word(";")
+                }
             }
         }
     }
@@ -1394,16 +1397,24 @@ pub fn print_item(&mut self, item: &ast::Item) -> io::Result<()> {
                 self.print_where_clause(&generics.where_clause)?;
                 self.s.word(";")?;
             }
-            ast::ItemKind::Mac(codemap::Spanned { ref node, .. }) => {
-                self.print_path(&node.path, false, 0)?;
-                self.s.word("! ")?;
-                self.print_ident(item.ident)?;
-                self.cbox(INDENT_UNIT)?;
-                self.popen()?;
-                self.print_tts(node.stream())?;
-                self.pclose()?;
-                self.s.word(";")?;
-                self.end()?;
+            ast::ItemKind::Mac(ref mac) => {
+                if item.ident.name == keywords::Invalid.name() {
+                    self.print_mac(mac)?;
+                    match mac.node.delim {
+                        MacDelimiter::Brace => {}
+                        _ => self.s.word(";")?,
+                    }
+                } else {
+                    self.print_path(&mac.node.path, false, 0)?;
+                    self.s.word("! ")?;
+                    self.print_ident(item.ident)?;
+                    self.cbox(INDENT_UNIT)?;
+                    self.popen()?;
+                    self.print_tts(mac.node.stream())?;
+                    self.pclose()?;
+                    self.s.word(";")?;
+                    self.end()?;
+                }
             }
             ast::ItemKind::MacroDef(ref tts) => {
                 self.s.word("macro_rules! ")?;
@@ -1609,16 +1620,12 @@ pub fn print_trait_item(&mut self, ti: &ast::TraitItem)
                 self.print_associated_type(ti.ident, Some(bounds),
                                            default.as_ref().map(|ty| &**ty))?;
             }
-            ast::TraitItemKind::Macro(codemap::Spanned { ref node, .. }) => {
-                // code copied from ItemKind::Mac:
-                self.print_path(&node.path, false, 0)?;
-                self.s.word("! ")?;
-                self.cbox(INDENT_UNIT)?;
-                self.popen()?;
-                self.print_tts(node.stream())?;
-                self.pclose()?;
-                self.s.word(";")?;
-                self.end()?
+            ast::TraitItemKind::Macro(ref mac) => {
+                self.print_mac(mac)?;
+                match mac.node.delim {
+                    MacDelimiter::Brace => {}
+                    _ => self.s.word(";")?,
+                }
             }
         }
         self.ann.post(self, NodeSubItem(ti.id))
@@ -1643,16 +1650,12 @@ pub fn print_impl_item(&mut self, ii: &ast::ImplItem) -> io::Result<()> {
             ast::ImplItemKind::Type(ref ty) => {
                 self.print_associated_type(ii.ident, None, Some(ty))?;
             }
-            ast::ImplItemKind::Macro(codemap::Spanned { ref node, .. }) => {
-                // code copied from ItemKind::Mac:
-                self.print_path(&node.path, false, 0)?;
-                self.s.word("! ")?;
-                self.cbox(INDENT_UNIT)?;
-                self.popen()?;
-                self.print_tts(node.stream())?;
-                self.pclose()?;
-                self.s.word(";")?;
-                self.end()?
+            ast::ImplItemKind::Macro(ref mac) => {
+                self.print_mac(mac)?;
+                match mac.node.delim {
+                    MacDelimiter::Brace => {}
+                    _ => self.s.word(";")?,
+                }
             }
         }
         self.ann.post(self, NodeSubItem(ii.id))
@@ -1695,11 +1698,7 @@ pub fn print_stmt(&mut self, st: &ast::Stmt) -> io::Result<()> {
                 let (ref mac, style, ref attrs) = **mac;
                 self.space_if_not_bol()?;
                 self.print_outer_attributes(attrs)?;
-                let delim = match style {
-                    ast::MacStmtStyle::Braces => token::Brace,
-                    _ => token::Paren
-                };
-                self.print_mac(mac, delim)?;
+                self.print_mac(mac)?;
                 if style == ast::MacStmtStyle::Semicolon {
                     self.s.word(";")?;
                 }
@@ -1829,25 +1828,22 @@ pub fn print_if_let(&mut self, pats: &[P<ast::Pat>], expr: &ast::Expr, blk: &ast
         self.print_else(elseopt)
     }
 
-    pub fn print_mac(&mut self, m: &ast::Mac, delim: token::DelimToken)
-                     -> io::Result<()> {
+    pub fn print_mac(&mut self, m: &ast::Mac) -> io::Result<()> {
         self.print_path(&m.node.path, false, 0)?;
         self.s.word("!")?;
-        match delim {
-            token::Paren => self.popen()?,
-            token::Bracket => self.s.word("[")?,
-            token::Brace => {
+        match m.node.delim {
+            MacDelimiter::Parenthesis => self.popen()?,
+            MacDelimiter::Bracket => self.s.word("[")?,
+            MacDelimiter::Brace => {
                 self.head("")?;
                 self.bopen()?;
             }
-            token::NoDelim => {}
         }
         self.print_tts(m.node.stream())?;
-        match delim {
-            token::Paren => self.pclose(),
-            token::Bracket => self.s.word("]"),
-            token::Brace => self.bclose(m.span),
-            token::NoDelim => Ok(()),
+        match m.node.delim {
+            MacDelimiter::Parenthesis => self.pclose(),
+            MacDelimiter::Bracket => self.s.word("]"),
+            MacDelimiter::Brace => self.bclose(m.span),
         }
     }
 
@@ -2333,7 +2329,7 @@ fn print_expr_outer_attr_style(&mut self,
 
                 self.pclose()?;
             }
-            ast::ExprKind::Mac(ref m) => self.print_mac(m, token::Paren)?,
+            ast::ExprKind::Mac(ref m) => self.print_mac(m)?,
             ast::ExprKind::Paren(ref e) => {
                 self.popen()?;
                 self.print_inner_attributes_inline(attrs)?;
@@ -2660,7 +2656,7 @@ pub fn print_pat(&mut self, pat: &ast::Pat) -> io::Result<()> {
                 self.print_pat(inner)?;
                 self.pclose()?;
             }
-            PatKind::Mac(ref m) => self.print_mac(m, token::Paren)?,
+            PatKind::Mac(ref m) => self.print_mac(m)?,
         }
         self.ann.post(self, NodePat(pat))
     }
index 754f04a26e7ee038ed2eeaa5186841e6ae0850fd..fe4d599d8242633a34ffd173f04adcf331ab4214 100644 (file)
@@ -53,6 +53,7 @@ pub fn expand_assert<'cx>(
                 ),
             )).into()
         },
+        delim: MacDelimiter::Parenthesis,
     };
     let if_expr = cx.expr_if(
         sp,
diff --git a/src/test/ui-fulldeps/proc-macro/auxiliary/macro-brackets.rs b/src/test/ui-fulldeps/proc-macro/auxiliary/macro-brackets.rs
new file mode 100644 (file)
index 0000000..ab1cfe1
--- /dev/null
@@ -0,0 +1,22 @@
+// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// no-prefer-dynamic
+
+#![crate_type = "proc-macro"]
+#![feature(proc_macro)]
+
+extern crate proc_macro;
+use proc_macro::*;
+
+#[proc_macro_attribute]
+pub fn doit(_: TokenStream, input: TokenStream) -> TokenStream {
+    input.into_iter().collect()
+}
diff --git a/src/test/ui-fulldeps/proc-macro/macro-brackets.rs b/src/test/ui-fulldeps/proc-macro/macro-brackets.rs
new file mode 100644 (file)
index 0000000..cb734e2
--- /dev/null
@@ -0,0 +1,26 @@
+// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// aux-build:macro-brackets.rs
+
+#![feature(proc_macro)]
+
+extern crate macro_brackets as bar;
+use bar::doit;
+
+macro_rules! id {
+    ($($t:tt)*) => ($($t)*)
+}
+
+#[doit]
+id![static X: u32 = 'a';]; //~ ERROR: mismatched types
+
+
+fn main() {}
diff --git a/src/test/ui-fulldeps/proc-macro/macro-brackets.stderr b/src/test/ui-fulldeps/proc-macro/macro-brackets.stderr
new file mode 100644 (file)
index 0000000..1f31a03
--- /dev/null
@@ -0,0 +1,9 @@
+error[E0308]: mismatched types
+  --> $DIR/macro-brackets.rs:23:21
+   |
+LL | id![static X: u32 = 'a';]; //~ ERROR: mismatched types
+   |                     ^^^ expected u32, found char
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0308`.