syntax: make a macros-injection pass; conditionally define debug! to a noop based on cfg(debug).
Macros can be conditionally defined because stripping occurs before macro expansion, but, the built-in macros were only added as part of the actual expansion process and so couldn't be stripped to have definitions conditional on cfg flags. debug! is defined conditionally in terms of the debug config, expanding to nothing unless the --cfg debug flag is passed (to be precise it expands to `if false { normal_debug!(...) }` so that they are still type checked, and to avoid unused variable lints).
This commit is contained in:
parent
98c16549cb
commit
b48e37e8ee
|
@ -194,6 +194,10 @@ pub fn compile_rest(sess: Session,
|
||||||
// mod bar { macro_rules! baz!(() => {{}}) }
|
// mod bar { macro_rules! baz!(() => {{}}) }
|
||||||
//
|
//
|
||||||
// baz! should not use this definition unless foo is enabled.
|
// baz! should not use this definition unless foo is enabled.
|
||||||
|
crate = time(time_passes, ~"std macros injection", ||
|
||||||
|
syntax::ext::expand::inject_std_macros(sess.parse_sess, copy cfg,
|
||||||
|
crate));
|
||||||
|
|
||||||
crate = time(time_passes, ~"configuration 1", ||
|
crate = time(time_passes, ~"configuration 1", ||
|
||||||
front::config::strip_unconfigured_items(crate));
|
front::config::strip_unconfigured_items(crate));
|
||||||
|
|
||||||
|
@ -214,7 +218,7 @@ pub fn compile_rest(sess: Session,
|
||||||
assert!(phases.from != cu_no_trans);
|
assert!(phases.from != cu_no_trans);
|
||||||
|
|
||||||
let (llcx, llmod, link_meta) = {
|
let (llcx, llmod, link_meta) = {
|
||||||
crate = time(time_passes, ~"extra injection", ||
|
crate = time(time_passes, ~"std injection", ||
|
||||||
front::std_inject::maybe_inject_libstd_ref(sess, crate));
|
front::std_inject::maybe_inject_libstd_ref(sess, crate));
|
||||||
|
|
||||||
let ast_map = time(time_passes, ~"ast indexing", ||
|
let ast_map = time(time_passes, ~"ast indexing", ||
|
||||||
|
|
|
@ -113,6 +113,8 @@ fn build_ctxt(sess: Session,
|
||||||
|
|
||||||
use rustc::front::config;
|
use rustc::front::config;
|
||||||
|
|
||||||
|
let ast = syntax::ext::expand::inject_std_macros(sess.parse_sess,
|
||||||
|
copy sess.opts.cfg, ast);
|
||||||
let ast = config::strip_unconfigured_items(ast);
|
let ast = config::strip_unconfigured_items(ast);
|
||||||
let ast = syntax::ext::expand::expand_crate(sess.parse_sess,
|
let ast = syntax::ext::expand::expand_crate(sess.parse_sess,
|
||||||
copy sess.opts.cfg, ast);
|
copy sess.opts.cfg, ast);
|
||||||
|
|
|
@ -8,15 +8,14 @@
|
||||||
// option. This file may not be copied, modified, or distributed
|
// option. This file may not be copied, modified, or distributed
|
||||||
// except according to those terms.
|
// except according to those terms.
|
||||||
|
|
||||||
use ast::{blk_, attribute_, attr_outer, meta_word};
|
use ast::{blk_, crate, expr_, expr_mac, mac_invoc_tt};
|
||||||
use ast::{crate, expr_, expr_mac, mac_invoc_tt};
|
|
||||||
use ast::{item_mac, stmt_, stmt_mac, stmt_expr, stmt_semi};
|
use ast::{item_mac, stmt_, stmt_mac, stmt_expr, stmt_semi};
|
||||||
use ast::{illegal_ctxt};
|
use ast::{illegal_ctxt};
|
||||||
use ast;
|
use ast;
|
||||||
use ast_util::{new_rename, new_mark, resolve};
|
use ast_util::{new_rename, new_mark, resolve};
|
||||||
use attr;
|
use attr;
|
||||||
use codemap;
|
use codemap;
|
||||||
use codemap::{span, ExpnInfo, NameAndSpan, spanned};
|
use codemap::{span, ExpnInfo, NameAndSpan};
|
||||||
use ext::base::*;
|
use ext::base::*;
|
||||||
use fold::*;
|
use fold::*;
|
||||||
use parse;
|
use parse;
|
||||||
|
@ -452,9 +451,11 @@ pub fn new_span(cx: @ExtCtxt, sp: span) -> span {
|
||||||
// the default compilation environment. It would be much nicer to use
|
// the default compilation environment. It would be much nicer to use
|
||||||
// a mechanism like syntax_quote to ensure hygiene.
|
// a mechanism like syntax_quote to ensure hygiene.
|
||||||
|
|
||||||
pub fn core_macros() -> @str {
|
pub fn std_macros() -> @str {
|
||||||
return
|
return
|
||||||
@"pub mod macros {
|
@"pub mod __std_macros {
|
||||||
|
#[macro_escape];
|
||||||
|
|
||||||
macro_rules! ignore (($($x:tt)*) => (()))
|
macro_rules! ignore (($($x:tt)*) => (()))
|
||||||
|
|
||||||
macro_rules! error (
|
macro_rules! error (
|
||||||
|
@ -484,7 +485,9 @@ pub fn core_macros() -> @str {
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
macro_rules! debug (
|
// conditionally define debug!, but keep it type checking even
|
||||||
|
// in non-debug builds.
|
||||||
|
macro_rules! __debug (
|
||||||
($arg:expr) => (
|
($arg:expr) => (
|
||||||
__log(4u32, fmt!( \"%?\", $arg ))
|
__log(4u32, fmt!( \"%?\", $arg ))
|
||||||
);
|
);
|
||||||
|
@ -493,6 +496,22 @@ pub fn core_macros() -> @str {
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
#[cfg(debug)]
|
||||||
|
#[macro_escape]
|
||||||
|
mod debug_macro {
|
||||||
|
macro_rules! debug (($($arg:expr),*) => {
|
||||||
|
__debug!($($arg),*)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(not(debug))]
|
||||||
|
#[macro_escape]
|
||||||
|
mod debug_macro {
|
||||||
|
macro_rules! debug (($($arg:expr),*) => {
|
||||||
|
if false { __debug!($($arg),*) }
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
macro_rules! fail(
|
macro_rules! fail(
|
||||||
() => (
|
() => (
|
||||||
fail!(\"explicit failure\")
|
fail!(\"explicit failure\")
|
||||||
|
@ -668,6 +687,35 @@ pub fn core_macros() -> @str {
|
||||||
}";
|
}";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// add a bunch of macros as though they were placed at the head of the
|
||||||
|
// program (ick). This should run before cfg stripping.
|
||||||
|
pub fn inject_std_macros(parse_sess: @mut parse::ParseSess,
|
||||||
|
cfg: ast::crate_cfg, c: &crate) -> @crate {
|
||||||
|
let sm = match parse_item_from_source_str(@"<std-macros>",
|
||||||
|
std_macros(),
|
||||||
|
copy cfg,
|
||||||
|
~[],
|
||||||
|
parse_sess) {
|
||||||
|
Some(item) => item,
|
||||||
|
None => fail!("expected core macros to parse correctly")
|
||||||
|
};
|
||||||
|
|
||||||
|
let injecter = @AstFoldFns {
|
||||||
|
fold_mod: |modd, _| {
|
||||||
|
// just inject the std macros at the start of the first
|
||||||
|
// module in the crate (i.e the crate file itself.)
|
||||||
|
let items = vec::append(~[sm], modd.items);
|
||||||
|
ast::_mod {
|
||||||
|
items: items,
|
||||||
|
// FIXME #2543: Bad copy.
|
||||||
|
.. copy *modd
|
||||||
|
}
|
||||||
|
},
|
||||||
|
.. *default_ast_fold()
|
||||||
|
};
|
||||||
|
@make_fold(injecter).fold_crate(c)
|
||||||
|
}
|
||||||
|
|
||||||
pub fn expand_crate(parse_sess: @mut parse::ParseSess,
|
pub fn expand_crate(parse_sess: @mut parse::ParseSess,
|
||||||
cfg: ast::crate_cfg, c: &crate) -> @crate {
|
cfg: ast::crate_cfg, c: &crate) -> @crate {
|
||||||
// adding *another* layer of indirection here so that the block
|
// adding *another* layer of indirection here so that the block
|
||||||
|
@ -692,33 +740,6 @@ pub fn expand_crate(parse_sess: @mut parse::ParseSess,
|
||||||
new_span: |a| new_span(cx, a),
|
new_span: |a| new_span(cx, a),
|
||||||
.. *afp};
|
.. *afp};
|
||||||
let f = make_fold(f_pre);
|
let f = make_fold(f_pre);
|
||||||
// add a bunch of macros as though they were placed at the
|
|
||||||
// head of the program (ick).
|
|
||||||
let attrs = ~[
|
|
||||||
spanned {
|
|
||||||
span: codemap::dummy_sp(),
|
|
||||||
node: attribute_ {
|
|
||||||
style: attr_outer,
|
|
||||||
value: @spanned {
|
|
||||||
node: meta_word(@"macro_escape"),
|
|
||||||
span: codemap::dummy_sp(),
|
|
||||||
},
|
|
||||||
is_sugared_doc: false,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
];
|
|
||||||
|
|
||||||
let cm = match parse_item_from_source_str(@"<core-macros>",
|
|
||||||
core_macros(),
|
|
||||||
copy cfg,
|
|
||||||
attrs,
|
|
||||||
parse_sess) {
|
|
||||||
Some(item) => item,
|
|
||||||
None => cx.bug("expected core macros to parse correctly")
|
|
||||||
};
|
|
||||||
// This is run for its side-effects on the expander env,
|
|
||||||
// as it registers all the core macros as expanders.
|
|
||||||
f.fold_item(cm);
|
|
||||||
|
|
||||||
@f.fold_crate(c)
|
@f.fold_crate(c)
|
||||||
}
|
}
|
||||||
|
@ -789,6 +810,8 @@ mod test {
|
||||||
@"<test>",
|
@"<test>",
|
||||||
src,
|
src,
|
||||||
~[],sess);
|
~[],sess);
|
||||||
|
let crate_ast = inject_std_macros(sess, ~[], crate_ast);
|
||||||
|
// don't bother with striping, doesn't affect fail!.
|
||||||
expand_crate(sess,~[],crate_ast);
|
expand_crate(sess,~[],crate_ast);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -836,20 +859,14 @@ mod test {
|
||||||
expand_crate(sess,~[],crate_ast);
|
expand_crate(sess,~[],crate_ast);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test] fn core_macros_must_parse () {
|
#[test] fn std_macros_must_parse () {
|
||||||
let src = @"
|
let src = super::std_macros();
|
||||||
pub mod macros {
|
|
||||||
macro_rules! ignore (($($x:tt)*) => (()))
|
|
||||||
|
|
||||||
macro_rules! error ( ($( $arg:expr ),+) => (
|
|
||||||
log(::core::error, fmt!( $($arg),+ )) ))
|
|
||||||
}";
|
|
||||||
let sess = parse::new_parse_sess(None);
|
let sess = parse::new_parse_sess(None);
|
||||||
let cfg = ~[];
|
let cfg = ~[];
|
||||||
let item_ast = parse::parse_item_from_source_str(
|
let item_ast = parse::parse_item_from_source_str(
|
||||||
@"<test>",
|
@"<test>",
|
||||||
src,
|
src,
|
||||||
cfg,~[make_dummy_attr (@"macro_escape")],sess);
|
cfg,~[],sess);
|
||||||
match item_ast {
|
match item_ast {
|
||||||
Some(_) => (), // success
|
Some(_) => (), // success
|
||||||
None => fail!("expected this to parse")
|
None => fail!("expected this to parse")
|
||||||
|
|
|
@ -0,0 +1,17 @@
|
||||||
|
// Copyright 2012 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.
|
||||||
|
|
||||||
|
// xfail-fast exec-env directive doesn't work for check-fast
|
||||||
|
// exec-env:RUST_LOG=conditional-debug-macro-off=4
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
// only fails if debug! evaluates its argument.
|
||||||
|
debug!({ if true { fail!() } });
|
||||||
|
}
|
|
@ -0,0 +1,21 @@
|
||||||
|
// Copyright 2012 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.
|
||||||
|
|
||||||
|
// xfail-fast compile-flags directive doesn't work for check-fast
|
||||||
|
// compile-flags: --cfg debug
|
||||||
|
// exec-env:RUST_LOG=conditional-debug-macro-on=4
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
// exits early if debug! evaluates its arguments, otherwise it
|
||||||
|
// will hit the fail.
|
||||||
|
debug!({ if true { return; } });
|
||||||
|
|
||||||
|
fail!();
|
||||||
|
}
|
Loading…
Reference in New Issue