about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--src/librustc/cfg/mod.rs2
-rw-r--r--src/librustc/dep_graph/debug.rs69
-rw-r--r--src/librustc/dep_graph/dep_node.rs7
-rw-r--r--src/librustc/dep_graph/mod.rs2
-rw-r--r--src/librustc/dep_graph/query.rs21
-rw-r--r--src/librustc/dep_graph/thread.rs3
-rw-r--r--src/librustc/dep_graph/visit.rs3
-rw-r--r--src/librustc/hir/lowering.rs11
-rw-r--r--src/librustc/hir/map/definitions.rs37
-rw-r--r--src/librustc/hir/map/mod.rs11
-rw-r--r--src/librustc/hir/svh.rs72
-rw-r--r--src/librustc/infer/region_inference/mod.rs4
-rw-r--r--src/librustc/lib.rs1
-rw-r--r--src/librustc/middle/cstore.rs25
-rw-r--r--src/librustc/session/config.rs14
-rw-r--r--src/librustc/session/mod.rs28
-rw-r--r--src/librustc/ty/context.rs48
-rw-r--r--src/librustc/ty/util.rs2
-rw-r--r--src/librustc_data_structures/graph/mod.rs14
-rw-r--r--src/librustc_driver/driver.rs11
-rw-r--r--src/librustc_driver/lib.rs15
-rw-r--r--src/librustc_driver/pretty.rs2
-rw-r--r--src/librustc_driver/test.rs11
-rw-r--r--src/librustc_incremental/assert_dep_graph.rs30
-rw-r--r--src/librustc_incremental/calculate_svh.rs13
-rw-r--r--src/librustc_incremental/persist/data.rs61
-rw-r--r--src/librustc_incremental/persist/directory.rs21
-rw-r--r--src/librustc_incremental/persist/hash.rs163
-rw-r--r--src/librustc_incremental/persist/load.rs20
-rw-r--r--src/librustc_incremental/persist/mod.rs1
-rw-r--r--src/librustc_incremental/persist/save.rs197
-rw-r--r--src/librustc_incremental/persist/util.rs21
-rw-r--r--src/librustc_metadata/creader.rs1
-rw-r--r--src/librustc_metadata/csearch.rs64
-rw-r--r--src/librustc_metadata/cstore.rs16
-rw-r--r--src/librustc_metadata/decoder.rs47
-rw-r--r--src/librustc_metadata/encoder.rs133
-rw-r--r--src/librustc_metadata/index.rs2
-rw-r--r--src/librustc_metadata/loader.rs2
-rw-r--r--src/librustc_resolve/lib.rs1
-rw-r--r--src/librustc_trans/back/link.rs3
-rw-r--r--src/librustc_trans/base.rs3
-rw-r--r--src/librustdoc/core.rs12
-rw-r--r--src/librustdoc/test.rs13
-rw-r--r--src/test/incremental/callee_caller_cross_crate/auxiliary/a.rs24
-rw-r--r--src/test/incremental/callee_caller_cross_crate/b.rs28
-rw-r--r--src/test/incremental/type_alias_cross_crate/auxiliary/a.rs21
-rw-r--r--src/test/incremental/type_alias_cross_crate/b.rs29
-rw-r--r--src/test/run-make/execution-engine/test.rs12
-rw-r--r--src/test/run-make/issue-19371/foo.rs6
-rw-r--r--src/tools/compiletest/src/header.rs16
-rw-r--r--src/tools/compiletest/src/runtest.rs34
52 files changed, 1037 insertions, 370 deletions
diff --git a/src/librustc/cfg/mod.rs b/src/librustc/cfg/mod.rs
index 617e2ed2f1a..d06f51073df 100644
--- a/src/librustc/cfg/mod.rs
+++ b/src/librustc/cfg/mod.rs
@@ -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)
     }
 }
diff --git a/src/librustc/dep_graph/debug.rs b/src/librustc/dep_graph/debug.rs
new file mode 100644
index 00000000000..15b0380374c
--- /dev/null
+++ b/src/librustc/dep_graph/debug.rs
@@ -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]),
+            })
+        }
+    }
+}
diff --git a/src/librustc/dep_graph/dep_node.rs b/src/librustc/dep_graph/dep_node.rs
index 3e43c8e2c93..84c84a7ed57 100644
--- a/src/librustc/dep_graph/dep_node.rs
+++ b/src/librustc/dep_graph/dep_node.rs
@@ -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),
diff --git a/src/librustc/dep_graph/mod.rs b/src/librustc/dep_graph/mod.rs
index 49481dcb796..e65f6bbcf7a 100644
--- a/src/librustc/dep_graph/mod.rs
+++ b/src/librustc/dep_graph/mod.rs
@@ -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;
diff --git a/src/librustc/dep_graph/query.rs b/src/librustc/dep_graph/query.rs
index acc6660da6e..93248edb197 100644
--- a/src/librustc/dep_graph/query.rs
+++ b/src/librustc/dep_graph/query.rs
@@ -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())
diff --git a/src/librustc/dep_graph/thread.rs b/src/librustc/dep_graph/thread.rs
index b15e0e33b84..70d0a4e315c 100644
--- a/src/librustc/dep_graph/thread.rs
+++ b/src/librustc/dep_graph/thread.rs
@@ -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.
diff --git a/src/librustc/dep_graph/visit.rs b/src/librustc/dep_graph/visit.rs
index 321d109ca0e..9133b4d22ee 100644
--- a/src/librustc/dep_graph/visit.rs
+++ b/src/librustc/dep_graph/visit.rs
@@ -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);
         }
     }
 
diff --git a/src/librustc/hir/lowering.rs b/src/librustc/hir/lowering.rs
index 67ea7951de7..ba655b35eda 100644
--- a/src/librustc/hir/lowering.rs
+++ b/src/librustc/hir/lowering.rs
@@ -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
diff --git a/src/librustc/hir/map/definitions.rs b/src/librustc/hir/map/definitions.rs
index 358301ab404..457511cdbc3 100644
--- a/src/librustc/hir/map/definitions.rs
+++ b/src/librustc/hir/map/definitions.rs
@@ -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,
diff --git a/src/librustc/hir/map/mod.rs b/src/librustc/hir/map/mod.rs
index c0bbccad5f2..2f310806a74 100644
--- a/src/librustc/hir/map/mod.rs
+++ b/src/librustc/hir/map/mod.rs
@@ -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 {
diff --git a/src/librustc/hir/svh.rs b/src/librustc/hir/svh.rs
index 1536f884b09..d4e797c9f2d 100644
--- a/src/librustc/hir/svh.rs
+++ b/src/librustc/hir/svh.rs
@@ -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());
+    pub fn as_u64(&self) -> u64 {
+        self.hash
+    }
 
-        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 to_string(&self) -> String {
+        format!("{:016x}", self.hash)
     }
+}
 
-    pub fn as_str<'a>(&'a self) -> &'a str {
-        &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())
     }
 }
diff --git a/src/librustc/infer/region_inference/mod.rs b/src/librustc/infer/region_inference/mod.rs
index 9d2d52015e3..5312d030525 100644
--- a/src/librustc/infer/region_inference/mod.rs
+++ b/src/librustc/infer/region_inference/mod.rs
@@ -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 };
diff --git a/src/librustc/lib.rs b/src/librustc/lib.rs
index ed63783366b..e1fb701e641 100644
--- a/src/librustc/lib.rs
+++ b/src/librustc/lib.rs
@@ -37,7 +37,6 @@
 #![feature(rustc_private)]
 #![feature(slice_patterns)]
 #![feature(staged_api)]
-#![feature(step_by)]
 #![feature(question_mark)]
 #![cfg_attr(test, feature(test))]
 
diff --git a/src/librustc/middle/cstore.rs b/src/librustc/middle/cstore.rs
index c0af457ed23..e5a8c1d1b4e 100644
--- a/src/librustc/middle/cstore.rs
+++ b/src/librustc/middle/cstore.rs
@@ -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>
diff --git a/src/librustc/session/config.rs b/src/librustc/session/config.rs
index 7d1d5dba398..7bb96c5ab2b 100644
--- a/src/librustc/session/config.rs
+++ b/src/librustc/session/config.rs
@@ -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);
         }
diff --git a/src/librustc/session/mod.rs b/src/librustc/session/mod.rs
index 1bea01c4849..907241d1746 100644
--- a/src/librustc/session/mod.rs
+++ b/src/librustc/session/mod.rs
@@ -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) {
diff --git a/src/librustc/ty/context.rs b/src/librustc/ty/context.rs
index aa502669777..45aa6f881e8 100644
--- a/src/librustc/ty/context.rs
+++ b/src/librustc/ty/context.rs
@@ -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>
diff --git a/src/librustc/ty/util.rs b/src/librustc/ty/util.rs
index 08909861d3f..4f6188ea3c5 100644
--- a/src/librustc/ty/util.rs
+++ b/src/librustc/ty/util.rs
@@ -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| {
diff --git a/src/librustc_data_structures/graph/mod.rs b/src/librustc_data_structures/graph/mod.rs
index 99a87d1e760..731471b0600 100644
--- a/src/librustc_data_structures/graph/mod.rs
+++ b/src/librustc_data_structures/graph/mod.rs
@@ -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);
                 }
             }
 
diff --git a/src/librustc_driver/driver.rs b/src/librustc_driver/driver.rs
index 46356add8c6..1d60c2eb437 100644
--- a/src/librustc_driver/driver.rs
+++ b/src/librustc_driver/driver.rs
@@ -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 {
diff --git a/src/librustc_driver/lib.rs b/src/librustc_driver/lib.rs
index 2a4b30e016f..06133c508d9 100644
--- a/src/librustc_driver/lib.rs
+++ b/src/librustc_driver/lib.rs
@@ -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 {
diff --git a/src/librustc_driver/pretty.rs b/src/librustc_driver/pretty.rs
index 9aae9f04c92..8c84e561e31 100644
--- a/src/librustc_driver/pretty.rs
+++ b/src/librustc_driver/pretty.rs
@@ -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;
diff --git a/src/librustc_driver/test.rs b/src/librustc_driver/test.rs
index bbda1965c7f..e0d693c4230 100644
--- a/src/librustc_driver/test.rs
+++ b/src/librustc_driver/test.rs
@@ -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();
diff --git a/src/librustc_incremental/assert_dep_graph.rs b/src/librustc_incremental/assert_dep_graph.rs
index b74e7e21226..9dc50a63064 100644
--- a/src/librustc_incremental/assert_dep_graph.rs
+++ b/src/librustc_incremental/assert_dep_graph.rs
@@ -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>,
diff --git a/src/librustc_incremental/calculate_svh.rs b/src/librustc_incremental/calculate_svh.rs
index f134f3c3f10..24ecce11487 100644
--- a/src/librustc_incremental/calculate_svh.rs
+++ b/src/librustc_incremental/calculate_svh.rs
@@ -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
     }
 }
 
diff --git a/src/librustc_incremental/persist/data.rs b/src/librustc_incremental/persist/data.rs
index 37d5f8937f1..f57ab19a525 100644
--- a/src/librustc_incremental/persist/data.rs
+++ b/src/librustc_incremental/persist/data.rs
@@ -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,
diff --git a/src/librustc_incremental/persist/directory.rs b/src/librustc_incremental/persist/directory.rs
index e256b7cf7d0..f9e90f39321 100644
--- a/src/librustc_incremental/persist/directory.rs
+++ b/src/librustc_incremental/persist/directory.rs
@@ -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 {
diff --git a/src/librustc_incremental/persist/hash.rs b/src/librustc_incremental/persist/hash.rs
new file mode 100644
index 00000000000..b729f25b873
--- /dev/null
+++ b/src/librustc_incremental/persist/hash.rs
@@ -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(())
+    }
+}
diff --git a/src/librustc_incremental/persist/load.rs b/src/librustc_incremental/persist/load.rs
index f9e479745d1..e3fd290443c 100644
--- a/src/librustc_incremental/persist/load.rs
+++ b/src/librustc_incremental/persist/load.rs
@@ -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 => {
diff --git a/src/librustc_incremental/persist/mod.rs b/src/librustc_incremental/persist/mod.rs
index 8d04fd30a19..72ccc29c97b 100644
--- a/src/librustc_incremental/persist/mod.rs
+++ b/src/librustc_incremental/persist/mod.rs
@@ -15,6 +15,7 @@
 mod data;
 mod directory;
 mod dirty_clean;
+mod hash;
 mod load;
 mod save;
 mod util;
diff --git a/src/librustc_incremental/persist/save.rs b/src/librustc_incremental/persist/save.rs
index cbb3464f3ef..7deb1ca36db 100644
--- a/src/librustc_incremental/persist/save.rs
+++ b/src/librustc_incremental/persist/save.rs
@@ -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?
-
-        // 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;
-                }
-            }
-        }
+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;
+
+    let path_buf = match opt_path_buf {
+        Some(p) => p,
+        None => return
+    };
+
+    // FIXME(#32754) lock file?
 
-        // generate the data in a memory buffer
-        let mut wr = Cursor::new(Vec::new());
-        match encode_dep_graph(tcx, &mut Encoder::new(&mut wr)) {
+    // 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));
+                    &format!("unable to delete old dep-graph at `{}`: {}",
+                             path_buf.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));
-                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(())
+}
diff --git a/src/librustc_incremental/persist/util.rs b/src/librustc_incremental/persist/util.rs
index 8ebcbc0466f..a77a9607e77 100644
--- a/src/librustc_incremental/persist/util.rs
+++ b/src/librustc_incremental/persist/util.rs
@@ -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),
     }
 }
+
diff --git a/src/librustc_metadata/creader.rs b/src/librustc_metadata/creader.rs
index 63c6af704bb..0eacc0907bc 100644
--- a/src/librustc_metadata/creader.rs
+++ b/src/librustc_metadata/creader.rs
@@ -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,
diff --git a/src/librustc_metadata/csearch.rs b/src/librustc_metadata/csearch.rs
index 8d464099783..b87b5492f04 100644
--- a/src/librustc_metadata/csearch.rs
+++ b/src/librustc_metadata/csearch.rs
@@ -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)
     }
diff --git a/src/librustc_metadata/cstore.rs b/src/librustc_metadata/cstore.rs
index 04b6e1c42b9..2e1bdf21c9a 100644
--- a/src/librustc_metadata/cstore.rs
+++ b/src/librustc_metadata/cstore.rs
@@ -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()),
diff --git a/src/librustc_metadata/decoder.rs b/src/librustc_metadata/decoder.rs
index e233dda7e91..b6f35074b7d 100644
--- a/src/librustc_metadata/decoder.rs
+++ b/src/librustc_metadata/decoder.rs
@@ -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);
diff --git a/src/librustc_metadata/encoder.rs b/src/librustc_metadata/encoder.rs
index 662942a5bdc..928601095b0 100644
--- a/src/librustc_metadata/encoder.rs
+++ b/src/librustc_metadata/encoder.rs
@@ -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) {
diff --git a/src/librustc_metadata/index.rs b/src/librustc_metadata/index.rs
index 9c066f9f5f1..b850073462f 100644
--- a/src/librustc_metadata/index.rs
+++ b/src/librustc_metadata/index.rs
@@ -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) {
diff --git a/src/librustc_metadata/loader.rs b/src/librustc_metadata/loader.rs
index 4ecb7a28ef7..a5b1c3d301b 100644
--- a/src/librustc_metadata/loader.rs
+++ b/src/librustc_metadata/loader.rs
@@ -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;
             }
diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs
index 016dff5f005..61ed88ec173 100644
--- a/src/librustc_resolve/lib.rs
+++ b/src/librustc_resolve/lib.rs
@@ -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);
diff --git a/src/librustc_trans/back/link.rs b/src/librustc_trans/back/link.rs
index 00d9658cb59..b5248c209a3 100644
--- a/src/librustc_trans/back/link.rs
+++ b/src/librustc_trans/back/link.rs
@@ -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) {
diff --git a/src/librustc_trans/base.rs b/src/librustc_trans/base.rs
index 65c3aa12ba6..481154ba29f 100644
--- a/src/librustc_trans/base.rs
+++ b/src/librustc_trans/base.rs
@@ -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)) => {
diff --git a/src/librustdoc/core.rs b/src/librustdoc/core.rs
index 6d45980b45d..4ae869c3259 100644
--- a/src/librustdoc/core.rs
+++ b/src/librustdoc/core.rs
@@ -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
diff --git a/src/librustdoc/test.rs b/src/librustdoc/test.rs
index e4fbdba77a4..2754f77444c 100644
--- a/src/librustdoc/test.rs
+++ b/src/librustdoc/test.rs
@@ -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,
diff --git a/src/test/incremental/callee_caller_cross_crate/auxiliary/a.rs b/src/test/incremental/callee_caller_cross_crate/auxiliary/a.rs
new file mode 100644
index 00000000000..d802c9a8352
--- /dev/null
+++ b/src/test/incremental/callee_caller_cross_crate/auxiliary/a.rs
@@ -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) {
+}
diff --git a/src/test/incremental/callee_caller_cross_crate/b.rs b/src/test/incremental/callee_caller_cross_crate/b.rs
new file mode 100644
index 00000000000..e81f828beb1
--- /dev/null
+++ b/src/test/incremental/callee_caller_cross_crate/b.rs
@@ -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() { }
diff --git a/src/test/incremental/type_alias_cross_crate/auxiliary/a.rs b/src/test/incremental/type_alias_cross_crate/auxiliary/a.rs
new file mode 100644
index 00000000000..2494dca0509
--- /dev/null
+++ b/src/test/incremental/type_alias_cross_crate/auxiliary/a.rs
@@ -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() { }
diff --git a/src/test/incremental/type_alias_cross_crate/b.rs b/src/test/incremental/type_alias_cross_crate/b.rs
new file mode 100644
index 00000000000..b4e9b760101
--- /dev/null
+++ b/src/test/incremental/type_alias_cross_crate/b.rs
@@ -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() { }
diff --git a/src/test/run-make/execution-engine/test.rs b/src/test/run-make/execution-engine/test.rs
index 0ad113b8d8b..0e84a0f5221 100644
--- a/src/test/run-make/execution-engine/test.rs
+++ b/src/test/run-make/execution-engine/test.rs
@@ -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();
diff --git a/src/test/run-make/issue-19371/foo.rs b/src/test/run-make/issue-19371/foo.rs
index 80c06ca3274..41d250eadec 100644
--- a/src/test/run-make/issue-19371/foo.rs
+++ b/src/test/run-make/issue-19371/foo.rs
@@ -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)
 }
diff --git a/src/tools/compiletest/src/header.rs b/src/tools/compiletest/src/header.rs
index b5cebe2e3ea..7593033ffe3 100644
--- a/src/tools/compiletest/src/header.rs
+++ b/src/tools/compiletest/src/header.rs
@@ -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);
diff --git a/src/tools/compiletest/src/runtest.rs b/src/tools/compiletest/src/runtest.rs
index a213c6d2d54..f89ff6b3849 100644
--- a/src/tools/compiletest/src/runtest.rs
+++ b/src/tools/compiletest/src/runtest.rs
@@ -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,