From 0613dac042fc45c40248b699f380aa93532336aa Mon Sep 17 00:00:00 2001 From: Jeffrey Seyfried Date: Tue, 20 Sep 2016 06:33:42 +0000 Subject: Avoid aborting after expansion from `BuildReducedGraphVisitor` errors. --- src/libsyntax/ext/base.rs | 2 ++ src/libsyntax/ext/expand.rs | 4 +++- 2 files changed, 5 insertions(+), 1 deletion(-) (limited to 'src/libsyntax') diff --git a/src/libsyntax/ext/base.rs b/src/libsyntax/ext/base.rs index 3e85565beb6..cc9143497e6 100644 --- a/src/libsyntax/ext/base.rs +++ b/src/libsyntax/ext/base.rs @@ -708,6 +708,7 @@ pub struct ExtCtxt<'a> { pub ecfg: expand::ExpansionConfig<'a>, pub crate_root: Option<&'static str>, pub resolver: &'a mut Resolver, + pub resolve_err_count: usize, pub current_expansion: ExpansionData, } @@ -722,6 +723,7 @@ impl<'a> ExtCtxt<'a> { ecfg: ecfg, crate_root: None, resolver: resolver, + resolve_err_count: 0, current_expansion: ExpansionData { mark: Mark::root(), depth: 0, diff --git a/src/libsyntax/ext/expand.rs b/src/libsyntax/ext/expand.rs index 43c62218963..15db4b1b043 100644 --- a/src/libsyntax/ext/expand.rs +++ b/src/libsyntax/ext/expand.rs @@ -200,7 +200,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> { _ => unreachable!(), }; - if self.cx.parse_sess.span_diagnostic.err_count() > err_count { + if self.cx.parse_sess.span_diagnostic.err_count() - self.cx.resolve_err_count > err_count { self.cx.parse_sess.span_diagnostic.abort_if_errors(); } @@ -271,8 +271,10 @@ impl<'a, 'b> MacroExpander<'a, 'b> { self.cx.cfg = crate_config; if self.monotonic { + let err_count = self.cx.parse_sess.span_diagnostic.err_count(); let mark = self.cx.current_expansion.mark; self.cx.resolver.visit_expansion(mark, &result.0); + self.cx.resolve_err_count += self.cx.parse_sess.span_diagnostic.err_count() - err_count; } result -- cgit 1.4.1-3-g733a5 From f34e49dd90603337da2347fe81e4d3158ae5fbd1 Mon Sep 17 00:00:00 2001 From: Jeffrey Seyfried Date: Fri, 23 Sep 2016 07:23:01 +0000 Subject: With `--test`, make `#[test]` functions `pub` in `InvocationCollector` and expand the `__test_reexports` in the correct scope. --- src/librustc_resolve/macros.rs | 10 ++++++ src/libsyntax/config.rs | 2 +- src/libsyntax/ext/base.rs | 2 ++ src/libsyntax/ext/expand.rs | 11 +++++-- src/libsyntax/test.rs | 69 +++++++++++++++++------------------------- 5 files changed, 49 insertions(+), 45 deletions(-) (limited to 'src/libsyntax') diff --git a/src/librustc_resolve/macros.rs b/src/librustc_resolve/macros.rs index fad563218a0..1f721541ff8 100644 --- a/src/librustc_resolve/macros.rs +++ b/src/librustc_resolve/macros.rs @@ -43,6 +43,16 @@ impl<'a> base::Resolver for Resolver<'a> { self.session.next_node_id() } + fn get_module_scope(&mut self, id: ast::NodeId) -> Mark { + let mark = Mark::fresh(); + let module = self.module_map[&id]; + self.expansion_data.insert(mark.as_u32(), ExpansionData { + module: module, + def_index: module.def_id().unwrap().index, + }); + mark + } + fn visit_expansion(&mut self, mark: Mark, expansion: &Expansion) { self.collect_def_ids(mark, expansion); self.current_module = self.expansion_data[&mark.as_u32()].module; diff --git a/src/libsyntax/config.rs b/src/libsyntax/config.rs index 78d047c7651..94a7f6030b9 100644 --- a/src/libsyntax/config.rs +++ b/src/libsyntax/config.rs @@ -303,6 +303,6 @@ fn is_cfg(attr: &ast::Attribute) -> bool { attr.check_name("cfg") } -fn is_test_or_bench(attr: &ast::Attribute) -> bool { +pub fn is_test_or_bench(attr: &ast::Attribute) -> bool { attr.check_name("test") || attr.check_name("bench") } diff --git a/src/libsyntax/ext/base.rs b/src/libsyntax/ext/base.rs index cc9143497e6..1d2a0dd0cbc 100644 --- a/src/libsyntax/ext/base.rs +++ b/src/libsyntax/ext/base.rs @@ -656,6 +656,7 @@ pub type NamedSyntaxExtension = (Name, SyntaxExtension); pub trait Resolver { fn next_node_id(&mut self) -> ast::NodeId; + fn get_module_scope(&mut self, id: ast::NodeId) -> Mark; fn visit_expansion(&mut self, mark: Mark, expansion: &Expansion); fn add_macro(&mut self, scope: Mark, def: ast::MacroDef); @@ -671,6 +672,7 @@ pub struct DummyResolver; impl Resolver for DummyResolver { fn next_node_id(&mut self) -> ast::NodeId { ast::DUMMY_NODE_ID } + fn get_module_scope(&mut self, _id: ast::NodeId) -> Mark { Mark::root() } fn visit_expansion(&mut self, _invoc: Mark, _expansion: &Expansion) {} fn add_macro(&mut self, _scope: Mark, _def: ast::MacroDef) {} diff --git a/src/libsyntax/ext/expand.rs b/src/libsyntax/ext/expand.rs index 15db4b1b043..aad895750c8 100644 --- a/src/libsyntax/ext/expand.rs +++ b/src/libsyntax/ext/expand.rs @@ -16,7 +16,7 @@ use ext::placeholders::{placeholder, PlaceholderExpander}; use attr::{self, HasAttrs}; use codemap::{ExpnInfo, NameAndSpan, MacroBang, MacroAttribute}; use syntax_pos::{self, Span, ExpnId}; -use config::StripUnconfigured; +use config::{is_test_or_bench, StripUnconfigured}; use ext::base::*; use feature_gate::{self, Features}; use fold; @@ -612,7 +612,7 @@ impl<'a, 'b> Folder for InvocationCollector<'a, 'b> { fn fold_item(&mut self, item: P) -> SmallVector> { let item = configure!(self, item); - let (item, attr) = self.classify_item(item); + let (mut item, attr) = self.classify_item(item); if let Some(attr) = attr { let item = Annotatable::Item(fully_configure!(self, item, noop_fold_item)); return self.collect_attr(attr, item, ExpansionKind::Items).make_items(); @@ -669,6 +669,13 @@ impl<'a, 'b> Folder for InvocationCollector<'a, 'b> { self.cx.current_expansion.module = orig_module; return result; } + // Ensure that test functions are accessible from the test harness. + ast::ItemKind::Fn(..) if self.cx.ecfg.should_test => { + if item.attrs.iter().any(|attr| is_test_or_bench(attr)) { + item = item.map(|mut item| { item.vis = ast::Visibility::Public; item }); + } + noop_fold_item(item, self) + } _ => noop_fold_item(item, self), } } diff --git a/src/libsyntax/test.rs b/src/libsyntax/test.rs index 6327e8f71bc..e4510520a55 100644 --- a/src/libsyntax/test.rs +++ b/src/libsyntax/test.rs @@ -119,7 +119,7 @@ impl<'a> fold::Folder for TestHarnessGenerator<'a> { } debug!("current path: {}", path_name_i(&self.cx.path)); - let i = if is_test_fn(&self.cx, &i) || is_bench_fn(&self.cx, &i) { + if is_test_fn(&self.cx, &i) || is_bench_fn(&self.cx, &i) { match i.node { ast::ItemKind::Fn(_, ast::Unsafety::Unsafe, _, _, _, _) => { let diag = self.cx.span_diagnostic; @@ -136,54 +136,37 @@ impl<'a> fold::Folder for TestHarnessGenerator<'a> { }; self.cx.testfns.push(test); self.tests.push(i.ident); - // debug!("have {} test/bench functions", - // cx.testfns.len()); - - // Make all tests public so we can call them from outside - // the module (note that the tests are re-exported and must - // be made public themselves to avoid privacy errors). - i.map(|mut i| { - i.vis = ast::Visibility::Public; - i - }) } } - } else { - i - }; + } + let mut item = i.unwrap(); // 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::ItemKind::Mod(..) => fold::noop_fold_item(i, self), - _ => SmallVector::one(i), - }; + if let ast::ItemKind::Mod(module) = item.node { + let tests = mem::replace(&mut self.tests, Vec::new()); + let tested_submods = mem::replace(&mut self.tested_submods, Vec::new()); + let mut mod_folded = fold::noop_fold_mod(module, self); + let tests = mem::replace(&mut self.tests, tests); + let tested_submods = mem::replace(&mut self.tested_submods, tested_submods); + + if !tests.is_empty() || !tested_submods.is_empty() { + let (it, sym) = mk_reexport_mod(&mut self.cx, item.id, tests, tested_submods); + mod_folded.items.push(it); + + if !self.cx.path.is_empty() { + self.tested_submods.push((self.cx.path[self.cx.path.len()-1], sym)); + } else { + debug!("pushing nothing, sym: {:?}", sym); + self.cx.toplevel_reexport = Some(sym); + } + } + item.node = ast::ItemKind::Mod(mod_folded); + } if ident.name != keywords::Invalid.name() { self.cx.path.pop(); } - res - } - - fn fold_mod(&mut self, m: ast::Mod) -> ast::Mod { - let tests = mem::replace(&mut self.tests, Vec::new()); - let tested_submods = mem::replace(&mut self.tested_submods, Vec::new()); - let mut mod_folded = fold::noop_fold_mod(m, self); - let tests = mem::replace(&mut self.tests, tests); - let tested_submods = mem::replace(&mut self.tested_submods, tested_submods); - - if !tests.is_empty() || !tested_submods.is_empty() { - let (it, sym) = mk_reexport_mod(&mut self.cx, tests, tested_submods); - mod_folded.items.push(it); - - if !self.cx.path.is_empty() { - self.tested_submods.push((self.cx.path[self.cx.path.len()-1], sym)); - } else { - debug!("pushing nothing, sym: {:?}", sym); - self.cx.toplevel_reexport = Some(sym); - } - } - - mod_folded + SmallVector::one(P(item)) } fn fold_mac(&mut self, mac: ast::Mac) -> ast::Mac { mac } @@ -239,7 +222,7 @@ impl fold::Folder for EntryPointCleaner { fn fold_mac(&mut self, mac: ast::Mac) -> ast::Mac { mac } } -fn mk_reexport_mod(cx: &mut TestCtxt, tests: Vec, +fn mk_reexport_mod(cx: &mut TestCtxt, parent: ast::NodeId, tests: Vec, tested_submods: Vec<(ast::Ident, ast::Ident)>) -> (P, ast::Ident) { let super_ = token::str_to_ident("super"); @@ -257,6 +240,8 @@ fn mk_reexport_mod(cx: &mut TestCtxt, tests: Vec, }; let sym = token::gensym_ident("__test_reexports"); + let parent = if parent == ast::DUMMY_NODE_ID { ast::CRATE_NODE_ID } else { parent }; + cx.ext_cx.current_expansion.mark = cx.ext_cx.resolver.get_module_scope(parent); let it = cx.ext_cx.monotonic_expander().fold_item(P(ast::Item { ident: sym.clone(), attrs: Vec::new(), -- cgit 1.4.1-3-g733a5