Skip to content

Commit bf78389

Browse files
committed
Auto merge of #29828 - sanxiyn:check-macro, r=nrc
Fix #27409.
2 parents 531b053 + cce7b8b commit bf78389

File tree

3 files changed

+83
-50
lines changed

3 files changed

+83
-50
lines changed

src/libsyntax/ext/tt/macro_rules.rs

+63-49
Original file line numberDiff line numberDiff line change
@@ -10,10 +10,10 @@
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};
16-
use ext::tt::macro_parser::{NamedMatch, MatchedSeq, MatchedNonterminal};
16+
use ext::tt::macro_parser::{MatchedSeq, MatchedNonterminal};
1717
use ext::tt::macro_parser::parse;
1818
use parse::lexer::new_tt_reader;
1919
use parse::parser::Parser;
@@ -129,16 +129,20 @@ impl<'a> MacResult for ParserAnyMacro<'a> {
129129
struct MacroRulesMacroExpander {
130130
name: ast::Ident,
131131
imported_from: Option<ast::Ident>,
132-
lhses: Vec<Rc<NamedMatch>>,
133-
rhses: Vec<Rc<NamedMatch>>,
132+
lhses: Vec<TokenTree>,
133+
rhses: Vec<TokenTree>,
134+
valid: bool,
134135
}
135136

136137
impl TTMacroExpander for MacroRulesMacroExpander {
137138
fn expand<'cx>(&self,
138139
cx: &'cx mut ExtCtxt,
139140
sp: Span,
140-
arg: &[ast::TokenTree])
141+
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,
@@ -154,9 +158,9 @@ fn generic_extension<'cx>(cx: &'cx ExtCtxt,
154158
sp: Span,
155159
name: ast::Ident,
156160
imported_from: Option<ast::Ident>,
157-
arg: &[ast::TokenTree],
158-
lhses: &[Rc<NamedMatch>],
159-
rhses: &[Rc<NamedMatch>])
161+
arg: &[TokenTree],
162+
lhses: &[TokenTree],
163+
rhses: &[TokenTree])
160164
-> Box<MacResult+'cx> {
161165
if cx.trace_macros() {
162166
println!("{}! {{ {} }}",
@@ -169,25 +173,17 @@ fn generic_extension<'cx>(cx: &'cx ExtCtxt,
169173
let mut best_fail_msg = "internal error: ran no matchers".to_string();
170174

171175
for (i, lhs) in lhses.iter().enumerate() { // try each arm's matchers
172-
match **lhs {
173-
MatchedNonterminal(NtTT(ref lhs_tt)) => {
174-
let lhs_tt = match **lhs_tt {
175-
TokenTree::Delimited(_, ref delim) => &delim.tts[..],
176-
_ => panic!(cx.span_fatal(sp, "malformed macro lhs"))
177-
};
178-
179-
match TokenTree::parse(cx, lhs_tt, arg) {
180-
Success(named_matches) => {
181-
let rhs = match *rhses[i] {
182-
// okay, what's your transcriber?
183-
MatchedNonterminal(NtTT(ref tt)) => {
184-
match **tt {
185-
// ignore delimiters
186-
TokenTree::Delimited(_, ref delimed) => delimed.tts.clone(),
187-
_ => panic!(cx.span_fatal(sp, "macro rhs must be delimited")),
188-
}
189-
},
190-
_ => cx.span_bug(sp, "bad thing in rhs")
176+
let lhs_tt = match *lhs {
177+
TokenTree::Delimited(_, ref delim) => &delim.tts[..],
178+
_ => cx.span_bug(sp, "malformed macro lhs")
179+
};
180+
181+
match TokenTree::parse(cx, lhs_tt, arg) {
182+
Success(named_matches) => {
183+
let rhs = match rhses[i] {
184+
// ignore delimiters
185+
TokenTree::Delimited(_, ref delimed) => delimed.tts.clone(),
186+
_ => cx.span_bug(sp, "malformed macro rhs"),
191187
};
192188
// rhs has holes ( `$id` and `$(...)` that need filled)
193189
let trncbr = new_tt_reader(&cx.parse_sess().span_diagnostic,
@@ -207,17 +203,14 @@ fn generic_extension<'cx>(cx: &'cx ExtCtxt,
207203
site_span: sp,
208204
macro_ident: name
209205
})
210-
}
211-
Failure(sp, ref msg) => if sp.lo >= best_fail_spot.lo {
206+
}
207+
Failure(sp, ref msg) => if sp.lo >= best_fail_spot.lo {
212208
best_fail_spot = sp;
213209
best_fail_msg = (*msg).clone();
214-
},
215-
Error(err_sp, ref msg) => {
210+
},
211+
Error(err_sp, ref msg) => {
216212
panic!(cx.span_fatal(err_sp.substitute_dummy(sp), &msg[..]))
217-
}
218213
}
219-
}
220-
_ => cx.bug("non-matcher found in parsed lhses")
221214
}
222215
}
223216

@@ -282,9 +275,16 @@ pub fn compile<'cx>(cx: &'cx mut ExtCtxt,
282275
}
283276
};
284277

278+
let mut valid = true;
279+
285280
// Extract the arguments:
286281
let lhses = match **argument_map.get(&lhs_nm.name).unwrap() {
287-
MatchedSeq(ref s, _) => /* FIXME (#2543) */ (*s).clone(),
282+
MatchedSeq(ref s, _) => {
283+
s.iter().map(|m| match **m {
284+
MatchedNonterminal(NtTT(ref tt)) => (**tt).clone(),
285+
_ => cx.span_bug(def.span, "wrong-structured lhs")
286+
}).collect()
287+
}
288288
_ => cx.span_bug(def.span, "wrong-structured lhs")
289289
};
290290

@@ -293,41 +293,55 @@ pub fn compile<'cx>(cx: &'cx mut ExtCtxt,
293293
}
294294

295295
let rhses = match **argument_map.get(&rhs_nm.name).unwrap() {
296-
MatchedSeq(ref s, _) => /* FIXME (#2543) */ (*s).clone(),
296+
MatchedSeq(ref s, _) => {
297+
s.iter().map(|m| match **m {
298+
MatchedNonterminal(NtTT(ref tt)) => (**tt).clone(),
299+
_ => cx.span_bug(def.span, "wrong-structured rhs")
300+
}).collect()
301+
}
297302
_ => cx.span_bug(def.span, "wrong-structured rhs")
298303
};
299304

305+
for rhs in &rhses {
306+
valid &= check_rhs(cx, rhs);
307+
}
308+
300309
let exp: Box<_> = Box::new(MacroRulesMacroExpander {
301310
name: def.ident,
302311
imported_from: def.imported_from,
303312
lhses: lhses,
304313
rhses: rhses,
314+
valid: valid,
305315
});
306316

307317
NormalTT(exp, Some(def.span), def.allow_internal_unstable)
308318
}
309319

310-
fn check_lhs_nt_follows(cx: &mut ExtCtxt, lhs: &NamedMatch, sp: Span) {
311-
// lhs is going to be like MatchedNonterminal(NtTT(TokenTree::Delimited(...))), where the
320+
fn check_lhs_nt_follows(cx: &mut ExtCtxt, lhs: &TokenTree, sp: Span) {
321+
// lhs is going to be like TokenTree::Delimited(...), where the
312322
// entire lhs is those tts. Or, it can be a "bare sequence", not wrapped in parens.
313323
match lhs {
314-
&MatchedNonterminal(NtTT(ref inner)) => match &**inner {
315-
&TokenTree::Delimited(_, ref tts) => {
316-
check_matcher(cx, tts.tts.iter(), &Eof);
317-
},
318-
tt @ &TokenTree::Sequence(..) => {
319-
check_matcher(cx, Some(tt).into_iter(), &Eof);
320-
},
321-
_ => cx.span_err(sp, "Invalid macro matcher; matchers must be contained \
322-
in balanced delimiters or a repetition indicator")
324+
&TokenTree::Delimited(_, ref tts) => {
325+
check_matcher(cx, tts.tts.iter(), &Eof);
323326
},
324-
_ => cx.span_bug(sp, "wrong-structured lhs for follow check (didn't find a \
325-
MatchedNonterminal)")
327+
tt @ &TokenTree::Sequence(..) => {
328+
check_matcher(cx, Some(tt).into_iter(), &Eof);
329+
},
330+
_ => cx.span_err(sp, "Invalid macro matcher; matchers must be contained \
331+
in balanced delimiters or a repetition indicator")
326332
};
327333
// we don't abort on errors on rejection, the driver will do that for us
328334
// after parsing/expansion. we can report every error in every macro this way.
329335
}
330336

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+
331345
// returns the last token that was checked, for TokenTree::Sequence. this gets used later on.
332346
fn check_matcher<'a, I>(cx: &mut ExtCtxt, matcher: I, follow: &Token)
333347
-> 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)