about summary refs log tree commit diff
diff options
context:
space:
mode:
authorJeffrey Seyfried <jeffrey.seyfried@gmail.com>2016-10-28 06:52:45 +0000
committerJeffrey Seyfried <jeffrey.seyfried@gmail.com>2016-11-10 10:04:24 +0000
commit872943c3172619afa275987c4ad3e2041ede9fa3 (patch)
tree834c54f834381a238cfddc793461650a267ed31f
parent85f74c0eea3667e85720d6f427709873eb576b49 (diff)
downloadrust-872943c3172619afa275987c4ad3e2041ede9fa3.tar.gz
rust-872943c3172619afa275987c4ad3e2041ede9fa3.zip
Improve macro reexports.
-rw-r--r--src/librustc/hir/def_id.rs4
-rw-r--r--src/librustc/hir/map/collector.rs4
-rw-r--r--src/librustc/middle/cstore.rs18
-rw-r--r--src/librustc_metadata/creader.rs117
-rw-r--r--src/librustc_metadata/cstore_impl.rs41
-rw-r--r--src/librustc_metadata/decoder.rs9
-rw-r--r--src/librustc_metadata/encoder.rs55
-rw-r--r--src/librustc_metadata/index_builder.rs1
-rw-r--r--src/librustc_metadata/schema.rs2
-rw-r--r--src/librustc_resolve/build_reduced_graph.rs178
-rw-r--r--src/librustc_resolve/lib.rs13
-rw-r--r--src/librustc_resolve/macros.rs22
-rw-r--r--src/librustc_resolve/resolve_imports.rs5
13 files changed, 241 insertions, 228 deletions
diff --git a/src/librustc/hir/def_id.rs b/src/librustc/hir/def_id.rs
index 399243551d6..d3771b1755b 100644
--- a/src/librustc/hir/def_id.rs
+++ b/src/librustc/hir/def_id.rs
@@ -34,6 +34,10 @@ impl Idx for CrateNum {
 /// LOCAL_CRATE in their DefId.
 pub const LOCAL_CRATE: CrateNum = CrateNum(0);
 
+/// Virtual crate for builtin macros
+// FIXME(jseyfried): this is also used for custom derives until proc-macro crates get `CrateNum`s.
+pub const BUILTIN_MACROS_CRATE: CrateNum = CrateNum(!0);
+
 impl CrateNum {
     pub fn new(x: usize) -> CrateNum {
         assert!(x < (u32::MAX as usize));
diff --git a/src/librustc/hir/map/collector.rs b/src/librustc/hir/map/collector.rs
index e23a721da08..04fcf7e8450 100644
--- a/src/librustc/hir/map/collector.rs
+++ b/src/librustc/hir/map/collector.rs
@@ -226,4 +226,8 @@ impl<'ast> Visitor<'ast> for NodeCollector<'ast> {
     fn visit_lifetime(&mut self, lifetime: &'ast Lifetime) {
         self.insert(lifetime.id, NodeLifetime(lifetime));
     }
+
+    fn visit_macro_def(&mut self, macro_def: &'ast MacroDef) {
+        self.insert_entry(macro_def.id, NotPresent);
+    }
 }
diff --git a/src/librustc/middle/cstore.rs b/src/librustc/middle/cstore.rs
index bdef44bf5c1..db3c7d0450b 100644
--- a/src/librustc/middle/cstore.rs
+++ b/src/librustc/middle/cstore.rs
@@ -211,6 +211,7 @@ pub trait CrateStore<'tcx> {
     fn relative_def_path(&self, def: DefId) -> Option<hir_map::DefPath>;
     fn struct_field_names(&self, def: DefId) -> Vec<ast::Name>;
     fn item_children(&self, did: DefId) -> Vec<def::Export>;
+    fn load_macro(&self, did: DefId, sess: &Session) -> ast::MacroDef;
 
     // misc. metadata
     fn maybe_get_item_ast<'a>(&'tcx self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId)
@@ -382,6 +383,7 @@ impl<'tcx> CrateStore<'tcx> for DummyCrateStore {
     }
     fn struct_field_names(&self, def: DefId) -> Vec<ast::Name> { bug!("struct_field_names") }
     fn item_children(&self, did: DefId) -> Vec<def::Export> { bug!("item_children") }
+    fn load_macro(&self, did: DefId, sess: &Session) -> ast::MacroDef { bug!("load_macro") }
 
     // misc. metadata
     fn maybe_get_item_ast<'a>(&'tcx self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId)
@@ -421,22 +423,8 @@ impl<'tcx> CrateStore<'tcx> for DummyCrateStore {
     fn metadata_encoding_version(&self) -> &[u8] { bug!("metadata_encoding_version") }
 }
 
-pub enum LoadedMacros {
-    MacroRules(Vec<ast::MacroDef>),
-    ProcMacros(Vec<(ast::Name, SyntaxExtension)>),
-}
-
-impl LoadedMacros {
-    pub fn is_proc_macros(&self) -> bool {
-        match *self {
-            LoadedMacros::ProcMacros(_) => true,
-            _ => false,
-        }
-    }
-}
-
 pub trait CrateLoader {
     fn process_item(&mut self, item: &ast::Item, defs: &Definitions, load_macros: bool)
-                    -> Option<LoadedMacros>;
+                    -> Vec<(ast::Name, SyntaxExtension)>;
     fn postprocess(&mut self, krate: &ast::Crate);
 }
diff --git a/src/librustc_metadata/creader.rs b/src/librustc_metadata/creader.rs
index 9101f95c882..e53f1a0633b 100644
--- a/src/librustc_metadata/creader.rs
+++ b/src/librustc_metadata/creader.rs
@@ -16,7 +16,7 @@ use schema::CrateRoot;
 
 use rustc::hir::def_id::{CrateNum, DefIndex};
 use rustc::hir::svh::Svh;
-use rustc::middle::cstore::{DepKind, LoadedMacros};
+use rustc::middle::cstore::DepKind;
 use rustc::session::{config, Session};
 use rustc_back::PanicStrategy;
 use rustc::session::search_paths::PathKind;
@@ -33,11 +33,11 @@ use std::{cmp, fs};
 
 use syntax::ast;
 use syntax::abi::Abi;
-use syntax::parse;
 use syntax::attr;
 use syntax::ext::base::SyntaxExtension;
+use syntax::feature_gate::{self, emit_feature_err};
 use syntax::parse::token::{InternedString, intern};
-use syntax_pos::{Span, DUMMY_SP, mk_sp};
+use syntax_pos::{Span, DUMMY_SP};
 use log;
 
 pub struct Library {
@@ -518,68 +518,6 @@ impl<'a> CrateLoader<'a> {
         }
     }
 
-    fn read_macros(&mut self, item: &ast::Item, ekrate: &ExtensionCrate) -> LoadedMacros {
-        let root = ekrate.metadata.get_root();
-        let source_name = format!("<{} macros>", item.ident);
-        let mut macro_rules = Vec::new();
-
-        for def in root.macro_defs.decode(&*ekrate.metadata) {
-            // NB: Don't use parse::parse_tts_from_source_str because it parses with
-            // quote_depth > 0.
-            let mut p = parse::new_parser_from_source_str(&self.sess.parse_sess,
-                                                          source_name.clone(),
-                                                          def.body);
-            let lo = p.span.lo;
-            let body = match p.parse_all_token_trees() {
-                Ok(body) => body,
-                Err(mut err) => {
-                    err.emit();
-                    self.sess.abort_if_errors();
-                    unreachable!();
-                }
-            };
-            let local_span = mk_sp(lo, p.prev_span.hi);
-
-            // Mark the attrs as used
-            for attr in &def.attrs {
-                attr::mark_used(attr);
-            }
-
-            macro_rules.push(ast::MacroDef {
-                ident: ast::Ident::with_empty_ctxt(def.name),
-                id: ast::DUMMY_NODE_ID,
-                span: local_span,
-                imported_from: Some(item.ident),
-                allow_internal_unstable: attr::contains_name(&def.attrs, "allow_internal_unstable"),
-                attrs: def.attrs,
-                body: body,
-            });
-            self.sess.imported_macro_spans.borrow_mut()
-                .insert(local_span, (def.name.as_str().to_string(), def.span));
-        }
-
-        if let Some(id) = root.macro_derive_registrar {
-            let dylib = match ekrate.dylib.clone() {
-                Some(dylib) => dylib,
-                None => span_bug!(item.span, "proc-macro crate not dylib"),
-            };
-            if ekrate.target_only {
-                let message = format!("proc-macro crate is not available for \
-                                       triple `{}` (only found {})",
-                                      config::host_triple(),
-                                      self.sess.opts.target_triple);
-                self.sess.span_fatal(item.span, &message);
-            }
-
-            // custom derive crates currently should not have any macro_rules!
-            // exported macros, enforced elsewhere
-            assert_eq!(macro_rules.len(), 0);
-            LoadedMacros::ProcMacros(self.load_derive_macros(item, id, root.hash, dylib))
-        } else {
-            LoadedMacros::MacroRules(macro_rules)
-        }
-    }
-
     /// Load custom derive macros.
     ///
     /// Note that this is intentionally similar to how we load plugins today,
@@ -587,14 +525,34 @@ impl<'a> CrateLoader<'a> {
     /// implemented as dynamic libraries, but we have a possible future where
     /// custom derive (and other macro-1.1 style features) are implemented via
     /// executables and custom IPC.
-    fn load_derive_macros(&mut self, item: &ast::Item, index: DefIndex, svh: Svh, path: PathBuf)
-                          -> Vec<(ast::Name, SyntaxExtension)> {
+    fn load_derive_macros(&mut self, item: &ast::Item, ekrate: &ExtensionCrate)
+                          -> Option<Vec<(ast::Name, SyntaxExtension)>> {
         use std::{env, mem};
         use proc_macro::TokenStream;
         use proc_macro::__internal::Registry;
         use rustc_back::dynamic_lib::DynamicLibrary;
         use syntax_ext::deriving::custom::CustomDerive;
 
+        let root = ekrate.metadata.get_root();
+        let index = match root.macro_derive_registrar {
+            Some(index) => index,
+            None => return None,
+        };
+        if !self.sess.features.borrow().proc_macro {
+            let issue = feature_gate::GateIssue::Language;
+            let msg = "loading custom derive macro crates is experimentally supported";
+            emit_feature_err(&self.sess.parse_sess, "proc_macro", item.span, issue, msg);
+        }
+
+        if ekrate.target_only {
+            let msg = format!("proc-macro crate is not available for triple `{}` (only found {})",
+                               config::host_triple(), self.sess.opts.target_triple);
+            self.sess.span_fatal(item.span, &msg);
+        }
+        let path = match ekrate.dylib.clone() {
+            Some(dylib) => dylib,
+            None => span_bug!(item.span, "proc-macro crate not dylib"),
+        };
         // Make sure the path contains a / or the linker will search for it.
         let path = env::current_dir().unwrap().join(path);
         let lib = match DynamicLibrary::open(Some(&path)) {
@@ -602,7 +560,7 @@ impl<'a> CrateLoader<'a> {
             Err(err) => self.sess.span_fatal(item.span, &err),
         };
 
-        let sym = self.sess.generate_derive_registrar_symbol(&svh, index);
+        let sym = self.sess.generate_derive_registrar_symbol(&root.hash, index);
         let registrar = unsafe {
             let sym = match lib.symbol(&sym) {
                 Ok(f) => f,
@@ -632,7 +590,7 @@ impl<'a> CrateLoader<'a> {
         // Intentionally leak the dynamic library. We can't ever unload it
         // since the library can make things that will live arbitrarily long.
         mem::forget(lib);
-        my_registrar.0
+        Some(my_registrar.0)
     }
 
     /// Look for a plugin registrar. Returns library path, crate
@@ -971,24 +929,23 @@ impl<'a> middle::cstore::CrateLoader for CrateLoader<'a> {
     }
 
     fn process_item(&mut self, item: &ast::Item, definitions: &Definitions, load_macros: bool)
-                    -> Option<LoadedMacros> {
+                    -> Vec<(ast::Name, SyntaxExtension)> {
         match item.node {
             ast::ItemKind::ExternCrate(_) => {}
             ast::ItemKind::ForeignMod(ref fm) => {
                 self.process_foreign_mod(item, fm);
-                return None;
+                return Vec::new();
             }
-            _ => return None,
+            _ => return Vec::new(),
         }
 
         let info = self.extract_crate_info(item).unwrap();
-        let loaded_macros = if load_macros {
+        if load_macros {
             let ekrate = self.read_extension_crate(item.span, &info);
-            let loaded_macros = self.read_macros(item, &ekrate);
 
             // If this is a proc-macro crate, return here to avoid registering.
-            if loaded_macros.is_proc_macros() {
-                return Some(loaded_macros);
+            if let Some(custom_derives) = self.load_derive_macros(item, &ekrate) {
+                return custom_derives;
             }
 
             // Register crate now to avoid double-reading metadata
@@ -998,11 +955,7 @@ impl<'a> middle::cstore::CrateLoader for CrateLoader<'a> {
                     self.register_crate(&None, ident, name, item.span, lib, dep_kind);
                 }
             }
-
-            Some(loaded_macros)
-        } else {
-            None
-        };
+        }
 
         let (cnum, ..) = self.resolve_crate(
             &None, &info.ident, &info.name, None, item.span, PathKind::Crate, info.dep_kind,
@@ -1016,6 +969,6 @@ impl<'a> middle::cstore::CrateLoader for CrateLoader<'a> {
         self.update_extern_crate(cnum, extern_crate, &mut FxHashSet());
         self.cstore.add_extern_mod_stmt_cnum(info.id, cnum);
 
-        loaded_macros
+        Vec::new()
     }
 }
diff --git a/src/librustc_metadata/cstore_impl.rs b/src/librustc_metadata/cstore_impl.rs
index 59f65c7f7c7..3113bfcb5b4 100644
--- a/src/librustc_metadata/cstore_impl.rs
+++ b/src/librustc_metadata/cstore_impl.rs
@@ -17,6 +17,7 @@ use rustc::middle::cstore::{InlinedItem, CrateStore, CrateSource, DepKind, Exter
 use rustc::middle::cstore::{NativeLibraryKind, LinkMeta, LinkagePreference};
 use rustc::hir::def::{self, Def};
 use rustc::middle::lang_items;
+use rustc::session::Session;
 use rustc::ty::{self, Ty, TyCtxt};
 use rustc::hir::def_id::{CrateNum, DefId, DefIndex, CRATE_DEF_INDEX};
 
@@ -30,7 +31,8 @@ use rustc_back::PanicStrategy;
 use std::path::PathBuf;
 use syntax::ast;
 use syntax::attr;
-use syntax::parse::token;
+use syntax::parse::{token, new_parser_from_source_str};
+use syntax_pos::mk_sp;
 use rustc::hir::svh::Svh;
 use rustc_back::target::Target;
 use rustc::hir;
@@ -351,6 +353,43 @@ impl<'tcx> CrateStore<'tcx> for cstore::CStore {
         result
     }
 
+    fn load_macro(&self, id: DefId, sess: &Session) -> ast::MacroDef {
+        let (name, def) = self.get_crate_data(id.krate).get_macro(id.index);
+        let source_name = format!("<{} macros>", name);
+
+        // NB: Don't use parse_tts_from_source_str because it parses with quote_depth > 0.
+        let mut parser = new_parser_from_source_str(&sess.parse_sess, source_name, def.body);
+
+        let lo = parser.span.lo;
+        let body = match parser.parse_all_token_trees() {
+            Ok(body) => body,
+            Err(mut err) => {
+                err.emit();
+                sess.abort_if_errors();
+                unreachable!();
+            }
+        };
+        let local_span = mk_sp(lo, parser.prev_span.hi);
+
+        // Mark the attrs as used
+        for attr in &def.attrs {
+            attr::mark_used(attr);
+        }
+
+        sess.imported_macro_spans.borrow_mut()
+            .insert(local_span, (def.name.as_str().to_string(), def.span));
+
+        ast::MacroDef {
+            ident: ast::Ident::with_empty_ctxt(def.name),
+            id: ast::DUMMY_NODE_ID,
+            span: local_span,
+            imported_from: None, // FIXME
+            allow_internal_unstable: attr::contains_name(&def.attrs, "allow_internal_unstable"),
+            attrs: def.attrs,
+            body: body,
+        }
+    }
+
     fn maybe_get_item_ast<'a>(&'tcx self,
                               tcx: TyCtxt<'a, 'tcx, 'tcx>,
                               def_id: DefId)
diff --git a/src/librustc_metadata/decoder.rs b/src/librustc_metadata/decoder.rs
index 8eae4658983..64a90d56d55 100644
--- a/src/librustc_metadata/decoder.rs
+++ b/src/librustc_metadata/decoder.rs
@@ -468,6 +468,7 @@ impl<'tcx> EntryKind<'tcx> {
             EntryKind::Variant(_) => Def::Variant(did),
             EntryKind::Trait(_) => Def::Trait(did),
             EntryKind::Enum => Def::Enum(did),
+            EntryKind::MacroDef(_) => Def::Macro(did),
 
             EntryKind::ForeignMod |
             EntryKind::Impl(_) |
@@ -1004,6 +1005,14 @@ impl<'a, 'tcx> CrateMetadata {
         self.root.reachable_ids.decode(self).map(|index| self.local_def_id(index)).collect()
     }
 
+    pub fn get_macro(&self, id: DefIndex) -> (ast::Name, MacroDef) {
+        let entry = self.entry(id);
+        match entry.kind {
+            EntryKind::MacroDef(macro_def) => (self.item_name(&entry), macro_def.decode(self)),
+            _ => bug!(),
+        }
+    }
+
     pub fn is_const_fn(&self, id: DefIndex) -> bool {
         let constness = match self.entry(id).kind {
             EntryKind::Method(data) => data.decode(self).fn_data.constness,
diff --git a/src/librustc_metadata/encoder.rs b/src/librustc_metadata/encoder.rs
index 931ddb3cf8d..ac1f2afcb2a 100644
--- a/src/librustc_metadata/encoder.rs
+++ b/src/librustc_metadata/encoder.rs
@@ -830,6 +830,34 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
             },
         }
     }
+
+    /// Serialize the text of exported macros
+    fn encode_info_for_macro_def(&mut self, macro_def: &hir::MacroDef) -> Entry<'tcx> {
+        let def_id = self.tcx.map.local_def_id(macro_def.id);
+        let macro_def = MacroDef {
+            name: macro_def.name,
+            attrs: macro_def.attrs.to_vec(),
+            span: macro_def.span,
+            body: ::syntax::print::pprust::tts_to_string(&macro_def.body)
+        };
+        Entry {
+            kind: EntryKind::MacroDef(self.lazy(&macro_def)),
+            visibility: ty::Visibility::Public,
+            def_key: self.encode_def_key(def_id),
+
+            attributes: LazySeq::empty(),
+            children: LazySeq::empty(),
+            stability: None,
+            deprecation: None,
+            ty: None,
+            inherent_impls: LazySeq::empty(),
+            variances: LazySeq::empty(),
+            generics: None,
+            predicates: None,
+            ast: None,
+            mir: None,
+        }
+    }
 }
 
 impl<'a, 'b, 'tcx> IndexBuilder<'a, 'b, 'tcx> {
@@ -964,6 +992,10 @@ impl<'a, 'b, 'tcx> Visitor<'tcx> for EncodeVisitor<'a, 'b, 'tcx> {
         intravisit::walk_ty(self, ty);
         self.index.encode_info_for_ty(ty);
     }
+    fn visit_macro_def(&mut self, macro_def: &'tcx hir::MacroDef) {
+        let def_id = self.index.tcx.map.local_def_id(macro_def.id);
+        self.index.record(def_id, EncodeContext::encode_info_for_macro_def, macro_def);
+    }
 }
 
 impl<'a, 'b, 'tcx> IndexBuilder<'a, 'b, 'tcx> {
@@ -1043,6 +1075,9 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
                      FromId(CRATE_NODE_ID, (&krate.module, &krate.attrs, &hir::Public)));
         let mut visitor = EncodeVisitor { index: index };
         krate.visit_all_items(&mut visitor);
+        for macro_def in &krate.exported_macros {
+            visitor.visit_macro_def(macro_def);
+        }
         visitor.index.into_items()
     }
 
@@ -1122,19 +1157,6 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
             })
             .map(|filemap| &**filemap))
     }
-
-    /// Serialize the text of the exported macros
-    fn encode_macro_defs(&mut self) -> LazySeq<MacroDef> {
-        let tcx = self.tcx;
-        self.lazy_seq(tcx.map.krate().exported_macros.iter().map(|def| {
-            MacroDef {
-                name: def.name,
-                attrs: def.attrs.to_vec(),
-                span: def.span,
-                body: ::syntax::print::pprust::tts_to_string(&def.body),
-            }
-        }))
-    }
 }
 
 struct ImplVisitor<'a, 'tcx: 'a> {
@@ -1228,11 +1250,6 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
         let codemap = self.encode_codemap();
         let codemap_bytes = self.position() - i;
 
-        // Encode macro definitions
-        i = self.position();
-        let macro_defs = self.encode_macro_defs();
-        let macro_defs_bytes = self.position() - i;
-
         // Encode the def IDs of impls, for coherence checking.
         i = self.position();
         let impls = self.encode_impls();
@@ -1279,7 +1296,6 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
             lang_items_missing: lang_items_missing,
             native_libraries: native_libraries,
             codemap: codemap,
-            macro_defs: macro_defs,
             impls: impls,
             reachable_ids: reachable_ids,
             index: index,
@@ -1300,7 +1316,6 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
             println!("       lang item bytes: {}", lang_item_bytes);
             println!("          native bytes: {}", native_lib_bytes);
             println!("         codemap bytes: {}", codemap_bytes);
-            println!("       macro def bytes: {}", macro_defs_bytes);
             println!("            impl bytes: {}", impl_bytes);
             println!("       reachable bytes: {}", reachable_bytes);
             println!("            item bytes: {}", item_bytes);
diff --git a/src/librustc_metadata/index_builder.rs b/src/librustc_metadata/index_builder.rs
index 9938e20d186..1a74a925454 100644
--- a/src/librustc_metadata/index_builder.rs
+++ b/src/librustc_metadata/index_builder.rs
@@ -195,6 +195,7 @@ read_hir!(hir::Item);
 read_hir!(hir::ImplItem);
 read_hir!(hir::TraitItem);
 read_hir!(hir::ForeignItem);
+read_hir!(hir::MacroDef);
 
 /// Leaks access to a value of type T without any tracking. This is
 /// suitable for ambiguous types like `usize`, which *could* represent
diff --git a/src/librustc_metadata/schema.rs b/src/librustc_metadata/schema.rs
index 5b1774a1984..d7a5f7ad715 100644
--- a/src/librustc_metadata/schema.rs
+++ b/src/librustc_metadata/schema.rs
@@ -177,7 +177,6 @@ pub struct CrateRoot {
     pub lang_items_missing: LazySeq<lang_items::LangItem>,
     pub native_libraries: LazySeq<(NativeLibraryKind, String)>,
     pub codemap: LazySeq<syntax_pos::FileMap>,
-    pub macro_defs: LazySeq<MacroDef>,
     pub impls: LazySeq<TraitImpls>,
     pub reachable_ids: LazySeq<DefIndex>,
     pub index: LazySeq<index::Index>,
@@ -241,6 +240,7 @@ pub enum EntryKind<'tcx> {
     Fn(Lazy<FnData>),
     ForeignFn(Lazy<FnData>),
     Mod(Lazy<ModData>),
+    MacroDef(Lazy<MacroDef>),
     Closure(Lazy<ClosureData<'tcx>>),
     Trait(Lazy<TraitData<'tcx>>),
     Impl(Lazy<ImplData<'tcx>>),
diff --git a/src/librustc_resolve/build_reduced_graph.rs b/src/librustc_resolve/build_reduced_graph.rs
index 5fb9809104f..0833f85c1f6 100644
--- a/src/librustc_resolve/build_reduced_graph.rs
+++ b/src/librustc_resolve/build_reduced_graph.rs
@@ -16,17 +16,15 @@
 use macros::{InvocationData, LegacyScope};
 use resolve_imports::ImportDirective;
 use resolve_imports::ImportDirectiveSubclass::{self, GlobImport};
-use {Module, ModuleS, ModuleKind};
+use {Resolver, Module, ModuleS, ModuleKind, NameBinding, NameBindingKind, ToNameBinding};
 use Namespace::{self, TypeNS, ValueNS, MacroNS};
-use {NameBinding, NameBindingKind, ToNameBinding};
-use Resolver;
+use ResolveResult::Success;
 use {resolve_error, resolve_struct_error, ResolutionError};
 
-use rustc::middle::cstore::{DepKind, LoadedMacros};
+use rustc::middle::cstore::DepKind;
 use rustc::hir::def::*;
-use rustc::hir::def_id::{CrateNum, CRATE_DEF_INDEX, DefId};
+use rustc::hir::def_id::{CrateNum, CRATE_DEF_INDEX, DefId, DefIndex, BUILTIN_MACROS_CRATE};
 use rustc::ty;
-use rustc::util::nodemap::FxHashMap;
 
 use std::cell::Cell;
 use std::rc::Rc;
@@ -38,10 +36,9 @@ use syntax::parse::token;
 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::{SyntaxExtension, Resolver as SyntaxResolver};
+use syntax::ext::base::SyntaxExtension;
 use syntax::ext::expand::mark_tts;
 use syntax::ext::hygiene::Mark;
-use syntax::feature_gate::{self, emit_feature_err};
 use syntax::ext::tt::macro_rules;
 use syntax::parse::token::keywords;
 use syntax::visit::{self, Visitor};
@@ -227,7 +224,7 @@ impl<'b> Resolver<'b> {
                 }
 
                 let load_macros = legacy_imports != LegacyMacroImports::default();
-                let loaded_macros =
+                let proc_macros =
                     self.crate_loader.process_item(item, &self.definitions, load_macros);
 
                 // n.b. we don't need to look at the path option here, because cstore already did
@@ -250,19 +247,25 @@ impl<'b> Resolver<'b> {
                     self.populate_module_if_necessary(module);
                     module
                 } else {
-                    // Define an empty module
-                    let def = Def::Mod(self.definitions.local_def_id(item.id));
-                    let module = ModuleS::new(Some(parent), ModuleKind::Def(def, name));
-                    let module = self.arenas.alloc_module(module);
+                    // Define a module and populate it with proc macros.
+                    let module_kind =
+                        ModuleKind::Def(Def::Mod(self.definitions.local_def_id(item.id)), name);
+                    let module = self.arenas.alloc_module(ModuleS::new(None, module_kind));
                     self.define(parent, name, TypeNS, (module, sp, vis));
+                    for (name, ext) in proc_macros {
+                        let def_id = DefId {
+                            krate: BUILTIN_MACROS_CRATE,
+                            index: DefIndex::new(self.macro_map.len()),
+                        };
+                        self.macro_map.insert(def_id, Rc::new(ext));
+                        let vis = ty::Visibility::Public;
+                        self.define(module, name, MacroNS, (Def::Macro(def_id), DUMMY_SP, vis));
+                    }
                     module
                 };
 
-                if let Some(loaded_macros) = loaded_macros {
-                    self.import_extern_crate_macros(
-                        item, module, loaded_macros, legacy_imports, expansion == Mark::root(),
-                    );
-                }
+                let allow_shadowing = expansion == Mark::root();
+                self.process_legacy_macro_imports(module, legacy_imports, allow_shadowing);
             }
 
             ItemKind::Mod(..) if item.ident == keywords::Invalid.ident() => {} // Crate root
@@ -512,6 +515,31 @@ impl<'b> Resolver<'b> {
         })
     }
 
+    pub fn get_macro(&mut self, def: Def) -> Rc<SyntaxExtension> {
+        let def_id = match def {
+            Def::Macro(def_id) => def_id,
+            _ => panic!("Expected Def::Macro(..)"),
+        };
+        if let Some(ext) = self.macro_map.get(&def_id) {
+            return ext.clone();
+        }
+
+        let mut macro_rules = self.session.cstore.load_macro(def_id, &self.session);
+        let mark = Mark::fresh();
+        let invocation = self.arenas.alloc_invocation_data(InvocationData {
+            module: Cell::new(self.get_extern_crate_root(def_id.krate)),
+            def_index: CRATE_DEF_INDEX,
+            const_integer: false,
+            legacy_scope: Cell::new(LegacyScope::Empty),
+            expansion: Cell::new(LegacyScope::Empty),
+        });
+        self.invocations.insert(mark, invocation);
+        macro_rules.body = mark_tts(&macro_rules.body, mark);
+        let ext = Rc::new(macro_rules::compile(&self.session.parse_sess, &macro_rules));
+        self.macro_map.insert(def_id, ext.clone());
+        ext
+    }
+
     /// Ensures that the reduced graph rooted at the given external module
     /// is built, building it if it is not.
     pub fn populate_module_if_necessary(&mut self, module: Module<'b>) {
@@ -522,90 +550,46 @@ impl<'b> Resolver<'b> {
         module.populated.set(true)
     }
 
-    fn import_extern_crate_macros(&mut self,
-                                  extern_crate: &Item,
-                                  module: Module<'b>,
-                                  loaded_macros: LoadedMacros,
-                                  legacy_imports: LegacyMacroImports,
-                                  allow_shadowing: bool) {
-        let import_macro = |this: &mut Self, name, ext: Rc<_>, span| {
-            this.used_crates.insert(module.def_id().unwrap().krate);
-            if let SyntaxExtension::NormalTT(..) = *ext {
-                this.macro_names.insert(name);
-            }
-            if this.builtin_macros.insert(name, ext).is_some() && !allow_shadowing {
-                let msg = format!("`{}` is already in scope", name);
-                let note =
-                    "macro-expanded `#[macro_use]`s may not shadow existing macros (see RFC 1560)";
-                this.session.struct_span_err(span, &msg).note(note).emit();
-            }
-        };
-
-        match loaded_macros {
-            LoadedMacros::MacroRules(macros) => {
-                let mark = Mark::fresh();
-                if !macros.is_empty() {
-                    let invocation = self.arenas.alloc_invocation_data(InvocationData {
-                        module: Cell::new(module),
-                        def_index: CRATE_DEF_INDEX,
-                        const_integer: false,
-                        legacy_scope: Cell::new(LegacyScope::Empty),
-                        expansion: Cell::new(LegacyScope::Empty),
-                    });
-                    self.invocations.insert(mark, invocation);
-                }
-
-                let mut macros: FxHashMap<_, _> = macros.into_iter().map(|mut def| {
-                    def.body = mark_tts(&def.body, mark);
-                    let ext = macro_rules::compile(&self.session.parse_sess, &def);
-                    (def.ident.name, (def, Rc::new(ext)))
-                }).collect();
+    fn legacy_import_macro(&mut self, name: Name, def: Def, span: Span, allow_shadowing: bool) {
+        self.used_crates.insert(def.def_id().krate);
+        self.macro_names.insert(name);
+        if self.builtin_macros.insert(name, def.def_id()).is_some() && !allow_shadowing {
+            let msg = format!("`{}` is already in scope", name);
+            let note =
+                "macro-expanded `#[macro_use]`s may not shadow existing macros (see RFC 1560)";
+            self.session.struct_span_err(span, &msg).note(note).emit();
+        }
+    }
 
-                if let Some(span) = legacy_imports.import_all {
-                    for (&name, &(_, ref ext)) in macros.iter() {
-                        import_macro(self, name, ext.clone(), span);
-                    }
+    fn process_legacy_macro_imports(&mut self,
+                                    module: Module<'b>,
+                                    legacy_imports: LegacyMacroImports,
+                                    allow_shadowing: bool) {
+        if let Some(span) = legacy_imports.import_all {
+            module.for_each_child(|name, ns, binding| if ns == MacroNS {
+                self.legacy_import_macro(name, binding.def(), span, allow_shadowing);
+            });
+        } else {
+            for (name, span) in legacy_imports.imports {
+                let result = self.resolve_name_in_module(module, name, MacroNS, false, None);
+                if let Success(binding) = result {
+                    self.legacy_import_macro(name, binding.def(), span, allow_shadowing);
                 } else {
-                    for (name, span) in legacy_imports.imports {
-                        if let Some(&(_, ref ext)) = macros.get(&name) {
-                            import_macro(self, name, ext.clone(), span);
-                        } else {
-                            span_err!(self.session, span, E0469, "imported macro not found");
-                        }
-                    }
-                }
-                for (name, span) in legacy_imports.reexports {
-                    if let Some((mut def, _)) = macros.remove(&name) {
-                        def.id = self.next_node_id();
-                        self.exported_macros.push(def);
-                    } else {
-                        span_err!(self.session, span, E0470, "reexported macro not found");
-                    }
+                    span_err!(self.session, span, E0469, "imported macro not found");
                 }
             }
-
-            LoadedMacros::ProcMacros(macros) => {
-                if !self.session.features.borrow().proc_macro {
-                    let sess = &self.session.parse_sess;
-                    let issue = feature_gate::GateIssue::Language;
-                    let msg =
-                        "loading custom derive macro crates is experimentally supported";
-                    emit_feature_err(sess, "proc_macro", extern_crate.span, issue, msg);
-                }
-                if !legacy_imports.imports.is_empty() {
-                    let msg = "`proc-macro` crates cannot be selectively imported from, \
-                               must use `#[macro_use]`";
-                    self.session.span_err(extern_crate.span, msg);
-                }
-                if !legacy_imports.reexports.is_empty() {
-                    let msg = "`proc-macro` crates cannot be reexported from";
-                    self.session.span_err(extern_crate.span, msg);
-                }
-                if let Some(span) = legacy_imports.import_all {
-                    for (name, ext) in macros {
-                        import_macro(self, name, Rc::new(ext), span);
-                    }
+        }
+        for (name, span) in legacy_imports.reexports {
+            self.used_crates.insert(module.def_id().unwrap().krate);
+            let result = self.resolve_name_in_module(module, name, MacroNS, false, None);
+            if let Success(binding) = result {
+                let def = binding.def();
+                if let Def::Macro(DefId { krate: BUILTIN_MACROS_CRATE, .. }) = def {
+                    self.session.span_err(span, "`proc-macro` crates cannot be reexported from");
                 }
+                self.macro_exports.push(Export { name: name, def: def });
+            } else {
+                span_err!(self.session, span, E0470, "reexported macro not found");
             }
         }
     }
diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs
index 31711c0526d..fe90cd34687 100644
--- a/src/librustc_resolve/lib.rs
+++ b/src/librustc_resolve/lib.rs
@@ -1111,8 +1111,10 @@ pub struct Resolver<'a> {
     pub exported_macros: Vec<ast::MacroDef>,
     crate_loader: &'a mut CrateLoader,
     macro_names: FxHashSet<Name>,
-    builtin_macros: FxHashMap<Name, Rc<SyntaxExtension>>,
+    builtin_macros: FxHashMap<Name, DefId>,
     lexical_macro_resolutions: Vec<(Name, LegacyScope<'a>)>,
+    macro_map: FxHashMap<DefId, Rc<SyntaxExtension>>,
+    macro_exports: Vec<Export>,
 
     // Maps the `Mark` of an expansion to its containing module or block.
     invocations: FxHashMap<Mark, &'a InvocationData<'a>>,
@@ -1305,6 +1307,8 @@ impl<'a> Resolver<'a> {
             macro_names: FxHashSet(),
             builtin_macros: FxHashMap(),
             lexical_macro_resolutions: Vec::new(),
+            macro_map: FxHashMap(),
+            macro_exports: Vec::new(),
             invocations: invocations,
         }
     }
@@ -1323,13 +1327,6 @@ 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 e3078a42f65..f9d91e3aa63 100644
--- a/src/librustc_resolve/macros.rs
+++ b/src/librustc_resolve/macros.rs
@@ -10,7 +10,8 @@
 
 use {Module, Resolver};
 use build_reduced_graph::BuildReducedGraphVisitor;
-use rustc::hir::def_id::{CRATE_DEF_INDEX, DefIndex};
+use rustc::hir::def_id::{DefId, BUILTIN_MACROS_CRATE, CRATE_DEF_INDEX, DefIndex};
+use rustc::hir::def::{Def, Export};
 use rustc::hir::map::{self, DefCollector};
 use std::cell::Cell;
 use std::rc::Rc;
@@ -23,6 +24,7 @@ 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::visit::Visitor;
 use syntax_pos::Span;
 
 #[derive(Clone)]
@@ -128,6 +130,13 @@ impl<'a> base::Resolver for Resolver<'a> {
 
         if export {
             def.id = self.next_node_id();
+            DefCollector::new(&mut self.definitions).with_parent(CRATE_DEF_INDEX, |collector| {
+                collector.visit_macro_def(&def)
+            });
+            self.macro_exports.push(Export {
+                name: def.ident.name,
+                def: Def::Macro(self.definitions.local_def_id(def.id)),
+            });
             self.exported_macros.push(def);
         }
     }
@@ -136,7 +145,12 @@ impl<'a> base::Resolver for Resolver<'a> {
         if let NormalTT(..) = *ext {
             self.macro_names.insert(ident.name);
         }
-        self.builtin_macros.insert(ident.name, ext);
+        let def_id = DefId {
+            krate: BUILTIN_MACROS_CRATE,
+            index: DefIndex::new(self.macro_map.len()),
+        };
+        self.macro_map.insert(def_id, ext);
+        self.builtin_macros.insert(ident.name, def_id);
     }
 
     fn add_expansions_at_stmt(&mut self, id: ast::NodeId, macros: Vec<Mark>) {
@@ -147,7 +161,7 @@ impl<'a> base::Resolver for Resolver<'a> {
         for i in 0..attrs.len() {
             let name = intern(&attrs[i].name());
             match self.builtin_macros.get(&name) {
-                Some(ext) => match **ext {
+                Some(&def_id) => match *self.get_macro(Def::Macro(def_id)) {
                     MultiModifier(..) | MultiDecorator(..) | SyntaxExtension::AttrProcMacro(..) => {
                         return Some(attrs.remove(i))
                     }
@@ -226,7 +240,7 @@ impl<'a> Resolver<'a> {
         if let Some(scope) = possible_time_travel {
             self.lexical_macro_resolutions.push((name, scope));
         }
-        self.builtin_macros.get(&name).cloned()
+        self.builtin_macros.get(&name).cloned().map(|def_id| self.get_macro(Def::Macro(def_id)))
     }
 
     fn suggest_macro_name(&mut self, name: &str, err: &mut DiagnosticBuilder<'a>) {
diff --git a/src/librustc_resolve/resolve_imports.rs b/src/librustc_resolve/resolve_imports.rs
index 91a7dc4249a..5d66caec31b 100644
--- a/src/librustc_resolve/resolve_imports.rs
+++ b/src/librustc_resolve/resolve_imports.rs
@@ -30,6 +30,7 @@ use syntax::util::lev_distance::find_best_match_for_name;
 use syntax_pos::Span;
 
 use std::cell::{Cell, RefCell};
+use std::mem;
 
 impl<'a> Resolver<'a> {
     pub fn resolve_imports(&mut self) {
@@ -772,6 +773,10 @@ impl<'a, 'b:'a> ImportResolver<'a, 'b> {
         *module.globs.borrow_mut() = Vec::new();
 
         let mut reexports = Vec::new();
+        if module as *const _ == self.graph_root as *const _ {
+            reexports = mem::replace(&mut self.macro_exports, Vec::new());
+        }
+
         for (&(name, ns), resolution) in module.resolutions.borrow().iter() {
             let resolution = resolution.borrow();
             let binding = match resolution.binding {