about summary refs log tree commit diff
diff options
context:
space:
mode:
authorJeffrey Seyfried <jeffrey.seyfried@gmail.com>2016-10-11 03:41:18 +0000
committerJeffrey Seyfried <jeffrey.seyfried@gmail.com>2016-10-11 03:41:18 +0000
commitd5281ef681195828173d4fe516b653ba0f9e9fbc (patch)
tree9dbe1062b81fdbc416862dfc82a7bf5a65c491f6
parenta7bfb1aba9d089a0464c03b3841e889c6ee7c4f1 (diff)
parent6808b0a2b77448585dff3e0bfdd72a16ed5dab9b (diff)
downloadrust-d5281ef681195828173d4fe516b653ba0f9e9fbc.tar.gz
rust-d5281ef681195828173d4fe516b653ba0f9e9fbc.zip
Merge branch 'persistent_macro_scopes' into cleanup_expanded_macro_use_scopes
-rw-r--r--src/librustc/hir/lowering.rs8
-rw-r--r--src/librustc_driver/driver.rs12
-rw-r--r--src/librustc_resolve/build_reduced_graph.rs69
-rw-r--r--src/librustc_resolve/lib.rs50
-rw-r--r--src/librustc_resolve/macros.rs222
-rw-r--r--src/libsyntax/ext/base.rs23
-rw-r--r--src/libsyntax/ext/expand.rs49
-rw-r--r--src/libsyntax/ext/placeholders.rs3
-rw-r--r--src/libsyntax/print/pprust.rs2
-rw-r--r--src/libsyntax/std_inject.rs22
-rw-r--r--src/libsyntax_ext/lib.rs21
11 files changed, 282 insertions, 199 deletions
diff --git a/src/librustc/hir/lowering.rs b/src/librustc/hir/lowering.rs
index f56a27b9ae0..22904282642 100644
--- a/src/librustc/hir/lowering.rs
+++ b/src/librustc/hir/lowering.rs
@@ -95,13 +95,7 @@ pub fn lower_crate(sess: &Session,
     let _ignore = sess.dep_graph.in_ignore();
 
     LoweringContext {
-        crate_root: if std_inject::no_core(krate) {
-            None
-        } else if std_inject::no_std(krate) {
-            Some("core")
-        } else {
-            Some("std")
-        },
+        crate_root: std_inject::injected_crate_name(krate),
         sess: sess,
         parent_def: None,
         resolver: resolver,
diff --git a/src/librustc_driver/driver.rs b/src/librustc_driver/driver.rs
index ea42f7ba93e..e8ab2f3a240 100644
--- a/src/librustc_driver/driver.rs
+++ b/src/librustc_driver/driver.rs
@@ -649,7 +649,7 @@ pub fn phase_2_configure_and_expand<'a, F>(sess: &Session,
     let resolver_arenas = Resolver::arenas();
     let mut resolver =
         Resolver::new(sess, &krate, make_glob_map, &mut crate_loader, &resolver_arenas);
-    syntax_ext::register_builtins(&mut resolver, sess.features.borrow().quote);
+    syntax_ext::register_builtins(&mut resolver, syntax_exts, sess.features.borrow().quote);
 
     krate = time(time_passes, "expansion", || {
         // Windows dlls do not have rpaths, so they don't know how to find their
@@ -686,11 +686,17 @@ pub fn phase_2_configure_and_expand<'a, F>(sess: &Session,
             ..syntax::ext::expand::ExpansionConfig::default(crate_name.to_string())
         };
         let mut ecx = ExtCtxt::new(&sess.parse_sess, krate.config.clone(), cfg, &mut resolver);
-        let ret = syntax::ext::expand::expand_crate(&mut ecx, syntax_exts, krate);
+        let err_count = ecx.parse_sess.span_diagnostic.err_count();
+
+        let krate = ecx.monotonic_expander().expand_crate(krate);
+
+        if ecx.parse_sess.span_diagnostic.err_count() - ecx.resolve_err_count > err_count {
+            ecx.parse_sess.span_diagnostic.abort_if_errors();
+        }
         if cfg!(windows) {
             env::set_var("PATH", &old_path);
         }
-        ret
+        krate
     });
 
     krate.exported_macros = mem::replace(&mut resolver.exported_macros, Vec::new());
diff --git a/src/librustc_resolve/build_reduced_graph.rs b/src/librustc_resolve/build_reduced_graph.rs
index 9149202c1c1..12e56131597 100644
--- a/src/librustc_resolve/build_reduced_graph.rs
+++ b/src/librustc_resolve/build_reduced_graph.rs
@@ -13,7 +13,7 @@
 //! Here we build the "reduced graph": the graph of the module tree without
 //! any imports resolved.
 
-use macros;
+use macros::{InvocationData, LegacyImports, LegacyScope};
 use resolve_imports::ImportDirectiveSubclass::{self, GlobImport};
 use {Module, ModuleS, ModuleKind};
 use Namespace::{self, TypeNS, ValueNS};
@@ -84,7 +84,7 @@ impl<'b> Resolver<'b> {
     }
 
     /// Constructs the reduced graph for one item.
-    fn build_reduced_graph_for_item(&mut self, item: &Item, expansion: Mark) {
+    fn build_reduced_graph_for_item(&mut self, item: &Item, legacy_imports: &mut LegacyImports) {
         let parent = self.current_module;
         let name = item.ident.name;
         let sp = item.span;
@@ -200,16 +200,9 @@ impl<'b> Resolver<'b> {
                         LoadedMacroKind::Def(mut def) => {
                             let name = def.ident.name;
                             if def.use_locally {
-                                let ext = macro_rules::compile(&self.session.parse_sess, &def);
-                                let shadowing =
-                                    self.resolve_macro_name(Mark::root(), name, false).is_some();
-                                self.expansion_data[&Mark::root()].module.macros.borrow_mut()
-                                    .insert(name, macros::NameBinding {
-                                        ext: Rc::new(ext),
-                                        expansion: expansion,
-                                        shadowing: shadowing,
-                                        span: loaded_macro.import_site,
-                                    });
+                                let ext =
+                                    Rc::new(macro_rules::compile(&self.session.parse_sess, &def));
+                                legacy_imports.insert(name, (ext, loaded_macro.import_site));
                                 self.macro_names.insert(name);
                             }
                             if def.export {
@@ -250,7 +243,6 @@ 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));
@@ -520,22 +512,26 @@ impl<'b> Resolver<'b> {
 
 pub struct BuildReducedGraphVisitor<'a, 'b: 'a> {
     pub resolver: &'a mut Resolver<'b>,
-    pub expansion: Mark,
+    pub legacy_scope: LegacyScope<'b>,
+    pub legacy_imports: LegacyImports,
 }
 
 impl<'a, 'b> BuildReducedGraphVisitor<'a, 'b> {
-    fn visit_invoc(&mut self, id: ast::NodeId) {
-        self.resolver.expansion_data.get_mut(&Mark::from_placeholder_id(id)).unwrap().module =
-            self.resolver.current_module;
+    fn visit_invoc(&mut self, id: ast::NodeId) -> &'b InvocationData<'b> {
+        let invocation = self.resolver.invocations[&Mark::from_placeholder_id(id)];
+        invocation.module.set(self.resolver.current_module);
+        invocation.legacy_scope.set(self.legacy_scope);
+        invocation
     }
 }
 
 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),
+            if let $invoc(..) = node.node {
+                self.visit_invoc(node.id);
+            } else {
+                visit::$walk(self, node);
             }
         }
     }
@@ -543,22 +539,35 @@ macro_rules! method {
 
 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 {
+        let macro_use = match item.node {
             ItemKind::Mac(..) if item.id == ast::DUMMY_NODE_ID => return, // Scope placeholder
-            ItemKind::Mac(..) => return self.visit_invoc(item.id),
-            _ => {}
-        }
+            ItemKind::Mac(..) => {
+                return self.legacy_scope = LegacyScope::Expansion(self.visit_invoc(item.id));
+            }
+            ItemKind::Mod(..) => self.resolver.contains_macro_use(&item.attrs),
+            _ => false,
+        };
 
-        let parent = self.resolver.current_module;
-        self.resolver.build_reduced_graph_for_item(item, self.expansion);
+        let (parent, legacy_scope) = (self.resolver.current_module, self.legacy_scope);
+        self.resolver.build_reduced_graph_for_item(item, &mut self.legacy_imports);
         visit::walk_item(self, item);
         self.resolver.current_module = parent;
+        if !macro_use {
+            self.legacy_scope = legacy_scope;
+        }
+    }
+
+    fn visit_stmt(&mut self, stmt: &ast::Stmt) {
+        if let ast::StmtKind::Mac(..) = stmt.node {
+            self.legacy_scope = LegacyScope::Expansion(self.visit_invoc(stmt.id));
+        } else {
+            visit::walk_stmt(self, stmt);
+        }
     }
 
     fn visit_foreign_item(&mut self, foreign_item: &ForeignItem) {
@@ -567,10 +576,11 @@ impl<'a, 'b> Visitor for BuildReducedGraphVisitor<'a, 'b> {
     }
 
     fn visit_block(&mut self, block: &Block) {
-        let parent = self.resolver.current_module;
+        let (parent, legacy_scope) = (self.resolver.current_module, self.legacy_scope);
         self.resolver.build_reduced_graph_for_block(block);
         visit::walk_block(self, block);
         self.resolver.current_module = parent;
+        self.legacy_scope = legacy_scope;
     }
 
     fn visit_trait_item(&mut self, item: &TraitItem) {
@@ -578,7 +588,8 @@ impl<'a, 'b> Visitor for BuildReducedGraphVisitor<'a, 'b> {
         let def_id = parent.def_id().unwrap();
 
         if let TraitItemKind::Macro(_) = item.node {
-            return self.visit_invoc(item.id);
+            self.visit_invoc(item.id);
+            return
         }
 
         // Add the item to the trait info.
diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs
index 4f41dfc8b64..fb18615263c 100644
--- a/src/librustc_resolve/lib.rs
+++ b/src/librustc_resolve/lib.rs
@@ -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;
 
@@ -77,6 +78,7 @@ use std::mem::replace;
 use std::rc::Rc;
 
 use resolve_imports::{ImportDirective, NameResolution};
+use macros::{InvocationData, LegacyBinding, LegacyScope};
 
 // NB: This module needs to be declared first so diagnostics are
 // registered before they are used.
@@ -791,9 +793,6 @@ pub struct ModuleS<'a> {
     // access the children must be preceded with a
     // `populate_module_if_necessary` call.
     populated: Cell<bool>,
-
-    macros: RefCell<FnvHashMap<Name, macros::NameBinding>>,
-    macros_escape: bool,
 }
 
 pub type Module<'a> = &'a ModuleS<'a>;
@@ -811,8 +810,6 @@ impl<'a> ModuleS<'a> {
             globs: RefCell::new((Vec::new())),
             traits: RefCell::new(None),
             populated: Cell::new(true),
-            macros: RefCell::new(FnvHashMap()),
-            macros_escape: false,
         }
     }
 
@@ -1076,7 +1073,7 @@ pub struct Resolver<'a> {
 
     privacy_errors: Vec<PrivacyError<'a>>,
     ambiguity_errors: Vec<AmbiguityError<'a>>,
-    macro_shadowing_errors: FnvHashSet<Span>,
+    disallowed_shadowing: Vec<(Name, Span, LegacyScope<'a>)>,
 
     arenas: &'a ResolverArenas<'a>,
     dummy_binding: &'a NameBinding<'a>,
@@ -1086,9 +1083,10 @@ pub struct Resolver<'a> {
     pub derive_modes: FnvHashMap<Name, Rc<MultiItemModifier>>,
     crate_loader: &'a mut CrateLoader,
     macro_names: FnvHashSet<Name>,
+    builtin_macros: FnvHashMap<Name, Rc<SyntaxExtension>>,
 
     // Maps the `Mark` of an expansion to its containing module or block.
-    expansion_data: FnvHashMap<Mark, macros::ExpansionData<'a>>,
+    invocations: FnvHashMap<Mark, &'a InvocationData<'a>>,
 }
 
 pub struct ResolverArenas<'a> {
@@ -1097,6 +1095,8 @@ pub struct ResolverArenas<'a> {
     name_bindings: arena::TypedArena<NameBinding<'a>>,
     import_directives: arena::TypedArena<ImportDirective<'a>>,
     name_resolutions: arena::TypedArena<RefCell<NameResolution<'a>>>,
+    invocation_data: arena::TypedArena<InvocationData<'a>>,
+    legacy_bindings: arena::TypedArena<LegacyBinding<'a>>,
 }
 
 impl<'a> ResolverArenas<'a> {
@@ -1120,6 +1120,13 @@ impl<'a> ResolverArenas<'a> {
     fn alloc_name_resolution(&'a self) -> &'a RefCell<NameResolution<'a>> {
         self.name_resolutions.alloc(Default::default())
     }
+    fn alloc_invocation_data(&'a self, expansion_data: InvocationData<'a>)
+                             -> &'a InvocationData<'a> {
+        self.invocation_data.alloc(expansion_data)
+    }
+    fn alloc_legacy_binding(&'a self, binding: LegacyBinding<'a>) -> &'a LegacyBinding<'a> {
+        self.legacy_bindings.alloc(binding)
+    }
 }
 
 impl<'a> ty::NodeIdTree for Resolver<'a> {
@@ -1205,8 +1212,9 @@ impl<'a> Resolver<'a> {
         let mut definitions = Definitions::new();
         DefCollector::new(&mut definitions).collect_root();
 
-        let mut expansion_data = FnvHashMap();
-        expansion_data.insert(Mark::root(), macros::ExpansionData::root(graph_root));
+        let mut invocations = FnvHashMap();
+        invocations.insert(Mark::root(),
+                           arenas.alloc_invocation_data(InvocationData::root(graph_root)));
 
         Resolver {
             session: session,
@@ -1252,7 +1260,7 @@ impl<'a> Resolver<'a> {
 
             privacy_errors: Vec::new(),
             ambiguity_errors: Vec::new(),
-            macro_shadowing_errors: FnvHashSet(),
+            disallowed_shadowing: Vec::new(),
 
             arenas: arenas,
             dummy_binding: arenas.alloc_name_binding(NameBinding {
@@ -1266,7 +1274,8 @@ impl<'a> Resolver<'a> {
             derive_modes: FnvHashMap(),
             crate_loader: crate_loader,
             macro_names: FnvHashSet(),
-            expansion_data: expansion_data,
+            builtin_macros: FnvHashMap(),
+            invocations: invocations,
         }
     }
 
@@ -1277,6 +1286,8 @@ impl<'a> Resolver<'a> {
             name_bindings: arena::TypedArena::new(),
             import_directives: arena::TypedArena::new(),
             name_resolutions: arena::TypedArena::new(),
+            invocation_data: arena::TypedArena::new(),
+            legacy_bindings: arena::TypedArena::new(),
         }
     }
 
@@ -3342,7 +3353,8 @@ impl<'a> Resolver<'a> {
         vis.is_accessible_from(module.normal_ancestor_id.unwrap(), self)
     }
 
-    fn report_errors(&self) {
+    fn report_errors(&mut self) {
+        self.report_shadowing_errors();
         let mut reported_spans = FnvHashSet();
 
         for &AmbiguityError { span, name, b1, b2 } in &self.ambiguity_errors {
@@ -3370,6 +3382,20 @@ impl<'a> Resolver<'a> {
         }
     }
 
+    fn report_shadowing_errors(&mut self) {
+        let mut reported_errors = FnvHashSet();
+        for (name, span, scope) in replace(&mut self.disallowed_shadowing, Vec::new()) {
+            if self.resolve_macro_name(scope, name, false).is_some() &&
+               reported_errors.insert((name, span)) {
+                let msg = format!("`{}` is already in scope", name);
+                self.session.struct_span_err(span, &msg)
+                    .note("macro-expanded `macro_rules!`s and `#[macro_use]`s \
+                           may not shadow existing macros (see RFC 1560)")
+                    .emit();
+            }
+        }
+    }
+
     fn report_conflict(&self,
                        parent: Module,
                        name: Name,
diff --git a/src/librustc_resolve/macros.rs b/src/librustc_resolve/macros.rs
index 3f6c69278be..1c36b2452a4 100644
--- a/src/librustc_resolve/macros.rs
+++ b/src/librustc_resolve/macros.rs
@@ -12,47 +12,79 @@ use {Module, Resolver};
 use build_reduced_graph::BuildReducedGraphVisitor;
 use rustc::hir::def_id::{CRATE_DEF_INDEX, DefIndex};
 use rustc::hir::map::{self, DefCollector};
+use rustc::util::nodemap::FnvHashMap;
+use std::cell::Cell;
 use std::rc::Rc;
 use syntax::ast;
 use syntax::errors::DiagnosticBuilder;
 use syntax::ext::base::{self, MultiModifier, MultiDecorator, MultiItemModifier};
 use syntax::ext::base::{NormalTT, SyntaxExtension};
 use syntax::ext::expand::{Expansion, Invocation, InvocationKind};
-use syntax::ext::hygiene::{Mark, SyntaxContext};
+use syntax::ext::hygiene::Mark;
 use syntax::ext::tt::macro_rules;
 use syntax::parse::token::intern;
 use syntax::util::lev_distance::find_best_match_for_name;
-use syntax_pos::{Span, DUMMY_SP};
-
-// FIXME(jseyfried) Merge with `::NameBinding`.
-pub struct NameBinding {
-    pub ext: Rc<SyntaxExtension>,
-    pub expansion: Mark,
-    pub shadowing: bool,
-    pub span: Span,
-}
+use syntax_pos::Span;
 
 #[derive(Clone)]
-pub struct ExpansionData<'a> {
-    backtrace: SyntaxContext,
-    pub module: Module<'a>,
+pub struct InvocationData<'a> {
+    pub module: Cell<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,
+    // The scope in which the invocation path is resolved.
+    pub legacy_scope: Cell<LegacyScope<'a>>,
+    // The smallest scope that includes this invocation's expansion,
+    // or `Empty` if this invocation has not been expanded yet.
+    pub expansion: Cell<LegacyScope<'a>>,
 }
 
-impl<'a> ExpansionData<'a> {
+impl<'a> InvocationData<'a> {
     pub fn root(graph_root: Module<'a>) -> Self {
-        ExpansionData {
-            backtrace: SyntaxContext::empty(),
-            module: graph_root,
+        InvocationData {
+            module: Cell::new(graph_root),
             def_index: CRATE_DEF_INDEX,
             const_integer: false,
+            legacy_scope: Cell::new(LegacyScope::Empty),
+            expansion: Cell::new(LegacyScope::Empty),
         }
     }
 }
 
+#[derive(Copy, Clone)]
+pub enum LegacyScope<'a> {
+    Empty,
+    Invocation(&'a InvocationData<'a>), // The scope of the invocation, not including its expansion
+    Expansion(&'a InvocationData<'a>), // The scope of the invocation, including its expansion
+    Binding(&'a LegacyBinding<'a>),
+}
+
+impl<'a> LegacyScope<'a> {
+    fn simplify_expansion(mut invoc: &'a InvocationData<'a>) -> Self {
+        while let LegacyScope::Invocation(_) = invoc.expansion.get() {
+            match invoc.legacy_scope.get() {
+                LegacyScope::Expansion(new_invoc) => invoc = new_invoc,
+                LegacyScope::Binding(_) => break,
+                scope @ _ => return scope,
+            }
+        }
+        LegacyScope::Expansion(invoc)
+    }
+}
+
+pub struct LegacyBinding<'a> {
+    parent: LegacyScope<'a>,
+    kind: LegacyBindingKind,
+}
+
+pub enum LegacyBindingKind {
+    MacroRules(ast::Name, Rc<SyntaxExtension>, Span),
+    MacroUse(LegacyImports),
+}
+
+pub type LegacyImports = FnvHashMap<ast::Name, (Rc<SyntaxExtension>, Span)>;
+
 impl<'a> base::Resolver for Resolver<'a> {
     fn next_node_id(&mut self) -> ast::NodeId {
         self.session.next_node_id()
@@ -61,19 +93,37 @@ impl<'a> base::Resolver for Resolver<'a> {
     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, ExpansionData {
-            backtrace: SyntaxContext::empty(),
-            module: module,
+        self.invocations.insert(mark, self.arenas.alloc_invocation_data(InvocationData {
+            module: Cell::new(module),
             def_index: module.def_id().unwrap().index,
             const_integer: false,
-        });
+            legacy_scope: Cell::new(LegacyScope::Empty),
+            expansion: Cell::new(LegacyScope::Empty),
+        }));
         mark
     }
 
     fn visit_expansion(&mut self, mark: Mark, expansion: &Expansion) {
-        self.collect_def_ids(mark, expansion);
-        self.current_module = self.expansion_data[&mark].module;
-        expansion.visit_with(&mut BuildReducedGraphVisitor { resolver: self, expansion: mark });
+        let invocation = self.invocations[&mark];
+        self.collect_def_ids(invocation, expansion);
+
+        self.current_module = invocation.module.get();
+        let mut visitor = BuildReducedGraphVisitor {
+            resolver: self,
+            legacy_scope: LegacyScope::Invocation(invocation),
+            legacy_imports: FnvHashMap(),
+        };
+        expansion.visit_with(&mut visitor);
+        invocation.expansion.set(visitor.legacy_scope);
+
+        if !visitor.legacy_imports.is_empty() {
+            invocation.legacy_scope.set({
+                LegacyScope::Binding(self.arenas.alloc_legacy_binding(LegacyBinding {
+                    parent: invocation.legacy_scope.get(),
+                    kind: LegacyBindingKind::MacroUse(visitor.legacy_imports),
+                }))
+            });
+        }
     }
 
     fn add_macro(&mut self, scope: Mark, mut def: ast::MacroDef) {
@@ -81,17 +131,13 @@ impl<'a> base::Resolver for Resolver<'a> {
             self.session.span_err(def.span, "user-defined macros may not be named `macro_rules`");
         }
         if def.use_locally {
-            let ExpansionData { mut module, backtrace, .. } = self.expansion_data[&scope];
-            while module.macros_escape {
-                module = module.parent.unwrap();
-            }
-            let binding = NameBinding {
-                ext: Rc::new(macro_rules::compile(&self.session.parse_sess, &def)),
-                expansion: backtrace.data().prev_ctxt.data().outer_mark,
-                shadowing: self.resolve_macro_name(scope, def.ident.name, false).is_some(),
-                span: def.span,
-            };
-            module.macros.borrow_mut().insert(def.ident.name, binding);
+            let invocation = self.invocations[&scope];
+            let ext = Rc::new(macro_rules::compile(&self.session.parse_sess, &def));
+            let binding = self.arenas.alloc_legacy_binding(LegacyBinding {
+                parent: invocation.legacy_scope.get(),
+                kind: LegacyBindingKind::MacroRules(def.ident.name, ext, def.span),
+            });
+            invocation.legacy_scope.set(LegacyScope::Binding(binding));
             self.macro_names.insert(def.ident.name);
         }
         if def.export {
@@ -104,12 +150,7 @@ impl<'a> base::Resolver for Resolver<'a> {
         if let NormalTT(..) = *ext {
             self.macro_names.insert(ident.name);
         }
-        self.graph_root.macros.borrow_mut().insert(ident.name, NameBinding {
-            ext: ext,
-            expansion: Mark::root(),
-            shadowing: false,
-            span: DUMMY_SP,
-        });
+        self.builtin_macros.insert(ident.name, ext);
     }
 
     fn add_expansions_at_stmt(&mut self, id: ast::NodeId, macros: Vec<Mark>) {
@@ -119,8 +160,8 @@ impl<'a> base::Resolver for Resolver<'a> {
     fn find_attr_invoc(&mut self, attrs: &mut Vec<ast::Attribute>) -> Option<ast::Attribute> {
         for i in 0..attrs.len() {
             let name = intern(&attrs[i].name());
-            match self.expansion_data[&Mark::root()].module.macros.borrow().get(&name) {
-                Some(binding) => match *binding.ext {
+            match self.builtin_macros.get(&name) {
+                Some(ext) => match **ext {
                     MultiModifier(..) | MultiDecorator(..) | SyntaxExtension::AttrProcMacro(..) => {
                         return Some(attrs.remove(i))
                     }
@@ -147,7 +188,11 @@ impl<'a> base::Resolver for Resolver<'a> {
             InvocationKind::Attr { ref attr, .. } => (intern(&*attr.name()), attr.span),
         };
 
-        self.resolve_macro_name(scope, name, true).or_else(|| {
+        let invocation = self.invocations[&scope];
+        if let LegacyScope::Expansion(parent) = invocation.legacy_scope.get() {
+            invocation.legacy_scope.set(LegacyScope::simplify_expansion(parent));
+        }
+        self.resolve_macro_name(invocation.legacy_scope.get(), name, true).or_else(|| {
             let mut err =
                 self.session.struct_span_err(span, &format!("macro undefined: '{}!'", name));
             self.suggest_macro_name(&name.as_str(), &mut err);
@@ -162,36 +207,57 @@ impl<'a> base::Resolver for Resolver<'a> {
 }
 
 impl<'a> Resolver<'a> {
-    pub fn resolve_macro_name(&mut self, scope: Mark, name: ast::Name, record_used: bool)
+    pub fn resolve_macro_name(&mut self,
+                              mut scope: LegacyScope<'a>,
+                              name: ast::Name,
+                              record_used: bool)
                               -> Option<Rc<SyntaxExtension>> {
-        let ExpansionData { mut module, backtrace, .. } = self.expansion_data[&scope];
+        let check_shadowing = |this: &mut Self, relative_depth, scope, span| {
+            if record_used && relative_depth > 0 {
+                this.disallowed_shadowing.push((name, span, scope));
+            }
+        };
+
+        let mut relative_depth: u32 = 0;
         loop {
-            if let Some(binding) = module.macros.borrow().get(&name) {
-                let mut backtrace = backtrace.data();
-                while binding.expansion != backtrace.outer_mark {
-                    if backtrace.outer_mark != Mark::root() {
-                        backtrace = backtrace.prev_ctxt.data();
-                        continue
+            scope = match scope {
+                LegacyScope::Empty => break,
+                LegacyScope::Expansion(invocation) => {
+                    if let LegacyScope::Empty = invocation.expansion.get() {
+                        invocation.legacy_scope.get()
+                    } else {
+                        relative_depth += 1;
+                        invocation.expansion.get()
                     }
-
-                    if record_used && binding.shadowing &&
-                       self.macro_shadowing_errors.insert(binding.span) {
-                        let msg = format!("`{}` is already in scope", name);
-                        self.session.struct_span_err(binding.span, &msg)
-                            .note("macro-expanded `macro_rules!`s and `#[macro_use]`s \
-                                   may not shadow existing macros (see RFC 1560)")
-                            .emit();
+                }
+                LegacyScope::Invocation(invocation) => {
+                    let new_relative_depth = relative_depth.saturating_sub(1);
+                    let mut scope = invocation.legacy_scope.get();
+                    if let LegacyScope::Binding(binding) = scope {
+                        match binding.kind {
+                            LegacyBindingKind::MacroUse(ref imports) => {
+                                if let Some(&(ref ext, span)) = imports.get(&name) {
+                                    check_shadowing(self, relative_depth, binding.parent, span);
+                                    return Some(ext.clone());
+                                }
+                            },
+                            LegacyBindingKind::MacroRules(name_, ref ext, span) => {
+                                if name_ == name {
+                                    check_shadowing(self, new_relative_depth, binding.parent, span);
+                                    return Some(ext.clone());
+                                }
+                            }
+                        }
+                        scope = binding.parent
                     }
-                    break
+                    relative_depth = new_relative_depth;
+                    scope
                 }
-                return Some(binding.ext.clone());
-            }
-            match module.parent {
-                Some(parent) => module = parent,
-                None => break,
-            }
+                _ => unreachable!(),
+            };
         }
-        None
+
+        self.builtin_macros.get(&name).cloned()
     }
 
     fn suggest_macro_name(&mut self, name: &str, err: &mut DiagnosticBuilder<'a>) {
@@ -204,15 +270,19 @@ impl<'a> Resolver<'a> {
         }
     }
 
-    fn collect_def_ids(&mut self, mark: Mark, expansion: &Expansion) {
-        let expansion_data = &mut self.expansion_data;
-        let ExpansionData { backtrace, def_index, const_integer, module } = expansion_data[&mark];
+    fn collect_def_ids(&mut self, invocation: &'a InvocationData<'a>, expansion: &Expansion) {
+        let Resolver { ref mut invocations, arenas, graph_root, .. } = *self;
+        let InvocationData { def_index, const_integer, .. } = *invocation;
+
         let visit_macro_invoc = &mut |invoc: map::MacroInvocationData| {
-            expansion_data.entry(invoc.mark).or_insert(ExpansionData {
-                backtrace: backtrace.apply_mark(invoc.mark),
-                def_index: invoc.def_index,
-                const_integer: invoc.const_integer,
-                module: module,
+            invocations.entry(invoc.mark).or_insert_with(|| {
+                arenas.alloc_invocation_data(InvocationData {
+                    def_index: invoc.def_index,
+                    const_integer: invoc.const_integer,
+                    module: Cell::new(graph_root),
+                    expansion: Cell::new(LegacyScope::Empty),
+                    legacy_scope: Cell::new(LegacyScope::Empty),
+                })
             });
         };
 
diff --git a/src/libsyntax/ext/base.rs b/src/libsyntax/ext/base.rs
index b56018e1e9d..923d5d05439 100644
--- a/src/libsyntax/ext/base.rs
+++ b/src/libsyntax/ext/base.rs
@@ -22,7 +22,6 @@ use parse::{self, parser};
 use parse::token;
 use parse::token::{InternedString, str_to_ident};
 use ptr::P;
-use std_inject;
 use util::small_vector::SmallVector;
 
 use std::path::PathBuf;
@@ -737,28 +736,6 @@ impl<'a> ExtCtxt<'a> {
     pub fn name_of(&self, st: &str) -> ast::Name {
         token::intern(st)
     }
-
-    pub fn initialize(&mut self, user_exts: Vec<NamedSyntaxExtension>, krate: &ast::Crate) {
-        if std_inject::no_core(&krate) {
-            self.crate_root = None;
-        } else if std_inject::no_std(&krate) {
-            self.crate_root = Some("core");
-        } else {
-            self.crate_root = Some("std");
-        }
-
-        for (name, extension) in user_exts {
-            let ident = ast::Ident::with_empty_ctxt(name);
-            self.resolver.add_ext(ident, Rc::new(extension));
-        }
-
-        let mut module = ModuleData {
-            mod_path: vec![token::str_to_ident(&self.ecfg.crate_name)],
-            directory: PathBuf::from(self.parse_sess.codemap().span_to_filename(krate.span)),
-        };
-        module.directory.pop();
-        self.current_expansion.module = Rc::new(module);
-    }
 }
 
 /// Extract a string literal from the macro expanded version of `expr`,
diff --git a/src/libsyntax/ext/expand.rs b/src/libsyntax/ext/expand.rs
index 3abe7626efc..ab7ffe36673 100644
--- a/src/libsyntax/ext/expand.rs
+++ b/src/libsyntax/ext/expand.rs
@@ -8,7 +8,7 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-use ast::{Block, Crate, Ident, Mac_, PatKind};
+use ast::{Block, Ident, Mac_, PatKind};
 use ast::{Name, MacStmtStyle, StmtKind, ItemKind};
 use ast;
 use ext::hygiene::Mark;
@@ -26,6 +26,7 @@ use parse::parser::Parser;
 use parse::token::{self, intern, keywords};
 use print::pprust;
 use ptr::P;
+use std_inject;
 use tokenstream::{TokenTree, TokenStream};
 use util::small_vector::SmallVector;
 use visit::Visitor;
@@ -186,8 +187,14 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
         MacroExpander { cx: cx, monotonic: monotonic }
     }
 
-    fn expand_crate(&mut self, mut krate: ast::Crate) -> ast::Crate {
-        let err_count = self.cx.parse_sess.span_diagnostic.err_count();
+    pub fn expand_crate(&mut self, mut krate: ast::Crate) -> ast::Crate {
+        self.cx.crate_root = std_inject::injected_crate_name(&krate);
+        let mut module = ModuleData {
+            mod_path: vec![token::str_to_ident(&self.cx.ecfg.crate_name)],
+            directory: PathBuf::from(self.cx.codemap().span_to_filename(krate.span)),
+        };
+        module.directory.pop();
+        self.cx.current_expansion.module = Rc::new(module);
 
         let krate_item = Expansion::Items(SmallVector::one(P(ast::Item {
             attrs: krate.attrs,
@@ -206,10 +213,6 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
             _ => unreachable!(),
         };
 
-        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();
-        }
-
         krate
     }
 
@@ -221,7 +224,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
         let (expansion, mut invocations) = self.collect_invocations(expansion);
         invocations.reverse();
 
-        let mut expansions = vec![vec![(0, expansion)]];
+        let mut expansions = Vec::new();
         while let Some(invoc) = invocations.pop() {
             let ExpansionData { depth, mark, .. } = invoc.expansion_data;
             self.cx.current_expansion = invoc.expansion_data.clone();
@@ -233,13 +236,12 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
                 None => invoc.expansion_kind.dummy(invoc.span()),
             };
 
-            self.cx.current_expansion.depth = depth + 1;
             let (expansion, new_invocations) = self.collect_invocations(expansion);
 
-            if expansions.len() == depth {
+            if expansions.len() < depth {
                 expansions.push(Vec::new());
             }
-            expansions[depth].push((mark.as_u32(), expansion));
+            expansions[depth - 1].push((mark.as_u32(), expansion));
             if !self.cx.ecfg.single_step {
                 invocations.extend(new_invocations.into_iter().rev());
             }
@@ -250,12 +252,11 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
         let mut placeholder_expander = PlaceholderExpander::new(self.cx, self.monotonic);
         while let Some(expansions) = expansions.pop() {
             for (mark, expansion) in expansions.into_iter().rev() {
-                let expansion = expansion.fold_with(&mut placeholder_expander);
                 placeholder_expander.add(ast::NodeId::from_u32(mark), expansion);
             }
         }
 
-        placeholder_expander.remove(ast::NodeId::from_u32(0))
+        expansion.fold_with(&mut placeholder_expander)
     }
 
     fn collect_invocations(&mut self, expansion: Expansion) -> (Expansion, Vec<Invocation>) {
@@ -538,7 +539,11 @@ impl<'a, 'b> InvocationCollector<'a, 'b> {
         self.invocations.push(Invocation {
             kind: kind,
             expansion_kind: expansion_kind,
-            expansion_data: ExpansionData { mark: mark, ..self.cx.current_expansion.clone() },
+            expansion_data: ExpansionData {
+                mark: mark,
+                depth: self.cx.current_expansion.depth + 1,
+                ..self.cx.current_expansion.clone()
+            },
         });
         placeholder(expansion_kind, ast::NodeId::from_u32(mark.as_u32()))
     }
@@ -866,22 +871,6 @@ impl<'feat> ExpansionConfig<'feat> {
     }
 }
 
-pub fn expand_crate(cx: &mut ExtCtxt,
-                    user_exts: Vec<NamedSyntaxExtension>,
-                    c: Crate) -> Crate {
-    cx.initialize(user_exts, &c);
-    cx.monotonic_expander().expand_crate(c)
-}
-
-// Expands crate using supplied MacroExpander - allows for
-// non-standard expansion behaviour (e.g. step-wise).
-pub fn expand_crate_with_expander(expander: &mut MacroExpander,
-                                  user_exts: Vec<NamedSyntaxExtension>,
-                                  c: Crate) -> Crate {
-    expander.cx.initialize(user_exts, &c);
-    expander.expand_crate(c)
-}
-
 // A Marker adds the given mark to the syntax context and
 // sets spans' `expn_id` to the given expn_id (unless it is `None`).
 struct Marker { mark: Mark, expn_id: Option<ExpnId> }
diff --git a/src/libsyntax/ext/placeholders.rs b/src/libsyntax/ext/placeholders.rs
index 0ede6dd98e5..e323dd2f623 100644
--- a/src/libsyntax/ext/placeholders.rs
+++ b/src/libsyntax/ext/placeholders.rs
@@ -88,10 +88,11 @@ impl<'a, 'b> PlaceholderExpander<'a, 'b> {
     }
 
     pub fn add(&mut self, id: ast::NodeId, expansion: Expansion) {
+        let expansion = expansion.fold_with(self);
         self.expansions.insert(id, expansion);
     }
 
-    pub fn remove(&mut self, id: ast::NodeId) -> Expansion {
+    fn remove(&mut self, id: ast::NodeId) -> Expansion {
         self.expansions.remove(&id).unwrap()
     }
 }
diff --git a/src/libsyntax/print/pprust.rs b/src/libsyntax/print/pprust.rs
index 3c106970232..ecb437f31a5 100644
--- a/src/libsyntax/print/pprust.rs
+++ b/src/libsyntax/print/pprust.rs
@@ -112,7 +112,7 @@ pub fn print_crate<'a>(cm: &'a CodeMap,
                                       out,
                                       ann,
                                       is_expanded);
-    if is_expanded && !std_inject::no_std(krate) {
+    if is_expanded && !std_inject::injected_crate_name(krate).is_none() {
         // We need to print `#![no_std]` (and its feature gate) so that
         // compiling pretty-printed source won't inject libstd again.
         // However we don't want these attributes in the AST because
diff --git a/src/libsyntax/std_inject.rs b/src/libsyntax/std_inject.rs
index d1454ab06cb..1b63a2b7076 100644
--- a/src/libsyntax/std_inject.rs
+++ b/src/libsyntax/std_inject.rs
@@ -34,23 +34,25 @@ fn ignored_span(sess: &ParseSess, sp: Span) -> Span {
     return sp;
 }
 
-pub fn no_core(krate: &ast::Crate) -> bool {
-    attr::contains_name(&krate.attrs, "no_core")
-}
-
-pub fn no_std(krate: &ast::Crate) -> bool {
-    attr::contains_name(&krate.attrs, "no_std") || no_core(krate)
+pub fn injected_crate_name(krate: &ast::Crate) -> Option<&'static str> {
+    if attr::contains_name(&krate.attrs, "no_core") {
+        None
+    } else if attr::contains_name(&krate.attrs, "no_std") {
+        Some("core")
+    } else {
+        Some("std")
+    }
 }
 
 pub fn maybe_inject_crates_ref(sess: &ParseSess,
                                mut krate: ast::Crate,
                                alt_std_name: Option<String>)
                                -> ast::Crate {
-    if no_core(&krate) {
-        return krate;
-    }
+    let name = match injected_crate_name(&krate) {
+        Some(name) => name,
+        None => return krate,
+    };
 
-    let name = if no_std(&krate) { "core" } else { "std" };
     let crate_name = token::intern(&alt_std_name.unwrap_or(name.to_string()));
 
     krate.module.items.insert(0, P(ast::Item {
diff --git a/src/libsyntax_ext/lib.rs b/src/libsyntax_ext/lib.rs
index e9d2c0a503b..f336b26ae41 100644
--- a/src/libsyntax_ext/lib.rs
+++ b/src/libsyntax_ext/lib.rs
@@ -50,20 +50,23 @@ pub mod deriving;
 
 use std::rc::Rc;
 use syntax::ast;
-use syntax::ext::base::{MacroExpanderFn, NormalTT, IdentTT, MultiModifier};
+use syntax::ext::base::{MacroExpanderFn, NormalTT, IdentTT, MultiModifier, NamedSyntaxExtension};
 use syntax::ext::tt::macro_rules::MacroRulesExpander;
 use syntax::parse::token::intern;
 
-pub fn register_builtins(resolver: &mut syntax::ext::base::Resolver, enable_quotes: bool) {
+pub fn register_builtins(resolver: &mut syntax::ext::base::Resolver,
+                         user_exts: Vec<NamedSyntaxExtension>,
+                         enable_quotes: bool) {
     let mut register = |name, ext| {
-        resolver.add_ext(ast::Ident::with_empty_ctxt(intern(name)), Rc::new(ext));
+        resolver.add_ext(ast::Ident::with_empty_ctxt(name), Rc::new(ext));
     };
 
-    register("macro_rules", IdentTT(Box::new(MacroRulesExpander), None, false));
+    register(intern("macro_rules"), IdentTT(Box::new(MacroRulesExpander), None, false));
 
     macro_rules! register {
         ($( $name:ident: $f:expr, )*) => { $(
-            register(stringify!($name), NormalTT(Box::new($f as MacroExpanderFn), None, false));
+            register(intern(stringify!($name)),
+                     NormalTT(Box::new($f as MacroExpanderFn), None, false));
         )* }
     }
 
@@ -108,7 +111,11 @@ pub fn register_builtins(resolver: &mut syntax::ext::base::Resolver, enable_quot
     }
 
     // format_args uses `unstable` things internally.
-    register("format_args", NormalTT(Box::new(format::expand_format_args), None, true));
+    register(intern("format_args"), NormalTT(Box::new(format::expand_format_args), None, true));
 
-    register("derive", MultiModifier(Box::new(deriving::expand_derive)));
+    register(intern("derive"), MultiModifier(Box::new(deriving::expand_derive)));
+
+    for (name, ext) in user_exts {
+        register(name, ext);
+    }
 }