Skip to content

Commit 3f39dc1

Browse files
committed
syntax: Unsupport foo! bar { ... } macros in the parser
Unreserve `macro_rules` as a macro name
1 parent 5748825 commit 3f39dc1

File tree

11 files changed

+70
-186
lines changed

11 files changed

+70
-186
lines changed

src/librustc_plugin/registry.rs

+1-4
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ use rustc::util::nodemap::FxHashMap;
66

77
use syntax::ext::base::{SyntaxExtension, SyntaxExtensionKind, NamedSyntaxExtension};
88
use syntax::ext::base::MacroExpanderFn;
9-
use syntax::symbol::{Symbol, sym};
9+
use syntax::symbol::Symbol;
1010
use syntax::ast;
1111
use syntax::feature_gate::AttributeType;
1212
use syntax_pos::Span;
@@ -85,9 +85,6 @@ impl<'a> Registry<'a> {
8585
///
8686
/// This is the most general hook into `libsyntax`'s expansion behavior.
8787
pub fn register_syntax_extension(&mut self, name: ast::Name, mut extension: SyntaxExtension) {
88-
if name == sym::macro_rules {
89-
panic!("user-defined macros may not be named `macro_rules`");
90-
}
9188
if extension.def_info.is_none() {
9289
extension.def_info = Some((ast::CRATE_NODE_ID, self.krate_span));
9390
}

src/librustc_resolve/macros.rs

-3
Original file line numberDiff line numberDiff line change
@@ -1109,9 +1109,6 @@ impl<'a> Resolver<'a> {
11091109
current_legacy_scope: &mut LegacyScope<'a>) {
11101110
self.local_macro_def_scopes.insert(item.id, self.current_module);
11111111
let ident = item.ident;
1112-
if ident.name == sym::macro_rules {
1113-
self.session.span_err(item.span, "user-defined macros may not be named `macro_rules`");
1114-
}
11151112

11161113
let def_id = self.definitions.local_def_id(item.id);
11171114
let ext = Lrc::new(macro_rules::compile(&self.session.parse_sess,

src/libsyntax/ext/expand.rs

+12-33
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,7 @@ use crate::parse::{DirectoryOwnership, PResult, ParseSess};
1313
use crate::parse::token;
1414
use crate::parse::parser::Parser;
1515
use crate::ptr::P;
16-
use crate::symbol::Symbol;
17-
use crate::symbol::{kw, sym};
16+
use crate::symbol::{sym, Symbol};
1817
use crate::tokenstream::{TokenStream, TokenTree};
1918
use crate::visit::{self, Visitor};
2019
use crate::util::map_in_place::MapInPlace;
@@ -197,7 +196,6 @@ pub struct Invocation {
197196
pub enum InvocationKind {
198197
Bang {
199198
mac: ast::Mac,
200-
ident: Option<Ident>,
201199
span: Span,
202200
},
203201
Attr {
@@ -664,13 +662,12 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
664662
ext: &SyntaxExtension)
665663
-> Option<AstFragment> {
666664
let kind = invoc.fragment_kind;
667-
let (mac, ident, span) = match invoc.kind {
668-
InvocationKind::Bang { mac, ident, span } => (mac, ident, span),
665+
let (mac, span) = match invoc.kind {
666+
InvocationKind::Bang { mac, span } => (mac, span),
669667
_ => unreachable!(),
670668
};
671669
let path = &mac.node.path;
672670

673-
let ident = ident.unwrap_or_else(|| Ident::invalid());
674671
let validate = |this: &mut Self| {
675672
// feature-gate the macro invocation
676673
if let Some((feature, issue)) = ext.unstable_feature {
@@ -690,12 +687,6 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
690687
}
691688
}
692689

693-
if ident.name != kw::Invalid {
694-
let msg = format!("macro {}! expects no ident argument, given '{}'", path, ident);
695-
this.cx.span_err(path.span, &msg);
696-
this.cx.trace_macros_diag();
697-
return Err(kind.dummy(span));
698-
}
699690
Ok(())
700691
};
701692

@@ -729,19 +720,11 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
729720
}
730721

731722
SyntaxExtensionKind::Bang(expander) => {
732-
if ident.name != kw::Invalid {
733-
let msg =
734-
format!("macro {}! expects no ident argument, given '{}'", path, ident);
735-
self.cx.span_err(path.span, &msg);
736-
self.cx.trace_macros_diag();
737-
kind.dummy(span)
738-
} else {
739-
self.gate_proc_macro_expansion_kind(span, kind);
740-
let tok_result = expander.expand(self.cx, span, mac.node.stream());
741-
let result = self.parse_ast_fragment(tok_result, kind, path, span);
742-
self.gate_proc_macro_expansion(span, &result);
743-
result
744-
}
723+
self.gate_proc_macro_expansion_kind(span, kind);
724+
let tok_result = expander.expand(self.cx, span, mac.node.stream());
725+
let result = self.parse_ast_fragment(tok_result, kind, path, span);
726+
self.gate_proc_macro_expansion(span, &result);
727+
result
745728
}
746729
};
747730

@@ -944,7 +927,7 @@ impl<'a, 'b> InvocationCollector<'a, 'b> {
944927
}
945928

946929
fn collect_bang(&mut self, mac: ast::Mac, span: Span, kind: AstFragmentKind) -> AstFragment {
947-
self.collect(kind, InvocationKind::Bang { mac, ident: None, span })
930+
self.collect(kind, InvocationKind::Bang { mac, span })
948931
}
949932

950933
fn collect_attr(&mut self,
@@ -1179,13 +1162,9 @@ impl<'a, 'b> MutVisitor for InvocationCollector<'a, 'b> {
11791162
ast::ItemKind::Mac(..) => {
11801163
self.check_attributes(&item.attrs);
11811164
item.and_then(|item| match item.node {
1182-
ItemKind::Mac(mac) => {
1183-
self.collect(AstFragmentKind::Items, InvocationKind::Bang {
1184-
mac,
1185-
ident: Some(item.ident),
1186-
span: item.span,
1187-
}).make_items()
1188-
}
1165+
ItemKind::Mac(mac) => self.collect(
1166+
AstFragmentKind::Items, InvocationKind::Bang { mac, span: item.span }
1167+
).make_items(),
11891168
_ => unreachable!(),
11901169
})
11911170
}

src/libsyntax/parse/parser.rs

+36-93
Original file line numberDiff line numberDiff line change
@@ -4353,8 +4353,9 @@ impl<'a> Parser<'a> {
43534353

43544354
(ident, ast::MacroDef { tokens: tokens.into(), legacy: false })
43554355
}
4356-
token::Ident(name, _) if name == sym::macro_rules &&
4357-
self.look_ahead(1, |t| *t == token::Not) => {
4356+
token::Ident(name, false) if name == sym::macro_rules &&
4357+
self.look_ahead(1, |t| *t == token::Not) &&
4358+
self.look_ahead(2, |t| t.is_ident()) => {
43584359
let prev_span = self.prev_span;
43594360
self.complain_if_pub_macro(&vis.node, prev_span);
43604361
self.bump();
@@ -4434,34 +4435,6 @@ impl<'a> Parser<'a> {
44344435
}));
44354436
}
44364437

4437-
// it's a macro invocation
4438-
let id = match self.token.kind {
4439-
token::OpenDelim(_) => Ident::invalid(), // no special identifier
4440-
_ => self.parse_ident()?,
4441-
};
4442-
4443-
// check that we're pointing at delimiters (need to check
4444-
// again after the `if`, because of `parse_ident`
4445-
// consuming more tokens).
4446-
match self.token.kind {
4447-
token::OpenDelim(_) => {}
4448-
_ => {
4449-
// we only expect an ident if we didn't parse one
4450-
// above.
4451-
let ident_str = if id.name == kw::Invalid {
4452-
"identifier, "
4453-
} else {
4454-
""
4455-
};
4456-
let tok_str = self.this_token_descr();
4457-
let mut err = self.fatal(&format!("expected {}`(` or `{{`, found {}",
4458-
ident_str,
4459-
tok_str));
4460-
err.span_label(self.token.span, format!("expected {}`(` or `{{`", ident_str));
4461-
return Err(err)
4462-
},
4463-
}
4464-
44654438
let (delim, tts) = self.expect_delimited_token_tree()?;
44664439
let hi = self.prev_span;
44674440

@@ -4471,59 +4444,38 @@ impl<'a> Parser<'a> {
44714444
MacStmtStyle::NoBraces
44724445
};
44734446

4474-
if id.name == kw::Invalid {
4475-
let mac = respan(lo.to(hi), Mac_ { path: pth, tts, delim });
4476-
let node = if delim == MacDelimiter::Brace ||
4477-
self.token == token::Semi || self.token == token::Eof {
4478-
StmtKind::Mac(P((mac, style, attrs.into())))
4479-
}
4480-
// We used to incorrectly stop parsing macro-expanded statements here.
4481-
// If the next token will be an error anyway but could have parsed with the
4482-
// earlier behavior, stop parsing here and emit a warning to avoid breakage.
4483-
else if macro_legacy_warnings &&
4484-
self.token.can_begin_expr() &&
4485-
match self.token.kind {
4486-
// These can continue an expression, so we can't stop parsing and warn.
4487-
token::OpenDelim(token::Paren) | token::OpenDelim(token::Bracket) |
4488-
token::BinOp(token::Minus) | token::BinOp(token::Star) |
4489-
token::BinOp(token::And) | token::BinOp(token::Or) |
4490-
token::AndAnd | token::OrOr |
4491-
token::DotDot | token::DotDotDot | token::DotDotEq => false,
4492-
_ => true,
4493-
} {
4494-
self.warn_missing_semicolon();
4495-
StmtKind::Mac(P((mac, style, attrs.into())))
4496-
} else {
4497-
let e = self.mk_expr(mac.span, ExprKind::Mac(mac), ThinVec::new());
4498-
let e = self.maybe_recover_from_bad_qpath(e, true)?;
4499-
let e = self.parse_dot_or_call_expr_with(e, lo, attrs.into())?;
4500-
let e = self.parse_assoc_expr_with(0, LhsExpr::AlreadyParsed(e))?;
4501-
StmtKind::Expr(e)
4502-
};
4503-
Stmt {
4504-
id: ast::DUMMY_NODE_ID,
4505-
span: lo.to(hi),
4506-
node,
4507-
}
4447+
let mac = respan(lo.to(hi), Mac_ { path: pth, tts, delim });
4448+
let node = if delim == MacDelimiter::Brace ||
4449+
self.token == token::Semi || self.token == token::Eof {
4450+
StmtKind::Mac(P((mac, style, attrs.into())))
4451+
}
4452+
// We used to incorrectly stop parsing macro-expanded statements here.
4453+
// If the next token will be an error anyway but could have parsed with the
4454+
// earlier behavior, stop parsing here and emit a warning to avoid breakage.
4455+
else if macro_legacy_warnings &&
4456+
self.token.can_begin_expr() &&
4457+
match self.token.kind {
4458+
// These can continue an expression, so we can't stop parsing and warn.
4459+
token::OpenDelim(token::Paren) | token::OpenDelim(token::Bracket) |
4460+
token::BinOp(token::Minus) | token::BinOp(token::Star) |
4461+
token::BinOp(token::And) | token::BinOp(token::Or) |
4462+
token::AndAnd | token::OrOr |
4463+
token::DotDot | token::DotDotDot | token::DotDotEq => false,
4464+
_ => true,
4465+
} {
4466+
self.warn_missing_semicolon();
4467+
StmtKind::Mac(P((mac, style, attrs.into())))
45084468
} else {
4509-
// if it has a special ident, it's definitely an item
4510-
//
4511-
// Require a semicolon or braces.
4512-
if style != MacStmtStyle::Braces && !self.eat(&token::Semi) {
4513-
self.report_invalid_macro_expansion_item();
4514-
}
4515-
let span = lo.to(hi);
4516-
Stmt {
4517-
id: ast::DUMMY_NODE_ID,
4518-
span,
4519-
node: StmtKind::Item({
4520-
self.mk_item(
4521-
span, id /*id is good here*/,
4522-
ItemKind::Mac(respan(span, Mac_ { path: pth, tts, delim })),
4523-
respan(lo, VisibilityKind::Inherited),
4524-
attrs)
4525-
}),
4526-
}
4469+
let e = self.mk_expr(mac.span, ExprKind::Mac(mac), ThinVec::new());
4470+
let e = self.maybe_recover_from_bad_qpath(e, true)?;
4471+
let e = self.parse_dot_or_call_expr_with(e, lo, attrs.into())?;
4472+
let e = self.parse_assoc_expr_with(0, LhsExpr::AlreadyParsed(e))?;
4473+
StmtKind::Expr(e)
4474+
};
4475+
Stmt {
4476+
id: ast::DUMMY_NODE_ID,
4477+
span: lo.to(hi),
4478+
node,
45274479
}
45284480
} else {
45294481
// FIXME: Bad copy of attrs
@@ -7611,24 +7563,15 @@ impl<'a> Parser<'a> {
76117563
// item macro.
76127564
let pth = self.parse_path(PathStyle::Mod)?;
76137565
self.expect(&token::Not)?;
7614-
7615-
// a 'special' identifier (like what `macro_rules!` uses)
7616-
// is optional. We should eventually unify invoc syntax
7617-
// and remove this.
7618-
let id = if self.token.is_ident() {
7619-
self.parse_ident()?
7620-
} else {
7621-
Ident::invalid() // no special identifier
7622-
};
7623-
// eat a matched-delimiter token tree:
76247566
let (delim, tts) = self.expect_delimited_token_tree()?;
76257567
if delim != MacDelimiter::Brace && !self.eat(&token::Semi) {
76267568
self.report_invalid_macro_expansion_item();
76277569
}
76287570

76297571
let hi = self.prev_span;
76307572
let mac = respan(mac_lo.to(hi), Mac_ { path: pth, tts, delim });
7631-
let item = self.mk_item(lo.to(hi), id, ItemKind::Mac(mac), visibility, attrs);
7573+
let item =
7574+
self.mk_item(lo.to(hi), Ident::invalid(), ItemKind::Mac(mac), visibility, attrs);
76327575
return Ok(Some(item));
76337576
}
76347577

src/test/run-pass/rfcs/rfc-2151-raw-identifiers/macros.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
// run-pass
22
#![feature(decl_macro)]
33

4-
r#macro_rules! r#struct {
4+
macro_rules! r#struct {
55
($r#struct:expr) => { $r#struct }
66
}
77

src/test/ui/issues/issue-10536.rs

+2-6
Original file line numberDiff line numberDiff line change
@@ -11,13 +11,9 @@ macro_rules! foo{
1111
pub fn main() {
1212
foo!();
1313

14-
assert!({one! two()});
15-
//~^ ERROR macros that expand to items
16-
//~| ERROR cannot find macro `one!` in this scope
17-
//~| ERROR mismatched types
14+
assert!({one! two()}); //~ ERROR expected open delimiter
1815

1916
// regardless of whether nested macro_rules works, the following should at
2017
// least throw a conventional error.
21-
assert!({one! two});
22-
//~^ ERROR expected `(` or `{`, found `}`
18+
assert!({one! two}); //~ ERROR expected open delimiter
2319
}

src/test/ui/issues/issue-10536.stderr

+7-31
Original file line numberDiff line numberDiff line change
@@ -1,38 +1,14 @@
1-
error: macros that expand to items must be delimited with braces or followed by a semicolon
2-
--> $DIR/issue-10536.rs:14:22
1+
error: expected open delimiter
2+
--> $DIR/issue-10536.rs:14:19
33
|
44
LL | assert!({one! two()});
5-
| ^^
6-
help: change the delimiters to curly braces
7-
|
8-
LL | assert!({one! two {}});
9-
| ^^
10-
help: add a semicolon
11-
|
12-
LL | assert!({one! two();});
13-
| ^
5+
| ^^^ expected open delimiter
146

15-
error: expected `(` or `{`, found `}`
16-
--> $DIR/issue-10536.rs:21:22
7+
error: expected open delimiter
8+
--> $DIR/issue-10536.rs:18:19
179
|
1810
LL | assert!({one! two});
19-
| ^ expected `(` or `{`
20-
21-
error: cannot find macro `one!` in this scope
22-
--> $DIR/issue-10536.rs:14:14
23-
|
24-
LL | assert!({one! two()});
25-
| ^^^
26-
27-
error[E0308]: mismatched types
28-
--> $DIR/issue-10536.rs:14:13
29-
|
30-
LL | assert!({one! two()});
31-
| ^^^^^^^^^^^^ expected bool, found ()
32-
|
33-
= note: expected type `bool`
34-
found type `()`
11+
| ^^^ expected open delimiter
3512

36-
error: aborting due to 4 previous errors
13+
error: aborting due to 2 previous errors
3714

38-
For more information about this error, try `rustc --explain E0308`.
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
11
fn main() {
2-
foo! bar < //~ ERROR expected `(` or `{`, found `<`
2+
foo! bar < //~ ERROR expected open delimiter
33
}
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
1-
error: expected `(` or `{`, found `<`
2-
--> $DIR/macro-bad-delimiter-ident.rs:2:14
1+
error: expected open delimiter
2+
--> $DIR/macro-bad-delimiter-ident.rs:2:10
33
|
44
LL | foo! bar <
5-
| ^ expected `(` or `{`
5+
| ^^^ expected open delimiter
66

77
error: aborting due to previous error
88

+7-3
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,9 @@
1-
#![allow(unused_macros)]
1+
// check-pass
22

3-
macro_rules! macro_rules { () => {} } //~ ERROR user-defined macros may not be named `macro_rules`
3+
macro_rules! macro_rules { () => { struct S; } } // OK
44

5-
fn main() {}
5+
macro_rules! {} // OK, calls the macro defined above
6+
7+
fn main() {
8+
let s = S;
9+
}

0 commit comments

Comments
 (0)