about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--src/librustc/hir/lowering.rs2
-rw-r--r--src/librustc/hir/mod.rs2
-rw-r--r--src/librustc/middle/cstore.rs22
-rw-r--r--src/librustc_incremental/calculate_svh/svh_visitor.rs12
-rw-r--r--src/librustc_metadata/creader.rs228
-rw-r--r--src/librustc_metadata/cstore.rs15
-rw-r--r--src/librustc_metadata/diagnostics.rs179
-rw-r--r--src/librustc_metadata/lib.rs1
-rw-r--r--src/librustc_metadata/macro_import.rs235
-rw-r--r--src/librustc_resolve/build_reduced_graph.rs220
-rw-r--r--src/librustc_resolve/diagnostics.rs179
-rw-r--r--src/librustc_resolve/macros.rs26
-rw-r--r--src/libsyntax/ast.rs2
-rw-r--r--src/libsyntax/ext/base.rs4
-rw-r--r--src/libsyntax/ext/tt/macro_rules.rs5
15 files changed, 490 insertions, 642 deletions
diff --git a/src/librustc/hir/lowering.rs b/src/librustc/hir/lowering.rs
index 80340f9a925..562156e70bd 100644
--- a/src/librustc/hir/lowering.rs
+++ b/src/librustc/hir/lowering.rs
@@ -716,8 +716,6 @@ impl<'a> LoweringContext<'a> {
             id: m.id,
             span: m.span,
             imported_from: m.imported_from.map(|x| x.name),
-            export: m.export,
-            use_locally: m.use_locally,
             allow_internal_unstable: m.allow_internal_unstable,
             body: m.body.clone().into(),
         }
diff --git a/src/librustc/hir/mod.rs b/src/librustc/hir/mod.rs
index 6e81c3e700e..1de4355ccdf 100644
--- a/src/librustc/hir/mod.rs
+++ b/src/librustc/hir/mod.rs
@@ -458,8 +458,6 @@ pub struct MacroDef {
     pub id: NodeId,
     pub span: Span,
     pub imported_from: Option<Name>,
-    pub export: bool,
-    pub use_locally: bool,
     pub allow_internal_unstable: bool,
     pub body: HirVec<TokenTree>,
 }
diff --git a/src/librustc/middle/cstore.rs b/src/librustc/middle/cstore.rs
index b54862ae0ad..a3a84f51780 100644
--- a/src/librustc/middle/cstore.rs
+++ b/src/librustc/middle/cstore.rs
@@ -37,7 +37,7 @@ use util::nodemap::{NodeSet, DefIdMap};
 use std::path::PathBuf;
 use syntax::ast;
 use syntax::attr;
-use syntax::ext::base::MultiItemModifier;
+use syntax::ext::base::SyntaxExtension;
 use syntax::ptr::P;
 use syntax::parse::token::InternedString;
 use syntax_pos::Span;
@@ -417,18 +417,22 @@ impl<'tcx> CrateStore<'tcx> for DummyCrateStore {
     fn metadata_encoding_version(&self) -> &[u8] { bug!("metadata_encoding_version") }
 }
 
-pub struct LoadedMacro {
-    pub import_site: Span,
-    pub kind: LoadedMacroKind,
+pub enum LoadedMacros {
+    MacroRules(Vec<ast::MacroDef>),
+    ProcMacros(Vec<(ast::Name, SyntaxExtension)>),
 }
 
-pub enum LoadedMacroKind {
-    Def(ast::MacroDef),
-    CustomDerive(String, Box<MultiItemModifier>),
+impl LoadedMacros {
+    pub fn is_proc_macros(&self) -> bool {
+        match *self {
+            LoadedMacros::ProcMacros(_) => true,
+            _ => false,
+        }
+    }
 }
 
 pub trait CrateLoader {
-    fn load_macros(&mut self, extern_crate: &ast::Item, allows_macros: bool) -> Vec<LoadedMacro>;
-    fn process_item(&mut self, item: &ast::Item, defs: &Definitions);
+    fn process_item(&mut self, item: &ast::Item, defs: &Definitions, load_macros: bool)
+                    -> Option<LoadedMacros>;
     fn postprocess(&mut self, krate: &ast::Crate);
 }
diff --git a/src/librustc_incremental/calculate_svh/svh_visitor.rs b/src/librustc_incremental/calculate_svh/svh_visitor.rs
index 584e5598b9f..51c894e1b78 100644
--- a/src/librustc_incremental/calculate_svh/svh_visitor.rs
+++ b/src/librustc_incremental/calculate_svh/svh_visitor.rs
@@ -675,13 +675,11 @@ impl<'a, 'hash, 'tcx> visit::Visitor<'tcx> for StrictVersionHashVisitor<'a, 'has
 
     fn visit_macro_def(&mut self, macro_def: &'tcx MacroDef) {
         debug!("visit_macro_def: st={:?}", self.st);
-        if macro_def.export {
-            SawMacroDef.hash(self.st);
-            hash_attrs!(self, &macro_def.attrs);
-            visit::walk_macro_def(self, macro_def)
-            // FIXME(mw): We should hash the body of the macro too but we don't
-            //            have a stable way of doing so yet.
-        }
+        SawMacroDef.hash(self.st);
+        hash_attrs!(self, &macro_def.attrs);
+        visit::walk_macro_def(self, macro_def)
+        // FIXME(mw): We should hash the body of the macro too but we don't
+        //            have a stable way of doing so yet.
     }
 }
 
diff --git a/src/librustc_metadata/creader.rs b/src/librustc_metadata/creader.rs
index 7ae3f6f8107..d160d29af7d 100644
--- a/src/librustc_metadata/creader.rs
+++ b/src/librustc_metadata/creader.rs
@@ -12,19 +12,18 @@
 
 use cstore::{self, CStore, CrateSource, MetadataBlob};
 use locator::{self, CratePaths};
-use macro_import;
 use schema::CrateRoot;
 
 use rustc::hir::def_id::{CrateNum, DefIndex};
 use rustc::hir::svh::Svh;
-use rustc::middle::cstore::LoadedMacro;
+use rustc::middle::cstore::LoadedMacros;
 use rustc::session::{config, Session};
 use rustc_back::PanicStrategy;
 use rustc::session::search_paths::PathKind;
 use rustc::middle;
 use rustc::middle::cstore::{CrateStore, validate_crate_name, ExternCrate};
 use rustc::util::nodemap::{FnvHashMap, FnvHashSet};
-use rustc::hir::map as hir_map;
+use rustc::hir::map::Definitions;
 
 use std::cell::{RefCell, Cell};
 use std::ops::Deref;
@@ -36,7 +35,8 @@ use syntax::ast;
 use syntax::abi::Abi;
 use syntax::parse;
 use syntax::attr;
-use syntax::parse::token::InternedString;
+use syntax::ext::base::SyntaxExtension;
+use syntax::parse::token::{InternedString, intern};
 use syntax_pos::{self, Span, mk_sp};
 use log;
 
@@ -120,11 +120,6 @@ struct ExtensionCrate {
     metadata: PMDSource,
     dylib: Option<PathBuf>,
     target_only: bool,
-
-    ident: String,
-    name: String,
-    span: Span,
-    should_link: bool,
 }
 
 enum PMDSource {
@@ -148,17 +143,6 @@ enum LoadResult {
     Loaded(Library),
 }
 
-pub struct Macros {
-    pub macro_rules: Vec<ast::MacroDef>,
-
-    /// An array of pairs where the first element is the name of the custom
-    /// derive (e.g. the trait being derived) and the second element is the
-    /// index of the definition.
-    pub custom_derive_registrar: Option<DefIndex>,
-    pub svh: Svh,
-    pub dylib: Option<PathBuf>,
-}
-
 impl<'a> CrateLoader<'a> {
     pub fn new(sess: &'a Session,
                cstore: &'a CStore,
@@ -490,7 +474,6 @@ impl<'a> CrateLoader<'a> {
               info.id, info.name, info.ident, info.should_link);
         let target_triple = &self.sess.opts.target_triple[..];
         let is_cross = target_triple != config::host_triple();
-        let mut should_link = info.should_link && !is_cross;
         let mut target_only = false;
         let ident = info.ident.clone();
         let name = info.name.clone();
@@ -517,7 +500,6 @@ impl<'a> CrateLoader<'a> {
             // Try loading from target crates. This will abort later if we
             // try to load a plugin registrar function,
             target_only = true;
-            should_link = info.should_link;
 
             locate_ctxt.target = &self.sess.target.target;
             locate_ctxt.triple = target_triple;
@@ -547,25 +529,14 @@ impl<'a> CrateLoader<'a> {
             metadata: metadata,
             dylib: dylib.map(|p| p.0),
             target_only: target_only,
-            name: info.name.to_string(),
-            ident: info.ident.to_string(),
-            span: span,
-            should_link: should_link,
         }
     }
 
-    pub fn read_macros(&mut self, item: &ast::Item) -> Macros {
-        let ci = self.extract_crate_info(item).unwrap();
-        let ekrate = self.read_extension_crate(item.span, &ci);
-
+    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 ret = Macros {
-            macro_rules: Vec::new(),
-            custom_derive_registrar: None,
-            svh: root.hash,
-            dylib: None,
-        };
+        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.
@@ -589,54 +560,90 @@ impl<'a> CrateLoader<'a> {
                 attr::mark_used(attr);
             }
 
-            ret.macro_rules.push(ast::MacroDef {
+            macro_rules.push(ast::MacroDef {
                 ident: ast::Ident::with_empty_ctxt(def.name),
-                attrs: def.attrs,
                 id: ast::DUMMY_NODE_ID,
                 span: local_span,
                 imported_from: Some(item.ident),
-                // overridden in plugin/load.rs
-                export: false,
-                use_locally: false,
-                allow_internal_unstable: false,
-
+                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));
         }
 
-        match root.macro_derive_registrar {
-            Some(id) => ret.custom_derive_registrar = Some(id),
-
-            // If this crate is not a proc-macro crate then we might be able to
-            // register it with the local crate store to prevent loading the
-            // metadata twice.
-            //
-            // If it's a proc-macro crate, though, then we definitely don't
-            // want to register it with the local crate store as we're just
-            // going to use it as we would a plugin.
-            None => {
-                ekrate.register(self);
-                return ret
+        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);
             }
-        }
 
-        self.cstore.add_used_for_derive_macros(item);
-        ret.dylib = ekrate.dylib.clone();
-        if ret.dylib.is_none() {
-            span_bug!(item.span, "proc-macro crate not dylib");
+            // 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)
         }
+    }
 
-        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);
+    /// Load custom derive macros.
+    ///
+    /// Note that this is intentionally similar to how we load plugins today,
+    /// but also intentionally separate. Plugins are likely always going to be
+    /// 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)> {
+        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;
+
+        // 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),
+        };
+
+        let sym = self.sess.generate_derive_registrar_symbol(&svh, index);
+        let registrar = unsafe {
+            let sym = match lib.symbol(&sym) {
+                Ok(f) => f,
+                Err(err) => self.sess.span_fatal(item.span, &err),
+            };
+            mem::transmute::<*mut u8, fn(&mut Registry)>(sym)
+        };
+
+        struct MyRegistrar(Vec<(ast::Name, SyntaxExtension)>);
+
+        impl Registry for MyRegistrar {
+            fn register_custom_derive(&mut self,
+                                      trait_name: &str,
+                                      expand: fn(TokenStream) -> TokenStream) {
+                let derive = SyntaxExtension::CustomDerive(Box::new(CustomDerive::new(expand)));
+                self.0.push((intern(trait_name), derive));
+            }
         }
 
-        return ret
+        let mut my_registrar = MyRegistrar(Vec::new());
+        registrar(&mut my_registrar);
+
+        // 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
     }
 
     /// Look for a plugin registrar. Returns library path, crate
@@ -889,22 +896,6 @@ impl<'a> CrateLoader<'a> {
     }
 }
 
-impl ExtensionCrate {
-    fn register(self, loader: &mut CrateLoader) {
-        if !self.should_link {
-            return
-        }
-
-        let library = match self.metadata {
-            PMDSource::Owned(lib) => lib,
-            PMDSource::Registered(_) => return,
-        };
-
-        // Register crate now to avoid double-reading metadata
-        loader.register_crate(&None, &self.ident, &self.name, self.span, library, true);
-    }
-}
-
 impl<'a> CrateLoader<'a> {
     pub fn preprocess(&mut self, krate: &ast::Crate) {
         for attr in krate.attrs.iter().filter(|m| m.name() == "link_args") {
@@ -990,47 +981,56 @@ impl<'a> middle::cstore::CrateLoader for CrateLoader<'a> {
         self.register_statically_included_foreign_items();
     }
 
-    fn process_item(&mut self, item: &ast::Item, definitions: &hir_map::Definitions) {
+    fn process_item(&mut self, item: &ast::Item, definitions: &Definitions, load_macros: bool)
+                    -> Option<LoadedMacros> {
         match item.node {
             ast::ItemKind::ExternCrate(_) => {}
-            ast::ItemKind::ForeignMod(ref fm) => return self.process_foreign_mod(item, fm),
-            _ => return,
+            ast::ItemKind::ForeignMod(ref fm) => {
+                self.process_foreign_mod(item, fm);
+                return None;
+            }
+            _ => return None,
         }
 
-        // If this `extern crate` item has `#[macro_use]` then we can safely skip it.
-        // These annotations were processed during macro expansion and are already loaded
-        // (if necessary) into our crate store.
-        //
-        // Note that it's important we *don't* fall through below as some `#[macro_use]`
-        // crates are explicitly not linked (e.g. macro crates) so we want to ensure
-        // we avoid `resolve_crate` with those.
-        if attr::contains_name(&item.attrs, "macro_use") {
-            if self.cstore.was_used_for_derive_macros(item) {
-                return
+        let info = self.extract_crate_info(item).unwrap();
+        let loaded_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 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 {
+                return Some(loaded_macros);
             }
-        }
 
-        if let Some(info) = self.extract_crate_info(item) {
-            if !info.should_link {
-                return;
+            // 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, true);
+                }
             }
 
-            let (cnum, ..) = self.resolve_crate(
-                &None, &info.ident, &info.name, None, item.span, PathKind::Crate, true,
-            );
+            Some(loaded_macros)
+        } else {
+            if !info.should_link {
+                return None;
+            }
+            None
+        };
 
-            let def_id = definitions.opt_local_def_id(item.id).unwrap();
-            let len = definitions.def_path(def_id.index).data.len();
+        let (cnum, ..) = self.resolve_crate(
+            &None, &info.ident, &info.name, None, item.span, PathKind::Crate, true,
+        );
 
-            let extern_crate =
-                ExternCrate { def_id: def_id, span: item.span, direct: true, path_len: len };
-            self.update_extern_crate(cnum, extern_crate, &mut FnvHashSet());
+        let def_id = definitions.opt_local_def_id(item.id).unwrap();
+        let len = definitions.def_path(def_id.index).data.len();
 
-            self.cstore.add_extern_mod_stmt_cnum(info.id, cnum);
-        }
-    }
+        let extern_crate =
+            ExternCrate { def_id: def_id, span: item.span, direct: true, path_len: len };
+        self.update_extern_crate(cnum, extern_crate, &mut FnvHashSet());
+        self.cstore.add_extern_mod_stmt_cnum(info.id, cnum);
 
-    fn load_macros(&mut self, extern_crate: &ast::Item, allows_macros: bool) -> Vec<LoadedMacro> {
-        macro_import::load_macros(self, extern_crate, allows_macros)
+        loaded_macros
     }
 }
diff --git a/src/librustc_metadata/cstore.rs b/src/librustc_metadata/cstore.rs
index f0952fd145d..58c70f959b7 100644
--- a/src/librustc_metadata/cstore.rs
+++ b/src/librustc_metadata/cstore.rs
@@ -21,14 +21,13 @@ use rustc::hir::svh::Svh;
 use rustc::middle::cstore::ExternCrate;
 use rustc_back::PanicStrategy;
 use rustc_data_structures::indexed_vec::IndexVec;
-use rustc::util::nodemap::{FnvHashMap, NodeMap, NodeSet, DefIdMap, FnvHashSet};
+use rustc::util::nodemap::{FnvHashMap, NodeMap, NodeSet, DefIdMap};
 
 use std::cell::{RefCell, Cell};
 use std::rc::Rc;
 use std::path::PathBuf;
 use flate::Bytes;
-use syntax::ast::{self, Ident};
-use syntax::attr;
+use syntax::{ast, attr};
 use syntax_pos;
 
 pub use rustc::middle::cstore::{NativeLibraryKind, LinkagePreference};
@@ -105,7 +104,6 @@ pub struct CStore {
     pub inlined_item_cache: RefCell<DefIdMap<Option<CachedInlinedItem>>>,
     pub defid_for_inlined_node: RefCell<NodeMap<DefId>>,
     pub visible_parent_map: RefCell<DefIdMap<DefId>>,
-    pub used_for_derive_macro: RefCell<FnvHashSet<Ident>>,
 }
 
 impl CStore {
@@ -121,7 +119,6 @@ impl CStore {
             visible_parent_map: RefCell::new(FnvHashMap()),
             inlined_item_cache: RefCell::new(FnvHashMap()),
             defid_for_inlined_node: RefCell::new(FnvHashMap()),
-            used_for_derive_macro: RefCell::new(FnvHashSet()),
         }
     }
 
@@ -279,14 +276,6 @@ impl CStore {
     pub fn do_extern_mod_stmt_cnum(&self, emod_id: ast::NodeId) -> Option<CrateNum> {
         self.extern_mod_crate_map.borrow().get(&emod_id).cloned()
     }
-
-    pub fn was_used_for_derive_macros(&self, i: &ast::Item) -> bool {
-        self.used_for_derive_macro.borrow().contains(&i.ident)
-    }
-
-    pub fn add_used_for_derive_macros(&self, i: &ast::Item) {
-        self.used_for_derive_macro.borrow_mut().insert(i.ident);
-    }
 }
 
 impl CrateMetadata {
diff --git a/src/librustc_metadata/diagnostics.rs b/src/librustc_metadata/diagnostics.rs
index c03375bf825..b2f4760727a 100644
--- a/src/librustc_metadata/diagnostics.rs
+++ b/src/librustc_metadata/diagnostics.rs
@@ -91,185 +91,6 @@ You need to link your code to the relevant crate in order to be able to use it
 well, and you link to them the same way.
 "##,
 
-E0466: r##"
-Macro import declarations were malformed.
-
-Erroneous code examples:
-
-```compile_fail,E0466
-#[macro_use(a_macro(another_macro))] // error: invalid import declaration
-extern crate core as some_crate;
-
-#[macro_use(i_want = "some_macros")] // error: invalid import declaration
-extern crate core as another_crate;
-```
-
-This is a syntax error at the level of attribute declarations. The proper
-syntax for macro imports is the following:
-
-```ignore
-// In some_crate:
-#[macro_export]
-macro_rules! get_tacos {
-    ...
-}
-
-#[macro_export]
-macro_rules! get_pimientos {
-    ...
-}
-
-// In your crate:
-#[macro_use(get_tacos, get_pimientos)] // It imports `get_tacos` and
-extern crate some_crate;               // `get_pimientos` macros from some_crate
-```
-
-If you would like to import all exported macros, write `macro_use` with no
-arguments.
-"##,
-
-E0467: r##"
-Macro reexport declarations were empty or malformed.
-
-Erroneous code examples:
-
-```compile_fail,E0467
-#[macro_reexport]                    // error: no macros listed for export
-extern crate core as macros_for_good;
-
-#[macro_reexport(fun_macro = "foo")] // error: not a macro identifier
-extern crate core as other_macros_for_good;
-```
-
-This is a syntax error at the level of attribute declarations.
-
-Currently, `macro_reexport` requires at least one macro name to be listed.
-Unlike `macro_use`, listing no names does not reexport all macros from the
-given crate.
-
-Decide which macros you would like to export and list them properly.
-
-These are proper reexport declarations:
-
-```ignore
-#[macro_reexport(some_macro, another_macro)]
-extern crate macros_for_good;
-```
-"##,
-
-E0468: r##"
-A non-root module attempts to import macros from another crate.
-
-Example of erroneous code:
-
-```compile_fail,E0468
-mod foo {
-    #[macro_use(helpful_macro)] // error: must be at crate root to import
-    extern crate core;          //        macros from another crate
-    helpful_macro!(...);
-}
-```
-
-Only `extern crate` imports at the crate root level are allowed to import
-macros.
-
-Either move the macro import to crate root or do without the foreign macros.
-This will work:
-
-```ignore
-#[macro_use(helpful_macro)]
-extern crate some_crate;
-
-mod foo {
-    helpful_macro!(...)
-}
-```
-"##,
-
-E0469: r##"
-A macro listed for import was not found.
-
-Erroneous code example:
-
-```compile_fail,E0469
-#[macro_use(drink, be_merry)] // error: imported macro not found
-extern crate collections;
-
-fn main() {
-    // ...
-}
-```
-
-Either the listed macro is not contained in the imported crate, or it is not
-exported from the given crate.
-
-This could be caused by a typo. Did you misspell the macro's name?
-
-Double-check the names of the macros listed for import, and that the crate
-in question exports them.
-
-A working version would be:
-
-```ignore
-// In some_crate crate:
-#[macro_export]
-macro_rules! eat {
-    ...
-}
-
-#[macro_export]
-macro_rules! drink {
-    ...
-}
-
-// In your crate:
-#[macro_use(eat, drink)]
-extern crate some_crate; //ok!
-```
-"##,
-
-E0470: r##"
-A macro listed for reexport was not found.
-
-Erroneous code example:
-
-```compile_fail,E0470
-#[macro_reexport(drink, be_merry)]
-extern crate collections;
-
-fn main() {
-    // ...
-}
-```
-
-Either the listed macro is not contained in the imported crate, or it is not
-exported from the given crate.
-
-This could be caused by a typo. Did you misspell the macro's name?
-
-Double-check the names of the macros listed for reexport, and that the crate
-in question exports them.
-
-A working version:
-
-```ignore
-// In some_crate crate:
-#[macro_export]
-macro_rules! eat {
-    ...
-}
-
-#[macro_export]
-macro_rules! drink {
-    ...
-}
-
-// In your_crate:
-#[macro_reexport(eat, drink)]
-extern crate some_crate;
-```
-"##,
-
 }
 
 register_diagnostics! {
diff --git a/src/librustc_metadata/lib.rs b/src/librustc_metadata/lib.rs
index c0fc1a7065c..300c5f0dec7 100644
--- a/src/librustc_metadata/lib.rs
+++ b/src/librustc_metadata/lib.rs
@@ -59,6 +59,5 @@ mod schema;
 pub mod creader;
 pub mod cstore;
 pub mod locator;
-pub mod macro_import;
 
 __build_diagnostic_array! { librustc_metadata, DIAGNOSTICS }
diff --git a/src/librustc_metadata/macro_import.rs b/src/librustc_metadata/macro_import.rs
deleted file mode 100644
index ddc254a16d9..00000000000
--- a/src/librustc_metadata/macro_import.rs
+++ /dev/null
@@ -1,235 +0,0 @@
-// Copyright 2012-2015 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.
-
-//! Used by `rustc` when loading a crate with exported macros.
-
-use std::collections::HashSet;
-use std::env;
-use std::mem;
-
-use creader::{CrateLoader, Macros};
-
-use proc_macro::TokenStream;
-use proc_macro::__internal::Registry;
-use rustc::hir::def_id::DefIndex;
-use rustc::middle::cstore::{LoadedMacro, LoadedMacroKind};
-use rustc::session::Session;
-use rustc::util::nodemap::FnvHashMap;
-use rustc_back::dynamic_lib::DynamicLibrary;
-use syntax::ast;
-use syntax::attr;
-use syntax::parse::token;
-use syntax_ext::deriving::custom::CustomDerive;
-use syntax_pos::{Span, DUMMY_SP};
-
-pub fn call_bad_macro_reexport(a: &Session, b: Span) {
-    span_err!(a, b, E0467, "bad macro reexport");
-}
-
-pub type MacroSelection = FnvHashMap<token::InternedString, Span>;
-
-enum ImportSelection {
-    All(Span),
-    Some(MacroSelection),
-}
-
-pub fn load_macros(loader: &mut CrateLoader, extern_crate: &ast::Item, allows_macros: bool)
-                   -> Vec<LoadedMacro> {
-    loader.load_crate(extern_crate, allows_macros)
-}
-
-impl<'a> CrateLoader<'a> {
-    fn load_crate(&mut self,
-                  extern_crate: &ast::Item,
-                  allows_macros: bool) -> Vec<LoadedMacro> {
-        // Parse the attributes relating to macros.
-        let mut import = ImportSelection::Some(FnvHashMap());
-        let mut reexport = FnvHashMap();
-        let mut no_link = false;
-
-        for attr in &extern_crate.attrs {
-            let mut used = true;
-            match &attr.name()[..] {
-                "macro_use" => {
-                    let names = attr.meta_item_list();
-                    if names.is_none() {
-                        import = ImportSelection::All(attr.span);
-                    } else if let ImportSelection::Some(ref mut sel) = import {
-                        for attr in names.unwrap() {
-                            if let Some(word) = attr.word() {
-                                sel.insert(word.name().clone(), attr.span());
-                            } else {
-                                span_err!(self.sess, attr.span(), E0466, "bad macro import");
-                            }
-                        }
-                    }
-                }
-                "macro_reexport" => {
-                    let names = match attr.meta_item_list() {
-                        Some(names) => names,
-                        None => {
-                            call_bad_macro_reexport(self.sess, attr.span);
-                            continue;
-                        }
-                    };
-
-                    for attr in names {
-                        if let Some(word) = attr.word() {
-                            reexport.insert(word.name().clone(), attr.span());
-                        } else {
-                            call_bad_macro_reexport(self.sess, attr.span());
-                        }
-                    }
-                }
-                "no_link" => no_link = true,
-                _ => used = false,
-            }
-            if used {
-                attr::mark_used(attr);
-            }
-        }
-
-        self.load_macros(extern_crate, allows_macros, import, reexport, no_link)
-    }
-
-    fn load_macros<'b>(&mut self,
-                       vi: &ast::Item,
-                       allows_macros: bool,
-                       import: ImportSelection,
-                       reexport: MacroSelection,
-                       no_link: bool)
-                       -> Vec<LoadedMacro> {
-        if let ImportSelection::Some(ref sel) = import {
-            if sel.is_empty() && reexport.is_empty() {
-                // Make sure we can read macros from `#[no_link]` crates.
-                if no_link {
-                    self.read_macros(vi);
-                }
-                return Vec::new();
-            }
-        }
-
-        if !allows_macros {
-            span_err!(self.sess, vi.span, E0468,
-                      "an `extern crate` loading macros must be at the crate root");
-            return Vec::new();
-        }
-
-        let mut macros = self.read_macros(vi);
-        let mut ret = Vec::new();
-        let mut seen = HashSet::new();
-
-        for mut def in macros.macro_rules.drain(..) {
-            let name = def.ident.name.as_str();
-
-            let import_site = match import {
-                ImportSelection::All(span) => Some(span),
-                ImportSelection::Some(ref sel) => sel.get(&name).cloned()
-            };
-            def.use_locally = import_site.is_some();
-            def.export = reexport.contains_key(&name);
-            def.allow_internal_unstable = attr::contains_name(&def.attrs,
-                                                              "allow_internal_unstable");
-            debug!("load_macros: loaded: {:?}", def);
-            ret.push(LoadedMacro {
-                kind: LoadedMacroKind::Def(def),
-                import_site: import_site.unwrap_or(DUMMY_SP),
-            });
-            seen.insert(name);
-        }
-
-        if let Some(index) = macros.custom_derive_registrar {
-            // custom derive crates currently should not have any macro_rules!
-            // exported macros, enforced elsewhere
-            assert_eq!(ret.len(), 0);
-
-            if let ImportSelection::Some(..) = import {
-                self.sess.span_err(vi.span, "`proc-macro` crates cannot be \
-                                             selectively imported from, must \
-                                             use `#[macro_use]`");
-            }
-
-            if reexport.len() > 0 {
-                self.sess.span_err(vi.span, "`proc-macro` crates cannot be \
-                                             reexported from");
-            }
-
-            self.load_derive_macros(vi.span, &macros, index, &mut ret);
-        }
-
-        if let ImportSelection::Some(sel) = import {
-            for (name, span) in sel {
-                if !seen.contains(&name) {
-                    span_err!(self.sess, span, E0469,
-                              "imported macro not found");
-                }
-            }
-        }
-
-        for (name, span) in &reexport {
-            if !seen.contains(&name) {
-                span_err!(self.sess, *span, E0470,
-                          "reexported macro not found");
-            }
-        }
-
-        return ret
-    }
-
-    /// Load the custom derive macros into the list of macros we're loading.
-    ///
-    /// Note that this is intentionally similar to how we load plugins today,
-    /// but also intentionally separate. Plugins are likely always going to be
-    /// 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,
-                          span: Span,
-                          macros: &Macros,
-                          index: DefIndex,
-                          ret: &mut Vec<LoadedMacro>) {
-        // Make sure the path contains a / or the linker will search for it.
-        let path = macros.dylib.as_ref().unwrap();
-        let path = env::current_dir().unwrap().join(path);
-        let lib = match DynamicLibrary::open(Some(&path)) {
-            Ok(lib) => lib,
-            Err(err) => self.sess.span_fatal(span, &err),
-        };
-
-        let sym = self.sess.generate_derive_registrar_symbol(&macros.svh, index);
-        let registrar = unsafe {
-            let sym = match lib.symbol(&sym) {
-                Ok(f) => f,
-                Err(err) => self.sess.span_fatal(span, &err),
-            };
-            mem::transmute::<*mut u8, fn(&mut Registry)>(sym)
-        };
-
-        struct MyRegistrar<'a>(&'a mut Vec<LoadedMacro>, Span);
-
-        impl<'a> Registry for MyRegistrar<'a> {
-            fn register_custom_derive(&mut self,
-                                      trait_name: &str,
-                                      expand: fn(TokenStream) -> TokenStream) {
-                let derive = Box::new(CustomDerive::new(expand));
-                self.0.push(LoadedMacro {
-                    kind: LoadedMacroKind::CustomDerive(trait_name.to_string(), derive),
-                    import_site: self.1,
-                });
-            }
-        }
-
-        registrar(&mut MyRegistrar(ret, span));
-
-        // 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);
-    }
-}
diff --git a/src/librustc_resolve/build_reduced_graph.rs b/src/librustc_resolve/build_reduced_graph.rs
index 9ed7be5af4e..db86840fd38 100644
--- a/src/librustc_resolve/build_reduced_graph.rs
+++ b/src/librustc_resolve/build_reduced_graph.rs
@@ -21,10 +21,11 @@ use {NameBinding, NameBindingKind, ToNameBinding};
 use Resolver;
 use {resolve_error, resolve_struct_error, ResolutionError};
 
-use rustc::middle::cstore::LoadedMacroKind;
+use rustc::middle::cstore::LoadedMacros;
 use rustc::hir::def::*;
 use rustc::hir::def_id::{CRATE_DEF_INDEX, DefId};
 use rustc::ty;
+use rustc::util::nodemap::FnvHashMap;
 
 use std::cell::Cell;
 use std::rc::Rc;
@@ -58,6 +59,14 @@ impl<'a> ToNameBinding<'a> for (Def, Span, ty::Visibility) {
     }
 }
 
+#[derive(Default, PartialEq, Eq)]
+struct LegacyMacroImports {
+    import_all: Option<Span>,
+    imports: Vec<(Name, Span)>,
+    reexports: Vec<(Name, Span)>,
+    no_link: bool,
+}
+
 impl<'b> Resolver<'b> {
     /// Defines `name` in namespace `ns` of module `parent` to be `def` if it is not yet defined;
     /// otherwise, reports an error.
@@ -193,57 +202,27 @@ impl<'b> Resolver<'b> {
             }
 
             ItemKind::ExternCrate(_) => {
-                // We need to error on `#[macro_use] extern crate` when it isn't at the
-                // crate root, because `$crate` won't work properly.
-                let is_crate_root = self.current_module.parent.is_none();
-                let import_macro = |this: &mut Self, name, ext, span| {
-                    let shadowing = this.builtin_macros.insert(name, Rc::new(ext)).is_some();
-                    if shadowing && expansion != Mark::root() {
-                        let msg = format!("`{}` is already in scope", name);
-                        this.session.struct_span_err(span, &msg)
-                            .note("macro-expanded `#[macro_use]`s may not shadow \
-                                   existing macros (see RFC 1560)")
-                            .emit();
-                    }
-                };
-
-                let mut custom_derive_crate = false;
-                // The mark of the expansion that generates the loaded macros.
-                let mut opt_mark = None;
-                for loaded_macro in self.crate_loader.load_macros(item, is_crate_root) {
-                    let mark = opt_mark.unwrap_or_else(Mark::fresh);
-                    opt_mark = Some(mark);
-                    match loaded_macro.kind {
-                        LoadedMacroKind::Def(mut def) => {
-                            if def.use_locally {
-                                self.macro_names.insert(def.ident.name);
-                                def.body = mark_tts(&def.body, mark);
-                                let ext = macro_rules::compile(&self.session.parse_sess, &def);
-                                import_macro(self, def.ident.name, ext, loaded_macro.import_site);
-                            }
-                            if def.export {
-                                def.id = self.next_node_id();
-                                self.exported_macros.push(def);
-                            }
-                        }
-                        LoadedMacroKind::CustomDerive(name, ext) => {
-                            custom_derive_crate = true;
-                            let ext = SyntaxExtension::CustomDerive(ext);
-                            import_macro(self, token::intern(&name), ext, loaded_macro.import_site);
-                        }
+                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()
+                } {
+                    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");
                     }
                 }
 
-                if custom_derive_crate && !self.session.features.borrow().proc_macro {
-                    let issue = feature_gate::GateIssue::Language;
-                    let msg = "loading custom derive macro crates is experimentally supported";
-                    emit_feature_err(&self.session.parse_sess, "proc_macro", item.span, issue, msg);
-                }
-
-                self.crate_loader.process_item(item, &self.definitions);
+                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)
+                };
 
                 // n.b. we don't need to look at the path option here, because cstore already did
-                if let Some(crate_id) = self.session.cstore.extern_mod_stmt_cnum(item.id) {
+                let 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,
@@ -254,25 +233,21 @@ impl<'b> Resolver<'b> {
                         ..ModuleS::new(Some(parent), ModuleKind::Def(Def::Mod(def_id), name))
                     });
                     self.define(parent, name, TypeNS, (module, sp, vis));
-
-                    if let Some(mark) = opt_mark {
-                        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);
-                    }
-
                     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);
                     self.define(parent, name, TypeNS, (module, sp, vis));
+                    module
+                };
+
+                if let Some(loaded_macros) = loaded_macros {
+                    self.import_extern_crate_macros(
+                        item, module, loaded_macros, legacy_imports, expansion == Mark::root(),
+                    );
                 }
             }
 
@@ -294,7 +269,9 @@ impl<'b> Resolver<'b> {
                 self.current_module = module;
             }
 
-            ItemKind::ForeignMod(..) => self.crate_loader.process_item(item, &self.definitions),
+            ItemKind::ForeignMod(..) => {
+                self.crate_loader.process_item(item, &self.definitions, false);
+            }
 
             // These items live in the value namespace.
             ItemKind::Static(_, m, _) => {
@@ -516,6 +493,93 @@ 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| {
+            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: FnvHashMap<_, _> = 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();
+
+                if let Some(span) = legacy_imports.import_all {
+                    for (&name, &(_, ref ext)) in macros.iter() {
+                        import_macro(self, name, ext.clone(), span);
+                    }
+                } 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");
+                    }
+                }
+            }
+
+            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);
+                    }
+                }
+            }
+        }
+    }
+
     // does this attribute list contain "macro_use"?
     fn contains_macro_use(&mut self, attrs: &[ast::Attribute]) -> bool {
         for attr in attrs {
@@ -539,6 +603,42 @@ impl<'b> Resolver<'b> {
 
         false
     }
+
+    fn legacy_macro_imports(&mut self, attrs: &[ast::Attribute]) -> LegacyMacroImports {
+        let mut imports = LegacyMacroImports::default();
+        for attr in attrs {
+            if attr.check_name("macro_use") {
+                match attr.meta_item_list() {
+                    Some(names) => for attr in names {
+                        if let Some(word) = attr.word() {
+                            imports.imports.push((token::intern(&word.name()), attr.span()));
+                        } else {
+                            span_err!(self.session, attr.span(), E0466, "bad macro import");
+                        }
+                    },
+                    None => imports.import_all = Some(attr.span),
+                }
+            } else if attr.check_name("macro_reexport") {
+                let bad_macro_reexport = |this: &mut Self, span| {
+                    span_err!(this.session, span, E0467, "bad macro reexport");
+                };
+                if let Some(names) = attr.meta_item_list() {
+                    for attr in names {
+                        if let Some(word) = attr.word() {
+                            imports.reexports.push((token::intern(&word.name()), attr.span()));
+                        } else {
+                            bad_macro_reexport(self, attr.span());
+                        }
+                    }
+                } else {
+                    bad_macro_reexport(self, attr.span());
+                }
+            } else if attr.check_name("no_link") {
+                imports.no_link = true;
+            }
+        }
+        imports
+    }
 }
 
 pub struct BuildReducedGraphVisitor<'a, 'b: 'a> {
diff --git a/src/librustc_resolve/diagnostics.rs b/src/librustc_resolve/diagnostics.rs
index f8f90bdb4e7..f2a5aedbb3a 100644
--- a/src/librustc_resolve/diagnostics.rs
+++ b/src/librustc_resolve/diagnostics.rs
@@ -1272,6 +1272,185 @@ impl Foo for i32 {}
 ```
 "##,
 
+E0466: r##"
+Macro import declarations were malformed.
+
+Erroneous code examples:
+
+```compile_fail,E0466
+#[macro_use(a_macro(another_macro))] // error: invalid import declaration
+extern crate core as some_crate;
+
+#[macro_use(i_want = "some_macros")] // error: invalid import declaration
+extern crate core as another_crate;
+```
+
+This is a syntax error at the level of attribute declarations. The proper
+syntax for macro imports is the following:
+
+```ignore
+// In some_crate:
+#[macro_export]
+macro_rules! get_tacos {
+    ...
+}
+
+#[macro_export]
+macro_rules! get_pimientos {
+    ...
+}
+
+// In your crate:
+#[macro_use(get_tacos, get_pimientos)] // It imports `get_tacos` and
+extern crate some_crate;               // `get_pimientos` macros from some_crate
+```
+
+If you would like to import all exported macros, write `macro_use` with no
+arguments.
+"##,
+
+E0467: r##"
+Macro reexport declarations were empty or malformed.
+
+Erroneous code examples:
+
+```compile_fail,E0467
+#[macro_reexport]                    // error: no macros listed for export
+extern crate core as macros_for_good;
+
+#[macro_reexport(fun_macro = "foo")] // error: not a macro identifier
+extern crate core as other_macros_for_good;
+```
+
+This is a syntax error at the level of attribute declarations.
+
+Currently, `macro_reexport` requires at least one macro name to be listed.
+Unlike `macro_use`, listing no names does not reexport all macros from the
+given crate.
+
+Decide which macros you would like to export and list them properly.
+
+These are proper reexport declarations:
+
+```ignore
+#[macro_reexport(some_macro, another_macro)]
+extern crate macros_for_good;
+```
+"##,
+
+E0468: r##"
+A non-root module attempts to import macros from another crate.
+
+Example of erroneous code:
+
+```compile_fail,E0468
+mod foo {
+    #[macro_use(helpful_macro)] // error: must be at crate root to import
+    extern crate core;          //        macros from another crate
+    helpful_macro!(...);
+}
+```
+
+Only `extern crate` imports at the crate root level are allowed to import
+macros.
+
+Either move the macro import to crate root or do without the foreign macros.
+This will work:
+
+```ignore
+#[macro_use(helpful_macro)]
+extern crate some_crate;
+
+mod foo {
+    helpful_macro!(...)
+}
+```
+"##,
+
+E0469: r##"
+A macro listed for import was not found.
+
+Erroneous code example:
+
+```compile_fail,E0469
+#[macro_use(drink, be_merry)] // error: imported macro not found
+extern crate collections;
+
+fn main() {
+    // ...
+}
+```
+
+Either the listed macro is not contained in the imported crate, or it is not
+exported from the given crate.
+
+This could be caused by a typo. Did you misspell the macro's name?
+
+Double-check the names of the macros listed for import, and that the crate
+in question exports them.
+
+A working version would be:
+
+```ignore
+// In some_crate crate:
+#[macro_export]
+macro_rules! eat {
+    ...
+}
+
+#[macro_export]
+macro_rules! drink {
+    ...
+}
+
+// In your crate:
+#[macro_use(eat, drink)]
+extern crate some_crate; //ok!
+```
+"##,
+
+E0470: r##"
+A macro listed for reexport was not found.
+
+Erroneous code example:
+
+```compile_fail,E0470
+#[macro_reexport(drink, be_merry)]
+extern crate collections;
+
+fn main() {
+    // ...
+}
+```
+
+Either the listed macro is not contained in the imported crate, or it is not
+exported from the given crate.
+
+This could be caused by a typo. Did you misspell the macro's name?
+
+Double-check the names of the macros listed for reexport, and that the crate
+in question exports them.
+
+A working version:
+
+```ignore
+// In some_crate crate:
+#[macro_export]
+macro_rules! eat {
+    ...
+}
+
+#[macro_export]
+macro_rules! drink {
+    ...
+}
+
+// In your_crate:
+#[macro_reexport(eat, drink)]
+extern crate some_crate;
+```
+"##,
+
 E0530: r##"
 A binding shadowed something it shouldn't.
 
diff --git a/src/librustc_resolve/macros.rs b/src/librustc_resolve/macros.rs
index 0f42b4520c9..72e5823598e 100644
--- a/src/librustc_resolve/macros.rs
+++ b/src/librustc_resolve/macros.rs
@@ -114,22 +114,22 @@ impl<'a> base::Resolver for Resolver<'a> {
         invocation.expansion.set(visitor.legacy_scope);
     }
 
-    fn add_macro(&mut self, scope: Mark, mut def: ast::MacroDef) {
+    fn add_macro(&mut self, scope: Mark, mut def: ast::MacroDef, export: bool) {
         if &def.ident.name.as_str() == "macro_rules" {
             self.session.span_err(def.span, "user-defined macros may not be named `macro_rules`");
         }
-        if def.use_locally {
-            let invocation = self.invocations[&scope];
-            let binding = self.arenas.alloc_legacy_binding(LegacyBinding {
-                parent: invocation.legacy_scope.get(),
-                name: def.ident.name,
-                ext: Rc::new(macro_rules::compile(&self.session.parse_sess, &def)),
-                span: def.span,
-            });
-            invocation.legacy_scope.set(LegacyScope::Binding(binding));
-            self.macro_names.insert(def.ident.name);
-        }
-        if def.export {
+
+        let invocation = self.invocations[&scope];
+        let binding = self.arenas.alloc_legacy_binding(LegacyBinding {
+            parent: invocation.legacy_scope.get(),
+            name: def.ident.name,
+            ext: Rc::new(macro_rules::compile(&self.session.parse_sess, &def)),
+            span: def.span,
+        });
+        invocation.legacy_scope.set(LegacyScope::Binding(binding));
+        self.macro_names.insert(def.ident.name);
+
+        if export {
             def.id = self.next_node_id();
             self.exported_macros.push(def);
         }
diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs
index 30fc4c3dd80..ae036e66c69 100644
--- a/src/libsyntax/ast.rs
+++ b/src/libsyntax/ast.rs
@@ -2012,8 +2012,6 @@ pub struct MacroDef {
     pub id: NodeId,
     pub span: Span,
     pub imported_from: Option<Ident>,
-    pub export: bool,
-    pub use_locally: bool,
     pub allow_internal_unstable: bool,
     pub body: Vec<TokenTree>,
 }
diff --git a/src/libsyntax/ext/base.rs b/src/libsyntax/ext/base.rs
index f3272960e83..c404c6d1162 100644
--- a/src/libsyntax/ext/base.rs
+++ b/src/libsyntax/ext/base.rs
@@ -519,7 +519,7 @@ pub trait Resolver {
     fn get_module_scope(&mut self, id: ast::NodeId) -> Mark;
 
     fn visit_expansion(&mut self, mark: Mark, expansion: &Expansion);
-    fn add_macro(&mut self, scope: Mark, def: ast::MacroDef);
+    fn add_macro(&mut self, scope: Mark, def: ast::MacroDef, export: bool);
     fn add_ext(&mut self, ident: ast::Ident, ext: Rc<SyntaxExtension>);
     fn add_expansions_at_stmt(&mut self, id: ast::NodeId, macros: Vec<Mark>);
 
@@ -541,7 +541,7 @@ impl Resolver for DummyResolver {
     fn get_module_scope(&mut self, _id: ast::NodeId) -> Mark { Mark::root() }
 
     fn visit_expansion(&mut self, _invoc: Mark, _expansion: &Expansion) {}
-    fn add_macro(&mut self, _scope: Mark, _def: ast::MacroDef) {}
+    fn add_macro(&mut self, _scope: Mark, _def: ast::MacroDef, _export: bool) {}
     fn add_ext(&mut self, _ident: ast::Ident, _ext: Rc<SyntaxExtension>) {}
     fn add_expansions_at_stmt(&mut self, _id: ast::NodeId, _macros: Vec<Mark>) {}
 
diff --git a/src/libsyntax/ext/tt/macro_rules.rs b/src/libsyntax/ext/tt/macro_rules.rs
index 61911e0d3b3..ceca698f479 100644
--- a/src/libsyntax/ext/tt/macro_rules.rs
+++ b/src/libsyntax/ext/tt/macro_rules.rs
@@ -157,14 +157,13 @@ impl IdentMacroExpander for MacroRulesExpander {
               tts: Vec<tokenstream::TokenTree>,
               attrs: Vec<ast::Attribute>)
               -> Box<MacResult> {
+        let export = attr::contains_name(&attrs, "macro_export");
         let def = ast::MacroDef {
             ident: ident,
             id: ast::DUMMY_NODE_ID,
             span: span,
             imported_from: None,
-            use_locally: true,
             body: tts,
-            export: attr::contains_name(&attrs, "macro_export"),
             allow_internal_unstable: attr::contains_name(&attrs, "allow_internal_unstable"),
             attrs: attrs,
         };
@@ -176,7 +175,7 @@ impl IdentMacroExpander for MacroRulesExpander {
             MacEager::items(placeholders::macro_scope_placeholder().make_items())
         };
 
-        cx.resolver.add_macro(cx.current_expansion.mark, def);
+        cx.resolver.add_macro(cx.current_expansion.mark, def, export);
         result
     }
 }