diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/librustc/middle/cstore.rs | 13 | ||||
| -rw-r--r-- | src/librustc_metadata/creader.rs | 136 | ||||
| -rw-r--r-- | src/librustc_metadata/cstore.rs | 3 | ||||
| -rw-r--r-- | src/librustc_metadata/cstore_impl.rs | 15 | ||||
| -rw-r--r-- | src/librustc_metadata/decoder.rs | 11 | ||||
| -rw-r--r-- | src/librustc_metadata/locator.rs | 7 | ||||
| -rw-r--r-- | src/librustc_resolve/build_reduced_graph.rs | 121 | ||||
| -rw-r--r-- | src/librustdoc/visit_ast.rs | 8 | ||||
| -rw-r--r-- | src/libsyntax_ext/deriving/mod.rs | 10 | ||||
| -rw-r--r-- | src/test/compile-fail-fulldeps/proc-macro/auxiliary/derive-a.rs | 2 | ||||
| -rw-r--r-- | src/test/compile-fail-fulldeps/proc-macro/feature-gate-4.rs | 4 | ||||
| -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.rs | 2 | ||||
| -rw-r--r-- | src/test/compile-fail/no-link.rs | 1 |
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 |
