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;
///
/// 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));
}
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,
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;
pub enum InvocationKind {
Bang {
mac: ast::Mac,
- ident: Option<Ident>,
span: Span,
},
Attr {
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 {
}
}
- 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(())
};
}
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
}
};
}
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,
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!(),
})
}
(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();
}));
}
- // 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;
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
// 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();
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));
}
// run-pass
#![feature(decl_macro)]
-r#macro_rules! r#struct {
+macro_rules! r#struct {
($r#struct:expr) => { $r#struct }
}
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
}
-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`.
fn main() {
- foo! bar < //~ ERROR expected `(` or `{`, found `<`
+ foo! bar < //~ ERROR expected open delimiter
}
-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
-#![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;
+}
+++ /dev/null
-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
-