Skip to content

Commit cce7b8b

Browse files
committed
Check macro definition and do not expand invalid macros
1 parent 289b1b4 commit cce7b8b

File tree

3 files changed

+42
-4
lines changed

3 files changed

+42
-4
lines changed

src/libsyntax/ext/tt/macro_rules.rs

+22-3
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010

1111
use ast::{self, TokenTree};
1212
use codemap::{Span, DUMMY_SP};
13-
use ext::base::{ExtCtxt, MacResult, SyntaxExtension};
13+
use ext::base::{DummyResult, ExtCtxt, MacResult, SyntaxExtension};
1414
use ext::base::{NormalTT, TTMacroExpander};
1515
use ext::tt::macro_parser::{Success, Error, Failure};
1616
use ext::tt::macro_parser::{MatchedSeq, MatchedNonterminal};
@@ -131,6 +131,7 @@ struct MacroRulesMacroExpander {
131131
imported_from: Option<ast::Ident>,
132132
lhses: Vec<TokenTree>,
133133
rhses: Vec<TokenTree>,
134+
valid: bool,
134135
}
135136

136137
impl TTMacroExpander for MacroRulesMacroExpander {
@@ -139,6 +140,9 @@ impl TTMacroExpander for MacroRulesMacroExpander {
139140
sp: Span,
140141
arg: &[TokenTree])
141142
-> Box<MacResult+'cx> {
143+
if !self.valid {
144+
return DummyResult::any(sp);
145+
}
142146
generic_extension(cx,
143147
sp,
144148
self.name,
@@ -171,15 +175,15 @@ fn generic_extension<'cx>(cx: &'cx ExtCtxt,
171175
for (i, lhs) in lhses.iter().enumerate() { // try each arm's matchers
172176
let lhs_tt = match *lhs {
173177
TokenTree::Delimited(_, ref delim) => &delim.tts[..],
174-
_ => panic!(cx.span_fatal(sp, "malformed macro lhs"))
178+
_ => cx.span_bug(sp, "malformed macro lhs")
175179
};
176180

177181
match TokenTree::parse(cx, lhs_tt, arg) {
178182
Success(named_matches) => {
179183
let rhs = match rhses[i] {
180184
// ignore delimiters
181185
TokenTree::Delimited(_, ref delimed) => delimed.tts.clone(),
182-
_ => panic!(cx.span_fatal(sp, "macro rhs must be delimited")),
186+
_ => cx.span_bug(sp, "malformed macro rhs"),
183187
};
184188
// rhs has holes ( `$id` and `$(...)` that need filled)
185189
let trncbr = new_tt_reader(&cx.parse_sess().span_diagnostic,
@@ -271,6 +275,8 @@ pub fn compile<'cx>(cx: &'cx mut ExtCtxt,
271275
}
272276
};
273277

278+
let mut valid = true;
279+
274280
// Extract the arguments:
275281
let lhses = match **argument_map.get(&lhs_nm.name).unwrap() {
276282
MatchedSeq(ref s, _) => {
@@ -296,11 +302,16 @@ pub fn compile<'cx>(cx: &'cx mut ExtCtxt,
296302
_ => cx.span_bug(def.span, "wrong-structured rhs")
297303
};
298304

305+
for rhs in &rhses {
306+
valid &= check_rhs(cx, rhs);
307+
}
308+
299309
let exp: Box<_> = Box::new(MacroRulesMacroExpander {
300310
name: def.ident,
301311
imported_from: def.imported_from,
302312
lhses: lhses,
303313
rhses: rhses,
314+
valid: valid,
304315
});
305316

306317
NormalTT(exp, Some(def.span), def.allow_internal_unstable)
@@ -323,6 +334,14 @@ fn check_lhs_nt_follows(cx: &mut ExtCtxt, lhs: &TokenTree, sp: Span) {
323334
// after parsing/expansion. we can report every error in every macro this way.
324335
}
325336

337+
fn check_rhs(cx: &mut ExtCtxt, rhs: &TokenTree) -> bool {
338+
match *rhs {
339+
TokenTree::Delimited(..) => return true,
340+
_ => cx.span_err(rhs.get_span(), "macro rhs must be delimited")
341+
}
342+
false
343+
}
344+
326345
// returns the last token that was checked, for TokenTree::Sequence. this gets used later on.
327346
fn check_matcher<'a, I>(cx: &mut ExtCtxt, matcher: I, follow: &Token)
328347
-> Option<(Span, Token)> where I: Iterator<Item=&'a TokenTree> {

src/test/compile-fail/macro-error.rs

+19
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
// Check that we report errors at macro definition, not expansion.
12+
13+
macro_rules! foo {
14+
($a:expr) => $a; //~ ERROR macro rhs must be delimited
15+
}
16+
17+
fn main() {
18+
foo!(0);
19+
}

src/test/compile-fail/type-macros-fail.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
// except according to those terms.
1010

1111
macro_rules! Id {
12-
{ $T:tt } => $T
12+
($T:tt) => ($T);
1313
}
1414

1515
struct Foo<T> {

0 commit comments

Comments
 (0)