mirror of
https://github.com/rust-lang/rust.git
synced 2024-11-01 15:01:51 +00:00
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.
This commit is contained in:
parent
87ea0a19bf
commit
64a70342e6
@ -545,6 +545,11 @@ define_dep_nodes!( <'tcx>
|
||||
|
||||
[] 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 {
|
||||
|
@ -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 @@ pub trait CrateStore {
|
||||
// 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)>;
|
||||
@ -329,10 +323,6 @@ impl CrateStore for DummyCrateStore {
|
||||
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 @@ impl CrateStore for DummyCrateStore {
|
||||
// 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)>
|
||||
|
@ -17,6 +17,7 @@ use hir::svh::Svh;
|
||||
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 @@ impl<'tcx> QueryDescription for queries::all_trait_implementations<'tcx> {
|
||||
}
|
||||
}
|
||||
|
||||
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 @@ define_maps! { <'tcx>
|
||||
-> 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> {
|
||||
@ -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
|
||||
}
|
||||
|
@ -694,7 +694,6 @@ pub fn phase_2_configure_and_expand<F>(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,
|
||||
|
@ -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;
|
||||
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::rc::Rc;
|
||||
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<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,
|
||||
@ -721,33 +669,6 @@ impl<'a> CrateLoader<'a> {
|
||||
}
|
||||
}
|
||||
|
||||
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.
|
||||
@ -1152,84 +1073,6 @@ impl<'a> CrateLoader<'a> {
|
||||
}
|
||||
}
|
||||
|
||||
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 @@ impl<'a> middle::cstore::CrateLoader for CrateLoader<'a> {
|
||||
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(
|
||||
|
@ -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<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>,
|
||||
}
|
||||
@ -109,10 +105,6 @@ impl 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 @@ impl CStore {
|
||||
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()
|
||||
}
|
||||
|
@ -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 @@ provide! { <'tcx> tcx, def_id, other, cdata,
|
||||
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 @@ 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
|
||||
};
|
||||
}
|
||||
@ -244,20 +275,6 @@ impl CrateStore for cstore::CStore {
|
||||
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 @@ impl CrateStore for cstore::CStore {
|
||||
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)
|
||||
|
@ -14,7 +14,7 @@ register_long_diagnostics! {
|
||||
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 @@ https://doc.rust-lang.org/book/first-edition/conditional-compilation.html
|
||||
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 @@ Please specify a valid "kind" value, from one of the following:
|
||||
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"`
|
||||
```
|
||||
|
@ -1283,8 +1283,8 @@ impl<'a, 'b: 'a, 'tcx: 'b> IsolatedEncoder<'a, 'b, 'tcx> {
|
||||
}
|
||||
|
||||
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> {
|
||||
|
@ -50,6 +50,8 @@ mod decoder;
|
||||
mod cstore_impl;
|
||||
mod isolated_encoder;
|
||||
mod schema;
|
||||
mod native_libs;
|
||||
mod link_args;
|
||||
|
||||
pub mod creader;
|
||||
pub mod cstore;
|
||||
|
65
src/librustc_metadata/link_args.rs
Normal file
65
src/librustc_metadata/link_args.rs
Normal file
@ -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 <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()))
|
||||
}
|
||||
}
|
217
src/librustc_metadata/native_libs.rs
Normal file
217
src/librustc_metadata/native_libs.rs
Normal file
@ -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 <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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -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)
|
||||
});
|
||||
|
||||
|
@ -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 @@ impl 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 @@ impl CrateInfo {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return info
|
||||
}
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -234,6 +234,8 @@ pub struct CrateInfo {
|
||||
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 }
|
||||
|
@ -11,3 +11,5 @@
|
||||
#[link(name = "")] //~ ERROR: given with empty name
|
||||
extern {
|
||||
}
|
||||
|
||||
fn main() {}
|
||||
|
@ -11,3 +11,5 @@
|
||||
#[link(name="foo", kind="static-nobundle")]
|
||||
//~^ ERROR: kind="static-nobundle" is feature gated
|
||||
extern {}
|
||||
|
||||
fn main() {}
|
||||
|
Loading…
Reference in New Issue
Block a user