Auto merge of #33476 - nikomatsakis:incr-comp-xcrate, r=mw

track incr. comp. dependencies across crates

This PR refactors the compiler's incremental compilation hashing so that it can track dependencies across crates. The main bits are:

- computing a hash representing the metadata for an item we are emitting
  - we do this by making `MetaData(X)` be the current task while computing metadata for an item
  - this naturally registers reads from any tables and things that we read for that purpose
  - we can then hash all the inputs to those tables
- tracking when we access metadata
  - we do this by registering a read of `MetaData(X)` for each foreign item `X` whose metadata we read
- hashing metadata from foreign items
  - we do this by loading up metadata from a file in the incr. comp. directory
  - if there is no file, we use the SVH for the entire crate

There is one very simple test only at this point. The next PR will be focused on expanding out the tests.

Note that this is based on top of https://github.com/rust-lang/rust/pull/33228

r? @michaelwoerister
This commit is contained in:
bors 2016-05-18 08:47:53 -07:00
commit 9a140454ea
52 changed files with 1039 additions and 372 deletions

View file

@ -64,7 +64,7 @@ impl CFG {
}
pub fn node_is_reachable(&self, id: ast::NodeId) -> bool {
self.graph.depth_traverse(self.entry)
self.graph.depth_traverse(self.entry, graph::OUTGOING)
.any(|idx| self.graph.node_data(idx).id() == id)
}
}

View file

@ -0,0 +1,69 @@
// Copyright 2012-2015 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.
//! Code for debugging the dep-graph.
use super::dep_node::DepNode;
use std::error::Error;
use std::fmt::Debug;
/// A dep-node filter goes from a user-defined string to a query over
/// nodes. Right now the format is like this:
///
/// x & y & z
///
/// where the format-string of the dep-node must contain `x`, `y`, and
/// `z`.
#[derive(Debug)]
pub struct DepNodeFilter {
text: String
}
impl DepNodeFilter {
pub fn new(text: &str) -> Self {
DepNodeFilter {
text: text.trim().to_string()
}
}
/// True if all nodes always pass the filter.
pub fn accepts_all(&self) -> bool {
self.text.is_empty()
}
/// Tests whether `node` meets the filter, returning true if so.
pub fn test<D: Clone + Debug>(&self, node: &DepNode<D>) -> bool {
let debug_str = format!("{:?}", node);
self.text.split("&")
.map(|s| s.trim())
.all(|f| debug_str.contains(f))
}
}
/// A filter like `F -> G` where `F` and `G` are valid dep-node
/// filters. This can be used to test the source/target independently.
pub struct EdgeFilter {
pub source: DepNodeFilter,
pub target: DepNodeFilter,
}
impl EdgeFilter {
pub fn new(test: &str) -> Result<EdgeFilter, Box<Error>> {
let parts: Vec<_> = test.split("->").collect();
if parts.len() != 2 {
Err(format!("expected a filter like `a&b -> c&d`, not `{}`", test).into())
} else {
Ok(EdgeFilter {
source: DepNodeFilter::new(parts[0]),
target: DepNodeFilter::new(parts[1]),
})
}
}
}

View file

@ -32,6 +32,10 @@ pub enum DepNode<D: Clone + Debug> {
// Represents the HIR node with the given node-id
Hir(D),
// Represents the metadata for a given HIR node, typically found
// in an extern crate.
MetaData(D),
// Represents different phases in the compiler.
CrateReader,
CollectLanguageItems,
@ -77,6 +81,7 @@ pub enum DepNode<D: Clone + Debug> {
TransCrateItem(D),
TransInlinedItem(D),
TransWriteMetadata,
LinkBinary,
// Nodes representing bits of computed IR in the tcx. Each shared
// table in the tcx (or elsewhere) maps to one of these
@ -174,7 +179,9 @@ impl<D: Clone + Debug> DepNode<D> {
LateLintCheck => Some(LateLintCheck),
TransCrate => Some(TransCrate),
TransWriteMetadata => Some(TransWriteMetadata),
LinkBinary => Some(LinkBinary),
Hir(ref d) => op(d).map(Hir),
MetaData(ref d) => op(d).map(MetaData),
CollectItem(ref d) => op(d).map(CollectItem),
CoherenceCheckImpl(ref d) => op(d).map(CoherenceCheckImpl),
CoherenceOverlapCheck(ref d) => op(d).map(CoherenceOverlapCheck),

View file

@ -8,6 +8,7 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
pub mod debug;
mod dep_node;
mod dep_tracking_map;
mod edges;
@ -22,3 +23,4 @@ pub use self::dep_node::DepNode;
pub use self::graph::DepGraph;
pub use self::query::DepGraphQuery;
pub use self::visit::visit_all_items_in_krate;
pub use self::raii::DepTask;

View file

@ -9,7 +9,7 @@
// except according to those terms.
use rustc_data_structures::fnv::FnvHashMap;
use rustc_data_structures::graph::{Graph, NodeIndex};
use rustc_data_structures::graph::{Direction, INCOMING, Graph, NodeIndex, OUTGOING};
use std::fmt::Debug;
use std::hash::Hash;
@ -63,11 +63,9 @@ impl<D: Clone + Debug + Hash + Eq> DepGraphQuery<D> {
.collect()
}
/// All nodes reachable from `node`. In other words, things that
/// will have to be recomputed if `node` changes.
pub fn transitive_dependents(&self, node: DepNode<D>) -> Vec<DepNode<D>> {
fn reachable_nodes(&self, node: DepNode<D>, direction: Direction) -> Vec<DepNode<D>> {
if let Some(&index) = self.indices.get(&node) {
self.graph.depth_traverse(index)
self.graph.depth_traverse(index, direction)
.map(|s| self.graph.node_data(s).clone())
.collect()
} else {
@ -75,8 +73,19 @@ impl<D: Clone + Debug + Hash + Eq> DepGraphQuery<D> {
}
}
/// All nodes reachable from `node`. In other words, things that
/// will have to be recomputed if `node` changes.
pub fn transitive_successors(&self, node: DepNode<D>) -> Vec<DepNode<D>> {
self.reachable_nodes(node, OUTGOING)
}
/// All nodes that can reach `node`.
pub fn transitive_predecessors(&self, node: DepNode<D>) -> Vec<DepNode<D>> {
self.reachable_nodes(node, INCOMING)
}
/// Just the outgoing edges from `node`.
pub fn immediate_dependents(&self, node: DepNode<D>) -> Vec<DepNode<D>> {
pub fn immediate_successors(&self, node: DepNode<D>) -> Vec<DepNode<D>> {
if let Some(&index) = self.indices.get(&node) {
self.graph.successor_nodes(index)
.map(|s| self.graph.node_data(s).clone())

View file

@ -28,6 +28,7 @@ use super::DepGraphQuery;
use super::DepNode;
use super::edges::DepGraphEdges;
#[derive(Debug)]
pub enum DepMessage {
Read(DepNode<DefId>),
Write(DepNode<DefId>),
@ -117,6 +118,8 @@ impl DepGraphThreadData {
/// the buffer is full, this may swap.)
#[inline]
pub fn enqueue(&self, message: DepMessage) {
debug!("enqueue: {:?} tasks_pushed={}", message, self.tasks_pushed.get());
// Regardless of whether dep graph construction is enabled, we
// still want to check that we always have a valid task on the
// stack when a read/write/etc event occurs.

View file

@ -42,7 +42,8 @@ pub fn visit_all_items_in_krate<'a, 'tcx, V, F>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
let _task = self.tcx.dep_graph.in_task(task_id);
debug!("Started task {:?}", task_id);
self.tcx.dep_graph.read(DepNode::Hir(item_def_id));
self.visitor.visit_item(i)
self.visitor.visit_item(i);
debug!("Ended task {:?}", task_id);
}
}

View file

@ -45,6 +45,7 @@ use hir::map::Definitions;
use hir::map::definitions::DefPathData;
use hir::def_id::{DefIndex, DefId};
use hir::def::{Def, PathResolution};
use session::Session;
use std::collections::BTreeMap;
use std::iter;
@ -97,8 +98,16 @@ impl Resolver for DummyResolver {
}
}
pub fn lower_crate(krate: &Crate, id_assigner: &NodeIdAssigner, resolver: &mut Resolver)
pub fn lower_crate(sess: &Session,
krate: &Crate,
id_assigner: &NodeIdAssigner,
resolver: &mut Resolver)
-> hir::Crate {
// We're constructing the HIR here; we don't care what we will
// read, since we haven't even constructed the *input* to
// incr. comp. yet.
let _ignore = sess.dep_graph.in_ignore();
LoweringContext {
crate_root: if std_inject::no_core(krate) {
None

View file

@ -82,8 +82,10 @@ impl DefPath {
let mut data = vec![];
let mut index = Some(start_index);
loop {
debug!("DefPath::make: krate={:?} index={:?}", krate, index);
let p = index.unwrap();
let key = get_key(p);
debug!("DefPath::make: key={:?}", key);
match key.disambiguated_data.data {
DefPathData::CrateRoot => {
assert!(key.parent.is_none());
@ -178,6 +180,10 @@ impl Definitions {
self.data[index.as_usize()].key.clone()
}
pub fn def_index_for_def_key(&self, key: DefKey) -> Option<DefIndex> {
self.key_map.get(&key).cloned()
}
/// Returns the path from the crate root to `index`. The root
/// nodes are not included in the path (i.e., this will be an
/// empty vector for the crate root). For an inlined item, this
@ -208,37 +214,6 @@ impl Definitions {
}
}
pub fn retrace_path(&self, path: &DefPath) -> Option<DefIndex> {
debug!("retrace_path(path={:?})", path);
// we assume that we only want to retrace paths relative to
// the crate root
assert!(path.is_local());
let root_key = DefKey {
parent: None,
disambiguated_data: DisambiguatedDefPathData {
data: DefPathData::CrateRoot,
disambiguator: 0,
},
};
let root_id = self.key_map[&root_key];
debug!("retrace_path: root_id={:?}", root_id);
let mut id = root_id;
for data in &path.data {
let key = DefKey { parent: Some(id), disambiguated_data: data.clone() };
debug!("key = {:?}", key);
id = match self.key_map.get(&key) {
Some(&id) => id,
None => return None
};
}
Some(id)
}
pub fn create_def_with_parent(&mut self,
parent: Option<DefIndex>,
node_id: ast::NodeId,

View file

@ -19,7 +19,7 @@ use dep_graph::{DepGraph, DepNode};
use middle::cstore::InlinedItem;
use middle::cstore::InlinedItem as II;
use hir::def_id::{CRATE_DEF_INDEX, DefId};
use hir::def_id::{CRATE_DEF_INDEX, DefId, DefIndex};
use syntax::abi::Abi;
use syntax::ast::{self, Name, NodeId, DUMMY_NODE_ID, };
@ -160,10 +160,10 @@ pub struct Forest {
}
impl Forest {
pub fn new(krate: Crate, dep_graph: DepGraph) -> Forest {
pub fn new(krate: Crate, dep_graph: &DepGraph) -> Forest {
Forest {
krate: krate,
dep_graph: dep_graph,
dep_graph: dep_graph.clone(),
inlined_items: TypedArena::new()
}
}
@ -285,9 +285,8 @@ impl<'ast> Map<'ast> {
self.definitions.borrow().def_path(def_id.index)
}
pub fn retrace_path(&self, path: &DefPath) -> Option<DefId> {
self.definitions.borrow().retrace_path(path)
.map(DefId::local)
pub fn def_index_for_def_key(&self, def_key: DefKey) -> Option<DefIndex> {
self.definitions.borrow().def_index_for_def_key(def_key)
}
pub fn local_def_id(&self, node: NodeId) -> DefId {

View file

@ -10,78 +10,44 @@
//! Calculation and management of a Strict Version Hash for crates
//!
//! # Today's ABI problem
//!
//! In today's implementation of rustc, it is incredibly difficult to achieve
//! forward binary compatibility without resorting to C-like interfaces. Within
//! rust code itself, abi details such as symbol names suffer from a variety of
//! unrelated factors to code changing such as the "def id drift" problem. This
//! ends up yielding confusing error messages about metadata mismatches and
//! such.
//!
//! The core of this problem is when an upstream dependency changes and
//! downstream dependents are not recompiled. This causes compile errors because
//! the upstream crate's metadata has changed but the downstream crates are
//! still referencing the older crate's metadata.
//!
//! This problem exists for many reasons, the primary of which is that rust does
//! not currently support forwards ABI compatibility (in place upgrades of a
//! crate).
//!
//! # SVH and how it alleviates the problem
//!
//! With all of this knowledge on hand, this module contains the implementation
//! of a notion of a "Strict Version Hash" for a crate. This is essentially a
//! hash of all contents of a crate which can somehow be exposed to downstream
//! crates.
//!
//! This hash is currently calculated by just hashing the AST, but this is
//! obviously wrong (doc changes should not result in an incompatible ABI).
//! Implementation-wise, this is required at this moment in time.
//!
//! By encoding this strict version hash into all crate's metadata, stale crates
//! can be detected immediately and error'd about by rustc itself.
//!
//! # Relevant links
//!
//! Original issue: https://github.com/rust-lang/rust/issues/10207
//! The SVH is used for incremental compilation to track when HIR
//! nodes have changed between compilations, and also to detect
//! mismatches where we have two versions of the same crate that were
//! compiled from distinct sources.
use std::fmt;
use std::hash::{Hash, Hasher};
#[derive(Clone, Eq, Hash, PartialEq, Debug)]
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
pub struct Svh {
hash: String,
hash: u64,
}
impl Svh {
/// Create a new `Svh` given the hash. If you actually want to
/// compute the SVH from some HIR, you want the `calculate_svh`
/// function found in `librustc_trans`.
pub fn new(hash: String) -> Svh {
assert!(hash.len() == 16);
/// function found in `librustc_incremental`.
pub fn new(hash: u64) -> Svh {
Svh { hash: hash }
}
pub fn from_hash(hash: u64) -> Svh {
return Svh::new((0..64).step_by(4).map(|i| hex(hash >> i)).collect());
fn hex(b: u64) -> char {
let b = (b & 0xf) as u8;
let b = match b {
0 ... 9 => '0' as u8 + b,
_ => 'a' as u8 + b - 10,
};
b as char
}
pub fn as_u64(&self) -> u64 {
self.hash
}
pub fn as_str<'a>(&'a self) -> &'a str {
&self.hash
pub fn to_string(&self) -> String {
format!("{:016x}", self.hash)
}
}
impl Hash for Svh {
fn hash<H>(&self, state: &mut H) where H: Hasher {
self.hash.to_le().hash(state);
}
}
impl fmt::Display for Svh {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.pad(self.as_str())
f.pad(&self.to_string())
}
}

View file

@ -20,7 +20,7 @@ pub use self::VarValue::*;
use super::{RegionVariableOrigin, SubregionOrigin, MiscVariable};
use super::unify_key;
use rustc_data_structures::graph::{self, Direction, NodeIndex};
use rustc_data_structures::graph::{self, Direction, NodeIndex, OUTGOING};
use rustc_data_structures::unify::{self, UnificationTable};
use middle::free_region::FreeRegionMap;
use ty::{self, Ty, TyCtxt};
@ -872,7 +872,7 @@ impl<'a, 'gcx, 'tcx> RegionVarBindings<'a, 'gcx, 'tcx> {
let seeds: Vec<_> = givens.iter().cloned().collect();
for (fr, vid) in seeds {
let seed_index = NodeIndex(vid.index as usize);
for succ_index in graph.depth_traverse(seed_index) {
for succ_index in graph.depth_traverse(seed_index, OUTGOING) {
let succ_index = succ_index.0 as u32;
if succ_index < self.num_vars() {
let succ_vid = RegionVid { index: succ_index };

View file

@ -37,7 +37,6 @@
#![feature(rustc_private)]
#![feature(slice_patterns)]
#![feature(staged_api)]
#![feature(step_by)]
#![feature(question_mark)]
#![cfg_attr(test, feature(test))]

View file

@ -22,19 +22,19 @@
// are *mostly* used as a part of that interface, but these should
// probably get a better home if someone can find one.
use hir::svh::Svh;
use hir::map as hir_map;
use hir::def::{self, Def};
use hir::def_id::{DefId, DefIndex};
use hir::map as hir_map;
use hir::map::definitions::DefKey;
use hir::svh::Svh;
use middle::lang_items;
use ty::{self, Ty, TyCtxt, VariantKind};
use hir::def_id::{DefId, DefIndex};
use mir::repr::Mir;
use mir::mir_map::MirMap;
use session::Session;
use session::config::PanicStrategy;
use session::search_paths::PathKind;
use util::nodemap::{FnvHashMap, NodeMap, NodeSet, DefIdMap};
use std::any::Any;
use std::cell::RefCell;
use std::rc::Rc;
use std::path::PathBuf;
@ -150,12 +150,7 @@ pub struct ExternCrate {
/// A store of Rust crates, through with their metadata
/// can be accessed.
///
/// The `: Any` bound is a temporary measure that allows access
/// to the backing `rustc_metadata::cstore::CStore` object. It
/// will be removed in the near future - if you need to access
/// internal APIs, please tell us.
pub trait CrateStore<'tcx> : Any {
pub trait CrateStore<'tcx> {
// item info
fn stability(&self, def: DefId) -> Option<attr::Stability>;
fn deprecation(&self, def: DefId) -> Option<attr::Deprecation>;
@ -240,6 +235,10 @@ pub trait CrateStore<'tcx> : Any {
fn reachable_ids(&self, cnum: ast::CrateNum) -> Vec<DefId>;
// resolve
fn def_index_for_def_key(&self,
cnum: ast::CrateNum,
def: DefKey)
-> Option<DefIndex>;
fn def_key(&self, def: DefId) -> hir_map::DefKey;
fn relative_def_path(&self, def: DefId) -> hir_map::DefPath;
fn variant_kind(&self, def_id: DefId) -> Option<VariantKind>;
@ -367,6 +366,12 @@ impl<'tcx> CrateStore<'tcx> for DummyCrateStore {
-> Vec<Rc<ty::Method<'tcx>>> { bug!("provided_trait_methods") }
fn trait_item_def_ids(&self, def: DefId)
-> Vec<ty::ImplOrTraitItemId> { bug!("trait_item_def_ids") }
fn def_index_for_def_key(&self,
cnum: ast::CrateNum,
def: DefKey)
-> Option<DefIndex> {
None
}
// impl info
fn impl_items(&self, impl_def_id: DefId) -> Vec<ty::ImplOrTraitItemId>

View file

@ -1420,6 +1420,7 @@ impl fmt::Display for CrateType {
#[cfg(test)]
mod tests {
use dep_graph::DepGraph;
use middle::cstore::DummyCrateStore;
use session::config::{build_configuration, build_session_options};
use session::build_session;
@ -1439,6 +1440,7 @@ mod tests {
// When the user supplies --test we should implicitly supply --cfg test
#[test]
fn test_switch_implies_cfg_test() {
let dep_graph = DepGraph::new(false);
let matches =
&match getopts(&["--test".to_string()], &optgroups()) {
Ok(m) => m,
@ -1446,7 +1448,7 @@ mod tests {
};
let registry = diagnostics::registry::Registry::new(&[]);
let sessopts = build_session_options(matches);
let sess = build_session(sessopts, None, registry, Rc::new(DummyCrateStore));
let sess = build_session(sessopts, &dep_graph, None, registry, Rc::new(DummyCrateStore));
let cfg = build_configuration(&sess);
assert!((attr::contains_name(&cfg[..], "test")));
}
@ -1455,6 +1457,7 @@ mod tests {
// another --cfg test
#[test]
fn test_switch_implies_cfg_test_unless_cfg_test() {
let dep_graph = DepGraph::new(false);
let matches =
&match getopts(&["--test".to_string(), "--cfg=test".to_string()],
&optgroups()) {
@ -1465,7 +1468,7 @@ mod tests {
};
let registry = diagnostics::registry::Registry::new(&[]);
let sessopts = build_session_options(matches);
let sess = build_session(sessopts, None, registry,
let sess = build_session(sessopts, &dep_graph, None, registry,
Rc::new(DummyCrateStore));
let cfg = build_configuration(&sess);
let mut test_items = cfg.iter().filter(|m| m.name() == "test");
@ -1475,13 +1478,14 @@ mod tests {
#[test]
fn test_can_print_warnings() {
let dep_graph = DepGraph::new(false);
{
let matches = getopts(&[
"-Awarnings".to_string()
], &optgroups()).unwrap();
let registry = diagnostics::registry::Registry::new(&[]);
let sessopts = build_session_options(&matches);
let sess = build_session(sessopts, None, registry,
let sess = build_session(sessopts, &dep_graph, None, registry,
Rc::new(DummyCrateStore));
assert!(!sess.diagnostic().can_emit_warnings);
}
@ -1493,7 +1497,7 @@ mod tests {
], &optgroups()).unwrap();
let registry = diagnostics::registry::Registry::new(&[]);
let sessopts = build_session_options(&matches);
let sess = build_session(sessopts, None, registry,
let sess = build_session(sessopts, &dep_graph, None, registry,
Rc::new(DummyCrateStore));
assert!(sess.diagnostic().can_emit_warnings);
}
@ -1504,7 +1508,7 @@ mod tests {
], &optgroups()).unwrap();
let registry = diagnostics::registry::Registry::new(&[]);
let sessopts = build_session_options(&matches);
let sess = build_session(sessopts, None, registry,
let sess = build_session(sessopts, &dep_graph, None, registry,
Rc::new(DummyCrateStore));
assert!(sess.diagnostic().can_emit_warnings);
}

View file

@ -8,6 +8,7 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
use dep_graph::DepGraph;
use lint;
use middle::cstore::CrateStore;
use middle::dependency_format;
@ -49,6 +50,7 @@ pub mod search_paths;
// Represents the data associated with a compilation
// session for a single crate.
pub struct Session {
pub dep_graph: DepGraph,
pub target: config::Config,
pub host: Target,
pub opts: config::Options,
@ -408,18 +410,21 @@ fn split_msg_into_multilines(msg: &str) -> Option<String> {
}
pub fn build_session(sopts: config::Options,
dep_graph: &DepGraph,
local_crate_source_file: Option<PathBuf>,
registry: diagnostics::registry::Registry,
cstore: Rc<for<'a> CrateStore<'a>>)
-> Session {
build_session_with_codemap(sopts,
local_crate_source_file,
registry,
cstore,
Rc::new(codemap::CodeMap::new()))
dep_graph,
local_crate_source_file,
registry,
cstore,
Rc::new(codemap::CodeMap::new()))
}
pub fn build_session_with_codemap(sopts: config::Options,
dep_graph: &DepGraph,
local_crate_source_file: Option<PathBuf>,
registry: diagnostics::registry::Registry,
cstore: Rc<for<'a> CrateStore<'a>>,
@ -450,10 +455,16 @@ pub fn build_session_with_codemap(sopts: config::Options,
treat_err_as_bug,
emitter);
build_session_(sopts, local_crate_source_file, diagnostic_handler, codemap, cstore)
build_session_(sopts,
dep_graph,
local_crate_source_file,
diagnostic_handler,
codemap,
cstore)
}
pub fn build_session_(sopts: config::Options,
dep_graph: &DepGraph,
local_crate_source_file: Option<PathBuf>,
span_diagnostic: errors::Handler,
codemap: Rc<codemap::CodeMap>,
@ -482,6 +493,7 @@ pub fn build_session_(sopts: config::Options,
);
let sess = Session {
dep_graph: dep_graph.clone(),
target: target_cfg,
host: host,
opts: sopts,
@ -616,9 +628,9 @@ pub fn span_bug_fmt<S: Into<MultiSpan>>(file: &'static str,
}
fn opt_span_bug_fmt<S: Into<MultiSpan>>(file: &'static str,
line: u32,
span: Option<S>,
args: fmt::Arguments) -> ! {
line: u32,
span: Option<S>,
args: fmt::Arguments) -> ! {
tls::with_opt(move |tcx| {
let msg = format!("{}:{}: {}", file, line, args);
match (tcx, span) {

View file

@ -11,13 +11,14 @@
//! type context book-keeping
use dep_graph::{DepGraph, DepTrackingMap};
use hir::map as ast_map;
use session::Session;
use lint;
use middle;
use middle::cstore::LOCAL_CRATE;
use hir::def::DefMap;
use hir::def_id::DefId;
use hir::def_id::{DefId, DefIndex};
use hir::map as ast_map;
use hir::map::{DefKey, DefPath, DefPathData, DisambiguatedDefPathData};
use middle::free_region::FreeRegionMap;
use middle::region::RegionMaps;
use middle::resolve_lifetime;
@ -513,6 +514,49 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
}
}
/// Given a def-key `key` and a crate `krate`, finds the def-index
/// that `krate` assigned to `key`. This `DefIndex` will always be
/// relative to `krate`.
///
/// Returns `None` if there is no `DefIndex` with that key.
pub fn def_index_for_def_key(self, krate: ast::CrateNum, key: DefKey)
-> Option<DefIndex> {
if krate == LOCAL_CRATE {
self.map.def_index_for_def_key(key)
} else {
self.sess.cstore.def_index_for_def_key(krate, key)
}
}
pub fn retrace_path(self, path: &DefPath) -> Option<DefId> {
debug!("retrace_path(path={:?})", path);
let root_key = DefKey {
parent: None,
disambiguated_data: DisambiguatedDefPathData {
data: DefPathData::CrateRoot,
disambiguator: 0,
},
};
let root_index = self.def_index_for_def_key(path.krate, root_key)
.expect("no root key?");
debug!("retrace_path: root_index={:?}", root_index);
let mut index = root_index;
for data in &path.data {
let key = DefKey { parent: Some(index), disambiguated_data: data.clone() };
debug!("retrace_path: key={:?}", key);
match self.def_index_for_def_key(path.krate, key) {
Some(i) => index = i,
None => return None,
}
}
Some(DefId { krate: path.krate, index: index })
}
pub fn type_parameter_def(self,
node_id: NodeId)
-> ty::TypeParameterDef<'tcx>

View file

@ -368,7 +368,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
} else {
tcx.sess.cstore.crate_hash(did.krate)
};
h.as_str().hash(state);
h.hash(state);
did.index.hash(state);
};
let mt = |state: &mut SipHasher, mt: TypeAndMut| {

View file

@ -292,11 +292,15 @@ impl<N: Debug, E: Debug> Graph<N, E> {
}
}
pub fn depth_traverse<'a>(&'a self, start: NodeIndex) -> DepthFirstTraversal<'a, N, E> {
pub fn depth_traverse<'a>(&'a self,
start: NodeIndex,
direction: Direction)
-> DepthFirstTraversal<'a, N, E> {
DepthFirstTraversal {
graph: self,
stack: vec![start],
visited: BitVector::new(self.nodes.len()),
direction: direction,
}
}
}
@ -371,6 +375,7 @@ pub struct DepthFirstTraversal<'g, N: 'g, E: 'g> {
graph: &'g Graph<N, E>,
stack: Vec<NodeIndex>,
visited: BitVector,
direction: Direction,
}
impl<'g, N: Debug, E: Debug> Iterator for DepthFirstTraversal<'g, N, E> {
@ -382,9 +387,10 @@ impl<'g, N: Debug, E: Debug> Iterator for DepthFirstTraversal<'g, N, E> {
continue;
}
for (_, edge) in self.graph.outgoing_edges(idx) {
if !self.visited.contains(edge.target().node_id()) {
self.stack.push(edge.target());
for (_, edge) in self.graph.adjacent_edges(idx, self.direction) {
let target = edge.source_or_target(self.direction);
if !self.visited.contains(target.node_id()) {
self.stack.push(target);
}
}

View file

@ -152,7 +152,6 @@ pub fn compile_input(sess: &Session,
Ok(()));
let expanded_crate = assign_node_ids(sess, expanded_crate);
let dep_graph = DepGraph::new(sess.opts.build_dep_graph());
// Collect defintions for def ids.
let mut defs = time(sess.time_passes(),
@ -161,15 +160,15 @@ pub fn compile_input(sess: &Session,
time(sess.time_passes(),
"external crate/lib resolution",
|| read_local_crates(sess, &cstore, &defs, &expanded_crate, &id, &dep_graph));
|| read_local_crates(sess, &cstore, &defs, &expanded_crate, &id, &sess.dep_graph));
time(sess.time_passes(),
"early lint checks",
|| lint::check_ast_crate(sess, &expanded_crate));
let (analysis, resolutions, mut hir_forest) = {
lower_and_resolve(sess, &id, &mut defs, &expanded_crate, dep_graph,
control.make_glob_map)
lower_and_resolve(sess, &id, &mut defs, &expanded_crate,
&sess.dep_graph, control.make_glob_map)
};
// Discard MTWT tables that aren't required past lowering to HIR.
@ -805,7 +804,7 @@ pub fn lower_and_resolve<'a>(sess: &Session,
id: &'a str,
defs: &mut hir_map::Definitions,
krate: &ast::Crate,
dep_graph: DepGraph,
dep_graph: &DepGraph,
make_glob_map: resolve::MakeGlobMap)
-> (ty::CrateAnalysis<'a>, Resolutions, hir_map::Forest) {
resolve::with_resolver(sess, defs, make_glob_map, |mut resolver| {
@ -815,7 +814,7 @@ pub fn lower_and_resolve<'a>(sess: &Session,
// Lower ast -> hir.
let hir_forest = time(sess.time_passes(), "lowering ast -> hir", || {
hir_map::Forest::new(lower_crate(krate, sess, &mut resolver), dep_graph)
hir_map::Forest::new(lower_crate(sess, krate, sess, &mut resolver), dep_graph)
});
(ty::CrateAnalysis {

View file

@ -67,6 +67,7 @@ use pretty::{PpMode, UserIdentifiedItem};
use rustc_resolve as resolve;
use rustc_save_analysis as save;
use rustc_trans::back::link;
use rustc::dep_graph::DepGraph;
use rustc::session::{self, config, Session, build_session, CompileResult};
use rustc::session::config::{Input, PrintRequest, OutputType, ErrorOutputType};
use rustc::session::config::{get_unstable_features_setting, nightly_options};
@ -196,9 +197,11 @@ pub fn run_compiler_with_file_loader<'a, L>(args: &[String],
},
};
let cstore = Rc::new(CStore::new(token::get_ident_interner()));
let dep_graph = DepGraph::new(sopts.build_dep_graph());
let cstore = Rc::new(CStore::new(&dep_graph, token::get_ident_interner()));
let codemap = Rc::new(CodeMap::with_file_loader(loader));
let sess = session::build_session_with_codemap(sopts,
&dep_graph,
input_file_path,
descriptions,
cstore.clone(),
@ -425,9 +428,13 @@ impl<'a> CompilerCalls<'a> for RustcDefaultCalls {
describe_lints(&ls, false);
return None;
}
let cstore = Rc::new(CStore::new(token::get_ident_interner()));
let sess = build_session(sopts.clone(), None, descriptions.clone(),
cstore.clone());
let dep_graph = DepGraph::new(sopts.build_dep_graph());
let cstore = Rc::new(CStore::new(&dep_graph, token::get_ident_interner()));
let sess = build_session(sopts.clone(),
&dep_graph,
None,
descriptions.clone(),
cstore.clone());
rustc_lint::register_builtins(&mut sess.lint_store.borrow_mut(), Some(&sess));
let should_stop = RustcDefaultCalls::print_crate_info(&sess, None, odir, ofile);
if should_stop == Compilation::Stop {

View file

@ -18,10 +18,10 @@ use self::NodesMatchingUII::*;
use abort_on_err;
use driver::{self, Resolutions};
use rustc::dep_graph::DepGraph;
use rustc::ty::{self, TyCtxt};
use rustc::cfg;
use rustc::cfg::graphviz::LabelledCFG;
use rustc::dep_graph::DepGraph;
use rustc::session::Session;
use rustc::session::config::Input;
use rustc_borrowck as borrowck;

View file

@ -104,8 +104,10 @@ fn test_env<F>(source_string: &str,
options.unstable_features = UnstableFeatures::Allow;
let diagnostic_handler = errors::Handler::with_emitter(true, false, emitter);
let cstore = Rc::new(CStore::new(token::get_ident_interner()));
let sess = session::build_session_(options, None, diagnostic_handler,
let dep_graph = DepGraph::new(false);
let _ignore = dep_graph.in_ignore();
let cstore = Rc::new(CStore::new(&dep_graph, token::get_ident_interner()));
let sess = session::build_session_(options, &dep_graph, None, diagnostic_handler,
Rc::new(CodeMap::new()), cstore.clone());
rustc_lint::register_builtins(&mut sess.lint_store.borrow_mut(), Some(&sess));
let krate_config = Vec::new();
@ -117,15 +119,14 @@ fn test_env<F>(source_string: &str,
let krate = driver::phase_2_configure_and_expand(&sess, &cstore, krate, "test", None)
.expect("phase 2 aborted");
let dep_graph = DepGraph::new(false);
let krate = driver::assign_node_ids(&sess, krate);
let mut defs = hir_map::collect_definitions(&krate);
read_local_crates(&sess, &cstore, &defs, &krate, "test_crate", &dep_graph);
let _ignore = dep_graph.in_ignore();
let (_, resolutions, mut hir_forest) = {
driver::lower_and_resolve(&sess, "test-crate", &mut defs, &krate, dep_graph.clone(),
MakeGlobMap::No)
driver::lower_and_resolve(&sess, "test-crate", &mut defs, &krate,
&sess.dep_graph, MakeGlobMap::No)
};
let arenas = ty::CtxtArenas::new();

View file

@ -44,6 +44,7 @@
use graphviz as dot;
use rustc::dep_graph::{DepGraphQuery, DepNode};
use rustc::dep_graph::debug::{DepNodeFilter, EdgeFilter};
use rustc::hir::def_id::DefId;
use rustc::ty::TyCtxt;
use rustc_data_structures::fnv::{FnvHashMap, FnvHashSet};
@ -195,7 +196,7 @@ fn check_paths<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
};
for &(_, source_def_id, source_dep_node) in sources {
let dependents = query.transitive_dependents(source_dep_node);
let dependents = query.transitive_successors(source_dep_node);
for &(target_span, ref target_pass, _, ref target_dep_node) in targets {
if !dependents.contains(&target_dep_node) {
tcx.sess.span_err(
@ -220,12 +221,11 @@ fn dump_graph(tcx: TyCtxt) {
let nodes = match env::var("RUST_DEP_GRAPH_FILTER") {
Ok(string) => {
// Expect one of: "-> target", "source -> target", or "source ->".
let parts: Vec<_> = string.split("->").collect();
if parts.len() > 2 {
bug!("Invalid RUST_DEP_GRAPH_FILTER: expected '[source] -> [target]'");
}
let sources = node_set(&query, &parts[0]);
let targets = node_set(&query, &parts[1]);
let edge_filter = EdgeFilter::new(&string).unwrap_or_else(|e| {
bug!("invalid filter: {}", e)
});
let sources = node_set(&query, &edge_filter.source);
let targets = node_set(&query, &edge_filter.target);
filter_nodes(&query, &sources, &targets)
}
Err(_) => {
@ -295,26 +295,16 @@ impl<'a, 'tcx> dot::Labeller<'a> for GraphvizDepGraph {
// Given an optional filter like `"x,y,z"`, returns either `None` (no
// filter) or the set of nodes whose labels contain all of those
// substrings.
fn node_set(query: &DepGraphQuery<DefId>, filter: &str)
fn node_set(query: &DepGraphQuery<DefId>, filter: &DepNodeFilter)
-> Option<FnvHashSet<DepNode<DefId>>>
{
debug!("node_set(filter={:?})", filter);
if filter.trim().is_empty() {
if filter.accepts_all() {
return None;
}
let filters: Vec<&str> = filter.split("&").map(|s| s.trim()).collect();
debug!("node_set: filters={:?}", filters);
Some(query.nodes()
.into_iter()
.filter(|n| {
let s = format!("{:?}", n);
filters.iter().all(|f| s.contains(f))
})
.collect())
Some(query.nodes().into_iter().filter(|n| filter.test(n)).collect())
}
fn filter_nodes(query: &DepGraphQuery<DefId>,

View file

@ -72,12 +72,14 @@ impl<'a, 'tcx> SvhCalculate for TyCtxt<'a, 'tcx, 'tcx> {
attr.node.value.hash(&mut state);
}
Svh::from_hash(state.finish())
Svh::new(state.finish())
}
fn calculate_item_hash(self, def_id: DefId) -> u64 {
assert!(def_id.is_local());
debug!("calculate_item_hash(def_id={:?})", def_id);
let mut state = SipHasher::new();
{
@ -89,11 +91,16 @@ impl<'a, 'tcx> SvhCalculate for TyCtxt<'a, 'tcx, 'tcx> {
intravisit::walk_crate(&mut visit, krate);
} else {
let node_id = self.map.as_local_node_id(def_id).unwrap();
visit.visit_item(self.map.expect_item(node_id));
let item = self.map.expect_item(node_id);
visit.visit_item(item);
}
}
state.finish()
let hash = state.finish();
debug!("calculate_item_hash: def_id={:?} hash={:?}", def_id, hash);
hash
}
}

View file

@ -11,13 +11,35 @@
//! The data that we will serialize and deserialize.
use rustc::dep_graph::DepNode;
use rustc::hir::def_id::DefIndex;
use super::directory::DefPathIndex;
/// Data for use when recompiling the **current crate**.
#[derive(Debug, RustcEncodable, RustcDecodable)]
pub struct SerializedDepGraph {
pub nodes: Vec<DepNode<DefPathIndex>>,
pub edges: Vec<SerializedEdge>,
/// These are hashes of two things:
/// - the HIR nodes in this crate
/// - the metadata nodes from dependent crates we use
///
/// In each case, we store a hash summarizing the contents of
/// those items as they were at the time we did this compilation.
/// In the case of HIR nodes, this hash is derived by walking the
/// HIR itself. In the case of metadata nodes, the hash is loaded
/// from saved state.
///
/// When we do the next compile, we will load these back up and
/// compare them against the hashes we see at that time, which
/// will tell us what has changed, either in this crate or in some
/// crate that we depend on.
///
/// Because they will be reloaded, we don't store the DefId (which
/// will be different when we next compile) related to each node,
/// but rather the `DefPathIndex`. This can then be retraced
/// to find the current def-id.
pub hashes: Vec<SerializedHash>,
}
@ -25,7 +47,44 @@ pub type SerializedEdge = (DepNode<DefPathIndex>, DepNode<DefPathIndex>);
#[derive(Debug, RustcEncodable, RustcDecodable)]
pub struct SerializedHash {
pub index: DefPathIndex,
/// node being hashed; either a Hir or MetaData variant, in
/// practice
pub node: DepNode<DefPathIndex>,
/// the hash itself, computed by `calculate_item_hash`
pub hash: u64,
}
/// Data for use when downstream crates get recompiled.
#[derive(Debug, RustcEncodable, RustcDecodable)]
pub struct SerializedMetadataHashes {
/// For each def-id defined in this crate that appears in the
/// metadata, we hash all the inputs that were used when producing
/// the metadata. We save this after compilation is done. Then,
/// when some downstream crate is being recompiled, it can compare
/// the hashes we saved against the hashes that it saw from
/// before; this will tell it which of the items in this crate
/// changed, which in turn implies what items in the downstream
/// crate need to be recompiled.
///
/// Note that we store the def-ids here. This is because we don't
/// reload this file when we recompile this crate, we will just
/// regenerate it completely with the current hashes and new def-ids.
///
/// Then downstream creates will load up their
/// `SerializedDepGraph`, which may contain `MetaData(X)` nodes
/// where `X` refers to some item in this crate. That `X` will be
/// a `DefPathIndex` that gets retracted to the current `DefId`
/// (matching the one found in this structure).
pub hashes: Vec<SerializedMetadataHash>,
}
/// The hash for some metadata that (when saving) will be exported
/// from this crate, or which (when importing) was exported by an
/// upstream crate.
#[derive(Debug, RustcEncodable, RustcDecodable)]
pub struct SerializedMetadataHash {
pub def_index: DefIndex,
/// the hash itself, computed by `calculate_item_hash`
pub hash: u64,

View file

@ -41,7 +41,7 @@ impl DefIdDirectory {
pub fn retrace(&self, tcx: TyCtxt) -> RetracedDefIdDirectory {
let ids = self.paths.iter()
.map(|path| tcx.map.retrace_path(path))
.map(|path| tcx.retrace_path(path))
.collect();
RetracedDefIdDirectory { ids: ids }
}
@ -64,7 +64,7 @@ impl RetracedDefIdDirectory {
pub struct DefIdDirectoryBuilder<'a,'tcx:'a> {
tcx: TyCtxt<'a, 'tcx, 'tcx>,
hash: DefIdMap<Option<DefPathIndex>>,
hash: DefIdMap<DefPathIndex>,
directory: DefIdDirectory,
}
@ -77,29 +77,22 @@ impl<'a,'tcx> DefIdDirectoryBuilder<'a,'tcx> {
}
}
pub fn add(&mut self, def_id: DefId) -> Option<DefPathIndex> {
if !def_id.is_local() {
// FIXME(#32015) clarify story about cross-crate dep tracking
return None;
}
pub fn add(&mut self, def_id: DefId) -> DefPathIndex {
debug!("DefIdDirectoryBuilder: def_id={:?}", def_id);
let tcx = self.tcx;
let paths = &mut self.directory.paths;
self.hash.entry(def_id)
.or_insert_with(|| {
let def_path = tcx.def_path(def_id);
if !def_path.is_local() {
return None;
}
let index = paths.len() as u32;
paths.push(def_path);
Some(DefPathIndex { index: index })
DefPathIndex { index: index }
})
.clone()
}
pub fn map(&mut self, node: DepNode<DefId>) -> Option<DepNode<DefPathIndex>> {
node.map_def(|&def_id| self.add(def_id))
pub fn map(&mut self, node: DepNode<DefId>) -> DepNode<DefPathIndex> {
node.map_def(|&def_id| Some(self.add(def_id))).unwrap()
}
pub fn into_directory(self) -> DefIdDirectory {

View file

@ -0,0 +1,163 @@
// Copyright 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.
use calculate_svh::SvhCalculate;
use rbml::Error;
use rbml::opaque::Decoder;
use rustc::dep_graph::DepNode;
use rustc::hir::def_id::DefId;
use rustc::hir::svh::Svh;
use rustc::ty::TyCtxt;
use rustc_data_structures::fnv::FnvHashMap;
use rustc_serialize::Decodable;
use std::io::{ErrorKind, Read};
use std::fs::File;
use syntax::ast;
use super::data::*;
use super::util::*;
pub struct HashContext<'a, 'tcx: 'a> {
pub tcx: TyCtxt<'a, 'tcx, 'tcx>,
item_metadata_hashes: FnvHashMap<DefId, u64>,
crate_hashes: FnvHashMap<ast::CrateNum, Svh>,
}
impl<'a, 'tcx> HashContext<'a, 'tcx> {
pub fn new(tcx: TyCtxt<'a, 'tcx, 'tcx>) -> Self {
HashContext {
tcx: tcx,
item_metadata_hashes: FnvHashMap(),
crate_hashes: FnvHashMap(),
}
}
pub fn hash(&mut self, dep_node: DepNode<DefId>) -> Option<u64> {
match dep_node {
// HIR nodes (which always come from our crate) are an input:
DepNode::Hir(def_id) => {
assert!(def_id.is_local());
Some(self.hir_hash(def_id))
}
// MetaData from other crates is an *input* to us.
// MetaData nodes from *our* crates are an *output*; we
// don't hash them, but we do compute a hash for them and
// save it for others to use.
DepNode::MetaData(def_id) if !def_id.is_local() => {
Some(self.metadata_hash(def_id))
}
_ => {
// Other kinds of nodes represent computed by-products
// that we don't hash directly; instead, they should
// have some transitive dependency on a Hir or
// MetaData node, so we'll just hash that
None
}
}
}
fn hir_hash(&mut self, def_id: DefId) -> u64 {
assert!(def_id.is_local());
// FIXME(#32753) -- should we use a distinct hash here
self.tcx.calculate_item_hash(def_id)
}
fn metadata_hash(&mut self, def_id: DefId) -> u64 {
debug!("metadata_hash(def_id={:?})", def_id);
assert!(!def_id.is_local());
loop {
// check whether we have a result cached for this def-id
if let Some(&hash) = self.item_metadata_hashes.get(&def_id) {
debug!("metadata_hash: def_id={:?} hash={:?}", def_id, hash);
return hash;
}
// check whether we did not find detailed metadata for this
// krate; in that case, we just use the krate's overall hash
if let Some(&hash) = self.crate_hashes.get(&def_id.krate) {
debug!("metadata_hash: def_id={:?} crate_hash={:?}", def_id, hash);
// micro-"optimization": avoid a cache miss if we ask
// for metadata from this particular def-id again.
self.item_metadata_hashes.insert(def_id, hash.as_u64());
return hash.as_u64();
}
// otherwise, load the data and repeat.
self.load_data(def_id.krate);
assert!(self.crate_hashes.contains_key(&def_id.krate));
}
}
fn load_data(&mut self, cnum: ast::CrateNum) {
debug!("load_data(cnum={})", cnum);
let svh = self.tcx.sess.cstore.crate_hash(cnum);
let old = self.crate_hashes.insert(cnum, svh);
debug!("load_data: svh={}", svh);
assert!(old.is_none(), "loaded data for crate {:?} twice", cnum);
if let Some(path) = metadata_hash_path(self.tcx, cnum) {
debug!("load_data: path={:?}", path);
let mut data = vec![];
match
File::open(&path)
.and_then(|mut file| file.read_to_end(&mut data))
{
Ok(_) => {
match self.load_from_data(cnum, &data) {
Ok(()) => { }
Err(err) => {
bug!("decoding error in dep-graph from `{}`: {}",
path.display(), err);
}
}
}
Err(err) => {
match err.kind() {
ErrorKind::NotFound => {
// If the file is not found, that's ok.
}
_ => {
self.tcx.sess.err(
&format!("could not load dep information from `{}`: {}",
path.display(), err));
return;
}
}
}
}
}
}
fn load_from_data(&mut self, cnum: ast::CrateNum, data: &[u8]) -> Result<(), Error> {
debug!("load_from_data(cnum={})", cnum);
// Load up the hashes for the def-ids from this crate.
let mut decoder = Decoder::new(data, 0);
let serialized_hashes = try!(SerializedMetadataHashes::decode(&mut decoder));
for serialized_hash in serialized_hashes.hashes {
// the hashes are stored with just a def-index, which is
// always relative to the old crate; convert that to use
// our internal crate number
let def_id = DefId { krate: cnum, index: serialized_hash.def_index };
// record the hash for this dep-node
let old = self.item_metadata_hashes.insert(def_id, serialized_hash.hash);
debug!("load_from_data: def_id={:?} hash={}", def_id, serialized_hash.hash);
assert!(old.is_none(), "already have hash for {:?}", def_id);
}
Ok(())
}
}

View file

@ -10,7 +10,6 @@
//! Code to save/load the dep-graph from files.
use calculate_svh::SvhCalculate;
use rbml::Error;
use rbml::opaque::Decoder;
use rustc::dep_graph::DepNode;
@ -25,6 +24,7 @@ use std::path::Path;
use super::data::*;
use super::directory::*;
use super::dirty_clean;
use super::hash::*;
use super::util::*;
type DirtyNodes = FnvHashSet<DepNode<DefId>>;
@ -131,20 +131,20 @@ pub fn decode_dep_graph<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
}
fn initial_dirty_nodes<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
hashed_items: &[SerializedHash],
hashes: &[SerializedHash],
retraced: &RetracedDefIdDirectory)
-> DirtyNodes {
let mut hcx = HashContext::new(tcx);
let mut items_removed = false;
let mut dirty_nodes = FnvHashSet();
for hashed_item in hashed_items {
match retraced.def_id(hashed_item.index) {
Some(def_id) => {
// FIXME(#32753) -- should we use a distinct hash here
let current_hash = tcx.calculate_item_hash(def_id);
for hash in hashes {
match hash.node.map_def(|&i| retraced.def_id(i)) {
Some(dep_node) => {
let current_hash = hcx.hash(dep_node).unwrap();
debug!("initial_dirty_nodes: hash of {:?} is {:?}, was {:?}",
def_id, current_hash, hashed_item.hash);
if current_hash != hashed_item.hash {
dirty_nodes.insert(DepNode::Hir(def_id));
dep_node, current_hash, hash.hash);
if current_hash != hash.hash {
dirty_nodes.insert(dep_node);
}
}
None => {

View file

@ -15,6 +15,7 @@
mod data;
mod directory;
mod dirty_clean;
mod hash;
mod load;
mod save;
mod util;

View file

@ -8,116 +8,115 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
use calculate_svh::SvhCalculate;
use rbml::opaque::Encoder;
use rustc::dep_graph::DepNode;
use rustc::middle::cstore::LOCAL_CRATE;
use rustc::ty::TyCtxt;
use rustc_serialize::{Encodable as RustcEncodable};
use std::hash::{Hasher, SipHasher};
use std::io::{self, Cursor, Write};
use std::fs::{self, File};
use std::path::PathBuf;
use super::data::*;
use super::directory::*;
use super::hash::*;
use super::util::*;
pub fn save_dep_graph<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) {
let _ignore = tcx.dep_graph.in_ignore();
let mut hcx = HashContext::new(tcx);
save_in(&mut hcx, dep_graph_path(tcx), encode_dep_graph);
save_in(&mut hcx, metadata_hash_path(tcx, LOCAL_CRATE), encode_metadata_hashes);
}
if let Some(dep_graph) = dep_graph_path(tcx) {
// FIXME(#32754) lock file?
fn save_in<'a, 'tcx, F>(hcx: &mut HashContext<'a, 'tcx>,
opt_path_buf: Option<PathBuf>,
encode: F)
where F: FnOnce(&mut HashContext<'a, 'tcx>, &mut Encoder) -> io::Result<()>
{
let tcx = hcx.tcx;
// delete the old dep-graph, if any
if dep_graph.exists() {
match fs::remove_file(&dep_graph) {
Ok(()) => { }
Err(err) => {
tcx.sess.err(
&format!("unable to delete old dep-graph at `{}`: {}",
dep_graph.display(), err));
return;
}
}
}
let path_buf = match opt_path_buf {
Some(p) => p,
None => return
};
// generate the data in a memory buffer
let mut wr = Cursor::new(Vec::new());
match encode_dep_graph(tcx, &mut Encoder::new(&mut wr)) {
// FIXME(#32754) lock file?
// delete the old dep-graph, if any
if path_buf.exists() {
match fs::remove_file(&path_buf) {
Ok(()) => { }
Err(err) => {
tcx.sess.err(
&format!("could not encode dep-graph to `{}`: {}",
dep_graph.display(), err));
return;
}
}
// write the data out
let data = wr.into_inner();
match
File::create(&dep_graph)
.and_then(|mut file| file.write_all(&data))
{
Ok(_) => { }
Err(err) => {
tcx.sess.err(
&format!("failed to write dep-graph to `{}`: {}",
dep_graph.display(), err));
&format!("unable to delete old dep-graph at `{}`: {}",
path_buf.display(), err));
return;
}
}
}
// generate the data in a memory buffer
let mut wr = Cursor::new(Vec::new());
match encode(hcx, &mut Encoder::new(&mut wr)) {
Ok(()) => { }
Err(err) => {
tcx.sess.err(
&format!("could not encode dep-graph to `{}`: {}",
path_buf.display(), err));
return;
}
}
// write the data out
let data = wr.into_inner();
match
File::create(&path_buf)
.and_then(|mut file| file.write_all(&data))
{
Ok(_) => { }
Err(err) => {
tcx.sess.err(
&format!("failed to write dep-graph to `{}`: {}",
path_buf.display(), err));
return;
}
}
}
pub fn encode_dep_graph<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
pub fn encode_dep_graph<'a, 'tcx>(hcx: &mut HashContext<'a, 'tcx>,
encoder: &mut Encoder)
-> io::Result<()> {
// Here we take advantage of how RBML allows us to skip around
// and encode the depgraph as a two-part structure:
//
// ```
// <dep-graph>[SerializedDepGraph]</dep-graph> // tag 0
// <directory>[DefIdDirectory]</directory> // tag 1
// ```
//
// Then later we can load the directory by skipping to find tag 1.
-> io::Result<()>
{
let tcx = hcx.tcx;
let query = tcx.dep_graph.query();
let mut builder = DefIdDirectoryBuilder::new(tcx);
// Create hashes for things we can persist.
// Create hashes for inputs.
let hashes =
query.nodes()
.into_iter()
.filter_map(|dep_node| match dep_node {
DepNode::Hir(def_id) => {
assert!(def_id.is_local());
builder.add(def_id)
.map(|index| {
// FIXME(#32753) -- should we use a distinct hash here
let hash = tcx.calculate_item_hash(def_id);
SerializedHash { index: index, hash: hash }
})
}
_ => None
.filter_map(|dep_node| {
hcx.hash(dep_node)
.map(|hash| {
let node = builder.map(dep_node);
SerializedHash { node: node, hash: hash }
})
})
.collect();
// Create the serialized dep-graph, dropping nodes that are
// from other crates or from inlined items.
//
// FIXME(#32015) fix handling of other crates
// Create the serialized dep-graph.
let graph = SerializedDepGraph {
nodes: query.nodes().into_iter()
.flat_map(|node| builder.map(node))
.map(|node| builder.map(node))
.collect(),
edges: query.edges().into_iter()
.flat_map(|(source_node, target_node)| {
builder.map(source_node)
.and_then(|source| {
builder.map(target_node)
.map(|target| (source, target))
})
.map(|(source_node, target_node)| {
let source = builder.map(source_node);
let target = builder.map(target_node);
(source, target)
})
.collect(),
hashes: hashes,
@ -133,3 +132,63 @@ pub fn encode_dep_graph<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
Ok(())
}
pub fn encode_metadata_hashes<'a, 'tcx>(hcx: &mut HashContext<'a, 'tcx>,
encoder: &mut Encoder)
-> io::Result<()>
{
let tcx = hcx.tcx;
let query = tcx.dep_graph.query();
let serialized_hashes = {
// Identify the `MetaData(X)` nodes where `X` is local. These are
// the metadata items we export. Downstream crates will want to
// see a hash that tells them whether we might have changed the
// metadata for a given item since they last compiled.
let meta_data_def_ids =
query.nodes()
.into_iter()
.filter_map(|dep_node| match dep_node {
DepNode::MetaData(def_id) if def_id.is_local() => Some(def_id),
_ => None,
});
// To create the hash for each item `X`, we don't hash the raw
// bytes of the metadata (though in principle we
// could). Instead, we walk the predecessors of `MetaData(X)`
// from the dep-graph. This corresponds to all the inputs that
// were read to construct the metadata. To create the hash for
// the metadata, we hash (the hash of) all of those inputs.
let hashes =
meta_data_def_ids
.map(|def_id| {
assert!(def_id.is_local());
let dep_node = DepNode::MetaData(def_id);
let mut state = SipHasher::new();
debug!("save: computing metadata hash for {:?}", dep_node);
for node in query.transitive_predecessors(dep_node) {
if let Some(hash) = hcx.hash(node) {
debug!("save: predecessor {:?} has hash {}", node, hash);
state.write_u64(hash.to_le());
} else {
debug!("save: predecessor {:?} cannot be hashed", node);
}
}
let hash = state.finish();
debug!("save: metadata hash for {:?} is {}", dep_node, hash);
SerializedMetadataHash {
def_index: def_id.index,
hash: hash,
}
});
// Collect these up into a vector.
SerializedMetadataHashes {
hashes: hashes.collect()
}
};
// Encode everything.
try!(serialized_hashes.encode(encoder));
Ok(())
}

View file

@ -8,13 +8,23 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
use rustc::middle::cstore::LOCAL_CRATE;
use rustc::ty::TyCtxt;
use std::fs;
use std::io;
use std::path::{PathBuf, Path};
use std::path::{Path, PathBuf};
use syntax::ast;
pub fn dep_graph_path(tcx: TyCtxt) -> Option<PathBuf> {
path(tcx, LOCAL_CRATE, "local")
}
pub fn metadata_hash_path(tcx: TyCtxt, cnum: ast::CrateNum) -> Option<PathBuf> {
path(tcx, cnum, "metadata")
}
fn path(tcx: TyCtxt, cnum: ast::CrateNum, suffix: &str) -> Option<PathBuf> {
// For now, just save/load dep-graph from
// directory/dep_graph.rbml
tcx.sess.opts.incremental.as_ref().and_then(|incr_dir| {
@ -28,7 +38,13 @@ pub fn dep_graph_path(tcx: TyCtxt) -> Option<PathBuf> {
}
}
Some(incr_dir.join("dep_graph.rbml"))
let crate_name = tcx.crate_name(cnum);
let crate_disambiguator = tcx.crate_disambiguator(cnum);
let file_name = format!("{}-{}.{}.bin",
crate_name,
crate_disambiguator,
suffix);
Some(incr_dir.join(file_name))
})
}
@ -52,3 +68,4 @@ fn create_dir_racy(path: &Path) -> io::Result<()> {
Err(e) => Err(e),
}
}

View file

@ -319,6 +319,7 @@ impl<'a> CrateReader<'a> {
extern_crate: Cell::new(None),
index: decoder::load_index(metadata.as_slice()),
xref_index: decoder::load_xrefs(metadata.as_slice()),
key_map: decoder::load_key_map(metadata.as_slice()),
data: metadata,
cnum_map: RefCell::new(cnum_map),
cnum: cnum,

View file

@ -20,7 +20,9 @@ use middle::lang_items;
use rustc::ty::{self, Ty, TyCtxt, VariantKind};
use rustc::hir::def_id::{DefId, DefIndex, CRATE_DEF_INDEX};
use rustc::dep_graph::DepNode;
use rustc::hir::map as hir_map;
use rustc::hir::map::DefKey;
use rustc::mir::repr::Mir;
use rustc::mir::mir_map::MirMap;
use rustc::util::nodemap::{FnvHashMap, NodeMap, NodeSet, DefIdMap};
@ -37,19 +39,20 @@ use rustc_back::target::Target;
use rustc::hir;
impl<'tcx> CrateStore<'tcx> for cstore::CStore {
fn stability(&self, def: DefId) -> Option<attr::Stability>
{
fn stability(&self, def: DefId) -> Option<attr::Stability> {
self.dep_graph.read(DepNode::MetaData(def));
let cdata = self.get_crate_data(def.krate);
decoder::get_stability(&cdata, def.index)
}
fn deprecation(&self, def: DefId) -> Option<attr::Deprecation>
{
fn deprecation(&self, def: DefId) -> Option<attr::Deprecation> {
self.dep_graph.read(DepNode::MetaData(def));
let cdata = self.get_crate_data(def.krate);
decoder::get_deprecation(&cdata, def.index)
}
fn visibility(&self, def: DefId) -> ty::Visibility {
self.dep_graph.read(DepNode::MetaData(def));
let cdata = self.get_crate_data(def.krate);
decoder::get_visibility(&cdata, def.index)
}
@ -57,23 +60,26 @@ impl<'tcx> CrateStore<'tcx> for cstore::CStore {
fn closure_kind(&self, def_id: DefId) -> ty::ClosureKind
{
assert!(!def_id.is_local());
self.dep_graph.read(DepNode::MetaData(def_id));
let cdata = self.get_crate_data(def_id.krate);
decoder::closure_kind(&cdata, def_id.index)
}
fn closure_ty<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> ty::ClosureTy<'tcx>
{
fn closure_ty<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> ty::ClosureTy<'tcx> {
assert!(!def_id.is_local());
self.dep_graph.read(DepNode::MetaData(def_id));
let cdata = self.get_crate_data(def_id.krate);
decoder::closure_ty(&cdata, def_id.index, tcx)
}
fn item_variances(&self, def: DefId) -> ty::ItemVariances {
self.dep_graph.read(DepNode::MetaData(def));
let cdata = self.get_crate_data(def.krate);
decoder::get_item_variances(&cdata, def.index)
}
fn repr_attrs(&self, def: DefId) -> Vec<attr::ReprAttr> {
self.dep_graph.read(DepNode::MetaData(def));
let cdata = self.get_crate_data(def.krate);
decoder::get_repr_attrs(&cdata, def.index)
}
@ -81,6 +87,7 @@ impl<'tcx> CrateStore<'tcx> for cstore::CStore {
fn item_type<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId)
-> ty::TypeScheme<'tcx>
{
self.dep_graph.read(DepNode::MetaData(def));
let cdata = self.get_crate_data(def.krate);
decoder::get_type(&cdata, def.index, tcx)
}
@ -88,6 +95,7 @@ impl<'tcx> CrateStore<'tcx> for cstore::CStore {
fn item_predicates<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId)
-> ty::GenericPredicates<'tcx>
{
self.dep_graph.read(DepNode::MetaData(def));
let cdata = self.get_crate_data(def.krate);
decoder::get_predicates(&cdata, def.index, tcx)
}
@ -95,41 +103,48 @@ impl<'tcx> CrateStore<'tcx> for cstore::CStore {
fn item_super_predicates<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId)
-> ty::GenericPredicates<'tcx>
{
self.dep_graph.read(DepNode::MetaData(def));
let cdata = self.get_crate_data(def.krate);
decoder::get_super_predicates(&cdata, def.index, tcx)
}
fn item_attrs(&self, def_id: DefId) -> Vec<ast::Attribute>
{
self.dep_graph.read(DepNode::MetaData(def_id));
let cdata = self.get_crate_data(def_id.krate);
decoder::get_item_attrs(&cdata, def_id.index)
}
fn item_symbol(&self, def: DefId) -> String
{
self.dep_graph.read(DepNode::MetaData(def));
let cdata = self.get_crate_data(def.krate);
decoder::get_symbol(&cdata, def.index)
}
fn trait_def<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId) -> ty::TraitDef<'tcx>
{
self.dep_graph.read(DepNode::MetaData(def));
let cdata = self.get_crate_data(def.krate);
decoder::get_trait_def(&cdata, def.index, tcx)
}
fn adt_def<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId) -> ty::AdtDefMaster<'tcx>
{
self.dep_graph.read(DepNode::MetaData(def));
let cdata = self.get_crate_data(def.krate);
decoder::get_adt_def(&self.intr, &cdata, def.index, tcx)
}
fn method_arg_names(&self, did: DefId) -> Vec<String>
{
self.dep_graph.read(DepNode::MetaData(did));
let cdata = self.get_crate_data(did.krate);
decoder::get_method_arg_names(&cdata, did.index)
}
fn item_name(&self, def: DefId) -> ast::Name {
self.dep_graph.read(DepNode::MetaData(def));
let cdata = self.get_crate_data(def.krate);
decoder::get_item_name(&self.intr, &cdata, def.index)
}
@ -137,6 +152,7 @@ impl<'tcx> CrateStore<'tcx> for cstore::CStore {
fn inherent_implementations_for_type(&self, def_id: DefId) -> Vec<DefId>
{
self.dep_graph.read(DepNode::MetaData(def_id));
let mut result = vec![];
let cdata = self.get_crate_data(def_id.krate);
decoder::each_inherent_implementation_for_type(&cdata, def_id.index,
@ -146,6 +162,7 @@ impl<'tcx> CrateStore<'tcx> for cstore::CStore {
fn implementations_of_trait(&self, def_id: DefId) -> Vec<DefId>
{
self.dep_graph.read(DepNode::MetaData(def_id));
let mut result = vec![];
self.iter_crate_data(|_, cdata| {
decoder::each_implementation_for_trait(cdata, def_id, &mut |iid| {
@ -158,6 +175,7 @@ impl<'tcx> CrateStore<'tcx> for cstore::CStore {
fn provided_trait_methods<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId)
-> Vec<Rc<ty::Method<'tcx>>>
{
self.dep_graph.read(DepNode::MetaData(def));
let cdata = self.get_crate_data(def.krate);
decoder::get_provided_trait_methods(self.intr.clone(), &cdata, def.index, tcx)
}
@ -165,18 +183,21 @@ impl<'tcx> CrateStore<'tcx> for cstore::CStore {
fn trait_item_def_ids(&self, def: DefId)
-> Vec<ty::ImplOrTraitItemId>
{
self.dep_graph.read(DepNode::MetaData(def));
let cdata = self.get_crate_data(def.krate);
decoder::get_trait_item_def_ids(&cdata, def.index)
}
fn impl_items(&self, impl_def_id: DefId) -> Vec<ty::ImplOrTraitItemId>
{
self.dep_graph.read(DepNode::MetaData(impl_def_id));
let cdata = self.get_crate_data(impl_def_id.krate);
decoder::get_impl_items(&cdata, impl_def_id.index)
}
fn impl_polarity(&self, def: DefId) -> Option<hir::ImplPolarity>
{
self.dep_graph.read(DepNode::MetaData(def));
let cdata = self.get_crate_data(def.krate);
decoder::get_impl_polarity(&cdata, def.index)
}
@ -184,6 +205,7 @@ impl<'tcx> CrateStore<'tcx> for cstore::CStore {
fn impl_trait_ref<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId)
-> Option<ty::TraitRef<'tcx>>
{
self.dep_graph.read(DepNode::MetaData(def));
let cdata = self.get_crate_data(def.krate);
decoder::get_impl_trait(&cdata, def.index, tcx)
}
@ -191,6 +213,7 @@ impl<'tcx> CrateStore<'tcx> for cstore::CStore {
fn custom_coerce_unsized_kind(&self, def: DefId)
-> Option<ty::adjustment::CustomCoerceUnsized>
{
self.dep_graph.read(DepNode::MetaData(def));
let cdata = self.get_crate_data(def.krate);
decoder::get_custom_coerce_unsized_kind(&cdata, def.index)
}
@ -198,17 +221,20 @@ impl<'tcx> CrateStore<'tcx> for cstore::CStore {
// FIXME: killme
fn associated_consts<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId)
-> Vec<Rc<ty::AssociatedConst<'tcx>>> {
self.dep_graph.read(DepNode::MetaData(def));
let cdata = self.get_crate_data(def.krate);
decoder::get_associated_consts(self.intr.clone(), &cdata, def.index, tcx)
}
fn impl_parent(&self, impl_def: DefId) -> Option<DefId> {
self.dep_graph.read(DepNode::MetaData(impl_def));
let cdata = self.get_crate_data(impl_def.krate);
decoder::get_parent_impl(&*cdata, impl_def.index)
}
fn trait_of_item<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> Option<DefId>
{
self.dep_graph.read(DepNode::MetaData(def_id));
let cdata = self.get_crate_data(def_id.krate);
decoder::get_trait_of_item(&cdata, def_id.index, tcx)
}
@ -216,6 +242,7 @@ impl<'tcx> CrateStore<'tcx> for cstore::CStore {
fn impl_or_trait_item<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId)
-> Option<ty::ImplOrTraitItem<'tcx>>
{
self.dep_graph.read(DepNode::MetaData(def));
let cdata = self.get_crate_data(def.krate);
decoder::get_impl_or_trait_item(
self.intr.clone(),
@ -226,34 +253,40 @@ impl<'tcx> CrateStore<'tcx> for cstore::CStore {
fn is_const_fn(&self, did: DefId) -> bool
{
self.dep_graph.read(DepNode::MetaData(did));
let cdata = self.get_crate_data(did.krate);
decoder::is_const_fn(&cdata, did.index)
}
fn is_defaulted_trait(&self, trait_def_id: DefId) -> bool
{
self.dep_graph.read(DepNode::MetaData(trait_def_id));
let cdata = self.get_crate_data(trait_def_id.krate);
decoder::is_defaulted_trait(&cdata, trait_def_id.index)
}
fn is_impl(&self, did: DefId) -> bool
{
self.dep_graph.read(DepNode::MetaData(did));
let cdata = self.get_crate_data(did.krate);
decoder::is_impl(&cdata, did.index)
}
fn is_default_impl(&self, impl_did: DefId) -> bool {
self.dep_graph.read(DepNode::MetaData(impl_did));
let cdata = self.get_crate_data(impl_did.krate);
decoder::is_default_impl(&cdata, impl_did.index)
}
fn is_extern_item<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, did: DefId) -> bool {
self.dep_graph.read(DepNode::MetaData(did));
let cdata = self.get_crate_data(did.krate);
decoder::is_extern_item(&cdata, did.index, tcx)
}
fn is_static_method(&self, def: DefId) -> bool
{
self.dep_graph.read(DepNode::MetaData(def));
let cdata = self.get_crate_data(def.krate);
decoder::is_static_method(&cdata, def.index)
}
@ -264,6 +297,7 @@ impl<'tcx> CrateStore<'tcx> for cstore::CStore {
}
fn is_typedef(&self, did: DefId) -> bool {
self.dep_graph.read(DepNode::MetaData(did));
let cdata = self.get_crate_data(did.krate);
decoder::is_typedef(&cdata, did.index)
}
@ -375,44 +409,59 @@ impl<'tcx> CrateStore<'tcx> for cstore::CStore {
decoder::get_reachable_ids(&cdata)
}
fn def_index_for_def_key(&self,
cnum: ast::CrateNum,
def: DefKey)
-> Option<DefIndex> {
let cdata = self.get_crate_data(cnum);
cdata.key_map.get(&def).cloned()
}
/// Returns the `DefKey` for a given `DefId`. This indicates the
/// parent `DefId` as well as some idea of what kind of data the
/// `DefId` refers to.
fn def_key(&self, def: DefId) -> hir_map::DefKey {
self.dep_graph.read(DepNode::MetaData(def));
let cdata = self.get_crate_data(def.krate);
decoder::def_key(&cdata, def.index)
}
fn relative_def_path(&self, def: DefId) -> hir_map::DefPath {
self.dep_graph.read(DepNode::MetaData(def));
let cdata = self.get_crate_data(def.krate);
decoder::def_path(&cdata, def.index)
}
fn variant_kind(&self, def_id: DefId) -> Option<VariantKind> {
self.dep_graph.read(DepNode::MetaData(def_id));
let cdata = self.get_crate_data(def_id.krate);
decoder::get_variant_kind(&cdata, def_id.index)
}
fn struct_ctor_def_id(&self, struct_def_id: DefId) -> Option<DefId>
{
self.dep_graph.read(DepNode::MetaData(struct_def_id));
let cdata = self.get_crate_data(struct_def_id.krate);
decoder::get_struct_ctor_def_id(&cdata, struct_def_id.index)
}
fn tuple_struct_definition_if_ctor(&self, did: DefId) -> Option<DefId>
{
self.dep_graph.read(DepNode::MetaData(did));
let cdata = self.get_crate_data(did.krate);
decoder::get_tuple_struct_definition_if_ctor(&cdata, did.index)
}
fn struct_field_names(&self, def: DefId) -> Vec<ast::Name>
{
self.dep_graph.read(DepNode::MetaData(def));
let cdata = self.get_crate_data(def.krate);
decoder::get_struct_field_names(&self.intr, &cdata, def.index)
}
fn item_children(&self, def_id: DefId) -> Vec<ChildItem>
{
self.dep_graph.read(DepNode::MetaData(def_id));
let mut result = vec![];
let crate_data = self.get_crate_data(def_id.krate);
let get_crate_data = |cnum| self.get_crate_data(cnum);
@ -445,17 +494,20 @@ impl<'tcx> CrateStore<'tcx> for cstore::CStore {
fn maybe_get_item_ast<'a>(&'tcx self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId)
-> FoundAst<'tcx>
{
self.dep_graph.read(DepNode::MetaData(def));
let cdata = self.get_crate_data(def.krate);
decoder::maybe_get_item_ast(&cdata, tcx, def.index)
}
fn maybe_get_item_mir<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId)
-> Option<Mir<'tcx>> {
self.dep_graph.read(DepNode::MetaData(def));
let cdata = self.get_crate_data(def.krate);
decoder::maybe_get_item_mir(&cdata, tcx, def.index)
}
fn is_item_mir_available(&self, def: DefId) -> bool {
self.dep_graph.read(DepNode::MetaData(def));
let cdata = self.get_crate_data(def.krate);
decoder::is_item_mir_available(&cdata, def.index)
}

View file

@ -20,7 +20,9 @@ use decoder;
use index;
use loader;
use rustc::hir::def_id::DefId;
use rustc::dep_graph::DepGraph;
use rustc::hir::def_id::{DefIndex, DefId};
use rustc::hir::map::DefKey;
use rustc::hir::svh::Svh;
use rustc::middle::cstore::{ExternCrate};
use rustc::session::config::PanicStrategy;
@ -78,6 +80,13 @@ pub struct crate_metadata {
pub index: index::Index,
pub xref_index: index::DenseIndex,
/// 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: FnvHashMap<DefKey, DefIndex>,
/// Flag if this crate is required by an rlib version of this crate, or in
/// other words whether it was explicitly linked to. An example of a crate
/// where this is false is when an allocator crate is injected into the
@ -86,6 +95,7 @@ pub struct crate_metadata {
}
pub struct CStore {
pub dep_graph: DepGraph,
metas: RefCell<FnvHashMap<ast::CrateNum, Rc<crate_metadata>>>,
/// Map from NodeId's of local extern crate statements to crate numbers
extern_mod_crate_map: RefCell<NodeMap<ast::CrateNum>>,
@ -98,8 +108,10 @@ pub struct CStore {
}
impl CStore {
pub fn new(intr: Rc<IdentInterner>) -> CStore {
pub fn new(dep_graph: &DepGraph,
intr: Rc<IdentInterner>) -> CStore {
CStore {
dep_graph: dep_graph.clone(),
metas: RefCell::new(FnvHashMap()),
extern_mod_crate_map: RefCell::new(FnvHashMap()),
used_crate_sources: RefCell::new(Vec::new()),

View file

@ -25,6 +25,7 @@ use tydecode::TyDecoder;
use rustc::hir::svh::Svh;
use rustc::hir::map as hir_map;
use rustc::hir::map::DefKey;
use rustc::util::nodemap::FnvHashMap;
use rustc::hir;
use rustc::session::config::PanicStrategy;
@ -71,7 +72,10 @@ impl crate_metadata {
fn lookup_item(&self, item_id: DefIndex) -> rbml::Doc {
match self.get_item(item_id) {
None => bug!("lookup_item: id not found: {:?}", item_id),
None => bug!("lookup_item: id not found: {:?} in crate {:?} with number {}",
item_id,
self.name,
self.cnum),
Some(d) => d
}
}
@ -92,6 +96,29 @@ pub fn load_xrefs(data: &[u8]) -> index::DenseIndex {
index::DenseIndex::from_buf(index.data, index.start, index.end)
}
// Go through each item in the metadata and create a map from that
// item's def-key to the item's DefIndex.
pub fn load_key_map(data: &[u8]) -> FnvHashMap<DefKey, DefIndex> {
let root_doc = rbml::Doc::new(data);
let items_doc = reader::get_doc(root_doc, tag_items);
let items_data_doc = reader::get_doc(items_doc, tag_items_data);
reader::docs(items_data_doc)
.filter(|&(tag, _)| tag == tag_items_data_item)
.map(|(_, item_doc)| {
// load def-key from item
let key = item_def_key(item_doc);
// load def-index from item; we only encode the full def-id,
// so just pull out the index
let def_id_doc = reader::get_doc(item_doc, tag_def_id);
let def_id = untranslated_def_id(def_id_doc);
assert!(def_id.is_local()); // local to the crate we are decoding, that is
(key, def_id.index)
})
.collect()
}
#[derive(Clone, Copy, Debug, PartialEq)]
enum Family {
ImmStatic, // c
@ -190,10 +217,14 @@ fn item_symbol(item: rbml::Doc) -> String {
reader::get_doc(item, tag_items_data_item_symbol).as_str().to_string()
}
fn translated_def_id(cdata: Cmd, d: rbml::Doc) -> DefId {
fn untranslated_def_id(d: rbml::Doc) -> DefId {
let id = reader::doc_as_u64(d);
let index = DefIndex::new((id & 0xFFFF_FFFF) as usize);
let def_id = DefId { krate: (id >> 32) as u32, index: index };
DefId { krate: (id >> 32) as u32, index: index }
}
fn translated_def_id(cdata: Cmd, d: rbml::Doc) -> DefId {
let def_id = untranslated_def_id(d);
translate_def_id(cdata, def_id)
}
@ -1248,7 +1279,7 @@ pub fn get_crate_deps(data: &[u8]) -> Vec<CrateDep> {
reader::tagged_docs(depsdoc, tag_crate_dep).enumerate().map(|(crate_num, depdoc)| {
let name = docstr(depdoc, tag_crate_dep_crate_name);
let hash = Svh::new(docstr(depdoc, tag_crate_dep_hash));
let hash = Svh::new(reader::doc_as_u64(reader::get_doc(depdoc, tag_crate_dep_hash)));
let doc = reader::get_doc(depdoc, tag_crate_dep_explicitly_linked);
let explicitly_linked = reader::doc_as_u8(doc) != 0;
CrateDep {
@ -1272,14 +1303,14 @@ fn list_crate_deps(data: &[u8], out: &mut io::Write) -> io::Result<()> {
pub fn maybe_get_crate_hash(data: &[u8]) -> Option<Svh> {
let cratedoc = rbml::Doc::new(data);
reader::maybe_get_doc(cratedoc, tag_crate_hash).map(|doc| {
Svh::new(doc.as_str_slice().to_string())
Svh::new(reader::doc_as_u64(doc))
})
}
pub fn get_crate_hash(data: &[u8]) -> Svh {
let cratedoc = rbml::Doc::new(data);
let hashdoc = reader::get_doc(cratedoc, tag_crate_hash);
Svh::new(hashdoc.as_str_slice().to_string())
Svh::new(reader::doc_as_u64(hashdoc))
}
pub fn maybe_get_crate_name(data: &[u8]) -> Option<&str> {
@ -1747,6 +1778,10 @@ pub fn closure_ty<'a, 'tcx>(cdata: Cmd, closure_id: DefIndex, tcx: TyCtxt<'a, 't
pub fn def_key(cdata: Cmd, id: DefIndex) -> hir_map::DefKey {
debug!("def_key: id={:?}", id);
let item_doc = cdata.lookup_item(id);
item_def_key(item_doc)
}
fn item_def_key(item_doc: rbml::Doc) -> hir_map::DefKey {
match reader::maybe_get_doc(item_doc, tag_def_key) {
Some(def_key_doc) => {
let mut decoder = reader::Decoder::new(def_key_doc);

View file

@ -25,6 +25,7 @@ use middle::cstore::{LOCAL_CRATE, InlinedItemRef, LinkMeta, tls};
use rustc::hir::def;
use rustc::hir::def_id::{CRATE_DEF_INDEX, DefId};
use middle::dependency_format::Linkage;
use rustc::dep_graph::{DepGraph, DepNode, DepTask};
use rustc::ty::subst;
use rustc::traits::specialization_graph;
use rustc::ty::{self, Ty, TyCtxt};
@ -76,15 +77,23 @@ impl<'a, 'tcx> EncodeContext<'a,'tcx> {
#[derive(PartialEq, Eq, Hash)]
pub enum XRef<'tcx> { Predicate(ty::Predicate<'tcx>) }
struct CrateIndex<'tcx> {
struct CrateIndex<'a, 'tcx> {
dep_graph: &'a DepGraph,
items: IndexData,
xrefs: FnvHashMap<XRef<'tcx>, u32>, // sequentially-assigned
}
impl<'tcx> CrateIndex<'tcx> {
fn record(&mut self, id: DefId, rbml_w: &mut Encoder) {
impl<'a, 'tcx> CrateIndex<'a, 'tcx> {
/// Records that `id` is being emitted at the current offset.
/// This data is later used to construct the item index in the
/// metadata so we can quickly find the data for a given item.
///
/// Returns a dep-graph task that you should keep live as long as
/// the data for this item is being emitted.
fn record(&mut self, id: DefId, rbml_w: &mut Encoder) -> DepTask<'a> {
let position = rbml_w.mark_stable_position();
self.items.record(id, position);
self.dep_graph.in_task(DepNode::MetaData(id))
}
fn add_xref(&mut self, xref: XRef<'tcx>) -> u32 {
@ -154,7 +163,7 @@ fn encode_item_variances(rbml_w: &mut Encoder,
fn encode_bounds_and_type_for_item<'a, 'tcx>(rbml_w: &mut Encoder,
ecx: &EncodeContext<'a, 'tcx>,
index: &mut CrateIndex<'tcx>,
index: &mut CrateIndex<'a, 'tcx>,
id: NodeId) {
encode_bounds_and_type(rbml_w,
ecx,
@ -165,7 +174,7 @@ fn encode_bounds_and_type_for_item<'a, 'tcx>(rbml_w: &mut Encoder,
fn encode_bounds_and_type<'a, 'tcx>(rbml_w: &mut Encoder,
ecx: &EncodeContext<'a, 'tcx>,
index: &mut CrateIndex<'tcx>,
index: &mut CrateIndex<'a, 'tcx>,
scheme: &ty::TypeScheme<'tcx>,
predicates: &ty::GenericPredicates<'tcx>) {
encode_generics(rbml_w, ecx, index,
@ -248,7 +257,7 @@ fn encode_enum_variant_info<'a, 'tcx>(ecx: &EncodeContext<'a, 'tcx>,
rbml_w: &mut Encoder,
did: DefId,
vis: &hir::Visibility,
index: &mut CrateIndex<'tcx>) {
index: &mut CrateIndex<'a, 'tcx>) {
debug!("encode_enum_variant_info(did={:?})", did);
let repr_hints = ecx.tcx.lookup_repr_hints(did);
let repr_type = ecx.tcx.enum_repr_type(repr_hints.get(0));
@ -258,15 +267,11 @@ fn encode_enum_variant_info<'a, 'tcx>(ecx: &EncodeContext<'a, 'tcx>,
let vid = variant.did;
let variant_node_id = ecx.local_id(vid);
if let ty::VariantKind::Struct = variant.kind() {
// tuple-like enum variant fields aren't really items so
// don't try to encode them.
for field in &variant.fields {
encode_field(ecx, rbml_w, field, index);
}
for field in &variant.fields {
encode_field(ecx, rbml_w, field, index);
}
index.record(vid, rbml_w);
let _task = index.record(vid, rbml_w);
rbml_w.start_tag(tag_items_data_item);
encode_def_id_and_key(ecx, rbml_w, vid);
encode_family(rbml_w, match variant.kind() {
@ -297,6 +302,7 @@ fn encode_enum_variant_info<'a, 'tcx>(ecx: &EncodeContext<'a, 'tcx>,
encode_bounds_and_type_for_item(rbml_w, ecx, index, variant_node_id);
rbml_w.end_tag();
disr_val = disr_val.wrap_incr();
}
}
@ -471,11 +477,11 @@ fn encode_item_sort(rbml_w: &mut Encoder, sort: char) {
fn encode_field<'a, 'tcx>(ecx: &EncodeContext<'a, 'tcx>,
rbml_w: &mut Encoder,
field: ty::FieldDef<'tcx>,
index: &mut CrateIndex<'tcx>) {
index: &mut CrateIndex<'a, 'tcx>) {
let nm = field.name;
let id = ecx.local_id(field.did);
index.record(field.did, rbml_w);
let _task = index.record(field.did, rbml_w);
rbml_w.start_tag(tag_items_data_item);
debug!("encode_field: encoding {} {}", nm, id);
encode_struct_field_family(rbml_w, field.vis);
@ -495,12 +501,12 @@ fn encode_info_for_struct_ctor<'a, 'tcx>(ecx: &EncodeContext<'a, 'tcx>,
rbml_w: &mut Encoder,
name: Name,
struct_def: &hir::VariantData,
index: &mut CrateIndex<'tcx>,
index: &mut CrateIndex<'a, 'tcx>,
struct_id: NodeId) {
let ctor_id = struct_def.id();
let ctor_def_id = ecx.tcx.map.local_def_id(ctor_id);
index.record(ctor_def_id, rbml_w);
let _task = index.record(ctor_def_id, rbml_w);
rbml_w.start_tag(tag_items_data_item);
encode_def_id_and_key(ecx, rbml_w, ctor_def_id);
encode_family(rbml_w, match *struct_def {
@ -531,7 +537,7 @@ fn encode_info_for_struct_ctor<'a, 'tcx>(ecx: &EncodeContext<'a, 'tcx>,
fn encode_generics<'a, 'tcx>(rbml_w: &mut Encoder,
ecx: &EncodeContext<'a, 'tcx>,
index: &mut CrateIndex<'tcx>,
index: &mut CrateIndex<'a, 'tcx>,
generics: &ty::Generics<'tcx>,
predicates: &ty::GenericPredicates<'tcx>,
tag: usize)
@ -576,7 +582,7 @@ fn encode_generics<'a, 'tcx>(rbml_w: &mut Encoder,
fn encode_predicates_in_current_doc<'a,'tcx>(rbml_w: &mut Encoder,
_ecx: &EncodeContext<'a,'tcx>,
index: &mut CrateIndex<'tcx>,
index: &mut CrateIndex<'a, 'tcx>,
predicates: &ty::GenericPredicates<'tcx>)
{
for (space, _, predicate) in predicates.predicates.iter_enumerated() {
@ -593,7 +599,7 @@ fn encode_predicates_in_current_doc<'a,'tcx>(rbml_w: &mut Encoder,
fn encode_predicates<'a,'tcx>(rbml_w: &mut Encoder,
ecx: &EncodeContext<'a,'tcx>,
index: &mut CrateIndex<'tcx>,
index: &mut CrateIndex<'a, 'tcx>,
predicates: &ty::GenericPredicates<'tcx>,
tag: usize)
{
@ -604,7 +610,7 @@ fn encode_predicates<'a,'tcx>(rbml_w: &mut Encoder,
fn encode_method_ty_fields<'a, 'tcx>(ecx: &EncodeContext<'a, 'tcx>,
rbml_w: &mut Encoder,
index: &mut CrateIndex<'tcx>,
index: &mut CrateIndex<'a, 'tcx>,
method_ty: &ty::Method<'tcx>) {
encode_def_id_and_key(ecx, rbml_w, method_ty.def_id);
encode_name(rbml_w, method_ty.name);
@ -623,7 +629,7 @@ fn encode_method_ty_fields<'a, 'tcx>(ecx: &EncodeContext<'a, 'tcx>,
fn encode_info_for_associated_const<'a, 'tcx>(ecx: &EncodeContext<'a, 'tcx>,
rbml_w: &mut Encoder,
index: &mut CrateIndex<'tcx>,
index: &mut CrateIndex<'a, 'tcx>,
associated_const: &ty::AssociatedConst,
parent_id: NodeId,
impl_item_opt: Option<&hir::ImplItem>) {
@ -631,7 +637,7 @@ fn encode_info_for_associated_const<'a, 'tcx>(ecx: &EncodeContext<'a, 'tcx>,
associated_const.def_id,
associated_const.name);
index.record(associated_const.def_id, rbml_w);
let _task = index.record(associated_const.def_id, rbml_w);
rbml_w.start_tag(tag_items_data_item);
encode_def_id_and_key(ecx, rbml_w, associated_const.def_id);
@ -665,7 +671,7 @@ fn encode_info_for_associated_const<'a, 'tcx>(ecx: &EncodeContext<'a, 'tcx>,
fn encode_info_for_method<'a, 'tcx>(ecx: &EncodeContext<'a, 'tcx>,
rbml_w: &mut Encoder,
index: &mut CrateIndex<'tcx>,
index: &mut CrateIndex<'a, 'tcx>,
m: &ty::Method<'tcx>,
is_default_impl: bool,
parent_id: NodeId,
@ -673,7 +679,7 @@ fn encode_info_for_method<'a, 'tcx>(ecx: &EncodeContext<'a, 'tcx>,
debug!("encode_info_for_method: {:?} {:?}", m.def_id,
m.name);
index.record(m.def_id, rbml_w);
let _task = index.record(m.def_id, rbml_w);
rbml_w.start_tag(tag_items_data_item);
encode_method_ty_fields(ecx, rbml_w, index, m);
@ -717,7 +723,7 @@ fn encode_info_for_method<'a, 'tcx>(ecx: &EncodeContext<'a, 'tcx>,
fn encode_info_for_associated_type<'a, 'tcx>(ecx: &EncodeContext<'a, 'tcx>,
rbml_w: &mut Encoder,
index: &mut CrateIndex<'tcx>,
index: &mut CrateIndex<'a, 'tcx>,
associated_type: &ty::AssociatedType<'tcx>,
parent_id: NodeId,
impl_item_opt: Option<&hir::ImplItem>) {
@ -725,7 +731,7 @@ fn encode_info_for_associated_type<'a, 'tcx>(ecx: &EncodeContext<'a, 'tcx>,
associated_type.def_id,
associated_type.name);
index.record(associated_type.def_id, rbml_w);
let _task = index.record(associated_type.def_id, rbml_w);
rbml_w.start_tag(tag_items_data_item);
encode_def_id_and_key(ecx, rbml_w, associated_type.def_id);
@ -863,7 +869,7 @@ fn encode_xrefs<'a, 'tcx>(ecx: &EncodeContext<'a, 'tcx>,
fn encode_info_for_item<'a, 'tcx>(ecx: &EncodeContext<'a, 'tcx>,
rbml_w: &mut Encoder,
item: &hir::Item,
index: &mut CrateIndex<'tcx>) {
index: &mut CrateIndex<'a, 'tcx>) {
let tcx = ecx.tcx;
debug!("encoding info for item at {}",
@ -871,12 +877,15 @@ fn encode_info_for_item<'a, 'tcx>(ecx: &EncodeContext<'a, 'tcx>,
let vis = &item.vis;
let def_id = ecx.tcx.map.local_def_id(item.id);
let stab = tcx.lookup_stability(ecx.tcx.map.local_def_id(item.id));
let depr = tcx.lookup_deprecation(ecx.tcx.map.local_def_id(item.id));
let (stab, depr) = tcx.dep_graph.with_task(DepNode::MetaData(def_id), || {
(tcx.lookup_stability(ecx.tcx.map.local_def_id(item.id)),
tcx.lookup_deprecation(ecx.tcx.map.local_def_id(item.id)))
});
match item.node {
hir::ItemStatic(_, m, _) => {
index.record(def_id, rbml_w);
let _task = index.record(def_id, rbml_w);
rbml_w.start_tag(tag_items_data_item);
encode_def_id_and_key(ecx, rbml_w, def_id);
if m == hir::MutMutable {
@ -894,7 +903,7 @@ fn encode_info_for_item<'a, 'tcx>(ecx: &EncodeContext<'a, 'tcx>,
rbml_w.end_tag();
}
hir::ItemConst(_, _) => {
index.record(def_id, rbml_w);
let _task = index.record(def_id, rbml_w);
rbml_w.start_tag(tag_items_data_item);
encode_def_id_and_key(ecx, rbml_w, def_id);
encode_family(rbml_w, 'C');
@ -909,7 +918,7 @@ fn encode_info_for_item<'a, 'tcx>(ecx: &EncodeContext<'a, 'tcx>,
rbml_w.end_tag();
}
hir::ItemFn(ref decl, _, constness, _, ref generics, _) => {
index.record(def_id, rbml_w);
let _task = index.record(def_id, rbml_w);
rbml_w.start_tag(tag_items_data_item);
encode_def_id_and_key(ecx, rbml_w, def_id);
encode_family(rbml_w, FN_FAMILY);
@ -933,7 +942,7 @@ fn encode_info_for_item<'a, 'tcx>(ecx: &EncodeContext<'a, 'tcx>,
rbml_w.end_tag();
}
hir::ItemMod(ref m) => {
index.record(def_id, rbml_w);
let _task = index.record(def_id, rbml_w);
encode_info_for_mod(ecx,
rbml_w,
m,
@ -943,7 +952,7 @@ fn encode_info_for_item<'a, 'tcx>(ecx: &EncodeContext<'a, 'tcx>,
&item.vis);
}
hir::ItemForeignMod(ref fm) => {
index.record(def_id, rbml_w);
let _task = index.record(def_id, rbml_w);
rbml_w.start_tag(tag_items_data_item);
encode_def_id_and_key(ecx, rbml_w, def_id);
encode_family(rbml_w, 'n');
@ -960,7 +969,7 @@ fn encode_info_for_item<'a, 'tcx>(ecx: &EncodeContext<'a, 'tcx>,
rbml_w.end_tag();
}
hir::ItemTy(..) => {
index.record(def_id, rbml_w);
let _task = index.record(def_id, rbml_w);
rbml_w.start_tag(tag_items_data_item);
encode_def_id_and_key(ecx, rbml_w, def_id);
encode_family(rbml_w, 'y');
@ -972,7 +981,7 @@ fn encode_info_for_item<'a, 'tcx>(ecx: &EncodeContext<'a, 'tcx>,
rbml_w.end_tag();
}
hir::ItemEnum(ref enum_definition, _) => {
index.record(def_id, rbml_w);
let _task = index.record(def_id, rbml_w);
rbml_w.start_tag(tag_items_data_item);
encode_def_id_and_key(ecx, rbml_w, def_id);
@ -1003,12 +1012,12 @@ fn encode_info_for_item<'a, 'tcx>(ecx: &EncodeContext<'a, 'tcx>,
index);
}
hir::ItemStruct(ref struct_def, _) => {
/* Index the class*/
let _task = index.record(def_id, rbml_w);
let def = ecx.tcx.lookup_adt_def(def_id);
let variant = def.struct_variant();
/* Index the class*/
index.record(def_id, rbml_w);
/* Now, make an item for the class itself */
rbml_w.start_tag(tag_items_data_item);
encode_def_id_and_key(ecx, rbml_w, def_id);
@ -1056,7 +1065,7 @@ fn encode_info_for_item<'a, 'tcx>(ecx: &EncodeContext<'a, 'tcx>,
}
}
hir::ItemDefaultImpl(unsafety, _) => {
index.record(def_id, rbml_w);
let _task = index.record(def_id, rbml_w);
rbml_w.start_tag(tag_items_data_item);
encode_def_id_and_key(ecx, rbml_w, def_id);
encode_family(rbml_w, 'd');
@ -1068,12 +1077,13 @@ fn encode_info_for_item<'a, 'tcx>(ecx: &EncodeContext<'a, 'tcx>,
rbml_w.end_tag();
}
hir::ItemImpl(unsafety, polarity, _, _, _, ref ast_items) => {
let _task = index.record(def_id, rbml_w);
// We need to encode information about the default methods we
// have inherited, so we drive this based on the impl structure.
let impl_items = tcx.impl_items.borrow();
let items = impl_items.get(&def_id).unwrap();
index.record(def_id, rbml_w);
rbml_w.start_tag(tag_items_data_item);
encode_def_id_and_key(ecx, rbml_w, def_id);
encode_family(rbml_w, 'i');
@ -1170,7 +1180,7 @@ fn encode_info_for_item<'a, 'tcx>(ecx: &EncodeContext<'a, 'tcx>,
}
}
hir::ItemTrait(_, _, _, ref ms) => {
index.record(def_id, rbml_w);
let _task = index.record(def_id, rbml_w);
rbml_w.start_tag(tag_items_data_item);
encode_def_id_and_key(ecx, rbml_w, def_id);
encode_family(rbml_w, 'I');
@ -1225,7 +1235,7 @@ fn encode_info_for_item<'a, 'tcx>(ecx: &EncodeContext<'a, 'tcx>,
for (i, &item_def_id) in r.iter().enumerate() {
assert_eq!(item_def_id.def_id().krate, LOCAL_CRATE);
index.record(item_def_id.def_id(), rbml_w);
let _task = index.record(item_def_id.def_id(), rbml_w);
rbml_w.start_tag(tag_items_data_item);
encode_parent_item(rbml_w, def_id);
@ -1336,12 +1346,12 @@ fn encode_info_for_item<'a, 'tcx>(ecx: &EncodeContext<'a, 'tcx>,
fn encode_info_for_foreign_item<'a, 'tcx>(ecx: &EncodeContext<'a, 'tcx>,
rbml_w: &mut Encoder,
nitem: &hir::ForeignItem,
index: &mut CrateIndex<'tcx>) {
index: &mut CrateIndex<'a, 'tcx>) {
debug!("writing foreign item {}", ecx.tcx.node_path_str(nitem.id));
let def_id = ecx.tcx.map.local_def_id(nitem.id);
let abi = ecx.tcx.map.get_foreign_abi(nitem.id);
index.record(def_id, rbml_w);
let _task = index.record(def_id, rbml_w);
rbml_w.start_tag(tag_items_data_item);
encode_def_id_and_key(ecx, rbml_w, def_id);
encode_visibility(rbml_w, &nitem.vis);
@ -1390,7 +1400,7 @@ fn my_visit_expr(expr: &hir::Expr,
hir::ExprClosure(..) => {
let def_id = ecx.tcx.map.local_def_id(expr.id);
index.record(def_id, rbml_w);
let _task = index.record(def_id, rbml_w);
rbml_w.start_tag(tag_items_data_item);
encode_def_id_and_key(ecx, rbml_w, def_id);
@ -1414,8 +1424,8 @@ fn my_visit_expr(expr: &hir::Expr,
struct EncodeVisitor<'a, 'b:'a, 'c:'a, 'tcx:'c> {
rbml_w_for_visit_item: &'a mut Encoder<'b>,
ecx: &'a EncodeContext<'c,'tcx>,
index: &'a mut CrateIndex<'tcx>,
ecx: &'a EncodeContext<'c, 'tcx>,
index: &'a mut CrateIndex<'c, 'tcx>,
}
impl<'a, 'b, 'c, 'tcx> Visitor<'tcx> for EncodeVisitor<'a, 'b, 'c, 'tcx> {
@ -1435,23 +1445,26 @@ impl<'a, 'b, 'c, 'tcx> Visitor<'tcx> for EncodeVisitor<'a, 'b, 'c, 'tcx> {
fn encode_info_for_items<'a, 'tcx>(ecx: &EncodeContext<'a, 'tcx>,
rbml_w: &mut Encoder)
-> CrateIndex<'tcx> {
-> CrateIndex<'a, 'tcx> {
let krate = ecx.tcx.map.krate();
let mut index = CrateIndex {
dep_graph: &ecx.tcx.dep_graph,
items: IndexData::new(ecx.tcx.map.num_local_def_ids()),
xrefs: FnvHashMap()
};
rbml_w.start_tag(tag_items_data);
index.record(DefId::local(CRATE_DEF_INDEX), rbml_w);
encode_info_for_mod(ecx,
rbml_w,
&krate.module,
&[],
CRATE_NODE_ID,
syntax::parse::token::intern(&ecx.link_meta.crate_name),
&hir::Public);
{
let _task = index.record(DefId::local(CRATE_DEF_INDEX), rbml_w);
encode_info_for_mod(ecx,
rbml_w,
&krate.module,
&[],
CRATE_NODE_ID,
syntax::parse::token::intern(&ecx.link_meta.crate_name),
&hir::Public);
}
krate.visit_all_items(&mut EncodeVisitor {
index: &mut index,
@ -1780,14 +1793,14 @@ fn encode_crate_dep(rbml_w: &mut Encoder,
rbml_w.start_tag(tag_crate_dep);
rbml_w.wr_tagged_str(tag_crate_dep_crate_name, &dep.name());
let hash = decoder::get_crate_hash(dep.data());
rbml_w.wr_tagged_str(tag_crate_dep_hash, hash.as_str());
rbml_w.wr_tagged_u64(tag_crate_dep_hash, hash.as_u64());
rbml_w.wr_tagged_u8(tag_crate_dep_explicitly_linked,
dep.explicitly_linked.get() as u8);
rbml_w.end_tag();
}
fn encode_hash(rbml_w: &mut Encoder, hash: &Svh) {
rbml_w.wr_tagged_str(tag_crate_hash, hash.as_str());
rbml_w.wr_tagged_u64(tag_crate_hash, hash.as_u64());
}
fn encode_rustc_version(rbml_w: &mut Encoder) {

View file

@ -75,7 +75,7 @@ impl IndexData {
pub fn record(&mut self, def_id: DefId, position: u64) {
assert!(def_id.is_local());
self.record_index(def_id.index, position)
self.record_index(def_id.index, position);
}
pub fn record_index(&mut self, item: DefIndex, position: u64) {

View file

@ -620,7 +620,7 @@ impl<'a> Context<'a> {
info!("Rejecting via hash: expected {} got {}", *myhash, hash);
self.rejected_via_hash.push(CrateMismatch {
path: libpath.to_path_buf(),
got: myhash.as_str().to_string()
got: myhash.to_string()
});
return None;
}

View file

@ -3624,6 +3624,7 @@ pub fn resolve_crate<'a, 'b>(resolver: &'b mut Resolver<'a>, krate: &'b Crate) {
// reflects not just its contents but the results of name
// resolution on those contents. Hopefully we'll push this back at
// some point.
let _ignore = resolver.session.dep_graph.in_ignore();
resolver.build_reduced_graph(krate);
resolve_imports::resolve_imports(resolver);

View file

@ -25,6 +25,7 @@ use middle::dependency_format::Linkage;
use CrateTranslation;
use util::common::time;
use util::fs::fix_windows_verbatim_for_gcc;
use rustc::dep_graph::DepNode;
use rustc::ty::TyCtxt;
use rustc_back::tempdir::TempDir;
@ -183,6 +184,8 @@ pub fn link_binary(sess: &Session,
trans: &CrateTranslation,
outputs: &OutputFilenames,
crate_name: &str) -> Vec<PathBuf> {
let _task = sess.dep_graph.in_task(DepNode::LinkBinary);
let mut out_filenames = Vec::new();
for &crate_type in sess.crate_types.borrow().iter() {
if invalid_output_for_target(sess, crate_type) {

View file

@ -47,6 +47,7 @@ use rustc::dep_graph::DepNode;
use rustc::hir::map as hir_map;
use rustc::util::common::time;
use rustc::mir::mir_map::MirMap;
use rustc_data_structures::graph::OUTGOING;
use session::config::{self, NoDebugInfo, FullDebugInfo};
use session::Session;
use _match;
@ -1368,7 +1369,7 @@ fn build_cfg<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
// return slot alloca. This can cause errors related to clean-up due to
// the clobbering of the existing value in the return slot.
fn has_nested_returns(tcx: TyCtxt, cfg: &cfg::CFG, blk_id: ast::NodeId) -> bool {
for index in cfg.graph.depth_traverse(cfg.entry) {
for index in cfg.graph.depth_traverse(cfg.entry, OUTGOING) {
let n = cfg.graph.node_data(index);
match tcx.map.find(n.id()) {
Some(hir_map::NodeExpr(ex)) => {

View file

@ -134,8 +134,10 @@ pub fn run_core(search_paths: SearchPaths,
false,
codemap.clone());
let cstore = Rc::new(CStore::new(token::get_ident_interner()));
let sess = session::build_session_(sessopts, cpath, diagnostic_handler,
let dep_graph = DepGraph::new(false);
let _ignore = dep_graph.in_ignore();
let cstore = Rc::new(CStore::new(&dep_graph, token::get_ident_interner()));
let sess = session::build_session_(sessopts, &dep_graph, cpath, diagnostic_handler,
codemap, cstore.clone());
rustc_lint::register_builtins(&mut sess.lint_store.borrow_mut(), Some(&sess));
@ -151,15 +153,14 @@ pub fn run_core(search_paths: SearchPaths,
.expect("phase_2_configure_and_expand aborted in rustdoc!");
let krate = driver::assign_node_ids(&sess, krate);
let dep_graph = DepGraph::new(false);
let mut defs = hir_map::collect_definitions(&krate);
read_local_crates(&sess, &cstore, &defs, &krate, &name, &dep_graph);
// Lower ast -> hir and resolve.
let (analysis, resolutions, mut hir_forest) = {
driver::lower_and_resolve(&sess, &name, &mut defs, &krate, dep_graph,
resolve::MakeGlobMap::No)
driver::lower_and_resolve(&sess, &name, &mut defs, &krate,
&sess.dep_graph, resolve::MakeGlobMap::No)
};
let arenas = ty::CtxtArenas::new();
@ -177,7 +178,6 @@ pub fn run_core(search_paths: SearchPaths,
return None
}
let _ignore = tcx.dep_graph.in_ignore();
let ty::CrateAnalysis { access_levels, .. } = analysis;
// Convert from a NodeId set to a DefId set since we don't always have easy access

View file

@ -79,8 +79,11 @@ pub fn run(input: &str,
false,
codemap.clone());
let cstore = Rc::new(CStore::new(token::get_ident_interner()));
let dep_graph = DepGraph::new(false);
let _ignore = dep_graph.in_ignore();
let cstore = Rc::new(CStore::new(&dep_graph, token::get_ident_interner()));
let sess = session::build_session_(sessopts,
&dep_graph,
Some(input_path.clone()),
diagnostic_handler,
codemap,
@ -98,12 +101,12 @@ pub fn run(input: &str,
let defs = hir_map::collect_definitions(&krate);
let mut dummy_resolver = DummyResolver;
let krate = lower_crate(&krate, &sess, &mut dummy_resolver);
let krate = lower_crate(&sess, &krate, &sess, &mut dummy_resolver);
let opts = scrape_test_config(&krate);
let _ignore = dep_graph.in_ignore();
let mut forest = hir_map::Forest::new(krate, dep_graph.clone());
let mut forest = hir_map::Forest::new(krate, &dep_graph);
let map = hir_map::map_crate(&mut forest, defs);
let ctx = core::DocContext {
@ -238,8 +241,10 @@ fn runtest(test: &str, cratename: &str, cfgs: Vec<String>, libs: SearchPaths,
// Compile the code
let diagnostic_handler = errors::Handler::with_emitter(true, false, box emitter);
let cstore = Rc::new(CStore::new(token::get_ident_interner()));
let dep_graph = DepGraph::new(false);
let cstore = Rc::new(CStore::new(&dep_graph, token::get_ident_interner()));
let sess = session::build_session_(sessopts,
&dep_graph,
None,
diagnostic_handler,
codemap,

View file

@ -0,0 +1,24 @@
// Copyright 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.
#![crate_type="rlib"]
#[cfg(rpass1)]
pub fn function0(x: u32) -> u32 {
x
}
#[cfg(rpass2)]
pub fn function0(x: i32) -> i32 {
x
}
pub fn function1(x: u32) {
}

View file

@ -0,0 +1,28 @@
// Copyright 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.
// aux-build:a.rs
// revisions:rpass1 rpass2
#![feature(rustc_attrs)]
extern crate a;
#[rustc_dirty(label="TypeckItemBody", cfg="rpass2")]
pub fn call_function0() {
a::function0(77);
}
#[rustc_clean(label="TypeckItemBody", cfg="rpass2")]
pub fn call_function1() {
a::function1(77);
}
pub fn main() { }

View file

@ -0,0 +1,21 @@
// Copyright 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.
#![crate_type="rlib"]
#[cfg(rpass1)]
pub type X = u32;
#[cfg(rpass2)]
pub type X = i32;
pub type Y = char;
pub fn foo() { }

View file

@ -0,0 +1,29 @@
// Copyright 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.
// aux-build:a.rs
// revisions:rpass1 rpass2
#![feature(rustc_attrs)]
extern crate a;
#[rustc_dirty(label="TypeckItemBody", cfg="rpass2")]
pub fn use_X() -> u32 {
let x: a::X = 22;
x as u32
}
#[rustc_clean(label="TypeckItemBody", cfg="rpass2")]
pub fn use_Y() {
let x: a::Y = 'c';
}
pub fn main() { }

View file

@ -223,8 +223,12 @@ fn compile_program(input: &str, sysroot: PathBuf)
let handle = thread.spawn(move || {
let opts = build_exec_options(sysroot);
let cstore = Rc::new(CStore::new(token::get_ident_interner()));
let sess = build_session(opts, None, Registry::new(&rustc::DIAGNOSTICS),
let dep_graph = DepGraph::new(opts.build_dep_graph());
let cstore = Rc::new(CStore::new(&dep_graph, token::get_ident_interner()));
let sess = build_session(opts,
&dep_graph,
None,
Registry::new(&rustc::DIAGNOSTICS),
cstore.clone());
rustc_lint::register_builtins(&mut sess.lint_store.borrow_mut(), Some(&sess));
@ -237,12 +241,12 @@ fn compile_program(input: &str, sysroot: PathBuf)
let krate = driver::phase_2_configure_and_expand(&sess, &cstore, krate, &id, None)
.expect("phase_2 returned `None`");
let dep_graph = DepGraph::new(sess.opts.build_dep_graph());
let krate = driver::assign_node_ids(&sess, krate);
let mut defs = ast_map::collect_definitions(&krate);
read_local_crates(&sess, &cstore, &defs, &krate, &id, &dep_graph);
let (analysis, resolutions, mut hir_forest) = {
driver::lower_and_resolve(&sess, &id, &mut defs, &krate, dep_graph, MakeGlobMap::No)
driver::lower_and_resolve(&sess, &id, &mut defs, &krate,
&sess.dep_graph, MakeGlobMap::No)
};
let arenas = ty::CtxtArenas::new();

View file

@ -16,6 +16,7 @@ extern crate rustc_lint;
extern crate rustc_metadata;
extern crate syntax;
use rustc::dep_graph::DepGraph;
use rustc::session::{build_session, Session};
use rustc::session::config::{basic_options, build_configuration, Input, OutputType};
use rustc_driver::driver::{compile_input, CompileController, anon_src};
@ -54,8 +55,9 @@ fn basic_sess(sysroot: PathBuf) -> (Session, Rc<CStore>) {
opts.maybe_sysroot = Some(sysroot);
let descriptions = Registry::new(&rustc::DIAGNOSTICS);
let cstore = Rc::new(CStore::new(token::get_ident_interner()));
let sess = build_session(opts, None, descriptions, cstore.clone());
let dep_graph = DepGraph::new(opts.build_dep_graph());
let cstore = Rc::new(CStore::new(&dep_graph, token::get_ident_interner()));
let sess = build_session(opts, &dep_graph, None, descriptions, cstore.clone());
rustc_lint::register_builtins(&mut sess.lint_store.borrow_mut(), Some(&sess));
(sess, cstore)
}

View file

@ -162,6 +162,11 @@ pub struct TestProps {
pub forbid_output: Vec<String>,
// Revisions to test for incremental compilation.
pub revisions: Vec<String>,
// Directory (if any) to use for incremental compilation. This is
// not set by end-users; rather it is set by the incremental
// testing harness and used when generating compilation
// arguments. (In particular, it propagates to the aux-builds.)
pub incremental_dir: Option<PathBuf>,
}
impl TestProps {
@ -197,9 +202,20 @@ impl TestProps {
pretty_mode: format!("normal"),
pretty_compare_only: pretty_compare_only,
forbid_output: forbid_output,
incremental_dir: None,
}
}
pub fn from_aux_file(&self, testfile: &Path, cfg: Option<&str>) -> Self {
let mut props = TestProps::new();
// copy over select properties to the aux build:
props.incremental_dir = self.incremental_dir.clone();
props.load_from(testfile, cfg);
props
}
pub fn from_file(testfile: &Path) -> Self {
let mut props = TestProps::new();
props.load_from(testfile, None);

View file

@ -63,10 +63,6 @@ pub fn run(config: Config, testpaths: &TestPaths) {
for revision in &base_props.revisions {
let mut revision_props = base_props.clone();
revision_props.load_from(&testpaths.file, Some(&revision));
revision_props.compile_flags.extend(vec![
format!("--cfg"),
format!("{}", revision),
]);
let rev_cx = TestCx {
config: &config,
props: &revision_props,
@ -383,6 +379,12 @@ actual:\n\
self.config.build_base.to_str().unwrap().to_owned(),
"-L".to_owned(),
aux_dir.to_str().unwrap().to_owned());
if let Some(revision) = self.revision {
args.extend(vec![
format!("--cfg"),
format!("{}", revision),
]);
}
args.extend(self.split_maybe_args(&self.config.target_rustcflags));
args.extend(self.props.compile_flags.iter().cloned());
// FIXME (#9639): This needs to handle non-utf8 paths
@ -1102,7 +1104,7 @@ actual:\n\
if self.props.build_aux_docs {
for rel_ab in &self.props.aux_builds {
let aux_testpaths = self.compute_aux_test_paths(rel_ab);
let aux_props = TestProps::from_file(&aux_testpaths.file);
let aux_props = self.props.from_aux_file(&aux_testpaths.file, self.revision);
let aux_cx = TestCx {
config: self.config,
props: &aux_props,
@ -1186,7 +1188,7 @@ actual:\n\
for rel_ab in &self.props.aux_builds {
let aux_testpaths = self.compute_aux_test_paths(rel_ab);
let aux_props = TestProps::from_file(&aux_testpaths.file);
let aux_props = self.props.from_aux_file(&aux_testpaths.file, self.revision);
let mut crate_type = if aux_props.no_prefer_dynamic {
Vec::new()
} else {
@ -1291,6 +1293,21 @@ actual:\n\
self.config.build_base.to_str().unwrap().to_owned(),
format!("--target={}", target));
if let Some(revision) = self.revision {
args.extend(vec![
format!("--cfg"),
format!("{}", revision),
]);
}
if let Some(ref incremental_dir) = self.props.incremental_dir {
args.extend(vec![
format!("-Z"),
format!("incremental={}", incremental_dir.display()),
]);
}
match self.config.mode {
CompileFail |
ParseFail |
@ -1980,10 +1997,7 @@ actual:\n\
// Add an extra flag pointing at the incremental directory.
let mut revision_props = self.props.clone();
revision_props.compile_flags.extend(vec![
format!("-Z"),
format!("incremental={}", incremental_dir.display()),
]);
revision_props.incremental_dir = Some(incremental_dir);
let revision_cx = TestCx {
config: self.config,