Skip to content

Commit b48e37e

Browse files
committed
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).
1 parent 98c1654 commit b48e37e

File tree

5 files changed

+104
-43
lines changed

5 files changed

+104
-43
lines changed

src/librustc/driver/driver.rs

+5-1
Original file line numberDiff line numberDiff line change
@@ -194,6 +194,10 @@ pub fn compile_rest(sess: Session,
194194
// mod bar { macro_rules! baz!(() => {{}}) }
195195
//
196196
// baz! should not use this definition unless foo is enabled.
197+
crate = time(time_passes, ~"std macros injection", ||
198+
syntax::ext::expand::inject_std_macros(sess.parse_sess, copy cfg,
199+
crate));
200+
197201
crate = time(time_passes, ~"configuration 1", ||
198202
front::config::strip_unconfigured_items(crate));
199203

@@ -214,7 +218,7 @@ pub fn compile_rest(sess: Session,
214218
assert!(phases.from != cu_no_trans);
215219

216220
let (llcx, llmod, link_meta) = {
217-
crate = time(time_passes, ~"extra injection", ||
221+
crate = time(time_passes, ~"std injection", ||
218222
front::std_inject::maybe_inject_libstd_ref(sess, crate));
219223

220224
let ast_map = time(time_passes, ~"ast indexing", ||

src/librustdoc/astsrv.rs

+2
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,8 @@ fn build_ctxt(sess: Session,
113113

114114
use rustc::front::config;
115115

116+
let ast = syntax::ext::expand::inject_std_macros(sess.parse_sess,
117+
copy sess.opts.cfg, ast);
116118
let ast = config::strip_unconfigured_items(ast);
117119
let ast = syntax::ext::expand::expand_crate(sess.parse_sess,
118120
copy sess.opts.cfg, ast);

src/libsyntax/ext/expand.rs

+59-42
Original file line numberDiff line numberDiff line change
@@ -8,15 +8,14 @@
88
// option. This file may not be copied, modified, or distributed
99
// except according to those terms.
1010

11-
use ast::{blk_, attribute_, attr_outer, meta_word};
12-
use ast::{crate, expr_, expr_mac, mac_invoc_tt};
11+
use ast::{blk_, crate, expr_, expr_mac, mac_invoc_tt};
1312
use ast::{item_mac, stmt_, stmt_mac, stmt_expr, stmt_semi};
1413
use ast::{illegal_ctxt};
1514
use ast;
1615
use ast_util::{new_rename, new_mark, resolve};
1716
use attr;
1817
use codemap;
19-
use codemap::{span, ExpnInfo, NameAndSpan, spanned};
18+
use codemap::{span, ExpnInfo, NameAndSpan};
2019
use ext::base::*;
2120
use fold::*;
2221
use parse;
@@ -452,9 +451,11 @@ pub fn new_span(cx: @ExtCtxt, sp: span) -> span {
452451
// the default compilation environment. It would be much nicer to use
453452
// a mechanism like syntax_quote to ensure hygiene.
454453

455-
pub fn core_macros() -> @str {
454+
pub fn std_macros() -> @str {
456455
return
457-
@"pub mod macros {
456+
@"pub mod __std_macros {
457+
#[macro_escape];
458+
458459
macro_rules! ignore (($($x:tt)*) => (()))
459460

460461
macro_rules! error (
@@ -484,7 +485,9 @@ pub fn core_macros() -> @str {
484485
)
485486
)
486487

487-
macro_rules! debug (
488+
// conditionally define debug!, but keep it type checking even
489+
// in non-debug builds.
490+
macro_rules! __debug (
488491
($arg:expr) => (
489492
__log(4u32, fmt!( \"%?\", $arg ))
490493
);
@@ -493,6 +496,22 @@ pub fn core_macros() -> @str {
493496
)
494497
)
495498

499+
#[cfg(debug)]
500+
#[macro_escape]
501+
mod debug_macro {
502+
macro_rules! debug (($($arg:expr),*) => {
503+
__debug!($($arg),*)
504+
})
505+
}
506+
507+
#[cfg(not(debug))]
508+
#[macro_escape]
509+
mod debug_macro {
510+
macro_rules! debug (($($arg:expr),*) => {
511+
if false { __debug!($($arg),*) }
512+
})
513+
}
514+
496515
macro_rules! fail(
497516
() => (
498517
fail!(\"explicit failure\")
@@ -668,6 +687,35 @@ pub fn core_macros() -> @str {
668687
}";
669688
}
670689
690+
// add a bunch of macros as though they were placed at the head of the
691+
// program (ick). This should run before cfg stripping.
692+
pub fn inject_std_macros(parse_sess: @mut parse::ParseSess,
693+
cfg: ast::crate_cfg, c: &crate) -> @crate {
694+
let sm = match parse_item_from_source_str(@"<std-macros>",
695+
std_macros(),
696+
copy cfg,
697+
~[],
698+
parse_sess) {
699+
Some(item) => item,
700+
None => fail!("expected core macros to parse correctly")
701+
};
702+
703+
let injecter = @AstFoldFns {
704+
fold_mod: |modd, _| {
705+
// just inject the std macros at the start of the first
706+
// module in the crate (i.e the crate file itself.)
707+
let items = vec::append(~[sm], modd.items);
708+
ast::_mod {
709+
items: items,
710+
// FIXME #2543: Bad copy.
711+
.. copy *modd
712+
}
713+
},
714+
.. *default_ast_fold()
715+
};
716+
@make_fold(injecter).fold_crate(c)
717+
}
718+
671719
pub fn expand_crate(parse_sess: @mut parse::ParseSess,
672720
cfg: ast::crate_cfg, c: &crate) -> @crate {
673721
// adding *another* layer of indirection here so that the block
@@ -692,33 +740,6 @@ pub fn expand_crate(parse_sess: @mut parse::ParseSess,
692740
new_span: |a| new_span(cx, a),
693741
.. *afp};
694742
let f = make_fold(f_pre);
695-
// add a bunch of macros as though they were placed at the
696-
// head of the program (ick).
697-
let attrs = ~[
698-
spanned {
699-
span: codemap::dummy_sp(),
700-
node: attribute_ {
701-
style: attr_outer,
702-
value: @spanned {
703-
node: meta_word(@"macro_escape"),
704-
span: codemap::dummy_sp(),
705-
},
706-
is_sugared_doc: false,
707-
}
708-
}
709-
];
710-
711-
let cm = match parse_item_from_source_str(@"<core-macros>",
712-
core_macros(),
713-
copy cfg,
714-
attrs,
715-
parse_sess) {
716-
Some(item) => item,
717-
None => cx.bug("expected core macros to parse correctly")
718-
};
719-
// This is run for its side-effects on the expander env,
720-
// as it registers all the core macros as expanders.
721-
f.fold_item(cm);
722743

723744
@f.fold_crate(c)
724745
}
@@ -789,6 +810,8 @@ mod test {
789810
@"<test>",
790811
src,
791812
~[],sess);
813+
let crate_ast = inject_std_macros(sess, ~[], crate_ast);
814+
// don't bother with striping, doesn't affect fail!.
792815
expand_crate(sess,~[],crate_ast);
793816
}
794817
@@ -836,20 +859,14 @@ mod test {
836859
expand_crate(sess,~[],crate_ast);
837860
}
838861
839-
#[test] fn core_macros_must_parse () {
840-
let src = @"
841-
pub mod macros {
842-
macro_rules! ignore (($($x:tt)*) => (()))
843-
844-
macro_rules! error ( ($( $arg:expr ),+) => (
845-
log(::core::error, fmt!( $($arg),+ )) ))
846-
}";
862+
#[test] fn std_macros_must_parse () {
863+
let src = super::std_macros();
847864
let sess = parse::new_parse_sess(None);
848865
let cfg = ~[];
849866
let item_ast = parse::parse_item_from_source_str(
850867
@"<test>",
851868
src,
852-
cfg,~[make_dummy_attr (@"macro_escape")],sess);
869+
cfg,~[],sess);
853870
match item_ast {
854871
Some(_) => (), // success
855872
None => fail!("expected this to parse")
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
// xfail-fast exec-env directive doesn't work for check-fast
12+
// exec-env:RUST_LOG=conditional-debug-macro-off=4
13+
14+
fn main() {
15+
// only fails if debug! evaluates its argument.
16+
debug!({ if true { fail!() } });
17+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
// xfail-fast compile-flags directive doesn't work for check-fast
12+
// compile-flags: --cfg debug
13+
// exec-env:RUST_LOG=conditional-debug-macro-on=4
14+
15+
fn main() {
16+
// exits early if debug! evaluates its arguments, otherwise it
17+
// will hit the fail.
18+
debug!({ if true { return; } });
19+
20+
fail!();
21+
}

0 commit comments

Comments
 (0)