diff --git a/src/librustc/driver/driver.rs b/src/librustc/driver/driver.rs index e8ef95b811e..d41c1167c70 100644 --- a/src/librustc/driver/driver.rs +++ b/src/librustc/driver/driver.rs @@ -194,6 +194,10 @@ pub fn compile_rest(sess: Session, // mod bar { macro_rules! baz!(() => {{}}) } // // 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", || front::config::strip_unconfigured_items(crate)); @@ -214,7 +218,7 @@ pub fn compile_rest(sess: Session, assert!(phases.from != cu_no_trans); 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)); let ast_map = time(time_passes, ~"ast indexing", || diff --git a/src/librustdoc/astsrv.rs b/src/librustdoc/astsrv.rs index 9c586ae95d1..559186d316e 100644 --- a/src/librustdoc/astsrv.rs +++ b/src/librustdoc/astsrv.rs @@ -113,6 +113,8 @@ fn build_ctxt(sess: Session, 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 = syntax::ext::expand::expand_crate(sess.parse_sess, copy sess.opts.cfg, ast); diff --git a/src/libsyntax/ext/expand.rs b/src/libsyntax/ext/expand.rs index b45cde6a8e3..d63d914edd3 100644 --- a/src/libsyntax/ext/expand.rs +++ b/src/libsyntax/ext/expand.rs @@ -8,15 +8,14 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use ast::{blk_, attribute_, attr_outer, meta_word}; -use ast::{crate, expr_, expr_mac, mac_invoc_tt}; +use ast::{blk_, crate, expr_, expr_mac, mac_invoc_tt}; use ast::{item_mac, stmt_, stmt_mac, stmt_expr, stmt_semi}; use ast::{illegal_ctxt}; use ast; use ast_util::{new_rename, new_mark, resolve}; use attr; use codemap; -use codemap::{span, ExpnInfo, NameAndSpan, spanned}; +use codemap::{span, ExpnInfo, NameAndSpan}; use ext::base::*; use fold::*; 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 // a mechanism like syntax_quote to ensure hygiene. -pub fn core_macros() -> @str { +pub fn std_macros() -> @str { return -@"pub mod macros { +@"pub mod __std_macros { + #[macro_escape]; + macro_rules! ignore (($($x:tt)*) => (())) 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) => ( __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( () => ( 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(), + 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, cfg: ast::crate_cfg, c: &crate) -> @crate { // 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), .. *afp}; 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(), - 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) } @@ -789,6 +810,8 @@ mod test { @"", src, ~[],sess); + let crate_ast = inject_std_macros(sess, ~[], crate_ast); + // don't bother with striping, doesn't affect fail!. expand_crate(sess,~[],crate_ast); } @@ -836,20 +859,14 @@ mod test { expand_crate(sess,~[],crate_ast); } - #[test] fn core_macros_must_parse () { - let src = @" - pub mod macros { - macro_rules! ignore (($($x:tt)*) => (())) - - macro_rules! error ( ($( $arg:expr ),+) => ( - log(::core::error, fmt!( $($arg),+ )) )) -}"; + #[test] fn std_macros_must_parse () { + let src = super::std_macros(); let sess = parse::new_parse_sess(None); let cfg = ~[]; let item_ast = parse::parse_item_from_source_str( @"", src, - cfg,~[make_dummy_attr (@"macro_escape")],sess); + cfg,~[],sess); match item_ast { Some(_) => (), // success None => fail!("expected this to parse") diff --git a/src/test/run-pass/conditional-debug-macro-off.rs b/src/test/run-pass/conditional-debug-macro-off.rs new file mode 100644 index 00000000000..f40c8112e0b --- /dev/null +++ b/src/test/run-pass/conditional-debug-macro-off.rs @@ -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 or the MIT license +// , 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!() } }); +} \ No newline at end of file diff --git a/src/test/run-pass/conditional-debug-macro-on.rs b/src/test/run-pass/conditional-debug-macro-on.rs new file mode 100644 index 00000000000..65b751a5826 --- /dev/null +++ b/src/test/run-pass/conditional-debug-macro-on.rs @@ -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 or the MIT license +// , 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!(); +} \ No newline at end of file