From 64a70342e67f09b5326538b08990d1b0d2900a5b Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Wed, 30 Aug 2017 14:48:57 -0700 Subject: [PATCH] rustc: Remove a number of mutable fields in cstore This commit started by moving methods from `CrateStore` to queries, but it ended up necessitating some deeper refactorings to move more items in general to queries. Before this commit the *resolver* would walk over the AST and process foreign modules (`extern { .. }` blocks) and collect `#[link]` annotations. It would then also process the command line `-l` directives and such. This information was then stored as precalculated lists in the `CrateStore` object for iterating over later. After this, commit, however, this pass no longer happens during resolution but now instead happens through queries. A query for the linked libraries of a crate will crawl the crate for `extern` blocks and then process the linkage annotations at that time. --- src/librustc/dep_graph/dep_node.rs | 5 + src/librustc/middle/cstore.rs | 12 - src/librustc/ty/maps.rs | 17 ++ src/librustc_driver/driver.rs | 1 - src/librustc_metadata/creader.rs | 221 +----------------- src/librustc_metadata/cstore.rs | 38 +-- src/librustc_metadata/cstore_impl.rs | 60 ++--- src/librustc_metadata/diagnostics.rs | 6 +- src/librustc_metadata/encoder.rs | 4 +- src/librustc_metadata/lib.rs | 2 + src/librustc_metadata/link_args.rs | 65 ++++++ src/librustc_metadata/native_libs.rs | 217 +++++++++++++++++ src/librustc_trans/back/link.rs | 12 +- src/librustc_trans/base.rs | 5 +- src/librustc_trans/callee.rs | 2 +- src/librustc_trans/consts.rs | 2 +- src/librustc_trans/lib.rs | 2 + src/test/compile-fail/empty-linkname.rs | 2 + .../feature-gate-static-nobundle.rs | 2 + 19 files changed, 366 insertions(+), 309 deletions(-) create mode 100644 src/librustc_metadata/link_args.rs create mode 100644 src/librustc_metadata/native_libs.rs diff --git a/src/librustc/dep_graph/dep_node.rs b/src/librustc/dep_graph/dep_node.rs index a3e38e5b8ad..9646d3a7b3b 100644 --- a/src/librustc/dep_graph/dep_node.rs +++ b/src/librustc/dep_graph/dep_node.rs @@ -545,6 +545,11 @@ pub fn to_dep_node(self, tcx: TyCtxt, kind: DepKind) -> DepNode { [] ImplementationsOfTrait { krate: CrateNum, trait_id: DefId }, [] AllTraitImplementations(CrateNum), + + [] IsDllimportForeignItem(DefId), + [] IsStaticallyIncludedForeignItem(DefId), + [] NativeLibraryKind(DefId), + [] LinkArgs, ); trait DepNodeParams<'a, 'gcx: 'tcx + 'a, 'tcx: 'a> : fmt::Debug { diff --git a/src/librustc/middle/cstore.rs b/src/librustc/middle/cstore.rs index 495b357b613..97b04747410 100644 --- a/src/librustc/middle/cstore.rs +++ b/src/librustc/middle/cstore.rs @@ -236,10 +236,6 @@ pub trait CrateStore { // trait/impl-item info fn associated_item_cloned(&self, def: DefId) -> ty::AssociatedItem; - // flags - fn is_dllimport_foreign_item(&self, def: DefId) -> bool; - fn is_statically_included_foreign_item(&self, def_id: DefId) -> bool; - // crate metadata fn dep_kind(&self, cnum: CrateNum) -> DepKind; fn export_macros(&self, cnum: CrateNum); @@ -265,8 +261,6 @@ fn item_body<'a, 'tcx>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId) // This is basically a 1-based range of ints, which is a little // silly - I may fix that. fn crates(&self) -> Vec; - fn used_libraries(&self) -> Vec; - fn used_link_args(&self) -> Vec; // utility functions fn used_crates(&self, prefer: LinkagePreference) -> Vec<(CrateNum, LibSource)>; @@ -329,10 +323,6 @@ fn item_generics_cloned(&self, def: DefId) -> ty::Generics fn associated_item_cloned(&self, def: DefId) -> ty::AssociatedItem { bug!("associated_item_cloned") } - // flags - fn is_dllimport_foreign_item(&self, id: DefId) -> bool { false } - fn is_statically_included_foreign_item(&self, def_id: DefId) -> bool { false } - // crate metadata fn lang_items(&self, cnum: CrateNum) -> Vec<(DefIndex, usize)> { bug!("lang_items") } @@ -368,8 +358,6 @@ fn item_body<'a, 'tcx>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId) // This is basically a 1-based range of ints, which is a little // silly - I may fix that. fn crates(&self) -> Vec { vec![] } - fn used_libraries(&self) -> Vec { vec![] } - fn used_link_args(&self) -> Vec { vec![] } // utility functions fn used_crates(&self, prefer: LinkagePreference) -> Vec<(CrateNum, LibSource)> diff --git a/src/librustc/ty/maps.rs b/src/librustc/ty/maps.rs index 41caaa30b5c..1312bd3a7a6 100644 --- a/src/librustc/ty/maps.rs +++ b/src/librustc/ty/maps.rs @@ -17,6 +17,7 @@ use lint; use middle::const_val; use middle::cstore::{ExternCrate, LinkagePreference, NativeLibrary}; +use middle::cstore::NativeLibraryKind; use middle::privacy::AccessLevels; use middle::region; use mir; @@ -642,6 +643,12 @@ fn describe(_tcx: TyCtxt, _: CrateNum) -> String { } } +impl<'tcx> QueryDescription for queries::link_args<'tcx> { + fn describe(_tcx: TyCtxt, _: CrateNum) -> String { + format!("looking up link arguments for a crate") + } +} + // If enabled, send a message to the profile-queries thread macro_rules! profq_msg { ($tcx:expr, $msg:expr) => { @@ -1230,6 +1237,12 @@ fn default() -> Self { -> Rc>, [] fn all_trait_implementations: AllTraitImplementations(CrateNum) -> Rc>, + + [] is_dllimport_foreign_item: IsDllimportForeignItem(DefId) -> bool, + [] is_statically_included_foreign_item: IsStaticallyIncludedForeignItem(DefId) -> bool, + [] native_library_kind: NativeLibraryKind(DefId) + -> Option, + [] link_args: link_args_node(CrateNum) -> Rc>, } fn type_param_predicates<'tcx>((item_id, param_id): (DefId, DefId)) -> DepConstructor<'tcx> { @@ -1315,3 +1328,7 @@ fn implementations_of_trait_node<'tcx>((krate, trait_id): (CrateNum, DefId)) { DepConstructor::ImplementationsOfTrait { krate, trait_id } } + +fn link_args_node<'tcx>(_: CrateNum) -> DepConstructor<'tcx> { + DepConstructor::LinkArgs +} diff --git a/src/librustc_driver/driver.rs b/src/librustc_driver/driver.rs index 000d89241a4..10b591432ee 100644 --- a/src/librustc_driver/driver.rs +++ b/src/librustc_driver/driver.rs @@ -694,7 +694,6 @@ pub fn phase_2_configure_and_expand(sess: &Session, // this back at some point. let _ignore = sess.dep_graph.in_ignore(); let mut crate_loader = CrateLoader::new(sess, &cstore, crate_name); - crate_loader.preprocess(&krate); let resolver_arenas = Resolver::arenas(); let mut resolver = Resolver::new(sess, &krate, diff --git a/src/librustc_metadata/creader.rs b/src/librustc_metadata/creader.rs index 4c25d03b441..aba5949c5a7 100644 --- a/src/librustc_metadata/creader.rs +++ b/src/librustc_metadata/creader.rs @@ -12,6 +12,7 @@ use cstore::{self, CStore, CrateSource, MetadataBlob}; use locator::{self, CratePaths}; +use native_libs::relevant_lib; use schema::{CrateRoot, Tracked}; use rustc::hir::def_id::{CrateNum, DefIndex}; @@ -26,7 +27,6 @@ use rustc::middle::cstore::{CrateStore, validate_crate_name, ExternCrate}; use rustc::util::common::record_time; use rustc::util::nodemap::FxHashSet; -use rustc::middle::cstore::NativeLibrary; use rustc::hir::map::Definitions; use std::cell::{RefCell, Cell}; @@ -36,10 +36,8 @@ use std::{cmp, fs}; use syntax::ast; -use syntax::abi::Abi; use syntax::attr; use syntax::ext::base::SyntaxExtension; -use syntax::feature_gate::{self, GateIssue}; use syntax::symbol::Symbol; use syntax::visit; use syntax_pos::{Span, DUMMY_SP}; @@ -81,56 +79,6 @@ struct ExternCrateInfo { dep_kind: DepKind, } -fn register_native_lib(sess: &Session, - cstore: &CStore, - span: Option, - lib: NativeLibrary) { - if lib.name.as_str().is_empty() { - match span { - Some(span) => { - struct_span_err!(sess, span, E0454, - "#[link(name = \"\")] given with empty name") - .span_label(span, "empty name given") - .emit(); - } - None => { - sess.err("empty library name given via `-l`"); - } - } - return - } - let is_osx = sess.target.target.options.is_like_osx; - if lib.kind == cstore::NativeFramework && !is_osx { - let msg = "native frameworks are only available on macOS targets"; - match span { - Some(span) => span_err!(sess, span, E0455, "{}", msg), - None => sess.err(msg), - } - } - if lib.cfg.is_some() && !sess.features.borrow().link_cfg { - feature_gate::emit_feature_err(&sess.parse_sess, - "link_cfg", - span.unwrap(), - GateIssue::Language, - "is feature gated"); - } - if lib.kind == cstore::NativeStaticNobundle && !sess.features.borrow().static_nobundle { - feature_gate::emit_feature_err(&sess.parse_sess, - "static_nobundle", - span.unwrap(), - GateIssue::Language, - "kind=\"static-nobundle\" is feature gated"); - } - cstore.add_used_library(lib); -} - -fn relevant_lib(sess: &Session, lib: &NativeLibrary) -> bool { - match lib.cfg { - Some(ref cfg) => attr::cfg_matches(cfg, &sess.parse_sess, None), - None => true, - } -} - // Extra info about a crate loaded for plugins or exported macros. struct ExtensionCrate { metadata: PMDSource, @@ -721,33 +669,6 @@ pub fn find_plugin_registrar(&mut self, } } - fn get_foreign_items_of_kind(&self, kind: cstore::NativeLibraryKind) -> Vec { - let mut items = vec![]; - let libs = self.cstore.get_used_libraries(); - for lib in libs.borrow().iter() { - if relevant_lib(self.sess, lib) && lib.kind == kind { - items.extend(&lib.foreign_items); - } - } - items - } - - fn register_statically_included_foreign_items(&mut self) { - for id in self.get_foreign_items_of_kind(cstore::NativeStatic) { - self.cstore.add_statically_included_foreign_item(id); - } - for id in self.get_foreign_items_of_kind(cstore::NativeStaticNobundle) { - self.cstore.add_statically_included_foreign_item(id); - } - } - - fn register_dllimport_foreign_items(&mut self) { - let mut dllimports = self.cstore.dllimport_foreign_items.borrow_mut(); - for id in self.get_foreign_items_of_kind(cstore::NativeUnknown) { - dllimports.insert(id); - } - } - fn inject_panic_runtime(&mut self, krate: &ast::Crate) { // If we're only compiling an rlib, then there's no need to select a // panic runtime, so we just skip this section entirely. @@ -1152,84 +1073,6 @@ fn inject_dependency_if(&self, } } -impl<'a> CrateLoader<'a> { - pub fn preprocess(&mut self, krate: &ast::Crate) { - for attr in &krate.attrs { - if attr.path == "link_args" { - if let Some(linkarg) = attr.value_str() { - self.cstore.add_used_link_args(&linkarg.as_str()); - } - } - } - } - - fn process_foreign_mod(&mut self, i: &ast::Item, fm: &ast::ForeignMod, - definitions: &Definitions) { - if fm.abi == Abi::Rust || fm.abi == Abi::RustIntrinsic || fm.abi == Abi::PlatformIntrinsic { - return; - } - - // First, add all of the custom #[link_args] attributes - for m in i.attrs.iter().filter(|a| a.check_name("link_args")) { - if let Some(linkarg) = m.value_str() { - self.cstore.add_used_link_args(&linkarg.as_str()); - } - } - - // Next, process all of the #[link(..)]-style arguments - for m in i.attrs.iter().filter(|a| a.check_name("link")) { - let items = match m.meta_item_list() { - Some(item) => item, - None => continue, - }; - let kind = items.iter().find(|k| { - k.check_name("kind") - }).and_then(|a| a.value_str()).map(Symbol::as_str); - let kind = match kind.as_ref().map(|s| &s[..]) { - Some("static") => cstore::NativeStatic, - Some("static-nobundle") => cstore::NativeStaticNobundle, - Some("dylib") => cstore::NativeUnknown, - Some("framework") => cstore::NativeFramework, - Some(k) => { - struct_span_err!(self.sess, m.span, E0458, - "unknown kind: `{}`", k) - .span_label(m.span, "unknown kind").emit(); - cstore::NativeUnknown - } - None => cstore::NativeUnknown - }; - let n = items.iter().find(|n| { - n.check_name("name") - }).and_then(|a| a.value_str()); - let n = match n { - Some(n) => n, - None => { - struct_span_err!(self.sess, m.span, E0459, - "#[link(...)] specified without `name = \"foo\"`") - .span_label(m.span, "missing `name` argument").emit(); - Symbol::intern("foo") - } - }; - let cfg = items.iter().find(|k| { - k.check_name("cfg") - }).and_then(|a| a.meta_item_list()); - let cfg = cfg.map(|list| { - list[0].meta_item().unwrap().clone() - }); - let foreign_items = fm.items.iter() - .map(|it| definitions.opt_def_index(it.id).unwrap()) - .collect(); - let lib = NativeLibrary { - name: n, - kind, - cfg, - foreign_items, - }; - register_native_lib(self.sess, self.cstore, Some(m.span), lib); - } - } -} - impl<'a> middle::cstore::CrateLoader for CrateLoader<'a> { fn postprocess(&mut self, krate: &ast::Crate) { // inject the sanitizer runtime before the allocator runtime because all @@ -1242,72 +1085,10 @@ fn postprocess(&mut self, krate: &ast::Crate) { if log_enabled!(log::LogLevel::Info) { dump_crates(&self.cstore); } - - // Process libs passed on the command line - // First, check for errors - let mut renames = FxHashSet(); - for &(ref name, ref new_name, _) in &self.sess.opts.libs { - if let &Some(ref new_name) = new_name { - if new_name.is_empty() { - self.sess.err( - &format!("an empty renaming target was specified for library `{}`",name)); - } else if !self.cstore.get_used_libraries().borrow().iter() - .any(|lib| lib.name == name as &str) { - self.sess.err(&format!("renaming of the library `{}` was specified, \ - however this crate contains no #[link(...)] \ - attributes referencing this library.", name)); - } else if renames.contains(name) { - self.sess.err(&format!("multiple renamings were specified for library `{}` .", - name)); - } else { - renames.insert(name); - } - } - } - // Update kind and, optionally, the name of all native libaries - // (there may be more than one) with the specified name. - for &(ref name, ref new_name, kind) in &self.sess.opts.libs { - let mut found = false; - for lib in self.cstore.get_used_libraries().borrow_mut().iter_mut() { - if lib.name == name as &str { - let mut changed = false; - if let Some(k) = kind { - lib.kind = k; - changed = true; - } - if let &Some(ref new_name) = new_name { - lib.name = Symbol::intern(new_name); - changed = true; - } - if !changed { - self.sess.warn(&format!("redundant linker flag specified for library `{}`", - name)); - } - - found = true; - } - } - if !found { - // Add if not found - let new_name = new_name.as_ref().map(|s| &**s); // &Option -> Option<&str> - let lib = NativeLibrary { - name: Symbol::intern(new_name.unwrap_or(name)), - kind: if let Some(k) = kind { k } else { cstore::NativeUnknown }, - cfg: None, - foreign_items: Vec::new(), - }; - register_native_lib(self.sess, self.cstore, None, lib); - } - } - self.register_statically_included_foreign_items(); - self.register_dllimport_foreign_items(); } fn process_item(&mut self, item: &ast::Item, definitions: &Definitions) { match item.node { - ast::ItemKind::ForeignMod(ref fm) => { - self.process_foreign_mod(item, fm, definitions) - }, ast::ItemKind::ExternCrate(_) => { let info = self.extract_crate_info(item).unwrap(); let (cnum, ..) = self.resolve_crate( diff --git a/src/librustc_metadata/cstore.rs b/src/librustc_metadata/cstore.rs index 1933949e922..543d257018d 100644 --- a/src/librustc_metadata/cstore.rs +++ b/src/librustc_metadata/cstore.rs @@ -14,7 +14,7 @@ use schema::{self, Tracked}; use rustc::dep_graph::DepGraph; -use rustc::hir::def_id::{CRATE_DEF_INDEX, LOCAL_CRATE, CrateNum, DefIndex, DefId}; +use rustc::hir::def_id::{CRATE_DEF_INDEX, CrateNum, DefIndex, DefId}; use rustc::hir::map::definitions::{DefPathTable, GlobalMetaDataKind}; use rustc::hir::svh::Svh; use rustc::middle::cstore::{DepKind, ExternCrate, MetadataLoader}; @@ -95,10 +95,6 @@ pub struct CStore { metas: RefCell>>, /// Map from NodeId's of local extern crate statements to crate numbers extern_mod_crate_map: RefCell>, - used_libraries: RefCell>, - used_link_args: RefCell>, - statically_included_foreign_items: RefCell>, - pub dllimport_foreign_items: RefCell>, pub visible_parent_map: RefCell>, pub metadata_loader: Box, } @@ -109,10 +105,6 @@ pub fn new(dep_graph: &DepGraph, metadata_loader: Box) -> CStore dep_graph: dep_graph.clone(), metas: RefCell::new(FxHashMap()), extern_mod_crate_map: RefCell::new(FxHashMap()), - used_libraries: RefCell::new(Vec::new()), - used_link_args: RefCell::new(Vec::new()), - statically_included_foreign_items: RefCell::new(FxHashSet()), - dllimport_foreign_items: RefCell::new(FxHashSet()), visible_parent_map: RefCell::new(FxHashMap()), metadata_loader, } @@ -208,38 +200,10 @@ pub fn do_get_used_crates(&self, libs } - pub fn add_used_library(&self, lib: NativeLibrary) { - assert!(!lib.name.as_str().is_empty()); - self.used_libraries.borrow_mut().push(lib); - } - - pub fn get_used_libraries(&self) -> &RefCell> { - &self.used_libraries - } - - pub fn add_used_link_args(&self, args: &str) { - for s in args.split(' ').filter(|s| !s.is_empty()) { - self.used_link_args.borrow_mut().push(s.to_string()); - } - } - - pub fn get_used_link_args<'a>(&'a self) -> &'a RefCell> { - &self.used_link_args - } - pub fn add_extern_mod_stmt_cnum(&self, emod_id: ast::NodeId, cnum: CrateNum) { self.extern_mod_crate_map.borrow_mut().insert(emod_id, cnum); } - pub fn add_statically_included_foreign_item(&self, id: DefIndex) { - self.statically_included_foreign_items.borrow_mut().insert(id); - } - - pub fn do_is_statically_included_foreign_item(&self, def_id: DefId) -> bool { - assert!(def_id.krate == LOCAL_CRATE); - self.statically_included_foreign_items.borrow().contains(&def_id.index) - } - pub fn do_extern_mod_stmt_cnum(&self, emod_id: ast::NodeId) -> Option { self.extern_mod_crate_map.borrow().get(&emod_id).cloned() } diff --git a/src/librustc_metadata/cstore_impl.rs b/src/librustc_metadata/cstore_impl.rs index 67fe62d69be..3f7a314c755 100644 --- a/src/librustc_metadata/cstore_impl.rs +++ b/src/librustc_metadata/cstore_impl.rs @@ -10,19 +10,21 @@ use cstore; use encoder; +use link_args; +use native_libs; use schema; use rustc::ty::maps::QueryConfig; use rustc::middle::cstore::{CrateStore, CrateSource, LibSource, DepKind, - NativeLibrary, MetadataLoader, LinkMeta, + MetadataLoader, LinkMeta, LinkagePreference, LoadedMacro, EncodedMetadata, - EncodedMetadataHashes}; + EncodedMetadataHashes, NativeLibraryKind}; use rustc::hir::def; use rustc::middle::lang_items; use rustc::session::Session; use rustc::ty::{self, TyCtxt}; use rustc::ty::maps::Providers; -use rustc::hir::def_id::{CrateNum, DefId, DefIndex, CRATE_DEF_INDEX, LOCAL_CRATE}; +use rustc::hir::def_id::{CrateNum, DefId, DefIndex, LOCAL_CRATE, CRATE_DEF_INDEX}; use rustc::hir::map::{DefKey, DefPath, DefPathHash}; use rustc::hir::map::blocks::FnLikeNode; use rustc::hir::map::definitions::{DefPathTable, GlobalMetaDataKind}; @@ -199,6 +201,10 @@ fn into_args(self) -> (DefId, DefId) { (self.0.as_def_id(), self.1) } cdata.get_implementations_for_trait(None, &tcx.dep_graph, &mut result); Rc::new(result) } + + is_dllimport_foreign_item => { + cdata.is_dllimport_foreign_item(def_id.index, &tcx.dep_graph) + } } pub fn provide_local<'tcx>(providers: &mut Providers<'tcx>) { @@ -215,6 +221,31 @@ fn is_const_fn<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> bool { *providers = Providers { is_const_fn, + is_dllimport_foreign_item: |tcx, id| { + tcx.native_library_kind(id) == Some(NativeLibraryKind::NativeUnknown) + }, + is_statically_included_foreign_item: |tcx, id| { + match tcx.native_library_kind(id) { + Some(NativeLibraryKind::NativeStatic) | + Some(NativeLibraryKind::NativeStaticNobundle) => true, + _ => false, + } + }, + native_library_kind: |tcx, id| { + tcx.native_libraries(id.krate) + .iter() + .filter(|lib| native_libs::relevant_lib(&tcx.sess, lib)) + .find(|l| l.foreign_items.contains(&id.index)) + .map(|l| l.kind) + }, + native_libraries: |tcx, cnum| { + assert_eq!(cnum, LOCAL_CRATE); + Rc::new(native_libs::collect(tcx)) + }, + link_args: |tcx, cnum| { + assert_eq!(cnum, LOCAL_CRATE); + Rc::new(link_args::collect(tcx)) + }, ..*providers }; } @@ -244,20 +275,6 @@ fn associated_item_cloned(&self, def: DefId) -> ty::AssociatedItem self.get_crate_data(def.krate).get_associated_item(def.index) } - fn is_statically_included_foreign_item(&self, def_id: DefId) -> bool - { - self.do_is_statically_included_foreign_item(def_id) - } - - fn is_dllimport_foreign_item(&self, def_id: DefId) -> bool { - if def_id.krate == LOCAL_CRATE { - self.dllimport_foreign_items.borrow().contains(&def_id.index) - } else { - self.get_crate_data(def_id.krate) - .is_dllimport_foreign_item(def_id.index, &self.dep_graph) - } - } - fn dep_kind(&self, cnum: CrateNum) -> DepKind { let data = self.get_crate_data(cnum); @@ -400,15 +417,6 @@ fn crates(&self) -> Vec result } - fn used_libraries(&self) -> Vec - { - self.get_used_libraries().borrow().clone() - } - - fn used_link_args(&self) -> Vec - { - self.get_used_link_args().borrow().clone() - } fn used_crates(&self, prefer: LinkagePreference) -> Vec<(CrateNum, LibSource)> { self.do_get_used_crates(prefer) diff --git a/src/librustc_metadata/diagnostics.rs b/src/librustc_metadata/diagnostics.rs index 1fa1a896dd6..8ff2acbac9d 100644 --- a/src/librustc_metadata/diagnostics.rs +++ b/src/librustc_metadata/diagnostics.rs @@ -14,7 +14,7 @@ E0454: r##" A link name was given with an empty name. Erroneous code example: -```compile_fail,E0454 +```ignore (cannot-test-this-because-???) #[link(name = "")] extern {} // error: #[link(name = "")] given with empty name ``` @@ -51,7 +51,7 @@ E0458: r##" An unknown "kind" was specified for a link attribute. Erroneous code example: -```compile_fail,E0458 +```ignore (cannot-test-this-because-???) #[link(kind = "wonderful_unicorn")] extern {} // error: unknown kind: `wonderful_unicorn` ``` @@ -67,7 +67,7 @@ E0459: r##" A link was used without a name parameter. Erroneous code example: -```compile_fail,E0459 +```ignore (cannot-test-this-because-???) #[link(kind = "dylib")] extern {} // error: #[link(...)] specified without `name = "foo"` ``` diff --git a/src/librustc_metadata/encoder.rs b/src/librustc_metadata/encoder.rs index 76ad9555d7e..4fd610ac79b 100644 --- a/src/librustc_metadata/encoder.rs +++ b/src/librustc_metadata/encoder.rs @@ -1283,8 +1283,8 @@ fn encode_attributes(&mut self, attrs: &[ast::Attribute]) -> LazySeq LazySeq { - let used_libraries = self.tcx.sess.cstore.used_libraries(); - self.lazy_seq(used_libraries) + let used_libraries = self.tcx.native_libraries(LOCAL_CRATE); + self.lazy_seq(used_libraries.iter().cloned()) } fn encode_crate_deps(&mut self, _: ()) -> LazySeq { diff --git a/src/librustc_metadata/lib.rs b/src/librustc_metadata/lib.rs index f4e6f57c437..54dbb68667b 100644 --- a/src/librustc_metadata/lib.rs +++ b/src/librustc_metadata/lib.rs @@ -50,6 +50,8 @@ mod cstore_impl; mod isolated_encoder; mod schema; +mod native_libs; +mod link_args; pub mod creader; pub mod cstore; diff --git a/src/librustc_metadata/link_args.rs b/src/librustc_metadata/link_args.rs new file mode 100644 index 00000000000..6fafde0d09c --- /dev/null +++ b/src/librustc_metadata/link_args.rs @@ -0,0 +1,65 @@ +// Copyright 2017 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use rustc::hir::itemlikevisit::ItemLikeVisitor; +use rustc::hir; +use rustc::ty::TyCtxt; +use syntax::abi::Abi; + +pub fn collect<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) -> Vec { + let mut collector = Collector { + args: Vec::new(), + }; + tcx.hir.krate().visit_all_item_likes(&mut collector); + + for attr in tcx.hir.krate().attrs.iter() { + if attr.path == "link_args" { + if let Some(linkarg) = attr.value_str() { + collector.add_link_args(&linkarg.as_str()); + } + } + } + + return collector.args +} + +struct Collector { + args: Vec, +} + +impl<'tcx> ItemLikeVisitor<'tcx> for Collector { + fn visit_item(&mut self, it: &'tcx hir::Item) { + let fm = match it.node { + hir::ItemForeignMod(ref fm) => fm, + _ => return, + }; + if fm.abi == Abi::Rust || + fm.abi == Abi::RustIntrinsic || + fm.abi == Abi::PlatformIntrinsic { + return + } + + // First, add all of the custom #[link_args] attributes + for m in it.attrs.iter().filter(|a| a.check_name("link_args")) { + if let Some(linkarg) = m.value_str() { + self.add_link_args(&linkarg.as_str()); + } + } + } + + fn visit_trait_item(&mut self, _it: &'tcx hir::TraitItem) {} + fn visit_impl_item(&mut self, _it: &'tcx hir::ImplItem) {} +} + +impl Collector { + fn add_link_args(&mut self, args: &str) { + self.args.extend(args.split(' ').filter(|s| !s.is_empty()).map(|s| s.to_string())) + } +} diff --git a/src/librustc_metadata/native_libs.rs b/src/librustc_metadata/native_libs.rs new file mode 100644 index 00000000000..669681d2aad --- /dev/null +++ b/src/librustc_metadata/native_libs.rs @@ -0,0 +1,217 @@ +// Copyright 2017 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use rustc::hir::itemlikevisit::ItemLikeVisitor; +use rustc::hir; +use rustc::middle::cstore::{self, NativeLibrary}; +use rustc::session::Session; +use rustc::ty::TyCtxt; +use rustc::util::nodemap::FxHashSet; +use syntax::abi::Abi; +use syntax::attr; +use syntax::codemap::Span; +use syntax::feature_gate::{self, GateIssue}; +use syntax::symbol::Symbol; + +pub fn collect<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) -> Vec { + let mut collector = Collector { + tcx, + libs: Vec::new(), + }; + tcx.hir.krate().visit_all_item_likes(&mut collector); + collector.process_command_line(); + return collector.libs +} + +pub fn relevant_lib(sess: &Session, lib: &NativeLibrary) -> bool { + match lib.cfg { + Some(ref cfg) => attr::cfg_matches(cfg, &sess.parse_sess, None), + None => true, + } +} + +struct Collector<'a, 'tcx: 'a> { + tcx: TyCtxt<'a, 'tcx, 'tcx>, + libs: Vec, +} + +impl<'a, 'tcx> ItemLikeVisitor<'tcx> for Collector<'a, 'tcx> { + fn visit_item(&mut self, it: &'tcx hir::Item) { + let fm = match it.node { + hir::ItemForeignMod(ref fm) => fm, + _ => return, + }; + + if fm.abi == Abi::Rust || + fm.abi == Abi::RustIntrinsic || + fm.abi == Abi::PlatformIntrinsic { + return + } + + // Process all of the #[link(..)]-style arguments + for m in it.attrs.iter().filter(|a| a.check_name("link")) { + let items = match m.meta_item_list() { + Some(item) => item, + None => continue, + }; + let kind = items.iter().find(|k| { + k.check_name("kind") + }).and_then(|a| a.value_str()).map(Symbol::as_str); + let kind = match kind.as_ref().map(|s| &s[..]) { + Some("static") => cstore::NativeStatic, + Some("static-nobundle") => cstore::NativeStaticNobundle, + Some("dylib") => cstore::NativeUnknown, + Some("framework") => cstore::NativeFramework, + Some(k) => { + struct_span_err!(self.tcx.sess, m.span, E0458, + "unknown kind: `{}`", k) + .span_label(m.span, "unknown kind").emit(); + cstore::NativeUnknown + } + None => cstore::NativeUnknown + }; + let n = items.iter().find(|n| { + n.check_name("name") + }).and_then(|a| a.value_str()); + let n = match n { + Some(n) => n, + None => { + struct_span_err!(self.tcx.sess, m.span, E0459, + "#[link(...)] specified without `name = \"foo\"`") + .span_label(m.span, "missing `name` argument").emit(); + Symbol::intern("foo") + } + }; + let cfg = items.iter().find(|k| { + k.check_name("cfg") + }).and_then(|a| a.meta_item_list()); + let cfg = cfg.map(|list| { + list[0].meta_item().unwrap().clone() + }); + let foreign_items = fm.items.iter() + .map(|it| self.tcx.hir.local_def_id(it.id).index) + .collect(); + let lib = NativeLibrary { + name: n, + kind, + cfg, + foreign_items, + }; + self.register_native_lib(Some(m.span), lib); + } + } + + fn visit_trait_item(&mut self, _it: &'tcx hir::TraitItem) {} + fn visit_impl_item(&mut self, _it: &'tcx hir::ImplItem) {} +} + +impl<'a, 'tcx> Collector<'a, 'tcx> { + fn register_native_lib(&mut self, span: Option, lib: NativeLibrary) { + if lib.name.as_str().is_empty() { + match span { + Some(span) => { + struct_span_err!(self.tcx.sess, span, E0454, + "#[link(name = \"\")] given with empty name") + .span_label(span, "empty name given") + .emit(); + } + None => { + self.tcx.sess.err("empty library name given via `-l`"); + } + } + return + } + let is_osx = self.tcx.sess.target.target.options.is_like_osx; + if lib.kind == cstore::NativeFramework && !is_osx { + let msg = "native frameworks are only available on macOS targets"; + match span { + Some(span) => span_err!(self.tcx.sess, span, E0455, "{}", msg), + None => self.tcx.sess.err(msg), + } + } + if lib.cfg.is_some() && !self.tcx.sess.features.borrow().link_cfg { + feature_gate::emit_feature_err(&self.tcx.sess.parse_sess, + "link_cfg", + span.unwrap(), + GateIssue::Language, + "is feature gated"); + } + if lib.kind == cstore::NativeStaticNobundle && + !self.tcx.sess.features.borrow().static_nobundle { + feature_gate::emit_feature_err(&self.tcx.sess.parse_sess, + "static_nobundle", + span.unwrap(), + GateIssue::Language, + "kind=\"static-nobundle\" is feature gated"); + } + self.libs.push(lib); + } + + // Process libs passed on the command line + fn process_command_line(&mut self) { + // First, check for errors + let mut renames = FxHashSet(); + for &(ref name, ref new_name, _) in &self.tcx.sess.opts.libs { + if let &Some(ref new_name) = new_name { + if new_name.is_empty() { + self.tcx.sess.err( + &format!("an empty renaming target was specified for library `{}`",name)); + } else if !self.libs.iter().any(|lib| lib.name == name as &str) { + self.tcx.sess.err(&format!("renaming of the library `{}` was specified, \ + however this crate contains no #[link(...)] \ + attributes referencing this library.", name)); + } else if renames.contains(name) { + self.tcx.sess.err(&format!("multiple renamings were \ + specified for library `{}` .", + name)); + } else { + renames.insert(name); + } + } + } + + // Update kind and, optionally, the name of all native libaries + // (there may be more than one) with the specified name. + for &(ref name, ref new_name, kind) in &self.tcx.sess.opts.libs { + let mut found = false; + for lib in self.libs.iter_mut() { + if lib.name == name as &str { + let mut changed = false; + if let Some(k) = kind { + lib.kind = k; + changed = true; + } + if let &Some(ref new_name) = new_name { + lib.name = Symbol::intern(new_name); + changed = true; + } + if !changed { + let msg = format!("redundant linker flag specified for \ + library `{}`", name); + self.tcx.sess.warn(&msg); + } + + found = true; + } + } + if !found { + // Add if not found + let new_name = new_name.as_ref().map(|s| &**s); // &Option -> Option<&str> + let lib = NativeLibrary { + name: Symbol::intern(new_name.unwrap_or(name)), + kind: if let Some(k) = kind { k } else { cstore::NativeUnknown }, + cfg: None, + foreign_items: Vec::new(), + }; + self.register_native_lib(None, lib); + } + } + } +} diff --git a/src/librustc_trans/back/link.rs b/src/librustc_trans/back/link.rs index 20c5b082101..d5d980da39f 100644 --- a/src/librustc_trans/back/link.rs +++ b/src/librustc_trans/back/link.rs @@ -431,7 +431,7 @@ fn link_rlib<'a>(sess: &'a Session, // feature then we'll need to figure out how to record what objects were // loaded from the libraries found here and then encode that into the // metadata of the rlib we're generating somehow. - for lib in sess.cstore.used_libraries() { + for lib in trans.crate_info.used_libraries.iter() { match lib.kind { NativeLibraryKind::NativeStatic => {} NativeLibraryKind::NativeStaticNobundle | @@ -930,7 +930,7 @@ fn link_args(cmd: &mut Linker, cmd.gc_sections(keep_metadata); } - let used_link_args = sess.cstore.used_link_args(); + let used_link_args = &trans.crate_info.link_args; if crate_type == config::CrateTypeExecutable && t.options.position_independent_executables { @@ -1000,7 +1000,7 @@ fn link_args(cmd: &mut Linker, // link line. And finally upstream native libraries can't depend on anything // in this DAG so far because they're only dylibs and dylibs can only depend // on other dylibs (e.g. other native deps). - add_local_native_libraries(cmd, sess); + add_local_native_libraries(cmd, sess, trans); add_upstream_rust_crates(cmd, sess, trans, crate_type, tmpdir); add_upstream_native_libraries(cmd, sess, trans, crate_type); @@ -1057,7 +1057,9 @@ fn link_args(cmd: &mut Linker, // Also note that the native libraries linked here are only the ones located // in the current crate. Upstream crates with native library dependencies // may have their native library pulled in above. -fn add_local_native_libraries(cmd: &mut Linker, sess: &Session) { +fn add_local_native_libraries(cmd: &mut Linker, + sess: &Session, + trans: &CrateTranslation) { sess.target_filesearch(PathKind::All).for_each_lib_search_path(|path, k| { match k { PathKind::Framework => { cmd.framework_path(path); } @@ -1065,7 +1067,7 @@ fn add_local_native_libraries(cmd: &mut Linker, sess: &Session) { } }); - let relevant_libs = sess.cstore.used_libraries().into_iter().filter(|l| { + let relevant_libs = trans.crate_info.used_libraries.iter().filter(|l| { relevant_lib(sess, l) }); diff --git a/src/librustc_trans/base.rs b/src/librustc_trans/base.rs index ccbd2a7550a..28929afc281 100644 --- a/src/librustc_trans/base.rs +++ b/src/librustc_trans/base.rs @@ -905,7 +905,7 @@ pub fn find_exported_symbols(tcx: TyCtxt, reachable: &NodeSet) -> NodeSet { match tcx.hir.get(id) { hir_map::NodeForeignItem(..) => { let def_id = tcx.hir.local_def_id(id); - tcx.sess.cstore.is_statically_included_foreign_item(def_id) + tcx.is_statically_included_foreign_item(def_id) } // Only consider nodes that actually have exported symbols. @@ -1516,6 +1516,8 @@ pub fn new(tcx: TyCtxt) -> CrateInfo { sanitizer_runtime: None, is_no_builtins: FxHashSet(), native_libraries: FxHashMap(), + used_libraries: tcx.native_libraries(LOCAL_CRATE), + link_args: tcx.link_args(LOCAL_CRATE), }; for cnum in tcx.sess.cstore.crates() { @@ -1537,6 +1539,7 @@ pub fn new(tcx: TyCtxt) -> CrateInfo { } } + return info } } diff --git a/src/librustc_trans/callee.rs b/src/librustc_trans/callee.rs index 76f94565bae..71d476c31ac 100644 --- a/src/librustc_trans/callee.rs +++ b/src/librustc_trans/callee.rs @@ -125,7 +125,7 @@ pub fn get_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, } if ccx.use_dll_storage_attrs() && - ccx.sess().cstore.is_dllimport_foreign_item(instance_def_id) + tcx.is_dllimport_foreign_item(instance_def_id) { unsafe { llvm::LLVMSetDLLStorageClass(llfn, llvm::DLLStorageClass::DllImport); diff --git a/src/librustc_trans/consts.rs b/src/librustc_trans/consts.rs index 310cd6fe955..282e960aab3 100644 --- a/src/librustc_trans/consts.rs +++ b/src/librustc_trans/consts.rs @@ -211,7 +211,7 @@ pub fn get_static(ccx: &CrateContext, def_id: DefId) -> ValueRef { g }; - if ccx.use_dll_storage_attrs() && ccx.sess().cstore.is_dllimport_foreign_item(def_id) { + if ccx.use_dll_storage_attrs() && ccx.tcx().is_dllimport_foreign_item(def_id) { // For foreign (native) libs we know the exact storage type to use. unsafe { llvm::LLVMSetDLLStorageClass(g, llvm::DLLStorageClass::DllImport); diff --git a/src/librustc_trans/lib.rs b/src/librustc_trans/lib.rs index 876870914be..babc030b59c 100644 --- a/src/librustc_trans/lib.rs +++ b/src/librustc_trans/lib.rs @@ -234,6 +234,8 @@ pub struct CrateInfo { sanitizer_runtime: Option, is_no_builtins: FxHashSet, native_libraries: FxHashMap>>, + used_libraries: Rc>, + link_args: Rc>, } __build_diagnostic_array! { librustc_trans, DIAGNOSTICS } diff --git a/src/test/compile-fail/empty-linkname.rs b/src/test/compile-fail/empty-linkname.rs index cd5ee1cafec..20e0f9cd0b2 100644 --- a/src/test/compile-fail/empty-linkname.rs +++ b/src/test/compile-fail/empty-linkname.rs @@ -11,3 +11,5 @@ #[link(name = "")] //~ ERROR: given with empty name extern { } + +fn main() {} diff --git a/src/test/compile-fail/feature-gate-static-nobundle.rs b/src/test/compile-fail/feature-gate-static-nobundle.rs index bc0025c7c95..0d13a4937c4 100644 --- a/src/test/compile-fail/feature-gate-static-nobundle.rs +++ b/src/test/compile-fail/feature-gate-static-nobundle.rs @@ -11,3 +11,5 @@ #[link(name="foo", kind="static-nobundle")] //~^ ERROR: kind="static-nobundle" is feature gated extern {} + +fn main() {} -- 2.44.0