rust/src/librustc_metadata/cstore.rs

298 lines
10 KiB
Rust
Raw Normal View History

// Copyright 2012-2014 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.
2011-07-08 03:39:44 +02:00
// The crate store - a central repo for information collected about external
// crates and libraries
2016-10-20 06:31:14 +02:00
use locator;
use schema;
use rustc::dep_graph::DepGraph;
use rustc::hir::def_id::{CRATE_DEF_INDEX, CrateNum, DefIndex, DefId};
use rustc::hir::map::DefKey;
2016-03-29 07:50:44 +02:00
use rustc::hir::svh::Svh;
use rustc::middle::cstore::{DepKind, ExternCrate};
use rustc_back::PanicStrategy;
use rustc_data_structures::indexed_vec::IndexVec;
use rustc::util::nodemap::{FxHashMap, NodeMap, NodeSet, DefIdMap};
use std::cell::{RefCell, Cell};
2014-03-27 18:28:38 +01:00
use std::rc::Rc;
use std::path::PathBuf;
use flate::Bytes;
use syntax::{ast, attr};
use syntax_pos;
pub use rustc::middle::cstore::{NativeLibraryKind, LinkagePreference};
pub use rustc::middle::cstore::{NativeStatic, NativeFramework, NativeUnknown};
pub use rustc::middle::cstore::{CrateSource, LinkMeta};
// A map from external crate numbers (as decoded from some crate file) to
// local crate numbers (as generated during this session). Each external
// crate may refer to types in other external crates, and each has their
// own crate numbers.
pub type CrateNumMap = IndexVec<CrateNum, CrateNum>;
pub enum MetadataBlob {
Inflated(Bytes),
2016-10-20 06:31:14 +02:00
Archive(locator::ArchiveMetadata),
}
/// Holds information about a syntax_pos::FileMap imported from another crate.
/// See `imported_filemaps()` for more information.
pub struct ImportedFileMap {
/// This FileMap's byte-offset within the codemap of its original crate
pub original_start_pos: syntax_pos::BytePos,
/// The end of this FileMap within the codemap of its original crate
pub original_end_pos: syntax_pos::BytePos,
/// The imported FileMap's representation within the local codemap
2016-10-23 05:02:37 +02:00
pub translated_filemap: Rc<syntax_pos::FileMap>,
}
pub struct CrateMetadata {
pub name: String,
/// Information about the extern crate that caused this crate to
/// be loaded. If this is `None`, then the crate was injected
/// (e.g., by the allocator)
pub extern_crate: Cell<Option<ExternCrate>>,
pub blob: MetadataBlob,
pub cnum_map: RefCell<CrateNumMap>,
pub cnum: CrateNum,
pub codemap_import_info: RefCell<Vec<ImportedFileMap>>,
pub root: schema::CrateRoot,
/// For each public item in this crate, we encode a key. When the
/// crate is loaded, we read all the keys and put them in this
/// hashmap, which gives the reverse mapping. This allows us to
/// quickly retrace a `DefPath`, which is needed for incremental
/// compilation support.
pub key_map: FxHashMap<DefKey, DefIndex>,
pub dep_kind: Cell<DepKind>,
2016-10-27 07:03:11 +02:00
pub source: CrateSource,
}
pub struct CachedInlinedItem {
/// The NodeId of the RootInlinedParent HIR map entry
pub inlined_root: ast::NodeId,
/// The local NodeId of the inlined entity
pub item_id: ast::NodeId,
}
pub struct CStore {
pub dep_graph: DepGraph,
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<(String, NativeLibraryKind)>>,
used_link_args: RefCell<Vec<String>>,
statically_included_foreign_items: RefCell<NodeSet>,
pub inlined_item_cache: RefCell<DefIdMap<Option<CachedInlinedItem>>>,
pub defid_for_inlined_node: RefCell<NodeMap<DefId>>,
pub visible_parent_map: RefCell<DefIdMap<DefId>>,
}
2013-12-25 21:08:04 +01:00
impl CStore {
pub fn new(dep_graph: &DepGraph) -> CStore {
2013-12-25 21:08:04 +01:00
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(NodeSet()),
visible_parent_map: RefCell::new(FxHashMap()),
inlined_item_cache: RefCell::new(FxHashMap()),
defid_for_inlined_node: RefCell::new(FxHashMap()),
2013-12-25 21:08:04 +01:00
}
}
pub fn next_crate_num(&self) -> CrateNum {
CrateNum::new(self.metas.borrow().len() + 1)
}
pub fn get_crate_data(&self, cnum: CrateNum) -> Rc<CrateMetadata> {
self.metas.borrow().get(&cnum).unwrap().clone()
2013-12-25 21:08:04 +01:00
}
pub fn get_crate_hash(&self, cnum: CrateNum) -> Svh {
self.get_crate_data(cnum).hash()
2013-12-25 21:08:04 +01:00
}
pub fn set_crate_data(&self, cnum: CrateNum, data: Rc<CrateMetadata>) {
2014-03-21 03:49:20 +01:00
self.metas.borrow_mut().insert(cnum, data);
2013-12-25 21:08:04 +01:00
}
2016-10-23 05:02:37 +02:00
pub fn iter_crate_data<I>(&self, mut i: I)
where I: FnMut(CrateNum, &Rc<CrateMetadata>)
2014-12-09 02:26:43 +01:00
{
for (&k, v) in self.metas.borrow().iter() {
i(k, v);
2013-12-25 21:08:04 +01:00
}
}
2013-12-25 19:10:33 +01:00
pub fn reset(&self) {
self.metas.borrow_mut().clear();
self.extern_mod_crate_map.borrow_mut().clear();
self.used_libraries.borrow_mut().clear();
self.used_link_args.borrow_mut().clear();
self.statically_included_foreign_items.borrow_mut().clear();
2013-12-25 19:10:33 +01:00
}
2016-10-23 05:02:37 +02:00
pub fn crate_dependencies_in_rpo(&self, krate: CrateNum) -> Vec<CrateNum> {
let mut ordering = Vec::new();
self.push_dependencies_in_postorder(&mut ordering, krate);
ordering.reverse();
ordering
}
2016-10-23 05:02:37 +02:00
pub fn push_dependencies_in_postorder(&self, ordering: &mut Vec<CrateNum>, krate: CrateNum) {
if ordering.contains(&krate) {
return;
}
let data = self.get_crate_data(krate);
for &dep in data.cnum_map.borrow().iter() {
if dep != krate {
self.push_dependencies_in_postorder(ordering, dep);
}
}
ordering.push(krate);
}
// This method is used when generating the command line to pass through to
// system linker. The linker expects undefined symbols on the left of the
// command line to be defined in libraries on the right, not the other way
// around. For more info, see some comments in the add_used_library function
// below.
//
// In order to get this left-to-right dependency ordering, we perform a
// topological sort of all crates putting the leaves at the right-most
// positions.
2016-10-23 05:02:37 +02:00
pub fn do_get_used_crates(&self,
prefer: LinkagePreference)
-> Vec<(CrateNum, Option<PathBuf>)> {
let mut ordering = Vec::new();
for (&num, _) in self.metas.borrow().iter() {
self.push_dependencies_in_postorder(&mut ordering, num);
}
info!("topological ordering: {:?}", ordering);
ordering.reverse();
2016-10-27 07:03:11 +02:00
let mut libs = self.metas
2016-10-23 05:02:37 +02:00
.borrow()
.iter()
2016-10-27 07:03:11 +02:00
.map(|(&cnum, data)| {
(cnum,
2016-10-23 05:02:37 +02:00
match prefer {
2016-10-27 07:03:11 +02:00
LinkagePreference::RequireDynamic => data.source.dylib.clone().map(|p| p.0),
LinkagePreference::RequireStatic => data.source.rlib.clone().map(|p| p.0),
2016-10-23 05:02:37 +02:00
})
})
rustc: Fix a leak in dependency= paths With the addition of separate search paths to the compiler, it was intended that applications such as Cargo could require a `--extern` flag per `extern crate` directive in the source. The system can currently be subverted, however, due to the `existing_match()` logic in the crate loader. When loading crates we first attempt to match an `extern crate` directive against all previously loaded crates to avoid reading metadata twice. This "hit the cache if possible" step was erroneously leaking crates across the search path boundaries, however. For example: extern crate b; extern crate a; If `b` depends on `a`, then it will load crate `a` when the `extern crate b` directive is being processed. When the compiler reaches `extern crate a` it will use the previously loaded version no matter what. If the compiler was not invoked with `-L crate=path/to/a`, it will still succeed. This behavior is allowing `extern crate` declarations in Cargo without a corresponding declaration in the manifest of a dependency, which is considered a bug. This commit fixes this problem by keeping track of the origin search path for a crate. Crates loaded from the dependency search path are not candidates for crates which are loaded from the crate search path. As a result of this fix, this is a likely a breaking change for a number of Cargo packages. If the compiler starts informing that a crate can no longer be found, it likely means that the dependency was forgotten in your Cargo.toml. [breaking-change]
2015-01-06 17:46:07 +01:00
.collect::<Vec<_>>();
libs.sort_by(|&(a, _), &(b, _)| {
let a = ordering.iter().position(|x| *x == a);
let b = ordering.iter().position(|x| *x == b);
a.cmp(&b)
});
libs
2013-12-25 21:08:04 +01:00
}
pub fn add_used_library(&self, lib: String, kind: NativeLibraryKind) {
2013-12-25 21:08:04 +01:00
assert!(!lib.is_empty());
2014-03-21 03:49:20 +01:00
self.used_libraries.borrow_mut().push((lib, kind));
2013-12-25 21:08:04 +01:00
}
2016-10-23 05:02:37 +02:00
pub fn get_used_libraries<'a>(&'a self) -> &'a RefCell<Vec<(String, NativeLibraryKind)>> {
&self.used_libraries
2013-12-25 21:08:04 +01:00
}
2013-12-21 05:00:58 +01:00
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());
2013-12-25 21:08:04 +01:00
}
}
2016-10-23 05:02:37 +02:00
pub fn get_used_link_args<'a>(&'a self) -> &'a RefCell<Vec<String>> {
&self.used_link_args
2013-12-25 21:08:04 +01:00
}
2016-10-23 05:02:37 +02:00
pub fn add_extern_mod_stmt_cnum(&self, emod_id: ast::NodeId, cnum: CrateNum) {
2014-03-21 03:49:20 +01:00
self.extern_mod_crate_map.borrow_mut().insert(emod_id, cnum);
}
pub fn add_statically_included_foreign_item(&self, id: ast::NodeId) {
self.statically_included_foreign_items.borrow_mut().insert(id);
}
pub fn do_is_statically_included_foreign_item(&self, id: ast::NodeId) -> bool {
self.statically_included_foreign_items.borrow().contains(&id)
}
2015-11-25 16:02:59 +01:00
2016-10-23 05:02:37 +02:00
pub fn do_extern_mod_stmt_cnum(&self, emod_id: ast::NodeId) -> Option<CrateNum> {
2015-11-25 16:02:59 +01:00
self.extern_mod_crate_map.borrow().get(&emod_id).cloned()
}
2013-07-02 21:47:32 +02:00
}
impl CrateMetadata {
2016-10-23 05:02:37 +02:00
pub fn name(&self) -> &str {
&self.root.name
}
pub fn hash(&self) -> Svh {
self.root.hash
}
pub fn disambiguator(&self) -> &str {
&self.root.disambiguator
}
pub fn is_staged_api(&self) -> bool {
2016-10-23 05:02:37 +02:00
self.get_item_attrs(CRATE_DEF_INDEX)
.iter()
.any(|attr| attr.name() == "stable" || attr.name() == "unstable")
}
pub fn is_allocator(&self) -> bool {
let attrs = self.get_item_attrs(CRATE_DEF_INDEX);
attr::contains_name(&attrs, "allocator")
}
pub fn needs_allocator(&self) -> bool {
let attrs = self.get_item_attrs(CRATE_DEF_INDEX);
attr::contains_name(&attrs, "needs_allocator")
}
rustc: Implement custom panic runtimes This commit is an implementation of [RFC 1513] which allows applications to alter the behavior of panics at compile time. A new compiler flag, `-C panic`, is added and accepts the values `unwind` or `panic`, with the default being `unwind`. This model affects how code is generated for the local crate, skipping generation of landing pads with `-C panic=abort`. [RFC 1513]: https://github.com/rust-lang/rfcs/blob/master/text/1513-less-unwinding.md Panic implementations are then provided by crates tagged with `#![panic_runtime]` and lazily required by crates with `#![needs_panic_runtime]`. The panic strategy (`-C panic` value) of the panic runtime must match the final product, and if the panic strategy is not `abort` then the entire DAG must have the same panic strategy. With the `-C panic=abort` strategy, users can expect a stable method to disable generation of landing pads, improving optimization in niche scenarios, decreasing compile time, and decreasing output binary size. With the `-C panic=unwind` strategy users can expect the existing ability to isolate failure in Rust code from the outside world. Organizationally, this commit dismantles the `sys_common::unwind` module in favor of some bits moving part of it to `libpanic_unwind` and the rest into the `panicking` module in libstd. The custom panic runtime support is pretty similar to the custom allocator support with the only major difference being how the panic runtime is injected (takes the `-C panic` flag into account).
2016-04-09 01:18:40 +02:00
pub fn is_panic_runtime(&self) -> bool {
let attrs = self.get_item_attrs(CRATE_DEF_INDEX);
rustc: Implement custom panic runtimes This commit is an implementation of [RFC 1513] which allows applications to alter the behavior of panics at compile time. A new compiler flag, `-C panic`, is added and accepts the values `unwind` or `panic`, with the default being `unwind`. This model affects how code is generated for the local crate, skipping generation of landing pads with `-C panic=abort`. [RFC 1513]: https://github.com/rust-lang/rfcs/blob/master/text/1513-less-unwinding.md Panic implementations are then provided by crates tagged with `#![panic_runtime]` and lazily required by crates with `#![needs_panic_runtime]`. The panic strategy (`-C panic` value) of the panic runtime must match the final product, and if the panic strategy is not `abort` then the entire DAG must have the same panic strategy. With the `-C panic=abort` strategy, users can expect a stable method to disable generation of landing pads, improving optimization in niche scenarios, decreasing compile time, and decreasing output binary size. With the `-C panic=unwind` strategy users can expect the existing ability to isolate failure in Rust code from the outside world. Organizationally, this commit dismantles the `sys_common::unwind` module in favor of some bits moving part of it to `libpanic_unwind` and the rest into the `panicking` module in libstd. The custom panic runtime support is pretty similar to the custom allocator support with the only major difference being how the panic runtime is injected (takes the `-C panic` flag into account).
2016-04-09 01:18:40 +02:00
attr::contains_name(&attrs, "panic_runtime")
}
pub fn needs_panic_runtime(&self) -> bool {
let attrs = self.get_item_attrs(CRATE_DEF_INDEX);
rustc: Implement custom panic runtimes This commit is an implementation of [RFC 1513] which allows applications to alter the behavior of panics at compile time. A new compiler flag, `-C panic`, is added and accepts the values `unwind` or `panic`, with the default being `unwind`. This model affects how code is generated for the local crate, skipping generation of landing pads with `-C panic=abort`. [RFC 1513]: https://github.com/rust-lang/rfcs/blob/master/text/1513-less-unwinding.md Panic implementations are then provided by crates tagged with `#![panic_runtime]` and lazily required by crates with `#![needs_panic_runtime]`. The panic strategy (`-C panic` value) of the panic runtime must match the final product, and if the panic strategy is not `abort` then the entire DAG must have the same panic strategy. With the `-C panic=abort` strategy, users can expect a stable method to disable generation of landing pads, improving optimization in niche scenarios, decreasing compile time, and decreasing output binary size. With the `-C panic=unwind` strategy users can expect the existing ability to isolate failure in Rust code from the outside world. Organizationally, this commit dismantles the `sys_common::unwind` module in favor of some bits moving part of it to `libpanic_unwind` and the rest into the `panicking` module in libstd. The custom panic runtime support is pretty similar to the custom allocator support with the only major difference being how the panic runtime is injected (takes the `-C panic` flag into account).
2016-04-09 01:18:40 +02:00
attr::contains_name(&attrs, "needs_panic_runtime")
}
pub fn is_compiler_builtins(&self) -> bool {
let attrs = self.get_item_attrs(CRATE_DEF_INDEX);
attr::contains_name(&attrs, "compiler_builtins")
}
pub fn is_no_builtins(&self) -> bool {
let attrs = self.get_item_attrs(CRATE_DEF_INDEX);
attr::contains_name(&attrs, "no_builtins")
}
rustc: Implement custom panic runtimes This commit is an implementation of [RFC 1513] which allows applications to alter the behavior of panics at compile time. A new compiler flag, `-C panic`, is added and accepts the values `unwind` or `panic`, with the default being `unwind`. This model affects how code is generated for the local crate, skipping generation of landing pads with `-C panic=abort`. [RFC 1513]: https://github.com/rust-lang/rfcs/blob/master/text/1513-less-unwinding.md Panic implementations are then provided by crates tagged with `#![panic_runtime]` and lazily required by crates with `#![needs_panic_runtime]`. The panic strategy (`-C panic` value) of the panic runtime must match the final product, and if the panic strategy is not `abort` then the entire DAG must have the same panic strategy. With the `-C panic=abort` strategy, users can expect a stable method to disable generation of landing pads, improving optimization in niche scenarios, decreasing compile time, and decreasing output binary size. With the `-C panic=unwind` strategy users can expect the existing ability to isolate failure in Rust code from the outside world. Organizationally, this commit dismantles the `sys_common::unwind` module in favor of some bits moving part of it to `libpanic_unwind` and the rest into the `panicking` module in libstd. The custom panic runtime support is pretty similar to the custom allocator support with the only major difference being how the panic runtime is injected (takes the `-C panic` flag into account).
2016-04-09 01:18:40 +02:00
pub fn panic_strategy(&self) -> PanicStrategy {
self.root.panic_strategy.clone()
}
}