about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2016-09-27 14:11:07 -0700
committerGitHub <noreply@github.com>2016-09-27 14:11:07 -0700
commita059cb2f3344c0a9efae17dde3d0e16a55ce93db (patch)
treef8c95278a99c33a5f92ae0f9e5ea4bfc0ecf47c6
parent322b5530ba8a74e0363243da5cdc3d0ac43762d7 (diff)
parentdfa69be38a3d232ebb0a548afff5e3560dd905ce (diff)
downloadrust-a059cb2f3344c0a9efae17dde3d0e16a55ce93db.tar.gz
rust-a059cb2f3344c0a9efae17dde3d0e16a55ce93db.zip
Auto merge of #36601 - jseyfried:build_reduced_graph_in_expansion, r=nrc
Assign def ids and build the module graph during expansion

r? @nrc
-rw-r--r--src/librustc/hir/map/def_collector.rs115
-rw-r--r--src/librustc/hir/map/definitions.rs9
-rw-r--r--src/librustc/hir/map/mod.rs2
-rw-r--r--src/librustc_driver/driver.rs16
-rw-r--r--src/librustc_metadata/diagnostics.rs12
-rw-r--r--src/librustc_resolve/build_reduced_graph.rs110
-rw-r--r--src/librustc_resolve/lib.rs26
-rw-r--r--src/librustc_resolve/macros.rs193
-rw-r--r--src/libsyntax/config.rs2
-rw-r--r--src/libsyntax/ext/base.rs4
-rw-r--r--src/libsyntax/ext/expand.rs15
-rw-r--r--src/libsyntax/test.rs69
-rw-r--r--src/test/codegen-units/item-collection/overloaded-operators.rs8
-rw-r--r--src/test/compile-fail-fulldeps/derive-no-std-not-supported.rs1
-rw-r--r--src/test/compile-fail/gated-non-ascii-idents.rs2
-rw-r--r--src/test/compile-fail/self_type_keyword.rs18
16 files changed, 321 insertions, 281 deletions
diff --git a/src/librustc/hir/map/def_collector.rs b/src/librustc/hir/map/def_collector.rs
index b0a717e18f9..c0f38061a0d 100644
--- a/src/librustc/hir/map/def_collector.rs
+++ b/src/librustc/hir/map/def_collector.rs
@@ -18,31 +18,39 @@ use middle::cstore::InlinedItem;
 
 use syntax::ast::*;
 use syntax::visit;
-use syntax::parse::token;
+use syntax::parse::token::{self, keywords};
 
 /// Creates def ids for nodes in the HIR.
-pub struct DefCollector<'ast> {
+pub struct DefCollector<'a> {
     // If we are walking HIR (c.f., AST), we need to keep a reference to the
     // crate.
-    hir_crate: Option<&'ast hir::Crate>,
-    definitions: &'ast mut Definitions,
+    hir_crate: Option<&'a hir::Crate>,
+    definitions: &'a mut Definitions,
     parent_def: Option<DefIndex>,
+    pub visit_macro_invoc: Option<&'a mut FnMut(MacroInvocationData)>,
 }
 
-impl<'ast> DefCollector<'ast> {
-    pub fn new(definitions: &'ast mut Definitions) -> DefCollector<'ast> {
+pub struct MacroInvocationData {
+    pub id: NodeId,
+    pub def_index: DefIndex,
+    pub const_integer: bool,
+}
+
+impl<'a> DefCollector<'a> {
+    pub fn new(definitions: &'a mut Definitions) -> Self {
         DefCollector {
             hir_crate: None,
             definitions: definitions,
             parent_def: None,
+            visit_macro_invoc: None,
         }
     }
 
     pub fn extend(parent_node: NodeId,
                   parent_def_path: DefPath,
                   parent_def_id: DefId,
-                  definitions: &'ast mut Definitions)
-                  -> DefCollector<'ast> {
+                  definitions: &'a mut Definitions)
+                  -> Self {
         let mut collector = DefCollector::new(definitions);
 
         assert_eq!(parent_def_path.krate, parent_def_id.krate);
@@ -65,7 +73,7 @@ impl<'ast> DefCollector<'ast> {
         self.create_def_with_parent(Some(CRATE_DEF_INDEX), DUMMY_NODE_ID, DefPathData::Misc);
     }
 
-    pub fn walk_item(&mut self, ii: &'ast InlinedItem, krate: &'ast hir::Crate) {
+    pub fn walk_item(&mut self, ii: &'a InlinedItem, krate: &'a hir::Crate) {
         self.hir_crate = Some(krate);
         ii.visit(self);
     }
@@ -84,29 +92,28 @@ impl<'ast> DefCollector<'ast> {
         self.definitions.create_def_with_parent(parent, node_id, data)
     }
 
-    fn with_parent<F: FnOnce(&mut Self)>(&mut self, parent_def: DefIndex, f: F) {
+    pub fn with_parent<F: FnOnce(&mut Self)>(&mut self, parent_def: DefIndex, f: F) {
         let parent = self.parent_def;
         self.parent_def = Some(parent_def);
         f(self);
         self.parent_def = parent;
     }
 
-    fn visit_ast_const_integer(&mut self, expr: &Expr) {
-        // Find the node which will be used after lowering.
-        if let ExprKind::Paren(ref inner) = expr.node {
-            return self.visit_ast_const_integer(inner);
-        }
-
-        // FIXME(eddyb) Closures should have separate
-        // function definition IDs and expression IDs.
-        if let ExprKind::Closure(..) = expr.node {
-            return;
+    pub fn visit_ast_const_integer(&mut self, expr: &Expr) {
+        match expr.node {
+            // Find the node which will be used after lowering.
+            ExprKind::Paren(ref inner) => return self.visit_ast_const_integer(inner),
+            ExprKind::Mac(..) => return self.visit_macro_invoc(expr.id, true),
+            // FIXME(eddyb) Closures should have separate
+            // function definition IDs and expression IDs.
+            ExprKind::Closure(..) => return,
+            _ => {}
         }
 
         self.create_def(expr.id, DefPathData::Initializer);
     }
 
-    fn visit_hir_const_integer(&mut self, expr: &'ast hir::Expr) {
+    fn visit_hir_const_integer(&mut self, expr: &hir::Expr) {
         // FIXME(eddyb) Closures should have separate
         // function definition IDs and expression IDs.
         if let hir::ExprClosure(..) = expr.node {
@@ -115,9 +122,19 @@ impl<'ast> DefCollector<'ast> {
 
         self.create_def(expr.id, DefPathData::Initializer);
     }
+
+    fn visit_macro_invoc(&mut self, id: NodeId, const_integer: bool) {
+        if let Some(ref mut visit) = self.visit_macro_invoc {
+            visit(MacroInvocationData {
+                id: id,
+                const_integer: const_integer,
+                def_index: self.parent_def.unwrap(),
+            })
+        }
+    }
 }
 
-impl<'ast> visit::Visitor for DefCollector<'ast> {
+impl<'a> visit::Visitor for DefCollector<'a> {
     fn visit_item(&mut self, i: &Item) {
         debug!("visit_item: {:?}", i);
 
@@ -129,10 +146,14 @@ impl<'ast> visit::Visitor for DefCollector<'ast> {
             ItemKind::Enum(..) | ItemKind::Struct(..) | ItemKind::Union(..) | ItemKind::Trait(..) |
             ItemKind::ExternCrate(..) | ItemKind::ForeignMod(..) | ItemKind::Ty(..) =>
                 DefPathData::TypeNs(i.ident.name.as_str()),
+            ItemKind::Mod(..) if i.ident == keywords::Invalid.ident() => {
+                return visit::walk_item(self, i);
+            }
             ItemKind::Mod(..) => DefPathData::Module(i.ident.name.as_str()),
             ItemKind::Static(..) | ItemKind::Const(..) | ItemKind::Fn(..) =>
                 DefPathData::ValueNs(i.ident.name.as_str()),
-            ItemKind::Mac(..) => DefPathData::MacroDef(i.ident.name.as_str()),
+            ItemKind::Mac(..) if i.id == DUMMY_NODE_ID => return, // Scope placeholder
+            ItemKind::Mac(..) => return self.visit_macro_invoc(i.id, false),
             ItemKind::Use(..) => DefPathData::Misc,
         };
         let def = self.create_def(i.id, def_data);
@@ -198,7 +219,7 @@ impl<'ast> visit::Visitor for DefCollector<'ast> {
             TraitItemKind::Method(..) | TraitItemKind::Const(..) =>
                 DefPathData::ValueNs(ti.ident.name.as_str()),
             TraitItemKind::Type(..) => DefPathData::TypeNs(ti.ident.name.as_str()),
-            TraitItemKind::Macro(..) => DefPathData::MacroDef(ti.ident.name.as_str()),
+            TraitItemKind::Macro(..) => return self.visit_macro_invoc(ti.id, false),
         };
 
         let def = self.create_def(ti.id, def_data);
@@ -216,7 +237,7 @@ impl<'ast> visit::Visitor for DefCollector<'ast> {
             ImplItemKind::Method(..) | ImplItemKind::Const(..) =>
                 DefPathData::ValueNs(ii.ident.name.as_str()),
             ImplItemKind::Type(..) => DefPathData::TypeNs(ii.ident.name.as_str()),
-            ImplItemKind::Macro(..) => DefPathData::MacroDef(ii.ident.name.as_str()),
+            ImplItemKind::Macro(..) => return self.visit_macro_invoc(ii.id, false),
         };
 
         let def = self.create_def(ii.id, def_data);
@@ -232,9 +253,13 @@ impl<'ast> visit::Visitor for DefCollector<'ast> {
     fn visit_pat(&mut self, pat: &Pat) {
         let parent_def = self.parent_def;
 
-        if let PatKind::Ident(_, id, _) = pat.node {
-            let def = self.create_def(pat.id, DefPathData::Binding(id.node.name.as_str()));
-            self.parent_def = Some(def);
+        match pat.node {
+            PatKind::Mac(..) => return self.visit_macro_invoc(pat.id, false),
+            PatKind::Ident(_, id, _) => {
+                let def = self.create_def(pat.id, DefPathData::Binding(id.node.name.as_str()));
+                self.parent_def = Some(def);
+            }
+            _ => {}
         }
 
         visit::walk_pat(self, pat);
@@ -244,13 +269,14 @@ impl<'ast> visit::Visitor for DefCollector<'ast> {
     fn visit_expr(&mut self, expr: &Expr) {
         let parent_def = self.parent_def;
 
-        if let ExprKind::Repeat(_, ref count) = expr.node {
-            self.visit_ast_const_integer(count);
-        }
-
-        if let ExprKind::Closure(..) = expr.node {
-            let def = self.create_def(expr.id, DefPathData::ClosureExpr);
-            self.parent_def = Some(def);
+        match expr.node {
+            ExprKind::Mac(..) => return self.visit_macro_invoc(expr.id, false),
+            ExprKind::Repeat(_, ref count) => self.visit_ast_const_integer(count),
+            ExprKind::Closure(..) => {
+                let def = self.create_def(expr.id, DefPathData::ClosureExpr);
+                self.parent_def = Some(def);
+            }
+            _ => {}
         }
 
         visit::walk_expr(self, expr);
@@ -258,11 +284,13 @@ impl<'ast> visit::Visitor for DefCollector<'ast> {
     }
 
     fn visit_ty(&mut self, ty: &Ty) {
-        if let TyKind::FixedLengthVec(_, ref length) = ty.node {
-            self.visit_ast_const_integer(length);
-        }
-        if let TyKind::ImplTrait(..) = ty.node {
-            self.create_def(ty.id, DefPathData::ImplTrait);
+        match ty.node {
+            TyKind::Mac(..) => return self.visit_macro_invoc(ty.id, false),
+            TyKind::FixedLengthVec(_, ref length) => self.visit_ast_const_integer(length),
+            TyKind::ImplTrait(..) => {
+                self.create_def(ty.id, DefPathData::ImplTrait);
+            }
+            _ => {}
         }
         visit::walk_ty(self, ty);
     }
@@ -274,6 +302,13 @@ impl<'ast> visit::Visitor for DefCollector<'ast> {
     fn visit_macro_def(&mut self, macro_def: &MacroDef) {
         self.create_def(macro_def.id, DefPathData::MacroDef(macro_def.ident.name.as_str()));
     }
+
+    fn visit_stmt(&mut self, stmt: &Stmt) {
+        match stmt.node {
+            StmtKind::Mac(..) => self.visit_macro_invoc(stmt.id, false),
+            _ => visit::walk_stmt(self, stmt),
+        }
+    }
 }
 
 // We walk the HIR rather than the AST when reading items from metadata.
diff --git a/src/librustc/hir/map/definitions.rs b/src/librustc/hir/map/definitions.rs
index 5cfb71f4fc8..f87844652cc 100644
--- a/src/librustc/hir/map/definitions.rs
+++ b/src/librustc/hir/map/definitions.rs
@@ -9,11 +9,10 @@
 // except according to those terms.
 
 use hir::def_id::{CrateNum, DefId, DefIndex, LOCAL_CRATE};
-use hir::map::def_collector::DefCollector;
 use rustc_data_structures::fnv::FnvHashMap;
 use std::fmt::Write;
 use std::hash::{Hash, Hasher, SipHasher};
-use syntax::{ast, visit};
+use syntax::ast;
 use syntax::parse::token::{self, InternedString};
 use ty::TyCtxt;
 use util::nodemap::NodeMap;
@@ -224,12 +223,6 @@ impl Definitions {
         }
     }
 
-    pub fn collect(&mut self, krate: &ast::Crate) {
-        let mut def_collector = DefCollector::new(self);
-        def_collector.collect_root();
-        visit::walk_crate(&mut def_collector, krate);
-    }
-
     /// Get the number of definitions.
     pub fn len(&self) -> usize {
         self.data.len()
diff --git a/src/librustc/hir/map/mod.rs b/src/librustc/hir/map/mod.rs
index b351bd427ac..bafb00edc19 100644
--- a/src/librustc/hir/map/mod.rs
+++ b/src/librustc/hir/map/mod.rs
@@ -11,7 +11,7 @@
 pub use self::Node::*;
 use self::MapEntry::*;
 use self::collector::NodeCollector;
-use self::def_collector::DefCollector;
+pub use self::def_collector::{DefCollector, MacroInvocationData};
 pub use self::definitions::{Definitions, DefKey, DefPath, DefPathData,
                             DisambiguatedDefPathData, InlinedRootPath};
 
diff --git a/src/librustc_driver/driver.rs b/src/librustc_driver/driver.rs
index 9d5dce7ad05..f9ac1312d3c 100644
--- a/src/librustc_driver/driver.rs
+++ b/src/librustc_driver/driver.rs
@@ -639,6 +639,12 @@ pub fn phase_2_configure_and_expand<'a, F>(sess: &Session,
     }
     sess.track_errors(|| sess.lint_store.borrow_mut().process_command_line(sess))?;
 
+    // Currently, we ignore the name resolution data structures for the purposes of dependency
+    // tracking. Instead we will run name resolution and include its output in the hash of each
+    // item, much like we do for macro expansion. In other words, the hash reflects not just
+    // its contents but the results of name resolution on those contents. Hopefully we'll push
+    // this back at some point.
+    let _ignore = sess.dep_graph.in_ignore();
     let mut crate_loader = CrateLoader::new(sess, &cstore, &krate, crate_name);
     let resolver_arenas = Resolver::arenas();
     let mut resolver =
@@ -733,9 +739,6 @@ pub fn phase_2_configure_and_expand<'a, F>(sess: &Session,
         })
     })?;
 
-    // Collect defintions for def ids.
-    time(sess.time_passes(), "collecting defs", || resolver.definitions.collect(&krate));
-
     time(sess.time_passes(),
          "early lint checks",
          || lint::check_ast_crate(sess, &krate));
@@ -745,13 +748,6 @@ pub fn phase_2_configure_and_expand<'a, F>(sess: &Session,
          || ast_validation::check_crate(sess, &krate));
 
     time(sess.time_passes(), "name resolution", || -> CompileResult {
-        // Currently, we ignore the name resolution data structures for the purposes of dependency
-        // tracking. Instead we will run name resolution and include its output in the hash of each
-        // item, much like we do for macro expansion. In other words, the hash reflects not just
-        // its contents but the results of name resolution on those contents. Hopefully we'll push
-        // this back at some point.
-        let _ignore = sess.dep_graph.in_ignore();
-        resolver.build_reduced_graph(&krate);
         resolver.resolve_imports();
 
         // Since import resolution will eventually happen in expansion,
diff --git a/src/librustc_metadata/diagnostics.rs b/src/librustc_metadata/diagnostics.rs
index f52e1437acc..c03375bf825 100644
--- a/src/librustc_metadata/diagnostics.rs
+++ b/src/librustc_metadata/diagnostics.rs
@@ -98,10 +98,10 @@ Erroneous code examples:
 
 ```compile_fail,E0466
 #[macro_use(a_macro(another_macro))] // error: invalid import declaration
-extern crate some_crate;
+extern crate core as some_crate;
 
 #[macro_use(i_want = "some_macros")] // error: invalid import declaration
-extern crate another_crate;
+extern crate core as another_crate;
 ```
 
 This is a syntax error at the level of attribute declarations. The proper
@@ -135,10 +135,10 @@ Erroneous code examples:
 
 ```compile_fail,E0467
 #[macro_reexport]                    // error: no macros listed for export
-extern crate macros_for_good;
+extern crate core as macros_for_good;
 
 #[macro_reexport(fun_macro = "foo")] // error: not a macro identifier
-extern crate other_macros_for_good;
+extern crate core as other_macros_for_good;
 ```
 
 This is a syntax error at the level of attribute declarations.
@@ -165,8 +165,8 @@ Example of erroneous code:
 ```compile_fail,E0468
 mod foo {
     #[macro_use(helpful_macro)] // error: must be at crate root to import
-    extern crate some_crate;    //        macros from another crate
-    helpful_macro!(...)
+    extern crate core;          //        macros from another crate
+    helpful_macro!(...);
 }
 ```
 
diff --git a/src/librustc_resolve/build_reduced_graph.rs b/src/librustc_resolve/build_reduced_graph.rs
index 9202f8c0946..55bf5dcf1cf 100644
--- a/src/librustc_resolve/build_reduced_graph.rs
+++ b/src/librustc_resolve/build_reduced_graph.rs
@@ -20,21 +20,25 @@ use {NameBinding, NameBindingKind, ToNameBinding};
 use Resolver;
 use {resolve_error, resolve_struct_error, ResolutionError};
 
+use rustc::middle::cstore::LoadedMacro;
 use rustc::hir::def::*;
 use rustc::hir::def_id::{CRATE_DEF_INDEX, DefId};
 use rustc::hir::map::DefPathData;
 use rustc::ty;
 
 use std::cell::Cell;
+use std::rc::Rc;
 
 use syntax::ast::Name;
 use syntax::attr;
 use syntax::parse::token;
 
-use syntax::ast::{Block, Crate};
-use syntax::ast::{ForeignItem, ForeignItemKind, Item, ItemKind};
+use syntax::ast::{self, Block, ForeignItem, ForeignItemKind, Item, ItemKind};
 use syntax::ast::{Mutability, StmtKind, TraitItem, TraitItemKind};
 use syntax::ast::{Variant, ViewPathGlob, ViewPathList, ViewPathSimple};
+use syntax::ext::base::{MultiItemModifier, Resolver as SyntaxResolver};
+use syntax::ext::hygiene::Mark;
+use syntax::feature_gate::{self, emit_feature_err};
 use syntax::parse::token::keywords;
 use syntax::visit::{self, Visitor};
 
@@ -53,11 +57,6 @@ impl<'a> ToNameBinding<'a> for (Def, Span, ty::Visibility) {
 }
 
 impl<'b> Resolver<'b> {
-    /// Constructs the reduced graph for the entire crate.
-    pub fn build_reduced_graph(&mut self, krate: &Crate) {
-        visit::walk_crate(&mut BuildReducedGraphVisitor { resolver: self }, krate);
-    }
-
     /// Defines `name` in namespace `ns` of module `parent` to be `def` if it is not yet defined;
     /// otherwise, reports an error.
     fn define<T>(&mut self, parent: Module<'b>, name: Name, ns: Namespace, def: T)
@@ -72,15 +71,13 @@ impl<'b> Resolver<'b> {
     fn block_needs_anonymous_module(&mut self, block: &Block) -> bool {
         // If any statements are items, we need to create an anonymous module
         block.stmts.iter().any(|statement| match statement.node {
-            StmtKind::Item(_) => true,
+            StmtKind::Item(_) | StmtKind::Mac(_) => true,
             _ => false,
         })
     }
 
     /// Constructs the reduced graph for one item.
     fn build_reduced_graph_for_item(&mut self, item: &Item) {
-        self.crate_loader.process_item(item, &self.definitions);
-
         let parent = self.current_module;
         let name = item.ident.name;
         let sp = item.span;
@@ -188,8 +185,20 @@ impl<'b> Resolver<'b> {
             }
 
             ItemKind::ExternCrate(_) => {
-                // n.b. we don't need to look at the path option here, because cstore already
-                // did
+                // We need to error on `#[macro_use] extern crate` when it isn't at the
+                // crate root, because `$crate` won't work properly.
+                let is_crate_root = self.current_module.parent.is_none();
+                for def in self.crate_loader.load_macros(item, is_crate_root) {
+                    match def {
+                        LoadedMacro::Def(def) => self.add_macro(Mark::root(), def),
+                        LoadedMacro::CustomDerive(name, ext) => {
+                            self.insert_custom_derive(&name, ext, item.span);
+                        }
+                    }
+                }
+                self.crate_loader.process_item(item, &self.definitions);
+
+                // n.b. we don't need to look at the path option here, because cstore already did
                 if let Some(crate_id) = self.session.cstore.extern_mod_stmt_cnum(item.id) {
                     let def_id = DefId {
                         krate: crate_id,
@@ -206,6 +215,8 @@ impl<'b> Resolver<'b> {
                 }
             }
 
+            ItemKind::Mod(..) if item.ident == keywords::Invalid.ident() => {} // Crate root
+
             ItemKind::Mod(..) => {
                 let def = Def::Mod(self.definitions.local_def_id(item.id));
                 let module = self.arenas.alloc_module(ModuleS {
@@ -213,6 +224,7 @@ impl<'b> Resolver<'b> {
                         attr::contains_name(&item.attrs, "no_implicit_prelude")
                     },
                     normal_ancestor_id: Some(item.id),
+                    macros_escape: self.contains_macro_use(&item.attrs),
                     ..ModuleS::new(Some(parent), ModuleKind::Def(def, name))
                 });
                 self.define(parent, name, TypeNS, (module, sp, vis));
@@ -222,7 +234,7 @@ impl<'b> Resolver<'b> {
                 self.current_module = module;
             }
 
-            ItemKind::ForeignMod(..) => {}
+            ItemKind::ForeignMod(..) => self.crate_loader.process_item(item, &self.definitions),
 
             // These items live in the value namespace.
             ItemKind::Static(_, m, _) => {
@@ -476,14 +488,79 @@ impl<'b> Resolver<'b> {
         }
         module.populated.set(true)
     }
+
+    // does this attribute list contain "macro_use"?
+    fn contains_macro_use(&mut self, attrs: &[ast::Attribute]) -> bool {
+        for attr in attrs {
+            if attr.check_name("macro_escape") {
+                let msg = "macro_escape is a deprecated synonym for macro_use";
+                let mut err = self.session.struct_span_warn(attr.span, msg);
+                if let ast::AttrStyle::Inner = attr.node.style {
+                    err.help("consider an outer attribute, #[macro_use] mod ...").emit();
+                } else {
+                    err.emit();
+                }
+            } else if !attr.check_name("macro_use") {
+                continue;
+            }
+
+            if !attr.is_word() {
+                self.session.span_err(attr.span, "arguments to macro_use are not allowed here");
+            }
+            return true;
+        }
+
+        false
+    }
+
+    fn insert_custom_derive(&mut self, name: &str, ext: Rc<MultiItemModifier>, sp: Span) {
+        if !self.session.features.borrow().rustc_macro {
+            let sess = &self.session.parse_sess;
+            let msg = "loading custom derive macro crates is experimentally supported";
+            emit_feature_err(sess, "rustc_macro", sp, feature_gate::GateIssue::Language, msg);
+        }
+        if self.derive_modes.insert(token::intern(name), ext).is_some() {
+            self.session.span_err(sp, &format!("cannot shadow existing derive mode `{}`", name));
+        }
+    }
+}
+
+pub struct BuildReducedGraphVisitor<'a, 'b: 'a> {
+    pub resolver: &'a mut Resolver<'b>,
+}
+
+impl<'a, 'b> BuildReducedGraphVisitor<'a, 'b> {
+    fn visit_invoc(&mut self, id: ast::NodeId) {
+        self.resolver.expansion_data.get_mut(&id.as_u32()).unwrap().module =
+            self.resolver.current_module;
+    }
 }
 
-struct BuildReducedGraphVisitor<'a, 'b: 'a> {
-    resolver: &'a mut Resolver<'b>,
+macro_rules! method {
+    ($visit:ident: $ty:ty, $invoc:path, $walk:ident) => {
+        fn $visit(&mut self, node: &$ty) {
+            match node.node {
+                $invoc(..) => self.visit_invoc(node.id),
+                _ => visit::$walk(self, node),
+            }
+        }
+    }
 }
 
 impl<'a, 'b> Visitor for BuildReducedGraphVisitor<'a, 'b> {
+    method!(visit_impl_item: ast::ImplItem, ast::ImplItemKind::Macro, walk_impl_item);
+    method!(visit_stmt:      ast::Stmt,     ast::StmtKind::Mac,       walk_stmt);
+    method!(visit_expr:      ast::Expr,     ast::ExprKind::Mac,       walk_expr);
+    method!(visit_pat:       ast::Pat,      ast::PatKind::Mac,        walk_pat);
+    method!(visit_ty:        ast::Ty,       ast::TyKind::Mac,         walk_ty);
+
     fn visit_item(&mut self, item: &Item) {
+        match item.node {
+            ItemKind::Mac(..) if item.id == ast::DUMMY_NODE_ID => return, // Scope placeholder
+            ItemKind::Mac(..) => return self.visit_invoc(item.id),
+            _ => {}
+        }
+
         let parent = self.resolver.current_module;
         self.resolver.build_reduced_graph_for_item(item);
         visit::walk_item(self, item);
@@ -492,6 +569,7 @@ impl<'a, 'b> Visitor for BuildReducedGraphVisitor<'a, 'b> {
 
     fn visit_foreign_item(&mut self, foreign_item: &ForeignItem) {
         self.resolver.build_reduced_graph_for_foreign_item(foreign_item);
+        visit::walk_foreign_item(self, foreign_item);
     }
 
     fn visit_block(&mut self, block: &Block) {
@@ -515,7 +593,7 @@ impl<'a, 'b> Visitor for BuildReducedGraphVisitor<'a, 'b> {
                 (Def::Method(item_def_id), ValueNS)
             }
             TraitItemKind::Type(..) => (Def::AssociatedTy(item_def_id), TypeNS),
-            TraitItemKind::Macro(_) => panic!("unexpanded macro in resolve!"),
+            TraitItemKind::Macro(_) => return self.visit_invoc(item.id),
         };
 
         self.resolver.trait_item_map.insert((item.ident.name, def_id), is_static_method);
diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs
index 38b31db6781..0694edd2357 100644
--- a/src/librustc_resolve/lib.rs
+++ b/src/librustc_resolve/lib.rs
@@ -42,7 +42,7 @@ use self::RibKind::*;
 use self::UseLexicalScopeFlag::*;
 use self::ModulePrefixResult::*;
 
-use rustc::hir::map::Definitions;
+use rustc::hir::map::{Definitions, DefCollector};
 use rustc::hir::{self, PrimTy, TyBool, TyChar, TyFloat, TyInt, TyUint, TyStr};
 use rustc::middle::cstore::CrateLoader;
 use rustc::session::Session;
@@ -57,6 +57,7 @@ use syntax::ext::base::MultiItemModifier;
 use syntax::ext::hygiene::Mark;
 use syntax::ast::{self, FloatTy};
 use syntax::ast::{CRATE_NODE_ID, Name, NodeId, IntTy, UintTy};
+use syntax::ext::base::SyntaxExtension;
 use syntax::parse::token::{self, keywords};
 use syntax::util::lev_distance::find_best_match_for_name;
 
@@ -72,9 +73,9 @@ use syntax_pos::{Span, DUMMY_SP};
 use errors::DiagnosticBuilder;
 
 use std::cell::{Cell, RefCell};
-use std::rc::Rc;
 use std::fmt;
 use std::mem::replace;
+use std::rc::Rc;
 
 use resolve_imports::{ImportDirective, NameResolution};
 
@@ -791,6 +792,9 @@ pub struct ModuleS<'a> {
     // access the children must be preceded with a
     // `populate_module_if_necessary` call.
     populated: Cell<bool>,
+
+    macros: RefCell<FnvHashMap<Name, Rc<SyntaxExtension>>>,
+    macros_escape: bool,
 }
 
 pub type Module<'a> = &'a ModuleS<'a>;
@@ -808,6 +812,8 @@ impl<'a> ModuleS<'a> {
             globs: RefCell::new((Vec::new())),
             traits: RefCell::new(None),
             populated: Cell::new(true),
+            macros: RefCell::new(FnvHashMap()),
+            macros_escape: false,
         }
     }
 
@@ -1079,7 +1085,7 @@ pub struct Resolver<'a> {
     macro_names: FnvHashSet<Name>,
 
     // Maps the `Mark` of an expansion to its containing module or block.
-    expansion_data: FnvHashMap<u32, macros::ExpansionData>,
+    expansion_data: FnvHashMap<u32, macros::ExpansionData<'a>>,
 }
 
 pub struct ResolverArenas<'a> {
@@ -1193,13 +1199,16 @@ impl<'a> Resolver<'a> {
         let mut module_map = NodeMap();
         module_map.insert(CRATE_NODE_ID, graph_root);
 
+        let mut definitions = Definitions::new();
+        DefCollector::new(&mut definitions).collect_root();
+
         let mut expansion_data = FnvHashMap();
-        expansion_data.insert(0, macros::ExpansionData::default()); // Crate root expansion
+        expansion_data.insert(0, macros::ExpansionData::root(graph_root)); // Crate root expansion
 
         Resolver {
             session: session,
 
-            definitions: Definitions::new(),
+            definitions: definitions,
             macros_at_scope: FnvHashMap(),
 
             // The outermost module has def ID 0; this is not reflected in the
@@ -1269,6 +1278,13 @@ impl<'a> Resolver<'a> {
 
     /// Entry point to crate resolution.
     pub fn resolve_crate(&mut self, krate: &Crate) {
+        // Collect `DefId`s for exported macro defs.
+        for def in &krate.exported_macros {
+            DefCollector::new(&mut self.definitions).with_parent(CRATE_DEF_INDEX, |collector| {
+                collector.visit_macro_def(def)
+            })
+        }
+
         self.current_module = self.graph_root;
         visit::walk_crate(self, krate);
 
diff --git a/src/librustc_resolve/macros.rs b/src/librustc_resolve/macros.rs
index 3a9fb845190..17f2dff28c3 100644
--- a/src/librustc_resolve/macros.rs
+++ b/src/librustc_resolve/macros.rs
@@ -8,36 +8,38 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-use Resolver;
-use rustc::middle::cstore::LoadedMacro;
-use rustc::util::nodemap::FnvHashMap;
-use std::cell::RefCell;
-use std::mem;
+use {Module, Resolver};
+use build_reduced_graph::BuildReducedGraphVisitor;
+use rustc::hir::def_id::{CRATE_DEF_INDEX, DefIndex};
+use rustc::hir::map::{self, DefCollector};
 use std::rc::Rc;
-use syntax::ast::{self, Name};
+use syntax::ast;
 use syntax::errors::DiagnosticBuilder;
 use syntax::ext::base::{self, MultiModifier, MultiDecorator, MultiItemModifier};
-use syntax::ext::base::{NormalTT, Resolver as SyntaxResolver, SyntaxExtension};
+use syntax::ext::base::{NormalTT, SyntaxExtension};
 use syntax::ext::expand::{Expansion, Invocation, InvocationKind};
 use syntax::ext::hygiene::Mark;
 use syntax::ext::tt::macro_rules;
-use syntax::feature_gate::{self, emit_feature_err};
-use syntax::parse::token::{self, intern};
+use syntax::parse::token::intern;
 use syntax::util::lev_distance::find_best_match_for_name;
-use syntax::visit::{self, Visitor};
-use syntax_pos::Span;
 
-#[derive(Clone, Default)]
-pub struct ExpansionData {
-    module: Rc<ModuleData>,
+#[derive(Clone)]
+pub struct ExpansionData<'a> {
+    pub module: Module<'a>,
+    def_index: DefIndex,
+    // True if this expansion is in a `const_integer` position, for example `[u32; m!()]`.
+    // c.f. `DefCollector::visit_ast_const_integer`.
+    const_integer: bool,
 }
 
-// FIXME(jseyfried): merge with `::ModuleS`.
-#[derive(Default)]
-struct ModuleData {
-    parent: Option<Rc<ModuleData>>,
-    macros: RefCell<FnvHashMap<Name, Rc<SyntaxExtension>>>,
-    macros_escape: bool,
+impl<'a> ExpansionData<'a> {
+    pub fn root(graph_root: Module<'a>) -> Self {
+        ExpansionData {
+            module: graph_root,
+            def_index: CRATE_DEF_INDEX,
+            const_integer: false,
+        }
+    }
 }
 
 impl<'a> base::Resolver for Resolver<'a> {
@@ -45,11 +47,21 @@ impl<'a> base::Resolver for Resolver<'a> {
         self.session.next_node_id()
     }
 
-    fn visit_expansion(&mut self, mark: Mark, expansion: &Expansion) {
-        expansion.visit_with(&mut ExpansionVisitor {
-            current_module: self.expansion_data[&mark.as_u32()].module.clone(),
-            resolver: self,
+    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,
+            const_integer: false,
         });
+        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;
+        expansion.visit_with(&mut BuildReducedGraphVisitor { resolver: self });
     }
 
     fn add_macro(&mut self, scope: Mark, mut def: ast::MacroDef) {
@@ -71,9 +83,9 @@ impl<'a> base::Resolver for Resolver<'a> {
             self.macro_names.insert(ident.name);
         }
 
-        let mut module = self.expansion_data[&scope.as_u32()].module.clone();
+        let mut module = self.expansion_data[&scope.as_u32()].module;
         while module.macros_escape {
-            module = module.parent.clone().unwrap();
+            module = module.parent.unwrap();
         }
         module.macros.borrow_mut().insert(ident.name, ext);
     }
@@ -113,12 +125,12 @@ impl<'a> base::Resolver for Resolver<'a> {
             InvocationKind::Attr { ref attr, .. } => (intern(&*attr.name()), attr.span),
         };
 
-        let mut module = self.expansion_data[&scope.as_u32()].module.clone();
+        let mut module = self.expansion_data[&scope.as_u32()].module;
         loop {
             if let Some(ext) = module.macros.borrow().get(&name) {
                 return Some(ext.clone());
             }
-            match module.parent.clone() {
+            match module.parent {
                 Some(parent) => module = parent,
                 None => break,
             }
@@ -147,116 +159,23 @@ impl<'a> Resolver<'a> {
         }
     }
 
-    fn insert_custom_derive(&mut self, name: &str, ext: Rc<MultiItemModifier>, sp: Span) {
-        if !self.session.features.borrow().rustc_macro {
-            let sess = &self.session.parse_sess;
-            let msg = "loading custom derive macro crates is experimentally supported";
-            emit_feature_err(sess, "rustc_macro", sp, feature_gate::GateIssue::Language, msg);
-        }
-        if self.derive_modes.insert(token::intern(name), ext).is_some() {
-            self.session.span_err(sp, &format!("cannot shadow existing derive mode `{}`", name));
-        }
-    }
-}
-
-struct ExpansionVisitor<'b, 'a: 'b> {
-    resolver: &'b mut Resolver<'a>,
-    current_module: Rc<ModuleData>,
-}
+    fn collect_def_ids(&mut self, mark: Mark, expansion: &Expansion) {
+        let expansion_data = &mut self.expansion_data;
+        let ExpansionData { def_index, const_integer, module } = expansion_data[&mark.as_u32()];
+        let visit_macro_invoc = &mut |invoc: map::MacroInvocationData| {
+            expansion_data.entry(invoc.id.as_u32()).or_insert(ExpansionData {
+                def_index: invoc.def_index,
+                const_integer: invoc.const_integer,
+                module: module,
+            });
+        };
 
-impl<'a, 'b> ExpansionVisitor<'a, 'b> {
-    fn visit_invoc(&mut self, id: ast::NodeId) {
-        self.resolver.expansion_data.insert(id.as_u32(), ExpansionData {
-            module: self.current_module.clone(),
+        let mut def_collector = DefCollector::new(&mut self.definitions);
+        def_collector.visit_macro_invoc = Some(visit_macro_invoc);
+        def_collector.with_parent(def_index, |def_collector| if !const_integer {
+            expansion.visit_with(def_collector)
+        } else if let Expansion::Expr(ref expr) = *expansion {
+            def_collector.visit_ast_const_integer(expr);
         });
     }
-
-    // does this attribute list contain "macro_use"?
-    fn contains_macro_use(&mut self, attrs: &[ast::Attribute]) -> bool {
-        for attr in attrs {
-            if attr.check_name("macro_escape") {
-                let msg = "macro_escape is a deprecated synonym for macro_use";
-                let mut err = self.resolver.session.struct_span_warn(attr.span, msg);
-                if let ast::AttrStyle::Inner = attr.node.style {
-                    err.help("consider an outer attribute, #[macro_use] mod ...").emit();
-                } else {
-                    err.emit();
-                }
-            } else if !attr.check_name("macro_use") {
-                continue;
-            }
-
-            if !attr.is_word() {
-                self.resolver.session.span_err(attr.span,
-                                               "arguments to macro_use are not allowed here");
-            }
-            return true;
-        }
-
-        false
-    }
-}
-
-macro_rules! method {
-    ($visit:ident: $ty:ty, $invoc:path, $walk:ident) => {
-        fn $visit(&mut self, node: &$ty) {
-            match node.node {
-                $invoc(..) => self.visit_invoc(node.id),
-                _ => visit::$walk(self, node),
-            }
-        }
-    }
-}
-
-impl<'a, 'b> Visitor for ExpansionVisitor<'a, 'b>  {
-    method!(visit_trait_item: ast::TraitItem, ast::TraitItemKind::Macro, walk_trait_item);
-    method!(visit_impl_item:  ast::ImplItem,  ast::ImplItemKind::Macro,  walk_impl_item);
-    method!(visit_stmt:       ast::Stmt,      ast::StmtKind::Mac,        walk_stmt);
-    method!(visit_expr:       ast::Expr,      ast::ExprKind::Mac,        walk_expr);
-    method!(visit_pat:        ast::Pat,       ast::PatKind::Mac,         walk_pat);
-    method!(visit_ty:         ast::Ty,        ast::TyKind::Mac,          walk_ty);
-
-    fn visit_item(&mut self, item: &ast::Item) {
-        match item.node {
-            ast::ItemKind::Mac(..) if item.id == ast::DUMMY_NODE_ID => {} // Scope placeholder
-            ast::ItemKind::Mac(..) => self.visit_invoc(item.id),
-            ast::ItemKind::Mod(..) => {
-                let module_data = ModuleData {
-                    parent: Some(self.current_module.clone()),
-                    macros: RefCell::new(FnvHashMap()),
-                    macros_escape: self.contains_macro_use(&item.attrs),
-                };
-                let orig_module = mem::replace(&mut self.current_module, Rc::new(module_data));
-                visit::walk_item(self, item);
-                self.current_module = orig_module;
-            }
-            ast::ItemKind::ExternCrate(..) => {
-                // We need to error on `#[macro_use] extern crate` when it isn't at the
-                // crate root, because `$crate` won't work properly.
-                // FIXME(jseyfried): This will be nicer once `ModuleData` is merged with `ModuleS`.
-                let is_crate_root = self.current_module.parent.as_ref().unwrap().parent.is_none();
-                for def in self.resolver.crate_loader.load_macros(item, is_crate_root) {
-                    match def {
-                        LoadedMacro::Def(def) => self.resolver.add_macro(Mark::root(), def),
-                        LoadedMacro::CustomDerive(name, ext) => {
-                            self.resolver.insert_custom_derive(&name, ext, item.span);
-                        }
-                    }
-                }
-                visit::walk_item(self, item);
-            }
-            _ => visit::walk_item(self, item),
-        }
-    }
-
-    fn visit_block(&mut self, block: &ast::Block) {
-        let module_data = ModuleData {
-            parent: Some(self.current_module.clone()),
-            macros: RefCell::new(FnvHashMap()),
-            macros_escape: false,
-        };
-        let orig_module = mem::replace(&mut self.current_module, Rc::new(module_data));
-        visit::walk_block(self, block);
-        self.current_module = orig_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 495ad176542..5082f64ccbb 100644
--- a/src/libsyntax/ext/base.rs
+++ b/src/libsyntax/ext/base.rs
@@ -515,6 +515,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);
@@ -530,6 +531,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) {}
@@ -567,6 +569,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,
 }
 
@@ -581,6 +584,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 8436835da3e..36a33dcc5c5 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;
@@ -206,7 +206,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();
         }
 
@@ -277,8 +277,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
@@ -674,7 +676,7 @@ impl<'a, 'b> Folder for InvocationCollector<'a, 'b> {
     fn fold_item(&mut self, item: P<ast::Item>) -> SmallVector<P<ast::Item>> {
         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();
@@ -731,6 +733,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<ast::Ident>,
+fn mk_reexport_mod(cx: &mut TestCtxt, parent: ast::NodeId, tests: Vec<ast::Ident>,
                    tested_submods: Vec<(ast::Ident, ast::Ident)>) -> (P<ast::Item>, ast::Ident) {
     let super_ = token::str_to_ident("super");
 
@@ -257,6 +240,8 @@ fn mk_reexport_mod(cx: &mut TestCtxt, tests: Vec<ast::Ident>,
     };
 
     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(),
diff --git a/src/test/codegen-units/item-collection/overloaded-operators.rs b/src/test/codegen-units/item-collection/overloaded-operators.rs
index c275eb954b0..0295311334b 100644
--- a/src/test/codegen-units/item-collection/overloaded-operators.rs
+++ b/src/test/codegen-units/item-collection/overloaded-operators.rs
@@ -45,8 +45,8 @@ impl IndexMut<usize> for Indexable {
 }
 
 
-//~ TRANS_ITEM fn overloaded_operators::{{impl}}[2]::eq[0]
-//~ TRANS_ITEM fn overloaded_operators::{{impl}}[2]::ne[0]
+//~ TRANS_ITEM fn overloaded_operators::{{impl}}[4]::eq[0]
+//~ TRANS_ITEM fn overloaded_operators::{{impl}}[4]::ne[0]
 #[derive(PartialEq)]
 pub struct Equatable(u32);
 
@@ -54,7 +54,7 @@ pub struct Equatable(u32);
 impl Add<u32> for Equatable {
     type Output = u32;
 
-    //~ TRANS_ITEM fn overloaded_operators::{{impl}}[3]::add[0]
+    //~ TRANS_ITEM fn overloaded_operators::{{impl}}[2]::add[0]
     fn add(self, rhs: u32) -> u32 {
         self.0 + rhs
     }
@@ -63,7 +63,7 @@ impl Add<u32> for Equatable {
 impl Deref for Equatable {
     type Target = u32;
 
-    //~ TRANS_ITEM fn overloaded_operators::{{impl}}[4]::deref[0]
+    //~ TRANS_ITEM fn overloaded_operators::{{impl}}[3]::deref[0]
     fn deref(&self) -> &Self::Target {
         &self.0
     }
diff --git a/src/test/compile-fail-fulldeps/derive-no-std-not-supported.rs b/src/test/compile-fail-fulldeps/derive-no-std-not-supported.rs
index 01c81a8bbce..6ae5544d686 100644
--- a/src/test/compile-fail-fulldeps/derive-no-std-not-supported.rs
+++ b/src/test/compile-fail-fulldeps/derive-no-std-not-supported.rs
@@ -10,7 +10,6 @@
 
 #![no_std]
 
-extern crate core;
 extern crate rand;
 extern crate serialize as rustc_serialize;
 
diff --git a/src/test/compile-fail/gated-non-ascii-idents.rs b/src/test/compile-fail/gated-non-ascii-idents.rs
index f4b9830d579..9e042c3a7d5 100644
--- a/src/test/compile-fail/gated-non-ascii-idents.rs
+++ b/src/test/compile-fail/gated-non-ascii-idents.rs
@@ -8,7 +8,7 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-extern crate bäz; //~ ERROR non-ascii idents
+extern crate core as bäz; //~ ERROR non-ascii idents
 
 use föö::bar; //~ ERROR non-ascii idents
 
diff --git a/src/test/compile-fail/self_type_keyword.rs b/src/test/compile-fail/self_type_keyword.rs
index 911606ef012..0f2a3f12107 100644
--- a/src/test/compile-fail/self_type_keyword.rs
+++ b/src/test/compile-fail/self_type_keyword.rs
@@ -38,11 +38,17 @@ pub fn main() {
     }
 }
 
-use std::option::Option as Self;
-//~^ ERROR expected identifier, found keyword `Self`
+mod m1 {
+    extern crate core as Self;
+    //~^ ERROR expected identifier, found keyword `Self`
+}
 
-extern crate Self;
-//~^ ERROR expected identifier, found keyword `Self`
+mod m2 {
+    use std::option::Option as Self;
+    //~^ ERROR expected identifier, found keyword `Self`
+}
 
-trait Self {}
-//~^ ERROR expected identifier, found keyword `Self`
+mod m3 {
+    trait Self {}
+    //~^ ERROR expected identifier, found keyword `Self`
+}