Check macro definition and do not expand invalid macros
This commit is contained in:
parent
289b1b400a
commit
cce7b8bd25
@ -10,7 +10,7 @@
|
||||
|
||||
use ast::{self, TokenTree};
|
||||
use codemap::{Span, DUMMY_SP};
|
||||
use ext::base::{ExtCtxt, MacResult, SyntaxExtension};
|
||||
use ext::base::{DummyResult, ExtCtxt, MacResult, SyntaxExtension};
|
||||
use ext::base::{NormalTT, TTMacroExpander};
|
||||
use ext::tt::macro_parser::{Success, Error, Failure};
|
||||
use ext::tt::macro_parser::{MatchedSeq, MatchedNonterminal};
|
||||
@ -131,6 +131,7 @@ struct MacroRulesMacroExpander {
|
||||
imported_from: Option<ast::Ident>,
|
||||
lhses: Vec<TokenTree>,
|
||||
rhses: Vec<TokenTree>,
|
||||
valid: bool,
|
||||
}
|
||||
|
||||
impl TTMacroExpander for MacroRulesMacroExpander {
|
||||
@ -139,6 +140,9 @@ impl TTMacroExpander for MacroRulesMacroExpander {
|
||||
sp: Span,
|
||||
arg: &[TokenTree])
|
||||
-> Box<MacResult+'cx> {
|
||||
if !self.valid {
|
||||
return DummyResult::any(sp);
|
||||
}
|
||||
generic_extension(cx,
|
||||
sp,
|
||||
self.name,
|
||||
@ -171,7 +175,7 @@ fn generic_extension<'cx>(cx: &'cx ExtCtxt,
|
||||
for (i, lhs) in lhses.iter().enumerate() { // try each arm's matchers
|
||||
let lhs_tt = match *lhs {
|
||||
TokenTree::Delimited(_, ref delim) => &delim.tts[..],
|
||||
_ => panic!(cx.span_fatal(sp, "malformed macro lhs"))
|
||||
_ => cx.span_bug(sp, "malformed macro lhs")
|
||||
};
|
||||
|
||||
match TokenTree::parse(cx, lhs_tt, arg) {
|
||||
@ -179,7 +183,7 @@ fn generic_extension<'cx>(cx: &'cx ExtCtxt,
|
||||
let rhs = match rhses[i] {
|
||||
// ignore delimiters
|
||||
TokenTree::Delimited(_, ref delimed) => delimed.tts.clone(),
|
||||
_ => panic!(cx.span_fatal(sp, "macro rhs must be delimited")),
|
||||
_ => cx.span_bug(sp, "malformed macro rhs"),
|
||||
};
|
||||
// rhs has holes ( `$id` and `$(...)` that need filled)
|
||||
let trncbr = new_tt_reader(&cx.parse_sess().span_diagnostic,
|
||||
@ -271,6 +275,8 @@ pub fn compile<'cx>(cx: &'cx mut ExtCtxt,
|
||||
}
|
||||
};
|
||||
|
||||
let mut valid = true;
|
||||
|
||||
// Extract the arguments:
|
||||
let lhses = match **argument_map.get(&lhs_nm.name).unwrap() {
|
||||
MatchedSeq(ref s, _) => {
|
||||
@ -296,11 +302,16 @@ pub fn compile<'cx>(cx: &'cx mut ExtCtxt,
|
||||
_ => cx.span_bug(def.span, "wrong-structured rhs")
|
||||
};
|
||||
|
||||
for rhs in &rhses {
|
||||
valid &= check_rhs(cx, rhs);
|
||||
}
|
||||
|
||||
let exp: Box<_> = Box::new(MacroRulesMacroExpander {
|
||||
name: def.ident,
|
||||
imported_from: def.imported_from,
|
||||
lhses: lhses,
|
||||
rhses: rhses,
|
||||
valid: valid,
|
||||
});
|
||||
|
||||
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) {
|
||||
// after parsing/expansion. we can report every error in every macro this way.
|
||||
}
|
||||
|
||||
fn check_rhs(cx: &mut ExtCtxt, rhs: &TokenTree) -> bool {
|
||||
match *rhs {
|
||||
TokenTree::Delimited(..) => return true,
|
||||
_ => cx.span_err(rhs.get_span(), "macro rhs must be delimited")
|
||||
}
|
||||
false
|
||||
}
|
||||
|
||||
// returns the last token that was checked, for TokenTree::Sequence. this gets used later on.
|
||||
fn check_matcher<'a, I>(cx: &mut ExtCtxt, matcher: I, follow: &Token)
|
||||
-> Option<(Span, Token)> where I: Iterator<Item=&'a TokenTree> {
|
||||
|
19
src/test/compile-fail/macro-error.rs
Normal file
19
src/test/compile-fail/macro-error.rs
Normal file
@ -0,0 +1,19 @@
|
||||
// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
// Check that we report errors at macro definition, not expansion.
|
||||
|
||||
macro_rules! foo {
|
||||
($a:expr) => $a; //~ ERROR macro rhs must be delimited
|
||||
}
|
||||
|
||||
fn main() {
|
||||
foo!(0);
|
||||
}
|
@ -9,7 +9,7 @@
|
||||
// except according to those terms.
|
||||
|
||||
macro_rules! Id {
|
||||
{ $T:tt } => $T
|
||||
($T:tt) => ($T);
|
||||
}
|
||||
|
||||
struct Foo<T> {
|
||||
|
Loading…
Reference in New Issue
Block a user