about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/librustc/middle/cstore.rs13
-rw-r--r--src/librustc_metadata/creader.rs136
-rw-r--r--src/librustc_metadata/cstore.rs3
-rw-r--r--src/librustc_metadata/cstore_impl.rs15
-rw-r--r--src/librustc_metadata/decoder.rs11
-rw-r--r--src/librustc_metadata/locator.rs7
-rw-r--r--src/librustc_resolve/build_reduced_graph.rs121
-rw-r--r--src/librustdoc/visit_ast.rs8
-rw-r--r--src/libsyntax_ext/deriving/mod.rs10
-rw-r--r--src/test/compile-fail-fulldeps/proc-macro/auxiliary/derive-a.rs2
-rw-r--r--src/test/compile-fail-fulldeps/proc-macro/feature-gate-4.rs4
-rw-r--r--src/test/compile-fail-fulldeps/proc-macro/no-macro-use-attr.rs (renamed from src/test/compile-fail-fulldeps/proc-macro/cannot-link.rs)7
-rw-r--r--src/test/compile-fail-fulldeps/proc-macro/shadow.rs2
-rw-r--r--src/test/compile-fail/no-link.rs1
14 files changed, 170 insertions, 170 deletions
diff --git a/src/librustc/middle/cstore.rs b/src/librustc/middle/cstore.rs
index db3c7d0450b..3583ccdb97b 100644
--- a/src/librustc/middle/cstore.rs
+++ b/src/librustc/middle/cstore.rs
@@ -34,6 +34,7 @@ use session::Session;
 use session::search_paths::PathKind;
 use util::nodemap::{NodeSet, DefIdMap};
 use std::path::PathBuf;
+use std::rc::Rc;
 use syntax::ast;
 use syntax::attr;
 use syntax::ext::base::SyntaxExtension;
@@ -106,6 +107,11 @@ pub enum InlinedItemRef<'a> {
     ImplItem(DefId, &'a hir::ImplItem)
 }
 
+pub enum LoadedMacro {
+    MacroRules(ast::MacroDef),
+    ProcMacro(Rc<SyntaxExtension>),
+}
+
 #[derive(Copy, Clone, Debug)]
 pub struct ExternCrate {
     /// def_id of an `extern crate` in the current crate that caused
@@ -211,7 +217,7 @@ pub trait CrateStore<'tcx> {
     fn relative_def_path(&self, def: DefId) -> Option<hir_map::DefPath>;
     fn struct_field_names(&self, def: DefId) -> Vec<ast::Name>;
     fn item_children(&self, did: DefId) -> Vec<def::Export>;
-    fn load_macro(&self, did: DefId, sess: &Session) -> ast::MacroDef;
+    fn load_macro(&self, did: DefId, sess: &Session) -> LoadedMacro;
 
     // misc. metadata
     fn maybe_get_item_ast<'a>(&'tcx self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId)
@@ -383,7 +389,7 @@ impl<'tcx> CrateStore<'tcx> for DummyCrateStore {
     }
     fn struct_field_names(&self, def: DefId) -> Vec<ast::Name> { bug!("struct_field_names") }
     fn item_children(&self, did: DefId) -> Vec<def::Export> { bug!("item_children") }
-    fn load_macro(&self, did: DefId, sess: &Session) -> ast::MacroDef { bug!("load_macro") }
+    fn load_macro(&self, did: DefId, sess: &Session) -> LoadedMacro { bug!("load_macro") }
 
     // misc. metadata
     fn maybe_get_item_ast<'a>(&'tcx self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId)
@@ -424,7 +430,6 @@ impl<'tcx> CrateStore<'tcx> for DummyCrateStore {
 }
 
 pub trait CrateLoader {
-    fn process_item(&mut self, item: &ast::Item, defs: &Definitions, load_macros: bool)
-                    -> Vec<(ast::Name, SyntaxExtension)>;
+    fn process_item(&mut self, item: &ast::Item, defs: &Definitions);
     fn postprocess(&mut self, krate: &ast::Crate);
 }
diff --git a/src/librustc_metadata/creader.rs b/src/librustc_metadata/creader.rs
index e53f1a0633b..75944122f5c 100644
--- a/src/librustc_metadata/creader.rs
+++ b/src/librustc_metadata/creader.rs
@@ -35,7 +35,6 @@ use syntax::ast;
 use syntax::abi::Abi;
 use syntax::attr;
 use syntax::ext::base::SyntaxExtension;
-use syntax::feature_gate::{self, emit_feature_err};
 use syntax::parse::token::{InternedString, intern};
 use syntax_pos::{Span, DUMMY_SP};
 use log;
@@ -285,15 +284,13 @@ impl<'a> CrateLoader<'a> {
 
         let cnum_map = self.resolve_crate_deps(root, &crate_root, &metadata, cnum, span, dep_kind);
 
-        if crate_root.macro_derive_registrar.is_some() {
-            self.sess.span_err(span, "crates of the `proc-macro` crate type \
-                                      cannot be linked at runtime");
-        }
-
         let cmeta = Rc::new(cstore::CrateMetadata {
             name: name.to_string(),
             extern_crate: Cell::new(None),
             key_map: metadata.load_key_map(crate_root.index),
+            proc_macros: crate_root.macro_derive_registrar.map(|_| {
+                self.load_derive_macros(&crate_root, dylib.clone().map(|p| p.0), span)
+            }),
             root: crate_root,
             blob: metadata,
             cnum_map: RefCell::new(cnum_map),
@@ -317,34 +314,48 @@ impl<'a> CrateLoader<'a> {
                      hash: Option<&Svh>,
                      span: Span,
                      kind: PathKind,
-                     dep_kind: DepKind)
+                     mut dep_kind: DepKind)
                      -> (CrateNum, Rc<cstore::CrateMetadata>) {
         info!("resolving crate `extern crate {} as {}`", name, ident);
-        let result = match self.existing_match(name, hash, kind) {
-            Some(cnum) => LoadResult::Previous(cnum),
-            None => {
-                info!("falling back to a load");
-                let mut locate_ctxt = locator::Context {
-                    sess: self.sess,
-                    span: span,
-                    ident: ident,
-                    crate_name: name,
-                    hash: hash.map(|a| &*a),
-                    filesearch: self.sess.target_filesearch(kind),
-                    target: &self.sess.target.target,
-                    triple: &self.sess.opts.target_triple,
-                    root: root,
+        let result = if let Some(cnum) = self.existing_match(name, hash, kind) {
+            LoadResult::Previous(cnum)
+        } else {
+            info!("falling back to a load");
+            let mut locate_ctxt = locator::Context {
+                sess: self.sess,
+                span: span,
+                ident: ident,
+                crate_name: name,
+                hash: hash.map(|a| &*a),
+                filesearch: self.sess.target_filesearch(kind),
+                target: &self.sess.target.target,
+                triple: &self.sess.opts.target_triple,
+                root: root,
+                rejected_via_hash: vec![],
+                rejected_via_triple: vec![],
+                rejected_via_kind: vec![],
+                rejected_via_version: vec![],
+                should_match_name: true,
+                is_proc_macro: Some(false),
+            };
+
+            self.load(&mut locate_ctxt).or_else(|| {
+                dep_kind = DepKind::MacrosOnly;
+
+                let mut proc_macro_locator = locator::Context {
+                    target: &self.sess.host,
+                    triple: config::host_triple(),
+                    filesearch: self.sess.host_filesearch(PathKind::Crate),
                     rejected_via_hash: vec![],
                     rejected_via_triple: vec![],
                     rejected_via_kind: vec![],
                     rejected_via_version: vec![],
-                    should_match_name: true,
+                    is_proc_macro: Some(true),
+                    ..locate_ctxt
                 };
-                match self.load(&mut locate_ctxt) {
-                    Some(result) => result,
-                    None => locate_ctxt.report_errs(),
-                }
-            }
+
+                self.load(&mut proc_macro_locator)
+            }).unwrap_or_else(|| locate_ctxt.report_errs())
         };
 
         match result {
@@ -431,6 +442,10 @@ impl<'a> CrateLoader<'a> {
                           dep_kind: DepKind)
                           -> cstore::CrateNumMap {
         debug!("resolving deps of external crate");
+        if crate_root.macro_derive_registrar.is_some() {
+            return cstore::CrateNumMap::new();
+        }
+
         // The map from crate numbers in the crate we're resolving to local crate
         // numbers
         let deps = crate_root.crate_deps.decode(metadata);
@@ -479,6 +494,7 @@ impl<'a> CrateLoader<'a> {
             rejected_via_kind: vec![],
             rejected_via_version: vec![],
             should_match_name: true,
+            is_proc_macro: None,
         };
         let library = self.load(&mut locate_ctxt).or_else(|| {
             if !is_cross {
@@ -525,51 +541,36 @@ impl<'a> CrateLoader<'a> {
     /// implemented as dynamic libraries, but we have a possible future where
     /// custom derive (and other macro-1.1 style features) are implemented via
     /// executables and custom IPC.
-    fn load_derive_macros(&mut self, item: &ast::Item, ekrate: &ExtensionCrate)
-                          -> Option<Vec<(ast::Name, SyntaxExtension)>> {
+    fn load_derive_macros(&mut self, root: &CrateRoot, dylib: Option<PathBuf>, span: Span)
+                          -> Vec<(ast::Name, Rc<SyntaxExtension>)> {
         use std::{env, mem};
         use proc_macro::TokenStream;
         use proc_macro::__internal::Registry;
         use rustc_back::dynamic_lib::DynamicLibrary;
         use syntax_ext::deriving::custom::CustomDerive;
 
-        let root = ekrate.metadata.get_root();
-        let index = match root.macro_derive_registrar {
-            Some(index) => index,
-            None => return None,
-        };
-        if !self.sess.features.borrow().proc_macro {
-            let issue = feature_gate::GateIssue::Language;
-            let msg = "loading custom derive macro crates is experimentally supported";
-            emit_feature_err(&self.sess.parse_sess, "proc_macro", item.span, issue, msg);
-        }
-
-        if ekrate.target_only {
-            let msg = format!("proc-macro crate is not available for triple `{}` (only found {})",
-                               config::host_triple(), self.sess.opts.target_triple);
-            self.sess.span_fatal(item.span, &msg);
-        }
-        let path = match ekrate.dylib.clone() {
+        let path = match dylib {
             Some(dylib) => dylib,
-            None => span_bug!(item.span, "proc-macro crate not dylib"),
+            None => span_bug!(span, "proc-macro crate not dylib"),
         };
         // Make sure the path contains a / or the linker will search for it.
         let path = env::current_dir().unwrap().join(path);
         let lib = match DynamicLibrary::open(Some(&path)) {
             Ok(lib) => lib,
-            Err(err) => self.sess.span_fatal(item.span, &err),
+            Err(err) => self.sess.span_fatal(span, &err),
         };
 
-        let sym = self.sess.generate_derive_registrar_symbol(&root.hash, index);
+        let sym = self.sess.generate_derive_registrar_symbol(&root.hash,
+                                                             root.macro_derive_registrar.unwrap());
         let registrar = unsafe {
             let sym = match lib.symbol(&sym) {
                 Ok(f) => f,
-                Err(err) => self.sess.span_fatal(item.span, &err),
+                Err(err) => self.sess.span_fatal(span, &err),
             };
             mem::transmute::<*mut u8, fn(&mut Registry)>(sym)
         };
 
-        struct MyRegistrar(Vec<(ast::Name, SyntaxExtension)>);
+        struct MyRegistrar(Vec<(ast::Name, Rc<SyntaxExtension>)>);
 
         impl Registry for MyRegistrar {
             fn register_custom_derive(&mut self,
@@ -580,7 +581,7 @@ impl<'a> CrateLoader<'a> {
                 let derive = SyntaxExtension::CustomDerive(
                     Box::new(CustomDerive::new(expand, attrs))
                 );
-                self.0.push((intern(trait_name), derive));
+                self.0.push((intern(trait_name), Rc::new(derive)));
             }
         }
 
@@ -590,7 +591,7 @@ impl<'a> CrateLoader<'a> {
         // Intentionally leak the dynamic library. We can't ever unload it
         // since the library can make things that will live arbitrarily long.
         mem::forget(lib);
-        Some(my_registrar.0)
+        my_registrar.0
     }
 
     /// Look for a plugin registrar. Returns library path, crate
@@ -928,35 +929,14 @@ impl<'a> middle::cstore::CrateLoader for CrateLoader<'a> {
         self.register_statically_included_foreign_items();
     }
 
-    fn process_item(&mut self, item: &ast::Item, definitions: &Definitions, load_macros: bool)
-                    -> Vec<(ast::Name, SyntaxExtension)> {
+    fn process_item(&mut self, item: &ast::Item, definitions: &Definitions) {
         match item.node {
             ast::ItemKind::ExternCrate(_) => {}
-            ast::ItemKind::ForeignMod(ref fm) => {
-                self.process_foreign_mod(item, fm);
-                return Vec::new();
-            }
-            _ => return Vec::new(),
+            ast::ItemKind::ForeignMod(ref fm) => return self.process_foreign_mod(item, fm),
+            _ => return,
         }
 
         let info = self.extract_crate_info(item).unwrap();
-        if load_macros {
-            let ekrate = self.read_extension_crate(item.span, &info);
-
-            // If this is a proc-macro crate, return here to avoid registering.
-            if let Some(custom_derives) = self.load_derive_macros(item, &ekrate) {
-                return custom_derives;
-            }
-
-            // Register crate now to avoid double-reading metadata
-            if let PMDSource::Owned(lib) = ekrate.metadata {
-                if ekrate.target_only || config::host_triple() == self.sess.opts.target_triple {
-                    let ExternCrateInfo { ref ident, ref name, dep_kind, .. } = info;
-                    self.register_crate(&None, ident, name, item.span, lib, dep_kind);
-                }
-            }
-        }
-
         let (cnum, ..) = self.resolve_crate(
             &None, &info.ident, &info.name, None, item.span, PathKind::Crate, info.dep_kind,
         );
@@ -968,7 +948,5 @@ impl<'a> middle::cstore::CrateLoader for CrateLoader<'a> {
             ExternCrate { def_id: def_id, span: item.span, direct: true, path_len: len };
         self.update_extern_crate(cnum, extern_crate, &mut FxHashSet());
         self.cstore.add_extern_mod_stmt_cnum(info.id, cnum);
-
-        Vec::new()
     }
 }
diff --git a/src/librustc_metadata/cstore.rs b/src/librustc_metadata/cstore.rs
index 10e86c427a8..8c95e4aec0a 100644
--- a/src/librustc_metadata/cstore.rs
+++ b/src/librustc_metadata/cstore.rs
@@ -28,6 +28,7 @@ use std::rc::Rc;
 use std::path::PathBuf;
 use flate::Bytes;
 use syntax::{ast, attr};
+use syntax::ext::base::SyntaxExtension;
 use syntax_pos;
 
 pub use rustc::middle::cstore::{NativeLibraryKind, LinkagePreference};
@@ -80,6 +81,8 @@ pub struct CrateMetadata {
 
     pub dep_kind: Cell<DepKind>,
     pub source: CrateSource,
+
+    pub proc_macros: Option<Vec<(ast::Name, Rc<SyntaxExtension>)>>,
 }
 
 pub struct CachedInlinedItem {
diff --git a/src/librustc_metadata/cstore_impl.rs b/src/librustc_metadata/cstore_impl.rs
index 3113bfcb5b4..83de8acdb60 100644
--- a/src/librustc_metadata/cstore_impl.rs
+++ b/src/librustc_metadata/cstore_impl.rs
@@ -14,7 +14,7 @@ use locator;
 use schema;
 
 use rustc::middle::cstore::{InlinedItem, CrateStore, CrateSource, DepKind, ExternCrate};
-use rustc::middle::cstore::{NativeLibraryKind, LinkMeta, LinkagePreference};
+use rustc::middle::cstore::{NativeLibraryKind, LinkMeta, LinkagePreference, LoadedMacro};
 use rustc::hir::def::{self, Def};
 use rustc::middle::lang_items;
 use rustc::session::Session;
@@ -353,8 +353,13 @@ impl<'tcx> CrateStore<'tcx> for cstore::CStore {
         result
     }
 
-    fn load_macro(&self, id: DefId, sess: &Session) -> ast::MacroDef {
-        let (name, def) = self.get_crate_data(id.krate).get_macro(id.index);
+    fn load_macro(&self, id: DefId, sess: &Session) -> LoadedMacro {
+        let data = self.get_crate_data(id.krate);
+        if let Some(ref proc_macros) = data.proc_macros {
+            return LoadedMacro::ProcMacro(proc_macros[id.index.as_usize()].1.clone());
+        }
+
+        let (name, def) = data.get_macro(id.index);
         let source_name = format!("<{} macros>", name);
 
         // NB: Don't use parse_tts_from_source_str because it parses with quote_depth > 0.
@@ -379,7 +384,7 @@ impl<'tcx> CrateStore<'tcx> for cstore::CStore {
         sess.imported_macro_spans.borrow_mut()
             .insert(local_span, (def.name.as_str().to_string(), def.span));
 
-        ast::MacroDef {
+        LoadedMacro::MacroRules(ast::MacroDef {
             ident: ast::Ident::with_empty_ctxt(def.name),
             id: ast::DUMMY_NODE_ID,
             span: local_span,
@@ -387,7 +392,7 @@ impl<'tcx> CrateStore<'tcx> for cstore::CStore {
             allow_internal_unstable: attr::contains_name(&def.attrs, "allow_internal_unstable"),
             attrs: def.attrs,
             body: body,
-        }
+        })
     }
 
     fn maybe_get_item_ast<'a>(&'tcx self,
diff --git a/src/librustc_metadata/decoder.rs b/src/librustc_metadata/decoder.rs
index 64a90d56d55..78cde4c2fcb 100644
--- a/src/librustc_metadata/decoder.rs
+++ b/src/librustc_metadata/decoder.rs
@@ -691,7 +691,15 @@ impl<'a, 'tcx> CrateMetadata {
     pub fn each_child_of_item<F>(&self, id: DefIndex, mut callback: F)
         where F: FnMut(def::Export)
     {
-        let macros_only = self.dep_kind.get() == DepKind::MacrosOnly;
+        if let Some(ref proc_macros) = self.proc_macros {
+            for (id, &(name, _)) in proc_macros.iter().enumerate() {
+                callback(def::Export {
+                    name: name,
+                    def: Def::Macro(DefId { krate: self.cnum, index: DefIndex::new(id), }),
+                })
+            }
+            return
+        }
 
         // Find the item.
         let item = match self.maybe_entry(id) {
@@ -700,6 +708,7 @@ impl<'a, 'tcx> CrateMetadata {
         };
 
         // Iterate over all children.
+        let macros_only = self.dep_kind.get() == DepKind::MacrosOnly;
         for child_index in item.children.decode(self) {
             if macros_only {
                 continue
diff --git a/src/librustc_metadata/locator.rs b/src/librustc_metadata/locator.rs
index c31b209768c..b6b347fff5f 100644
--- a/src/librustc_metadata/locator.rs
+++ b/src/librustc_metadata/locator.rs
@@ -262,6 +262,7 @@ pub struct Context<'a> {
     pub rejected_via_kind: Vec<CrateMismatch>,
     pub rejected_via_version: Vec<CrateMismatch>,
     pub should_match_name: bool,
+    pub is_proc_macro: Option<bool>,
 }
 
 pub struct ArchiveMetadata {
@@ -623,6 +624,12 @@ impl<'a> Context<'a> {
 
     fn crate_matches(&mut self, metadata: &MetadataBlob, libpath: &Path) -> Option<Svh> {
         let root = metadata.get_root();
+        if let Some(is_proc_macro) = self.is_proc_macro {
+            if root.macro_derive_registrar.is_some() != is_proc_macro {
+                return None;
+            }
+        }
+
         let rustc_version = rustc_version();
         if root.rustc_version != rustc_version {
             info!("Rejecting via version: expected {} got {}",
diff --git a/src/librustc_resolve/build_reduced_graph.rs b/src/librustc_resolve/build_reduced_graph.rs
index 0833f85c1f6..99e7a9042c0 100644
--- a/src/librustc_resolve/build_reduced_graph.rs
+++ b/src/librustc_resolve/build_reduced_graph.rs
@@ -21,9 +21,9 @@ use Namespace::{self, TypeNS, ValueNS, MacroNS};
 use ResolveResult::Success;
 use {resolve_error, resolve_struct_error, ResolutionError};
 
-use rustc::middle::cstore::DepKind;
+use rustc::middle::cstore::{DepKind, LoadedMacro};
 use rustc::hir::def::*;
-use rustc::hir::def_id::{CrateNum, CRATE_DEF_INDEX, DefId, DefIndex, BUILTIN_MACROS_CRATE};
+use rustc::hir::def_id::{CrateNum, CRATE_DEF_INDEX, DefId};
 use rustc::ty;
 
 use std::cell::Cell;
@@ -62,7 +62,6 @@ struct LegacyMacroImports {
     import_all: Option<Span>,
     imports: Vec<(Name, Span)>,
     reexports: Vec<(Name, Span)>,
-    no_link: bool,
 }
 
 impl<'b> Resolver<'b> {
@@ -213,59 +212,26 @@ impl<'b> Resolver<'b> {
             }
 
             ItemKind::ExternCrate(_) => {
-                let legacy_imports = self.legacy_macro_imports(&item.attrs);
-                // `#[macro_use]` and `#[macro_reexport]` are only allowed at the crate root.
-                if self.current_module.parent.is_some() && {
-                    legacy_imports.import_all.is_some() || !legacy_imports.imports.is_empty() ||
-                    !legacy_imports.reexports.is_empty()
-                } {
-                    span_err!(self.session, item.span, E0468,
-                              "an `extern crate` loading macros must be at the crate root");
-                }
-
-                let load_macros = legacy_imports != LegacyMacroImports::default();
-                let proc_macros =
-                    self.crate_loader.process_item(item, &self.definitions, load_macros);
+                self.crate_loader.process_item(item, &self.definitions);
 
                 // n.b. we don't need to look at the path option here, because cstore already did
-                let crate_id = self.session.cstore.extern_mod_stmt_cnum(item.id);
-                let module = if let Some(crate_id) = crate_id {
-                    let module = self.get_extern_crate_root(crate_id);
-                    let binding = (module, sp, ty::Visibility::Public).to_name_binding();
-                    let binding = self.arenas.alloc_name_binding(binding);
-                    let directive = self.arenas.alloc_import_directive(ImportDirective {
-                        id: item.id,
-                        parent: parent,
-                        imported_module: Cell::new(Some(module)),
-                        subclass: ImportDirectiveSubclass::ExternCrate,
-                        span: item.span,
-                        module_path: Vec::new(),
-                        vis: Cell::new(vis),
-                    });
-                    let imported_binding = self.import(binding, directive);
-                    self.define(parent, name, TypeNS, imported_binding);
-                    self.populate_module_if_necessary(module);
-                    module
-                } else {
-                    // Define a module and populate it with proc macros.
-                    let module_kind =
-                        ModuleKind::Def(Def::Mod(self.definitions.local_def_id(item.id)), name);
-                    let module = self.arenas.alloc_module(ModuleS::new(None, module_kind));
-                    self.define(parent, name, TypeNS, (module, sp, vis));
-                    for (name, ext) in proc_macros {
-                        let def_id = DefId {
-                            krate: BUILTIN_MACROS_CRATE,
-                            index: DefIndex::new(self.macro_map.len()),
-                        };
-                        self.macro_map.insert(def_id, Rc::new(ext));
-                        let vis = ty::Visibility::Public;
-                        self.define(module, name, MacroNS, (Def::Macro(def_id), DUMMY_SP, vis));
-                    }
-                    module
-                };
-
-                let allow_shadowing = expansion == Mark::root();
-                self.process_legacy_macro_imports(module, legacy_imports, allow_shadowing);
+                let crate_id = self.session.cstore.extern_mod_stmt_cnum(item.id).unwrap();
+                let module = self.get_extern_crate_root(crate_id);
+                let binding = (module, sp, ty::Visibility::Public).to_name_binding();
+                let binding = self.arenas.alloc_name_binding(binding);
+                let directive = self.arenas.alloc_import_directive(ImportDirective {
+                    id: item.id,
+                    parent: parent,
+                    imported_module: Cell::new(Some(module)),
+                    subclass: ImportDirectiveSubclass::ExternCrate,
+                    span: item.span,
+                    module_path: Vec::new(),
+                    vis: Cell::new(vis),
+                });
+                let imported_binding = self.import(binding, directive);
+                self.define(parent, name, TypeNS, imported_binding);
+                self.populate_module_if_necessary(module);
+                self.process_legacy_macro_imports(item, module, expansion);
             }
 
             ItemKind::Mod(..) if item.ident == keywords::Invalid.ident() => {} // Crate root
@@ -286,9 +252,7 @@ impl<'b> Resolver<'b> {
                 self.current_module = module;
             }
 
-            ItemKind::ForeignMod(..) => {
-                self.crate_loader.process_item(item, &self.definitions, false);
-            }
+            ItemKind::ForeignMod(..) => self.crate_loader.process_item(item, &self.definitions),
 
             // These items live in the value namespace.
             ItemKind::Static(_, m, _) => {
@@ -431,10 +395,10 @@ impl<'b> Resolver<'b> {
         let name = child.name;
         let def = child.def;
         let def_id = def.def_id();
-        let vis = if parent.is_trait() {
-            ty::Visibility::Public
-        } else {
-            self.session.cstore.visibility(def_id)
+        let vis = match def {
+            Def::Macro(..) => ty::Visibility::Public,
+            _ if parent.is_trait() => ty::Visibility::Public,
+            _ => self.session.cstore.visibility(def_id),
         };
 
         match def {
@@ -524,7 +488,11 @@ impl<'b> Resolver<'b> {
             return ext.clone();
         }
 
-        let mut macro_rules = self.session.cstore.load_macro(def_id, &self.session);
+        let mut macro_rules = match self.session.cstore.load_macro(def_id, &self.session) {
+            LoadedMacro::MacroRules(macro_rules) => macro_rules,
+            LoadedMacro::ProcMacro(ext) => return ext,
+        };
+
         let mark = Mark::fresh();
         let invocation = self.arenas.alloc_invocation_data(InvocationData {
             module: Cell::new(self.get_extern_crate_root(def_id.krate)),
@@ -561,10 +529,23 @@ impl<'b> Resolver<'b> {
         }
     }
 
-    fn process_legacy_macro_imports(&mut self,
-                                    module: Module<'b>,
-                                    legacy_imports: LegacyMacroImports,
-                                    allow_shadowing: bool) {
+    fn process_legacy_macro_imports(&mut self, item: &Item, module: Module<'b>, expansion: Mark) {
+        let allow_shadowing = expansion == Mark::root();
+        let legacy_imports = self.legacy_macro_imports(&item.attrs);
+        let cnum = module.def_id().unwrap().krate;
+
+        // `#[macro_use]` and `#[macro_reexport]` are only allowed at the crate root.
+        if self.current_module.parent.is_some() && legacy_imports != LegacyMacroImports::default() {
+            span_err!(self.session, item.span, E0468,
+                      "an `extern crate` loading macros must be at the crate root");
+        } else if self.session.cstore.dep_kind(cnum) == DepKind::MacrosOnly &&
+                  legacy_imports == LegacyMacroImports::default() {
+            let msg = "custom derive crates and `#[no_link]` crates have no effect without \
+                       `#[macro_use]`";
+            self.session.span_warn(item.span, msg);
+            self.used_crates.insert(cnum); // Avoid the normal unused extern crate warning
+        }
+
         if let Some(span) = legacy_imports.import_all {
             module.for_each_child(|name, ns, binding| if ns == MacroNS {
                 self.legacy_import_macro(name, binding.def(), span, allow_shadowing);
@@ -583,11 +564,7 @@ impl<'b> Resolver<'b> {
             self.used_crates.insert(module.def_id().unwrap().krate);
             let result = self.resolve_name_in_module(module, name, MacroNS, false, None);
             if let Success(binding) = result {
-                let def = binding.def();
-                if let Def::Macro(DefId { krate: BUILTIN_MACROS_CRATE, .. }) = def {
-                    self.session.span_err(span, "`proc-macro` crates cannot be reexported from");
-                }
-                self.macro_exports.push(Export { name: name, def: def });
+                self.macro_exports.push(Export { name: name, def: binding.def() });
             } else {
                 span_err!(self.session, span, E0470, "reexported macro not found");
             }
@@ -647,8 +624,6 @@ impl<'b> Resolver<'b> {
                 } else {
                     bad_macro_reexport(self, attr.span());
                 }
-            } else if attr.check_name("no_link") {
-                imports.no_link = true;
             }
         }
         imports
diff --git a/src/librustdoc/visit_ast.rs b/src/librustdoc/visit_ast.rs
index b91d71198e8..d0407162793 100644
--- a/src/librustdoc/visit_ast.rs
+++ b/src/librustdoc/visit_ast.rs
@@ -21,6 +21,7 @@ use syntax_pos::Span;
 use rustc::hir::map as hir_map;
 use rustc::hir::def::Def;
 use rustc::hir::def_id::LOCAL_CRATE;
+use rustc::middle::cstore::LoadedMacro;
 use rustc::middle::privacy::AccessLevel;
 use rustc::util::nodemap::FxHashSet;
 
@@ -198,7 +199,12 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> {
                     if def_id.krate == LOCAL_CRATE {
                         continue // These are `krate.exported_macros`, handled in `self.visit()`.
                     }
-                    let def = self.cx.sess().cstore.load_macro(def_id, self.cx.sess());
+                    let def = match self.cx.sess().cstore.load_macro(def_id, self.cx.sess()) {
+                        LoadedMacro::MacroRules(macro_rules) => macro_rules,
+                        // FIXME(jseyfried): document proc macro reexports
+                        LoadedMacro::ProcMacro(..) => continue,
+                    };
+
                     // FIXME(jseyfried) merge with `self.visit_macro()`
                     let matchers = def.body.chunks(4).map(|arm| arm[0].get_span()).collect();
                     om.macros.push(Macro {
diff --git a/src/libsyntax_ext/deriving/mod.rs b/src/libsyntax_ext/deriving/mod.rs
index c2bfead5686..b1d473820f7 100644
--- a/src/libsyntax_ext/deriving/mod.rs
+++ b/src/libsyntax_ext/deriving/mod.rs
@@ -12,10 +12,10 @@
 
 use syntax::ast::{self, MetaItem};
 use syntax::attr::HasAttrs;
+use syntax::codemap;
 use syntax::ext::base::{Annotatable, ExtCtxt, SyntaxExtension};
 use syntax::ext::build::AstBuilder;
-use syntax::feature_gate;
-use syntax::codemap;
+use syntax::feature_gate::{self, emit_feature_err};
 use syntax::parse::token::{intern, intern_and_get_ident};
 use syntax::ptr::P;
 use syntax_pos::Span;
@@ -220,6 +220,12 @@ pub fn expand_derive(cx: &mut ExtCtxt,
                                  .filter(|&(_, ref name)| !is_builtin_trait(&name.name().unwrap()))
                                  .next();
     if let Some((i, titem)) = macros_11_derive {
+        if !cx.ecfg.features.unwrap().proc_macro {
+            let issue = feature_gate::GateIssue::Language;
+            let msg = "custom derive macros are experimentally supported";
+            emit_feature_err(cx.parse_sess, "proc_macro", titem.span, issue, msg);
+        }
+
         let tname = ast::Ident::with_empty_ctxt(intern(&titem.name().unwrap()));
         let path = ast::Path::from_ident(titem.span, tname);
         let ext = cx.resolver.resolve_macro(cx.current_expansion.mark, &path, false).unwrap();
diff --git a/src/test/compile-fail-fulldeps/proc-macro/auxiliary/derive-a.rs b/src/test/compile-fail-fulldeps/proc-macro/auxiliary/derive-a.rs
index 4aa4238611d..8d26207273d 100644
--- a/src/test/compile-fail-fulldeps/proc-macro/auxiliary/derive-a.rs
+++ b/src/test/compile-fail-fulldeps/proc-macro/auxiliary/derive-a.rs
@@ -21,5 +21,5 @@ use proc_macro::TokenStream;
 
 #[proc_macro_derive(A)]
 pub fn derive_a(input: TokenStream) -> TokenStream {
-    input
+    "".parse().unwrap()
 }
diff --git a/src/test/compile-fail-fulldeps/proc-macro/feature-gate-4.rs b/src/test/compile-fail-fulldeps/proc-macro/feature-gate-4.rs
index 0fdd13bc30c..6a8fcdf4ab7 100644
--- a/src/test/compile-fail-fulldeps/proc-macro/feature-gate-4.rs
+++ b/src/test/compile-fail-fulldeps/proc-macro/feature-gate-4.rs
@@ -12,4 +12,6 @@
 
 #[macro_use]
 extern crate derive_a;
-//~^ ERROR: loading custom derive macro crates is experimentally supported
+
+#[derive(A)] //~ ERROR custom derive macros are experimentally supported
+struct S;
diff --git a/src/test/compile-fail-fulldeps/proc-macro/cannot-link.rs b/src/test/compile-fail-fulldeps/proc-macro/no-macro-use-attr.rs
index f6f1be37fc3..f61b8b4073b 100644
--- a/src/test/compile-fail-fulldeps/proc-macro/cannot-link.rs
+++ b/src/test/compile-fail-fulldeps/proc-macro/no-macro-use-attr.rs
@@ -10,7 +10,10 @@
 
 // aux-build:derive-a.rs
 
+#![feature(rustc_attrs)]
+
 extern crate derive_a;
-//~^ ERROR: crates of the `proc-macro` crate type cannot be linked at runtime
+//~^ WARN custom derive crates and `#[no_link]` crates have no effect without `#[macro_use]`
 
-fn main() {}
+#[rustc_error]
+fn main() {} //~ ERROR compilation successful
diff --git a/src/test/compile-fail-fulldeps/proc-macro/shadow.rs b/src/test/compile-fail-fulldeps/proc-macro/shadow.rs
index a04756ca19b..dc828fbf7d1 100644
--- a/src/test/compile-fail-fulldeps/proc-macro/shadow.rs
+++ b/src/test/compile-fail-fulldeps/proc-macro/shadow.rs
@@ -15,6 +15,6 @@
 #[macro_use]
 extern crate derive_a;
 #[macro_use]
-extern crate derive_a; //~ ERROR `derive_a` has already been defined
+extern crate derive_a; //~ ERROR `derive_a` has already been imported
 
 fn main() {}
diff --git a/src/test/compile-fail/no-link.rs b/src/test/compile-fail/no-link.rs
index 5ea07403cf7..c4737a37399 100644
--- a/src/test/compile-fail/no-link.rs
+++ b/src/test/compile-fail/no-link.rs
@@ -12,6 +12,7 @@
 
 #[no_link]
 extern crate empty_struct;
+//~^ WARN custom derive crates and `#[no_link]` crates have no effect without `#[macro_use]`
 
 fn main() {
     empty_struct::XEmpty1; //~ ERROR unresolved name