From cda33346d0e9e4d1ff26163583831f96d42a4bc0 Mon Sep 17 00:00:00 2001 From: Huon Wilson Date: Tue, 18 Mar 2014 23:14:08 +1100 Subject: [PATCH] syntax: allow `trace_macros!` and `log_syntax!` in item position. Previously trace_macros!(true) fn main() {} would complain about `trace_macros` being an expression macro in item position. This is a pointless limitation, because the macro is purely compile-time, with no runtime effect. (And similarly for log_syntax.) This also changes the behaviour of `trace_macros!` very slightly, it used to be equivalent to macro_rules! trace_macros { (true $($_x: tt)*) => { true }; (false $($_x: tt)*) => { false } } I.e. you could invoke it with arbitrary trailing arguments, which were ignored. It is changed to accept only exactly `true` or `false` (with no trailing arguments) and expands to `()`. --- src/libsyntax/ext/base.rs | 22 +++++++++++-- src/libsyntax/ext/log_syntax.rs | 14 ++------ src/libsyntax/ext/trace_macros.rs | 32 ++++++------------- src/test/compile-fail/issue-11692.rs | 1 - src/test/compile-fail/trace_macros-format.rs | 29 +++++++++++++++++ ...log_syntax-trace_macros-macro-locations.rs | 30 +++++++++++++++++ 6 files changed, 92 insertions(+), 36 deletions(-) create mode 100644 src/test/compile-fail/trace_macros-format.rs create mode 100644 src/test/run-pass/log_syntax-trace_macros-macro-locations.rs diff --git a/src/libsyntax/ext/base.rs b/src/libsyntax/ext/base.rs index df2c265e6ebf3..97f85a1c807b5 100644 --- a/src/libsyntax/ext/base.rs +++ b/src/libsyntax/ext/base.rs @@ -120,13 +120,31 @@ impl MacResult { pub fn raw_dummy_expr(sp: codemap::Span) -> @ast::Expr { @ast::Expr { id: ast::DUMMY_NODE_ID, - node: ast::ExprTup(Vec::new()), - span: sp + node: ast::ExprLit(@codemap::respan(sp, ast::LitNil)), + span: sp, } } pub fn dummy_expr(sp: codemap::Span) -> MacResult { MRExpr(MacResult::raw_dummy_expr(sp)) } + pub fn dummy_any(sp: codemap::Span) -> MacResult { + MRAny(~DummyMacResult { sp: sp }) + } +} +struct DummyMacResult { + sp: codemap::Span +} +impl AnyMacro for DummyMacResult { + fn make_expr(&self) -> @ast::Expr { + MacResult::raw_dummy_expr(self.sp) + } + fn make_items(&self) -> SmallVector<@ast::Item> { + SmallVector::zero() + } + fn make_stmt(&self) -> @ast::Stmt { + @codemap::respan(self.sp, + ast::StmtExpr(MacResult::raw_dummy_expr(self.sp), ast::DUMMY_NODE_ID)) + } } /// An enum representing the different kinds of syntax extensions. diff --git a/src/libsyntax/ext/log_syntax.rs b/src/libsyntax/ext/log_syntax.rs index b94928238e9bb..1ce08b8303ec9 100644 --- a/src/libsyntax/ext/log_syntax.rs +++ b/src/libsyntax/ext/log_syntax.rs @@ -10,11 +10,10 @@ use ast; use codemap; -use ext::base::*; use ext::base; use print; -pub fn expand_syntax_ext(cx: &mut ExtCtxt, +pub fn expand_syntax_ext(cx: &mut base::ExtCtxt, sp: codemap::Span, tt: &[ast::TokenTree]) -> base::MacResult { @@ -23,13 +22,6 @@ pub fn expand_syntax_ext(cx: &mut ExtCtxt, println!("{}", print::pprust::tt_to_str(&ast::TTDelim( @tt.iter().map(|x| (*x).clone()).collect()))); - //trivial expression - MRExpr(@ast::Expr { - id: ast::DUMMY_NODE_ID, - node: ast::ExprLit(@codemap::Spanned { - node: ast::LitNil, - span: sp - }), - span: sp, - }) + // any so that `log_syntax` can be invoked as an expression and item. + base::MacResult::dummy_any(sp) } diff --git a/src/libsyntax/ext/trace_macros.rs b/src/libsyntax/ext/trace_macros.rs index fa49f06e51671..173cf4c9ad92a 100644 --- a/src/libsyntax/ext/trace_macros.rs +++ b/src/libsyntax/ext/trace_macros.rs @@ -12,33 +12,21 @@ use ast; use codemap::Span; use ext::base::ExtCtxt; use ext::base; -use parse::lexer::{new_tt_reader, Reader}; -use parse::parser::Parser; -use parse::token::keywords; +use parse::token::{keywords, is_keyword}; pub fn expand_trace_macros(cx: &mut ExtCtxt, sp: Span, tt: &[ast::TokenTree]) -> base::MacResult { - let sess = cx.parse_sess(); - let cfg = cx.cfg(); - let tt_rdr = new_tt_reader(&cx.parse_sess().span_diagnostic, - None, - tt.iter().map(|x| (*x).clone()).collect()); - let mut rust_parser = Parser(sess, cfg.clone(), tt_rdr.dup()); - - if rust_parser.is_keyword(keywords::True) { - cx.set_trace_macros(true); - } else if rust_parser.is_keyword(keywords::False) { - cx.set_trace_macros(false); - } else { - cx.span_err(sp, "trace_macros! only accepts `true` or `false`"); - return base::MacResult::dummy_expr(sp); + match tt { + [ast::TTTok(_, ref tok)] if is_keyword(keywords::True, tok) => { + cx.set_trace_macros(true); + } + [ast::TTTok(_, ref tok)] if is_keyword(keywords::False, tok) => { + cx.set_trace_macros(false); + } + _ => cx.span_err(sp, "trace_macros! accepts only `true` or `false`"), } - rust_parser.bump(); - - let mut rust_parser = Parser(sess, cfg, tt_rdr.dup()); - let result = rust_parser.parse_expr(); - base::MRExpr(result) + base::MacResult::dummy_any(sp) } diff --git a/src/test/compile-fail/issue-11692.rs b/src/test/compile-fail/issue-11692.rs index aed2c4d579a3d..848deac4d55c0 100644 --- a/src/test/compile-fail/issue-11692.rs +++ b/src/test/compile-fail/issue-11692.rs @@ -15,5 +15,4 @@ fn main() { concat!(test!()); //~^ ERROR: macro undefined: 'test' - //~^^ ERROR: expected a literal } diff --git a/src/test/compile-fail/trace_macros-format.rs b/src/test/compile-fail/trace_macros-format.rs new file mode 100644 index 0000000000000..557dcdc73c8e1 --- /dev/null +++ b/src/test/compile-fail/trace_macros-format.rs @@ -0,0 +1,29 @@ +// Copyright 2014 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. + +// ignore-fast feature doesn't work +#[feature(macro_rules, trace_macros)]; + +fn main() { + trace_macros!(); //~ ERROR trace_macros! accepts only `true` or `false` + trace_macros!(1); //~ ERROR trace_macros! accepts only `true` or `false` + trace_macros!(ident); //~ ERROR trace_macros! accepts only `true` or `false` + trace_macros!(for); //~ ERROR trace_macros! accepts only `true` or `false` + trace_macros!(true,); //~ ERROR trace_macros! accepts only `true` or `false` + trace_macros!(false 1); //~ ERROR trace_macros! accepts only `true` or `false` + + + // should be fine: + macro_rules! expando { + ($x: ident) => { trace_macros!($x) } + } + + expando!(true); +} diff --git a/src/test/run-pass/log_syntax-trace_macros-macro-locations.rs b/src/test/run-pass/log_syntax-trace_macros-macro-locations.rs new file mode 100644 index 0000000000000..a00ba6067dc7e --- /dev/null +++ b/src/test/run-pass/log_syntax-trace_macros-macro-locations.rs @@ -0,0 +1,30 @@ +// Copyright 2014 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. + +// ignore-fast feature doesn't work +#[feature(trace_macros, log_syntax)]; + +// make sure these macros can be used as in the various places that +// macros can occur. + +// items +trace_macros!(false) +log_syntax!() + +fn main() { + + // statements + trace_macros!(false); + log_syntax!(); + + // expressions + (trace_macros!(false), + log_syntax!()); +}