about summary refs log tree commit diff
diff options
context:
space:
mode:
authorJeffrey Seyfried <jeffrey.seyfried@gmail.com>2016-10-17 07:46:25 +0000
committerJeffrey Seyfried <jeffrey.seyfried@gmail.com>2016-10-24 00:43:12 +0000
commite4baeaa30da3736d9a85f24509319d7148c2feea (patch)
tree1b17a11b3a47a93413e1578d76512e4fd73718df
parent4845adde360c306624faa3305ea95f95cd11e2b4 (diff)
downloadrust-e4baeaa30da3736d9a85f24509319d7148c2feea.tar.gz
rust-e4baeaa30da3736d9a85f24509319d7148c2feea.zip
Import macros in `resolve` instead of in `metadata::macro_import`.
-rw-r--r--src/librustc/middle/cstore.rs15
-rw-r--r--src/librustc_metadata/creader.rs77
-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.rs215
-rw-r--r--src/librustc_resolve/diagnostics.rs179
7 files changed, 410 insertions, 491 deletions
diff --git a/src/librustc/middle/cstore.rs b/src/librustc/middle/cstore.rs
index b54862ae0ad..4e0e561f661 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,13 @@ 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 LoadedMacroKind {
-    Def(ast::MacroDef),
-    CustomDerive(String, Box<MultiItemModifier>),
+pub enum LoadedMacros {
+    MacroRules(Vec<ast::MacroDef>),
+    ProcMacros(Vec<(ast::Name, SyntaxExtension)>),
 }
 
 pub trait CrateLoader {
-    fn load_macros(&mut self, extern_crate: &ast::Item, allows_macros: bool) -> Vec<LoadedMacro>;
+    fn load_macros(&mut self, extern_crate: &ast::Item) -> LoadedMacros;
     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 7ae3f6f8107..ad2a7afbc8b 100644
--- a/src/librustc_metadata/creader.rs
+++ b/src/librustc_metadata/creader.rs
@@ -12,12 +12,11 @@
 
 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;
@@ -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;
 
@@ -591,15 +591,14 @@ impl<'a> CrateLoader<'a> {
 
             ret.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()
@@ -639,6 +638,58 @@ impl<'a> CrateLoader<'a> {
         return ret
     }
 
+    /// 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, span: Span, macros: &Macros, index: DefIndex)
+                          -> 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 = 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(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));
+            }
+        }
+
+        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
     /// SVH and DefIndex of the registrar function.
     pub fn find_plugin_registrar(&mut self, span: Span, name: &str)
@@ -1030,7 +1081,17 @@ impl<'a> middle::cstore::CrateLoader for CrateLoader<'a> {
         }
     }
 
-    fn load_macros(&mut self, extern_crate: &ast::Item, allows_macros: bool) -> Vec<LoadedMacro> {
-        macro_import::load_macros(self, extern_crate, allows_macros)
+    fn load_macros(&mut self, extern_crate: &ast::Item) -> LoadedMacros {
+        let macros = self.read_macros(extern_crate);
+
+        if let Some(index) = macros.custom_derive_registrar {
+            // custom derive crates currently should not have any macro_rules!
+            // exported macros, enforced elsewhere
+            assert_eq!(macros.macro_rules.len(), 0);
+            let custom_derives = self.load_derive_macros(extern_crate.span, &macros, index);
+            LoadedMacros::ProcMacros(custom_derives)
+        } else {
+            LoadedMacros::MacroRules(macros.macro_rules)
+        }
     }
 }
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..69210b98e3a 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,28 @@ 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);
-                }
+                let loaded_macros = if legacy_imports != LegacyMacroImports::default() {
+                    Some(self.crate_loader.load_macros(item))
+                } else {
+                    None
+                };
 
                 self.crate_loader.process_item(item, &self.definitions);
-
                 // n.b. we don't need to look at the path option here, because cstore already did
-                if let Some(crate_id) = self.session.cstore.extern_mod_stmt_cnum(item.id) {
+                let 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 +234,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(),
+                    );
                 }
             }
 
@@ -516,6 +492,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 +602,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.