diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs index 0ce9763ded8bf..8991398ae4473 100644 --- a/src/libsyntax/ast.rs +++ b/src/libsyntax/ast.rs @@ -1239,9 +1239,17 @@ pub type Mac = Spanned; #[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() diff --git a/src/libsyntax/ext/placeholders.rs b/src/libsyntax/ext/placeholders.rs index 9f60882ca29fc..5c1c661fffd37 100644 --- a/src/libsyntax/ext/placeholders.rs +++ b/src/libsyntax/ext/placeholders.rs @@ -27,6 +27,7 @@ pub fn placeholder(kind: ExpansionKind, id: ast::NodeId) -> Expansion { dummy_spanned(ast::Mac_ { path: ast::Path { span: DUMMY_SP, segments: Vec::new() }, tts: TokenStream::empty().into(), + delim: ast::MacDelimiter::Brace, }) } diff --git a/src/libsyntax/fold.rs b/src/libsyntax/fold.rs index 28fb95f165fde..190fef2a9972f 100644 --- a/src/libsyntax/fold.rs +++ b/src/libsyntax/fold.rs @@ -520,6 +520,7 @@ pub fn noop_fold_mac(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) } diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index 729ad491fd544..7cfb34fab8468 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, Mac_}; +use ast::{Mac, Mac_, MacDelimiter}; use ast::{MutTy, Mutability}; use ast::{Pat, PatKind, PathSegment}; use ast::{PolyTraitRef, QSelf}; @@ -1611,8 +1611,9 @@ impl<'a> Parser<'a> { 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 @@ impl<'a> Parser<'a> { }) } - 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 @@ impl<'a> Parser<'a> { // `!`, 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 @@ impl<'a> Parser<'a> { 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 @@ impl<'a> Parser<'a> { 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 @@ impl<'a> Parser<'a> { // 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 @@ impl<'a> Parser<'a> { 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 @@ impl<'a> Parser<'a> { 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 @@ impl<'a> Parser<'a> { }; // 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 @@ impl<'a> Parser<'a> { } 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 @@ impl<'a> Parser<'a> { // 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) } diff --git a/src/libsyntax/print/pprust.rs b/src/libsyntax/print/pprust.rs index be3408ce56599..585d49d7076c4 100644 --- a/src/libsyntax/print/pprust.rs +++ b/src/libsyntax/print/pprust.rs @@ -13,7 +13,7 @@ pub use self::AnnNode::*; 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 @@ impl<'a> State<'a> { 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 @@ impl<'a> State<'a> { 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 @@ impl<'a> State<'a> { 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 @@ impl<'a> State<'a> { 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 @@ impl<'a> State<'a> { 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 @@ impl<'a> State<'a> { 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 @@ impl<'a> State<'a> { 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 @@ impl<'a> State<'a> { 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 @@ impl<'a> State<'a> { 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)) } diff --git a/src/libsyntax_ext/assert.rs b/src/libsyntax_ext/assert.rs index 754f04a26e7ee..fe4d599d82426 100644 --- a/src/libsyntax_ext/assert.rs +++ b/src/libsyntax_ext/assert.rs @@ -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 index 0000000000000..ab1cfe1dbd67b --- /dev/null +++ b/src/test/ui-fulldeps/proc-macro/auxiliary/macro-brackets.rs @@ -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 or the MIT license +// , 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 index 0000000000000..cb734e2d10b7f --- /dev/null +++ b/src/test/ui-fulldeps/proc-macro/macro-brackets.rs @@ -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 or the MIT license +// , 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 index 0000000000000..1f31a03491311 --- /dev/null +++ b/src/test/ui-fulldeps/proc-macro/macro-brackets.stderr @@ -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`.