From cce7b8bd25484a882a2be5472d6a2aadd84e9539 Mon Sep 17 00:00:00 2001 From: Seo Sanghyeon Date: Sat, 14 Nov 2015 19:50:46 +0900 Subject: [PATCH] Check macro definition and do not expand invalid macros --- src/libsyntax/ext/tt/macro_rules.rs | 25 ++++++++++++++++++++--- src/test/compile-fail/macro-error.rs | 19 +++++++++++++++++ src/test/compile-fail/type-macros-fail.rs | 2 +- 3 files changed, 42 insertions(+), 4 deletions(-) create mode 100644 src/test/compile-fail/macro-error.rs diff --git a/src/libsyntax/ext/tt/macro_rules.rs b/src/libsyntax/ext/tt/macro_rules.rs index c5cbb95aeeb..323cc53ecef 100644 --- a/src/libsyntax/ext/tt/macro_rules.rs +++ b/src/libsyntax/ext/tt/macro_rules.rs @@ -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, lhses: Vec, rhses: Vec, + valid: bool, } impl TTMacroExpander for MacroRulesMacroExpander { @@ -139,6 +140,9 @@ impl TTMacroExpander for MacroRulesMacroExpander { sp: Span, arg: &[TokenTree]) -> Box { + 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 { diff --git a/src/test/compile-fail/macro-error.rs b/src/test/compile-fail/macro-error.rs new file mode 100644 index 00000000000..817b675aedf --- /dev/null +++ b/src/test/compile-fail/macro-error.rs @@ -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 or the MIT license +// , 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); +} diff --git a/src/test/compile-fail/type-macros-fail.rs b/src/test/compile-fail/type-macros-fail.rs index d51176a925d..756f5d4547a 100644 --- a/src/test/compile-fail/type-macros-fail.rs +++ b/src/test/compile-fail/type-macros-fail.rs @@ -9,7 +9,7 @@ // except according to those terms. macro_rules! Id { - { $T:tt } => $T + ($T:tt) => ($T); } struct Foo {