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.
[] 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 {
// 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);
// This is basically a 1-based range of ints, which is a little
// silly - I may fix that.
fn crates(&self) -> Vec<CrateNum>;
- fn used_libraries(&self) -> Vec<NativeLibrary>;
- fn used_link_args(&self) -> Vec<String>;
// utility functions
fn used_crates(&self, prefer: LinkagePreference) -> Vec<(CrateNum, LibSource)>;
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") }
// This is basically a 1-based range of ints, which is a little
// silly - I may fix that.
fn crates(&self) -> Vec<CrateNum> { vec![] }
- fn used_libraries(&self) -> Vec<NativeLibrary> { vec![] }
- fn used_link_args(&self) -> Vec<String> { vec![] }
// utility functions
fn used_crates(&self, prefer: LinkagePreference) -> Vec<(CrateNum, LibSource)>
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;
}
}
+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) => {
-> Rc<Vec<DefId>>,
[] fn all_trait_implementations: AllTraitImplementations(CrateNum)
-> Rc<Vec<DefId>>,
+
+ [] is_dllimport_foreign_item: IsDllimportForeignItem(DefId) -> bool,
+ [] is_statically_included_foreign_item: IsStaticallyIncludedForeignItem(DefId) -> bool,
+ [] native_library_kind: NativeLibraryKind(DefId)
+ -> Option<NativeLibraryKind>,
+ [] link_args: link_args_node(CrateNum) -> Rc<Vec<String>>,
}
fn type_param_predicates<'tcx>((item_id, param_id): (DefId, DefId)) -> DepConstructor<'tcx> {
{
DepConstructor::ImplementationsOfTrait { krate, trait_id }
}
+
+fn link_args_node<'tcx>(_: CrateNum) -> DepConstructor<'tcx> {
+ DepConstructor::LinkArgs
+}
// 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,
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};
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};
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};
dep_kind: DepKind,
}
-fn register_native_lib(sess: &Session,
- cstore: &CStore,
- span: Option<Span>,
- 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,
}
}
- fn get_foreign_items_of_kind(&self, kind: cstore::NativeLibraryKind) -> Vec<DefIndex> {
- 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.
}
}
-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
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<String> -> 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(
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};
metas: RefCell<FxHashMap<CrateNum, Rc<CrateMetadata>>>,
/// Map from NodeId's of local extern crate statements to crate numbers
extern_mod_crate_map: RefCell<NodeMap<CrateNum>>,
- used_libraries: RefCell<Vec<NativeLibrary>>,
- used_link_args: RefCell<Vec<String>>,
- statically_included_foreign_items: RefCell<FxHashSet<DefIndex>>,
- pub dllimport_foreign_items: RefCell<FxHashSet<DefIndex>>,
pub visible_parent_map: RefCell<DefIdMap<DefId>>,
pub metadata_loader: Box<MetadataLoader>,
}
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,
}
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<Vec<NativeLibrary>> {
- &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<Vec<String>> {
- &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<CrateNum> {
self.extern_mod_crate_map.borrow().get(&emod_id).cloned()
}
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};
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>) {
*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
};
}
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);
result
}
- fn used_libraries(&self) -> Vec<NativeLibrary>
- {
- self.get_used_libraries().borrow().clone()
- }
-
- fn used_link_args(&self) -> Vec<String>
- {
- self.get_used_link_args().borrow().clone()
- }
fn used_crates(&self, prefer: LinkagePreference) -> Vec<(CrateNum, LibSource)>
{
self.do_get_used_crates(prefer)
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
```
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`
```
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"`
```
}
fn encode_native_libraries(&mut self, _: ()) -> LazySeq<NativeLibrary> {
- 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<CrateDep> {
mod cstore_impl;
mod isolated_encoder;
mod schema;
+mod native_libs;
+mod link_args;
pub mod creader;
pub mod cstore;
--- /dev/null
+// 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 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, 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<String> {
+ 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<String>,
+}
+
+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()))
+ }
+}
--- /dev/null
+// 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 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, 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<NativeLibrary> {
+ 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<NativeLibrary>,
+}
+
+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<Span>, 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<String> -> 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);
+ }
+ }
+ }
+}
// 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 |
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 {
// 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);
// 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); }
}
});
- 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)
});
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.
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() {
}
}
+
return info
}
}
}
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);
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);
sanitizer_runtime: Option<CrateNum>,
is_no_builtins: FxHashSet<CrateNum>,
native_libraries: FxHashMap<CrateNum, Rc<Vec<NativeLibrary>>>,
+ used_libraries: Rc<Vec<NativeLibrary>>,
+ link_args: Rc<Vec<String>>,
}
__build_diagnostic_array! { librustc_trans, DIAGNOSTICS }
#[link(name = "")] //~ ERROR: given with empty name
extern {
}
+
+fn main() {}
#[link(name="foo", kind="static-nobundle")]
//~^ ERROR: kind="static-nobundle" is feature gated
extern {}
+
+fn main() {}