diff options
| author | Vadim Petrochenkov <vadim.petrochenkov@gmail.com> | 2019-07-01 01:08:49 +0300 |
|---|---|---|
| committer | Vadim Petrochenkov <vadim.petrochenkov@gmail.com> | 2019-07-01 12:20:54 +0300 |
| commit | 3f39dc1b9095bf3808e45a8ff9afc6b9a4d8e9a3 (patch) | |
| tree | 9ead154fd184181baa7895f7c948ecc4129c8bc0 | |
| parent | 5748825cc8c74cccef0059cdd4043e6e9b4aa188 (diff) | |
| download | rust-3f39dc1b9095bf3808e45a8ff9afc6b9a4d8e9a3.tar.gz rust-3f39dc1b9095bf3808e45a8ff9afc6b9a4d8e9a3.zip | |
syntax: Unsupport `foo! bar { ... }` macros in the parser
Unreserve `macro_rules` as a macro name
| -rw-r--r-- | src/librustc_plugin/registry.rs | 5 | ||||
| -rw-r--r-- | src/librustc_resolve/macros.rs | 3 | ||||
| -rw-r--r-- | src/libsyntax/ext/expand.rs | 45 | ||||
| -rw-r--r-- | src/libsyntax/parse/parser.rs | 129 | ||||
| -rw-r--r-- | src/test/run-pass/rfcs/rfc-2151-raw-identifiers/macros.rs | 2 | ||||
| -rw-r--r-- | src/test/ui/issues/issue-10536.rs | 8 | ||||
| -rw-r--r-- | src/test/ui/issues/issue-10536.stderr | 38 | ||||
| -rw-r--r-- | src/test/ui/parser/macro-bad-delimiter-ident.rs | 2 | ||||
| -rw-r--r-- | src/test/ui/parser/macro-bad-delimiter-ident.stderr | 6 | ||||
| -rw-r--r-- | src/test/ui/user-defined-macro-rules.rs | 10 | ||||
| -rw-r--r-- | src/test/ui/user-defined-macro-rules.stderr | 8 |
11 files changed, 70 insertions, 186 deletions
diff --git a/src/librustc_plugin/registry.rs b/src/librustc_plugin/registry.rs index 16d484e2a98..640662d7733 100644 --- a/src/librustc_plugin/registry.rs +++ b/src/librustc_plugin/registry.rs @@ -6,7 +6,7 @@ use rustc::util::nodemap::FxHashMap; use syntax::ext::base::{SyntaxExtension, SyntaxExtensionKind, NamedSyntaxExtension}; use syntax::ext::base::MacroExpanderFn; -use syntax::symbol::{Symbol, sym}; +use syntax::symbol::Symbol; use syntax::ast; use syntax::feature_gate::AttributeType; use syntax_pos::Span; @@ -85,9 +85,6 @@ impl<'a> Registry<'a> { /// /// This is the most general hook into `libsyntax`'s expansion behavior. pub fn register_syntax_extension(&mut self, name: ast::Name, mut extension: SyntaxExtension) { - if name == sym::macro_rules { - panic!("user-defined macros may not be named `macro_rules`"); - } if extension.def_info.is_none() { extension.def_info = Some((ast::CRATE_NODE_ID, self.krate_span)); } diff --git a/src/librustc_resolve/macros.rs b/src/librustc_resolve/macros.rs index 392a46a262f..68e842c5e54 100644 --- a/src/librustc_resolve/macros.rs +++ b/src/librustc_resolve/macros.rs @@ -1109,9 +1109,6 @@ impl<'a> Resolver<'a> { current_legacy_scope: &mut LegacyScope<'a>) { self.local_macro_def_scopes.insert(item.id, self.current_module); let ident = item.ident; - if ident.name == sym::macro_rules { - self.session.span_err(item.span, "user-defined macros may not be named `macro_rules`"); - } let def_id = self.definitions.local_def_id(item.id); let ext = Lrc::new(macro_rules::compile(&self.session.parse_sess, diff --git a/src/libsyntax/ext/expand.rs b/src/libsyntax/ext/expand.rs index 5473f55aa33..f7a4ae98d67 100644 --- a/src/libsyntax/ext/expand.rs +++ b/src/libsyntax/ext/expand.rs @@ -13,8 +13,7 @@ use crate::parse::{DirectoryOwnership, PResult, ParseSess}; use crate::parse::token; use crate::parse::parser::Parser; use crate::ptr::P; -use crate::symbol::Symbol; -use crate::symbol::{kw, sym}; +use crate::symbol::{sym, Symbol}; use crate::tokenstream::{TokenStream, TokenTree}; use crate::visit::{self, Visitor}; use crate::util::map_in_place::MapInPlace; @@ -197,7 +196,6 @@ pub struct Invocation { pub enum InvocationKind { Bang { mac: ast::Mac, - ident: Option<Ident>, span: Span, }, Attr { @@ -664,13 +662,12 @@ impl<'a, 'b> MacroExpander<'a, 'b> { ext: &SyntaxExtension) -> Option<AstFragment> { let kind = invoc.fragment_kind; - let (mac, ident, span) = match invoc.kind { - InvocationKind::Bang { mac, ident, span } => (mac, ident, span), + let (mac, span) = match invoc.kind { + InvocationKind::Bang { mac, span } => (mac, span), _ => unreachable!(), }; let path = &mac.node.path; - let ident = ident.unwrap_or_else(|| Ident::invalid()); let validate = |this: &mut Self| { // feature-gate the macro invocation if let Some((feature, issue)) = ext.unstable_feature { @@ -690,12 +687,6 @@ impl<'a, 'b> MacroExpander<'a, 'b> { } } - if ident.name != kw::Invalid { - let msg = format!("macro {}! expects no ident argument, given '{}'", path, ident); - this.cx.span_err(path.span, &msg); - this.cx.trace_macros_diag(); - return Err(kind.dummy(span)); - } Ok(()) }; @@ -729,19 +720,11 @@ impl<'a, 'b> MacroExpander<'a, 'b> { } SyntaxExtensionKind::Bang(expander) => { - if ident.name != kw::Invalid { - let msg = - format!("macro {}! expects no ident argument, given '{}'", path, ident); - self.cx.span_err(path.span, &msg); - self.cx.trace_macros_diag(); - kind.dummy(span) - } else { - self.gate_proc_macro_expansion_kind(span, kind); - let tok_result = expander.expand(self.cx, span, mac.node.stream()); - let result = self.parse_ast_fragment(tok_result, kind, path, span); - self.gate_proc_macro_expansion(span, &result); - result - } + self.gate_proc_macro_expansion_kind(span, kind); + let tok_result = expander.expand(self.cx, span, mac.node.stream()); + let result = self.parse_ast_fragment(tok_result, kind, path, span); + self.gate_proc_macro_expansion(span, &result); + result } }; @@ -944,7 +927,7 @@ impl<'a, 'b> InvocationCollector<'a, 'b> { } fn collect_bang(&mut self, mac: ast::Mac, span: Span, kind: AstFragmentKind) -> AstFragment { - self.collect(kind, InvocationKind::Bang { mac, ident: None, span }) + self.collect(kind, InvocationKind::Bang { mac, span }) } fn collect_attr(&mut self, @@ -1179,13 +1162,9 @@ impl<'a, 'b> MutVisitor for InvocationCollector<'a, 'b> { ast::ItemKind::Mac(..) => { self.check_attributes(&item.attrs); item.and_then(|item| match item.node { - ItemKind::Mac(mac) => { - self.collect(AstFragmentKind::Items, InvocationKind::Bang { - mac, - ident: Some(item.ident), - span: item.span, - }).make_items() - } + ItemKind::Mac(mac) => self.collect( + AstFragmentKind::Items, InvocationKind::Bang { mac, span: item.span } + ).make_items(), _ => unreachable!(), }) } diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index fc206580e38..cbecdb0738b 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -4353,8 +4353,9 @@ impl<'a> Parser<'a> { (ident, ast::MacroDef { tokens: tokens.into(), legacy: false }) } - token::Ident(name, _) if name == sym::macro_rules && - self.look_ahead(1, |t| *t == token::Not) => { + token::Ident(name, false) if name == sym::macro_rules && + self.look_ahead(1, |t| *t == token::Not) && + self.look_ahead(2, |t| t.is_ident()) => { let prev_span = self.prev_span; self.complain_if_pub_macro(&vis.node, prev_span); self.bump(); @@ -4434,34 +4435,6 @@ impl<'a> Parser<'a> { })); } - // it's a macro invocation - let id = match self.token.kind { - token::OpenDelim(_) => Ident::invalid(), // no special identifier - _ => self.parse_ident()?, - }; - - // check that we're pointing at delimiters (need to check - // again after the `if`, because of `parse_ident` - // consuming more tokens). - match self.token.kind { - token::OpenDelim(_) => {} - _ => { - // we only expect an ident if we didn't parse one - // above. - let ident_str = if id.name == kw::Invalid { - "identifier, " - } else { - "" - }; - let tok_str = self.this_token_descr(); - let mut err = self.fatal(&format!("expected {}`(` or `{{`, found {}", - ident_str, - tok_str)); - err.span_label(self.token.span, format!("expected {}`(` or `{{`", ident_str)); - return Err(err) - }, - } - let (delim, tts) = self.expect_delimited_token_tree()?; let hi = self.prev_span; @@ -4471,59 +4444,38 @@ impl<'a> Parser<'a> { MacStmtStyle::NoBraces }; - if id.name == kw::Invalid { - 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()))) - } - // We used to incorrectly stop parsing macro-expanded statements here. - // If the next token will be an error anyway but could have parsed with the - // earlier behavior, stop parsing here and emit a warning to avoid breakage. - else if macro_legacy_warnings && - self.token.can_begin_expr() && - match self.token.kind { - // These can continue an expression, so we can't stop parsing and warn. - token::OpenDelim(token::Paren) | token::OpenDelim(token::Bracket) | - token::BinOp(token::Minus) | token::BinOp(token::Star) | - token::BinOp(token::And) | token::BinOp(token::Or) | - token::AndAnd | token::OrOr | - token::DotDot | token::DotDotDot | token::DotDotEq => false, - _ => true, - } { - self.warn_missing_semicolon(); - StmtKind::Mac(P((mac, style, attrs.into()))) - } else { - let e = self.mk_expr(mac.span, ExprKind::Mac(mac), ThinVec::new()); - let e = self.maybe_recover_from_bad_qpath(e, true)?; - let e = self.parse_dot_or_call_expr_with(e, lo, attrs.into())?; - let e = self.parse_assoc_expr_with(0, LhsExpr::AlreadyParsed(e))?; - StmtKind::Expr(e) - }; - Stmt { - id: ast::DUMMY_NODE_ID, - span: lo.to(hi), - node, - } + 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()))) + } + // We used to incorrectly stop parsing macro-expanded statements here. + // If the next token will be an error anyway but could have parsed with the + // earlier behavior, stop parsing here and emit a warning to avoid breakage. + else if macro_legacy_warnings && + self.token.can_begin_expr() && + match self.token.kind { + // These can continue an expression, so we can't stop parsing and warn. + token::OpenDelim(token::Paren) | token::OpenDelim(token::Bracket) | + token::BinOp(token::Minus) | token::BinOp(token::Star) | + token::BinOp(token::And) | token::BinOp(token::Or) | + token::AndAnd | token::OrOr | + token::DotDot | token::DotDotDot | token::DotDotEq => false, + _ => true, + } { + self.warn_missing_semicolon(); + StmtKind::Mac(P((mac, style, attrs.into()))) } else { - // if it has a special ident, it's definitely an item - // - // Require a semicolon or braces. - if style != MacStmtStyle::Braces && !self.eat(&token::Semi) { - self.report_invalid_macro_expansion_item(); - } - let span = lo.to(hi); - Stmt { - id: ast::DUMMY_NODE_ID, - span, - node: StmtKind::Item({ - self.mk_item( - span, id /*id is good here*/, - ItemKind::Mac(respan(span, Mac_ { path: pth, tts, delim })), - respan(lo, VisibilityKind::Inherited), - attrs) - }), - } + let e = self.mk_expr(mac.span, ExprKind::Mac(mac), ThinVec::new()); + let e = self.maybe_recover_from_bad_qpath(e, true)?; + let e = self.parse_dot_or_call_expr_with(e, lo, attrs.into())?; + let e = self.parse_assoc_expr_with(0, LhsExpr::AlreadyParsed(e))?; + StmtKind::Expr(e) + }; + Stmt { + id: ast::DUMMY_NODE_ID, + span: lo.to(hi), + node, } } else { // FIXME: Bad copy of attrs @@ -7611,16 +7563,6 @@ impl<'a> Parser<'a> { // item macro. let pth = self.parse_path(PathStyle::Mod)?; self.expect(&token::Not)?; - - // a 'special' identifier (like what `macro_rules!` uses) - // is optional. We should eventually unify invoc syntax - // and remove this. - let id = if self.token.is_ident() { - self.parse_ident()? - } else { - Ident::invalid() // no special identifier - }; - // eat a matched-delimiter token tree: let (delim, tts) = self.expect_delimited_token_tree()?; if delim != MacDelimiter::Brace && !self.eat(&token::Semi) { self.report_invalid_macro_expansion_item(); @@ -7628,7 +7570,8 @@ impl<'a> Parser<'a> { let hi = self.prev_span; 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), Ident::invalid(), ItemKind::Mac(mac), visibility, attrs); return Ok(Some(item)); } diff --git a/src/test/run-pass/rfcs/rfc-2151-raw-identifiers/macros.rs b/src/test/run-pass/rfcs/rfc-2151-raw-identifiers/macros.rs index 51a3b46d461..0ab7e17f87b 100644 --- a/src/test/run-pass/rfcs/rfc-2151-raw-identifiers/macros.rs +++ b/src/test/run-pass/rfcs/rfc-2151-raw-identifiers/macros.rs @@ -1,7 +1,7 @@ // run-pass #![feature(decl_macro)] -r#macro_rules! r#struct { +macro_rules! r#struct { ($r#struct:expr) => { $r#struct } } diff --git a/src/test/ui/issues/issue-10536.rs b/src/test/ui/issues/issue-10536.rs index ceb44ecf7f5..111078abb37 100644 --- a/src/test/ui/issues/issue-10536.rs +++ b/src/test/ui/issues/issue-10536.rs @@ -11,13 +11,9 @@ macro_rules! foo{ pub fn main() { foo!(); - assert!({one! two()}); - //~^ ERROR macros that expand to items - //~| ERROR cannot find macro `one!` in this scope - //~| ERROR mismatched types + assert!({one! two()}); //~ ERROR expected open delimiter // regardless of whether nested macro_rules works, the following should at // least throw a conventional error. - assert!({one! two}); - //~^ ERROR expected `(` or `{`, found `}` + assert!({one! two}); //~ ERROR expected open delimiter } diff --git a/src/test/ui/issues/issue-10536.stderr b/src/test/ui/issues/issue-10536.stderr index 584cdf43a8f..73f948107f1 100644 --- a/src/test/ui/issues/issue-10536.stderr +++ b/src/test/ui/issues/issue-10536.stderr @@ -1,38 +1,14 @@ -error: macros that expand to items must be delimited with braces or followed by a semicolon - --> $DIR/issue-10536.rs:14:22 +error: expected open delimiter + --> $DIR/issue-10536.rs:14:19 | LL | assert!({one! two()}); - | ^^ -help: change the delimiters to curly braces - | -LL | assert!({one! two {}}); - | ^^ -help: add a semicolon - | -LL | assert!({one! two();}); - | ^ + | ^^^ expected open delimiter -error: expected `(` or `{`, found `}` - --> $DIR/issue-10536.rs:21:22 +error: expected open delimiter + --> $DIR/issue-10536.rs:18:19 | LL | assert!({one! two}); - | ^ expected `(` or `{` - -error: cannot find macro `one!` in this scope - --> $DIR/issue-10536.rs:14:14 - | -LL | assert!({one! two()}); - | ^^^ - -error[E0308]: mismatched types - --> $DIR/issue-10536.rs:14:13 - | -LL | assert!({one! two()}); - | ^^^^^^^^^^^^ expected bool, found () - | - = note: expected type `bool` - found type `()` + | ^^^ expected open delimiter -error: aborting due to 4 previous errors +error: aborting due to 2 previous errors -For more information about this error, try `rustc --explain E0308`. diff --git a/src/test/ui/parser/macro-bad-delimiter-ident.rs b/src/test/ui/parser/macro-bad-delimiter-ident.rs index 987c955d1dc..13dec95435b 100644 --- a/src/test/ui/parser/macro-bad-delimiter-ident.rs +++ b/src/test/ui/parser/macro-bad-delimiter-ident.rs @@ -1,3 +1,3 @@ fn main() { - foo! bar < //~ ERROR expected `(` or `{`, found `<` + foo! bar < //~ ERROR expected open delimiter } diff --git a/src/test/ui/parser/macro-bad-delimiter-ident.stderr b/src/test/ui/parser/macro-bad-delimiter-ident.stderr index 6a17d39e8bf..e97839a4f4a 100644 --- a/src/test/ui/parser/macro-bad-delimiter-ident.stderr +++ b/src/test/ui/parser/macro-bad-delimiter-ident.stderr @@ -1,8 +1,8 @@ -error: expected `(` or `{`, found `<` - --> $DIR/macro-bad-delimiter-ident.rs:2:14 +error: expected open delimiter + --> $DIR/macro-bad-delimiter-ident.rs:2:10 | LL | foo! bar < - | ^ expected `(` or `{` + | ^^^ expected open delimiter error: aborting due to previous error diff --git a/src/test/ui/user-defined-macro-rules.rs b/src/test/ui/user-defined-macro-rules.rs index 31bfdd025d9..09e071ec454 100644 --- a/src/test/ui/user-defined-macro-rules.rs +++ b/src/test/ui/user-defined-macro-rules.rs @@ -1,5 +1,9 @@ -#![allow(unused_macros)] +// check-pass -macro_rules! macro_rules { () => {} } //~ ERROR user-defined macros may not be named `macro_rules` +macro_rules! macro_rules { () => { struct S; } } // OK -fn main() {} +macro_rules! {} // OK, calls the macro defined above + +fn main() { + let s = S; +} diff --git a/src/test/ui/user-defined-macro-rules.stderr b/src/test/ui/user-defined-macro-rules.stderr deleted file mode 100644 index 057515228e0..00000000000 --- a/src/test/ui/user-defined-macro-rules.stderr +++ /dev/null @@ -1,8 +0,0 @@ -error: user-defined macros may not be named `macro_rules` - --> $DIR/user-defined-macro-rules.rs:3:1 - | -LL | macro_rules! macro_rules { () => {} } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -error: aborting due to previous error - |
