From e5cc221aefaeb4ad233ae85cd17df35342272523 Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Sun, 20 Jul 2014 18:05:59 -0700 Subject: [PATCH 1/4] Remove useless RefCells --- src/librustc/front/test.rs | 23 +++++++++++------------ 1 file changed, 11 insertions(+), 12 deletions(-) diff --git a/src/librustc/front/test.rs b/src/librustc/front/test.rs index 0860d111a9ef0..889af7a884666 100644 --- a/src/librustc/front/test.rs +++ b/src/librustc/front/test.rs @@ -16,7 +16,6 @@ use driver::session::Session; use front::config; -use std::cell::RefCell; use std::gc::{Gc, GC}; use std::slice; use std::vec; @@ -46,9 +45,9 @@ struct Test { struct TestCtxt<'a> { sess: &'a Session, - path: RefCell>, + path: Vec, ext_cx: ExtCtxt<'a>, - testfns: RefCell >, + testfns: Vec, is_test_crate: bool, config: ast::CrateConfig, } @@ -86,9 +85,9 @@ impl<'a> fold::Folder for TestHarnessGenerator<'a> { } fn fold_item(&mut self, i: Gc) -> SmallVector> { - self.cx.path.borrow_mut().push(i.ident); + self.cx.path.push(i.ident); debug!("current path: {}", - ast_util::path_name_i(self.cx.path.borrow().as_slice())); + ast_util::path_name_i(self.cx.path.as_slice())); if is_test_fn(&self.cx, i) || is_bench_fn(&self.cx, i) { match i.node { @@ -102,12 +101,12 @@ impl<'a> fold::Folder for TestHarnessGenerator<'a> { debug!("this is a test function"); let test = Test { span: i.span, - path: self.cx.path.borrow().clone(), + path: self.cx.path.clone(), bench: is_bench_fn(&self.cx, i), ignore: is_ignored(&self.cx, i), should_fail: should_fail(i) }; - self.cx.testfns.borrow_mut().push(test); + self.cx.testfns.push(test); // debug!("have {} test/bench functions", // cx.testfns.len()); } @@ -115,7 +114,7 @@ impl<'a> fold::Folder for TestHarnessGenerator<'a> { } let res = fold::noop_fold_item(&*i, self); - self.cx.path.borrow_mut().pop(); + self.cx.path.pop(); res } @@ -155,8 +154,8 @@ fn generate_test_harness(sess: &Session, krate: ast::Crate) deriving_hash_type_parameter: false, crate_name: "test".to_string(), }), - path: RefCell::new(Vec::new()), - testfns: RefCell::new(Vec::new()), + path: Vec::new(), + testfns: Vec::new(), is_test_crate: is_test_crate(&krate), config: krate.config.clone(), }; @@ -399,13 +398,13 @@ fn is_test_crate(krate: &ast::Crate) -> bool { } fn mk_test_descs(cx: &TestCtxt) -> Gc { - debug!("building test vector from {} tests", cx.testfns.borrow().len()); + debug!("building test vector from {} tests", cx.testfns.len()); box(GC) ast::Expr { id: ast::DUMMY_NODE_ID, node: ast::ExprVstore(box(GC) ast::Expr { id: ast::DUMMY_NODE_ID, - node: ast::ExprVec(cx.testfns.borrow().iter().map(|test| { + node: ast::ExprVec(cx.testfns.iter().map(|test| { mk_test_desc_and_fn_rec(cx, test) }).collect()), span: DUMMY_SP, From bca53e9382b92aa8a854840fee9e0d92c5cb5451 Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Sun, 20 Jul 2014 22:10:11 -0700 Subject: [PATCH 2/4] Restructure test harness We now build up a set of modules that reexport everything the test framework needs, instead of turning off privacy. --- src/librustc/front/test.rs | 85 ++++++++++++++++++++++++-------------- 1 file changed, 53 insertions(+), 32 deletions(-) diff --git a/src/librustc/front/test.rs b/src/librustc/front/test.rs index 889af7a884666..3e6b8a92d2d63 100644 --- a/src/librustc/front/test.rs +++ b/src/librustc/front/test.rs @@ -18,6 +18,7 @@ use front::config; use std::gc::{Gc, GC}; use std::slice; +use std::mem; use std::vec; use syntax::ast_util::*; use syntax::attr::AttrMetaMethods; @@ -25,6 +26,7 @@ use syntax::attr; use syntax::codemap::{DUMMY_SP, Span, ExpnInfo, NameAndSpan, MacroAttribute}; use syntax::codemap; use syntax::ext::base::ExtCtxt; +use syntax::ext::build::AstBuilder; use syntax::ext::expand::ExpansionConfig; use syntax::fold::Folder; use syntax::fold; @@ -46,8 +48,10 @@ struct Test { struct TestCtxt<'a> { sess: &'a Session, path: Vec, + reexports: Vec>, ext_cx: ExtCtxt<'a>, testfns: Vec, + reexport_mod_ident: ast::Ident, is_test_crate: bool, config: ast::CrateConfig, } @@ -107,25 +111,35 @@ impl<'a> fold::Folder for TestHarnessGenerator<'a> { should_fail: should_fail(i) }; self.cx.testfns.push(test); + self.cx.reexports.push(self.cx.path.clone()); // debug!("have {} test/bench functions", // cx.testfns.len()); } } } - let res = fold::noop_fold_item(&*i, self); + // We don't want to recurse into anything other than mods, since + // mods or tests inside of functions will break things + let res = match i.node { + ast::ItemMod(..) => fold::noop_fold_item(&*i, self), + _ => SmallVector::one(i), + }; self.cx.path.pop(); res } fn fold_mod(&mut self, m: &ast::Mod) -> ast::Mod { + let reexports = mem::replace(&mut self.cx.reexports, Vec::new()); + let mut mod_folded = fold::noop_fold_mod(m, self); + let reexports = mem::replace(&mut self.cx.reexports, reexports); + // Remove any #[main] from the AST so it doesn't clash with // the one we're going to add. Only if compiling an executable. fn nomain(item: Gc) -> Gc { box(GC) ast::Item { attrs: item.attrs.iter().filter_map(|attr| { - if !attr.name().equiv(&("main")) { + if !attr.check_name("main") { Some(*attr) } else { None @@ -135,18 +149,37 @@ impl<'a> fold::Folder for TestHarnessGenerator<'a> { } } - let mod_nomain = ast::Mod { - inner: m.inner, - view_items: m.view_items.clone(), - items: m.items.iter().map(|i| nomain(*i)).collect(), - }; + for i in mod_folded.items.mut_iter() { + *i = nomain(*i); + } + mod_folded.items.push(mk_reexport_mod(&mut self.cx, reexports)); + self.cx.reexports.push(self.cx.path.clone()); + + mod_folded + } +} - fold::noop_fold_mod(&mod_nomain, self) +fn mk_reexport_mod(cx: &mut TestCtxt, reexports: Vec>) + -> Gc { + let view_items = reexports.move_iter().map(|r| { + cx.ext_cx.view_use_simple(DUMMY_SP, ast::Public, cx.ext_cx.path(DUMMY_SP, r)) + }).collect(); + let reexport_mod = ast::Mod { + inner: DUMMY_SP, + view_items: view_items, + items: Vec::new(), + }; + box(GC) ast::Item { + ident: cx.reexport_mod_ident.clone(), + attrs: Vec::new(), + id: ast::DUMMY_NODE_ID, + node: ast::ItemMod(reexport_mod), + vis: ast::Public, + span: DUMMY_SP, } } -fn generate_test_harness(sess: &Session, krate: ast::Crate) - -> ast::Crate { +fn generate_test_harness(sess: &Session, krate: ast::Crate) -> ast::Crate { let mut cx: TestCtxt = TestCtxt { sess: sess, ext_cx: ExtCtxt::new(&sess.parse_sess, sess.opts.cfg.clone(), @@ -155,7 +188,9 @@ fn generate_test_harness(sess: &Session, krate: ast::Crate) crate_name: "test".to_string(), }), path: Vec::new(), + reexports: Vec::new(), testfns: Vec::new(), + reexport_mod_ident: token::str_to_ident("__test_reexports"), is_test_crate: is_test_crate(&krate), config: krate.config.clone(), }; @@ -170,7 +205,7 @@ fn generate_test_harness(sess: &Session, krate: ast::Crate) }); let mut fold = TestHarnessGenerator { - cx: cx + cx: cx, }; let res = fold.fold_crate(krate); fold.cx.ext_cx.bt_pop(); @@ -274,7 +309,6 @@ fn add_test_module(cx: &TestCtxt, m: &ast::Mod) -> ast::Mod { We're going to be building a module that looks more or less like: mod __test { - #![!resolve_unexported] extern crate test (name = "test", vers = "..."); fn main() { test::test_main_static(::os::args().as_slice(), tests) @@ -331,15 +365,9 @@ fn mk_test_module(cx: &TestCtxt) -> Gc { }; let item_ = ast::ItemMod(testmod); - // This attribute tells resolve to let us call unexported functions - let resolve_unexported_str = InternedString::new("!resolve_unexported"); - let resolve_unexported_attr = - attr::mk_attr_inner(attr::mk_attr_id(), - attr::mk_word_item(resolve_unexported_str)); - let item = ast::Item { ident: token::str_to_ident("__test"), - attrs: vec!(resolve_unexported_attr), + attrs: Vec::new(), id: ast::DUMMY_NODE_ID, node: item_, vis: ast::Public, @@ -367,18 +395,6 @@ fn path_node(ids: Vec ) -> ast::Path { } } -fn path_node_global(ids: Vec ) -> ast::Path { - ast::Path { - span: DUMMY_SP, - global: true, - segments: ids.move_iter().map(|identifier| ast::PathSegment { - identifier: identifier, - lifetimes: Vec::new(), - types: OwnedSlice::empty(), - }).collect() - } -} - fn mk_tests(cx: &TestCtxt) -> Gc { // The vector of test_descs for this crate let test_descs = mk_test_descs(cx); @@ -430,7 +446,12 @@ fn mk_test_desc_and_fn_rec(cx: &TestCtxt, test: &Test) -> Gc { span: span }; - let fn_path = path_node_global(path); + let mut visible_path = Vec::new(); + for ident in path.move_iter() { + visible_path.push(cx.reexport_mod_ident.clone()); + visible_path.push(ident); + } + let fn_path = cx.ext_cx.path_global(DUMMY_SP, visible_path); let fn_expr = box(GC) ast::Expr { id: ast::DUMMY_NODE_ID, From 1d522a6bd2c2037a6165f69e1de71340c0edba82 Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Sun, 20 Jul 2014 22:11:43 -0700 Subject: [PATCH 3/4] Purge !resolve_unexported --- src/librustc/middle/privacy.rs | 7 ------- 1 file changed, 7 deletions(-) diff --git a/src/librustc/middle/privacy.rs b/src/librustc/middle/privacy.rs index cdb3f9dbb1dbf..1169e1c54803b 100644 --- a/src/librustc/middle/privacy.rs +++ b/src/librustc/middle/privacy.rs @@ -27,7 +27,6 @@ use util::nodemap::{NodeMap, NodeSet}; use syntax::ast; use syntax::ast_map; use syntax::ast_util::{is_local, local_def, PostExpansionMethod}; -use syntax::attr; use syntax::codemap::Span; use syntax::parse::token; use syntax::owned_slice::OwnedSlice; @@ -786,12 +785,6 @@ impl<'a> PrivacyVisitor<'a> { impl<'a> Visitor<()> for PrivacyVisitor<'a> { fn visit_item(&mut self, item: &ast::Item, _: ()) { - // Do not check privacy inside items with the resolve_unexported - // attribute. This is used for the test runner. - if attr::contains_name(item.attrs.as_slice(), "!resolve_unexported") { - return; - } - let orig_curitem = replace(&mut self.curitem, item.id); visit::walk_item(self, item, ()); self.curitem = orig_curitem; From 173dcec884885aa2babcf4ccd150860e924e733f Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Sun, 20 Jul 2014 22:34:09 -0700 Subject: [PATCH 4/4] Don't create reexport module if there are none --- src/librustc/front/test.rs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/librustc/front/test.rs b/src/librustc/front/test.rs index 3e6b8a92d2d63..08907f6c0ed5d 100644 --- a/src/librustc/front/test.rs +++ b/src/librustc/front/test.rs @@ -152,8 +152,10 @@ impl<'a> fold::Folder for TestHarnessGenerator<'a> { for i in mod_folded.items.mut_iter() { *i = nomain(*i); } - mod_folded.items.push(mk_reexport_mod(&mut self.cx, reexports)); - self.cx.reexports.push(self.cx.path.clone()); + if !reexports.is_empty() { + mod_folded.items.push(mk_reexport_mod(&mut self.cx, reexports)); + self.cx.reexports.push(self.cx.path.clone()); + } mod_folded }