From dd0781ea254564cad86e3d594367b1988edf308d Mon Sep 17 00:00:00 2001 From: Jeffrey Seyfried Date: Fri, 28 Oct 2016 05:56:06 +0000 Subject: [PATCH] Register and stability check `#[no_link]` crates. --- src/librustc/middle/cstore.rs | 2 + src/librustc/middle/dependency_format.rs | 2 + src/librustc_llvm/lib.rs | 1 + src/librustc_metadata/creader.rs | 52 ++++++++++----------- src/librustc_metadata/cstore.rs | 13 +++--- src/librustc_metadata/decoder.rs | 6 ++- src/librustc_resolve/build_reduced_graph.rs | 5 +- src/librustc_resolve/lib.rs | 2 +- src/test/compile-fail/no-link.rs | 8 ++-- 9 files changed, 50 insertions(+), 41 deletions(-) diff --git a/src/librustc/middle/cstore.rs b/src/librustc/middle/cstore.rs index cb2a4b3f622..bdef44bf5c1 100644 --- a/src/librustc/middle/cstore.rs +++ b/src/librustc/middle/cstore.rs @@ -65,6 +65,8 @@ pub struct CrateSource { #[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, diff --git a/src/librustc/middle/dependency_format.rs b/src/librustc/middle/dependency_format.rs index 2267c42b543..92d1ab85c5a 100644 --- a/src/librustc/middle/dependency_format.rs +++ b/src/librustc/middle/dependency_format.rs @@ -124,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", @@ -156,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() { diff --git a/src/librustc_llvm/lib.rs b/src/librustc_llvm/lib.rs index da09bfa66d2..07b87072c43 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 08168fd4fd7..9101f95c882 100644 --- a/src/librustc_metadata/creader.rs +++ b/src/librustc_metadata/creader.rs @@ -67,16 +67,12 @@ fn dump_crates(cstore: &CStore) { }) } -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, @@ -168,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 @@ -283,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 \ @@ -427,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 @@ -435,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.kind); + 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(); @@ -455,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; @@ -641,7 +643,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 { @@ -984,30 +986,26 @@ impl<'a> middle::cstore::CrateLoader for CrateLoader<'a> { 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 { + // If this is a proc-macro crate, return here to avoid registering. + if loaded_macros.is_proc_macros() { return Some(loaded_macros); } // 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, DepKind::Explicit); + 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, DepKind::Explicit, + &None, &info.ident, &info.name, None, item.span, PathKind::Crate, info.dep_kind, ); let def_id = definitions.opt_local_def_id(item.id).unwrap(); diff --git a/src/librustc_metadata/cstore.rs b/src/librustc_metadata/cstore.rs index 36d55dd95b9..10e86c427a8 100644 --- a/src/librustc_metadata/cstore.rs +++ b/src/librustc_metadata/cstore.rs @@ -192,12 +192,13 @@ impl CStore { let mut libs = self.metas .borrow() .iter() - .map(|(&cnum, data)| { - (cnum, - match prefer { - LinkagePreference::RequireDynamic => data.source.dylib.clone().map(|p| p.0), - LinkagePreference::RequireStatic => data.source.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/decoder.rs b/src/librustc_metadata/decoder.rs index 7973cd880fe..1da26418965 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; @@ -690,6 +690,10 @@ impl<'a, 'tcx> CrateMetadata { pub fn each_child_of_item(&self, id: DefIndex, mut callback: F) where F: FnMut(def::Export) { + if self.dep_kind.get() == DepKind::MacrosOnly { + return + } + // Find the item. let item = match self.maybe_entry(id) { None => return, diff --git a/src/librustc_resolve/build_reduced_graph.rs b/src/librustc_resolve/build_reduced_graph.rs index d987930544e..ed87c61ef3b 100644 --- a/src/librustc_resolve/build_reduced_graph.rs +++ b/src/librustc_resolve/build_reduced_graph.rs @@ -22,7 +22,7 @@ use {NameBinding, NameBindingKind, ToNameBinding}; use Resolver; use {resolve_error, resolve_struct_error, ResolutionError}; -use rustc::middle::cstore::LoadedMacros; +use rustc::middle::cstore::{DepKind, LoadedMacros}; use rustc::hir::def::*; use rustc::hir::def_id::{CrateNum, CRATE_DEF_INDEX, DefId}; use rustc::ty; @@ -499,8 +499,9 @@ 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).or_insert_with(|| { + *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())) diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index b16b61b46b8..89a0826254c 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -1083,7 +1083,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>, + 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, diff --git a/src/test/compile-fail/no-link.rs b/src/test/compile-fail/no-link.rs index 8f6da99806b..5ea07403cf7 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 }