diff --git a/src/librustc/hir/def.rs b/src/librustc/hir/def.rs index 8b9cee1d2f6d6..044e36e5c9cd4 100644 --- a/src/librustc/hir/def.rs +++ b/src/librustc/hir/def.rs @@ -52,6 +52,9 @@ pub enum Def { ast::NodeId), // expr node that creates the closure Label(ast::NodeId), + // Macro namespace + Macro(DefId), + // Both namespaces Err, } @@ -133,7 +136,7 @@ impl Def { Def::Variant(id) | Def::VariantCtor(id, ..) | Def::Enum(id) | Def::TyAlias(id) | Def::AssociatedTy(id) | Def::TyParam(id) | Def::Struct(id) | Def::StructCtor(id, ..) | Def::Union(id) | Def::Trait(id) | Def::Method(id) | Def::Const(id) | - Def::AssociatedConst(id) | Def::Local(id) | Def::Upvar(id, ..) => { + Def::AssociatedConst(id) | Def::Local(id) | Def::Upvar(id, ..) | Def::Macro(id) => { id } @@ -173,6 +176,7 @@ impl Def { Def::Upvar(..) => "closure capture", Def::Label(..) => "label", Def::SelfTy(..) => "self type", + Def::Macro(..) => "macro", Def::Err => "unresolved item", } } diff --git a/src/librustc/hir/def_id.rs b/src/librustc/hir/def_id.rs index 399243551d651..d3771b1755b16 100644 --- a/src/librustc/hir/def_id.rs +++ b/src/librustc/hir/def_id.rs @@ -34,6 +34,10 @@ impl Idx for CrateNum { /// LOCAL_CRATE in their DefId. pub const LOCAL_CRATE: CrateNum = CrateNum(0); +/// Virtual crate for builtin macros +// FIXME(jseyfried): this is also used for custom derives until proc-macro crates get `CrateNum`s. +pub const BUILTIN_MACROS_CRATE: CrateNum = CrateNum(!0); + impl CrateNum { pub fn new(x: usize) -> CrateNum { assert!(x < (u32::MAX as usize)); diff --git a/src/librustc/hir/map/collector.rs b/src/librustc/hir/map/collector.rs index e23a721da08a6..04fcf7e84508e 100644 --- a/src/librustc/hir/map/collector.rs +++ b/src/librustc/hir/map/collector.rs @@ -226,4 +226,8 @@ impl<'ast> Visitor<'ast> for NodeCollector<'ast> { fn visit_lifetime(&mut self, lifetime: &'ast Lifetime) { self.insert(lifetime.id, NodeLifetime(lifetime)); } + + fn visit_macro_def(&mut self, macro_def: &'ast MacroDef) { + self.insert_entry(macro_def.id, NotPresent); + } } diff --git a/src/librustc/middle/cstore.rs b/src/librustc/middle/cstore.rs index a1f226ab11d80..db3c7d0450b38 100644 --- a/src/librustc/middle/cstore.rs +++ b/src/librustc/middle/cstore.rs @@ -61,7 +61,18 @@ pub struct LinkMeta { pub struct CrateSource { pub dylib: Option<(PathBuf, PathKind)>, pub rlib: Option<(PathBuf, PathKind)>, - pub cnum: CrateNum, +} + +#[derive(RustcEncodable, RustcDecodable, Copy, Clone, Ord, PartialOrd, Eq, PartialEq, Debug)] +pub enum DepKind { + /// A dependency that is only used for its macros. + MacrosOnly, + /// A dependency that is always injected into the dependency list and so + /// doesn't need to be linked to an rlib, e.g. the injected allocator. + Implicit, + /// A dependency that is required by an rlib version of this crate. + /// Ordinary `extern crate`s result in `Explicit` dependencies. + Explicit, } #[derive(Copy, Debug, PartialEq, Clone, RustcEncodable, RustcDecodable)] @@ -170,10 +181,10 @@ pub trait CrateStore<'tcx> { // crate metadata fn dylib_dependency_formats(&self, cnum: CrateNum) -> Vec<(CrateNum, LinkagePreference)>; + fn dep_kind(&self, cnum: CrateNum) -> DepKind; fn lang_items(&self, cnum: CrateNum) -> Vec<(DefIndex, usize)>; fn missing_lang_items(&self, cnum: CrateNum) -> Vec; fn is_staged_api(&self, cnum: CrateNum) -> bool; - fn is_explicitly_linked(&self, cnum: CrateNum) -> bool; fn is_allocator(&self, cnum: CrateNum) -> bool; fn is_panic_runtime(&self, cnum: CrateNum) -> bool; fn is_compiler_builtins(&self, cnum: CrateNum) -> bool; @@ -200,6 +211,7 @@ pub trait CrateStore<'tcx> { fn relative_def_path(&self, def: DefId) -> Option; fn struct_field_names(&self, def: DefId) -> Vec; fn item_children(&self, did: DefId) -> Vec; + fn load_macro(&self, did: DefId, sess: &Session) -> ast::MacroDef; // misc. metadata fn maybe_get_item_ast<'a>(&'tcx self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId) @@ -342,7 +354,7 @@ impl<'tcx> CrateStore<'tcx> for DummyCrateStore { fn missing_lang_items(&self, cnum: CrateNum) -> Vec { bug!("missing_lang_items") } fn is_staged_api(&self, cnum: CrateNum) -> bool { bug!("is_staged_api") } - fn is_explicitly_linked(&self, cnum: CrateNum) -> bool { bug!("is_explicitly_linked") } + fn dep_kind(&self, cnum: CrateNum) -> DepKind { bug!("is_explicitly_linked") } fn is_allocator(&self, cnum: CrateNum) -> bool { bug!("is_allocator") } fn is_panic_runtime(&self, cnum: CrateNum) -> bool { bug!("is_panic_runtime") } fn is_compiler_builtins(&self, cnum: CrateNum) -> bool { bug!("is_compiler_builtins") } @@ -371,6 +383,7 @@ impl<'tcx> CrateStore<'tcx> for DummyCrateStore { } fn struct_field_names(&self, def: DefId) -> Vec { bug!("struct_field_names") } fn item_children(&self, did: DefId) -> Vec { bug!("item_children") } + fn load_macro(&self, did: DefId, sess: &Session) -> ast::MacroDef { bug!("load_macro") } // misc. metadata fn maybe_get_item_ast<'a>(&'tcx self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId) @@ -410,22 +423,8 @@ impl<'tcx> CrateStore<'tcx> for DummyCrateStore { fn metadata_encoding_version(&self) -> &[u8] { bug!("metadata_encoding_version") } } -pub enum LoadedMacros { - MacroRules(Vec), - ProcMacros(Vec<(ast::Name, SyntaxExtension)>), -} - -impl LoadedMacros { - pub fn is_proc_macros(&self) -> bool { - match *self { - LoadedMacros::ProcMacros(_) => true, - _ => false, - } - } -} - pub trait CrateLoader { fn process_item(&mut self, item: &ast::Item, defs: &Definitions, load_macros: bool) - -> Option; + -> Vec<(ast::Name, SyntaxExtension)>; fn postprocess(&mut self, krate: &ast::Crate); } diff --git a/src/librustc/middle/dependency_format.rs b/src/librustc/middle/dependency_format.rs index c658f47ec1be0..92d1ab85c5a05 100644 --- a/src/librustc/middle/dependency_format.rs +++ b/src/librustc/middle/dependency_format.rs @@ -65,6 +65,7 @@ use hir::def_id::CrateNum; use session; use session::config; +use middle::cstore::DepKind; use middle::cstore::LinkagePreference::{self, RequireStatic, RequireDynamic}; use util::nodemap::FxHashMap; use rustc_back::PanicStrategy; @@ -123,6 +124,7 @@ fn calculate_type(sess: &session::Session, return v; } for cnum in sess.cstore.crates() { + if sess.cstore.dep_kind(cnum) == DepKind::MacrosOnly { continue } let src = sess.cstore.used_crate_source(cnum); if src.rlib.is_some() { continue } sess.err(&format!("dependency `{}` not found in rlib format", @@ -155,6 +157,7 @@ fn calculate_type(sess: &session::Session, // dependencies, ensuring there are no conflicts. The only valid case for a // dependency to be relied upon twice is for both cases to rely on a dylib. for cnum in sess.cstore.crates() { + if sess.cstore.dep_kind(cnum) == DepKind::MacrosOnly { continue } let name = sess.cstore.crate_name(cnum); let src = sess.cstore.used_crate_source(cnum); if src.dylib.is_some() { @@ -188,7 +191,7 @@ fn calculate_type(sess: &session::Session, let src = sess.cstore.used_crate_source(cnum); if src.dylib.is_none() && !formats.contains_key(&cnum) && - sess.cstore.is_explicitly_linked(cnum) { + sess.cstore.dep_kind(cnum) == DepKind::Explicit { assert!(src.rlib.is_some()); info!("adding staticlib: {}", sess.cstore.crate_name(cnum)); add_library(sess, cnum, RequireStatic, &mut formats); @@ -272,7 +275,7 @@ fn attempt_static(sess: &session::Session) -> Option { // everything in explicitly so long as it's actually required. let last_crate = sess.cstore.crates().len(); let mut ret = (1..last_crate+1).map(|cnum| { - if sess.cstore.is_explicitly_linked(CrateNum::new(cnum)) { + if sess.cstore.dep_kind(CrateNum::new(cnum)) == DepKind::Explicit { Linkage::Static } else { Linkage::NotLinked diff --git a/src/librustc_incremental/calculate_svh/svh_visitor.rs b/src/librustc_incremental/calculate_svh/svh_visitor.rs index 2358d60d0de21..0b0dd596784e9 100644 --- a/src/librustc_incremental/calculate_svh/svh_visitor.rs +++ b/src/librustc_incremental/calculate_svh/svh_visitor.rs @@ -834,7 +834,8 @@ impl<'a, 'hash, 'tcx> StrictVersionHashVisitor<'a, 'hash, 'tcx> { Def::Const(..) | Def::AssociatedConst(..) | Def::Local(..) | - Def::Upvar(..) => { + Def::Upvar(..) | + Def::Macro(..) => { DefHash::SawDefId.hash(self.st); self.hash_def_id(def.def_id()); } diff --git a/src/librustc_llvm/lib.rs b/src/librustc_llvm/lib.rs index da09bfa66d28f..07b87072c435e 100644 --- a/src/librustc_llvm/lib.rs +++ b/src/librustc_llvm/lib.rs @@ -29,6 +29,7 @@ #![feature(staged_api)] #![feature(linked_from)] #![feature(concat_idents)] +#![cfg_attr(not(stage0), feature(rustc_private))] extern crate libc; #[macro_use] diff --git a/src/librustc_metadata/creader.rs b/src/librustc_metadata/creader.rs index 4385f024b4139..e53f1a0633b62 100644 --- a/src/librustc_metadata/creader.rs +++ b/src/librustc_metadata/creader.rs @@ -16,7 +16,7 @@ use schema::CrateRoot; use rustc::hir::def_id::{CrateNum, DefIndex}; use rustc::hir::svh::Svh; -use rustc::middle::cstore::LoadedMacros; +use rustc::middle::cstore::DepKind; use rustc::session::{config, Session}; use rustc_back::PanicStrategy; use rustc::session::search_paths::PathKind; @@ -29,15 +29,15 @@ use std::cell::{RefCell, Cell}; use std::ops::Deref; use std::path::PathBuf; use std::rc::Rc; -use std::fs; +use std::{cmp, fs}; use syntax::ast; use syntax::abi::Abi; -use syntax::parse; use syntax::attr; use syntax::ext::base::SyntaxExtension; +use syntax::feature_gate::{self, emit_feature_err}; use syntax::parse::token::{InternedString, intern}; -use syntax_pos::{self, Span, mk_sp}; +use syntax_pos::{Span, DUMMY_SP}; use log; pub struct Library { @@ -56,29 +56,23 @@ pub struct CrateLoader<'a> { fn dump_crates(cstore: &CStore) { info!("resolved crates:"); - cstore.iter_crate_data_origins(|_, data, opt_source| { + cstore.iter_crate_data(|_, data| { info!(" name: {}", data.name()); info!(" cnum: {}", data.cnum); info!(" hash: {}", data.hash()); - info!(" reqd: {}", data.explicitly_linked.get()); - opt_source.map(|cs| { - let CrateSource { dylib, rlib, cnum: _ } = cs; - dylib.map(|dl| info!(" dylib: {}", dl.0.display())); - rlib.map(|rl| info!(" rlib: {}", rl.0.display())); - }); + info!(" reqd: {:?}", data.dep_kind.get()); + let CrateSource { dylib, rlib } = data.source.clone(); + dylib.map(|dl| info!(" dylib: {}", dl.0.display())); + rlib.map(|rl| info!(" rlib: {}", rl.0.display())); }) } -fn should_link(i: &ast::Item) -> bool { - !attr::contains_name(&i.attrs, "no_link") -} - #[derive(Debug)] struct ExternCrateInfo { ident: String, name: String, id: ast::NodeId, - should_link: bool, + dep_kind: DepKind, } fn register_native_lib(sess: &Session, @@ -170,7 +164,11 @@ impl<'a> CrateLoader<'a> { ident: i.ident.to_string(), name: name, id: i.id, - should_link: should_link(i), + dep_kind: if attr::contains_name(&i.attrs, "no_link") { + DepKind::MacrosOnly + } else { + DepKind::Explicit + }, }) } _ => None @@ -260,9 +258,8 @@ impl<'a> CrateLoader<'a> { name: &str, span: Span, lib: Library, - explicitly_linked: bool) - -> (CrateNum, Rc, - cstore::CrateSource) { + dep_kind: DepKind) + -> (CrateNum, Rc) { info!("register crate `extern crate {} as {}`", name, ident); let crate_root = lib.metadata.get_root(); self.verify_no_symbol_conflicts(span, &crate_root); @@ -286,7 +283,7 @@ impl<'a> CrateLoader<'a> { let Library { dylib, rlib, metadata } = lib; - let cnum_map = self.resolve_crate_deps(root, &crate_root, &metadata, cnum, span); + let cnum_map = self.resolve_crate_deps(root, &crate_root, &metadata, cnum, span, dep_kind); if crate_root.macro_derive_registrar.is_some() { self.sess.span_err(span, "crates of the `proc-macro` crate type \ @@ -302,18 +299,15 @@ impl<'a> CrateLoader<'a> { cnum_map: RefCell::new(cnum_map), cnum: cnum, codemap_import_info: RefCell::new(vec![]), - explicitly_linked: Cell::new(explicitly_linked), + dep_kind: Cell::new(dep_kind), + source: cstore::CrateSource { + dylib: dylib, + rlib: rlib, + }, }); - let source = cstore::CrateSource { - dylib: dylib, - rlib: rlib, - cnum: cnum, - }; - self.cstore.set_crate_data(cnum, cmeta.clone()); - self.cstore.add_used_crate_source(source.clone()); - (cnum, cmeta, source) + (cnum, cmeta) } fn resolve_crate(&mut self, @@ -323,8 +317,8 @@ impl<'a> CrateLoader<'a> { hash: Option<&Svh>, span: Span, kind: PathKind, - explicitly_linked: bool) - -> (CrateNum, Rc, cstore::CrateSource) { + dep_kind: DepKind) + -> (CrateNum, Rc) { info!("resolving crate `extern crate {} as {}`", name, ident); let result = match self.existing_match(name, hash, kind) { Some(cnum) => LoadResult::Previous(cnum), @@ -356,14 +350,11 @@ impl<'a> CrateLoader<'a> { match result { LoadResult::Previous(cnum) => { let data = self.cstore.get_crate_data(cnum); - if explicitly_linked && !data.explicitly_linked.get() { - data.explicitly_linked.set(explicitly_linked); - } - (cnum, data, self.cstore.used_crate_source(cnum)) + data.dep_kind.set(cmp::max(data.dep_kind.get(), dep_kind)); + (cnum, data) } LoadResult::Loaded(library) => { - self.register_crate(root, ident, name, span, library, - explicitly_linked) + self.register_crate(root, ident, name, span, library, dep_kind) } } } @@ -436,7 +427,8 @@ impl<'a> CrateLoader<'a> { crate_root: &CrateRoot, metadata: &MetadataBlob, krate: CrateNum, - span: Span) + span: Span, + dep_kind: DepKind) -> cstore::CrateNumMap { debug!("resolving deps of external crate"); // The map from crate numbers in the crate we're resolving to local crate @@ -444,13 +436,14 @@ impl<'a> CrateLoader<'a> { let deps = crate_root.crate_deps.decode(metadata); let map: FxHashMap<_, _> = deps.enumerate().map(|(crate_num, dep)| { debug!("resolving dep crate {} hash: `{}`", dep.name, dep.hash); - let (local_cnum, ..) = self.resolve_crate(root, - &dep.name.as_str(), - &dep.name.as_str(), - Some(&dep.hash), - span, - PathKind::Dependency, - dep.explicitly_linked); + let dep_name = &dep.name.as_str(); + let dep_kind = match dep_kind { + DepKind::MacrosOnly => DepKind::MacrosOnly, + _ => dep.kind, + }; + let (local_cnum, ..) = self.resolve_crate( + root, dep_name, dep_name, Some(&dep.hash), span, PathKind::Dependency, dep_kind, + ); (CrateNum::new(crate_num + 1), local_cnum) }).collect(); @@ -464,8 +457,8 @@ impl<'a> CrateLoader<'a> { } fn read_extension_crate(&mut self, span: Span, info: &ExternCrateInfo) -> ExtensionCrate { - info!("read extension crate {} `extern crate {} as {}` linked={}", - info.id, info.name, info.ident, info.should_link); + info!("read extension crate {} `extern crate {} as {}` dep_kind={:?}", + info.id, info.name, info.ident, info.dep_kind); let target_triple = &self.sess.opts.target_triple[..]; let is_cross = target_triple != config::host_triple(); let mut target_only = false; @@ -508,9 +501,8 @@ impl<'a> CrateLoader<'a> { let (dylib, metadata) = match library { LoadResult::Previous(cnum) => { - let dylib = self.cstore.opt_used_crate_source(cnum).unwrap().dylib; let data = self.cstore.get_crate_data(cnum); - (dylib, PMDSource::Registered(data)) + (data.source.dylib.clone(), PMDSource::Registered(data)) } LoadResult::Loaded(library) => { let dylib = library.dylib.clone(); @@ -526,68 +518,6 @@ impl<'a> CrateLoader<'a> { } } - fn read_macros(&mut self, item: &ast::Item, ekrate: &ExtensionCrate) -> LoadedMacros { - let root = ekrate.metadata.get_root(); - let source_name = format!("<{} macros>", item.ident); - let mut macro_rules = Vec::new(); - - for def in root.macro_defs.decode(&*ekrate.metadata) { - // NB: Don't use parse::parse_tts_from_source_str because it parses with - // quote_depth > 0. - let mut p = parse::new_parser_from_source_str(&self.sess.parse_sess, - source_name.clone(), - def.body); - let lo = p.span.lo; - let body = match p.parse_all_token_trees() { - Ok(body) => body, - Err(mut err) => { - err.emit(); - self.sess.abort_if_errors(); - unreachable!(); - } - }; - let local_span = mk_sp(lo, p.prev_span.hi); - - // Mark the attrs as used - for attr in &def.attrs { - attr::mark_used(attr); - } - - macro_rules.push(ast::MacroDef { - ident: ast::Ident::with_empty_ctxt(def.name), - id: ast::DUMMY_NODE_ID, - span: local_span, - imported_from: Some(item.ident), - allow_internal_unstable: attr::contains_name(&def.attrs, "allow_internal_unstable"), - attrs: def.attrs, - body: body, - }); - self.sess.imported_macro_spans.borrow_mut() - .insert(local_span, (def.name.as_str().to_string(), def.span)); - } - - if let Some(id) = root.macro_derive_registrar { - let dylib = match ekrate.dylib.clone() { - Some(dylib) => dylib, - None => span_bug!(item.span, "proc-macro crate not dylib"), - }; - if ekrate.target_only { - let message = format!("proc-macro crate is not available for \ - triple `{}` (only found {})", - config::host_triple(), - self.sess.opts.target_triple); - self.sess.span_fatal(item.span, &message); - } - - // custom derive crates currently should not have any macro_rules! - // exported macros, enforced elsewhere - assert_eq!(macro_rules.len(), 0); - LoadedMacros::ProcMacros(self.load_derive_macros(item, id, root.hash, dylib)) - } else { - LoadedMacros::MacroRules(macro_rules) - } - } - /// Load custom derive macros. /// /// Note that this is intentionally similar to how we load plugins today, @@ -595,14 +525,34 @@ impl<'a> CrateLoader<'a> { /// implemented as dynamic libraries, but we have a possible future where /// custom derive (and other macro-1.1 style features) are implemented via /// executables and custom IPC. - fn load_derive_macros(&mut self, item: &ast::Item, index: DefIndex, svh: Svh, path: PathBuf) - -> Vec<(ast::Name, SyntaxExtension)> { + fn load_derive_macros(&mut self, item: &ast::Item, ekrate: &ExtensionCrate) + -> Option> { use std::{env, mem}; use proc_macro::TokenStream; use proc_macro::__internal::Registry; use rustc_back::dynamic_lib::DynamicLibrary; use syntax_ext::deriving::custom::CustomDerive; + let root = ekrate.metadata.get_root(); + let index = match root.macro_derive_registrar { + Some(index) => index, + None => return None, + }; + if !self.sess.features.borrow().proc_macro { + let issue = feature_gate::GateIssue::Language; + let msg = "loading custom derive macro crates is experimentally supported"; + emit_feature_err(&self.sess.parse_sess, "proc_macro", item.span, issue, msg); + } + + if ekrate.target_only { + let msg = format!("proc-macro crate is not available for triple `{}` (only found {})", + config::host_triple(), self.sess.opts.target_triple); + self.sess.span_fatal(item.span, &msg); + } + let path = match ekrate.dylib.clone() { + Some(dylib) => dylib, + None => span_bug!(item.span, "proc-macro crate not dylib"), + }; // Make sure the path contains a / or the linker will search for it. let path = env::current_dir().unwrap().join(path); let lib = match DynamicLibrary::open(Some(&path)) { @@ -610,7 +560,7 @@ impl<'a> CrateLoader<'a> { Err(err) => self.sess.span_fatal(item.span, &err), }; - let sym = self.sess.generate_derive_registrar_symbol(&svh, index); + let sym = self.sess.generate_derive_registrar_symbol(&root.hash, index); let registrar = unsafe { let sym = match lib.symbol(&sym) { Ok(f) => f, @@ -640,7 +590,7 @@ impl<'a> CrateLoader<'a> { // Intentionally leak the dynamic library. We can't ever unload it // since the library can make things that will live arbitrarily long. mem::forget(lib); - my_registrar.0 + Some(my_registrar.0) } /// Look for a plugin registrar. Returns library path, crate @@ -651,7 +601,7 @@ impl<'a> CrateLoader<'a> { name: name.to_string(), ident: name.to_string(), id: ast::DUMMY_NODE_ID, - should_link: false, + dep_kind: DepKind::MacrosOnly, }); if ekrate.target_only { @@ -725,7 +675,7 @@ impl<'a> CrateLoader<'a> { // #![panic_runtime] crate. self.inject_dependency_if(cnum, "a panic runtime", &|data| data.needs_panic_runtime()); - runtime_found = runtime_found || data.explicitly_linked.get(); + runtime_found = runtime_found || data.dep_kind.get() == DepKind::Explicit; } }); @@ -754,9 +704,9 @@ impl<'a> CrateLoader<'a> { }; info!("panic runtime not found -- loading {}", name); - let (cnum, data, _) = self.resolve_crate(&None, name, name, None, - syntax_pos::DUMMY_SP, - PathKind::Crate, false); + let dep_kind = DepKind::Implicit; + let (cnum, data) = + self.resolve_crate(&None, name, name, None, DUMMY_SP, PathKind::Crate, dep_kind); // Sanity check the loaded crate to ensure it is indeed a panic runtime // and the panic strategy is indeed what we thought it was. @@ -790,7 +740,7 @@ impl<'a> CrateLoader<'a> { self.inject_dependency_if(cnum, "an allocator", &|data| data.needs_allocator()); found_required_allocator = found_required_allocator || - data.explicitly_linked.get(); + data.dep_kind.get() == DepKind::Explicit; } }); if !needs_allocator || found_required_allocator { return } @@ -836,9 +786,9 @@ impl<'a> CrateLoader<'a> { } else { &self.sess.target.target.options.exe_allocation_crate }; - let (cnum, data, _) = self.resolve_crate(&None, name, name, None, - syntax_pos::DUMMY_SP, - PathKind::Crate, false); + let dep_kind = DepKind::Implicit; + let (cnum, data) = + self.resolve_crate(&None, name, name, None, DUMMY_SP, PathKind::Crate, dep_kind); // Sanity check the crate we loaded to ensure that it is indeed an // allocator. @@ -979,45 +929,36 @@ impl<'a> middle::cstore::CrateLoader for CrateLoader<'a> { } fn process_item(&mut self, item: &ast::Item, definitions: &Definitions, load_macros: bool) - -> Option { + -> Vec<(ast::Name, SyntaxExtension)> { match item.node { ast::ItemKind::ExternCrate(_) => {} ast::ItemKind::ForeignMod(ref fm) => { self.process_foreign_mod(item, fm); - return None; + return Vec::new(); } - _ => return None, + _ => return Vec::new(), } let info = self.extract_crate_info(item).unwrap(); - let loaded_macros = if load_macros { + if load_macros { let ekrate = self.read_extension_crate(item.span, &info); - let loaded_macros = self.read_macros(item, &ekrate); - // If this is a proc-macro crate or `#[no_link]` crate, it is only used at compile time, - // so we return here to avoid registering the crate. - if loaded_macros.is_proc_macros() || !info.should_link { - return Some(loaded_macros); + // If 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, .. } = info; - self.register_crate(&None, ident, name, item.span, lib, true); + let ExternCrateInfo { ref ident, ref name, dep_kind, .. } = info; + self.register_crate(&None, ident, name, item.span, lib, dep_kind); } } - - Some(loaded_macros) - } else { - if !info.should_link { - return None; - } - None - }; + } let (cnum, ..) = self.resolve_crate( - &None, &info.ident, &info.name, None, item.span, PathKind::Crate, true, + &None, &info.ident, &info.name, None, item.span, PathKind::Crate, info.dep_kind, ); let def_id = definitions.opt_local_def_id(item.id).unwrap(); @@ -1028,6 +969,6 @@ impl<'a> middle::cstore::CrateLoader for CrateLoader<'a> { self.update_extern_crate(cnum, extern_crate, &mut FxHashSet()); self.cstore.add_extern_mod_stmt_cnum(info.id, cnum); - loaded_macros + Vec::new() } } diff --git a/src/librustc_metadata/cstore.rs b/src/librustc_metadata/cstore.rs index f452cc23b7330..10e86c427a832 100644 --- a/src/librustc_metadata/cstore.rs +++ b/src/librustc_metadata/cstore.rs @@ -18,7 +18,7 @@ use rustc::dep_graph::DepGraph; use rustc::hir::def_id::{CRATE_DEF_INDEX, CrateNum, DefIndex, DefId}; use rustc::hir::map::DefKey; use rustc::hir::svh::Svh; -use rustc::middle::cstore::ExternCrate; +use rustc::middle::cstore::{DepKind, ExternCrate}; use rustc_back::PanicStrategy; use rustc_data_structures::indexed_vec::IndexVec; use rustc::util::nodemap::{FxHashMap, NodeMap, NodeSet, DefIdMap}; @@ -78,11 +78,8 @@ pub struct CrateMetadata { /// compilation support. pub key_map: FxHashMap, - /// Flag if this crate is required by an rlib version of this crate, or in - /// other words whether it was explicitly linked to. An example of a crate - /// where this is false is when an allocator crate is injected into the - /// dependency list, and therefore isn't actually needed to link an rlib. - pub explicitly_linked: Cell, + pub dep_kind: Cell, + pub source: CrateSource, } pub struct CachedInlinedItem { @@ -97,7 +94,6 @@ pub struct CStore { metas: RefCell>>, /// Map from NodeId's of local extern crate statements to crate numbers extern_mod_crate_map: RefCell>, - used_crate_sources: RefCell>, used_libraries: RefCell>, used_link_args: RefCell>, statically_included_foreign_items: RefCell, @@ -112,7 +108,6 @@ impl CStore { dep_graph: dep_graph.clone(), metas: RefCell::new(FxHashMap()), extern_mod_crate_map: RefCell::new(FxHashMap()), - used_crate_sources: RefCell::new(Vec::new()), used_libraries: RefCell::new(Vec::new()), used_link_args: RefCell::new(Vec::new()), statically_included_foreign_items: RefCell::new(NodeSet()), @@ -146,38 +141,9 @@ impl CStore { } } - /// Like `iter_crate_data`, but passes source paths (if available) as well. - pub fn iter_crate_data_origins(&self, mut i: I) - where I: FnMut(CrateNum, &CrateMetadata, Option) - { - for (&k, v) in self.metas.borrow().iter() { - let origin = self.opt_used_crate_source(k); - origin.as_ref().map(|cs| { - assert!(k == cs.cnum); - }); - i(k, &v, origin); - } - } - - pub fn add_used_crate_source(&self, src: CrateSource) { - let mut used_crate_sources = self.used_crate_sources.borrow_mut(); - if !used_crate_sources.contains(&src) { - used_crate_sources.push(src); - } - } - - pub fn opt_used_crate_source(&self, cnum: CrateNum) -> Option { - self.used_crate_sources - .borrow_mut() - .iter() - .find(|source| source.cnum == cnum) - .cloned() - } - pub fn reset(&self) { self.metas.borrow_mut().clear(); self.extern_mod_crate_map.borrow_mut().clear(); - self.used_crate_sources.borrow_mut().clear(); self.used_libraries.borrow_mut().clear(); self.used_link_args.borrow_mut().clear(); self.statically_included_foreign_items.borrow_mut().clear(); @@ -223,15 +189,16 @@ impl CStore { } info!("topological ordering: {:?}", ordering); ordering.reverse(); - let mut libs = self.used_crate_sources + let mut libs = self.metas .borrow() .iter() - .map(|src| { - (src.cnum, - match prefer { - LinkagePreference::RequireDynamic => src.dylib.clone().map(|p| p.0), - LinkagePreference::RequireStatic => src.rlib.clone().map(|p| p.0), - }) + .filter_map(|(&cnum, data)| { + if data.dep_kind.get() == DepKind::MacrosOnly { return None; } + let path = match prefer { + LinkagePreference::RequireDynamic => data.source.dylib.clone().map(|p| p.0), + LinkagePreference::RequireStatic => data.source.rlib.clone().map(|p| p.0), + }; + Some((cnum, path)) }) .collect::>(); libs.sort_by(|&(a, _), &(b, _)| { diff --git a/src/librustc_metadata/cstore_impl.rs b/src/librustc_metadata/cstore_impl.rs index 18ce514c9c42d..3113bfcb5b452 100644 --- a/src/librustc_metadata/cstore_impl.rs +++ b/src/librustc_metadata/cstore_impl.rs @@ -13,10 +13,11 @@ use encoder; use locator; use schema; -use rustc::middle::cstore::{InlinedItem, CrateStore, CrateSource, ExternCrate}; +use rustc::middle::cstore::{InlinedItem, CrateStore, CrateSource, DepKind, ExternCrate}; use rustc::middle::cstore::{NativeLibraryKind, LinkMeta, LinkagePreference}; use rustc::hir::def::{self, Def}; use rustc::middle::lang_items; +use rustc::session::Session; use rustc::ty::{self, Ty, TyCtxt}; use rustc::hir::def_id::{CrateNum, DefId, DefIndex, CRATE_DEF_INDEX}; @@ -30,7 +31,8 @@ use rustc_back::PanicStrategy; use std::path::PathBuf; use syntax::ast; use syntax::attr; -use syntax::parse::token; +use syntax::parse::{token, new_parser_from_source_str}; +use syntax_pos::mk_sp; use rustc::hir::svh::Svh; use rustc_back::target::Target; use rustc::hir; @@ -221,6 +223,11 @@ impl<'tcx> CrateStore<'tcx> for cstore::CStore { self.get_crate_data(cnum).get_dylib_dependency_formats() } + fn dep_kind(&self, cnum: CrateNum) -> DepKind + { + self.get_crate_data(cnum).dep_kind.get() + } + fn lang_items(&self, cnum: CrateNum) -> Vec<(DefIndex, usize)> { self.get_crate_data(cnum).get_lang_items() @@ -237,11 +244,6 @@ impl<'tcx> CrateStore<'tcx> for cstore::CStore { self.get_crate_data(cnum).is_staged_api() } - fn is_explicitly_linked(&self, cnum: CrateNum) -> bool - { - self.get_crate_data(cnum).explicitly_linked.get() - } - fn is_allocator(&self, cnum: CrateNum) -> bool { self.get_crate_data(cnum).is_allocator() @@ -351,6 +353,43 @@ impl<'tcx> CrateStore<'tcx> for cstore::CStore { result } + fn load_macro(&self, id: DefId, sess: &Session) -> ast::MacroDef { + let (name, def) = self.get_crate_data(id.krate).get_macro(id.index); + let source_name = format!("<{} macros>", name); + + // NB: Don't use parse_tts_from_source_str because it parses with quote_depth > 0. + let mut parser = new_parser_from_source_str(&sess.parse_sess, source_name, def.body); + + let lo = parser.span.lo; + let body = match parser.parse_all_token_trees() { + Ok(body) => body, + Err(mut err) => { + err.emit(); + sess.abort_if_errors(); + unreachable!(); + } + }; + let local_span = mk_sp(lo, parser.prev_span.hi); + + // Mark the attrs as used + for attr in &def.attrs { + attr::mark_used(attr); + } + + sess.imported_macro_spans.borrow_mut() + .insert(local_span, (def.name.as_str().to_string(), def.span)); + + ast::MacroDef { + ident: ast::Ident::with_empty_ctxt(def.name), + id: ast::DUMMY_NODE_ID, + span: local_span, + imported_from: None, // FIXME + allow_internal_unstable: attr::contains_name(&def.attrs, "allow_internal_unstable"), + attrs: def.attrs, + body: body, + } + } + fn maybe_get_item_ast<'a>(&'tcx self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) @@ -507,7 +546,7 @@ impl<'tcx> CrateStore<'tcx> for cstore::CStore { fn used_crate_source(&self, cnum: CrateNum) -> CrateSource { - self.opt_used_crate_source(cnum).unwrap() + self.get_crate_data(cnum).source.clone() } fn extern_mod_stmt_cnum(&self, emod_id: ast::NodeId) -> Option diff --git a/src/librustc_metadata/decoder.rs b/src/librustc_metadata/decoder.rs index 7973cd880fe34..64a90d56d5561 100644 --- a/src/librustc_metadata/decoder.rs +++ b/src/librustc_metadata/decoder.rs @@ -21,7 +21,7 @@ use rustc::util::nodemap::FxHashMap; use rustc::hir; use rustc::hir::intravisit::IdRange; -use rustc::middle::cstore::{InlinedItem, LinkagePreference}; +use rustc::middle::cstore::{DepKind, InlinedItem, LinkagePreference}; use rustc::hir::def::{self, Def, CtorKind}; use rustc::hir::def_id::{CrateNum, DefId, DefIndex, LOCAL_CRATE}; use rustc::middle::lang_items; @@ -468,6 +468,7 @@ impl<'tcx> EntryKind<'tcx> { EntryKind::Variant(_) => Def::Variant(did), EntryKind::Trait(_) => Def::Trait(did), EntryKind::Enum => Def::Enum(did), + EntryKind::MacroDef(_) => Def::Macro(did), EntryKind::ForeignMod | EntryKind::Impl(_) | @@ -690,6 +691,8 @@ impl<'a, 'tcx> CrateMetadata { pub fn each_child_of_item(&self, id: DefIndex, mut callback: F) where F: FnMut(def::Export) { + let macros_only = self.dep_kind.get() == DepKind::MacrosOnly; + // Find the item. let item = match self.maybe_entry(id) { None => return, @@ -698,9 +701,19 @@ impl<'a, 'tcx> CrateMetadata { // Iterate over all children. for child_index in item.children.decode(self) { + if macros_only { + continue + } + // Get the item. if let Some(child) = self.maybe_entry(child_index) { let child = child.decode(self); + match child.kind { + EntryKind::MacroDef(..) => {} + _ if macros_only => continue, + _ => {} + } + // Hand off the item to the callback. match child.kind { // FIXME(eddyb) Don't encode these in children. @@ -759,6 +772,11 @@ impl<'a, 'tcx> CrateMetadata { if let EntryKind::Mod(data) = item.kind { for exp in data.decode(self).reexports.decode(self) { + match exp.def { + Def::Macro(..) => {} + _ if macros_only => continue, + _ => {} + } callback(exp); } } @@ -987,6 +1005,14 @@ impl<'a, 'tcx> CrateMetadata { self.root.reachable_ids.decode(self).map(|index| self.local_def_id(index)).collect() } + pub fn get_macro(&self, id: DefIndex) -> (ast::Name, MacroDef) { + let entry = self.entry(id); + match entry.kind { + EntryKind::MacroDef(macro_def) => (self.item_name(&entry), macro_def.decode(self)), + _ => bug!(), + } + } + pub fn is_const_fn(&self, id: DefIndex) -> bool { let constness = match self.entry(id).kind { EntryKind::Method(data) => data.decode(self).fn_data.constness, diff --git a/src/librustc_metadata/encoder.rs b/src/librustc_metadata/encoder.rs index 2379e744c49e1..ac1f2afcb2adb 100644 --- a/src/librustc_metadata/encoder.rs +++ b/src/librustc_metadata/encoder.rs @@ -830,6 +830,34 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { }, } } + + /// Serialize the text of exported macros + fn encode_info_for_macro_def(&mut self, macro_def: &hir::MacroDef) -> Entry<'tcx> { + let def_id = self.tcx.map.local_def_id(macro_def.id); + let macro_def = MacroDef { + name: macro_def.name, + attrs: macro_def.attrs.to_vec(), + span: macro_def.span, + body: ::syntax::print::pprust::tts_to_string(¯o_def.body) + }; + Entry { + kind: EntryKind::MacroDef(self.lazy(¯o_def)), + visibility: ty::Visibility::Public, + def_key: self.encode_def_key(def_id), + + attributes: LazySeq::empty(), + children: LazySeq::empty(), + stability: None, + deprecation: None, + ty: None, + inherent_impls: LazySeq::empty(), + variances: LazySeq::empty(), + generics: None, + predicates: None, + ast: None, + mir: None, + } + } } impl<'a, 'b, 'tcx> IndexBuilder<'a, 'b, 'tcx> { @@ -964,6 +992,10 @@ impl<'a, 'b, 'tcx> Visitor<'tcx> for EncodeVisitor<'a, 'b, 'tcx> { intravisit::walk_ty(self, ty); self.index.encode_info_for_ty(ty); } + fn visit_macro_def(&mut self, macro_def: &'tcx hir::MacroDef) { + let def_id = self.index.tcx.map.local_def_id(macro_def.id); + self.index.record(def_id, EncodeContext::encode_info_for_macro_def, macro_def); + } } impl<'a, 'b, 'tcx> IndexBuilder<'a, 'b, 'tcx> { @@ -1043,6 +1075,9 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { FromId(CRATE_NODE_ID, (&krate.module, &krate.attrs, &hir::Public))); let mut visitor = EncodeVisitor { index: index }; krate.visit_all_items(&mut visitor); + for macro_def in &krate.exported_macros { + visitor.visit_macro_def(macro_def); + } visitor.index.into_items() } @@ -1080,7 +1115,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { CrateDep { name: syntax::parse::token::intern(dep.name()), hash: dep.hash(), - explicitly_linked: dep.explicitly_linked.get(), + kind: dep.dep_kind.get(), } })) } @@ -1122,19 +1157,6 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { }) .map(|filemap| &**filemap)) } - - /// Serialize the text of the exported macros - fn encode_macro_defs(&mut self) -> LazySeq { - let tcx = self.tcx; - self.lazy_seq(tcx.map.krate().exported_macros.iter().map(|def| { - MacroDef { - name: def.name, - attrs: def.attrs.to_vec(), - span: def.span, - body: ::syntax::print::pprust::tts_to_string(&def.body), - } - })) - } } struct ImplVisitor<'a, 'tcx: 'a> { @@ -1228,11 +1250,6 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { let codemap = self.encode_codemap(); let codemap_bytes = self.position() - i; - // Encode macro definitions - i = self.position(); - let macro_defs = self.encode_macro_defs(); - let macro_defs_bytes = self.position() - i; - // Encode the def IDs of impls, for coherence checking. i = self.position(); let impls = self.encode_impls(); @@ -1279,7 +1296,6 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { lang_items_missing: lang_items_missing, native_libraries: native_libraries, codemap: codemap, - macro_defs: macro_defs, impls: impls, reachable_ids: reachable_ids, index: index, @@ -1300,7 +1316,6 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { println!(" lang item bytes: {}", lang_item_bytes); println!(" native bytes: {}", native_lib_bytes); println!(" codemap bytes: {}", codemap_bytes); - println!(" macro def bytes: {}", macro_defs_bytes); println!(" impl bytes: {}", impl_bytes); println!(" reachable bytes: {}", reachable_bytes); println!(" item bytes: {}", item_bytes); diff --git a/src/librustc_metadata/index_builder.rs b/src/librustc_metadata/index_builder.rs index 9938e20d1861d..1a74a92545477 100644 --- a/src/librustc_metadata/index_builder.rs +++ b/src/librustc_metadata/index_builder.rs @@ -195,6 +195,7 @@ read_hir!(hir::Item); read_hir!(hir::ImplItem); read_hir!(hir::TraitItem); read_hir!(hir::ForeignItem); +read_hir!(hir::MacroDef); /// Leaks access to a value of type T without any tracking. This is /// suitable for ambiguous types like `usize`, which *could* represent diff --git a/src/librustc_metadata/schema.rs b/src/librustc_metadata/schema.rs index ff2a764571025..d7a5f7ad71544 100644 --- a/src/librustc_metadata/schema.rs +++ b/src/librustc_metadata/schema.rs @@ -14,7 +14,7 @@ use index; use rustc::hir; use rustc::hir::def::{self, CtorKind}; use rustc::hir::def_id::{DefIndex, DefId}; -use rustc::middle::cstore::{LinkagePreference, NativeLibraryKind}; +use rustc::middle::cstore::{DepKind, LinkagePreference, NativeLibraryKind}; use rustc::middle::lang_items; use rustc::mir; use rustc::ty::{self, Ty}; @@ -177,7 +177,6 @@ pub struct CrateRoot { pub lang_items_missing: LazySeq, pub native_libraries: LazySeq<(NativeLibraryKind, String)>, pub codemap: LazySeq, - pub macro_defs: LazySeq, pub impls: LazySeq, pub reachable_ids: LazySeq, pub index: LazySeq, @@ -187,7 +186,7 @@ pub struct CrateRoot { pub struct CrateDep { pub name: ast::Name, pub hash: hir::svh::Svh, - pub explicitly_linked: bool, + pub kind: DepKind, } #[derive(RustcEncodable, RustcDecodable)] @@ -241,6 +240,7 @@ pub enum EntryKind<'tcx> { Fn(Lazy), ForeignFn(Lazy), Mod(Lazy), + MacroDef(Lazy), Closure(Lazy>), Trait(Lazy>), Impl(Lazy>), diff --git a/src/librustc_resolve/build_reduced_graph.rs b/src/librustc_resolve/build_reduced_graph.rs index cb8dd7250b496..0833f85c1f6a2 100644 --- a/src/librustc_resolve/build_reduced_graph.rs +++ b/src/librustc_resolve/build_reduced_graph.rs @@ -14,18 +14,17 @@ //! any imports resolved. use macros::{InvocationData, LegacyScope}; +use resolve_imports::ImportDirective; use resolve_imports::ImportDirectiveSubclass::{self, GlobImport}; -use {Module, ModuleS, ModuleKind}; -use Namespace::{self, TypeNS, ValueNS}; -use {NameBinding, NameBindingKind, ToNameBinding}; -use Resolver; +use {Resolver, Module, ModuleS, ModuleKind, NameBinding, NameBindingKind, ToNameBinding}; +use Namespace::{self, TypeNS, ValueNS, MacroNS}; +use ResolveResult::Success; use {resolve_error, resolve_struct_error, ResolutionError}; -use rustc::middle::cstore::LoadedMacros; +use rustc::middle::cstore::DepKind; use rustc::hir::def::*; -use rustc::hir::def_id::{CRATE_DEF_INDEX, DefId}; +use rustc::hir::def_id::{CrateNum, CRATE_DEF_INDEX, DefId, DefIndex, BUILTIN_MACROS_CRATE}; use rustc::ty; -use rustc::util::nodemap::FxHashMap; use std::cell::Cell; use std::rc::Rc; @@ -37,10 +36,9 @@ use syntax::parse::token; use syntax::ast::{self, Block, ForeignItem, ForeignItemKind, Item, ItemKind}; use syntax::ast::{Mutability, StmtKind, TraitItem, TraitItemKind}; use syntax::ast::{Variant, ViewPathGlob, ViewPathList, ViewPathSimple}; -use syntax::ext::base::{SyntaxExtension, Resolver as SyntaxResolver}; +use syntax::ext::base::SyntaxExtension; use syntax::ext::expand::mark_tts; use syntax::ext::hygiene::Mark; -use syntax::feature_gate::{self, emit_feature_err}; use syntax::ext::tt::macro_rules; use syntax::parse::token::keywords; use syntax::visit::{self, Visitor}; @@ -221,47 +219,53 @@ impl<'b> Resolver<'b> { legacy_imports.import_all.is_some() || !legacy_imports.imports.is_empty() || !legacy_imports.reexports.is_empty() } { - if self.current_module.parent.is_some() { - span_err!(self.session, item.span, E0468, - "an `extern crate` loading macros must be at the crate root"); - } + span_err!(self.session, item.span, E0468, + "an `extern crate` loading macros must be at the crate root"); } - let loaded_macros = if legacy_imports != LegacyMacroImports::default() { - self.crate_loader.process_item(item, &self.definitions, true) - } else { - self.crate_loader.process_item(item, &self.definitions, false) - }; + let load_macros = legacy_imports != LegacyMacroImports::default(); + let proc_macros = + self.crate_loader.process_item(item, &self.definitions, load_macros); // n.b. we don't need to look at the path option here, because cstore already did let crate_id = self.session.cstore.extern_mod_stmt_cnum(item.id); let module = if let Some(crate_id) = crate_id { - let def_id = DefId { - krate: crate_id, - index: CRATE_DEF_INDEX, - }; - let module = self.arenas.alloc_module(ModuleS { - extern_crate_id: Some(item.id), - populated: Cell::new(false), - ..ModuleS::new(Some(parent), ModuleKind::Def(Def::Mod(def_id), name)) + let module = self.get_extern_crate_root(crate_id); + let binding = (module, sp, ty::Visibility::Public).to_name_binding(); + let binding = self.arenas.alloc_name_binding(binding); + let directive = self.arenas.alloc_import_directive(ImportDirective { + 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), }); - self.define(parent, name, TypeNS, (module, sp, vis)); + let imported_binding = self.import(binding, directive); + self.define(parent, name, TypeNS, imported_binding); self.populate_module_if_necessary(module); module } else { - // Define an empty module - let def = Def::Mod(self.definitions.local_def_id(item.id)); - let module = ModuleS::new(Some(parent), ModuleKind::Def(def, name)); - let module = self.arenas.alloc_module(module); + // Define a module and populate it with proc macros. + let module_kind = + ModuleKind::Def(Def::Mod(self.definitions.local_def_id(item.id)), name); + let module = self.arenas.alloc_module(ModuleS::new(None, module_kind)); self.define(parent, name, TypeNS, (module, sp, vis)); + for (name, ext) in proc_macros { + let def_id = DefId { + krate: BUILTIN_MACROS_CRATE, + index: DefIndex::new(self.macro_map.len()), + }; + self.macro_map.insert(def_id, Rc::new(ext)); + let vis = ty::Visibility::Public; + self.define(module, name, MacroNS, (Def::Macro(def_id), DUMMY_SP, vis)); + } module }; - if let Some(loaded_macros) = loaded_macros { - self.import_extern_crate_macros( - item, module, loaded_macros, legacy_imports, expansion == Mark::root(), - ); - } + let allow_shadowing = expansion == Mark::root(); + self.process_legacy_macro_imports(module, legacy_imports, allow_shadowing); } ItemKind::Mod(..) if item.ident == keywords::Invalid.ident() => {} // Crate root @@ -484,6 +488,9 @@ impl<'b> Resolver<'b> { let field_names = self.session.cstore.struct_field_names(def_id); self.insert_field_names(def_id, field_names); } + Def::Macro(..) => { + self.define(parent, name, MacroNS, (def, DUMMY_SP, vis)); + } Def::Local(..) | Def::PrimTy(..) | Def::TyParam(..) | @@ -496,6 +503,43 @@ impl<'b> Resolver<'b> { } } + fn get_extern_crate_root(&mut self, cnum: CrateNum) -> Module<'b> { + let def_id = DefId { krate: cnum, index: CRATE_DEF_INDEX }; + let macros_only = self.session.cstore.dep_kind(cnum) == DepKind::MacrosOnly; + let arenas = self.arenas; + *self.extern_crate_roots.entry((cnum, macros_only)).or_insert_with(|| { + arenas.alloc_module(ModuleS { + populated: Cell::new(false), + ..ModuleS::new(None, ModuleKind::Def(Def::Mod(def_id), keywords::Invalid.name())) + }) + }) + } + + pub fn get_macro(&mut self, def: Def) -> Rc { + let def_id = match def { + Def::Macro(def_id) => def_id, + _ => panic!("Expected Def::Macro(..)"), + }; + if let Some(ext) = self.macro_map.get(&def_id) { + return ext.clone(); + } + + let mut macro_rules = self.session.cstore.load_macro(def_id, &self.session); + let mark = Mark::fresh(); + let invocation = self.arenas.alloc_invocation_data(InvocationData { + module: Cell::new(self.get_extern_crate_root(def_id.krate)), + def_index: CRATE_DEF_INDEX, + const_integer: false, + legacy_scope: Cell::new(LegacyScope::Empty), + expansion: Cell::new(LegacyScope::Empty), + }); + self.invocations.insert(mark, invocation); + macro_rules.body = mark_tts(¯o_rules.body, mark); + let ext = Rc::new(macro_rules::compile(&self.session.parse_sess, ¯o_rules)); + self.macro_map.insert(def_id, ext.clone()); + ext + } + /// Ensures that the reduced graph rooted at the given external module /// is built, building it if it is not. pub fn populate_module_if_necessary(&mut self, module: Module<'b>) { @@ -506,90 +550,46 @@ impl<'b> Resolver<'b> { module.populated.set(true) } - fn import_extern_crate_macros(&mut self, - extern_crate: &Item, - module: Module<'b>, - loaded_macros: LoadedMacros, - legacy_imports: LegacyMacroImports, - allow_shadowing: bool) { - let import_macro = |this: &mut Self, name, ext: Rc<_>, span| { - this.used_crates.insert(module.def_id().unwrap().krate); - if let SyntaxExtension::NormalTT(..) = *ext { - this.macro_names.insert(name); - } - if this.builtin_macros.insert(name, ext).is_some() && !allow_shadowing { - let msg = format!("`{}` is already in scope", name); - let note = - "macro-expanded `#[macro_use]`s may not shadow existing macros (see RFC 1560)"; - this.session.struct_span_err(span, &msg).note(note).emit(); - } - }; - - match loaded_macros { - LoadedMacros::MacroRules(macros) => { - let mark = Mark::fresh(); - if !macros.is_empty() { - let invocation = self.arenas.alloc_invocation_data(InvocationData { - module: Cell::new(module), - def_index: CRATE_DEF_INDEX, - const_integer: false, - legacy_scope: Cell::new(LegacyScope::Empty), - expansion: Cell::new(LegacyScope::Empty), - }); - self.invocations.insert(mark, invocation); - } - - let mut macros: FxHashMap<_, _> = macros.into_iter().map(|mut def| { - def.body = mark_tts(&def.body, mark); - let ext = macro_rules::compile(&self.session.parse_sess, &def); - (def.ident.name, (def, Rc::new(ext))) - }).collect(); + fn legacy_import_macro(&mut self, name: Name, def: Def, span: Span, allow_shadowing: bool) { + self.used_crates.insert(def.def_id().krate); + self.macro_names.insert(name); + if self.builtin_macros.insert(name, def.def_id()).is_some() && !allow_shadowing { + let msg = format!("`{}` is already in scope", name); + let note = + "macro-expanded `#[macro_use]`s may not shadow existing macros (see RFC 1560)"; + self.session.struct_span_err(span, &msg).note(note).emit(); + } + } - if let Some(span) = legacy_imports.import_all { - for (&name, &(_, ref ext)) in macros.iter() { - import_macro(self, name, ext.clone(), span); - } + fn process_legacy_macro_imports(&mut self, + module: Module<'b>, + legacy_imports: LegacyMacroImports, + allow_shadowing: bool) { + if let Some(span) = legacy_imports.import_all { + module.for_each_child(|name, ns, binding| if ns == MacroNS { + self.legacy_import_macro(name, binding.def(), span, allow_shadowing); + }); + } else { + for (name, span) in legacy_imports.imports { + let result = self.resolve_name_in_module(module, name, MacroNS, false, None); + if let Success(binding) = result { + self.legacy_import_macro(name, binding.def(), span, allow_shadowing); } else { - for (name, span) in legacy_imports.imports { - if let Some(&(_, ref ext)) = macros.get(&name) { - import_macro(self, name, ext.clone(), span); - } else { - span_err!(self.session, span, E0469, "imported macro not found"); - } - } - } - for (name, span) in legacy_imports.reexports { - if let Some((mut def, _)) = macros.remove(&name) { - def.id = self.next_node_id(); - self.exported_macros.push(def); - } else { - span_err!(self.session, span, E0470, "reexported macro not found"); - } + span_err!(self.session, span, E0469, "imported macro not found"); } } - - LoadedMacros::ProcMacros(macros) => { - if !self.session.features.borrow().proc_macro { - let sess = &self.session.parse_sess; - let issue = feature_gate::GateIssue::Language; - let msg = - "loading custom derive macro crates is experimentally supported"; - emit_feature_err(sess, "proc_macro", extern_crate.span, issue, msg); - } - if !legacy_imports.imports.is_empty() { - let msg = "`proc-macro` crates cannot be selectively imported from, \ - must use `#[macro_use]`"; - self.session.span_err(extern_crate.span, msg); - } - if !legacy_imports.reexports.is_empty() { - let msg = "`proc-macro` crates cannot be reexported from"; - self.session.span_err(extern_crate.span, msg); - } - if let Some(span) = legacy_imports.import_all { - for (name, ext) in macros { - import_macro(self, name, Rc::new(ext), span); - } + } + for (name, span) in legacy_imports.reexports { + self.used_crates.insert(module.def_id().unwrap().krate); + let result = self.resolve_name_in_module(module, name, MacroNS, false, None); + if let Success(binding) = result { + let def = binding.def(); + if let Def::Macro(DefId { krate: BUILTIN_MACROS_CRATE, .. }) = def { + self.session.span_err(span, "`proc-macro` crates cannot be reexported from"); } + self.macro_exports.push(Export { name: name, def: def }); + } else { + span_err!(self.session, span, E0470, "reexported macro not found"); } } } diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index 664efc27fbb53..fe90cd34687c0 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -76,7 +76,7 @@ use std::fmt; use std::mem::replace; use std::rc::Rc; -use resolve_imports::{ImportDirective, NameResolution}; +use resolve_imports::{ImportDirective, ImportDirectiveSubclass, NameResolution}; use macros::{InvocationData, LegacyBinding, LegacyScope}; // NB: This module needs to be declared first so diagnostics are @@ -533,6 +533,7 @@ impl PatternSource { pub enum Namespace { TypeNS, ValueNS, + MacroNS, } impl<'a> Visitor for Resolver<'a> { @@ -796,10 +797,6 @@ pub struct ModuleS<'a> { // The node id of the closest normal module (`mod`) ancestor (including this module). normal_ancestor_id: Option, - // If the module is an extern crate, `def` is root of the external crate and `extern_crate_id` - // is the NodeId of the local `extern crate` item (otherwise, `extern_crate_id` is None). - extern_crate_id: Option, - resolutions: RefCell>>>, no_implicit_prelude: bool, @@ -824,7 +821,6 @@ impl<'a> ModuleS<'a> { parent: parent, kind: kind, normal_ancestor_id: None, - extern_crate_id: None, resolutions: RefCell::new(FxHashMap()), no_implicit_prelude: false, glob_importers: RefCell::new(Vec::new()), @@ -953,7 +949,14 @@ impl<'a> NameBinding<'a> { } fn is_extern_crate(&self) -> bool { - self.module().ok().and_then(|module| module.extern_crate_id).is_some() + match self.kind { + NameBindingKind::Import { + directive: &ImportDirective { + subclass: ImportDirectiveSubclass::ExternCrate, .. + }, .. + } => true, + _ => false, + } } fn is_import(&self) -> bool { @@ -1081,6 +1084,7 @@ pub struct Resolver<'a> { // There will be an anonymous module created around `g` with the ID of the // entry block for `f`. module_map: NodeMap>, + extern_crate_roots: FxHashMap<(CrateNum, bool /* MacrosOnly? */), Module<'a>>, // Whether or not to print error messages. Can be set to true // when getting additional info for error message suggestions, @@ -1107,8 +1111,10 @@ pub struct Resolver<'a> { pub exported_macros: Vec, crate_loader: &'a mut CrateLoader, macro_names: FxHashSet, - builtin_macros: FxHashMap>, + builtin_macros: FxHashMap, lexical_macro_resolutions: Vec<(Name, LegacyScope<'a>)>, + macro_map: FxHashMap>, + macro_exports: Vec, // Maps the `Mark` of an expansion to its containing module or block. invocations: FxHashMap>, @@ -1274,6 +1280,7 @@ impl<'a> Resolver<'a> { export_map: NodeMap(), trait_map: NodeMap(), module_map: module_map, + extern_crate_roots: FxHashMap(), emit_errors: true, make_glob_map: make_glob_map == MakeGlobMap::Yes, @@ -1300,6 +1307,8 @@ impl<'a> Resolver<'a> { macro_names: FxHashSet(), builtin_macros: FxHashMap(), lexical_macro_resolutions: Vec::new(), + macro_map: FxHashMap(), + macro_exports: Vec::new(), invocations: invocations, } } @@ -1318,13 +1327,6 @@ impl<'a> Resolver<'a> { /// Entry point to crate resolution. pub fn resolve_crate(&mut self, krate: &Crate) { - // Collect `DefId`s for exported macro defs. - for def in &krate.exported_macros { - DefCollector::new(&mut self.definitions).with_parent(CRATE_DEF_INDEX, |collector| { - collector.visit_macro_def(def) - }) - } - self.current_module = self.graph_root; visit::walk_crate(self, krate); @@ -1342,7 +1344,11 @@ impl<'a> Resolver<'a> { } fn get_ribs<'b>(&'b mut self, ns: Namespace) -> &'b mut Vec> { - match ns { ValueNS => &mut self.value_ribs, TypeNS => &mut self.type_ribs } + match ns { + ValueNS => &mut self.value_ribs, + TypeNS => &mut self.type_ribs, + MacroNS => panic!("The macro namespace has no ribs"), + } } fn record_use(&mut self, name: Name, ns: Namespace, binding: &'a NameBinding<'a>, span: Span) @@ -3233,7 +3239,7 @@ impl<'a> Resolver<'a> { in_module.for_each_child(|name, ns, name_binding| { // avoid imports entirely - if name_binding.is_import() { return; } + if name_binding.is_import() && !name_binding.is_extern_crate() { return; } // collect results based on the filter function if name == lookup_name && ns == namespace { @@ -3269,21 +3275,11 @@ impl<'a> Resolver<'a> { // collect submodules to explore if let Ok(module) = name_binding.module() { // form the path - let path_segments = match module.kind { - _ if module.parent.is_none() => path_segments.clone(), - ModuleKind::Def(_, name) => { - let mut paths = path_segments.clone(); - let ident = Ident::with_empty_ctxt(name); - let params = PathParameters::none(); - let segm = PathSegment { - identifier: ident, - parameters: params, - }; - paths.push(segm); - paths - } - _ => bug!(), - }; + let mut path_segments = path_segments.clone(); + path_segments.push(PathSegment { + identifier: Ident::with_empty_ctxt(name), + parameters: PathParameters::none(), + }); if !in_module_is_extern || name_binding.vis == ty::Visibility::Public { // add the module to the lookup @@ -3369,7 +3365,10 @@ impl<'a> Resolver<'a> { if !reported_spans.insert(span) { continue } if binding.is_extern_crate() { // Warn when using an inaccessible extern crate. - let node_id = binding.module().unwrap().extern_crate_id.unwrap(); + let node_id = match binding.kind { + NameBindingKind::Import { directive, .. } => directive.id, + _ => unreachable!(), + }; let msg = format!("extern crate `{}` is private", name); self.session.add_lint(lint::builtin::INACCESSIBLE_EXTERN_CRATE, node_id, span, msg); } else { @@ -3415,7 +3414,7 @@ impl<'a> Resolver<'a> { _ => "enum", }; - let (participle, noun) = match old_binding.is_import() || old_binding.is_extern_crate() { + let (participle, noun) = match old_binding.is_import() { true => ("imported", "import"), false => ("defined", "definition"), }; @@ -3424,7 +3423,8 @@ impl<'a> Resolver<'a> { let msg = { let kind = match (ns, old_binding.module()) { (ValueNS, _) => "a value", - (TypeNS, Ok(module)) if module.extern_crate_id.is_some() => "an extern crate", + (MacroNS, _) => "a macro", + (TypeNS, _) if old_binding.is_extern_crate() => "an extern crate", (TypeNS, Ok(module)) if module.is_normal() => "a module", (TypeNS, Ok(module)) if module.is_trait() => "a trait", (TypeNS, _) => "a type", @@ -3439,7 +3439,7 @@ impl<'a> Resolver<'a> { e.span_label(span, &format!("`{}` was already imported", name)); e }, - (true, _) | (_, true) if binding.is_import() || old_binding.is_import() => { + (true, _) | (_, true) if binding.is_import() && old_binding.is_import() => { let mut e = struct_span_err!(self.session, span, E0254, "{}", msg); e.span_label(span, &"already imported"); e diff --git a/src/librustc_resolve/macros.rs b/src/librustc_resolve/macros.rs index e3078a42f6538..f9d91e3aa63fd 100644 --- a/src/librustc_resolve/macros.rs +++ b/src/librustc_resolve/macros.rs @@ -10,7 +10,8 @@ use {Module, Resolver}; use build_reduced_graph::BuildReducedGraphVisitor; -use rustc::hir::def_id::{CRATE_DEF_INDEX, DefIndex}; +use rustc::hir::def_id::{DefId, BUILTIN_MACROS_CRATE, CRATE_DEF_INDEX, DefIndex}; +use rustc::hir::def::{Def, Export}; use rustc::hir::map::{self, DefCollector}; use std::cell::Cell; use std::rc::Rc; @@ -23,6 +24,7 @@ use syntax::ext::hygiene::Mark; use syntax::ext::tt::macro_rules; use syntax::parse::token::intern; use syntax::util::lev_distance::find_best_match_for_name; +use syntax::visit::Visitor; use syntax_pos::Span; #[derive(Clone)] @@ -128,6 +130,13 @@ impl<'a> base::Resolver for Resolver<'a> { if export { def.id = self.next_node_id(); + DefCollector::new(&mut self.definitions).with_parent(CRATE_DEF_INDEX, |collector| { + collector.visit_macro_def(&def) + }); + self.macro_exports.push(Export { + name: def.ident.name, + def: Def::Macro(self.definitions.local_def_id(def.id)), + }); self.exported_macros.push(def); } } @@ -136,7 +145,12 @@ impl<'a> base::Resolver for Resolver<'a> { if let NormalTT(..) = *ext { self.macro_names.insert(ident.name); } - self.builtin_macros.insert(ident.name, ext); + let def_id = DefId { + krate: BUILTIN_MACROS_CRATE, + index: DefIndex::new(self.macro_map.len()), + }; + self.macro_map.insert(def_id, ext); + self.builtin_macros.insert(ident.name, def_id); } fn add_expansions_at_stmt(&mut self, id: ast::NodeId, macros: Vec) { @@ -147,7 +161,7 @@ impl<'a> base::Resolver for Resolver<'a> { for i in 0..attrs.len() { let name = intern(&attrs[i].name()); match self.builtin_macros.get(&name) { - Some(ext) => match **ext { + Some(&def_id) => match *self.get_macro(Def::Macro(def_id)) { MultiModifier(..) | MultiDecorator(..) | SyntaxExtension::AttrProcMacro(..) => { return Some(attrs.remove(i)) } @@ -226,7 +240,7 @@ impl<'a> Resolver<'a> { if let Some(scope) = possible_time_travel { self.lexical_macro_resolutions.push((name, scope)); } - self.builtin_macros.get(&name).cloned() + self.builtin_macros.get(&name).cloned().map(|def_id| self.get_macro(Def::Macro(def_id))) } fn suggest_macro_name(&mut self, name: &str, err: &mut DiagnosticBuilder<'a>) { diff --git a/src/librustc_resolve/resolve_imports.rs b/src/librustc_resolve/resolve_imports.rs index 2b3945bd0d920..5d66caec31b3e 100644 --- a/src/librustc_resolve/resolve_imports.rs +++ b/src/librustc_resolve/resolve_imports.rs @@ -30,6 +30,7 @@ use syntax::util::lev_distance::find_best_match_for_name; use syntax_pos::Span; use std::cell::{Cell, RefCell}; +use std::mem; impl<'a> Resolver<'a> { pub fn resolve_imports(&mut self) { @@ -51,6 +52,7 @@ pub enum ImportDirectiveSubclass<'a> { max_vis: Cell, // The visibility of the greatest reexport. // n.b. `max_vis` is only used in `finalize_import` to check for reexport errors. }, + ExternCrate, } impl<'a> ImportDirectiveSubclass<'a> { @@ -68,12 +70,12 @@ impl<'a> ImportDirectiveSubclass<'a> { #[derive(Debug,Clone)] pub struct ImportDirective<'a> { pub id: NodeId, - parent: Module<'a>, - module_path: Vec, - imported_module: Cell>>, // the resolution of `module_path` - subclass: ImportDirectiveSubclass<'a>, - span: Span, - vis: Cell, + pub parent: Module<'a>, + pub module_path: Vec, + pub imported_module: Cell>>, // the resolution of `module_path` + pub subclass: ImportDirectiveSubclass<'a>, + pub span: Span, + pub vis: Cell, } impl<'a> ImportDirective<'a> { @@ -169,7 +171,8 @@ impl<'a> Resolver<'a> { let new_import_semantics = self.new_import_semantics; let is_disallowed_private_import = |binding: &NameBinding| { !new_import_semantics && !allow_private_imports && // disallowed - binding.vis != ty::Visibility::Public && binding.is_import() // non-`pub` import + binding.vis != ty::Visibility::Public && binding.is_import() && // non-`pub` import + !binding.is_extern_crate() // not an `extern crate` }; if let Some(span) = record_used { @@ -237,7 +240,7 @@ impl<'a> Resolver<'a> { }; let name = match directive.subclass { SingleImport { source, .. } => source, - GlobImport { .. } => unreachable!(), + _ => unreachable!(), }; match self.resolve_name_in_module(module, name, ns, true, None) { Failed(_) => {} @@ -280,13 +283,14 @@ impl<'a> Resolver<'a> { // which are not relevant to import resolution. GlobImport { is_prelude: true, .. } => {} GlobImport { .. } => self.current_module.globs.borrow_mut().push(directive), + _ => unreachable!(), } } // Given a binding and an import directive that resolves to it, // return the corresponding binding defined by the import directive. - fn import(&mut self, binding: &'a NameBinding<'a>, directive: &'a ImportDirective<'a>) - -> NameBinding<'a> { + pub fn import(&mut self, binding: &'a NameBinding<'a>, directive: &'a ImportDirective<'a>) + -> NameBinding<'a> { let vis = if binding.pseudo_vis().is_at_least(directive.vis.get(), self) || !directive.is_glob() && binding.is_extern_crate() { // c.f. `PRIVATE_IN_PUBLIC` directive.vis.get() @@ -529,6 +533,7 @@ impl<'a, 'b:'a> ImportResolver<'a, 'b> { self.resolve_glob_import(directive); return Success(()); } + _ => unreachable!(), }; let mut indeterminate = false; @@ -616,6 +621,7 @@ impl<'a, 'b:'a> ImportResolver<'a, 'b> { } return Success(()); } + _ => unreachable!(), }; for &(ns, result) in &[(ValueNS, value_result), (TypeNS, type_result)] { @@ -767,6 +773,10 @@ impl<'a, 'b:'a> ImportResolver<'a, 'b> { *module.globs.borrow_mut() = Vec::new(); let mut reexports = Vec::new(); + if module as *const _ == self.graph_root as *const _ { + reexports = mem::replace(&mut self.macro_exports, Vec::new()); + } + for (&(name, ns), resolution) in module.resolutions.borrow().iter() { let resolution = resolution.borrow(); let binding = match resolution.binding { @@ -831,5 +841,6 @@ fn import_directive_subclass_to_string(subclass: &ImportDirectiveSubclass) -> St match *subclass { SingleImport { source, .. } => source.to_string(), GlobImport { .. } => "*".to_string(), + ExternCrate => "".to_string(), } } diff --git a/src/librustc_save_analysis/dump_visitor.rs b/src/librustc_save_analysis/dump_visitor.rs index 36c6a6760137f..e83c2359979c0 100644 --- a/src/librustc_save_analysis/dump_visitor.rs +++ b/src/librustc_save_analysis/dump_visitor.rs @@ -341,6 +341,7 @@ impl<'l, 'tcx: 'l, 'll, D: Dump + 'll> DumpVisitor<'l, 'tcx, 'll, D> { Def::AssociatedTy(..) | Def::AssociatedConst(..) | Def::PrimTy(_) | + Def::Macro(_) | Def::Err => { span_bug!(span, "process_def_kind for unexpected item: {:?}", diff --git a/src/librustc_save_analysis/lib.rs b/src/librustc_save_analysis/lib.rs index fded34d2c856c..ab5bbea07a301 100644 --- a/src/librustc_save_analysis/lib.rs +++ b/src/librustc_save_analysis/lib.rs @@ -565,6 +565,7 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> { Def::PrimTy(..) | Def::SelfTy(..) | Def::Label(..) | + Def::Macro(..) | Def::Err => None, } } diff --git a/src/librustdoc/core.rs b/src/librustdoc/core.rs index 810bea4c5b098..a25cb0bacc5cf 100644 --- a/src/librustdoc/core.rs +++ b/src/librustdoc/core.rs @@ -14,7 +14,7 @@ use rustc_driver::{driver, target_features, abort_on_err}; use rustc::dep_graph::DepGraph; use rustc::session::{self, config}; use rustc::hir::def_id::DefId; -use rustc::hir::def::Def; +use rustc::hir::def::{Def, ExportMap}; use rustc::middle::privacy::AccessLevels; use rustc::ty::{self, TyCtxt}; use rustc::hir::map as hir_map; @@ -74,6 +74,7 @@ pub struct DocContext<'a, 'tcx: 'a> { pub ty_substs: RefCell>, /// Table node id of lifetime parameter definition -> substituted lifetime pub lt_substs: RefCell>, + pub export_map: ExportMap, } impl<'b, 'tcx> DocContext<'b, 'tcx> { @@ -196,7 +197,7 @@ pub fn run_core(search_paths: SearchPaths, sess.fatal("Compilation failed, aborting rustdoc"); } - let ty::CrateAnalysis { access_levels, .. } = analysis; + let ty::CrateAnalysis { access_levels, export_map, .. } = analysis; // Convert from a NodeId set to a DefId set since we don't always have easy access // to the map from defid -> nodeid @@ -218,6 +219,7 @@ pub fn run_core(search_paths: SearchPaths, renderinfo: Default::default(), ty_substs: Default::default(), lt_substs: Default::default(), + export_map: export_map, }; debug!("crate: {:?}", ctxt.map.krate()); diff --git a/src/librustdoc/test.rs b/src/librustdoc/test.rs index 1bbd67fb9be3a..12d33dcb207f7 100644 --- a/src/librustdoc/test.rs +++ b/src/librustdoc/test.rs @@ -87,7 +87,7 @@ pub fn run(input: &str, config::build_configuration(&sess, config::parse_cfgspecs(cfgs.clone())); let krate = panictry!(driver::phase_1_parse_input(&sess, &input)); - let driver::ExpansionResult { defs, mut hir_forest, .. } = { + let driver::ExpansionResult { defs, mut hir_forest, analysis, .. } = { phase_2_configure_and_expand( &sess, &cstore, krate, None, "rustdoc-test", None, MakeGlobMap::No, |_| Ok(()) ).expect("phase_2_configure_and_expand aborted in rustdoc!") @@ -110,6 +110,7 @@ pub fn run(input: &str, renderinfo: Default::default(), ty_substs: Default::default(), lt_substs: Default::default(), + export_map: analysis.export_map, }; let mut v = RustdocVisitor::new(&ctx); diff --git a/src/librustdoc/visit_ast.rs b/src/librustdoc/visit_ast.rs index 6e47c037ad3db..b91d71198e819 100644 --- a/src/librustdoc/visit_ast.rs +++ b/src/librustdoc/visit_ast.rs @@ -85,8 +85,9 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> { &krate.module, None); // attach the crate's exported macros to the top-level module: - self.module.macros = krate.exported_macros.iter() - .map(|def| self.visit_macro(def)).collect(); + let macro_exports: Vec<_> = + krate.exported_macros.iter().map(|def| self.visit_macro(def)).collect(); + self.module.macros.extend(macro_exports); self.module.is_crate = true; } @@ -191,6 +192,28 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> { let item = self.cx.map.expect_item(i.id); self.visit_item(item, None, &mut om); } + if let Some(exports) = self.cx.export_map.get(&id) { + for export in exports { + if let Def::Macro(def_id) = export.def { + if def_id.krate == LOCAL_CRATE { + continue // These are `krate.exported_macros`, handled in `self.visit()`. + } + let def = self.cx.sess().cstore.load_macro(def_id, self.cx.sess()); + // FIXME(jseyfried) merge with `self.visit_macro()` + let matchers = def.body.chunks(4).map(|arm| arm[0].get_span()).collect(); + om.macros.push(Macro { + id: def.id, + attrs: def.attrs.clone().into(), + name: def.ident.name, + whence: def.span, + matchers: matchers, + stab: self.stability(def.id), + depr: self.deprecation(def.id), + imported_from: def.imported_from.map(|ident| ident.name), + }) + } + } + } om } diff --git a/src/test/compile-fail/no-link.rs b/src/test/compile-fail/no-link.rs index 8f6da99806b3b..5ea07403cf793 100644 --- a/src/test/compile-fail/no-link.rs +++ b/src/test/compile-fail/no-link.rs @@ -8,11 +8,11 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +// aux-build:empty-struct.rs + #[no_link] -extern crate libc; +extern crate empty_struct; fn main() { - unsafe { - libc::abs(0); //~ ERROR unresolved name - } + empty_struct::XEmpty1; //~ ERROR unresolved name }