From 8021ede6011a3fc4f74079b8f8f45df252e6f53a Mon Sep 17 00:00:00 2001
From: Jeffrey Seyfried <jeffrey.seyfried@gmail.com>
Date: Wed, 26 Oct 2016 05:45:19 +0000
Subject: [PATCH 01/11] nit: clean up some redundant code.

---
 src/librustc_resolve/build_reduced_graph.rs | 14 +++++---------
 1 file changed, 5 insertions(+), 9 deletions(-)

diff --git a/src/librustc_resolve/build_reduced_graph.rs b/src/librustc_resolve/build_reduced_graph.rs
index cb8dd7250b496..475d454e220ea 100644
--- a/src/librustc_resolve/build_reduced_graph.rs
+++ b/src/librustc_resolve/build_reduced_graph.rs
@@ -221,17 +221,13 @@ impl<'b> Resolver<'b> {
                     legacy_imports.import_all.is_some() || !legacy_imports.imports.is_empty() ||
                     !legacy_imports.reexports.is_empty()
                 } {
-                    if self.current_module.parent.is_some() {
-                        span_err!(self.session, item.span, E0468,
-                                  "an `extern crate` loading macros must be at the crate root");
-                    }
+                    span_err!(self.session, item.span, E0468,
+                              "an `extern crate` loading macros must be at the crate root");
                 }
 
-                let loaded_macros = if legacy_imports != LegacyMacroImports::default() {
-                    self.crate_loader.process_item(item, &self.definitions, true)
-                } else {
-                    self.crate_loader.process_item(item, &self.definitions, false)
-                };
+                let load_macros = legacy_imports != LegacyMacroImports::default();
+                let loaded_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
                 let crate_id = self.session.cstore.extern_mod_stmt_cnum(item.id);

From b0e13dc5ba7a8f91ba564c84c62032735bbdc918 Mon Sep 17 00:00:00 2001
From: Jeffrey Seyfried <jeffrey.seyfried@gmail.com>
Date: Fri, 28 Oct 2016 03:40:58 +0000
Subject: [PATCH 02/11] Treat `extern crate`s more like imports (pure
 refactoring).

---
 src/librustc_resolve/build_reduced_graph.rs | 16 ++++++-
 src/librustc_resolve/lib.rs                 | 49 +++++++++------------
 src/librustc_resolve/resolve_imports.rs     | 26 ++++++-----
 3 files changed, 52 insertions(+), 39 deletions(-)

diff --git a/src/librustc_resolve/build_reduced_graph.rs b/src/librustc_resolve/build_reduced_graph.rs
index 475d454e220ea..ca6e72dd4f44d 100644
--- a/src/librustc_resolve/build_reduced_graph.rs
+++ b/src/librustc_resolve/build_reduced_graph.rs
@@ -14,6 +14,7 @@
 //! any imports resolved.
 
 use macros::{InvocationData, LegacyScope};
+use resolve_imports::ImportDirective;
 use resolve_imports::ImportDirectiveSubclass::{self, GlobImport};
 use {Module, ModuleS, ModuleKind};
 use Namespace::{self, TypeNS, ValueNS};
@@ -237,11 +238,22 @@ impl<'b> Resolver<'b> {
                         index: CRATE_DEF_INDEX,
                     };
                     let module = self.arenas.alloc_module(ModuleS {
-                        extern_crate_id: Some(item.id),
                         populated: Cell::new(false),
                         ..ModuleS::new(Some(parent), ModuleKind::Def(Def::Mod(def_id), name))
                     });
-                    self.define(parent, name, TypeNS, (module, sp, vis));
+                    let binding = (module, sp, ty::Visibility::Public).to_name_binding();
+                    let binding = self.arenas.alloc_name_binding(binding);
+                    let directive = self.arenas.alloc_import_directive(ImportDirective {
+                        id: item.id,
+                        parent: parent,
+                        imported_module: Cell::new(Some(module)),
+                        subclass: ImportDirectiveSubclass::ExternCrate,
+                        span: item.span,
+                        module_path: Vec::new(),
+                        vis: Cell::new(vis),
+                    });
+                    let imported_binding = self.import(binding, directive);
+                    self.define(parent, name, TypeNS, imported_binding);
                     self.populate_module_if_necessary(module);
                     module
                 } else {
diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs
index 664efc27fbb53..4de272bc3a045 100644
--- a/src/librustc_resolve/lib.rs
+++ b/src/librustc_resolve/lib.rs
@@ -76,7 +76,7 @@ use std::fmt;
 use std::mem::replace;
 use std::rc::Rc;
 
-use resolve_imports::{ImportDirective, NameResolution};
+use resolve_imports::{ImportDirective, ImportDirectiveSubclass, NameResolution};
 use macros::{InvocationData, LegacyBinding, LegacyScope};
 
 // NB: This module needs to be declared first so diagnostics are
@@ -796,10 +796,6 @@ pub struct ModuleS<'a> {
     // The node id of the closest normal module (`mod`) ancestor (including this module).
     normal_ancestor_id: Option<NodeId>,
 
-    // If the module is an extern crate, `def` is root of the external crate and `extern_crate_id`
-    // is the NodeId of the local `extern crate` item (otherwise, `extern_crate_id` is None).
-    extern_crate_id: Option<NodeId>,
-
     resolutions: RefCell<FxHashMap<(Name, Namespace), &'a RefCell<NameResolution<'a>>>>,
 
     no_implicit_prelude: bool,
@@ -824,7 +820,6 @@ impl<'a> ModuleS<'a> {
             parent: parent,
             kind: kind,
             normal_ancestor_id: None,
-            extern_crate_id: None,
             resolutions: RefCell::new(FxHashMap()),
             no_implicit_prelude: false,
             glob_importers: RefCell::new(Vec::new()),
@@ -953,7 +948,14 @@ impl<'a> NameBinding<'a> {
     }
 
     fn is_extern_crate(&self) -> bool {
-        self.module().ok().and_then(|module| module.extern_crate_id).is_some()
+        match self.kind {
+            NameBindingKind::Import {
+                directive: &ImportDirective {
+                    subclass: ImportDirectiveSubclass::ExternCrate, ..
+                }, ..
+            } => true,
+            _ => false,
+        }
     }
 
     fn is_import(&self) -> bool {
@@ -3233,7 +3235,7 @@ impl<'a> Resolver<'a> {
             in_module.for_each_child(|name, ns, name_binding| {
 
                 // avoid imports entirely
-                if name_binding.is_import() { return; }
+                if name_binding.is_import() && !name_binding.is_extern_crate() { return; }
 
                 // collect results based on the filter function
                 if name == lookup_name && ns == namespace {
@@ -3269,21 +3271,11 @@ impl<'a> Resolver<'a> {
                 // collect submodules to explore
                 if let Ok(module) = name_binding.module() {
                     // form the path
-                    let path_segments = match module.kind {
-                        _ if module.parent.is_none() => path_segments.clone(),
-                        ModuleKind::Def(_, name) => {
-                            let mut paths = path_segments.clone();
-                            let ident = Ident::with_empty_ctxt(name);
-                            let params = PathParameters::none();
-                            let segm = PathSegment {
-                                identifier: ident,
-                                parameters: params,
-                            };
-                            paths.push(segm);
-                            paths
-                        }
-                        _ => bug!(),
-                    };
+                    let mut path_segments = path_segments.clone();
+                    path_segments.push(PathSegment {
+                        identifier: Ident::with_empty_ctxt(name),
+                        parameters: PathParameters::none(),
+                    });
 
                     if !in_module_is_extern || name_binding.vis == ty::Visibility::Public {
                         // add the module to the lookup
@@ -3369,7 +3361,10 @@ impl<'a> Resolver<'a> {
             if !reported_spans.insert(span) { continue }
             if binding.is_extern_crate() {
                 // Warn when using an inaccessible extern crate.
-                let node_id = binding.module().unwrap().extern_crate_id.unwrap();
+                let node_id = match binding.kind {
+                    NameBindingKind::Import { directive, .. } => directive.id,
+                    _ => unreachable!(),
+                };
                 let msg = format!("extern crate `{}` is private", name);
                 self.session.add_lint(lint::builtin::INACCESSIBLE_EXTERN_CRATE, node_id, span, msg);
             } else {
@@ -3415,7 +3410,7 @@ impl<'a> Resolver<'a> {
             _ => "enum",
         };
 
-        let (participle, noun) = match old_binding.is_import() || old_binding.is_extern_crate() {
+        let (participle, noun) = match old_binding.is_import() {
             true => ("imported", "import"),
             false => ("defined", "definition"),
         };
@@ -3424,7 +3419,7 @@ impl<'a> Resolver<'a> {
         let msg = {
             let kind = match (ns, old_binding.module()) {
                 (ValueNS, _) => "a value",
-                (TypeNS, Ok(module)) if module.extern_crate_id.is_some() => "an extern crate",
+                (TypeNS, _) if old_binding.is_extern_crate() => "an extern crate",
                 (TypeNS, Ok(module)) if module.is_normal() => "a module",
                 (TypeNS, Ok(module)) if module.is_trait() => "a trait",
                 (TypeNS, _) => "a type",
@@ -3439,7 +3434,7 @@ impl<'a> Resolver<'a> {
                 e.span_label(span, &format!("`{}` was already imported", name));
                 e
             },
-            (true, _) | (_, true) if binding.is_import() || old_binding.is_import() => {
+            (true, _) | (_, true) if binding.is_import() && old_binding.is_import() => {
                 let mut e = struct_span_err!(self.session, span, E0254, "{}", msg);
                 e.span_label(span, &"already imported");
                 e
diff --git a/src/librustc_resolve/resolve_imports.rs b/src/librustc_resolve/resolve_imports.rs
index 2b3945bd0d920..91a7dc4249ac5 100644
--- a/src/librustc_resolve/resolve_imports.rs
+++ b/src/librustc_resolve/resolve_imports.rs
@@ -51,6 +51,7 @@ pub enum ImportDirectiveSubclass<'a> {
         max_vis: Cell<ty::Visibility>, // The visibility of the greatest reexport.
         // n.b. `max_vis` is only used in `finalize_import` to check for reexport errors.
     },
+    ExternCrate,
 }
 
 impl<'a> ImportDirectiveSubclass<'a> {
@@ -68,12 +69,12 @@ impl<'a> ImportDirectiveSubclass<'a> {
 #[derive(Debug,Clone)]
 pub struct ImportDirective<'a> {
     pub id: NodeId,
-    parent: Module<'a>,
-    module_path: Vec<Ident>,
-    imported_module: Cell<Option<Module<'a>>>, // the resolution of `module_path`
-    subclass: ImportDirectiveSubclass<'a>,
-    span: Span,
-    vis: Cell<ty::Visibility>,
+    pub parent: Module<'a>,
+    pub module_path: Vec<Ident>,
+    pub imported_module: Cell<Option<Module<'a>>>, // the resolution of `module_path`
+    pub subclass: ImportDirectiveSubclass<'a>,
+    pub span: Span,
+    pub vis: Cell<ty::Visibility>,
 }
 
 impl<'a> ImportDirective<'a> {
@@ -169,7 +170,8 @@ impl<'a> Resolver<'a> {
         let new_import_semantics = self.new_import_semantics;
         let is_disallowed_private_import = |binding: &NameBinding| {
             !new_import_semantics && !allow_private_imports && // disallowed
-            binding.vis != ty::Visibility::Public && binding.is_import() // non-`pub` import
+            binding.vis != ty::Visibility::Public && binding.is_import() && // non-`pub` import
+            !binding.is_extern_crate() // not an `extern crate`
         };
 
         if let Some(span) = record_used {
@@ -237,7 +239,7 @@ impl<'a> Resolver<'a> {
                 };
                 let name = match directive.subclass {
                     SingleImport { source, .. } => source,
-                    GlobImport { .. } => unreachable!(),
+                    _ => unreachable!(),
                 };
                 match self.resolve_name_in_module(module, name, ns, true, None) {
                     Failed(_) => {}
@@ -280,13 +282,14 @@ impl<'a> Resolver<'a> {
             // which are not relevant to import resolution.
             GlobImport { is_prelude: true, .. } => {}
             GlobImport { .. } => self.current_module.globs.borrow_mut().push(directive),
+            _ => unreachable!(),
         }
     }
 
     // Given a binding and an import directive that resolves to it,
     // return the corresponding binding defined by the import directive.
-    fn import(&mut self, binding: &'a NameBinding<'a>, directive: &'a ImportDirective<'a>)
-              -> NameBinding<'a> {
+    pub fn import(&mut self, binding: &'a NameBinding<'a>, directive: &'a ImportDirective<'a>)
+                  -> NameBinding<'a> {
         let vis = if binding.pseudo_vis().is_at_least(directive.vis.get(), self) ||
                      !directive.is_glob() && binding.is_extern_crate() { // c.f. `PRIVATE_IN_PUBLIC`
             directive.vis.get()
@@ -529,6 +532,7 @@ impl<'a, 'b:'a> ImportResolver<'a, 'b> {
                 self.resolve_glob_import(directive);
                 return Success(());
             }
+            _ => unreachable!(),
         };
 
         let mut indeterminate = false;
@@ -616,6 +620,7 @@ impl<'a, 'b:'a> ImportResolver<'a, 'b> {
                 }
                 return Success(());
             }
+            _ => unreachable!(),
         };
 
         for &(ns, result) in &[(ValueNS, value_result), (TypeNS, type_result)] {
@@ -831,5 +836,6 @@ fn import_directive_subclass_to_string(subclass: &ImportDirectiveSubclass) -> St
     match *subclass {
         SingleImport { source, .. } => source.to_string(),
         GlobImport { .. } => "*".to_string(),
+        ExternCrate => "<extern crate>".to_string(),
     }
 }

From 624a9b73113bdacc6a92d2d2b0704735093fae3c Mon Sep 17 00:00:00 2001
From: Jeffrey Seyfried <jeffrey.seyfried@gmail.com>
Date: Fri, 28 Oct 2016 05:17:06 +0000
Subject: [PATCH 03/11] Avoid building multiple reduced graphs for a crate that
 is referenced by multiple `extern crate` items.

---
 src/librustc_resolve/build_reduced_graph.rs | 22 ++++++++++++---------
 src/librustc_resolve/lib.rs                 |  2 ++
 2 files changed, 15 insertions(+), 9 deletions(-)

diff --git a/src/librustc_resolve/build_reduced_graph.rs b/src/librustc_resolve/build_reduced_graph.rs
index ca6e72dd4f44d..d987930544e2b 100644
--- a/src/librustc_resolve/build_reduced_graph.rs
+++ b/src/librustc_resolve/build_reduced_graph.rs
@@ -24,7 +24,7 @@ use {resolve_error, resolve_struct_error, ResolutionError};
 
 use rustc::middle::cstore::LoadedMacros;
 use rustc::hir::def::*;
-use rustc::hir::def_id::{CRATE_DEF_INDEX, DefId};
+use rustc::hir::def_id::{CrateNum, CRATE_DEF_INDEX, DefId};
 use rustc::ty;
 use rustc::util::nodemap::FxHashMap;
 
@@ -233,14 +233,7 @@ impl<'b> Resolver<'b> {
                 // n.b. we don't need to look at the path option here, because cstore already did
                 let crate_id = self.session.cstore.extern_mod_stmt_cnum(item.id);
                 let module = if let Some(crate_id) = crate_id {
-                    let def_id = DefId {
-                        krate: crate_id,
-                        index: CRATE_DEF_INDEX,
-                    };
-                    let module = self.arenas.alloc_module(ModuleS {
-                        populated: Cell::new(false),
-                        ..ModuleS::new(Some(parent), ModuleKind::Def(Def::Mod(def_id), name))
-                    });
+                    let module = self.get_extern_crate_root(crate_id);
                     let binding = (module, sp, ty::Visibility::Public).to_name_binding();
                     let binding = self.arenas.alloc_name_binding(binding);
                     let directive = self.arenas.alloc_import_directive(ImportDirective {
@@ -504,6 +497,17 @@ impl<'b> Resolver<'b> {
         }
     }
 
+    fn get_extern_crate_root(&mut self, cnum: CrateNum) -> Module<'b> {
+        let def_id = DefId { krate: cnum, index: CRATE_DEF_INDEX };
+        let arenas = self.arenas;
+        *self.extern_crate_roots.entry(cnum).or_insert_with(|| {
+            arenas.alloc_module(ModuleS {
+                populated: Cell::new(false),
+                ..ModuleS::new(None, ModuleKind::Def(Def::Mod(def_id), keywords::Invalid.name()))
+            })
+        })
+    }
+
     /// 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>) {
diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs
index 4de272bc3a045..b16b61b46b83d 100644
--- a/src/librustc_resolve/lib.rs
+++ b/src/librustc_resolve/lib.rs
@@ -1083,6 +1083,7 @@ pub struct Resolver<'a> {
     // There will be an anonymous module created around `g` with the ID of the
     // entry block for `f`.
     module_map: NodeMap<Module<'a>>,
+    extern_crate_roots: FxHashMap<CrateNum, Module<'a>>,
 
     // Whether or not to print error messages. Can be set to true
     // when getting additional info for error message suggestions,
@@ -1276,6 +1277,7 @@ impl<'a> Resolver<'a> {
             export_map: NodeMap(),
             trait_map: NodeMap(),
             module_map: module_map,
+            extern_crate_roots: FxHashMap(),
 
             emit_errors: true,
             make_glob_map: make_glob_map == MakeGlobMap::Yes,

From c102d7fb68b1da42af21d4546ed12de9140f87e1 Mon Sep 17 00:00:00 2001
From: Jeffrey Seyfried <jeffrey.seyfried@gmail.com>
Date: Thu, 27 Oct 2016 05:03:11 +0000
Subject: [PATCH 04/11] Clean up `CrateSource`.

---
 src/librustc/middle/cstore.rs        |  1 -
 src/librustc_metadata/creader.rs     | 49 +++++++++++-----------------
 src/librustc_metadata/cstore.rs      | 43 ++++--------------------
 src/librustc_metadata/cstore_impl.rs |  2 +-
 4 files changed, 27 insertions(+), 68 deletions(-)

diff --git a/src/librustc/middle/cstore.rs b/src/librustc/middle/cstore.rs
index a1f226ab11d80..8f6d4e9e7d7b7 100644
--- a/src/librustc/middle/cstore.rs
+++ b/src/librustc/middle/cstore.rs
@@ -61,7 +61,6 @@ pub struct LinkMeta {
 pub struct CrateSource {
     pub dylib: Option<(PathBuf, PathKind)>,
     pub rlib: Option<(PathBuf, PathKind)>,
-    pub cnum: CrateNum,
 }
 
 #[derive(Copy, Debug, PartialEq, Clone, RustcEncodable, RustcDecodable)]
diff --git a/src/librustc_metadata/creader.rs b/src/librustc_metadata/creader.rs
index 4385f024b4139..bc854cd4581a0 100644
--- a/src/librustc_metadata/creader.rs
+++ b/src/librustc_metadata/creader.rs
@@ -37,7 +37,7 @@ use syntax::parse;
 use syntax::attr;
 use syntax::ext::base::SyntaxExtension;
 use syntax::parse::token::{InternedString, intern};
-use syntax_pos::{self, Span, mk_sp};
+use syntax_pos::{Span, DUMMY_SP, mk_sp};
 use log;
 
 pub struct Library {
@@ -56,16 +56,14 @@ pub struct CrateLoader<'a> {
 
 fn dump_crates(cstore: &CStore) {
     info!("resolved crates:");
-    cstore.iter_crate_data_origins(|_, data, opt_source| {
+    cstore.iter_crate_data(|_, data| {
         info!("  name: {}", data.name());
         info!("  cnum: {}", data.cnum);
         info!("  hash: {}", data.hash());
         info!("  reqd: {}", data.explicitly_linked.get());
-        opt_source.map(|cs| {
-            let CrateSource { dylib, rlib, cnum: _ } = cs;
-            dylib.map(|dl| info!("  dylib: {}", dl.0.display()));
-            rlib.map(|rl|  info!("   rlib: {}", rl.0.display()));
-        });
+        let CrateSource { dylib, rlib } = data.source.clone();
+        dylib.map(|dl| info!("  dylib: {}", dl.0.display()));
+        rlib.map(|rl|  info!("   rlib: {}", rl.0.display()));
     })
 }
 
@@ -261,8 +259,7 @@ impl<'a> CrateLoader<'a> {
                       span: Span,
                       lib: Library,
                       explicitly_linked: bool)
-                      -> (CrateNum, Rc<cstore::CrateMetadata>,
-                          cstore::CrateSource) {
+                      -> (CrateNum, Rc<cstore::CrateMetadata>) {
         info!("register crate `extern crate {} as {}`", name, ident);
         let crate_root = lib.metadata.get_root();
         self.verify_no_symbol_conflicts(span, &crate_root);
@@ -303,17 +300,14 @@ impl<'a> CrateLoader<'a> {
             cnum: cnum,
             codemap_import_info: RefCell::new(vec![]),
             explicitly_linked: Cell::new(explicitly_linked),
+            source: cstore::CrateSource {
+                dylib: dylib,
+                rlib: rlib,
+            },
         });
 
-        let source = cstore::CrateSource {
-            dylib: dylib,
-            rlib: rlib,
-            cnum: cnum,
-        };
-
         self.cstore.set_crate_data(cnum, cmeta.clone());
-        self.cstore.add_used_crate_source(source.clone());
-        (cnum, cmeta, source)
+        (cnum, cmeta)
     }
 
     fn resolve_crate(&mut self,
@@ -324,7 +318,7 @@ impl<'a> CrateLoader<'a> {
                      span: Span,
                      kind: PathKind,
                      explicitly_linked: bool)
-                     -> (CrateNum, Rc<cstore::CrateMetadata>, cstore::CrateSource) {
+                     -> (CrateNum, Rc<cstore::CrateMetadata>) {
         info!("resolving crate `extern crate {} as {}`", name, ident);
         let result = match self.existing_match(name, hash, kind) {
             Some(cnum) => LoadResult::Previous(cnum),
@@ -356,10 +350,8 @@ impl<'a> CrateLoader<'a> {
         match result {
             LoadResult::Previous(cnum) => {
                 let data = self.cstore.get_crate_data(cnum);
-                if explicitly_linked && !data.explicitly_linked.get() {
-                    data.explicitly_linked.set(explicitly_linked);
-                }
-                (cnum, data, self.cstore.used_crate_source(cnum))
+                data.explicitly_linked.set(explicitly_linked || data.explicitly_linked.get());
+                (cnum, data)
             }
             LoadResult::Loaded(library) => {
                 self.register_crate(root, ident, name, span, library,
@@ -508,9 +500,8 @@ impl<'a> CrateLoader<'a> {
 
         let (dylib, metadata) = match library {
             LoadResult::Previous(cnum) => {
-                let dylib = self.cstore.opt_used_crate_source(cnum).unwrap().dylib;
                 let data = self.cstore.get_crate_data(cnum);
-                (dylib, PMDSource::Registered(data))
+                (data.source.dylib.clone(), PMDSource::Registered(data))
             }
             LoadResult::Loaded(library) => {
                 let dylib = library.dylib.clone();
@@ -754,9 +745,8 @@ impl<'a> CrateLoader<'a> {
         };
         info!("panic runtime not found -- loading {}", name);
 
-        let (cnum, data, _) = self.resolve_crate(&None, name, name, None,
-                                                 syntax_pos::DUMMY_SP,
-                                                 PathKind::Crate, false);
+        let (cnum, data) =
+            self.resolve_crate(&None, name, name, None, DUMMY_SP, PathKind::Crate, false);
 
         // Sanity check the loaded crate to ensure it is indeed a panic runtime
         // and the panic strategy is indeed what we thought it was.
@@ -836,9 +826,8 @@ impl<'a> CrateLoader<'a> {
         } else {
             &self.sess.target.target.options.exe_allocation_crate
         };
-        let (cnum, data, _) = self.resolve_crate(&None, name, name, None,
-                                                 syntax_pos::DUMMY_SP,
-                                                 PathKind::Crate, false);
+        let (cnum, data) =
+            self.resolve_crate(&None, name, name, None, DUMMY_SP, PathKind::Crate, false);
 
         // Sanity check the crate we loaded to ensure that it is indeed an
         // allocator.
diff --git a/src/librustc_metadata/cstore.rs b/src/librustc_metadata/cstore.rs
index f452cc23b7330..1580662342553 100644
--- a/src/librustc_metadata/cstore.rs
+++ b/src/librustc_metadata/cstore.rs
@@ -83,6 +83,8 @@ pub struct CrateMetadata {
     /// where this is false is when an allocator crate is injected into the
     /// dependency list, and therefore isn't actually needed to link an rlib.
     pub explicitly_linked: Cell<bool>,
+
+    pub source: CrateSource,
 }
 
 pub struct CachedInlinedItem {
@@ -97,7 +99,6 @@ pub struct CStore {
     metas: RefCell<FxHashMap<CrateNum, Rc<CrateMetadata>>>,
     /// Map from NodeId's of local extern crate statements to crate numbers
     extern_mod_crate_map: RefCell<NodeMap<CrateNum>>,
-    used_crate_sources: RefCell<Vec<CrateSource>>,
     used_libraries: RefCell<Vec<(String, NativeLibraryKind)>>,
     used_link_args: RefCell<Vec<String>>,
     statically_included_foreign_items: RefCell<NodeSet>,
@@ -112,7 +113,6 @@ impl CStore {
             dep_graph: dep_graph.clone(),
             metas: RefCell::new(FxHashMap()),
             extern_mod_crate_map: RefCell::new(FxHashMap()),
-            used_crate_sources: RefCell::new(Vec::new()),
             used_libraries: RefCell::new(Vec::new()),
             used_link_args: RefCell::new(Vec::new()),
             statically_included_foreign_items: RefCell::new(NodeSet()),
@@ -146,38 +146,9 @@ impl CStore {
         }
     }
 
-    /// Like `iter_crate_data`, but passes source paths (if available) as well.
-    pub fn iter_crate_data_origins<I>(&self, mut i: I)
-        where I: FnMut(CrateNum, &CrateMetadata, Option<CrateSource>)
-    {
-        for (&k, v) in self.metas.borrow().iter() {
-            let origin = self.opt_used_crate_source(k);
-            origin.as_ref().map(|cs| {
-                assert!(k == cs.cnum);
-            });
-            i(k, &v, origin);
-        }
-    }
-
-    pub fn add_used_crate_source(&self, src: CrateSource) {
-        let mut used_crate_sources = self.used_crate_sources.borrow_mut();
-        if !used_crate_sources.contains(&src) {
-            used_crate_sources.push(src);
-        }
-    }
-
-    pub fn opt_used_crate_source(&self, cnum: CrateNum) -> Option<CrateSource> {
-        self.used_crate_sources
-            .borrow_mut()
-            .iter()
-            .find(|source| source.cnum == cnum)
-            .cloned()
-    }
-
     pub fn reset(&self) {
         self.metas.borrow_mut().clear();
         self.extern_mod_crate_map.borrow_mut().clear();
-        self.used_crate_sources.borrow_mut().clear();
         self.used_libraries.borrow_mut().clear();
         self.used_link_args.borrow_mut().clear();
         self.statically_included_foreign_items.borrow_mut().clear();
@@ -223,14 +194,14 @@ impl CStore {
         }
         info!("topological ordering: {:?}", ordering);
         ordering.reverse();
-        let mut libs = self.used_crate_sources
+        let mut libs = self.metas
             .borrow()
             .iter()
-            .map(|src| {
-                (src.cnum,
+            .map(|(&cnum, data)| {
+                (cnum,
                  match prefer {
-                     LinkagePreference::RequireDynamic => src.dylib.clone().map(|p| p.0),
-                     LinkagePreference::RequireStatic => src.rlib.clone().map(|p| p.0),
+                     LinkagePreference::RequireDynamic => data.source.dylib.clone().map(|p| p.0),
+                     LinkagePreference::RequireStatic => data.source.rlib.clone().map(|p| p.0),
                  })
             })
             .collect::<Vec<_>>();
diff --git a/src/librustc_metadata/cstore_impl.rs b/src/librustc_metadata/cstore_impl.rs
index 18ce514c9c42d..2fdc35581b800 100644
--- a/src/librustc_metadata/cstore_impl.rs
+++ b/src/librustc_metadata/cstore_impl.rs
@@ -507,7 +507,7 @@ impl<'tcx> CrateStore<'tcx> for cstore::CStore {
 
     fn used_crate_source(&self, cnum: CrateNum) -> CrateSource
     {
-        self.opt_used_crate_source(cnum).unwrap()
+        self.get_crate_data(cnum).source.clone()
     }
 
     fn extern_mod_stmt_cnum(&self, emod_id: ast::NodeId) -> Option<CrateNum>

From a1d45d94b0c4096ffaeccb0398987f5d6e73dfc6 Mon Sep 17 00:00:00 2001
From: Jeffrey Seyfried <jeffrey.seyfried@gmail.com>
Date: Thu, 27 Oct 2016 09:18:45 +0000
Subject: [PATCH 05/11] Refactor `explicitly_linked: bool` -> `dep_kind:
 DepKind`.

---
 src/librustc/middle/cstore.rs            | 14 ++++++++--
 src/librustc/middle/dependency_format.rs |  5 ++--
 src/librustc_metadata/creader.rs         | 33 ++++++++++++------------
 src/librustc_metadata/cstore.rs          |  9 ++-----
 src/librustc_metadata/cstore_impl.rs     | 12 ++++-----
 src/librustc_metadata/encoder.rs         |  2 +-
 src/librustc_metadata/schema.rs          |  4 +--
 7 files changed, 43 insertions(+), 36 deletions(-)

diff --git a/src/librustc/middle/cstore.rs b/src/librustc/middle/cstore.rs
index 8f6d4e9e7d7b7..cb2a4b3f6229e 100644
--- a/src/librustc/middle/cstore.rs
+++ b/src/librustc/middle/cstore.rs
@@ -63,6 +63,16 @@ pub struct CrateSource {
     pub rlib: Option<(PathBuf, PathKind)>,
 }
 
+#[derive(RustcEncodable, RustcDecodable, Copy, Clone, Ord, PartialOrd, Eq, PartialEq, Debug)]
+pub enum DepKind {
+    /// A dependency that is always injected into the dependency list and so
+    /// doesn't need to be linked to an rlib, e.g. the injected allocator.
+    Implicit,
+    /// A dependency that is required by an rlib version of this crate.
+    /// Ordinary `extern crate`s result in `Explicit` dependencies.
+    Explicit,
+}
+
 #[derive(Copy, Debug, PartialEq, Clone, RustcEncodable, RustcDecodable)]
 pub enum LinkagePreference {
     RequireDynamic,
@@ -169,10 +179,10 @@ pub trait CrateStore<'tcx> {
     // crate metadata
     fn dylib_dependency_formats(&self, cnum: CrateNum)
                                     -> Vec<(CrateNum, LinkagePreference)>;
+    fn dep_kind(&self, cnum: CrateNum) -> DepKind;
     fn lang_items(&self, cnum: CrateNum) -> Vec<(DefIndex, usize)>;
     fn missing_lang_items(&self, cnum: CrateNum) -> Vec<lang_items::LangItem>;
     fn is_staged_api(&self, cnum: CrateNum) -> bool;
-    fn is_explicitly_linked(&self, cnum: CrateNum) -> bool;
     fn is_allocator(&self, cnum: CrateNum) -> bool;
     fn is_panic_runtime(&self, cnum: CrateNum) -> bool;
     fn is_compiler_builtins(&self, cnum: CrateNum) -> bool;
@@ -341,7 +351,7 @@ impl<'tcx> CrateStore<'tcx> for DummyCrateStore {
     fn missing_lang_items(&self, cnum: CrateNum) -> Vec<lang_items::LangItem>
         { bug!("missing_lang_items") }
     fn is_staged_api(&self, cnum: CrateNum) -> bool { bug!("is_staged_api") }
-    fn is_explicitly_linked(&self, cnum: CrateNum) -> bool { bug!("is_explicitly_linked") }
+    fn dep_kind(&self, cnum: CrateNum) -> DepKind { bug!("is_explicitly_linked") }
     fn is_allocator(&self, cnum: CrateNum) -> bool { bug!("is_allocator") }
     fn is_panic_runtime(&self, cnum: CrateNum) -> bool { bug!("is_panic_runtime") }
     fn is_compiler_builtins(&self, cnum: CrateNum) -> bool { bug!("is_compiler_builtins") }
diff --git a/src/librustc/middle/dependency_format.rs b/src/librustc/middle/dependency_format.rs
index c658f47ec1be0..2267c42b543a3 100644
--- a/src/librustc/middle/dependency_format.rs
+++ b/src/librustc/middle/dependency_format.rs
@@ -65,6 +65,7 @@ use hir::def_id::CrateNum;
 
 use session;
 use session::config;
+use middle::cstore::DepKind;
 use middle::cstore::LinkagePreference::{self, RequireStatic, RequireDynamic};
 use util::nodemap::FxHashMap;
 use rustc_back::PanicStrategy;
@@ -188,7 +189,7 @@ fn calculate_type(sess: &session::Session,
         let src = sess.cstore.used_crate_source(cnum);
         if src.dylib.is_none() &&
            !formats.contains_key(&cnum) &&
-           sess.cstore.is_explicitly_linked(cnum) {
+           sess.cstore.dep_kind(cnum) == DepKind::Explicit {
             assert!(src.rlib.is_some());
             info!("adding staticlib: {}", sess.cstore.crate_name(cnum));
             add_library(sess, cnum, RequireStatic, &mut formats);
@@ -272,7 +273,7 @@ fn attempt_static(sess: &session::Session) -> Option<DependencyList> {
     // everything in explicitly so long as it's actually required.
     let last_crate = sess.cstore.crates().len();
     let mut ret = (1..last_crate+1).map(|cnum| {
-        if sess.cstore.is_explicitly_linked(CrateNum::new(cnum)) {
+        if sess.cstore.dep_kind(CrateNum::new(cnum)) == DepKind::Explicit {
             Linkage::Static
         } else {
             Linkage::NotLinked
diff --git a/src/librustc_metadata/creader.rs b/src/librustc_metadata/creader.rs
index bc854cd4581a0..08168fd4fd7ec 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::LoadedMacros;
+use rustc::middle::cstore::{DepKind, LoadedMacros};
 use rustc::session::{config, Session};
 use rustc_back::PanicStrategy;
 use rustc::session::search_paths::PathKind;
@@ -29,7 +29,7 @@ use std::cell::{RefCell, Cell};
 use std::ops::Deref;
 use std::path::PathBuf;
 use std::rc::Rc;
-use std::fs;
+use std::{cmp, fs};
 
 use syntax::ast;
 use syntax::abi::Abi;
@@ -60,7 +60,7 @@ fn dump_crates(cstore: &CStore) {
         info!("  name: {}", data.name());
         info!("  cnum: {}", data.cnum);
         info!("  hash: {}", data.hash());
-        info!("  reqd: {}", data.explicitly_linked.get());
+        info!("  reqd: {:?}", data.dep_kind.get());
         let CrateSource { dylib, rlib } = data.source.clone();
         dylib.map(|dl| info!("  dylib: {}", dl.0.display()));
         rlib.map(|rl|  info!("   rlib: {}", rl.0.display()));
@@ -258,7 +258,7 @@ impl<'a> CrateLoader<'a> {
                       name: &str,
                       span: Span,
                       lib: Library,
-                      explicitly_linked: bool)
+                      dep_kind: DepKind)
                       -> (CrateNum, Rc<cstore::CrateMetadata>) {
         info!("register crate `extern crate {} as {}`", name, ident);
         let crate_root = lib.metadata.get_root();
@@ -299,7 +299,7 @@ impl<'a> CrateLoader<'a> {
             cnum_map: RefCell::new(cnum_map),
             cnum: cnum,
             codemap_import_info: RefCell::new(vec![]),
-            explicitly_linked: Cell::new(explicitly_linked),
+            dep_kind: Cell::new(dep_kind),
             source: cstore::CrateSource {
                 dylib: dylib,
                 rlib: rlib,
@@ -317,7 +317,7 @@ impl<'a> CrateLoader<'a> {
                      hash: Option<&Svh>,
                      span: Span,
                      kind: PathKind,
-                     explicitly_linked: bool)
+                     dep_kind: DepKind)
                      -> (CrateNum, Rc<cstore::CrateMetadata>) {
         info!("resolving crate `extern crate {} as {}`", name, ident);
         let result = match self.existing_match(name, hash, kind) {
@@ -350,12 +350,11 @@ impl<'a> CrateLoader<'a> {
         match result {
             LoadResult::Previous(cnum) => {
                 let data = self.cstore.get_crate_data(cnum);
-                data.explicitly_linked.set(explicitly_linked || data.explicitly_linked.get());
+                data.dep_kind.set(cmp::max(data.dep_kind.get(), dep_kind));
                 (cnum, data)
             }
             LoadResult::Loaded(library) => {
-                self.register_crate(root, ident, name, span, library,
-                                    explicitly_linked)
+                self.register_crate(root, ident, name, span, library, dep_kind)
             }
         }
     }
@@ -442,7 +441,7 @@ impl<'a> CrateLoader<'a> {
                                                         Some(&dep.hash),
                                                         span,
                                                         PathKind::Dependency,
-                                                        dep.explicitly_linked);
+                                                        dep.kind);
             (CrateNum::new(crate_num + 1), local_cnum)
         }).collect();
 
@@ -716,7 +715,7 @@ impl<'a> CrateLoader<'a> {
                 // #![panic_runtime] crate.
                 self.inject_dependency_if(cnum, "a panic runtime",
                                           &|data| data.needs_panic_runtime());
-                runtime_found = runtime_found || data.explicitly_linked.get();
+                runtime_found = runtime_found || data.dep_kind.get() == DepKind::Explicit;
             }
         });
 
@@ -745,8 +744,9 @@ impl<'a> CrateLoader<'a> {
         };
         info!("panic runtime not found -- loading {}", name);
 
+        let dep_kind = DepKind::Implicit;
         let (cnum, data) =
-            self.resolve_crate(&None, name, name, None, DUMMY_SP, PathKind::Crate, false);
+            self.resolve_crate(&None, name, name, None, DUMMY_SP, PathKind::Crate, dep_kind);
 
         // Sanity check the loaded crate to ensure it is indeed a panic runtime
         // and the panic strategy is indeed what we thought it was.
@@ -780,7 +780,7 @@ impl<'a> CrateLoader<'a> {
                 self.inject_dependency_if(cnum, "an allocator",
                                           &|data| data.needs_allocator());
                 found_required_allocator = found_required_allocator ||
-                    data.explicitly_linked.get();
+                    data.dep_kind.get() == DepKind::Explicit;
             }
         });
         if !needs_allocator || found_required_allocator { return }
@@ -826,8 +826,9 @@ impl<'a> CrateLoader<'a> {
         } else {
             &self.sess.target.target.options.exe_allocation_crate
         };
+        let dep_kind = DepKind::Implicit;
         let (cnum, data) =
-            self.resolve_crate(&None, name, name, None, DUMMY_SP, PathKind::Crate, false);
+            self.resolve_crate(&None, name, name, None, DUMMY_SP, PathKind::Crate, dep_kind);
 
         // Sanity check the crate we loaded to ensure that it is indeed an
         // allocator.
@@ -993,7 +994,7 @@ impl<'a> middle::cstore::CrateLoader for CrateLoader<'a> {
             if let PMDSource::Owned(lib) = ekrate.metadata {
                 if ekrate.target_only || config::host_triple() == self.sess.opts.target_triple {
                     let ExternCrateInfo { ref ident, ref name, .. } = info;
-                    self.register_crate(&None, ident, name, item.span, lib, true);
+                    self.register_crate(&None, ident, name, item.span, lib, DepKind::Explicit);
                 }
             }
 
@@ -1006,7 +1007,7 @@ impl<'a> middle::cstore::CrateLoader for CrateLoader<'a> {
         };
 
         let (cnum, ..) = self.resolve_crate(
-            &None, &info.ident, &info.name, None, item.span, PathKind::Crate, true,
+            &None, &info.ident, &info.name, None, item.span, PathKind::Crate, DepKind::Explicit,
         );
 
         let def_id = definitions.opt_local_def_id(item.id).unwrap();
diff --git a/src/librustc_metadata/cstore.rs b/src/librustc_metadata/cstore.rs
index 1580662342553..36d55dd95b91e 100644
--- a/src/librustc_metadata/cstore.rs
+++ b/src/librustc_metadata/cstore.rs
@@ -18,7 +18,7 @@ use rustc::dep_graph::DepGraph;
 use rustc::hir::def_id::{CRATE_DEF_INDEX, CrateNum, DefIndex, DefId};
 use rustc::hir::map::DefKey;
 use rustc::hir::svh::Svh;
-use rustc::middle::cstore::ExternCrate;
+use rustc::middle::cstore::{DepKind, ExternCrate};
 use rustc_back::PanicStrategy;
 use rustc_data_structures::indexed_vec::IndexVec;
 use rustc::util::nodemap::{FxHashMap, NodeMap, NodeSet, DefIdMap};
@@ -78,12 +78,7 @@ pub struct CrateMetadata {
     /// compilation support.
     pub key_map: FxHashMap<DefKey, DefIndex>,
 
-    /// Flag if this crate is required by an rlib version of this crate, or in
-    /// other words whether it was explicitly linked to. An example of a crate
-    /// where this is false is when an allocator crate is injected into the
-    /// dependency list, and therefore isn't actually needed to link an rlib.
-    pub explicitly_linked: Cell<bool>,
-
+    pub dep_kind: Cell<DepKind>,
     pub source: CrateSource,
 }
 
diff --git a/src/librustc_metadata/cstore_impl.rs b/src/librustc_metadata/cstore_impl.rs
index 2fdc35581b800..59f65c7f7c7d7 100644
--- a/src/librustc_metadata/cstore_impl.rs
+++ b/src/librustc_metadata/cstore_impl.rs
@@ -13,7 +13,7 @@ use encoder;
 use locator;
 use schema;
 
-use rustc::middle::cstore::{InlinedItem, CrateStore, CrateSource, ExternCrate};
+use rustc::middle::cstore::{InlinedItem, CrateStore, CrateSource, DepKind, ExternCrate};
 use rustc::middle::cstore::{NativeLibraryKind, LinkMeta, LinkagePreference};
 use rustc::hir::def::{self, Def};
 use rustc::middle::lang_items;
@@ -221,6 +221,11 @@ impl<'tcx> CrateStore<'tcx> for cstore::CStore {
         self.get_crate_data(cnum).get_dylib_dependency_formats()
     }
 
+    fn dep_kind(&self, cnum: CrateNum) -> DepKind
+    {
+        self.get_crate_data(cnum).dep_kind.get()
+    }
+
     fn lang_items(&self, cnum: CrateNum) -> Vec<(DefIndex, usize)>
     {
         self.get_crate_data(cnum).get_lang_items()
@@ -237,11 +242,6 @@ impl<'tcx> CrateStore<'tcx> for cstore::CStore {
         self.get_crate_data(cnum).is_staged_api()
     }
 
-    fn is_explicitly_linked(&self, cnum: CrateNum) -> bool
-    {
-        self.get_crate_data(cnum).explicitly_linked.get()
-    }
-
     fn is_allocator(&self, cnum: CrateNum) -> bool
     {
         self.get_crate_data(cnum).is_allocator()
diff --git a/src/librustc_metadata/encoder.rs b/src/librustc_metadata/encoder.rs
index 2379e744c49e1..931ddb3cf8d39 100644
--- a/src/librustc_metadata/encoder.rs
+++ b/src/librustc_metadata/encoder.rs
@@ -1080,7 +1080,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
             CrateDep {
                 name: syntax::parse::token::intern(dep.name()),
                 hash: dep.hash(),
-                explicitly_linked: dep.explicitly_linked.get(),
+                kind: dep.dep_kind.get(),
             }
         }))
     }
diff --git a/src/librustc_metadata/schema.rs b/src/librustc_metadata/schema.rs
index ff2a764571025..5b1774a19846b 100644
--- a/src/librustc_metadata/schema.rs
+++ b/src/librustc_metadata/schema.rs
@@ -14,7 +14,7 @@ use index;
 use rustc::hir;
 use rustc::hir::def::{self, CtorKind};
 use rustc::hir::def_id::{DefIndex, DefId};
-use rustc::middle::cstore::{LinkagePreference, NativeLibraryKind};
+use rustc::middle::cstore::{DepKind, LinkagePreference, NativeLibraryKind};
 use rustc::middle::lang_items;
 use rustc::mir;
 use rustc::ty::{self, Ty};
@@ -187,7 +187,7 @@ pub struct CrateRoot {
 pub struct CrateDep {
     pub name: ast::Name,
     pub hash: hir::svh::Svh,
-    pub explicitly_linked: bool,
+    pub kind: DepKind,
 }
 
 #[derive(RustcEncodable, RustcDecodable)]

From dd0781ea254564cad86e3d594367b1988edf308d Mon Sep 17 00:00:00 2001
From: Jeffrey Seyfried <jeffrey.seyfried@gmail.com>
Date: Fri, 28 Oct 2016 05:56:06 +0000
Subject: [PATCH 06/11] Register and stability check `#[no_link]` crates.

---
 src/librustc/middle/cstore.rs               |  2 +
 src/librustc/middle/dependency_format.rs    |  2 +
 src/librustc_llvm/lib.rs                    |  1 +
 src/librustc_metadata/creader.rs            | 52 ++++++++++-----------
 src/librustc_metadata/cstore.rs             | 13 +++---
 src/librustc_metadata/decoder.rs            |  6 ++-
 src/librustc_resolve/build_reduced_graph.rs |  5 +-
 src/librustc_resolve/lib.rs                 |  2 +-
 src/test/compile-fail/no-link.rs            |  8 ++--
 9 files changed, 50 insertions(+), 41 deletions(-)

diff --git a/src/librustc/middle/cstore.rs b/src/librustc/middle/cstore.rs
index cb2a4b3f6229e..bdef44bf5c18e 100644
--- a/src/librustc/middle/cstore.rs
+++ b/src/librustc/middle/cstore.rs
@@ -65,6 +65,8 @@ pub struct CrateSource {
 
 #[derive(RustcEncodable, RustcDecodable, Copy, Clone, Ord, PartialOrd, Eq, PartialEq, Debug)]
 pub enum DepKind {
+    /// A dependency that is only used for its macros.
+    MacrosOnly,
     /// A dependency that is always injected into the dependency list and so
     /// doesn't need to be linked to an rlib, e.g. the injected allocator.
     Implicit,
diff --git a/src/librustc/middle/dependency_format.rs b/src/librustc/middle/dependency_format.rs
index 2267c42b543a3..92d1ab85c5a05 100644
--- a/src/librustc/middle/dependency_format.rs
+++ b/src/librustc/middle/dependency_format.rs
@@ -124,6 +124,7 @@ fn calculate_type(sess: &session::Session,
                 return v;
             }
             for cnum in sess.cstore.crates() {
+                if sess.cstore.dep_kind(cnum) == DepKind::MacrosOnly { continue }
                 let src = sess.cstore.used_crate_source(cnum);
                 if src.rlib.is_some() { continue }
                 sess.err(&format!("dependency `{}` not found in rlib format",
@@ -156,6 +157,7 @@ fn calculate_type(sess: &session::Session,
     // dependencies, ensuring there are no conflicts. The only valid case for a
     // dependency to be relied upon twice is for both cases to rely on a dylib.
     for cnum in sess.cstore.crates() {
+        if sess.cstore.dep_kind(cnum) == DepKind::MacrosOnly { continue }
         let name = sess.cstore.crate_name(cnum);
         let src = sess.cstore.used_crate_source(cnum);
         if src.dylib.is_some() {
diff --git a/src/librustc_llvm/lib.rs b/src/librustc_llvm/lib.rs
index da09bfa66d28f..07b87072c435e 100644
--- a/src/librustc_llvm/lib.rs
+++ b/src/librustc_llvm/lib.rs
@@ -29,6 +29,7 @@
 #![feature(staged_api)]
 #![feature(linked_from)]
 #![feature(concat_idents)]
+#![cfg_attr(not(stage0), feature(rustc_private))]
 
 extern crate libc;
 #[macro_use]
diff --git a/src/librustc_metadata/creader.rs b/src/librustc_metadata/creader.rs
index 08168fd4fd7ec..9101f95c88214 100644
--- a/src/librustc_metadata/creader.rs
+++ b/src/librustc_metadata/creader.rs
@@ -67,16 +67,12 @@ fn dump_crates(cstore: &CStore) {
     })
 }
 
-fn should_link(i: &ast::Item) -> bool {
-    !attr::contains_name(&i.attrs, "no_link")
-}
-
 #[derive(Debug)]
 struct ExternCrateInfo {
     ident: String,
     name: String,
     id: ast::NodeId,
-    should_link: bool,
+    dep_kind: DepKind,
 }
 
 fn register_native_lib(sess: &Session,
@@ -168,7 +164,11 @@ impl<'a> CrateLoader<'a> {
                     ident: i.ident.to_string(),
                     name: name,
                     id: i.id,
-                    should_link: should_link(i),
+                    dep_kind: if attr::contains_name(&i.attrs, "no_link") {
+                        DepKind::MacrosOnly
+                    } else {
+                        DepKind::Explicit
+                    },
                 })
             }
             _ => None
@@ -283,7 +283,7 @@ impl<'a> CrateLoader<'a> {
 
         let Library { dylib, rlib, metadata } = lib;
 
-        let cnum_map = self.resolve_crate_deps(root, &crate_root, &metadata, cnum, span);
+        let cnum_map = self.resolve_crate_deps(root, &crate_root, &metadata, cnum, span, dep_kind);
 
         if crate_root.macro_derive_registrar.is_some() {
             self.sess.span_err(span, "crates of the `proc-macro` crate type \
@@ -427,7 +427,8 @@ impl<'a> CrateLoader<'a> {
                           crate_root: &CrateRoot,
                           metadata: &MetadataBlob,
                           krate: CrateNum,
-                          span: Span)
+                          span: Span,
+                          dep_kind: DepKind)
                           -> cstore::CrateNumMap {
         debug!("resolving deps of external crate");
         // The map from crate numbers in the crate we're resolving to local crate
@@ -435,13 +436,14 @@ impl<'a> CrateLoader<'a> {
         let deps = crate_root.crate_deps.decode(metadata);
         let map: FxHashMap<_, _> = deps.enumerate().map(|(crate_num, dep)| {
             debug!("resolving dep crate {} hash: `{}`", dep.name, dep.hash);
-            let (local_cnum, ..) = self.resolve_crate(root,
-                                                        &dep.name.as_str(),
-                                                        &dep.name.as_str(),
-                                                        Some(&dep.hash),
-                                                        span,
-                                                        PathKind::Dependency,
-                                                        dep.kind);
+            let dep_name = &dep.name.as_str();
+            let dep_kind = match dep_kind {
+                DepKind::MacrosOnly => DepKind::MacrosOnly,
+                _ => dep.kind,
+            };
+            let (local_cnum, ..) = self.resolve_crate(
+                root, dep_name, dep_name, Some(&dep.hash), span, PathKind::Dependency, dep_kind,
+            );
             (CrateNum::new(crate_num + 1), local_cnum)
         }).collect();
 
@@ -455,8 +457,8 @@ impl<'a> CrateLoader<'a> {
     }
 
     fn read_extension_crate(&mut self, span: Span, info: &ExternCrateInfo) -> ExtensionCrate {
-        info!("read extension crate {} `extern crate {} as {}` linked={}",
-              info.id, info.name, info.ident, info.should_link);
+        info!("read extension crate {} `extern crate {} as {}` dep_kind={:?}",
+              info.id, info.name, info.ident, info.dep_kind);
         let target_triple = &self.sess.opts.target_triple[..];
         let is_cross = target_triple != config::host_triple();
         let mut target_only = false;
@@ -641,7 +643,7 @@ impl<'a> CrateLoader<'a> {
              name: name.to_string(),
              ident: name.to_string(),
              id: ast::DUMMY_NODE_ID,
-             should_link: false,
+             dep_kind: DepKind::MacrosOnly,
         });
 
         if ekrate.target_only {
@@ -984,30 +986,26 @@ impl<'a> middle::cstore::CrateLoader for CrateLoader<'a> {
             let ekrate = self.read_extension_crate(item.span, &info);
             let loaded_macros = self.read_macros(item, &ekrate);
 
-            // If this is a proc-macro crate or `#[no_link]` crate, it is only used at compile time,
-            // so we return here to avoid registering the crate.
-            if loaded_macros.is_proc_macros() || !info.should_link {
+            // If this is a proc-macro crate, return here to avoid registering.
+            if loaded_macros.is_proc_macros() {
                 return Some(loaded_macros);
             }
 
             // Register crate now to avoid double-reading metadata
             if let PMDSource::Owned(lib) = ekrate.metadata {
                 if ekrate.target_only || config::host_triple() == self.sess.opts.target_triple {
-                    let ExternCrateInfo { ref ident, ref name, .. } = info;
-                    self.register_crate(&None, ident, name, item.span, lib, DepKind::Explicit);
+                    let ExternCrateInfo { ref ident, ref name, dep_kind, .. } = info;
+                    self.register_crate(&None, ident, name, item.span, lib, dep_kind);
                 }
             }
 
             Some(loaded_macros)
         } else {
-            if !info.should_link {
-                return None;
-            }
             None
         };
 
         let (cnum, ..) = self.resolve_crate(
-            &None, &info.ident, &info.name, None, item.span, PathKind::Crate, DepKind::Explicit,
+            &None, &info.ident, &info.name, None, item.span, PathKind::Crate, info.dep_kind,
         );
 
         let def_id = definitions.opt_local_def_id(item.id).unwrap();
diff --git a/src/librustc_metadata/cstore.rs b/src/librustc_metadata/cstore.rs
index 36d55dd95b91e..10e86c427a832 100644
--- a/src/librustc_metadata/cstore.rs
+++ b/src/librustc_metadata/cstore.rs
@@ -192,12 +192,13 @@ impl CStore {
         let mut libs = self.metas
             .borrow()
             .iter()
-            .map(|(&cnum, data)| {
-                (cnum,
-                 match prefer {
-                     LinkagePreference::RequireDynamic => data.source.dylib.clone().map(|p| p.0),
-                     LinkagePreference::RequireStatic => data.source.rlib.clone().map(|p| p.0),
-                 })
+            .filter_map(|(&cnum, data)| {
+                if data.dep_kind.get() == DepKind::MacrosOnly { return None; }
+                let path = match prefer {
+                    LinkagePreference::RequireDynamic => data.source.dylib.clone().map(|p| p.0),
+                    LinkagePreference::RequireStatic => data.source.rlib.clone().map(|p| p.0),
+                };
+                Some((cnum, path))
             })
             .collect::<Vec<_>>();
         libs.sort_by(|&(a, _), &(b, _)| {
diff --git a/src/librustc_metadata/decoder.rs b/src/librustc_metadata/decoder.rs
index 7973cd880fe34..1da2641896573 100644
--- a/src/librustc_metadata/decoder.rs
+++ b/src/librustc_metadata/decoder.rs
@@ -21,7 +21,7 @@ use rustc::util::nodemap::FxHashMap;
 use rustc::hir;
 use rustc::hir::intravisit::IdRange;
 
-use rustc::middle::cstore::{InlinedItem, LinkagePreference};
+use rustc::middle::cstore::{DepKind, InlinedItem, LinkagePreference};
 use rustc::hir::def::{self, Def, CtorKind};
 use rustc::hir::def_id::{CrateNum, DefId, DefIndex, LOCAL_CRATE};
 use rustc::middle::lang_items;
@@ -690,6 +690,10 @@ impl<'a, 'tcx> CrateMetadata {
     pub fn each_child_of_item<F>(&self, id: DefIndex, mut callback: F)
         where F: FnMut(def::Export)
     {
+        if self.dep_kind.get() == DepKind::MacrosOnly {
+            return
+        }
+
         // Find the item.
         let item = match self.maybe_entry(id) {
             None => return,
diff --git a/src/librustc_resolve/build_reduced_graph.rs b/src/librustc_resolve/build_reduced_graph.rs
index d987930544e2b..ed87c61ef3b74 100644
--- a/src/librustc_resolve/build_reduced_graph.rs
+++ b/src/librustc_resolve/build_reduced_graph.rs
@@ -22,7 +22,7 @@ use {NameBinding, NameBindingKind, ToNameBinding};
 use Resolver;
 use {resolve_error, resolve_struct_error, ResolutionError};
 
-use rustc::middle::cstore::LoadedMacros;
+use rustc::middle::cstore::{DepKind, LoadedMacros};
 use rustc::hir::def::*;
 use rustc::hir::def_id::{CrateNum, CRATE_DEF_INDEX, DefId};
 use rustc::ty;
@@ -499,8 +499,9 @@ impl<'b> Resolver<'b> {
 
     fn get_extern_crate_root(&mut self, cnum: CrateNum) -> Module<'b> {
         let def_id = DefId { krate: cnum, index: CRATE_DEF_INDEX };
+        let macros_only = self.session.cstore.dep_kind(cnum) == DepKind::MacrosOnly;
         let arenas = self.arenas;
-        *self.extern_crate_roots.entry(cnum).or_insert_with(|| {
+        *self.extern_crate_roots.entry((cnum, macros_only)).or_insert_with(|| {
             arenas.alloc_module(ModuleS {
                 populated: Cell::new(false),
                 ..ModuleS::new(None, ModuleKind::Def(Def::Mod(def_id), keywords::Invalid.name()))
diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs
index b16b61b46b83d..89a0826254c10 100644
--- a/src/librustc_resolve/lib.rs
+++ b/src/librustc_resolve/lib.rs
@@ -1083,7 +1083,7 @@ pub struct Resolver<'a> {
     // There will be an anonymous module created around `g` with the ID of the
     // entry block for `f`.
     module_map: NodeMap<Module<'a>>,
-    extern_crate_roots: FxHashMap<CrateNum, Module<'a>>,
+    extern_crate_roots: FxHashMap<(CrateNum, bool /* MacrosOnly? */), Module<'a>>,
 
     // Whether or not to print error messages. Can be set to true
     // when getting additional info for error message suggestions,
diff --git a/src/test/compile-fail/no-link.rs b/src/test/compile-fail/no-link.rs
index 8f6da99806b3b..5ea07403cf793 100644
--- a/src/test/compile-fail/no-link.rs
+++ b/src/test/compile-fail/no-link.rs
@@ -8,11 +8,11 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
+// aux-build:empty-struct.rs
+
 #[no_link]
-extern crate libc;
+extern crate empty_struct;
 
 fn main() {
-    unsafe {
-        libc::abs(0);  //~ ERROR unresolved name
-    }
+    empty_struct::XEmpty1; //~ ERROR unresolved name
 }

From 85f74c0eea3667e85720d6f427709873eb576b49 Mon Sep 17 00:00:00 2001
From: Jeffrey Seyfried <jeffrey.seyfried@gmail.com>
Date: Tue, 25 Oct 2016 22:05:02 +0000
Subject: [PATCH 07/11] Add variants `Def::Macro` and `Namespace::MacroNS`.

---
 src/librustc/hir/def.rs                       |  6 +++++-
 .../calculate_svh/svh_visitor.rs              |  3 ++-
 src/librustc_metadata/decoder.rs              | 19 ++++++++++++++++---
 src/librustc_resolve/build_reduced_graph.rs   |  5 ++++-
 src/librustc_resolve/lib.rs                   |  8 +++++++-
 src/librustc_save_analysis/dump_visitor.rs    |  1 +
 src/librustc_save_analysis/lib.rs             |  1 +
 7 files changed, 36 insertions(+), 7 deletions(-)

diff --git a/src/librustc/hir/def.rs b/src/librustc/hir/def.rs
index 8b9cee1d2f6d6..044e36e5c9cd4 100644
--- a/src/librustc/hir/def.rs
+++ b/src/librustc/hir/def.rs
@@ -52,6 +52,9 @@ pub enum Def {
           ast::NodeId), // expr node that creates the closure
     Label(ast::NodeId),
 
+    // Macro namespace
+    Macro(DefId),
+
     // Both namespaces
     Err,
 }
@@ -133,7 +136,7 @@ impl Def {
             Def::Variant(id) | Def::VariantCtor(id, ..) | Def::Enum(id) | Def::TyAlias(id) |
             Def::AssociatedTy(id) | Def::TyParam(id) | Def::Struct(id) | Def::StructCtor(id, ..) |
             Def::Union(id) | Def::Trait(id) | Def::Method(id) | Def::Const(id) |
-            Def::AssociatedConst(id) | Def::Local(id) | Def::Upvar(id, ..) => {
+            Def::AssociatedConst(id) | Def::Local(id) | Def::Upvar(id, ..) | Def::Macro(id) => {
                 id
             }
 
@@ -173,6 +176,7 @@ impl Def {
             Def::Upvar(..) => "closure capture",
             Def::Label(..) => "label",
             Def::SelfTy(..) => "self type",
+            Def::Macro(..) => "macro",
             Def::Err => "unresolved item",
         }
     }
diff --git a/src/librustc_incremental/calculate_svh/svh_visitor.rs b/src/librustc_incremental/calculate_svh/svh_visitor.rs
index 2358d60d0de21..0b0dd596784e9 100644
--- a/src/librustc_incremental/calculate_svh/svh_visitor.rs
+++ b/src/librustc_incremental/calculate_svh/svh_visitor.rs
@@ -834,7 +834,8 @@ impl<'a, 'hash, 'tcx> StrictVersionHashVisitor<'a, 'hash, 'tcx> {
             Def::Const(..) |
             Def::AssociatedConst(..) |
             Def::Local(..) |
-            Def::Upvar(..) => {
+            Def::Upvar(..) |
+            Def::Macro(..) => {
                 DefHash::SawDefId.hash(self.st);
                 self.hash_def_id(def.def_id());
             }
diff --git a/src/librustc_metadata/decoder.rs b/src/librustc_metadata/decoder.rs
index 1da2641896573..8eae46589834f 100644
--- a/src/librustc_metadata/decoder.rs
+++ b/src/librustc_metadata/decoder.rs
@@ -690,9 +690,7 @@ impl<'a, 'tcx> CrateMetadata {
     pub fn each_child_of_item<F>(&self, id: DefIndex, mut callback: F)
         where F: FnMut(def::Export)
     {
-        if self.dep_kind.get() == DepKind::MacrosOnly {
-            return
-        }
+        let macros_only = self.dep_kind.get() == DepKind::MacrosOnly;
 
         // Find the item.
         let item = match self.maybe_entry(id) {
@@ -702,9 +700,19 @@ impl<'a, 'tcx> CrateMetadata {
 
         // Iterate over all children.
         for child_index in item.children.decode(self) {
+            if macros_only {
+                continue
+            }
+
             // Get the item.
             if let Some(child) = self.maybe_entry(child_index) {
                 let child = child.decode(self);
+                match child.kind {
+                    EntryKind::MacroDef(..) => {}
+                    _ if macros_only => continue,
+                    _ => {}
+                }
+
                 // Hand off the item to the callback.
                 match child.kind {
                     // FIXME(eddyb) Don't encode these in children.
@@ -763,6 +771,11 @@ impl<'a, 'tcx> CrateMetadata {
 
         if let EntryKind::Mod(data) = item.kind {
             for exp in data.decode(self).reexports.decode(self) {
+                match exp.def {
+                    Def::Macro(..) => {}
+                    _ if macros_only => continue,
+                    _ => {}
+                }
                 callback(exp);
             }
         }
diff --git a/src/librustc_resolve/build_reduced_graph.rs b/src/librustc_resolve/build_reduced_graph.rs
index ed87c61ef3b74..5fb9809104fe0 100644
--- a/src/librustc_resolve/build_reduced_graph.rs
+++ b/src/librustc_resolve/build_reduced_graph.rs
@@ -17,7 +17,7 @@ use macros::{InvocationData, LegacyScope};
 use resolve_imports::ImportDirective;
 use resolve_imports::ImportDirectiveSubclass::{self, GlobImport};
 use {Module, ModuleS, ModuleKind};
-use Namespace::{self, TypeNS, ValueNS};
+use Namespace::{self, TypeNS, ValueNS, MacroNS};
 use {NameBinding, NameBindingKind, ToNameBinding};
 use Resolver;
 use {resolve_error, resolve_struct_error, ResolutionError};
@@ -485,6 +485,9 @@ impl<'b> Resolver<'b> {
                 let field_names = self.session.cstore.struct_field_names(def_id);
                 self.insert_field_names(def_id, field_names);
             }
+            Def::Macro(..) => {
+                self.define(parent, name, MacroNS, (def, DUMMY_SP, vis));
+            }
             Def::Local(..) |
             Def::PrimTy(..) |
             Def::TyParam(..) |
diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs
index 89a0826254c10..31711c0526d74 100644
--- a/src/librustc_resolve/lib.rs
+++ b/src/librustc_resolve/lib.rs
@@ -533,6 +533,7 @@ impl PatternSource {
 pub enum Namespace {
     TypeNS,
     ValueNS,
+    MacroNS,
 }
 
 impl<'a> Visitor for Resolver<'a> {
@@ -1346,7 +1347,11 @@ impl<'a> Resolver<'a> {
     }
 
     fn get_ribs<'b>(&'b mut self, ns: Namespace) -> &'b mut Vec<Rib<'a>> {
-        match ns { ValueNS => &mut self.value_ribs, TypeNS => &mut self.type_ribs }
+        match ns {
+            ValueNS => &mut self.value_ribs,
+            TypeNS => &mut self.type_ribs,
+            MacroNS => panic!("The macro namespace has no ribs"),
+        }
     }
 
     fn record_use(&mut self, name: Name, ns: Namespace, binding: &'a NameBinding<'a>, span: Span)
@@ -3421,6 +3426,7 @@ impl<'a> Resolver<'a> {
         let msg = {
             let kind = match (ns, old_binding.module()) {
                 (ValueNS, _) => "a value",
+                (MacroNS, _) => "a macro",
                 (TypeNS, _) if old_binding.is_extern_crate() => "an extern crate",
                 (TypeNS, Ok(module)) if module.is_normal() => "a module",
                 (TypeNS, Ok(module)) if module.is_trait() => "a trait",
diff --git a/src/librustc_save_analysis/dump_visitor.rs b/src/librustc_save_analysis/dump_visitor.rs
index 36c6a6760137f..e83c2359979c0 100644
--- a/src/librustc_save_analysis/dump_visitor.rs
+++ b/src/librustc_save_analysis/dump_visitor.rs
@@ -341,6 +341,7 @@ impl<'l, 'tcx: 'l, 'll, D: Dump + 'll> DumpVisitor<'l, 'tcx, 'll, D> {
             Def::AssociatedTy(..) |
             Def::AssociatedConst(..) |
             Def::PrimTy(_) |
+            Def::Macro(_) |
             Def::Err => {
                span_bug!(span,
                          "process_def_kind for unexpected item: {:?}",
diff --git a/src/librustc_save_analysis/lib.rs b/src/librustc_save_analysis/lib.rs
index fded34d2c856c..ab5bbea07a301 100644
--- a/src/librustc_save_analysis/lib.rs
+++ b/src/librustc_save_analysis/lib.rs
@@ -565,6 +565,7 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> {
             Def::PrimTy(..) |
             Def::SelfTy(..) |
             Def::Label(..) |
+            Def::Macro(..) |
             Def::Err => None,
         }
     }

From 872943c3172619afa275987c4ad3e2041ede9fa3 Mon Sep 17 00:00:00 2001
From: Jeffrey Seyfried <jeffrey.seyfried@gmail.com>
Date: Fri, 28 Oct 2016 06:52:45 +0000
Subject: [PATCH 08/11] Improve macro reexports.

---
 src/librustc/hir/def_id.rs                  |   4 +
 src/librustc/hir/map/collector.rs           |   4 +
 src/librustc/middle/cstore.rs               |  18 +-
 src/librustc_metadata/creader.rs            | 117 ++++---------
 src/librustc_metadata/cstore_impl.rs        |  41 ++++-
 src/librustc_metadata/decoder.rs            |   9 +
 src/librustc_metadata/encoder.rs            |  55 +++---
 src/librustc_metadata/index_builder.rs      |   1 +
 src/librustc_metadata/schema.rs             |   2 +-
 src/librustc_resolve/build_reduced_graph.rs | 178 +++++++++-----------
 src/librustc_resolve/lib.rs                 |  13 +-
 src/librustc_resolve/macros.rs              |  22 ++-
 src/librustc_resolve/resolve_imports.rs     |   5 +
 13 files changed, 241 insertions(+), 228 deletions(-)

diff --git a/src/librustc/hir/def_id.rs b/src/librustc/hir/def_id.rs
index 399243551d651..d3771b1755b16 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 e23a721da08a6..04fcf7e84508e 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 bdef44bf5c18e..db3c7d0450b38 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 9101f95c88214..e53f1a0633b62 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 59f65c7f7c7d7..3113bfcb5b452 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 8eae46589834f..64a90d56d5561 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 931ddb3cf8d39..ac1f2afcb2adb 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 9938e20d1861d..1a74a92545477 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 5b1774a19846b..d7a5f7ad71544 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 5fb9809104fe0..0833f85c1f6a2 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 31711c0526d74..fe90cd34687c0 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 e3078a42f6538..f9d91e3aa63fd 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 91a7dc4249ac5..5d66caec31b3e 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 {

From a0a9f8ca1bdfa5e71dc4e51661f80097cbe24513 Mon Sep 17 00:00:00 2001
From: Jeffrey Seyfried <jeffrey.seyfried@gmail.com>
Date: Sat, 29 Oct 2016 07:31:07 +0000
Subject: [PATCH 09/11] Fix fallout in `librustdoc`.

---
 src/librustdoc/core.rs      |  6 ++++--
 src/librustdoc/test.rs      |  3 ++-
 src/librustdoc/visit_ast.rs | 27 +++++++++++++++++++++++++--
 3 files changed, 31 insertions(+), 5 deletions(-)

diff --git a/src/librustdoc/core.rs b/src/librustdoc/core.rs
index 810bea4c5b098..a25cb0bacc5cf 100644
--- a/src/librustdoc/core.rs
+++ b/src/librustdoc/core.rs
@@ -14,7 +14,7 @@ use rustc_driver::{driver, target_features, abort_on_err};
 use rustc::dep_graph::DepGraph;
 use rustc::session::{self, config};
 use rustc::hir::def_id::DefId;
-use rustc::hir::def::Def;
+use rustc::hir::def::{Def, ExportMap};
 use rustc::middle::privacy::AccessLevels;
 use rustc::ty::{self, TyCtxt};
 use rustc::hir::map as hir_map;
@@ -74,6 +74,7 @@ pub struct DocContext<'a, 'tcx: 'a> {
     pub ty_substs: RefCell<FxHashMap<Def, clean::Type>>,
     /// Table node id of lifetime parameter definition -> substituted lifetime
     pub lt_substs: RefCell<FxHashMap<ast::NodeId, clean::Lifetime>>,
+    pub export_map: ExportMap,
 }
 
 impl<'b, 'tcx> DocContext<'b, 'tcx> {
@@ -196,7 +197,7 @@ pub fn run_core(search_paths: SearchPaths,
             sess.fatal("Compilation failed, aborting rustdoc");
         }
 
-        let ty::CrateAnalysis { access_levels, .. } = analysis;
+        let ty::CrateAnalysis { access_levels, export_map, .. } = analysis;
 
         // Convert from a NodeId set to a DefId set since we don't always have easy access
         // to the map from defid -> nodeid
@@ -218,6 +219,7 @@ pub fn run_core(search_paths: SearchPaths,
             renderinfo: Default::default(),
             ty_substs: Default::default(),
             lt_substs: Default::default(),
+            export_map: export_map,
         };
         debug!("crate: {:?}", ctxt.map.krate());
 
diff --git a/src/librustdoc/test.rs b/src/librustdoc/test.rs
index 1bbd67fb9be3a..12d33dcb207f7 100644
--- a/src/librustdoc/test.rs
+++ b/src/librustdoc/test.rs
@@ -87,7 +87,7 @@ pub fn run(input: &str,
         config::build_configuration(&sess, config::parse_cfgspecs(cfgs.clone()));
 
     let krate = panictry!(driver::phase_1_parse_input(&sess, &input));
-    let driver::ExpansionResult { defs, mut hir_forest, .. } = {
+    let driver::ExpansionResult { defs, mut hir_forest, analysis, .. } = {
         phase_2_configure_and_expand(
             &sess, &cstore, krate, None, "rustdoc-test", None, MakeGlobMap::No, |_| Ok(())
         ).expect("phase_2_configure_and_expand aborted in rustdoc!")
@@ -110,6 +110,7 @@ pub fn run(input: &str,
         renderinfo: Default::default(),
         ty_substs: Default::default(),
         lt_substs: Default::default(),
+        export_map: analysis.export_map,
     };
 
     let mut v = RustdocVisitor::new(&ctx);
diff --git a/src/librustdoc/visit_ast.rs b/src/librustdoc/visit_ast.rs
index 6e47c037ad3db..b91d71198e819 100644
--- a/src/librustdoc/visit_ast.rs
+++ b/src/librustdoc/visit_ast.rs
@@ -85,8 +85,9 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> {
                                               &krate.module,
                                               None);
         // attach the crate's exported macros to the top-level module:
-        self.module.macros = krate.exported_macros.iter()
-            .map(|def| self.visit_macro(def)).collect();
+        let macro_exports: Vec<_> =
+            krate.exported_macros.iter().map(|def| self.visit_macro(def)).collect();
+        self.module.macros.extend(macro_exports);
         self.module.is_crate = true;
     }
 
@@ -191,6 +192,28 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> {
             let item = self.cx.map.expect_item(i.id);
             self.visit_item(item, None, &mut om);
         }
+        if let Some(exports) = self.cx.export_map.get(&id) {
+            for export in exports {
+                if let Def::Macro(def_id) = export.def {
+                    if def_id.krate == LOCAL_CRATE {
+                        continue // These are `krate.exported_macros`, handled in `self.visit()`.
+                    }
+                    let def = self.cx.sess().cstore.load_macro(def_id, self.cx.sess());
+                    // FIXME(jseyfried) merge with `self.visit_macro()`
+                    let matchers = def.body.chunks(4).map(|arm| arm[0].get_span()).collect();
+                    om.macros.push(Macro {
+                        id: def.id,
+                        attrs: def.attrs.clone().into(),
+                        name: def.ident.name,
+                        whence: def.span,
+                        matchers: matchers,
+                        stab: self.stability(def.id),
+                        depr: self.deprecation(def.id),
+                        imported_from: def.imported_from.map(|ident| ident.name),
+                    })
+                }
+            }
+        }
         om
     }
 

From 0a998b86e977912dfabd4fddb3c7efe87accf2c2 Mon Sep 17 00:00:00 2001
From: Jeffrey Seyfried <jeffrey.seyfried@gmail.com>
Date: Sat, 5 Nov 2016 20:30:40 +0000
Subject: [PATCH 10/11] Support `#[macro_reexport]`ing custom derives.

---
 src/librustc/middle/cstore.rs                 |  13 +-
 src/librustc_metadata/creader.rs              | 136 ++++++++----------
 src/librustc_metadata/cstore.rs               |   3 +
 src/librustc_metadata/cstore_impl.rs          |  15 +-
 src/librustc_metadata/decoder.rs              |  11 +-
 src/librustc_metadata/locator.rs              |   7 +
 src/librustc_resolve/build_reduced_graph.rs   | 121 +++++++---------
 src/librustdoc/visit_ast.rs                   |   8 +-
 src/libsyntax_ext/deriving/mod.rs             |  10 +-
 .../proc-macro/auxiliary/derive-a.rs          |   2 +-
 .../proc-macro/feature-gate-4.rs              |   4 +-
 .../{cannot-link.rs => no-macro-use-attr.rs}  |   7 +-
 .../proc-macro/shadow.rs                      |   2 +-
 src/test/compile-fail/no-link.rs              |   1 +
 14 files changed, 170 insertions(+), 170 deletions(-)
 rename src/test/compile-fail-fulldeps/proc-macro/{cannot-link.rs => no-macro-use-attr.rs} (74%)

diff --git a/src/librustc/middle/cstore.rs b/src/librustc/middle/cstore.rs
index db3c7d0450b38..3583ccdb97bad 100644
--- a/src/librustc/middle/cstore.rs
+++ b/src/librustc/middle/cstore.rs
@@ -34,6 +34,7 @@ use session::Session;
 use session::search_paths::PathKind;
 use util::nodemap::{NodeSet, DefIdMap};
 use std::path::PathBuf;
+use std::rc::Rc;
 use syntax::ast;
 use syntax::attr;
 use syntax::ext::base::SyntaxExtension;
@@ -106,6 +107,11 @@ pub enum InlinedItemRef<'a> {
     ImplItem(DefId, &'a hir::ImplItem)
 }
 
+pub enum LoadedMacro {
+    MacroRules(ast::MacroDef),
+    ProcMacro(Rc<SyntaxExtension>),
+}
+
 #[derive(Copy, Clone, Debug)]
 pub struct ExternCrate {
     /// def_id of an `extern crate` in the current crate that caused
@@ -211,7 +217,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;
+    fn load_macro(&self, did: DefId, sess: &Session) -> LoadedMacro;
 
     // misc. metadata
     fn maybe_get_item_ast<'a>(&'tcx self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId)
@@ -383,7 +389,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") }
+    fn load_macro(&self, did: DefId, sess: &Session) -> LoadedMacro { bug!("load_macro") }
 
     // misc. metadata
     fn maybe_get_item_ast<'a>(&'tcx self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId)
@@ -424,7 +430,6 @@ impl<'tcx> CrateStore<'tcx> for DummyCrateStore {
 }
 
 pub trait CrateLoader {
-    fn process_item(&mut self, item: &ast::Item, defs: &Definitions, load_macros: bool)
-                    -> Vec<(ast::Name, SyntaxExtension)>;
+    fn process_item(&mut self, item: &ast::Item, defs: &Definitions);
     fn postprocess(&mut self, krate: &ast::Crate);
 }
diff --git a/src/librustc_metadata/creader.rs b/src/librustc_metadata/creader.rs
index e53f1a0633b62..75944122f5c10 100644
--- a/src/librustc_metadata/creader.rs
+++ b/src/librustc_metadata/creader.rs
@@ -35,7 +35,6 @@ use syntax::ast;
 use syntax::abi::Abi;
 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};
 use log;
@@ -285,15 +284,13 @@ impl<'a> CrateLoader<'a> {
 
         let cnum_map = self.resolve_crate_deps(root, &crate_root, &metadata, cnum, span, dep_kind);
 
-        if crate_root.macro_derive_registrar.is_some() {
-            self.sess.span_err(span, "crates of the `proc-macro` crate type \
-                                      cannot be linked at runtime");
-        }
-
         let cmeta = Rc::new(cstore::CrateMetadata {
             name: name.to_string(),
             extern_crate: Cell::new(None),
             key_map: metadata.load_key_map(crate_root.index),
+            proc_macros: crate_root.macro_derive_registrar.map(|_| {
+                self.load_derive_macros(&crate_root, dylib.clone().map(|p| p.0), span)
+            }),
             root: crate_root,
             blob: metadata,
             cnum_map: RefCell::new(cnum_map),
@@ -317,34 +314,48 @@ impl<'a> CrateLoader<'a> {
                      hash: Option<&Svh>,
                      span: Span,
                      kind: PathKind,
-                     dep_kind: DepKind)
+                     mut dep_kind: DepKind)
                      -> (CrateNum, Rc<cstore::CrateMetadata>) {
         info!("resolving crate `extern crate {} as {}`", name, ident);
-        let result = match self.existing_match(name, hash, kind) {
-            Some(cnum) => LoadResult::Previous(cnum),
-            None => {
-                info!("falling back to a load");
-                let mut locate_ctxt = locator::Context {
-                    sess: self.sess,
-                    span: span,
-                    ident: ident,
-                    crate_name: name,
-                    hash: hash.map(|a| &*a),
-                    filesearch: self.sess.target_filesearch(kind),
-                    target: &self.sess.target.target,
-                    triple: &self.sess.opts.target_triple,
-                    root: root,
+        let result = if let Some(cnum) = self.existing_match(name, hash, kind) {
+            LoadResult::Previous(cnum)
+        } else {
+            info!("falling back to a load");
+            let mut locate_ctxt = locator::Context {
+                sess: self.sess,
+                span: span,
+                ident: ident,
+                crate_name: name,
+                hash: hash.map(|a| &*a),
+                filesearch: self.sess.target_filesearch(kind),
+                target: &self.sess.target.target,
+                triple: &self.sess.opts.target_triple,
+                root: root,
+                rejected_via_hash: vec![],
+                rejected_via_triple: vec![],
+                rejected_via_kind: vec![],
+                rejected_via_version: vec![],
+                should_match_name: true,
+                is_proc_macro: Some(false),
+            };
+
+            self.load(&mut locate_ctxt).or_else(|| {
+                dep_kind = DepKind::MacrosOnly;
+
+                let mut proc_macro_locator = locator::Context {
+                    target: &self.sess.host,
+                    triple: config::host_triple(),
+                    filesearch: self.sess.host_filesearch(PathKind::Crate),
                     rejected_via_hash: vec![],
                     rejected_via_triple: vec![],
                     rejected_via_kind: vec![],
                     rejected_via_version: vec![],
-                    should_match_name: true,
+                    is_proc_macro: Some(true),
+                    ..locate_ctxt
                 };
-                match self.load(&mut locate_ctxt) {
-                    Some(result) => result,
-                    None => locate_ctxt.report_errs(),
-                }
-            }
+
+                self.load(&mut proc_macro_locator)
+            }).unwrap_or_else(|| locate_ctxt.report_errs())
         };
 
         match result {
@@ -431,6 +442,10 @@ impl<'a> CrateLoader<'a> {
                           dep_kind: DepKind)
                           -> cstore::CrateNumMap {
         debug!("resolving deps of external crate");
+        if crate_root.macro_derive_registrar.is_some() {
+            return cstore::CrateNumMap::new();
+        }
+
         // The map from crate numbers in the crate we're resolving to local crate
         // numbers
         let deps = crate_root.crate_deps.decode(metadata);
@@ -479,6 +494,7 @@ impl<'a> CrateLoader<'a> {
             rejected_via_kind: vec![],
             rejected_via_version: vec![],
             should_match_name: true,
+            is_proc_macro: None,
         };
         let library = self.load(&mut locate_ctxt).or_else(|| {
             if !is_cross {
@@ -525,51 +541,36 @@ 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, ekrate: &ExtensionCrate)
-                          -> Option<Vec<(ast::Name, SyntaxExtension)>> {
+    fn load_derive_macros(&mut self, root: &CrateRoot, dylib: Option<PathBuf>, span: Span)
+                          -> Vec<(ast::Name, Rc<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() {
+        let path = match dylib {
             Some(dylib) => dylib,
-            None => span_bug!(item.span, "proc-macro crate not dylib"),
+            None => span_bug!(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)) {
             Ok(lib) => lib,
-            Err(err) => self.sess.span_fatal(item.span, &err),
+            Err(err) => self.sess.span_fatal(span, &err),
         };
 
-        let sym = self.sess.generate_derive_registrar_symbol(&root.hash, index);
+        let sym = self.sess.generate_derive_registrar_symbol(&root.hash,
+                                                             root.macro_derive_registrar.unwrap());
         let registrar = unsafe {
             let sym = match lib.symbol(&sym) {
                 Ok(f) => f,
-                Err(err) => self.sess.span_fatal(item.span, &err),
+                Err(err) => self.sess.span_fatal(span, &err),
             };
             mem::transmute::<*mut u8, fn(&mut Registry)>(sym)
         };
 
-        struct MyRegistrar(Vec<(ast::Name, SyntaxExtension)>);
+        struct MyRegistrar(Vec<(ast::Name, Rc<SyntaxExtension>)>);
 
         impl Registry for MyRegistrar {
             fn register_custom_derive(&mut self,
@@ -580,7 +581,7 @@ impl<'a> CrateLoader<'a> {
                 let derive = SyntaxExtension::CustomDerive(
                     Box::new(CustomDerive::new(expand, attrs))
                 );
-                self.0.push((intern(trait_name), derive));
+                self.0.push((intern(trait_name), Rc::new(derive)));
             }
         }
 
@@ -590,7 +591,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);
-        Some(my_registrar.0)
+        my_registrar.0
     }
 
     /// Look for a plugin registrar. Returns library path, crate
@@ -928,35 +929,14 @@ impl<'a> middle::cstore::CrateLoader for CrateLoader<'a> {
         self.register_statically_included_foreign_items();
     }
 
-    fn process_item(&mut self, item: &ast::Item, definitions: &Definitions, load_macros: bool)
-                    -> Vec<(ast::Name, SyntaxExtension)> {
+    fn process_item(&mut self, item: &ast::Item, definitions: &Definitions) {
         match item.node {
             ast::ItemKind::ExternCrate(_) => {}
-            ast::ItemKind::ForeignMod(ref fm) => {
-                self.process_foreign_mod(item, fm);
-                return Vec::new();
-            }
-            _ => return Vec::new(),
+            ast::ItemKind::ForeignMod(ref fm) => return self.process_foreign_mod(item, fm),
+            _ => return,
         }
 
         let info = self.extract_crate_info(item).unwrap();
-        if load_macros {
-            let ekrate = self.read_extension_crate(item.span, &info);
-
-            // If this is a proc-macro crate, return here to avoid registering.
-            if let Some(custom_derives) = self.load_derive_macros(item, &ekrate) {
-                return custom_derives;
-            }
-
-            // Register crate now to avoid double-reading metadata
-            if let PMDSource::Owned(lib) = ekrate.metadata {
-                if ekrate.target_only || config::host_triple() == self.sess.opts.target_triple {
-                    let ExternCrateInfo { ref ident, ref name, dep_kind, .. } = info;
-                    self.register_crate(&None, ident, name, item.span, lib, dep_kind);
-                }
-            }
-        }
-
         let (cnum, ..) = self.resolve_crate(
             &None, &info.ident, &info.name, None, item.span, PathKind::Crate, info.dep_kind,
         );
@@ -968,7 +948,5 @@ impl<'a> middle::cstore::CrateLoader for CrateLoader<'a> {
             ExternCrate { def_id: def_id, span: item.span, direct: true, path_len: len };
         self.update_extern_crate(cnum, extern_crate, &mut FxHashSet());
         self.cstore.add_extern_mod_stmt_cnum(info.id, cnum);
-
-        Vec::new()
     }
 }
diff --git a/src/librustc_metadata/cstore.rs b/src/librustc_metadata/cstore.rs
index 10e86c427a832..8c95e4aec0a04 100644
--- a/src/librustc_metadata/cstore.rs
+++ b/src/librustc_metadata/cstore.rs
@@ -28,6 +28,7 @@ use std::rc::Rc;
 use std::path::PathBuf;
 use flate::Bytes;
 use syntax::{ast, attr};
+use syntax::ext::base::SyntaxExtension;
 use syntax_pos;
 
 pub use rustc::middle::cstore::{NativeLibraryKind, LinkagePreference};
@@ -80,6 +81,8 @@ pub struct CrateMetadata {
 
     pub dep_kind: Cell<DepKind>,
     pub source: CrateSource,
+
+    pub proc_macros: Option<Vec<(ast::Name, Rc<SyntaxExtension>)>>,
 }
 
 pub struct CachedInlinedItem {
diff --git a/src/librustc_metadata/cstore_impl.rs b/src/librustc_metadata/cstore_impl.rs
index 3113bfcb5b452..83de8acdb6056 100644
--- a/src/librustc_metadata/cstore_impl.rs
+++ b/src/librustc_metadata/cstore_impl.rs
@@ -14,7 +14,7 @@ use locator;
 use schema;
 
 use rustc::middle::cstore::{InlinedItem, CrateStore, CrateSource, DepKind, ExternCrate};
-use rustc::middle::cstore::{NativeLibraryKind, LinkMeta, LinkagePreference};
+use rustc::middle::cstore::{NativeLibraryKind, LinkMeta, LinkagePreference, LoadedMacro};
 use rustc::hir::def::{self, Def};
 use rustc::middle::lang_items;
 use rustc::session::Session;
@@ -353,8 +353,13 @@ 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);
+    fn load_macro(&self, id: DefId, sess: &Session) -> LoadedMacro {
+        let data = self.get_crate_data(id.krate);
+        if let Some(ref proc_macros) = data.proc_macros {
+            return LoadedMacro::ProcMacro(proc_macros[id.index.as_usize()].1.clone());
+        }
+
+        let (name, def) = data.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.
@@ -379,7 +384,7 @@ impl<'tcx> CrateStore<'tcx> for cstore::CStore {
         sess.imported_macro_spans.borrow_mut()
             .insert(local_span, (def.name.as_str().to_string(), def.span));
 
-        ast::MacroDef {
+        LoadedMacro::MacroRules(ast::MacroDef {
             ident: ast::Ident::with_empty_ctxt(def.name),
             id: ast::DUMMY_NODE_ID,
             span: local_span,
@@ -387,7 +392,7 @@ impl<'tcx> CrateStore<'tcx> for cstore::CStore {
             allow_internal_unstable: attr::contains_name(&def.attrs, "allow_internal_unstable"),
             attrs: def.attrs,
             body: body,
-        }
+        })
     }
 
     fn maybe_get_item_ast<'a>(&'tcx self,
diff --git a/src/librustc_metadata/decoder.rs b/src/librustc_metadata/decoder.rs
index 64a90d56d5561..78cde4c2fcb7e 100644
--- a/src/librustc_metadata/decoder.rs
+++ b/src/librustc_metadata/decoder.rs
@@ -691,7 +691,15 @@ impl<'a, 'tcx> CrateMetadata {
     pub fn each_child_of_item<F>(&self, id: DefIndex, mut callback: F)
         where F: FnMut(def::Export)
     {
-        let macros_only = self.dep_kind.get() == DepKind::MacrosOnly;
+        if let Some(ref proc_macros) = self.proc_macros {
+            for (id, &(name, _)) in proc_macros.iter().enumerate() {
+                callback(def::Export {
+                    name: name,
+                    def: Def::Macro(DefId { krate: self.cnum, index: DefIndex::new(id), }),
+                })
+            }
+            return
+        }
 
         // Find the item.
         let item = match self.maybe_entry(id) {
@@ -700,6 +708,7 @@ impl<'a, 'tcx> CrateMetadata {
         };
 
         // Iterate over all children.
+        let macros_only = self.dep_kind.get() == DepKind::MacrosOnly;
         for child_index in item.children.decode(self) {
             if macros_only {
                 continue
diff --git a/src/librustc_metadata/locator.rs b/src/librustc_metadata/locator.rs
index c31b209768c38..b6b347fff5f26 100644
--- a/src/librustc_metadata/locator.rs
+++ b/src/librustc_metadata/locator.rs
@@ -262,6 +262,7 @@ pub struct Context<'a> {
     pub rejected_via_kind: Vec<CrateMismatch>,
     pub rejected_via_version: Vec<CrateMismatch>,
     pub should_match_name: bool,
+    pub is_proc_macro: Option<bool>,
 }
 
 pub struct ArchiveMetadata {
@@ -623,6 +624,12 @@ impl<'a> Context<'a> {
 
     fn crate_matches(&mut self, metadata: &MetadataBlob, libpath: &Path) -> Option<Svh> {
         let root = metadata.get_root();
+        if let Some(is_proc_macro) = self.is_proc_macro {
+            if root.macro_derive_registrar.is_some() != is_proc_macro {
+                return None;
+            }
+        }
+
         let rustc_version = rustc_version();
         if root.rustc_version != rustc_version {
             info!("Rejecting via version: expected {} got {}",
diff --git a/src/librustc_resolve/build_reduced_graph.rs b/src/librustc_resolve/build_reduced_graph.rs
index 0833f85c1f6a2..99e7a9042c0ce 100644
--- a/src/librustc_resolve/build_reduced_graph.rs
+++ b/src/librustc_resolve/build_reduced_graph.rs
@@ -21,9 +21,9 @@ use Namespace::{self, TypeNS, ValueNS, MacroNS};
 use ResolveResult::Success;
 use {resolve_error, resolve_struct_error, ResolutionError};
 
-use rustc::middle::cstore::DepKind;
+use rustc::middle::cstore::{DepKind, LoadedMacro};
 use rustc::hir::def::*;
-use rustc::hir::def_id::{CrateNum, CRATE_DEF_INDEX, DefId, DefIndex, BUILTIN_MACROS_CRATE};
+use rustc::hir::def_id::{CrateNum, CRATE_DEF_INDEX, DefId};
 use rustc::ty;
 
 use std::cell::Cell;
@@ -62,7 +62,6 @@ struct LegacyMacroImports {
     import_all: Option<Span>,
     imports: Vec<(Name, Span)>,
     reexports: Vec<(Name, Span)>,
-    no_link: bool,
 }
 
 impl<'b> Resolver<'b> {
@@ -213,59 +212,26 @@ impl<'b> Resolver<'b> {
             }
 
             ItemKind::ExternCrate(_) => {
-                let legacy_imports = self.legacy_macro_imports(&item.attrs);
-                // `#[macro_use]` and `#[macro_reexport]` are only allowed at the crate root.
-                if self.current_module.parent.is_some() && {
-                    legacy_imports.import_all.is_some() || !legacy_imports.imports.is_empty() ||
-                    !legacy_imports.reexports.is_empty()
-                } {
-                    span_err!(self.session, item.span, E0468,
-                              "an `extern crate` loading macros must be at the crate root");
-                }
-
-                let load_macros = legacy_imports != LegacyMacroImports::default();
-                let proc_macros =
-                    self.crate_loader.process_item(item, &self.definitions, load_macros);
+                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
-                let crate_id = self.session.cstore.extern_mod_stmt_cnum(item.id);
-                let module = if let Some(crate_id) = crate_id {
-                    let module = self.get_extern_crate_root(crate_id);
-                    let binding = (module, sp, ty::Visibility::Public).to_name_binding();
-                    let binding = self.arenas.alloc_name_binding(binding);
-                    let directive = self.arenas.alloc_import_directive(ImportDirective {
-                        id: item.id,
-                        parent: parent,
-                        imported_module: Cell::new(Some(module)),
-                        subclass: ImportDirectiveSubclass::ExternCrate,
-                        span: item.span,
-                        module_path: Vec::new(),
-                        vis: Cell::new(vis),
-                    });
-                    let imported_binding = self.import(binding, directive);
-                    self.define(parent, name, TypeNS, imported_binding);
-                    self.populate_module_if_necessary(module);
-                    module
-                } else {
-                    // 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
-                };
-
-                let allow_shadowing = expansion == Mark::root();
-                self.process_legacy_macro_imports(module, legacy_imports, allow_shadowing);
+                let crate_id = self.session.cstore.extern_mod_stmt_cnum(item.id).unwrap();
+                let module = self.get_extern_crate_root(crate_id);
+                let binding = (module, sp, ty::Visibility::Public).to_name_binding();
+                let binding = self.arenas.alloc_name_binding(binding);
+                let directive = self.arenas.alloc_import_directive(ImportDirective {
+                    id: item.id,
+                    parent: parent,
+                    imported_module: Cell::new(Some(module)),
+                    subclass: ImportDirectiveSubclass::ExternCrate,
+                    span: item.span,
+                    module_path: Vec::new(),
+                    vis: Cell::new(vis),
+                });
+                let imported_binding = self.import(binding, directive);
+                self.define(parent, name, TypeNS, imported_binding);
+                self.populate_module_if_necessary(module);
+                self.process_legacy_macro_imports(item, module, expansion);
             }
 
             ItemKind::Mod(..) if item.ident == keywords::Invalid.ident() => {} // Crate root
@@ -286,9 +252,7 @@ impl<'b> Resolver<'b> {
                 self.current_module = module;
             }
 
-            ItemKind::ForeignMod(..) => {
-                self.crate_loader.process_item(item, &self.definitions, false);
-            }
+            ItemKind::ForeignMod(..) => self.crate_loader.process_item(item, &self.definitions),
 
             // These items live in the value namespace.
             ItemKind::Static(_, m, _) => {
@@ -431,10 +395,10 @@ impl<'b> Resolver<'b> {
         let name = child.name;
         let def = child.def;
         let def_id = def.def_id();
-        let vis = if parent.is_trait() {
-            ty::Visibility::Public
-        } else {
-            self.session.cstore.visibility(def_id)
+        let vis = match def {
+            Def::Macro(..) => ty::Visibility::Public,
+            _ if parent.is_trait() => ty::Visibility::Public,
+            _ => self.session.cstore.visibility(def_id),
         };
 
         match def {
@@ -524,7 +488,11 @@ impl<'b> Resolver<'b> {
             return ext.clone();
         }
 
-        let mut macro_rules = self.session.cstore.load_macro(def_id, &self.session);
+        let mut macro_rules = match self.session.cstore.load_macro(def_id, &self.session) {
+            LoadedMacro::MacroRules(macro_rules) => macro_rules,
+            LoadedMacro::ProcMacro(ext) => return ext,
+        };
+
         let mark = Mark::fresh();
         let invocation = self.arenas.alloc_invocation_data(InvocationData {
             module: Cell::new(self.get_extern_crate_root(def_id.krate)),
@@ -561,10 +529,23 @@ impl<'b> Resolver<'b> {
         }
     }
 
-    fn process_legacy_macro_imports(&mut self,
-                                    module: Module<'b>,
-                                    legacy_imports: LegacyMacroImports,
-                                    allow_shadowing: bool) {
+    fn process_legacy_macro_imports(&mut self, item: &Item, module: Module<'b>, expansion: Mark) {
+        let allow_shadowing = expansion == Mark::root();
+        let legacy_imports = self.legacy_macro_imports(&item.attrs);
+        let cnum = module.def_id().unwrap().krate;
+
+        // `#[macro_use]` and `#[macro_reexport]` are only allowed at the crate root.
+        if self.current_module.parent.is_some() && legacy_imports != LegacyMacroImports::default() {
+            span_err!(self.session, item.span, E0468,
+                      "an `extern crate` loading macros must be at the crate root");
+        } else if self.session.cstore.dep_kind(cnum) == DepKind::MacrosOnly &&
+                  legacy_imports == LegacyMacroImports::default() {
+            let msg = "custom derive crates and `#[no_link]` crates have no effect without \
+                       `#[macro_use]`";
+            self.session.span_warn(item.span, msg);
+            self.used_crates.insert(cnum); // Avoid the normal unused extern crate warning
+        }
+
         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);
@@ -583,11 +564,7 @@ impl<'b> Resolver<'b> {
             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 });
+                self.macro_exports.push(Export { name: name, def: binding.def() });
             } else {
                 span_err!(self.session, span, E0470, "reexported macro not found");
             }
@@ -647,8 +624,6 @@ impl<'b> Resolver<'b> {
                 } else {
                     bad_macro_reexport(self, attr.span());
                 }
-            } else if attr.check_name("no_link") {
-                imports.no_link = true;
             }
         }
         imports
diff --git a/src/librustdoc/visit_ast.rs b/src/librustdoc/visit_ast.rs
index b91d71198e819..d0407162793ee 100644
--- a/src/librustdoc/visit_ast.rs
+++ b/src/librustdoc/visit_ast.rs
@@ -21,6 +21,7 @@ use syntax_pos::Span;
 use rustc::hir::map as hir_map;
 use rustc::hir::def::Def;
 use rustc::hir::def_id::LOCAL_CRATE;
+use rustc::middle::cstore::LoadedMacro;
 use rustc::middle::privacy::AccessLevel;
 use rustc::util::nodemap::FxHashSet;
 
@@ -198,7 +199,12 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> {
                     if def_id.krate == LOCAL_CRATE {
                         continue // These are `krate.exported_macros`, handled in `self.visit()`.
                     }
-                    let def = self.cx.sess().cstore.load_macro(def_id, self.cx.sess());
+                    let def = match self.cx.sess().cstore.load_macro(def_id, self.cx.sess()) {
+                        LoadedMacro::MacroRules(macro_rules) => macro_rules,
+                        // FIXME(jseyfried): document proc macro reexports
+                        LoadedMacro::ProcMacro(..) => continue,
+                    };
+
                     // FIXME(jseyfried) merge with `self.visit_macro()`
                     let matchers = def.body.chunks(4).map(|arm| arm[0].get_span()).collect();
                     om.macros.push(Macro {
diff --git a/src/libsyntax_ext/deriving/mod.rs b/src/libsyntax_ext/deriving/mod.rs
index c2bfead568612..b1d473820f774 100644
--- a/src/libsyntax_ext/deriving/mod.rs
+++ b/src/libsyntax_ext/deriving/mod.rs
@@ -12,10 +12,10 @@
 
 use syntax::ast::{self, MetaItem};
 use syntax::attr::HasAttrs;
+use syntax::codemap;
 use syntax::ext::base::{Annotatable, ExtCtxt, SyntaxExtension};
 use syntax::ext::build::AstBuilder;
-use syntax::feature_gate;
-use syntax::codemap;
+use syntax::feature_gate::{self, emit_feature_err};
 use syntax::parse::token::{intern, intern_and_get_ident};
 use syntax::ptr::P;
 use syntax_pos::Span;
@@ -220,6 +220,12 @@ pub fn expand_derive(cx: &mut ExtCtxt,
                                  .filter(|&(_, ref name)| !is_builtin_trait(&name.name().unwrap()))
                                  .next();
     if let Some((i, titem)) = macros_11_derive {
+        if !cx.ecfg.features.unwrap().proc_macro {
+            let issue = feature_gate::GateIssue::Language;
+            let msg = "custom derive macros are experimentally supported";
+            emit_feature_err(cx.parse_sess, "proc_macro", titem.span, issue, msg);
+        }
+
         let tname = ast::Ident::with_empty_ctxt(intern(&titem.name().unwrap()));
         let path = ast::Path::from_ident(titem.span, tname);
         let ext = cx.resolver.resolve_macro(cx.current_expansion.mark, &path, false).unwrap();
diff --git a/src/test/compile-fail-fulldeps/proc-macro/auxiliary/derive-a.rs b/src/test/compile-fail-fulldeps/proc-macro/auxiliary/derive-a.rs
index 4aa4238611d89..8d26207273d42 100644
--- a/src/test/compile-fail-fulldeps/proc-macro/auxiliary/derive-a.rs
+++ b/src/test/compile-fail-fulldeps/proc-macro/auxiliary/derive-a.rs
@@ -21,5 +21,5 @@ use proc_macro::TokenStream;
 
 #[proc_macro_derive(A)]
 pub fn derive_a(input: TokenStream) -> TokenStream {
-    input
+    "".parse().unwrap()
 }
diff --git a/src/test/compile-fail-fulldeps/proc-macro/feature-gate-4.rs b/src/test/compile-fail-fulldeps/proc-macro/feature-gate-4.rs
index 0fdd13bc30cce..6a8fcdf4ab782 100644
--- a/src/test/compile-fail-fulldeps/proc-macro/feature-gate-4.rs
+++ b/src/test/compile-fail-fulldeps/proc-macro/feature-gate-4.rs
@@ -12,4 +12,6 @@
 
 #[macro_use]
 extern crate derive_a;
-//~^ ERROR: loading custom derive macro crates is experimentally supported
+
+#[derive(A)] //~ ERROR custom derive macros are experimentally supported
+struct S;
diff --git a/src/test/compile-fail-fulldeps/proc-macro/cannot-link.rs b/src/test/compile-fail-fulldeps/proc-macro/no-macro-use-attr.rs
similarity index 74%
rename from src/test/compile-fail-fulldeps/proc-macro/cannot-link.rs
rename to src/test/compile-fail-fulldeps/proc-macro/no-macro-use-attr.rs
index f6f1be37fc3c9..f61b8b4073b6f 100644
--- a/src/test/compile-fail-fulldeps/proc-macro/cannot-link.rs
+++ b/src/test/compile-fail-fulldeps/proc-macro/no-macro-use-attr.rs
@@ -10,7 +10,10 @@
 
 // aux-build:derive-a.rs
 
+#![feature(rustc_attrs)]
+
 extern crate derive_a;
-//~^ ERROR: crates of the `proc-macro` crate type cannot be linked at runtime
+//~^ WARN custom derive crates and `#[no_link]` crates have no effect without `#[macro_use]`
 
-fn main() {}
+#[rustc_error]
+fn main() {} //~ ERROR compilation successful
diff --git a/src/test/compile-fail-fulldeps/proc-macro/shadow.rs b/src/test/compile-fail-fulldeps/proc-macro/shadow.rs
index a04756ca19ba7..dc828fbf7d160 100644
--- a/src/test/compile-fail-fulldeps/proc-macro/shadow.rs
+++ b/src/test/compile-fail-fulldeps/proc-macro/shadow.rs
@@ -15,6 +15,6 @@
 #[macro_use]
 extern crate derive_a;
 #[macro_use]
-extern crate derive_a; //~ ERROR `derive_a` has already been defined
+extern crate derive_a; //~ ERROR `derive_a` has already been imported
 
 fn main() {}
diff --git a/src/test/compile-fail/no-link.rs b/src/test/compile-fail/no-link.rs
index 5ea07403cf793..c4737a373992d 100644
--- a/src/test/compile-fail/no-link.rs
+++ b/src/test/compile-fail/no-link.rs
@@ -12,6 +12,7 @@
 
 #[no_link]
 extern crate empty_struct;
+//~^ WARN custom derive crates and `#[no_link]` crates have no effect without `#[macro_use]`
 
 fn main() {
     empty_struct::XEmpty1; //~ ERROR unresolved name

From f35eff2c57ccbeab2b4775dddbebc9bdc8e0e785 Mon Sep 17 00:00:00 2001
From: Jeffrey Seyfried <jeffrey.seyfried@gmail.com>
Date: Mon, 7 Nov 2016 22:47:14 +0000
Subject: [PATCH 11/11] Test `#[macro_reexport]`ing custom derives.

---
 .../proc-macro/auxiliary/derive-reexport.rs   | 16 ++++++++++++++
 .../proc-macro/use-reexport.rs                | 22 +++++++++++++++++++
 2 files changed, 38 insertions(+)
 create mode 100644 src/test/run-pass-fulldeps/proc-macro/auxiliary/derive-reexport.rs
 create mode 100644 src/test/run-pass-fulldeps/proc-macro/use-reexport.rs

diff --git a/src/test/run-pass-fulldeps/proc-macro/auxiliary/derive-reexport.rs b/src/test/run-pass-fulldeps/proc-macro/auxiliary/derive-reexport.rs
new file mode 100644
index 0000000000000..05a6cbec69c5a
--- /dev/null
+++ b/src/test/run-pass-fulldeps/proc-macro/auxiliary/derive-reexport.rs
@@ -0,0 +1,16 @@
+// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// ignore-test
+
+#![feature(macro_reexport, proc_macro)]
+
+#[macro_reexport(A)]
+extern crate derive_a;
diff --git a/src/test/run-pass-fulldeps/proc-macro/use-reexport.rs b/src/test/run-pass-fulldeps/proc-macro/use-reexport.rs
new file mode 100644
index 0000000000000..7f09d8faebbb5
--- /dev/null
+++ b/src/test/run-pass-fulldeps/proc-macro/use-reexport.rs
@@ -0,0 +1,22 @@
+// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// aux-build:derive-a.rs
+// aux-build:derive-reexport.rs
+
+#![feature(proc_macro)]
+
+#[macro_use]
+extern crate derive_reexport;
+
+#[derive(Debug, PartialEq, A, Eq, Copy, Clone)]
+struct A;
+
+fn main() {}