1
Fork 0

rustc: Correctly pretty-print macro delimiters

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
This commit is contained in:
Alex Crichton 2018-05-22 08:01:21 -07:00
parent ff8fa5cc69
commit a137d00ce5
9 changed files with 156 additions and 82 deletions

View file

@ -1239,9 +1239,17 @@ pub type Mac = Spanned<Mac_>;
#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)] #[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)]
pub struct Mac_ { pub struct Mac_ {
pub path: Path, pub path: Path,
pub delim: MacDelimiter,
pub tts: ThinTokenStream, pub tts: ThinTokenStream,
} }
#[derive(Copy, Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)]
pub enum MacDelimiter {
Parenthesis,
Bracket,
Brace,
}
impl Mac_ { impl Mac_ {
pub fn stream(&self) -> TokenStream { pub fn stream(&self) -> TokenStream {
self.tts.clone().into() self.tts.clone().into()

View file

@ -27,6 +27,7 @@ pub fn placeholder(kind: ExpansionKind, id: ast::NodeId) -> Expansion {
dummy_spanned(ast::Mac_ { dummy_spanned(ast::Mac_ {
path: ast::Path { span: DUMMY_SP, segments: Vec::new() }, path: ast::Path { span: DUMMY_SP, segments: Vec::new() },
tts: TokenStream::empty().into(), tts: TokenStream::empty().into(),
delim: ast::MacDelimiter::Brace,
}) })
} }

View file

@ -520,6 +520,7 @@ pub fn noop_fold_mac<T: Folder>(Spanned {node, span}: Mac, fld: &mut T) -> Mac {
node: Mac_ { node: Mac_ {
tts: fld.fold_tts(node.stream()).into(), tts: fld.fold_tts(node.stream()).into(),
path: fld.fold_path(node.path), path: fld.fold_path(node.path),
delim: node.delim,
}, },
span: fld.new_span(span) span: fld.new_span(span)
} }

View file

@ -26,7 +26,7 @@ use ast::{Ident, ImplItem, IsAuto, Item, ItemKind};
use ast::{Label, Lifetime, LifetimeDef, Lit, LitKind, UintTy}; use ast::{Label, Lifetime, LifetimeDef, Lit, LitKind, UintTy};
use ast::Local; use ast::Local;
use ast::MacStmtStyle; use ast::MacStmtStyle;
use ast::{Mac, Mac_}; use ast::{Mac, Mac_, MacDelimiter};
use ast::{MutTy, Mutability}; use ast::{MutTy, Mutability};
use ast::{Pat, PatKind, PathSegment}; use ast::{Pat, PatKind, PathSegment};
use ast::{PolyTraitRef, QSelf}; use ast::{PolyTraitRef, QSelf};
@ -1611,8 +1611,9 @@ impl<'a> Parser<'a> {
let path = self.parse_path(PathStyle::Type)?; let path = self.parse_path(PathStyle::Type)?;
if self.eat(&token::Not) { if self.eat(&token::Not) {
// Macro invocation in type position // Macro invocation in type position
let (_, tts) = self.expect_delimited_token_tree()?; let (delim, tts) = self.expect_delimited_token_tree()?;
TyKind::Mac(respan(lo.to(self.prev_span), Mac_ { path: path, tts: tts })) let node = Mac_ { path, tts, delim };
TyKind::Mac(respan(lo.to(self.prev_span), node))
} else { } else {
// Just a type path or bound list (trait object type) starting with a trait. // Just a type path or bound list (trait object type) starting with a trait.
// `Type` // `Type`
@ -2181,19 +2182,27 @@ impl<'a> Parser<'a> {
}) })
} }
fn expect_delimited_token_tree(&mut self) -> PResult<'a, (token::DelimToken, ThinTokenStream)> { fn expect_delimited_token_tree(&mut self) -> PResult<'a, (MacDelimiter, ThinTokenStream)> {
match self.token { let delim = match self.token {
token::OpenDelim(delim) => match self.parse_token_tree() { token::OpenDelim(delim) => delim,
TokenTree::Delimited(_, delimited) => Ok((delim, delimited.stream().into())),
_ => unreachable!(),
},
_ => { _ => {
let msg = "expected open delimiter"; let msg = "expected open delimiter";
let mut err = self.fatal(msg); let mut err = self.fatal(msg);
err.span_label(self.span, 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, /// At the bottom (top?) of the precedence hierarchy,
@ -2406,9 +2415,10 @@ impl<'a> Parser<'a> {
// `!`, as an operator, is prefix, so we know this isn't that // `!`, as an operator, is prefix, so we know this isn't that
if self.eat(&token::Not) { if self.eat(&token::Not) {
// MACRO INVOCATION expression // MACRO INVOCATION expression
let (_, tts) = self.expect_delimited_token_tree()?; let (delim, tts) = self.expect_delimited_token_tree()?;
let hi = self.prev_span; 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)) { if self.check(&token::OpenDelim(token::Brace)) {
// This is a struct literal, unless we're prohibited // This is a struct literal, unless we're prohibited
@ -3881,8 +3891,8 @@ impl<'a> Parser<'a> {
token::Not if qself.is_none() => { token::Not if qself.is_none() => {
// Parse macro invocation // Parse macro invocation
self.bump(); self.bump();
let (_, tts) = self.expect_delimited_token_tree()?; let (delim, tts) = self.expect_delimited_token_tree()?;
let mac = respan(lo.to(self.prev_span), Mac_ { path: path, tts: tts }); let mac = respan(lo.to(self.prev_span), Mac_ { path, tts, delim });
pat = PatKind::Mac(mac); pat = PatKind::Mac(mac);
} }
token::DotDotDot | token::DotDotEq | token::DotDot => { token::DotDotDot | token::DotDotEq | token::DotDot => {
@ -4275,7 +4285,7 @@ impl<'a> Parser<'a> {
let ident = self.parse_ident()?; let ident = self.parse_ident()?;
let (delim, tokens) = self.expect_delimited_token_tree()?; let (delim, tokens) = self.expect_delimited_token_tree()?;
if delim != token::Brace { if delim != MacDelimiter::Brace {
if !self.eat(&token::Semi) { if !self.eat(&token::Semi) {
let msg = "macros that expand to items must either \ let msg = "macros that expand to items must either \
be surrounded with braces or followed by a semicolon"; be surrounded with braces or followed by a semicolon";
@ -4360,8 +4370,8 @@ impl<'a> Parser<'a> {
// check that we're pointing at delimiters (need to check // check that we're pointing at delimiters (need to check
// again after the `if`, because of `parse_ident` // again after the `if`, because of `parse_ident`
// consuming more tokens). // consuming more tokens).
let delim = match self.token { match self.token {
token::OpenDelim(delim) => delim, token::OpenDelim(_) => {}
_ => { _ => {
// we only expect an ident if we didn't parse one // we only expect an ident if we didn't parse one
// above. // above.
@ -4377,20 +4387,20 @@ impl<'a> Parser<'a> {
err.span_label(self.span, format!("expected {}`(` or `{{`", ident_str)); err.span_label(self.span, format!("expected {}`(` or `{{`", ident_str));
return Err(err) return Err(err)
}, },
}; }
let (_, tts) = self.expect_delimited_token_tree()?; let (delim, tts) = self.expect_delimited_token_tree()?;
let hi = self.prev_span; let hi = self.prev_span;
let style = if delim == token::Brace { let style = if delim == MacDelimiter::Brace {
MacStmtStyle::Braces MacStmtStyle::Braces
} else { } else {
MacStmtStyle::NoBraces MacStmtStyle::NoBraces
}; };
if id.name == keywords::Invalid.name() { if id.name == keywords::Invalid.name() {
let mac = respan(lo.to(hi), Mac_ { path: pth, tts: tts }); let mac = respan(lo.to(hi), Mac_ { path: pth, tts, delim });
let node = if delim == token::Brace || let node = if delim == MacDelimiter::Brace ||
self.token == token::Semi || self.token == token::Eof { self.token == token::Semi || self.token == token::Eof {
StmtKind::Mac(P((mac, style, attrs.into()))) StmtKind::Mac(P((mac, style, attrs.into())))
} }
@ -4438,7 +4448,7 @@ impl<'a> Parser<'a> {
node: StmtKind::Item({ node: StmtKind::Item({
self.mk_item( self.mk_item(
span, id /*id is good here*/, 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), respan(lo, VisibilityKind::Inherited),
attrs) attrs)
}), }),
@ -6871,7 +6881,7 @@ impl<'a> Parser<'a> {
}; };
// eat a matched-delimiter token tree: // eat a matched-delimiter token tree:
let (delim, tts) = self.expect_delimited_token_tree()?; let (delim, tts) = self.expect_delimited_token_tree()?;
if delim != token::Brace { if delim != MacDelimiter::Brace {
if !self.eat(&token::Semi) { if !self.eat(&token::Semi) {
self.span_err(self.prev_span, self.span_err(self.prev_span,
"macros that expand to items must either \ "macros that expand to items must either \
@ -6881,7 +6891,7 @@ impl<'a> Parser<'a> {
} }
let hi = self.prev_span; 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); let item = self.mk_item(lo.to(hi), id, ItemKind::Mac(mac), visibility, attrs);
return Ok(Some(item)); return Ok(Some(item));
} }
@ -6925,11 +6935,11 @@ impl<'a> Parser<'a> {
// eat a matched-delimiter token tree: // eat a matched-delimiter token tree:
let (delim, tts) = self.expect_delimited_token_tree()?; let (delim, tts) = self.expect_delimited_token_tree()?;
if delim != token::Brace { if delim != MacDelimiter::Brace {
self.expect(&token::Semi)? 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 { } else {
Ok(None) Ok(None)
} }

View file

@ -13,7 +13,7 @@ pub use self::AnnNode::*;
use rustc_target::spec::abi::{self, Abi}; use rustc_target::spec::abi::{self, Abi};
use ast::{self, BlockCheckMode, PatKind, RangeEnd, RangeSyntax}; use ast::{self, BlockCheckMode, PatKind, RangeEnd, RangeSyntax};
use ast::{SelfKind, RegionTyParamBound, TraitTyParamBound, TraitBoundModifier}; use ast::{SelfKind, RegionTyParamBound, TraitTyParamBound, TraitBoundModifier};
use ast::Attribute; use ast::{Attribute, MacDelimiter};
use util::parser::{self, AssocOp, Fixity}; use util::parser::{self, AssocOp, Fixity};
use attr; use attr;
use codemap::{self, CodeMap}; 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 { 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 { pub fn foreign_item_to_string(arg: &ast::ForeignItem) -> String {
@ -1098,7 +1098,7 @@ impl<'a> State<'a> {
self.s.word("Self")?; self.s.word("Self")?;
} }
ast::TyKind::Mac(ref m) => { ast::TyKind::Mac(ref m) => {
self.print_mac(m, token::Paren)?; self.print_mac(m)?;
} }
} }
self.end() self.end()
@ -1140,8 +1140,11 @@ impl<'a> State<'a> {
self.end() // end the outer cbox self.end() // end the outer cbox
} }
ast::ForeignItemKind::Macro(ref m) => { ast::ForeignItemKind::Macro(ref m) => {
self.print_mac(m, token::Paren)?; self.print_mac(m)?;
self.s.word(";") match m.node.delim {
MacDelimiter::Brace => Ok(()),
_ => self.s.word(";")
}
} }
} }
} }
@ -1394,16 +1397,24 @@ impl<'a> State<'a> {
self.print_where_clause(&generics.where_clause)?; self.print_where_clause(&generics.where_clause)?;
self.s.word(";")?; self.s.word(";")?;
} }
ast::ItemKind::Mac(codemap::Spanned { ref node, .. }) => { ast::ItemKind::Mac(ref mac) => {
self.print_path(&node.path, false, 0)?; if item.ident.name == keywords::Invalid.name() {
self.s.word("! ")?; self.print_mac(mac)?;
self.print_ident(item.ident)?; match mac.node.delim {
self.cbox(INDENT_UNIT)?; MacDelimiter::Brace => {}
self.popen()?; _ => self.s.word(";")?,
self.print_tts(node.stream())?; }
self.pclose()?; } else {
self.s.word(";")?; self.print_path(&mac.node.path, false, 0)?;
self.end()?; 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) => { ast::ItemKind::MacroDef(ref tts) => {
self.s.word("macro_rules! ")?; self.s.word("macro_rules! ")?;
@ -1609,16 +1620,12 @@ impl<'a> State<'a> {
self.print_associated_type(ti.ident, Some(bounds), self.print_associated_type(ti.ident, Some(bounds),
default.as_ref().map(|ty| &**ty))?; default.as_ref().map(|ty| &**ty))?;
} }
ast::TraitItemKind::Macro(codemap::Spanned { ref node, .. }) => { ast::TraitItemKind::Macro(ref mac) => {
// code copied from ItemKind::Mac: self.print_mac(mac)?;
self.print_path(&node.path, false, 0)?; match mac.node.delim {
self.s.word("! ")?; MacDelimiter::Brace => {}
self.cbox(INDENT_UNIT)?; _ => self.s.word(";")?,
self.popen()?; }
self.print_tts(node.stream())?;
self.pclose()?;
self.s.word(";")?;
self.end()?
} }
} }
self.ann.post(self, NodeSubItem(ti.id)) self.ann.post(self, NodeSubItem(ti.id))
@ -1643,16 +1650,12 @@ impl<'a> State<'a> {
ast::ImplItemKind::Type(ref ty) => { ast::ImplItemKind::Type(ref ty) => {
self.print_associated_type(ii.ident, None, Some(ty))?; self.print_associated_type(ii.ident, None, Some(ty))?;
} }
ast::ImplItemKind::Macro(codemap::Spanned { ref node, .. }) => { ast::ImplItemKind::Macro(ref mac) => {
// code copied from ItemKind::Mac: self.print_mac(mac)?;
self.print_path(&node.path, false, 0)?; match mac.node.delim {
self.s.word("! ")?; MacDelimiter::Brace => {}
self.cbox(INDENT_UNIT)?; _ => self.s.word(";")?,
self.popen()?; }
self.print_tts(node.stream())?;
self.pclose()?;
self.s.word(";")?;
self.end()?
} }
} }
self.ann.post(self, NodeSubItem(ii.id)) self.ann.post(self, NodeSubItem(ii.id))
@ -1695,11 +1698,7 @@ impl<'a> State<'a> {
let (ref mac, style, ref attrs) = **mac; let (ref mac, style, ref attrs) = **mac;
self.space_if_not_bol()?; self.space_if_not_bol()?;
self.print_outer_attributes(attrs)?; self.print_outer_attributes(attrs)?;
let delim = match style { self.print_mac(mac)?;
ast::MacStmtStyle::Braces => token::Brace,
_ => token::Paren
};
self.print_mac(mac, delim)?;
if style == ast::MacStmtStyle::Semicolon { if style == ast::MacStmtStyle::Semicolon {
self.s.word(";")?; self.s.word(";")?;
} }
@ -1829,25 +1828,22 @@ impl<'a> State<'a> {
self.print_else(elseopt) self.print_else(elseopt)
} }
pub fn print_mac(&mut self, m: &ast::Mac, delim: token::DelimToken) pub fn print_mac(&mut self, m: &ast::Mac) -> io::Result<()> {
-> io::Result<()> {
self.print_path(&m.node.path, false, 0)?; self.print_path(&m.node.path, false, 0)?;
self.s.word("!")?; self.s.word("!")?;
match delim { match m.node.delim {
token::Paren => self.popen()?, MacDelimiter::Parenthesis => self.popen()?,
token::Bracket => self.s.word("[")?, MacDelimiter::Bracket => self.s.word("[")?,
token::Brace => { MacDelimiter::Brace => {
self.head("")?; self.head("")?;
self.bopen()?; self.bopen()?;
} }
token::NoDelim => {}
} }
self.print_tts(m.node.stream())?; self.print_tts(m.node.stream())?;
match delim { match m.node.delim {
token::Paren => self.pclose(), MacDelimiter::Parenthesis => self.pclose(),
token::Bracket => self.s.word("]"), MacDelimiter::Bracket => self.s.word("]"),
token::Brace => self.bclose(m.span), MacDelimiter::Brace => self.bclose(m.span),
token::NoDelim => Ok(()),
} }
} }
@ -2333,7 +2329,7 @@ impl<'a> State<'a> {
self.pclose()?; 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) => { ast::ExprKind::Paren(ref e) => {
self.popen()?; self.popen()?;
self.print_inner_attributes_inline(attrs)?; self.print_inner_attributes_inline(attrs)?;
@ -2660,7 +2656,7 @@ impl<'a> State<'a> {
self.print_pat(inner)?; self.print_pat(inner)?;
self.pclose()?; 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)) self.ann.post(self, NodePat(pat))
} }

View file

@ -53,6 +53,7 @@ pub fn expand_assert<'cx>(
), ),
)).into() )).into()
}, },
delim: MacDelimiter::Parenthesis,
}; };
let if_expr = cx.expr_if( let if_expr = cx.expr_if(
sp, sp,

View file

@ -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()
}

View file

@ -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() {}

View file

@ -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`.