Auto merge of #38024 - jseyfried:avoid_needless_proc_macro_deps, r=nrc

Avoid loading needless proc-macro dependencies

Fixes #37958 when no proc-macros are exported; in particular, without `pub extern crate proc_macros;`, `#![feature(macro_reexport)]`, or `#![feature(use_extern_macros)]`.

I opened https://github.com/rust-lang/cargo/issues/3334 for exported proc macros.

r? @alexcrichton
This commit is contained in:
bors 2016-11-28 07:03:43 -06:00 committed by GitHub
commit 39c267a8d5
8 changed files with 48 additions and 27 deletions

View File

@ -67,6 +67,9 @@ pub struct CrateSource {
#[derive(RustcEncodable, RustcDecodable, Copy, Clone, Ord, PartialOrd, Eq, PartialEq, Debug)] #[derive(RustcEncodable, RustcDecodable, Copy, Clone, Ord, PartialOrd, Eq, PartialEq, Debug)]
pub enum DepKind { pub enum DepKind {
/// A dependency that is only used for its macros, none of which are visible from other crates.
/// These are included in the metadata only as placeholders and are ignored when decoding.
UnexportedMacrosOnly,
/// A dependency that is only used for its macros. /// A dependency that is only used for its macros.
MacrosOnly, MacrosOnly,
/// A dependency that is always injected into the dependency list and so /// A dependency that is always injected into the dependency list and so
@ -77,6 +80,15 @@ pub enum DepKind {
Explicit, Explicit,
} }
impl DepKind {
pub fn macros_only(self) -> bool {
match self {
DepKind::UnexportedMacrosOnly | DepKind::MacrosOnly => true,
DepKind::Implicit | DepKind::Explicit => false,
}
}
}
#[derive(PartialEq, Clone, Debug)] #[derive(PartialEq, Clone, Debug)]
pub enum LibSource { pub enum LibSource {
Some(PathBuf), Some(PathBuf),
@ -220,6 +232,7 @@ pub trait CrateStore<'tcx> {
fn dylib_dependency_formats(&self, cnum: CrateNum) fn dylib_dependency_formats(&self, cnum: CrateNum)
-> Vec<(CrateNum, LinkagePreference)>; -> Vec<(CrateNum, LinkagePreference)>;
fn dep_kind(&self, cnum: CrateNum) -> DepKind; fn dep_kind(&self, cnum: CrateNum) -> DepKind;
fn export_macros(&self, cnum: CrateNum);
fn lang_items(&self, cnum: CrateNum) -> Vec<(DefIndex, usize)>; fn lang_items(&self, cnum: CrateNum) -> Vec<(DefIndex, usize)>;
fn missing_lang_items(&self, cnum: CrateNum) -> Vec<lang_items::LangItem>; fn missing_lang_items(&self, cnum: CrateNum) -> Vec<lang_items::LangItem>;
fn is_staged_api(&self, cnum: CrateNum) -> bool; fn is_staged_api(&self, cnum: CrateNum) -> bool;
@ -393,6 +406,7 @@ impl<'tcx> CrateStore<'tcx> for DummyCrateStore {
{ bug!("missing_lang_items") } { bug!("missing_lang_items") }
fn is_staged_api(&self, cnum: CrateNum) -> bool { bug!("is_staged_api") } fn is_staged_api(&self, cnum: CrateNum) -> bool { bug!("is_staged_api") }
fn dep_kind(&self, cnum: CrateNum) -> DepKind { bug!("is_explicitly_linked") } fn dep_kind(&self, cnum: CrateNum) -> DepKind { bug!("is_explicitly_linked") }
fn export_macros(&self, cnum: CrateNum) { bug!("export_macros") }
fn is_allocator(&self, cnum: CrateNum) -> bool { bug!("is_allocator") } fn is_allocator(&self, cnum: CrateNum) -> bool { bug!("is_allocator") }
fn is_panic_runtime(&self, cnum: CrateNum) -> bool { bug!("is_panic_runtime") } fn is_panic_runtime(&self, cnum: CrateNum) -> bool { bug!("is_panic_runtime") }
fn is_compiler_builtins(&self, cnum: CrateNum) -> bool { bug!("is_compiler_builtins") } fn is_compiler_builtins(&self, cnum: CrateNum) -> bool { bug!("is_compiler_builtins") }

View File

@ -124,7 +124,7 @@ fn calculate_type(sess: &session::Session,
return v; return v;
} }
for cnum in sess.cstore.crates() { for cnum in sess.cstore.crates() {
if sess.cstore.dep_kind(cnum) == DepKind::MacrosOnly { continue } if sess.cstore.dep_kind(cnum).macros_only() { continue }
let src = sess.cstore.used_crate_source(cnum); let src = sess.cstore.used_crate_source(cnum);
if src.rlib.is_some() { continue } if src.rlib.is_some() { continue }
sess.err(&format!("dependency `{}` not found in rlib format", sess.err(&format!("dependency `{}` not found in rlib format",
@ -157,7 +157,7 @@ fn calculate_type(sess: &session::Session,
// dependencies, ensuring there are no conflicts. The only valid case for a // 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. // dependency to be relied upon twice is for both cases to rely on a dylib.
for cnum in sess.cstore.crates() { for cnum in sess.cstore.crates() {
if sess.cstore.dep_kind(cnum) == DepKind::MacrosOnly { continue } if sess.cstore.dep_kind(cnum).macros_only() { continue }
let name = sess.cstore.crate_name(cnum); let name = sess.cstore.crate_name(cnum);
let src = sess.cstore.used_crate_source(cnum); let src = sess.cstore.used_crate_source(cnum);
if src.dylib.is_some() { if src.dylib.is_some() {

View File

@ -171,7 +171,7 @@ impl<'a> CrateLoader<'a> {
name: name, name: name,
id: i.id, id: i.id,
dep_kind: if attr::contains_name(&i.attrs, "no_link") { dep_kind: if attr::contains_name(&i.attrs, "no_link") {
DepKind::MacrosOnly DepKind::UnexportedMacrosOnly
} else { } else {
DepKind::Explicit DepKind::Explicit
}, },
@ -350,7 +350,7 @@ impl<'a> CrateLoader<'a> {
}; };
self.load(&mut locate_ctxt).or_else(|| { self.load(&mut locate_ctxt).or_else(|| {
dep_kind = DepKind::MacrosOnly; dep_kind = DepKind::UnexportedMacrosOnly;
let mut proc_macro_locator = locator::Context { let mut proc_macro_locator = locator::Context {
target: &self.sess.host, target: &self.sess.host,
@ -373,7 +373,7 @@ impl<'a> CrateLoader<'a> {
LoadResult::Previous(cnum) => { LoadResult::Previous(cnum) => {
let data = self.cstore.get_crate_data(cnum); let data = self.cstore.get_crate_data(cnum);
if data.root.macro_derive_registrar.is_some() { if data.root.macro_derive_registrar.is_some() {
dep_kind = DepKind::MacrosOnly; dep_kind = DepKind::UnexportedMacrosOnly;
} }
data.dep_kind.set(cmp::max(data.dep_kind.get(), dep_kind)); data.dep_kind.set(cmp::max(data.dep_kind.get(), dep_kind));
(cnum, data) (cnum, data)
@ -460,11 +460,14 @@ impl<'a> CrateLoader<'a> {
return cstore::CrateNumMap::new(); return cstore::CrateNumMap::new();
} }
// The map from crate numbers in the crate we're resolving to local crate // The map from crate numbers in the crate we're resolving to local crate numbers.
// numbers // We map 0 and all other holes in the map to our parent crate. The "additional"
let deps = crate_root.crate_deps.decode(metadata); // self-dependencies should be harmless.
let map: FxHashMap<_, _> = deps.enumerate().map(|(crate_num, dep)| { ::std::iter::once(krate).chain(crate_root.crate_deps.decode(metadata).map(|dep| {
debug!("resolving dep crate {} hash: `{}`", dep.name, dep.hash); debug!("resolving dep crate {} hash: `{}`", dep.name, dep.hash);
if dep.kind == DepKind::UnexportedMacrosOnly {
return krate;
}
let dep_kind = match dep_kind { let dep_kind = match dep_kind {
DepKind::MacrosOnly => DepKind::MacrosOnly, DepKind::MacrosOnly => DepKind::MacrosOnly,
_ => dep.kind, _ => dep.kind,
@ -472,16 +475,8 @@ impl<'a> CrateLoader<'a> {
let (local_cnum, ..) = self.resolve_crate( let (local_cnum, ..) = self.resolve_crate(
root, dep.name, dep.name, Some(&dep.hash), span, PathKind::Dependency, dep_kind, root, dep.name, dep.name, Some(&dep.hash), span, PathKind::Dependency, dep_kind,
); );
(CrateNum::new(crate_num + 1), local_cnum) local_cnum
}).collect(); })).collect()
let max_cnum = map.values().cloned().max().map(|cnum| cnum.as_u32()).unwrap_or(0);
// we map 0 and all other holes in the map to our parent crate. The "additional"
// self-dependencies should be harmless.
(0..max_cnum+1).map(|cnum| {
map.get(&CrateNum::from_u32(cnum)).cloned().unwrap_or(krate)
}).collect()
} }
fn read_extension_crate(&mut self, span: Span, info: &ExternCrateInfo) -> ExtensionCrate { fn read_extension_crate(&mut self, span: Span, info: &ExternCrateInfo) -> ExtensionCrate {
@ -614,7 +609,7 @@ impl<'a> CrateLoader<'a> {
name: Symbol::intern(name), name: Symbol::intern(name),
ident: Symbol::intern(name), ident: Symbol::intern(name),
id: ast::DUMMY_NODE_ID, id: ast::DUMMY_NODE_ID,
dep_kind: DepKind::MacrosOnly, dep_kind: DepKind::UnexportedMacrosOnly,
}); });
if ekrate.target_only { if ekrate.target_only {

View File

@ -197,7 +197,7 @@ impl CStore {
.borrow() .borrow()
.iter() .iter()
.filter_map(|(&cnum, data)| { .filter_map(|(&cnum, data)| {
if data.dep_kind.get() == DepKind::MacrosOnly { return None; } if data.dep_kind.get().macros_only() { return None; }
let path = match prefer { let path = match prefer {
LinkagePreference::RequireDynamic => data.source.dylib.clone().map(|p| p.0), LinkagePreference::RequireDynamic => data.source.dylib.clone().map(|p| p.0),
LinkagePreference::RequireStatic => data.source.rlib.clone().map(|p| p.0), LinkagePreference::RequireStatic => data.source.rlib.clone().map(|p| p.0),

View File

@ -228,6 +228,12 @@ impl<'tcx> CrateStore<'tcx> for cstore::CStore {
self.get_crate_data(cnum).dep_kind.get() self.get_crate_data(cnum).dep_kind.get()
} }
fn export_macros(&self, cnum: CrateNum) {
if self.get_crate_data(cnum).dep_kind.get() == DepKind::UnexportedMacrosOnly {
self.get_crate_data(cnum).dep_kind.set(DepKind::MacrosOnly)
}
}
fn lang_items(&self, cnum: CrateNum) -> Vec<(DefIndex, usize)> fn lang_items(&self, cnum: CrateNum) -> Vec<(DefIndex, usize)>
{ {
self.get_crate_data(cnum).get_lang_items() self.get_crate_data(cnum).get_lang_items()

View File

@ -21,7 +21,7 @@ use rustc::util::nodemap::FxHashMap;
use rustc::hir; use rustc::hir;
use rustc::hir::intravisit::IdRange; use rustc::hir::intravisit::IdRange;
use rustc::middle::cstore::{DepKind, InlinedItem, LinkagePreference}; use rustc::middle::cstore::{InlinedItem, LinkagePreference};
use rustc::hir::def::{self, Def, CtorKind}; use rustc::hir::def::{self, Def, CtorKind};
use rustc::hir::def_id::{CrateNum, DefId, DefIndex, CRATE_DEF_INDEX, LOCAL_CRATE}; use rustc::hir::def_id::{CrateNum, DefId, DefIndex, CRATE_DEF_INDEX, LOCAL_CRATE};
use rustc::middle::lang_items; use rustc::middle::lang_items;
@ -729,7 +729,7 @@ impl<'a, 'tcx> CrateMetadata {
}; };
// Iterate over all children. // Iterate over all children.
let macros_only = self.dep_kind.get() == DepKind::MacrosOnly; let macros_only = self.dep_kind.get().macros_only();
for child_index in item.children.decode(self) { for child_index in item.children.decode(self) {
if macros_only { if macros_only {
continue continue

View File

@ -21,7 +21,7 @@ use Namespace::{self, TypeNS, ValueNS, MacroNS};
use ResolveResult::Success; use ResolveResult::Success;
use {resolve_error, resolve_struct_error, ResolutionError}; use {resolve_error, resolve_struct_error, ResolutionError};
use rustc::middle::cstore::{DepKind, LoadedMacro}; use rustc::middle::cstore::LoadedMacro;
use rustc::hir::def::*; use rustc::hir::def::*;
use rustc::hir::def_id::{CrateNum, CRATE_DEF_INDEX, DefId}; use rustc::hir::def_id::{CrateNum, CRATE_DEF_INDEX, DefId};
use rustc::ty; use rustc::ty;
@ -492,7 +492,7 @@ impl<'b> Resolver<'b> {
fn get_extern_crate_root(&mut self, cnum: CrateNum) -> Module<'b> { fn get_extern_crate_root(&mut self, cnum: CrateNum) -> Module<'b> {
let def_id = DefId { krate: cnum, index: CRATE_DEF_INDEX }; let def_id = DefId { krate: cnum, index: CRATE_DEF_INDEX };
let macros_only = self.session.cstore.dep_kind(cnum) == DepKind::MacrosOnly; let macros_only = self.session.cstore.dep_kind(cnum).macros_only();
let arenas = self.arenas; let arenas = self.arenas;
*self.extern_crate_roots.entry((cnum, macros_only)).or_insert_with(|| { *self.extern_crate_roots.entry((cnum, macros_only)).or_insert_with(|| {
arenas.alloc_module(ModuleS { arenas.alloc_module(ModuleS {
@ -567,7 +567,8 @@ impl<'b> Resolver<'b> {
if self.current_module.parent.is_some() && legacy_imports != LegacyMacroImports::default() { if self.current_module.parent.is_some() && legacy_imports != LegacyMacroImports::default() {
span_err!(self.session, item.span, E0468, span_err!(self.session, item.span, E0468,
"an `extern crate` loading macros must be at the crate root"); "an `extern crate` loading macros must be at the crate root");
} else if self.session.cstore.dep_kind(cnum) == DepKind::MacrosOnly && } else if !self.use_extern_macros &&
self.session.cstore.dep_kind(cnum).macros_only() &&
legacy_imports == LegacyMacroImports::default() { legacy_imports == LegacyMacroImports::default() {
let msg = "custom derive crates and `#[no_link]` crates have no effect without \ let msg = "custom derive crates and `#[no_link]` crates have no effect without \
`#[macro_use]`"; `#[macro_use]`";
@ -590,7 +591,9 @@ impl<'b> Resolver<'b> {
} }
} }
for (name, span) in legacy_imports.reexports { for (name, span) in legacy_imports.reexports {
self.used_crates.insert(module.def_id().unwrap().krate); let krate = module.def_id().unwrap().krate;
self.used_crates.insert(krate);
self.session.cstore.export_macros(krate);
let result = self.resolve_name_in_module(module, name, MacroNS, false, None); let result = self.resolve_name_in_module(module, name, MacroNS, false, None);
if let Success(binding) = result { if let Success(binding) = result {
self.macro_exports.push(Export { name: name, def: binding.def() }); self.macro_exports.push(Export { name: name, def: binding.def() });

View File

@ -743,6 +743,9 @@ impl<'a, 'b:'a> ImportResolver<'a, 'b> {
(binding.is_import() || binding.is_extern_crate()) { (binding.is_import() || binding.is_extern_crate()) {
let def = binding.def(); let def = binding.def();
if def != Def::Err { if def != Def::Err {
if !def.def_id().is_local() {
self.session.cstore.export_macros(def.def_id().krate);
}
reexports.push(Export { name: name, def: def }); reexports.push(Export { name: name, def: def });
} }
} }