Rollup merge of #62258 - petrochenkov:idclean, r=Centril
syntax: Unsupport `foo! bar { ... }` macros in the parser Their support in expansion was removed in https://github.com/rust-lang/rust/pull/61606. Also un-reserve `macro_rules` as a macro name, there's no ambiguity between `macro_rules` definitions and macro calls (it also wasn't reserved correctly). cc https://github.com/rust-lang-nursery/wg-grammar/issues/51
This commit is contained in:
commit
8867ba19de
|
@ -6,7 +6,7 @@ use rustc::util::nodemap::FxHashMap;
|
||||||
|
|
||||||
use syntax::ext::base::{SyntaxExtension, SyntaxExtensionKind, NamedSyntaxExtension};
|
use syntax::ext::base::{SyntaxExtension, SyntaxExtensionKind, NamedSyntaxExtension};
|
||||||
use syntax::ext::base::MacroExpanderFn;
|
use syntax::ext::base::MacroExpanderFn;
|
||||||
use syntax::symbol::{Symbol, sym};
|
use syntax::symbol::Symbol;
|
||||||
use syntax::ast;
|
use syntax::ast;
|
||||||
use syntax::feature_gate::AttributeType;
|
use syntax::feature_gate::AttributeType;
|
||||||
use syntax_pos::Span;
|
use syntax_pos::Span;
|
||||||
|
@ -85,9 +85,6 @@ impl<'a> Registry<'a> {
|
||||||
///
|
///
|
||||||
/// This is the most general hook into `libsyntax`'s expansion behavior.
|
/// This is the most general hook into `libsyntax`'s expansion behavior.
|
||||||
pub fn register_syntax_extension(&mut self, name: ast::Name, mut extension: SyntaxExtension) {
|
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() {
|
if extension.def_info.is_none() {
|
||||||
extension.def_info = Some((ast::CRATE_NODE_ID, self.krate_span));
|
extension.def_info = Some((ast::CRATE_NODE_ID, self.krate_span));
|
||||||
}
|
}
|
||||||
|
|
|
@ -1109,9 +1109,6 @@ impl<'a> Resolver<'a> {
|
||||||
current_legacy_scope: &mut LegacyScope<'a>) {
|
current_legacy_scope: &mut LegacyScope<'a>) {
|
||||||
self.local_macro_def_scopes.insert(item.id, self.current_module);
|
self.local_macro_def_scopes.insert(item.id, self.current_module);
|
||||||
let ident = item.ident;
|
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 def_id = self.definitions.local_def_id(item.id);
|
||||||
let ext = Lrc::new(macro_rules::compile(&self.session.parse_sess,
|
let ext = Lrc::new(macro_rules::compile(&self.session.parse_sess,
|
||||||
|
|
|
@ -13,8 +13,7 @@ use crate::parse::{DirectoryOwnership, PResult, ParseSess};
|
||||||
use crate::parse::token;
|
use crate::parse::token;
|
||||||
use crate::parse::parser::Parser;
|
use crate::parse::parser::Parser;
|
||||||
use crate::ptr::P;
|
use crate::ptr::P;
|
||||||
use crate::symbol::Symbol;
|
use crate::symbol::{sym, Symbol};
|
||||||
use crate::symbol::{kw, sym};
|
|
||||||
use crate::tokenstream::{TokenStream, TokenTree};
|
use crate::tokenstream::{TokenStream, TokenTree};
|
||||||
use crate::visit::{self, Visitor};
|
use crate::visit::{self, Visitor};
|
||||||
use crate::util::map_in_place::MapInPlace;
|
use crate::util::map_in_place::MapInPlace;
|
||||||
|
@ -197,7 +196,6 @@ pub struct Invocation {
|
||||||
pub enum InvocationKind {
|
pub enum InvocationKind {
|
||||||
Bang {
|
Bang {
|
||||||
mac: ast::Mac,
|
mac: ast::Mac,
|
||||||
ident: Option<Ident>,
|
|
||||||
span: Span,
|
span: Span,
|
||||||
},
|
},
|
||||||
Attr {
|
Attr {
|
||||||
|
@ -664,13 +662,12 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
|
||||||
ext: &SyntaxExtension)
|
ext: &SyntaxExtension)
|
||||||
-> Option<AstFragment> {
|
-> Option<AstFragment> {
|
||||||
let kind = invoc.fragment_kind;
|
let kind = invoc.fragment_kind;
|
||||||
let (mac, ident, span) = match invoc.kind {
|
let (mac, span) = match invoc.kind {
|
||||||
InvocationKind::Bang { mac, ident, span } => (mac, ident, span),
|
InvocationKind::Bang { mac, span } => (mac, span),
|
||||||
_ => unreachable!(),
|
_ => unreachable!(),
|
||||||
};
|
};
|
||||||
let path = &mac.node.path;
|
let path = &mac.node.path;
|
||||||
|
|
||||||
let ident = ident.unwrap_or_else(|| Ident::invalid());
|
|
||||||
let validate = |this: &mut Self| {
|
let validate = |this: &mut Self| {
|
||||||
// feature-gate the macro invocation
|
// feature-gate the macro invocation
|
||||||
if let Some((feature, issue)) = ext.unstable_feature {
|
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(())
|
Ok(())
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -729,20 +720,12 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
|
||||||
}
|
}
|
||||||
|
|
||||||
SyntaxExtensionKind::Bang(expander) => {
|
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);
|
self.gate_proc_macro_expansion_kind(span, kind);
|
||||||
let tok_result = expander.expand(self.cx, span, mac.node.stream());
|
let tok_result = expander.expand(self.cx, span, mac.node.stream());
|
||||||
let result = self.parse_ast_fragment(tok_result, kind, path, span);
|
let result = self.parse_ast_fragment(tok_result, kind, path, span);
|
||||||
self.gate_proc_macro_expansion(span, &result);
|
self.gate_proc_macro_expansion(span, &result);
|
||||||
result
|
result
|
||||||
}
|
}
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
if opt_expanded.is_some() {
|
if opt_expanded.is_some() {
|
||||||
|
@ -944,7 +927,7 @@ impl<'a, 'b> InvocationCollector<'a, 'b> {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn collect_bang(&mut self, mac: ast::Mac, span: Span, kind: AstFragmentKind) -> AstFragment {
|
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,
|
fn collect_attr(&mut self,
|
||||||
|
@ -1179,13 +1162,9 @@ impl<'a, 'b> MutVisitor for InvocationCollector<'a, 'b> {
|
||||||
ast::ItemKind::Mac(..) => {
|
ast::ItemKind::Mac(..) => {
|
||||||
self.check_attributes(&item.attrs);
|
self.check_attributes(&item.attrs);
|
||||||
item.and_then(|item| match item.node {
|
item.and_then(|item| match item.node {
|
||||||
ItemKind::Mac(mac) => {
|
ItemKind::Mac(mac) => self.collect(
|
||||||
self.collect(AstFragmentKind::Items, InvocationKind::Bang {
|
AstFragmentKind::Items, InvocationKind::Bang { mac, span: item.span }
|
||||||
mac,
|
).make_items(),
|
||||||
ident: Some(item.ident),
|
|
||||||
span: item.span,
|
|
||||||
}).make_items()
|
|
||||||
}
|
|
||||||
_ => unreachable!(),
|
_ => unreachable!(),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
|
@ -4324,9 +4324,7 @@ impl<'a> Parser<'a> {
|
||||||
fn eat_macro_def(&mut self, attrs: &[Attribute], vis: &Visibility, lo: Span)
|
fn eat_macro_def(&mut self, attrs: &[Attribute], vis: &Visibility, lo: Span)
|
||||||
-> PResult<'a, Option<P<Item>>> {
|
-> PResult<'a, Option<P<Item>>> {
|
||||||
let token_lo = self.token.span;
|
let token_lo = self.token.span;
|
||||||
let (ident, def) = match self.token.kind {
|
let (ident, def) = if self.eat_keyword(kw::Macro) {
|
||||||
token::Ident(name, false) if name == kw::Macro => {
|
|
||||||
self.bump();
|
|
||||||
let ident = self.parse_ident()?;
|
let ident = self.parse_ident()?;
|
||||||
let tokens = if self.check(&token::OpenDelim(token::Brace)) {
|
let tokens = if self.check(&token::OpenDelim(token::Brace)) {
|
||||||
match self.parse_token_tree() {
|
match self.parse_token_tree() {
|
||||||
|
@ -4352,9 +4350,9 @@ impl<'a> Parser<'a> {
|
||||||
};
|
};
|
||||||
|
|
||||||
(ident, ast::MacroDef { tokens: tokens.into(), legacy: false })
|
(ident, ast::MacroDef { tokens: tokens.into(), legacy: false })
|
||||||
}
|
} else if self.check_keyword(sym::macro_rules) &&
|
||||||
token::Ident(name, _) if name == sym::macro_rules &&
|
self.look_ahead(1, |t| *t == token::Not) &&
|
||||||
self.look_ahead(1, |t| *t == token::Not) => {
|
self.look_ahead(2, |t| t.is_ident()) {
|
||||||
let prev_span = self.prev_span;
|
let prev_span = self.prev_span;
|
||||||
self.complain_if_pub_macro(&vis.node, prev_span);
|
self.complain_if_pub_macro(&vis.node, prev_span);
|
||||||
self.bump();
|
self.bump();
|
||||||
|
@ -4367,8 +4365,8 @@ impl<'a> Parser<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
(ident, ast::MacroDef { tokens, legacy: true })
|
(ident, ast::MacroDef { tokens, legacy: true })
|
||||||
}
|
} else {
|
||||||
_ => return Ok(None),
|
return Ok(None);
|
||||||
};
|
};
|
||||||
|
|
||||||
let span = lo.to(self.prev_span);
|
let span = lo.to(self.prev_span);
|
||||||
|
@ -4412,14 +4410,14 @@ impl<'a> Parser<'a> {
|
||||||
!self.is_existential_type_decl() &&
|
!self.is_existential_type_decl() &&
|
||||||
!self.is_auto_trait_item() &&
|
!self.is_auto_trait_item() &&
|
||||||
!self.is_async_fn() {
|
!self.is_async_fn() {
|
||||||
let pth = self.parse_path(PathStyle::Expr)?;
|
let path = self.parse_path(PathStyle::Expr)?;
|
||||||
|
|
||||||
if !self.eat(&token::Not) {
|
if !self.eat(&token::Not) {
|
||||||
let expr = if self.check(&token::OpenDelim(token::Brace)) {
|
let expr = if self.check(&token::OpenDelim(token::Brace)) {
|
||||||
self.parse_struct_expr(lo, pth, ThinVec::new())?
|
self.parse_struct_expr(lo, path, ThinVec::new())?
|
||||||
} else {
|
} else {
|
||||||
let hi = self.prev_span;
|
let hi = self.prev_span;
|
||||||
self.mk_expr(lo.to(hi), ExprKind::Path(None, pth), ThinVec::new())
|
self.mk_expr(lo.to(hi), ExprKind::Path(None, path), ThinVec::new())
|
||||||
};
|
};
|
||||||
|
|
||||||
let expr = self.with_res(Restrictions::STMT_EXPR, |this| {
|
let expr = self.with_res(Restrictions::STMT_EXPR, |this| {
|
||||||
|
@ -4434,34 +4432,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 (delim, tts) = self.expect_delimited_token_tree()?;
|
||||||
let hi = self.prev_span;
|
let hi = self.prev_span;
|
||||||
|
|
||||||
|
@ -4471,8 +4441,7 @@ impl<'a> Parser<'a> {
|
||||||
MacStmtStyle::NoBraces
|
MacStmtStyle::NoBraces
|
||||||
};
|
};
|
||||||
|
|
||||||
if id.name == kw::Invalid {
|
let mac = respan(lo.to(hi), Mac_ { path, tts, delim });
|
||||||
let mac = respan(lo.to(hi), Mac_ { path: pth, tts, delim });
|
|
||||||
let node = if delim == MacDelimiter::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())))
|
||||||
|
@ -4505,26 +4474,6 @@ impl<'a> Parser<'a> {
|
||||||
span: lo.to(hi),
|
span: lo.to(hi),
|
||||||
node,
|
node,
|
||||||
}
|
}
|
||||||
} 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)
|
|
||||||
}),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
// FIXME: Bad copy of attrs
|
// FIXME: Bad copy of attrs
|
||||||
let old_directory_ownership =
|
let old_directory_ownership =
|
||||||
|
@ -7619,26 +7568,17 @@ impl<'a> Parser<'a> {
|
||||||
let mac_lo = self.token.span;
|
let mac_lo = self.token.span;
|
||||||
|
|
||||||
// item macro.
|
// item macro.
|
||||||
let pth = self.parse_path(PathStyle::Mod)?;
|
let path = self.parse_path(PathStyle::Mod)?;
|
||||||
self.expect(&token::Not)?;
|
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()?;
|
let (delim, tts) = self.expect_delimited_token_tree()?;
|
||||||
if delim != MacDelimiter::Brace && !self.eat(&token::Semi) {
|
if delim != MacDelimiter::Brace && !self.eat(&token::Semi) {
|
||||||
self.report_invalid_macro_expansion_item();
|
self.report_invalid_macro_expansion_item();
|
||||||
}
|
}
|
||||||
|
|
||||||
let hi = self.prev_span;
|
let hi = self.prev_span;
|
||||||
let mac = respan(mac_lo.to(hi), Mac_ { path: pth, tts, delim });
|
let mac = respan(mac_lo.to(hi), Mac_ { path, 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));
|
return Ok(Some(item));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -7664,9 +7604,9 @@ impl<'a> Parser<'a> {
|
||||||
!(self.is_async_fn() && self.token.span.rust_2015()) {
|
!(self.is_async_fn() && self.token.span.rust_2015()) {
|
||||||
let prev_span = self.prev_span;
|
let prev_span = self.prev_span;
|
||||||
let lo = self.token.span;
|
let lo = self.token.span;
|
||||||
let pth = self.parse_path(PathStyle::Mod)?;
|
let path = self.parse_path(PathStyle::Mod)?;
|
||||||
|
|
||||||
if pth.segments.len() == 1 {
|
if path.segments.len() == 1 {
|
||||||
if !self.eat(&token::Not) {
|
if !self.eat(&token::Not) {
|
||||||
return Err(self.missing_assoc_item_kind_err(item_kind, prev_span));
|
return Err(self.missing_assoc_item_kind_err(item_kind, prev_span));
|
||||||
}
|
}
|
||||||
|
@ -7686,7 +7626,7 @@ impl<'a> Parser<'a> {
|
||||||
self.expect(&token::Semi)?;
|
self.expect(&token::Semi)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(Some(respan(lo.to(self.prev_span), Mac_ { path: pth, tts, delim })))
|
Ok(Some(respan(lo.to(self.prev_span), Mac_ { path, tts, delim })))
|
||||||
} else {
|
} else {
|
||||||
Ok(None)
|
Ok(None)
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
// run-pass
|
// run-pass
|
||||||
#![feature(decl_macro)]
|
#![feature(decl_macro)]
|
||||||
|
|
||||||
r#macro_rules! r#struct {
|
macro_rules! r#struct {
|
||||||
($r#struct:expr) => { $r#struct }
|
($r#struct:expr) => { $r#struct }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -11,13 +11,9 @@ macro_rules! foo{
|
||||||
pub fn main() {
|
pub fn main() {
|
||||||
foo!();
|
foo!();
|
||||||
|
|
||||||
assert!({one! two()});
|
assert!({one! two()}); //~ ERROR expected open delimiter
|
||||||
//~^ ERROR macros that expand to items
|
|
||||||
//~| ERROR cannot find macro `one!` in this scope
|
|
||||||
//~| ERROR mismatched types
|
|
||||||
|
|
||||||
// regardless of whether nested macro_rules works, the following should at
|
// regardless of whether nested macro_rules works, the following should at
|
||||||
// least throw a conventional error.
|
// least throw a conventional error.
|
||||||
assert!({one! two});
|
assert!({one! two}); //~ ERROR expected open delimiter
|
||||||
//~^ ERROR expected `(` or `{`, found `}`
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,38 +1,14 @@
|
||||||
error: macros that expand to items must be delimited with braces or followed by a semicolon
|
error: expected open delimiter
|
||||||
--> $DIR/issue-10536.rs:14:22
|
--> $DIR/issue-10536.rs:14:19
|
||||||
|
|
|
|
||||||
LL | assert!({one! two()});
|
LL | assert!({one! two()});
|
||||||
| ^^
|
| ^^^ expected open delimiter
|
||||||
help: change the delimiters to curly braces
|
|
||||||
|
|
|
||||||
LL | assert!({one! two {}});
|
|
||||||
| ^^
|
|
||||||
help: add a semicolon
|
|
||||||
|
|
|
||||||
LL | assert!({one! two();});
|
|
||||||
| ^
|
|
||||||
|
|
||||||
error: expected `(` or `{`, found `}`
|
error: expected open delimiter
|
||||||
--> $DIR/issue-10536.rs:21:22
|
--> $DIR/issue-10536.rs:18:19
|
||||||
|
|
|
|
||||||
LL | assert!({one! two});
|
LL | assert!({one! two});
|
||||||
| ^ expected `(` or `{`
|
| ^^^ expected open delimiter
|
||||||
|
|
||||||
error: cannot find macro `one!` in this scope
|
error: aborting due to 2 previous errors
|
||||||
--> $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 `()`
|
|
||||||
|
|
||||||
error: aborting due to 4 previous errors
|
|
||||||
|
|
||||||
For more information about this error, try `rustc --explain E0308`.
|
|
||||||
|
|
|
@ -1,3 +1,3 @@
|
||||||
fn main() {
|
fn main() {
|
||||||
foo! bar < //~ ERROR expected `(` or `{`, found `<`
|
foo! bar < //~ ERROR expected open delimiter
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
error: expected `(` or `{`, found `<`
|
error: expected open delimiter
|
||||||
--> $DIR/macro-bad-delimiter-ident.rs:2:14
|
--> $DIR/macro-bad-delimiter-ident.rs:2:10
|
||||||
|
|
|
|
||||||
LL | foo! bar <
|
LL | foo! bar <
|
||||||
| ^ expected `(` or `{`
|
| ^^^ expected open delimiter
|
||||||
|
|
||||||
error: aborting due to previous error
|
error: aborting due to previous error
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
|
}
|
||||||
|
|
|
@ -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
|
|
||||||
|
|
Loading…
Reference in New Issue