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 ast::{self, TokenTree};
|
||||||
use codemap::{Span, DUMMY_SP};
|
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::base::{NormalTT, TTMacroExpander};
|
||||||
use ext::tt::macro_parser::{Success, Error, Failure};
|
use ext::tt::macro_parser::{Success, Error, Failure};
|
||||||
use ext::tt::macro_parser::{MatchedSeq, MatchedNonterminal};
|
use ext::tt::macro_parser::{MatchedSeq, MatchedNonterminal};
|
||||||
@ -131,6 +131,7 @@ struct MacroRulesMacroExpander {
|
|||||||
imported_from: Option<ast::Ident>,
|
imported_from: Option<ast::Ident>,
|
||||||
lhses: Vec<TokenTree>,
|
lhses: Vec<TokenTree>,
|
||||||
rhses: Vec<TokenTree>,
|
rhses: Vec<TokenTree>,
|
||||||
|
valid: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TTMacroExpander for MacroRulesMacroExpander {
|
impl TTMacroExpander for MacroRulesMacroExpander {
|
||||||
@ -139,6 +140,9 @@ impl TTMacroExpander for MacroRulesMacroExpander {
|
|||||||
sp: Span,
|
sp: Span,
|
||||||
arg: &[TokenTree])
|
arg: &[TokenTree])
|
||||||
-> Box<MacResult+'cx> {
|
-> Box<MacResult+'cx> {
|
||||||
|
if !self.valid {
|
||||||
|
return DummyResult::any(sp);
|
||||||
|
}
|
||||||
generic_extension(cx,
|
generic_extension(cx,
|
||||||
sp,
|
sp,
|
||||||
self.name,
|
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
|
for (i, lhs) in lhses.iter().enumerate() { // try each arm's matchers
|
||||||
let lhs_tt = match *lhs {
|
let lhs_tt = match *lhs {
|
||||||
TokenTree::Delimited(_, ref delim) => &delim.tts[..],
|
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) {
|
match TokenTree::parse(cx, lhs_tt, arg) {
|
||||||
@ -179,7 +183,7 @@ fn generic_extension<'cx>(cx: &'cx ExtCtxt,
|
|||||||
let rhs = match rhses[i] {
|
let rhs = match rhses[i] {
|
||||||
// ignore delimiters
|
// ignore delimiters
|
||||||
TokenTree::Delimited(_, ref delimed) => delimed.tts.clone(),
|
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)
|
// rhs has holes ( `$id` and `$(...)` that need filled)
|
||||||
let trncbr = new_tt_reader(&cx.parse_sess().span_diagnostic,
|
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:
|
// Extract the arguments:
|
||||||
let lhses = match **argument_map.get(&lhs_nm.name).unwrap() {
|
let lhses = match **argument_map.get(&lhs_nm.name).unwrap() {
|
||||||
MatchedSeq(ref s, _) => {
|
MatchedSeq(ref s, _) => {
|
||||||
@ -296,11 +302,16 @@ pub fn compile<'cx>(cx: &'cx mut ExtCtxt,
|
|||||||
_ => cx.span_bug(def.span, "wrong-structured rhs")
|
_ => cx.span_bug(def.span, "wrong-structured rhs")
|
||||||
};
|
};
|
||||||
|
|
||||||
|
for rhs in &rhses {
|
||||||
|
valid &= check_rhs(cx, rhs);
|
||||||
|
}
|
||||||
|
|
||||||
let exp: Box<_> = Box::new(MacroRulesMacroExpander {
|
let exp: Box<_> = Box::new(MacroRulesMacroExpander {
|
||||||
name: def.ident,
|
name: def.ident,
|
||||||
imported_from: def.imported_from,
|
imported_from: def.imported_from,
|
||||||
lhses: lhses,
|
lhses: lhses,
|
||||||
rhses: rhses,
|
rhses: rhses,
|
||||||
|
valid: valid,
|
||||||
});
|
});
|
||||||
|
|
||||||
NormalTT(exp, Some(def.span), def.allow_internal_unstable)
|
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.
|
// 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.
|
// 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)
|
fn check_matcher<'a, I>(cx: &mut ExtCtxt, matcher: I, follow: &Token)
|
||||||
-> Option<(Span, Token)> where I: Iterator<Item=&'a TokenTree> {
|
-> 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.
|
// except according to those terms.
|
||||||
|
|
||||||
macro_rules! Id {
|
macro_rules! Id {
|
||||||
{ $T:tt } => $T
|
($T:tt) => ($T);
|
||||||
}
|
}
|
||||||
|
|
||||||
struct Foo<T> {
|
struct Foo<T> {
|
||||||
|
Loading…
Reference in New Issue
Block a user